blob: 751fc5818aa3aec06dda6694b8e292bc51b5cea6 [file] [log] [blame]
wdenke887afc2002-08-27 09:44:07 +00001/*
2 * (C) Copyright 2001
3 * Denis Peter, MPL AG Switzerland
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenke887afc2002-08-27 09:44:07 +00006 */
7
8/*
9 * SCSI support.
10 */
wdenke887afc2002-08-27 09:44:07 +000011#include <common.h>
12#include <command.h>
Simon Glassf3609472014-10-15 04:38:37 -060013#include <inttypes.h>
wdenke887afc2002-08-27 09:44:07 +000014#include <asm/processor.h>
15#include <scsi.h>
16#include <image.h>
wdenke887afc2002-08-27 09:44:07 +000017#include <pci.h>
18
Vadim Bendebury4ae5eb72012-10-29 05:23:45 +000019#ifdef CONFIG_SCSI_DEV_LIST
20#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
21#else
wdenke887afc2002-08-27 09:44:07 +000022#ifdef CONFIG_SCSI_SYM53C8XX
23#define SCSI_VEND_ID 0x1000
24#ifndef CONFIG_SCSI_DEV_ID
25#define SCSI_DEV_ID 0x0001
26#else
27#define SCSI_DEV_ID CONFIG_SCSI_DEV_ID
28#endif
Jin Zhengxiong4782ac82006-08-23 19:10:44 +080029#elif defined CONFIG_SATA_ULI5288
30
31#define SCSI_VEND_ID 0x10b9
32#define SCSI_DEV_ID 0x5288
33
Rob Herring942e3142011-07-06 16:13:36 +000034#elif !defined(CONFIG_SCSI_AHCI_PLAT)
Jin Zhengxiong4782ac82006-08-23 19:10:44 +080035#error no scsi device defined
wdenke887afc2002-08-27 09:44:07 +000036#endif
Vadim Bendebury4ae5eb72012-10-29 05:23:45 +000037#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
38#endif
wdenke887afc2002-08-27 09:44:07 +000039
tang yuantian1a1cf6e2015-03-20 10:27:54 +080040#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT)
Vadim Bendebury4ae5eb72012-10-29 05:23:45 +000041const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
42#endif
wdenke887afc2002-08-27 09:44:07 +000043static ccb tempccb; /* temporary scsi command buffer */
44
45static unsigned char tempbuff[512]; /* temporary data buffer */
46
47static int scsi_max_devs; /* number of highest available scsi device */
48
49static int scsi_curr_dev; /* current device */
50
Simon Glass4101f682016-02-29 15:25:34 -070051static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
wdenke887afc2002-08-27 09:44:07 +000052
Simon Glass73a9cfd2016-05-01 11:35:57 -060053/* almost the maximum amount of the scsi_ext command.. */
54#define SCSI_MAX_READ_BLK 0xFFFF
55#define SCSI_LBA48_READ 0xFFFFFFF
wdenke887afc2002-08-27 09:44:07 +000056
Simon Glass73a9cfd2016-05-01 11:35:57 -060057#ifdef CONFIG_SYS_64BIT_LBA
Simon Glassf1d4d932016-05-01 11:35:58 -060058void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks)
wdenke887afc2002-08-27 09:44:07 +000059{
Simon Glass73a9cfd2016-05-01 11:35:57 -060060 pccb->cmd[0] = SCSI_READ16;
Simon Glassf1d4d932016-05-01 11:35:58 -060061 pccb->cmd[1] = pccb->lun << 5;
62 pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff;
63 pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff;
64 pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff;
65 pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff;
66 pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff;
67 pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff;
68 pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff;
69 pccb->cmd[9] = (unsigned char)start & 0xff;
Simon Glass73a9cfd2016-05-01 11:35:57 -060070 pccb->cmd[10] = 0;
Simon Glassf1d4d932016-05-01 11:35:58 -060071 pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff;
72 pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff;
73 pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff;
74 pccb->cmd[14] = (unsigned char)blocks & 0xff;
Simon Glass73a9cfd2016-05-01 11:35:57 -060075 pccb->cmd[15] = 0;
76 pccb->cmdlen = 16;
77 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
Simon Glassf1d4d932016-05-01 11:35:58 -060078 debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n",
79 pccb->cmd[0], pccb->cmd[1],
80 pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
81 pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9],
82 pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]);
Simon Glass73a9cfd2016-05-01 11:35:57 -060083}
Dan Murphyfff40a72014-02-03 06:59:01 -060084#endif
Simon Glass73a9cfd2016-05-01 11:35:57 -060085
86void scsi_setup_read_ext(ccb * pccb, lbaint_t start, unsigned short blocks)
87{
Simon Glassf1d4d932016-05-01 11:35:58 -060088 pccb->cmd[0] = SCSI_READ10;
89 pccb->cmd[1] = pccb->lun << 5;
90 pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
91 pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
92 pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
93 pccb->cmd[5] = (unsigned char)start & 0xff;
94 pccb->cmd[6] = 0;
95 pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff;
96 pccb->cmd[8] = (unsigned char)blocks & 0xff;
97 pccb->cmd[6] = 0;
Simon Glass73a9cfd2016-05-01 11:35:57 -060098 pccb->cmdlen=10;
Simon Glassf1d4d932016-05-01 11:35:58 -060099 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
Simon Glass73a9cfd2016-05-01 11:35:57 -0600100 debug ("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
101 pccb->cmd[0],pccb->cmd[1],
102 pccb->cmd[2],pccb->cmd[3],pccb->cmd[4],pccb->cmd[5],
103 pccb->cmd[7],pccb->cmd[8]);
104}
105
106void scsi_setup_write_ext(ccb *pccb, lbaint_t start, unsigned short blocks)
107{
108 pccb->cmd[0] = SCSI_WRITE10;
109 pccb->cmd[1] = pccb->lun << 5;
Simon Glassf1d4d932016-05-01 11:35:58 -0600110 pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
111 pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
112 pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
113 pccb->cmd[5] = (unsigned char)start & 0xff;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600114 pccb->cmd[6] = 0;
Simon Glassf1d4d932016-05-01 11:35:58 -0600115 pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600116 pccb->cmd[8] = (unsigned char)blocks & 0xff;
117 pccb->cmd[9] = 0;
118 pccb->cmdlen = 10;
119 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
120 debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
121 __func__,
122 pccb->cmd[0], pccb->cmd[1],
123 pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
124 pccb->cmd[7], pccb->cmd[8]);
125}
126
127void scsi_setup_read6(ccb * pccb, lbaint_t start, unsigned short blocks)
128{
Simon Glassf1d4d932016-05-01 11:35:58 -0600129 pccb->cmd[0] = SCSI_READ6;
130 pccb->cmd[1] = pccb->lun << 5 | ((unsigned char)(start >> 16) & 0x1f);
131 pccb->cmd[2] = (unsigned char)(start >> 8) & 0xff;
132 pccb->cmd[3] = (unsigned char)start & 0xff;
133 pccb->cmd[4] = (unsigned char)blocks & 0xff;
134 pccb->cmd[5] = 0;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600135 pccb->cmdlen=6;
Simon Glassf1d4d932016-05-01 11:35:58 -0600136 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
137 debug("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n",
138 pccb->cmd[0], pccb->cmd[1],
139 pccb->cmd[2], pccb->cmd[3], pccb->cmd[4]);
Simon Glass73a9cfd2016-05-01 11:35:57 -0600140}
141
142
143void scsi_setup_inquiry(ccb * pccb)
144{
Simon Glassf1d4d932016-05-01 11:35:58 -0600145 pccb->cmd[0] = SCSI_INQUIRY;
146 pccb->cmd[1] = pccb->lun << 5;
147 pccb->cmd[2] = 0;
148 pccb->cmd[3] = 0;
149 if (pccb->datalen > 255)
150 pccb->cmd[4] = 255;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600151 else
Simon Glassf1d4d932016-05-01 11:35:58 -0600152 pccb->cmd[4] = (unsigned char)pccb->datalen;
153 pccb->cmd[5] = 0;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600154 pccb->cmdlen=6;
Simon Glassf1d4d932016-05-01 11:35:58 -0600155 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
Simon Glass73a9cfd2016-05-01 11:35:57 -0600156}
157
158static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
159 lbaint_t blkcnt, void *buffer)
160{
161 int device = block_dev->devnum;
162 lbaint_t start, blks;
163 uintptr_t buf_addr;
164 unsigned short smallblks = 0;
165 ccb* pccb=(ccb *)&tempccb;
166 device&=0xff;
Simon Glassf1d4d932016-05-01 11:35:58 -0600167
168 /* Setup device */
169 pccb->target = scsi_dev_desc[device].target;
170 pccb->lun = scsi_dev_desc[device].lun;
171 buf_addr = (unsigned long)buffer;
172 start = blknr;
173 blks = blkcnt;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600174 debug("\nscsi_read: dev %d startblk " LBAF
175 ", blccnt " LBAF " buffer %lx\n",
176 device, start, blks, (unsigned long)buffer);
177 do {
Simon Glassf1d4d932016-05-01 11:35:58 -0600178 pccb->pdata = (unsigned char *)buf_addr;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600179#ifdef CONFIG_SYS_64BIT_LBA
180 if (start > SCSI_LBA48_READ) {
181 unsigned long blocks;
182 blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK);
183 pccb->datalen = scsi_dev_desc[device].blksz * blocks;
184 scsi_setup_read16(pccb, start, blocks);
185 start += blocks;
186 blks -= blocks;
187 } else
188#endif
189 if (blks > SCSI_MAX_READ_BLK) {
Simon Glassf1d4d932016-05-01 11:35:58 -0600190 pccb->datalen = scsi_dev_desc[device].blksz *
191 SCSI_MAX_READ_BLK;
192 smallblks = SCSI_MAX_READ_BLK;
193 scsi_setup_read_ext(pccb, start, smallblks);
194 start += SCSI_MAX_READ_BLK;
195 blks -= SCSI_MAX_READ_BLK;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600196 }
197 else {
Simon Glassf1d4d932016-05-01 11:35:58 -0600198 pccb->datalen = scsi_dev_desc[device].blksz * blks;
199 smallblks = (unsigned short)blks;
200 scsi_setup_read_ext(pccb, start, smallblks);
201 start += blks;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600202 blks=0;
203 }
204 debug("scsi_read_ext: startblk " LBAF
205 ", blccnt %x buffer %" PRIXPTR "\n",
206 start, smallblks, buf_addr);
207 if (scsi_exec(pccb) != true) {
208 scsi_print_error(pccb);
Simon Glassf1d4d932016-05-01 11:35:58 -0600209 blkcnt -= blks;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600210 break;
211 }
212 buf_addr+=pccb->datalen;
Simon Glassf1d4d932016-05-01 11:35:58 -0600213 } while (blks != 0);
Simon Glass73a9cfd2016-05-01 11:35:57 -0600214 debug("scsi_read_ext: end startblk " LBAF
215 ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr);
Simon Glassf1d4d932016-05-01 11:35:58 -0600216 return blkcnt;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600217}
218
219/*******************************************************************************
220 * scsi_write
221 */
222
223/* Almost the maximum amount of the scsi_ext command.. */
224#define SCSI_MAX_WRITE_BLK 0xFFFF
225
226static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr,
227 lbaint_t blkcnt, const void *buffer)
228{
229 int device = block_dev->devnum;
230 lbaint_t start, blks;
231 uintptr_t buf_addr;
232 unsigned short smallblks;
233 ccb* pccb = (ccb *)&tempccb;
234 device &= 0xff;
235 /* Setup device
236 */
237 pccb->target = scsi_dev_desc[device].target;
238 pccb->lun = scsi_dev_desc[device].lun;
239 buf_addr = (unsigned long)buffer;
240 start = blknr;
241 blks = blkcnt;
242 debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
243 __func__, device, start, blks, (unsigned long)buffer);
244 do {
245 pccb->pdata = (unsigned char *)buf_addr;
246 if (blks > SCSI_MAX_WRITE_BLK) {
247 pccb->datalen = (scsi_dev_desc[device].blksz *
248 SCSI_MAX_WRITE_BLK);
249 smallblks = SCSI_MAX_WRITE_BLK;
250 scsi_setup_write_ext(pccb, start, smallblks);
251 start += SCSI_MAX_WRITE_BLK;
252 blks -= SCSI_MAX_WRITE_BLK;
253 } else {
254 pccb->datalen = scsi_dev_desc[device].blksz * blks;
255 smallblks = (unsigned short)blks;
256 scsi_setup_write_ext(pccb, start, smallblks);
257 start += blks;
258 blks = 0;
259 }
260 debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n",
261 __func__, start, smallblks, buf_addr);
262 if (scsi_exec(pccb) != true) {
263 scsi_print_error(pccb);
264 blkcnt -= blks;
265 break;
266 }
267 buf_addr += pccb->datalen;
268 } while (blks != 0);
269 debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n",
270 __func__, start, smallblks, buf_addr);
271 return blkcnt;
Stefan Reinauer447c0312012-10-29 05:23:48 +0000272}
273
274int scsi_get_disk_count(void)
275{
276 return scsi_max_devs;
wdenke887afc2002-08-27 09:44:07 +0000277}
278
tang yuantian1a1cf6e2015-03-20 10:27:54 +0800279#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT)
wdenke887afc2002-08-27 09:44:07 +0000280void scsi_init(void)
281{
Simon Glass9fbdb942015-11-29 13:17:51 -0700282 int busdevfunc = -1;
Vadim Bendebury4ae5eb72012-10-29 05:23:45 +0000283 int i;
284 /*
285 * Find a device from the list, this driver will support a single
286 * controller.
287 */
288 for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
289 /* get PCI Device ID */
Simon Glass9fbdb942015-11-29 13:17:51 -0700290#ifdef CONFIG_DM_PCI
291 struct udevice *dev;
292 int ret;
293
294 ret = dm_pci_find_device(scsi_device_list[i].vendor,
295 scsi_device_list[i].device, 0, &dev);
296 if (!ret) {
297 busdevfunc = dm_pci_get_bdf(dev);
298 break;
299 }
300#else
Vadim Bendebury4ae5eb72012-10-29 05:23:45 +0000301 busdevfunc = pci_find_device(scsi_device_list[i].vendor,
302 scsi_device_list[i].device,
303 0);
Simon Glass9fbdb942015-11-29 13:17:51 -0700304#endif
Vadim Bendebury4ae5eb72012-10-29 05:23:45 +0000305 if (busdevfunc != -1)
306 break;
307 }
wdenke887afc2002-08-27 09:44:07 +0000308
Vadim Bendebury4ae5eb72012-10-29 05:23:45 +0000309 if (busdevfunc == -1) {
310 printf("Error: SCSI Controller(s) ");
311 for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
312 printf("%04X:%04X ",
313 scsi_device_list[i].vendor,
314 scsi_device_list[i].device);
315 }
316 printf("not found\n");
wdenke887afc2002-08-27 09:44:07 +0000317 return;
318 }
319#ifdef DEBUG
320 else {
Vadim Bendebury4ae5eb72012-10-29 05:23:45 +0000321 printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
322 scsi_device_list[i].vendor,
323 scsi_device_list[i].device,
324 (busdevfunc >> 16) & 0xFF,
325 (busdevfunc >> 11) & 0x1F,
326 (busdevfunc >> 8) & 0x7);
wdenke887afc2002-08-27 09:44:07 +0000327 }
328#endif
Simon Glassabbdb262015-01-27 22:13:44 -0700329 bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
wdenke887afc2002-08-27 09:44:07 +0000330 scsi_low_level_init(busdevfunc);
331 scsi_scan(1);
Simon Glassabbdb262015-01-27 22:13:44 -0700332 bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
wdenke887afc2002-08-27 09:44:07 +0000333}
Rob Herring942e3142011-07-06 16:13:36 +0000334#endif
wdenke887afc2002-08-27 09:44:07 +0000335
Matthew McClintockdf3fc522011-05-24 05:31:19 +0000336#ifdef CONFIG_PARTITIONS
Simon Glass4101f682016-02-29 15:25:34 -0700337struct blk_desc *scsi_get_dev(int dev)
wdenke887afc2002-08-27 09:44:07 +0000338{
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200339 return (dev < CONFIG_SYS_SCSI_MAX_DEVICE) ? &scsi_dev_desc[dev] : NULL;
wdenke887afc2002-08-27 09:44:07 +0000340}
Matthew McClintockdf3fc522011-05-24 05:31:19 +0000341#endif
wdenke887afc2002-08-27 09:44:07 +0000342
Tom Riniba524262016-03-16 09:45:03 -0400343#ifndef CONFIG_SPL_BUILD
wdenke887afc2002-08-27 09:44:07 +0000344/******************************************************************************
345 * scsi boot command intepreter. Derived from diskboot
346 */
Wolfgang Denk54841ab2010-06-28 22:00:46 +0200347int do_scsiboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenke887afc2002-08-27 09:44:07 +0000348{
Rob Herring7405a132012-09-21 04:02:30 +0000349 return common_diskboot(cmdtp, "scsi", argc, argv);
wdenke887afc2002-08-27 09:44:07 +0000350}
351
352/*********************************************************************************
353 * scsi command intepreter
354 */
Wolfgang Denk54841ab2010-06-28 22:00:46 +0200355int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenke887afc2002-08-27 09:44:07 +0000356{
357 switch (argc) {
Simon Glass4c12eeb2011-12-10 08:44:01 +0000358 case 0:
359 case 1:
360 return CMD_RET_USAGE;
Wolfgang Denk47e26b12010-07-17 01:06:04 +0200361
Simon Glass4c12eeb2011-12-10 08:44:01 +0000362 case 2:
Simon Glassf1d4d932016-05-01 11:35:58 -0600363 if (strncmp(argv[1], "res", 3) == 0) {
364 printf("\nReset SCSI\n");
365 scsi_bus_reset();
366 scsi_scan(1);
367 return 0;
368 }
369 if (strncmp(argv[1], "inf", 3) == 0) {
370 int i;
371 for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; ++i) {
372 if (scsi_dev_desc[i].type == DEV_TYPE_UNKNOWN)
373 continue; /* list only known devices */
374 printf("SCSI dev. %d: ", i);
375 dev_print(&scsi_dev_desc[i]);
wdenke887afc2002-08-27 09:44:07 +0000376 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600377 return 0;
378 }
379 if (strncmp(argv[1], "dev", 3) == 0) {
380 if (scsi_curr_dev < 0 ||
381 scsi_curr_dev >= CONFIG_SYS_SCSI_MAX_DEVICE) {
382 printf("\nno SCSI devices available\n");
wdenke887afc2002-08-27 09:44:07 +0000383 return 1;
384 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600385 printf("\n Device %d: ", scsi_curr_dev);
386 dev_print(&scsi_dev_desc[scsi_curr_dev]);
387 return 0;
388 }
389 if (strncmp(argv[1], "scan", 4) == 0) {
390 scsi_scan(1);
391 return 0;
392 }
393 if (strncmp(argv[1], "part", 4) == 0) {
394 int dev, ok;
395 for (ok = 0, dev = 0;
396 dev < CONFIG_SYS_SCSI_MAX_DEVICE; ++dev) {
397 if (scsi_dev_desc[dev].type !=
398 DEV_TYPE_UNKNOWN) {
399 ok++;
400 if (dev)
401 printf("\n");
402 debug("print_part of %x\n", dev);
Simon Glass3e8bd462016-02-29 15:25:48 -0700403 part_print(&scsi_dev_desc[dev]);
wdenke887afc2002-08-27 09:44:07 +0000404 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600405 }
406 if (!ok)
407 printf("\nno SCSI devices available\n");
408 return 1;
409 }
410 return CMD_RET_USAGE;
411 case 3:
412 if (strncmp(argv[1], "dev", 3) == 0) {
413 int dev = (int)simple_strtoul(argv[2], NULL, 10);
414 printf("\nSCSI device %d: ", dev);
415 if (dev >= CONFIG_SYS_SCSI_MAX_DEVICE) {
416 printf("unknown device\n");
wdenke887afc2002-08-27 09:44:07 +0000417 return 1;
418 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600419 printf("\n Device %d: ", dev);
420 dev_print(&scsi_dev_desc[dev]);
421 if (scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN)
422 return 1;
423 scsi_curr_dev = dev;
424 printf("... is now current device\n");
425 return 0;
426 }
427 if (strncmp(argv[1], "part", 4) == 0) {
428 int dev = (int)simple_strtoul(argv[2], NULL, 10);
429 if (scsi_dev_desc[dev].type != DEV_TYPE_UNKNOWN)
430 part_print(&scsi_dev_desc[dev]);
431 else
432 printf("\nSCSI device %d not available\n", dev);
433 return 1;
434 }
435 return CMD_RET_USAGE;
436 default:
437 /* at least 4 args */
438 if (strcmp(argv[1], "read") == 0) {
439 ulong addr = simple_strtoul(argv[2], NULL, 16);
440 ulong blk = simple_strtoul(argv[3], NULL, 16);
441 ulong cnt = simple_strtoul(argv[4], NULL, 16);
442 ulong n;
443 printf("\nSCSI read: device %d block # %ld, count %ld ... ",
444 scsi_curr_dev, blk, cnt);
445 n = scsi_read(&scsi_dev_desc[scsi_curr_dev],
446 blk, cnt, (ulong *)addr);
447 printf("%ld blocks read: %s\n", n,
448 n == cnt ? "OK" : "ERROR");
449 return 0;
450 } else if (strcmp(argv[1], "write") == 0) {
451 ulong addr = simple_strtoul(argv[2], NULL, 16);
452 ulong blk = simple_strtoul(argv[3], NULL, 16);
453 ulong cnt = simple_strtoul(argv[4], NULL, 16);
454 ulong n;
455 printf("\nSCSI write: device %d block # %ld, count %ld ... ",
456 scsi_curr_dev, blk, cnt);
457 n = scsi_write(&scsi_dev_desc[scsi_curr_dev],
458 blk, cnt, (ulong *)addr);
459 printf("%ld blocks written: %s\n", n,
460 n == cnt ? "OK" : "ERROR");
461 return 0;
462 }
wdenke887afc2002-08-27 09:44:07 +0000463 } /* switch */
Simon Glass4c12eeb2011-12-10 08:44:01 +0000464 return CMD_RET_USAGE;
wdenke887afc2002-08-27 09:44:07 +0000465}
466
Tom Riniba524262016-03-16 09:45:03 -0400467U_BOOT_CMD(
468 scsi, 5, 1, do_scsi,
469 "SCSI sub-system",
470 "reset - reset SCSI controller\n"
471 "scsi info - show available SCSI devices\n"
472 "scsi scan - (re-)scan SCSI bus\n"
473 "scsi device [dev] - show or set current device\n"
474 "scsi part [dev] - print partition table of one or all SCSI devices\n"
475 "scsi read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n"
476 " to memory address `addr'\n"
477 "scsi write addr blk# cnt - write `cnt' blocks starting at block\n"
478 " `blk#' from memory address `addr'"
479);
480
481U_BOOT_CMD(
482 scsiboot, 3, 1, do_scsiboot,
483 "boot from SCSI device",
484 "loadAddr dev:part"
485);
486#endif
487
wdenke887afc2002-08-27 09:44:07 +0000488/* copy src to dest, skipping leading and trailing blanks
489 * and null terminate the string
490 */
Simon Glassf1d4d932016-05-01 11:35:58 -0600491void scsi_ident_cpy(unsigned char *dest, unsigned char *src, unsigned int len)
wdenke887afc2002-08-27 09:44:07 +0000492{
493 int start,end;
494
Simon Glassf1d4d932016-05-01 11:35:58 -0600495 start = 0;
496 while (start < len) {
497 if (src[start] != ' ')
wdenke887afc2002-08-27 09:44:07 +0000498 break;
499 start++;
500 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600501 end = len-1;
502 while (end > start) {
503 if (src[end] != ' ')
wdenke887afc2002-08-27 09:44:07 +0000504 break;
505 end--;
506 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600507 for (; start <= end; start++)
508 *dest ++= src[start];
wdenke887afc2002-08-27 09:44:07 +0000509 *dest='\0';
510}
511
512
wdenke887afc2002-08-27 09:44:07 +0000513/* Trim trailing blanks, and NUL-terminate string
514 */
515void scsi_trim_trail (unsigned char *str, unsigned int len)
516{
517 unsigned char *p = str + len - 1;
518
519 while (len-- > 0) {
520 *p-- = '\0';
521 if (*p != ' ') {
522 return;
523 }
524 }
525}
526
Gabe Blackb4c5bbc2012-10-29 05:23:57 +0000527int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz)
528{
529 *capacity = 0;
530
Simon Glassf1d4d932016-05-01 11:35:58 -0600531 memset(pccb->cmd, '\0', sizeof(pccb->cmd));
Gabe Blackb4c5bbc2012-10-29 05:23:57 +0000532 pccb->cmd[0] = SCSI_RD_CAPAC10;
533 pccb->cmd[1] = pccb->lun << 5;
534 pccb->cmdlen = 10;
535 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
536
537 pccb->datalen = 8;
York Sun472d5462013-04-01 11:29:11 -0700538 if (scsi_exec(pccb) != true)
Gabe Blackb4c5bbc2012-10-29 05:23:57 +0000539 return 1;
540
541 *capacity = ((lbaint_t)pccb->pdata[0] << 24) |
542 ((lbaint_t)pccb->pdata[1] << 16) |
543 ((lbaint_t)pccb->pdata[2] << 8) |
544 ((lbaint_t)pccb->pdata[3]);
545
546 if (*capacity != 0xffffffff) {
547 /* Read capacity (10) was sufficient for this drive. */
548 *blksz = ((unsigned long)pccb->pdata[4] << 24) |
549 ((unsigned long)pccb->pdata[5] << 16) |
550 ((unsigned long)pccb->pdata[6] << 8) |
551 ((unsigned long)pccb->pdata[7]);
552 return 0;
553 }
554
555 /* Read capacity (10) was insufficient. Use read capacity (16). */
Simon Glassf1d4d932016-05-01 11:35:58 -0600556 memset(pccb->cmd, '\0', sizeof(pccb->cmd));
Gabe Blackb4c5bbc2012-10-29 05:23:57 +0000557 pccb->cmd[0] = SCSI_RD_CAPAC16;
558 pccb->cmd[1] = 0x10;
559 pccb->cmdlen = 16;
560 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
561
562 pccb->datalen = 16;
York Sun472d5462013-04-01 11:29:11 -0700563 if (scsi_exec(pccb) != true)
Gabe Blackb4c5bbc2012-10-29 05:23:57 +0000564 return 1;
565
566 *capacity = ((uint64_t)pccb->pdata[0] << 56) |
567 ((uint64_t)pccb->pdata[1] << 48) |
568 ((uint64_t)pccb->pdata[2] << 40) |
569 ((uint64_t)pccb->pdata[3] << 32) |
570 ((uint64_t)pccb->pdata[4] << 24) |
571 ((uint64_t)pccb->pdata[5] << 16) |
572 ((uint64_t)pccb->pdata[6] << 8) |
573 ((uint64_t)pccb->pdata[7]);
574
575 *blksz = ((uint64_t)pccb->pdata[8] << 56) |
576 ((uint64_t)pccb->pdata[9] << 48) |
577 ((uint64_t)pccb->pdata[10] << 40) |
578 ((uint64_t)pccb->pdata[11] << 32) |
579 ((uint64_t)pccb->pdata[12] << 24) |
580 ((uint64_t)pccb->pdata[13] << 16) |
581 ((uint64_t)pccb->pdata[14] << 8) |
582 ((uint64_t)pccb->pdata[15]);
583
584 return 0;
585}
586
wdenke887afc2002-08-27 09:44:07 +0000587
588/************************************************************************************
589 * Some setup (fill-in) routines
590 */
591void scsi_setup_test_unit_ready(ccb * pccb)
592{
Simon Glassf1d4d932016-05-01 11:35:58 -0600593 pccb->cmd[0] = SCSI_TST_U_RDY;
594 pccb->cmd[1] = pccb->lun << 5;
595 pccb->cmd[2] = 0;
596 pccb->cmd[3] = 0;
597 pccb->cmd[4] = 0;
598 pccb->cmd[5] = 0;
599 pccb->cmdlen = 6;
600 pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
wdenke887afc2002-08-27 09:44:07 +0000601}
602
Simon Glass73a9cfd2016-05-01 11:35:57 -0600603/*********************************************************************************
604 * (re)-scan the scsi bus and reports scsi device info
605 * to the user if mode = 1
606 */
607void scsi_scan(int mode)
Mark Langsdorf2b42c932015-06-05 00:58:45 +0100608{
Simon Glass73a9cfd2016-05-01 11:35:57 -0600609 unsigned char i,perq,modi,lun;
610 lbaint_t capacity;
611 unsigned long blksz;
612 ccb* pccb=(ccb *)&tempccb;
Mark Langsdorf2b42c932015-06-05 00:58:45 +0100613
Simon Glassf1d4d932016-05-01 11:35:58 -0600614 if (mode == 1)
Simon Glass73a9cfd2016-05-01 11:35:57 -0600615 printf("scanning bus for devices...\n");
Simon Glassf1d4d932016-05-01 11:35:58 -0600616 for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) {
617 scsi_dev_desc[i].target = 0xff;
618 scsi_dev_desc[i].lun = 0xff;
619 scsi_dev_desc[i].lba = 0;
620 scsi_dev_desc[i].blksz = 0;
621 scsi_dev_desc[i].log2blksz =
Simon Glass73a9cfd2016-05-01 11:35:57 -0600622 LOG2_INVALID(typeof(scsi_dev_desc[i].log2blksz));
Simon Glassf1d4d932016-05-01 11:35:58 -0600623 scsi_dev_desc[i].type = DEV_TYPE_UNKNOWN;
624 scsi_dev_desc[i].vendor[0] = 0;
625 scsi_dev_desc[i].product[0] = 0;
626 scsi_dev_desc[i].revision[0] = 0;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600627 scsi_dev_desc[i].removable = false;
Simon Glassf1d4d932016-05-01 11:35:58 -0600628 scsi_dev_desc[i].if_type = IF_TYPE_SCSI;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600629 scsi_dev_desc[i].devnum = i;
Simon Glassf1d4d932016-05-01 11:35:58 -0600630 scsi_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
631 scsi_dev_desc[i].block_read = scsi_read;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600632 scsi_dev_desc[i].block_write = scsi_write;
633 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600634 scsi_max_devs = 0;
635 for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
636 pccb->target = i;
637 for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) {
638 pccb->lun = lun;
639 pccb->pdata = (unsigned char *)&tempbuff;
640 pccb->datalen = 512;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600641 scsi_setup_inquiry(pccb);
642 if (scsi_exec(pccb) != true) {
643 if(pccb->contr_stat==SCSI_SEL_TIME_OUT) {
Simon Glassf1d4d932016-05-01 11:35:58 -0600644 debug("Selection timeout ID %d\n",
645 pccb->target);
Simon Glass73a9cfd2016-05-01 11:35:57 -0600646 continue; /* selection timeout => assuming no device present */
647 }
648 scsi_print_error(pccb);
649 continue;
650 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600651 perq = tempbuff[0];
652 modi = tempbuff[1];
653 if ((perq & 0x1f) == 0x1f)
Simon Glass73a9cfd2016-05-01 11:35:57 -0600654 continue; /* skip unknown devices */
Simon Glassf1d4d932016-05-01 11:35:58 -0600655 if ((modi & 0x80) == 0x80) /* drive is removable */
656 scsi_dev_desc[scsi_max_devs].removable = true;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600657 /* get info for this device */
658 scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].vendor[0],
659 &tempbuff[8], 8);
660 scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].product[0],
661 &tempbuff[16], 16);
662 scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].revision[0],
663 &tempbuff[32], 4);
Simon Glassf1d4d932016-05-01 11:35:58 -0600664 scsi_dev_desc[scsi_max_devs].target = pccb->target;
665 scsi_dev_desc[scsi_max_devs].lun = pccb->lun;
wdenke887afc2002-08-27 09:44:07 +0000666
Simon Glassf1d4d932016-05-01 11:35:58 -0600667 pccb->datalen = 0;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600668 scsi_setup_test_unit_ready(pccb);
669 if (scsi_exec(pccb) != true) {
Simon Glassf1d4d932016-05-01 11:35:58 -0600670 if (scsi_dev_desc[scsi_max_devs].removable) {
671 scsi_dev_desc[scsi_max_devs].type =
672 perq;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600673 goto removable;
674 }
675 scsi_print_error(pccb);
676 continue;
677 }
678 if (scsi_read_capacity(pccb, &capacity, &blksz)) {
679 scsi_print_error(pccb);
680 continue;
681 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600682 scsi_dev_desc[scsi_max_devs].lba = capacity;
683 scsi_dev_desc[scsi_max_devs].blksz = blksz;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600684 scsi_dev_desc[scsi_max_devs].log2blksz =
685 LOG2(scsi_dev_desc[scsi_max_devs].blksz);
Simon Glassf1d4d932016-05-01 11:35:58 -0600686 scsi_dev_desc[scsi_max_devs].type = perq;
Simon Glass73a9cfd2016-05-01 11:35:57 -0600687 part_init(&scsi_dev_desc[scsi_max_devs]);
688removable:
689 if(mode==1) {
690 printf (" Device %d: ", scsi_max_devs);
691 dev_print(&scsi_dev_desc[scsi_max_devs]);
692 } /* if mode */
693 scsi_max_devs++;
694 } /* next LUN */
695 }
Simon Glassf1d4d932016-05-01 11:35:58 -0600696 if (scsi_max_devs > 0)
697 scsi_curr_dev = 0;
wdenke887afc2002-08-27 09:44:07 +0000698 else
Simon Glass73a9cfd2016-05-01 11:35:57 -0600699 scsi_curr_dev = -1;
700
701 printf("Found %d device(s).\n", scsi_max_devs);
702#ifndef CONFIG_SPL_BUILD
703 setenv_ulong("scsidevs", scsi_max_devs);
704#endif
wdenke887afc2002-08-27 09:44:07 +0000705}