1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2001
3*4882a593Smuzhiyun * Denis Peter, MPL AG Switzerland
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <dm.h>
10*4882a593Smuzhiyun #include <inttypes.h>
11*4882a593Smuzhiyun #include <pci.h>
12*4882a593Smuzhiyun #include <scsi.h>
13*4882a593Smuzhiyun #include <dm/device-internal.h>
14*4882a593Smuzhiyun #include <dm/uclass-internal.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #if !defined(CONFIG_DM_SCSI)
17*4882a593Smuzhiyun # ifdef CONFIG_SCSI_DEV_LIST
18*4882a593Smuzhiyun # define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
19*4882a593Smuzhiyun # else
20*4882a593Smuzhiyun # ifdef CONFIG_SATA_ULI5288
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun # define SCSI_VEND_ID 0x10b9
23*4882a593Smuzhiyun # define SCSI_DEV_ID 0x5288
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun # elif !defined(CONFIG_SCSI_AHCI_PLAT)
26*4882a593Smuzhiyun # error no scsi device defined
27*4882a593Smuzhiyun # endif
28*4882a593Smuzhiyun # define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
29*4882a593Smuzhiyun # endif
30*4882a593Smuzhiyun #endif
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
33*4882a593Smuzhiyun !defined(CONFIG_DM_SCSI)
34*4882a593Smuzhiyun const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
35*4882a593Smuzhiyun #endif
36*4882a593Smuzhiyun static struct scsi_cmd tempccb; /* temporary scsi command buffer */
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun static unsigned char tempbuff[512]; /* temporary data buffer */
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #if !defined(CONFIG_DM_SCSI)
41*4882a593Smuzhiyun static int scsi_max_devs; /* number of highest available scsi device */
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun static int scsi_curr_dev; /* current device */
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
46*4882a593Smuzhiyun #endif
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /* almost the maximum amount of the scsi_ext command.. */
49*4882a593Smuzhiyun #define SCSI_MAX_READ_BLK 0xFFFF
50*4882a593Smuzhiyun #define SCSI_LBA48_READ 0xFFFFFFF
51*4882a593Smuzhiyun
scsi_print_error(struct scsi_cmd * pccb)52*4882a593Smuzhiyun static void scsi_print_error(struct scsi_cmd *pccb)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun /* Dummy function that could print an error for debugging */
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #ifdef CONFIG_SYS_64BIT_LBA
scsi_setup_read16(struct scsi_cmd * pccb,lbaint_t start,unsigned long blocks)58*4882a593Smuzhiyun void scsi_setup_read16(struct scsi_cmd *pccb, lbaint_t start,
59*4882a593Smuzhiyun unsigned long blocks)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun pccb->cmd[0] = SCSI_READ16;
62*4882a593Smuzhiyun pccb->cmd[1] = pccb->lun << 5;
63*4882a593Smuzhiyun pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff;
64*4882a593Smuzhiyun pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff;
65*4882a593Smuzhiyun pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff;
66*4882a593Smuzhiyun pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff;
67*4882a593Smuzhiyun pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff;
68*4882a593Smuzhiyun pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff;
69*4882a593Smuzhiyun pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff;
70*4882a593Smuzhiyun pccb->cmd[9] = (unsigned char)start & 0xff;
71*4882a593Smuzhiyun pccb->cmd[10] = 0;
72*4882a593Smuzhiyun pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff;
73*4882a593Smuzhiyun pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff;
74*4882a593Smuzhiyun pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff;
75*4882a593Smuzhiyun pccb->cmd[14] = (unsigned char)blocks & 0xff;
76*4882a593Smuzhiyun pccb->cmd[15] = 0;
77*4882a593Smuzhiyun pccb->cmdlen = 16;
78*4882a593Smuzhiyun pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
79*4882a593Smuzhiyun debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n",
80*4882a593Smuzhiyun pccb->cmd[0], pccb->cmd[1],
81*4882a593Smuzhiyun pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
82*4882a593Smuzhiyun pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9],
83*4882a593Smuzhiyun pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun
scsi_setup_read_ext(struct scsi_cmd * pccb,lbaint_t start,unsigned short blocks)87*4882a593Smuzhiyun static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start,
88*4882a593Smuzhiyun unsigned short blocks)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun pccb->cmd[0] = SCSI_READ10;
91*4882a593Smuzhiyun pccb->cmd[1] = pccb->lun << 5;
92*4882a593Smuzhiyun pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
93*4882a593Smuzhiyun pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
94*4882a593Smuzhiyun pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
95*4882a593Smuzhiyun pccb->cmd[5] = (unsigned char)start & 0xff;
96*4882a593Smuzhiyun pccb->cmd[6] = 0;
97*4882a593Smuzhiyun pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff;
98*4882a593Smuzhiyun pccb->cmd[8] = (unsigned char)blocks & 0xff;
99*4882a593Smuzhiyun pccb->cmd[6] = 0;
100*4882a593Smuzhiyun pccb->cmdlen = 10;
101*4882a593Smuzhiyun pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
102*4882a593Smuzhiyun debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
103*4882a593Smuzhiyun pccb->cmd[0], pccb->cmd[1],
104*4882a593Smuzhiyun pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
105*4882a593Smuzhiyun pccb->cmd[7], pccb->cmd[8]);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
scsi_setup_write_ext(struct scsi_cmd * pccb,lbaint_t start,unsigned short blocks)108*4882a593Smuzhiyun static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start,
109*4882a593Smuzhiyun unsigned short blocks)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun pccb->cmd[0] = SCSI_WRITE10;
112*4882a593Smuzhiyun pccb->cmd[1] = pccb->lun << 5;
113*4882a593Smuzhiyun pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
114*4882a593Smuzhiyun pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
115*4882a593Smuzhiyun pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
116*4882a593Smuzhiyun pccb->cmd[5] = (unsigned char)start & 0xff;
117*4882a593Smuzhiyun pccb->cmd[6] = 0;
118*4882a593Smuzhiyun pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff;
119*4882a593Smuzhiyun pccb->cmd[8] = (unsigned char)blocks & 0xff;
120*4882a593Smuzhiyun pccb->cmd[9] = 0;
121*4882a593Smuzhiyun pccb->cmdlen = 10;
122*4882a593Smuzhiyun pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
123*4882a593Smuzhiyun debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
124*4882a593Smuzhiyun __func__,
125*4882a593Smuzhiyun pccb->cmd[0], pccb->cmd[1],
126*4882a593Smuzhiyun pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
127*4882a593Smuzhiyun pccb->cmd[7], pccb->cmd[8]);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
scsi_setup_inquiry(struct scsi_cmd * pccb)130*4882a593Smuzhiyun static void scsi_setup_inquiry(struct scsi_cmd *pccb)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun pccb->cmd[0] = SCSI_INQUIRY;
133*4882a593Smuzhiyun pccb->cmd[1] = pccb->lun << 5;
134*4882a593Smuzhiyun pccb->cmd[2] = 0;
135*4882a593Smuzhiyun pccb->cmd[3] = 0;
136*4882a593Smuzhiyun if (pccb->datalen > 255)
137*4882a593Smuzhiyun pccb->cmd[4] = 255;
138*4882a593Smuzhiyun else
139*4882a593Smuzhiyun pccb->cmd[4] = (unsigned char)pccb->datalen;
140*4882a593Smuzhiyun pccb->cmd[5] = 0;
141*4882a593Smuzhiyun pccb->cmdlen = 6;
142*4882a593Smuzhiyun pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun #ifdef CONFIG_BLK
scsi_read(struct udevice * dev,lbaint_t blknr,lbaint_t blkcnt,void * buffer)146*4882a593Smuzhiyun static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
147*4882a593Smuzhiyun void *buffer)
148*4882a593Smuzhiyun #else
149*4882a593Smuzhiyun static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
150*4882a593Smuzhiyun lbaint_t blkcnt, void *buffer)
151*4882a593Smuzhiyun #endif
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun #ifdef CONFIG_BLK
154*4882a593Smuzhiyun struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
155*4882a593Smuzhiyun struct udevice *bdev = dev->parent;
156*4882a593Smuzhiyun #else
157*4882a593Smuzhiyun struct udevice *bdev = NULL;
158*4882a593Smuzhiyun #endif
159*4882a593Smuzhiyun lbaint_t start, blks;
160*4882a593Smuzhiyun uintptr_t buf_addr;
161*4882a593Smuzhiyun unsigned short smallblks = 0;
162*4882a593Smuzhiyun struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /* Setup device */
165*4882a593Smuzhiyun pccb->target = block_dev->target;
166*4882a593Smuzhiyun pccb->lun = block_dev->lun;
167*4882a593Smuzhiyun buf_addr = (unsigned long)buffer;
168*4882a593Smuzhiyun start = blknr;
169*4882a593Smuzhiyun blks = blkcnt;
170*4882a593Smuzhiyun debug("\nscsi_read: dev %d startblk " LBAF
171*4882a593Smuzhiyun ", blccnt " LBAF " buffer %lx\n",
172*4882a593Smuzhiyun block_dev->devnum, start, blks, (unsigned long)buffer);
173*4882a593Smuzhiyun do {
174*4882a593Smuzhiyun pccb->pdata = (unsigned char *)buf_addr;
175*4882a593Smuzhiyun pccb->dma_dir = DMA_FROM_DEVICE;
176*4882a593Smuzhiyun #ifdef CONFIG_SYS_64BIT_LBA
177*4882a593Smuzhiyun if (start > SCSI_LBA48_READ) {
178*4882a593Smuzhiyun unsigned long blocks;
179*4882a593Smuzhiyun blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK);
180*4882a593Smuzhiyun pccb->datalen = block_dev->blksz * blocks;
181*4882a593Smuzhiyun scsi_setup_read16(pccb, start, blocks);
182*4882a593Smuzhiyun start += blocks;
183*4882a593Smuzhiyun blks -= blocks;
184*4882a593Smuzhiyun } else
185*4882a593Smuzhiyun #endif
186*4882a593Smuzhiyun if (blks > SCSI_MAX_READ_BLK) {
187*4882a593Smuzhiyun pccb->datalen = block_dev->blksz *
188*4882a593Smuzhiyun SCSI_MAX_READ_BLK;
189*4882a593Smuzhiyun smallblks = SCSI_MAX_READ_BLK;
190*4882a593Smuzhiyun scsi_setup_read_ext(pccb, start, smallblks);
191*4882a593Smuzhiyun start += SCSI_MAX_READ_BLK;
192*4882a593Smuzhiyun blks -= SCSI_MAX_READ_BLK;
193*4882a593Smuzhiyun } else {
194*4882a593Smuzhiyun pccb->datalen = block_dev->blksz * blks;
195*4882a593Smuzhiyun smallblks = (unsigned short)blks;
196*4882a593Smuzhiyun scsi_setup_read_ext(pccb, start, smallblks);
197*4882a593Smuzhiyun start += blks;
198*4882a593Smuzhiyun blks = 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun debug("scsi_read_ext: startblk " LBAF
201*4882a593Smuzhiyun ", blccnt %x buffer %" PRIXPTR "\n",
202*4882a593Smuzhiyun start, smallblks, buf_addr);
203*4882a593Smuzhiyun if (scsi_exec(bdev, pccb)) {
204*4882a593Smuzhiyun scsi_print_error(pccb);
205*4882a593Smuzhiyun blkcnt -= blks;
206*4882a593Smuzhiyun break;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun buf_addr += pccb->datalen;
209*4882a593Smuzhiyun } while (blks != 0);
210*4882a593Smuzhiyun debug("scsi_read_ext: end startblk " LBAF
211*4882a593Smuzhiyun ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr);
212*4882a593Smuzhiyun return blkcnt;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /*******************************************************************************
216*4882a593Smuzhiyun * scsi_write
217*4882a593Smuzhiyun */
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* Almost the maximum amount of the scsi_ext command.. */
220*4882a593Smuzhiyun #define SCSI_MAX_WRITE_BLK 0xFFFF
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun #ifdef CONFIG_BLK
scsi_write(struct udevice * dev,lbaint_t blknr,lbaint_t blkcnt,const void * buffer)223*4882a593Smuzhiyun static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
224*4882a593Smuzhiyun const void *buffer)
225*4882a593Smuzhiyun #else
226*4882a593Smuzhiyun static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr,
227*4882a593Smuzhiyun lbaint_t blkcnt, const void *buffer)
228*4882a593Smuzhiyun #endif
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun #ifdef CONFIG_BLK
231*4882a593Smuzhiyun struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
232*4882a593Smuzhiyun struct udevice *bdev = dev->parent;
233*4882a593Smuzhiyun #else
234*4882a593Smuzhiyun struct udevice *bdev = NULL;
235*4882a593Smuzhiyun #endif
236*4882a593Smuzhiyun lbaint_t start, blks;
237*4882a593Smuzhiyun uintptr_t buf_addr;
238*4882a593Smuzhiyun unsigned short smallblks;
239*4882a593Smuzhiyun struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun /* Setup device */
242*4882a593Smuzhiyun pccb->target = block_dev->target;
243*4882a593Smuzhiyun pccb->lun = block_dev->lun;
244*4882a593Smuzhiyun buf_addr = (unsigned long)buffer;
245*4882a593Smuzhiyun start = blknr;
246*4882a593Smuzhiyun blks = blkcnt;
247*4882a593Smuzhiyun debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
248*4882a593Smuzhiyun __func__, block_dev->devnum, start, blks, (unsigned long)buffer);
249*4882a593Smuzhiyun do {
250*4882a593Smuzhiyun pccb->pdata = (unsigned char *)buf_addr;
251*4882a593Smuzhiyun pccb->dma_dir = DMA_TO_DEVICE;
252*4882a593Smuzhiyun if (blks > SCSI_MAX_WRITE_BLK) {
253*4882a593Smuzhiyun pccb->datalen = (block_dev->blksz *
254*4882a593Smuzhiyun SCSI_MAX_WRITE_BLK);
255*4882a593Smuzhiyun smallblks = SCSI_MAX_WRITE_BLK;
256*4882a593Smuzhiyun scsi_setup_write_ext(pccb, start, smallblks);
257*4882a593Smuzhiyun start += SCSI_MAX_WRITE_BLK;
258*4882a593Smuzhiyun blks -= SCSI_MAX_WRITE_BLK;
259*4882a593Smuzhiyun } else {
260*4882a593Smuzhiyun pccb->datalen = block_dev->blksz * blks;
261*4882a593Smuzhiyun smallblks = (unsigned short)blks;
262*4882a593Smuzhiyun scsi_setup_write_ext(pccb, start, smallblks);
263*4882a593Smuzhiyun start += blks;
264*4882a593Smuzhiyun blks = 0;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n",
267*4882a593Smuzhiyun __func__, start, smallblks, buf_addr);
268*4882a593Smuzhiyun if (scsi_exec(bdev, pccb)) {
269*4882a593Smuzhiyun scsi_print_error(pccb);
270*4882a593Smuzhiyun blkcnt -= blks;
271*4882a593Smuzhiyun break;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun buf_addr += pccb->datalen;
274*4882a593Smuzhiyun } while (blks != 0);
275*4882a593Smuzhiyun debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n",
276*4882a593Smuzhiyun __func__, start, smallblks, buf_addr);
277*4882a593Smuzhiyun return blkcnt;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) && \
281*4882a593Smuzhiyun !defined(CONFIG_DM_SCSI)
scsi_init(void)282*4882a593Smuzhiyun void scsi_init(void)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun int busdevfunc = -1;
285*4882a593Smuzhiyun int i;
286*4882a593Smuzhiyun /*
287*4882a593Smuzhiyun * Find a device from the list, this driver will support a single
288*4882a593Smuzhiyun * controller.
289*4882a593Smuzhiyun */
290*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
291*4882a593Smuzhiyun /* get PCI Device ID */
292*4882a593Smuzhiyun #ifdef CONFIG_DM_PCI
293*4882a593Smuzhiyun struct udevice *dev;
294*4882a593Smuzhiyun int ret;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun ret = dm_pci_find_device(scsi_device_list[i].vendor,
297*4882a593Smuzhiyun scsi_device_list[i].device, 0, &dev);
298*4882a593Smuzhiyun if (!ret) {
299*4882a593Smuzhiyun busdevfunc = dm_pci_get_bdf(dev);
300*4882a593Smuzhiyun break;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun #else
303*4882a593Smuzhiyun busdevfunc = pci_find_device(scsi_device_list[i].vendor,
304*4882a593Smuzhiyun scsi_device_list[i].device,
305*4882a593Smuzhiyun 0);
306*4882a593Smuzhiyun #endif
307*4882a593Smuzhiyun if (busdevfunc != -1)
308*4882a593Smuzhiyun break;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun if (busdevfunc == -1) {
312*4882a593Smuzhiyun printf("Error: SCSI Controller(s) ");
313*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
314*4882a593Smuzhiyun printf("%04X:%04X ",
315*4882a593Smuzhiyun scsi_device_list[i].vendor,
316*4882a593Smuzhiyun scsi_device_list[i].device);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun printf("not found\n");
319*4882a593Smuzhiyun return;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun #ifdef DEBUG
322*4882a593Smuzhiyun else {
323*4882a593Smuzhiyun printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
324*4882a593Smuzhiyun scsi_device_list[i].vendor,
325*4882a593Smuzhiyun scsi_device_list[i].device,
326*4882a593Smuzhiyun (busdevfunc >> 16) & 0xFF,
327*4882a593Smuzhiyun (busdevfunc >> 11) & 0x1F,
328*4882a593Smuzhiyun (busdevfunc >> 8) & 0x7);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun #endif
331*4882a593Smuzhiyun bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
332*4882a593Smuzhiyun scsi_low_level_init(busdevfunc);
333*4882a593Smuzhiyun scsi_scan(true);
334*4882a593Smuzhiyun bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun #endif
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /* copy src to dest, skipping leading and trailing blanks
339*4882a593Smuzhiyun * and null terminate the string
340*4882a593Smuzhiyun */
scsi_ident_cpy(unsigned char * dest,unsigned char * src,unsigned int len)341*4882a593Smuzhiyun static void scsi_ident_cpy(unsigned char *dest, unsigned char *src,
342*4882a593Smuzhiyun unsigned int len)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun int start, end;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun start = 0;
347*4882a593Smuzhiyun while (start < len) {
348*4882a593Smuzhiyun if (src[start] != ' ')
349*4882a593Smuzhiyun break;
350*4882a593Smuzhiyun start++;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun end = len-1;
353*4882a593Smuzhiyun while (end > start) {
354*4882a593Smuzhiyun if (src[end] != ' ')
355*4882a593Smuzhiyun break;
356*4882a593Smuzhiyun end--;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun for (; start <= end; start++)
359*4882a593Smuzhiyun *dest ++= src[start];
360*4882a593Smuzhiyun *dest = '\0';
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
scsi_read_capacity(struct udevice * dev,struct scsi_cmd * pccb,lbaint_t * capacity,unsigned long * blksz)363*4882a593Smuzhiyun static int scsi_read_capacity(struct udevice *dev, struct scsi_cmd *pccb,
364*4882a593Smuzhiyun lbaint_t *capacity, unsigned long *blksz)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun *capacity = 0;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun memset(pccb->cmd, '\0', sizeof(pccb->cmd));
369*4882a593Smuzhiyun pccb->cmd[0] = SCSI_RD_CAPAC10;
370*4882a593Smuzhiyun pccb->cmd[1] = pccb->lun << 5;
371*4882a593Smuzhiyun pccb->cmdlen = 10;
372*4882a593Smuzhiyun pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun pccb->datalen = 8;
375*4882a593Smuzhiyun if (scsi_exec(dev, pccb))
376*4882a593Smuzhiyun return 1;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun *capacity = ((lbaint_t)pccb->pdata[0] << 24) |
379*4882a593Smuzhiyun ((lbaint_t)pccb->pdata[1] << 16) |
380*4882a593Smuzhiyun ((lbaint_t)pccb->pdata[2] << 8) |
381*4882a593Smuzhiyun ((lbaint_t)pccb->pdata[3]);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (*capacity != 0xffffffff) {
384*4882a593Smuzhiyun /* Read capacity (10) was sufficient for this drive. */
385*4882a593Smuzhiyun *blksz = ((unsigned long)pccb->pdata[4] << 24) |
386*4882a593Smuzhiyun ((unsigned long)pccb->pdata[5] << 16) |
387*4882a593Smuzhiyun ((unsigned long)pccb->pdata[6] << 8) |
388*4882a593Smuzhiyun ((unsigned long)pccb->pdata[7]);
389*4882a593Smuzhiyun return 0;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /* Read capacity (10) was insufficient. Use read capacity (16). */
393*4882a593Smuzhiyun memset(pccb->cmd, '\0', sizeof(pccb->cmd));
394*4882a593Smuzhiyun pccb->cmd[0] = SCSI_RD_CAPAC16;
395*4882a593Smuzhiyun pccb->cmd[1] = 0x10;
396*4882a593Smuzhiyun pccb->cmdlen = 16;
397*4882a593Smuzhiyun pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun pccb->datalen = 16;
400*4882a593Smuzhiyun pccb->dma_dir = DMA_FROM_DEVICE;
401*4882a593Smuzhiyun if (scsi_exec(dev, pccb))
402*4882a593Smuzhiyun return 1;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun *capacity = ((uint64_t)pccb->pdata[0] << 56) |
405*4882a593Smuzhiyun ((uint64_t)pccb->pdata[1] << 48) |
406*4882a593Smuzhiyun ((uint64_t)pccb->pdata[2] << 40) |
407*4882a593Smuzhiyun ((uint64_t)pccb->pdata[3] << 32) |
408*4882a593Smuzhiyun ((uint64_t)pccb->pdata[4] << 24) |
409*4882a593Smuzhiyun ((uint64_t)pccb->pdata[5] << 16) |
410*4882a593Smuzhiyun ((uint64_t)pccb->pdata[6] << 8) |
411*4882a593Smuzhiyun ((uint64_t)pccb->pdata[7]);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun *blksz = ((uint64_t)pccb->pdata[8] << 56) |
414*4882a593Smuzhiyun ((uint64_t)pccb->pdata[9] << 48) |
415*4882a593Smuzhiyun ((uint64_t)pccb->pdata[10] << 40) |
416*4882a593Smuzhiyun ((uint64_t)pccb->pdata[11] << 32) |
417*4882a593Smuzhiyun ((uint64_t)pccb->pdata[12] << 24) |
418*4882a593Smuzhiyun ((uint64_t)pccb->pdata[13] << 16) |
419*4882a593Smuzhiyun ((uint64_t)pccb->pdata[14] << 8) |
420*4882a593Smuzhiyun ((uint64_t)pccb->pdata[15]);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun return 0;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /*
427*4882a593Smuzhiyun * Some setup (fill-in) routines
428*4882a593Smuzhiyun */
scsi_setup_test_unit_ready(struct scsi_cmd * pccb)429*4882a593Smuzhiyun static void scsi_setup_test_unit_ready(struct scsi_cmd *pccb)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun pccb->cmd[0] = SCSI_TST_U_RDY;
432*4882a593Smuzhiyun pccb->cmd[1] = pccb->lun << 5;
433*4882a593Smuzhiyun pccb->cmd[2] = 0;
434*4882a593Smuzhiyun pccb->cmd[3] = 0;
435*4882a593Smuzhiyun pccb->cmd[4] = 0;
436*4882a593Smuzhiyun pccb->cmd[5] = 0;
437*4882a593Smuzhiyun pccb->cmdlen = 6;
438*4882a593Smuzhiyun pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /**
442*4882a593Smuzhiyun * scsi_init_dev_desc_priv - initialize only SCSI specific blk_desc properties
443*4882a593Smuzhiyun *
444*4882a593Smuzhiyun * @dev_desc: Block device description pointer
445*4882a593Smuzhiyun */
scsi_init_dev_desc_priv(struct blk_desc * dev_desc)446*4882a593Smuzhiyun static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun dev_desc->target = 0xff;
449*4882a593Smuzhiyun dev_desc->lun = 0xff;
450*4882a593Smuzhiyun dev_desc->log2blksz =
451*4882a593Smuzhiyun LOG2_INVALID(typeof(dev_desc->log2blksz));
452*4882a593Smuzhiyun dev_desc->type = DEV_TYPE_UNKNOWN;
453*4882a593Smuzhiyun dev_desc->vendor[0] = 0;
454*4882a593Smuzhiyun dev_desc->product[0] = 0;
455*4882a593Smuzhiyun dev_desc->revision[0] = 0;
456*4882a593Smuzhiyun dev_desc->removable = false;
457*4882a593Smuzhiyun #if !CONFIG_IS_ENABLED(BLK)
458*4882a593Smuzhiyun dev_desc->block_read = scsi_read;
459*4882a593Smuzhiyun dev_desc->block_write = scsi_write;
460*4882a593Smuzhiyun #endif
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun #if !defined(CONFIG_DM_SCSI)
464*4882a593Smuzhiyun /**
465*4882a593Smuzhiyun * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties
466*4882a593Smuzhiyun *
467*4882a593Smuzhiyun * @dev_desc: Block device description pointer
468*4882a593Smuzhiyun * @devnum: Device number
469*4882a593Smuzhiyun */
scsi_init_dev_desc(struct blk_desc * dev_desc,int devnum)470*4882a593Smuzhiyun static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun dev_desc->lba = 0;
473*4882a593Smuzhiyun dev_desc->blksz = 0;
474*4882a593Smuzhiyun dev_desc->if_type = IF_TYPE_SCSI;
475*4882a593Smuzhiyun dev_desc->devnum = devnum;
476*4882a593Smuzhiyun dev_desc->part_type = PART_TYPE_UNKNOWN;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun scsi_init_dev_desc_priv(dev_desc);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun #endif
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun /**
483*4882a593Smuzhiyun * scsi_detect_dev - Detect scsi device
484*4882a593Smuzhiyun *
485*4882a593Smuzhiyun * @target: target id
486*4882a593Smuzhiyun * @lun: target lun
487*4882a593Smuzhiyun * @dev_desc: block device description
488*4882a593Smuzhiyun *
489*4882a593Smuzhiyun * The scsi_detect_dev detects and fills a dev_desc structure when the device is
490*4882a593Smuzhiyun * detected.
491*4882a593Smuzhiyun *
492*4882a593Smuzhiyun * Return: 0 on success, error value otherwise
493*4882a593Smuzhiyun */
scsi_detect_dev(struct udevice * dev,int target,int lun,struct blk_desc * dev_desc)494*4882a593Smuzhiyun static int scsi_detect_dev(struct udevice *dev, int target, int lun,
495*4882a593Smuzhiyun struct blk_desc *dev_desc)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun unsigned char perq, modi;
498*4882a593Smuzhiyun lbaint_t capacity;
499*4882a593Smuzhiyun unsigned long blksz;
500*4882a593Smuzhiyun struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun pccb->target = target;
503*4882a593Smuzhiyun pccb->lun = lun;
504*4882a593Smuzhiyun pccb->pdata = (unsigned char *)&tempbuff;
505*4882a593Smuzhiyun pccb->datalen = 512;
506*4882a593Smuzhiyun pccb->dma_dir = DMA_FROM_DEVICE;
507*4882a593Smuzhiyun scsi_setup_inquiry(pccb);
508*4882a593Smuzhiyun if (scsi_exec(dev, pccb)) {
509*4882a593Smuzhiyun if (pccb->contr_stat == SCSI_SEL_TIME_OUT) {
510*4882a593Smuzhiyun /*
511*4882a593Smuzhiyun * selection timeout => assuming no
512*4882a593Smuzhiyun * device present
513*4882a593Smuzhiyun */
514*4882a593Smuzhiyun debug("Selection timeout ID %d\n",
515*4882a593Smuzhiyun pccb->target);
516*4882a593Smuzhiyun return -ETIMEDOUT;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun scsi_print_error(pccb);
519*4882a593Smuzhiyun return -ENODEV;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun perq = tempbuff[0];
522*4882a593Smuzhiyun modi = tempbuff[1];
523*4882a593Smuzhiyun if ((perq & 0x1f) == 0x1f)
524*4882a593Smuzhiyun return -ENODEV; /* skip unknown devices */
525*4882a593Smuzhiyun if ((modi & 0x80) == 0x80) /* drive is removable */
526*4882a593Smuzhiyun dev_desc->removable = true;
527*4882a593Smuzhiyun /* get info for this device */
528*4882a593Smuzhiyun scsi_ident_cpy((unsigned char *)dev_desc->vendor,
529*4882a593Smuzhiyun &tempbuff[8], 8);
530*4882a593Smuzhiyun scsi_ident_cpy((unsigned char *)dev_desc->product,
531*4882a593Smuzhiyun &tempbuff[16], 16);
532*4882a593Smuzhiyun scsi_ident_cpy((unsigned char *)dev_desc->revision,
533*4882a593Smuzhiyun &tempbuff[32], 4);
534*4882a593Smuzhiyun dev_desc->target = pccb->target;
535*4882a593Smuzhiyun dev_desc->lun = pccb->lun;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun pccb->datalen = 0;
538*4882a593Smuzhiyun scsi_setup_test_unit_ready(pccb);
539*4882a593Smuzhiyun if (scsi_exec(dev, pccb)) {
540*4882a593Smuzhiyun if (dev_desc->removable) {
541*4882a593Smuzhiyun dev_desc->type = perq;
542*4882a593Smuzhiyun goto removable;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun scsi_print_error(pccb);
545*4882a593Smuzhiyun return -EINVAL;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun if (scsi_read_capacity(dev, pccb, &capacity, &blksz)) {
548*4882a593Smuzhiyun scsi_print_error(pccb);
549*4882a593Smuzhiyun return -EINVAL;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun dev_desc->lba = capacity;
552*4882a593Smuzhiyun dev_desc->blksz = blksz;
553*4882a593Smuzhiyun dev_desc->log2blksz = LOG2(dev_desc->blksz);
554*4882a593Smuzhiyun dev_desc->type = perq;
555*4882a593Smuzhiyun removable:
556*4882a593Smuzhiyun return 0;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun /*
560*4882a593Smuzhiyun * (re)-scan the scsi bus and reports scsi device info
561*4882a593Smuzhiyun * to the user if mode = 1
562*4882a593Smuzhiyun */
563*4882a593Smuzhiyun #if defined(CONFIG_DM_SCSI)
do_scsi_scan_one(struct udevice * dev,int id,int lun,bool verbose)564*4882a593Smuzhiyun static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun int ret;
567*4882a593Smuzhiyun struct udevice *bdev;
568*4882a593Smuzhiyun struct blk_desc bd;
569*4882a593Smuzhiyun struct blk_desc *bdesc;
570*4882a593Smuzhiyun char str[10];
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun /*
573*4882a593Smuzhiyun * detect the scsi driver to get information about its geometry (block
574*4882a593Smuzhiyun * size, number of blocks) and other parameters (ids, type, ...)
575*4882a593Smuzhiyun */
576*4882a593Smuzhiyun scsi_init_dev_desc_priv(&bd);
577*4882a593Smuzhiyun if (scsi_detect_dev(dev, id, lun, &bd))
578*4882a593Smuzhiyun return -ENODEV;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun /*
581*4882a593Smuzhiyun * Create only one block device and do detection
582*4882a593Smuzhiyun * to make sure that there won't be a lot of
583*4882a593Smuzhiyun * block devices created
584*4882a593Smuzhiyun */
585*4882a593Smuzhiyun snprintf(str, sizeof(str), "id%dlun%d", id, lun);
586*4882a593Smuzhiyun ret = blk_create_devicef(dev, "scsi_blk", str, IF_TYPE_SCSI, -1,
587*4882a593Smuzhiyun bd.blksz, bd.blksz * bd.lba, &bdev);
588*4882a593Smuzhiyun if (ret) {
589*4882a593Smuzhiyun debug("Can't create device\n");
590*4882a593Smuzhiyun return ret;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun bdesc = dev_get_uclass_platdata(bdev);
594*4882a593Smuzhiyun bdesc->target = id;
595*4882a593Smuzhiyun bdesc->lun = lun;
596*4882a593Smuzhiyun bdesc->removable = bd.removable;
597*4882a593Smuzhiyun bdesc->type = bd.type;
598*4882a593Smuzhiyun memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor));
599*4882a593Smuzhiyun memcpy(&bdesc->product, &bd.product, sizeof(bd.product));
600*4882a593Smuzhiyun memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision));
601*4882a593Smuzhiyun part_init(bdesc);
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun if (verbose) {
604*4882a593Smuzhiyun printf(" Device %d: ", 0);
605*4882a593Smuzhiyun dev_print(bdesc);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun return 0;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
scsi_scan_dev(struct udevice * dev,bool verbose)610*4882a593Smuzhiyun int scsi_scan_dev(struct udevice *dev, bool verbose)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun struct scsi_platdata *uc_plat; /* scsi controller platdata */
613*4882a593Smuzhiyun int ret;
614*4882a593Smuzhiyun int i;
615*4882a593Smuzhiyun int lun;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /* probe SCSI controller driver */
618*4882a593Smuzhiyun ret = device_probe(dev);
619*4882a593Smuzhiyun if (ret)
620*4882a593Smuzhiyun return ret;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun /* Get controller platdata */
623*4882a593Smuzhiyun uc_plat = dev_get_uclass_platdata(dev);
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun for (i = 0; i < uc_plat->max_id; i++)
626*4882a593Smuzhiyun for (lun = 0; lun < uc_plat->max_lun; lun++)
627*4882a593Smuzhiyun do_scsi_scan_one(dev, i, lun, verbose);
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun return 0;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
scsi_scan(bool verbose)632*4882a593Smuzhiyun int scsi_scan(bool verbose)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun struct uclass *uc;
635*4882a593Smuzhiyun struct udevice *dev; /* SCSI controller */
636*4882a593Smuzhiyun int ret;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun if (verbose)
639*4882a593Smuzhiyun printf("scanning bus for devices...\n");
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun blk_unbind_all(IF_TYPE_SCSI);
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun ret = uclass_get(UCLASS_SCSI, &uc);
644*4882a593Smuzhiyun if (ret)
645*4882a593Smuzhiyun return ret;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun uclass_foreach_dev(dev, uc) {
648*4882a593Smuzhiyun ret = scsi_scan_dev(dev, verbose);
649*4882a593Smuzhiyun if (ret)
650*4882a593Smuzhiyun return ret;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun return 0;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun #else
scsi_scan(bool verbose)656*4882a593Smuzhiyun int scsi_scan(bool verbose)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun unsigned char i, lun;
659*4882a593Smuzhiyun int ret;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun if (verbose)
662*4882a593Smuzhiyun printf("scanning bus for devices...\n");
663*4882a593Smuzhiyun for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++)
664*4882a593Smuzhiyun scsi_init_dev_desc(&scsi_dev_desc[i], i);
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun scsi_max_devs = 0;
667*4882a593Smuzhiyun for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
668*4882a593Smuzhiyun for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) {
669*4882a593Smuzhiyun ret = scsi_detect_dev(NULL, i, lun,
670*4882a593Smuzhiyun &scsi_dev_desc[scsi_max_devs]);
671*4882a593Smuzhiyun if (ret)
672*4882a593Smuzhiyun continue;
673*4882a593Smuzhiyun part_init(&scsi_dev_desc[scsi_max_devs]);
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun if (verbose) {
676*4882a593Smuzhiyun printf(" Device %d: ", 0);
677*4882a593Smuzhiyun dev_print(&scsi_dev_desc[scsi_max_devs]);
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun scsi_max_devs++;
680*4882a593Smuzhiyun } /* next LUN */
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun if (scsi_max_devs > 0)
683*4882a593Smuzhiyun scsi_curr_dev = 0;
684*4882a593Smuzhiyun else
685*4882a593Smuzhiyun scsi_curr_dev = -1;
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun printf("Found %d device(s).\n", scsi_max_devs);
688*4882a593Smuzhiyun #ifndef CONFIG_SPL_BUILD
689*4882a593Smuzhiyun env_set_ulong("scsidevs", scsi_max_devs);
690*4882a593Smuzhiyun #endif
691*4882a593Smuzhiyun return 0;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun #endif
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun #ifdef CONFIG_BLK
696*4882a593Smuzhiyun static const struct blk_ops scsi_blk_ops = {
697*4882a593Smuzhiyun .read = scsi_read,
698*4882a593Smuzhiyun .write = scsi_write,
699*4882a593Smuzhiyun };
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun U_BOOT_DRIVER(scsi_blk) = {
702*4882a593Smuzhiyun .name = "scsi_blk",
703*4882a593Smuzhiyun .id = UCLASS_BLK,
704*4882a593Smuzhiyun .ops = &scsi_blk_ops,
705*4882a593Smuzhiyun };
706*4882a593Smuzhiyun #else
707*4882a593Smuzhiyun U_BOOT_LEGACY_BLK(scsi) = {
708*4882a593Smuzhiyun .if_typename = "scsi",
709*4882a593Smuzhiyun .if_type = IF_TYPE_SCSI,
710*4882a593Smuzhiyun .max_devs = CONFIG_SYS_SCSI_MAX_DEVICE,
711*4882a593Smuzhiyun .desc = scsi_dev_desc,
712*4882a593Smuzhiyun };
713*4882a593Smuzhiyun #endif
714