* Code cleanup:
[platform/kernel/u-boot.git] / common / cmd_scsi.c
1 /*
2  * (C) Copyright 2001
3  * Denis Peter, MPL AG Switzerland
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  *
23  *
24  *
25  */
26
27 /*
28  * SCSI support.
29  */
30
31 #include <common.h>
32 #include <command.h>
33 #include <asm/processor.h>
34 #include <scsi.h>
35 #include <image.h>
36 #include <cmd_disk.h>
37 #include <pci.h>
38
39
40 #undef  SCSI_DEBUG
41
42 #ifdef  SCSI_DEBUG
43 #define PRINTF(fmt,args...)     printf (fmt ,##args)
44 #else
45 #define PRINTF(fmt,args...)
46 #endif
47
48 #if (CONFIG_COMMANDS & CFG_CMD_SCSI)
49
50 #ifdef CONFIG_SCSI_SYM53C8XX
51 #define SCSI_VEND_ID    0x1000
52 #ifndef CONFIG_SCSI_DEV_ID
53 #define SCSI_DEV_ID             0x0001
54 #else
55 #define SCSI_DEV_ID             CONFIG_SCSI_DEV_ID
56 #endif
57 #else
58 #error CONFIG_SCSI_SYM53C8XX must be defined
59 #endif
60
61
62 static ccb tempccb;     /* temporary scsi command buffer */
63
64 static unsigned char tempbuff[512]; /* temporary data buffer */
65
66 static int scsi_max_devs; /* number of highest available scsi device */
67
68 static int scsi_curr_dev; /* current device */
69
70 static block_dev_desc_t scsi_dev_desc[CFG_SCSI_MAX_DEVICE];
71
72 /********************************************************************************
73  *  forward declerations of some Setup Routines
74  */
75 void scsi_setup_test_unit_ready(ccb * pccb);
76 void scsi_setup_read_capacity(ccb * pccb);
77 void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks);
78 void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks);
79 void scsi_setup_inquiry(ccb * pccb);
80 void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
81
82
83 ulong scsi_read(int device, ulong blknr, ulong blkcnt, ulong *buffer);
84
85
86 /*********************************************************************************
87  * (re)-scan the scsi bus and reports scsi device info
88  * to the user if mode = 1
89  */
90 void scsi_scan(int mode)
91 {
92         unsigned char i,perq,modi,lun;
93         unsigned long capacity,blksz;
94         ccb* pccb=(ccb *)&tempccb;
95
96         if(mode==1) {
97                 printf("scanning bus for devices...\n");
98         }
99         for(i=0;i<CFG_SCSI_MAX_DEVICE;i++) {
100                 scsi_dev_desc[i].target=0xff;
101                 scsi_dev_desc[i].lun=0xff;
102                 scsi_dev_desc[i].lba=0;
103                 scsi_dev_desc[i].blksz=0;
104                 scsi_dev_desc[i].type=DEV_TYPE_UNKNOWN;
105                 scsi_dev_desc[i].vendor[0]=0;
106                 scsi_dev_desc[i].product[0]=0;
107                 scsi_dev_desc[i].revision[0]=0;
108                 scsi_dev_desc[i].removable=FALSE;
109                 scsi_dev_desc[i].if_type=IF_TYPE_SCSI;
110                 scsi_dev_desc[i].dev=i;
111                 scsi_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
112                 scsi_dev_desc[i].block_read=scsi_read;
113         }
114         scsi_max_devs=0;
115         for(i=0;i<CFG_SCSI_MAX_SCSI_ID;i++) {
116                 pccb->target=i;
117                 for(lun=0;lun<CFG_SCSI_MAX_LUN;lun++) {
118                         pccb->lun=lun;
119                         pccb->pdata=(unsigned char *)&tempbuff;
120                         pccb->datalen=512;
121                         scsi_setup_inquiry(pccb);
122                         if(scsi_exec(pccb)!=TRUE) {
123                                 if(pccb->contr_stat==SCSI_SEL_TIME_OUT) {
124                                         PRINTF("Selection timeout ID %d\n",pccb->target);
125                                         continue; /* selection timeout => assuming no device present */
126                                 }
127                                 scsi_print_error(pccb);
128                                 continue;
129                         }
130                         perq=tempbuff[0];
131                         modi=tempbuff[1];
132                         if((perq & 0x1f)==0x1f) {
133                                 continue; /* skip unknown devices */
134                         }
135                         if((modi&0x80)==0x80) /* drive is removable */
136                                 scsi_dev_desc[scsi_max_devs].removable=TRUE;
137                         /* get info for this device */
138                         scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].vendor[0],&tempbuff[8],8);
139                         scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].product[0],&tempbuff[16],16);
140                         scsi_ident_cpy(&scsi_dev_desc[scsi_max_devs].revision[0],&tempbuff[32],4);
141                         scsi_dev_desc[scsi_max_devs].target=pccb->target;
142                         scsi_dev_desc[scsi_max_devs].lun=pccb->lun;
143
144                         pccb->datalen=0;
145                         scsi_setup_test_unit_ready(pccb);
146                         if(scsi_exec(pccb)!=TRUE) {
147                                 if(scsi_dev_desc[scsi_max_devs].removable==TRUE) {
148                                         scsi_dev_desc[scsi_max_devs].type=perq;
149                                         goto removable;
150                                 }
151                                 scsi_print_error(pccb);
152                                 continue;
153                         }
154                         pccb->datalen=8;
155                         scsi_setup_read_capacity(pccb);
156                         if(scsi_exec(pccb)!=TRUE) {
157                                 scsi_print_error(pccb);
158                                 continue;
159                         }
160                         capacity=((unsigned long)tempbuff[0]<<24)|((unsigned long)tempbuff[1]<<16)|
161                                         ((unsigned long)tempbuff[2]<<8)|((unsigned long)tempbuff[3]);
162                         blksz=((unsigned long)tempbuff[4]<<24)|((unsigned long)tempbuff[5]<<16)|
163                                 ((unsigned long)tempbuff[6]<<8)|((unsigned long)tempbuff[7]);
164                         scsi_dev_desc[scsi_max_devs].lba=capacity;
165                         scsi_dev_desc[scsi_max_devs].blksz=blksz;
166                         scsi_dev_desc[scsi_max_devs].type=perq;
167                         init_part(&scsi_dev_desc[scsi_max_devs]);
168 removable:
169                         if(mode==1) {
170                                 printf ("  Device %d: ", scsi_max_devs);
171                                 dev_print(&scsi_dev_desc[scsi_max_devs]);
172                         } /* if mode */
173                         scsi_max_devs++;
174                 } /* next LUN */
175         }
176         if(scsi_max_devs>0)
177                 scsi_curr_dev=0;
178         else
179                 scsi_curr_dev=-1;
180 }
181
182
183 void scsi_init(void)
184 {
185         int busdevfunc;
186
187         busdevfunc=pci_find_device(SCSI_VEND_ID,SCSI_DEV_ID,0); /* get PCI Device ID */
188         if(busdevfunc==-1) {
189                 printf("Error SCSI Controller (%04X,%04X) not found\n",SCSI_VEND_ID,SCSI_DEV_ID);
190                 return;
191         }
192 #ifdef DEBUG
193         else {
194                 printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",SCSI_VEND_ID,SCSI_DEV_ID,(busdevfunc>>16)&0xFF,(busdevfunc>>11)&0x1F,(busdevfunc>>8)&0x7);
195         }
196 #endif
197         scsi_low_level_init(busdevfunc);
198         scsi_scan(1);
199 }
200
201 block_dev_desc_t * scsi_get_dev(int dev)
202 {
203         return((block_dev_desc_t *)&scsi_dev_desc[dev]);
204 }
205
206
207 /******************************************************************************
208  * scsi boot command intepreter. Derived from diskboot
209  */
210 int do_scsiboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
211 {
212         char *boot_device = NULL;
213         char *ep;
214         int dev, part = 0;
215         ulong cnt;
216         ulong addr;
217         disk_partition_t info;
218         image_header_t *hdr;
219         int rcode = 0;
220
221         switch (argc) {
222         case 1:
223                 addr = CFG_LOAD_ADDR;
224                 boot_device = getenv ("bootdevice");
225                 break;
226         case 2:
227                 addr = simple_strtoul(argv[1], NULL, 16);
228                 boot_device = getenv ("bootdevice");
229                 break;
230         case 3:
231                 addr = simple_strtoul(argv[1], NULL, 16);
232                 boot_device = argv[2];
233                 break;
234         default:
235                 printf ("Usage:\n%s\n", cmdtp->usage);
236                 return 1;
237         }
238
239         if (!boot_device) {
240                 puts ("\n** No boot device **\n");
241                 return 1;
242         }
243
244         dev = simple_strtoul(boot_device, &ep, 16);
245         printf("booting from dev %d\n",dev);
246         if (scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
247                 printf ("\n** Device %d not available\n", dev);
248                 return 1;
249         }
250
251         if (*ep) {
252                 if (*ep != ':') {
253                         puts ("\n** Invalid boot device, use `dev[:part]' **\n");
254                         return 1;
255                 }
256                 part = simple_strtoul(++ep, NULL, 16);
257         }
258         if (get_partition_info (&scsi_dev_desc[dev], part, &info)) {
259                 printf("error reading partinfo\n");
260                 return 1;
261         }
262         if ((strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) &&
263             (strncmp(info.type, BOOT_PART_COMP, sizeof(info.type)) != 0)) {
264                 printf ("\n** Invalid partition type \"%.32s\""
265                         " (expect \"" BOOT_PART_TYPE "\")\n",
266                         info.type);
267                 return 1;
268         }
269
270         printf ("\nLoading from SCSI device %d, partition %d: "
271                 "Name: %.32s  Type: %.32s\n",
272                 dev, part, info.name, info.type);
273
274         PRINTF ("First Block: %ld,  # of blocks: %ld, Block Size: %ld\n",
275                 info.start, info.size, info.blksz);
276
277         if (scsi_read (dev, info.start, 1, (ulong *)addr) != 1) {
278                 printf ("** Read error on %d:%d\n", dev, part);
279                 return 1;
280         }
281
282         hdr = (image_header_t *)addr;
283
284         if (hdr->ih_magic == IH_MAGIC) {
285
286                 print_image_hdr (hdr);
287                 cnt = (hdr->ih_size + sizeof(image_header_t));
288                 cnt += info.blksz - 1;
289                 cnt /= info.blksz;
290                 cnt -= 1;
291         } else {
292                 printf("\n** Bad Magic Number **\n");
293                 return 1;
294         }
295
296         if (scsi_read (dev, info.start+1, cnt,
297                       (ulong *)(addr+info.blksz)) != cnt) {
298                 printf ("** Read error on %d:%d\n", dev, part);
299                 return 1;
300         }
301         /* Loading ok, update default load address */
302         load_addr = addr;
303
304         flush_cache (addr, (cnt+1)*info.blksz);
305
306         /* Check if we should attempt an auto-start */
307         if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
308                 char *local_args[2];
309                 extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
310                 local_args[0] = argv[0];
311                 local_args[1] = NULL;
312                 printf ("Automatic boot of image at addr 0x%08lX ...\n", addr);
313                 rcode = do_bootm (cmdtp, 0, 1, local_args);
314         }
315          return rcode;
316 }
317
318 /*********************************************************************************
319  * scsi command intepreter
320  */
321 int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
322 {
323         switch (argc) {
324     case 0:
325     case 1:     printf ("Usage:\n%s\n", cmdtp->usage);  return 1;
326     case 2:
327                         if (strncmp(argv[1],"res",3) == 0) {
328                                 printf("\nReset SCSI\n");
329                                 scsi_bus_reset();
330                                 scsi_scan(1);
331                                 return 0;
332                         }
333                         if (strncmp(argv[1],"inf",3) == 0) {
334                                 int i;
335                                 for (i=0; i<CFG_SCSI_MAX_DEVICE; ++i) {
336                                         if(scsi_dev_desc[i].type==DEV_TYPE_UNKNOWN)
337                                                 continue; /* list only known devices */
338                                         printf ("SCSI dev. %d:  ", i);
339                                         dev_print(&scsi_dev_desc[i]);
340                                 }
341                                 return 0;
342                         }
343                         if (strncmp(argv[1],"dev",3) == 0) {
344                                 if ((scsi_curr_dev < 0) || (scsi_curr_dev >= CFG_SCSI_MAX_DEVICE)) {
345                                         printf("\nno SCSI devices available\n");
346                                         return 1;
347                                 }
348                                 printf ("\n    Device %d: ", scsi_curr_dev);
349                                 dev_print(&scsi_dev_desc[scsi_curr_dev]);
350                                 return 0;
351                         }
352                         if (strncmp(argv[1],"scan",4) == 0) {
353                                 scsi_scan(1);
354                                 return 0;
355                         }
356                         if (strncmp(argv[1],"part",4) == 0) {
357                                 int dev, ok;
358                                 for (ok=0, dev=0; dev<CFG_SCSI_MAX_DEVICE; ++dev) {
359                                         if (scsi_dev_desc[dev].type!=DEV_TYPE_UNKNOWN) {
360                                                 ok++;
361                                                 if (dev)
362                                                         printf("\n");
363                                                 PRINTF("print_part of %x\n",dev);
364                                                         print_part(&scsi_dev_desc[dev]);
365                                         }
366                                 }
367                                 if (!ok)
368                                         printf("\nno SCSI devices available\n");
369                                 return 1;
370                         }
371                         printf ("Usage:\n%s\n", cmdtp->usage);
372                         return 1;
373         case 3:
374                         if (strncmp(argv[1],"dev",3) == 0) {
375                                 int dev = (int)simple_strtoul(argv[2], NULL, 10);
376                                 printf ("\nSCSI device %d: ", dev);
377                                 if (dev >= CFG_SCSI_MAX_DEVICE) {
378                                         printf("unknown device\n");
379                                         return 1;
380                                 }
381                                 printf ("\n    Device %d: ", dev);
382                                 dev_print(&scsi_dev_desc[dev]);
383                                 if(scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
384                                         return 1;
385                                 }
386                                 scsi_curr_dev = dev;
387                                 printf("... is now current device\n");
388                                 return 0;
389                         }
390                         if (strncmp(argv[1],"part",4) == 0) {
391                                 int dev = (int)simple_strtoul(argv[2], NULL, 10);
392                                 if(scsi_dev_desc[dev].type != DEV_TYPE_UNKNOWN) {
393                                         print_part(&scsi_dev_desc[dev]);
394                                 }
395                                 else {
396                                         printf ("\nSCSI device %d not available\n", dev);
397                                 }
398                                 return 1;
399                         }
400                         printf ("Usage:\n%s\n", cmdtp->usage);
401                         return 1;
402     default:
403                         /* at least 4 args */
404                         if (strcmp(argv[1],"read") == 0) {
405                                 ulong addr = simple_strtoul(argv[2], NULL, 16);
406                                 ulong blk  = simple_strtoul(argv[3], NULL, 16);
407                                 ulong cnt  = simple_strtoul(argv[4], NULL, 16);
408                                 ulong n;
409                                 printf ("\nSCSI read: device %d block # %ld, count %ld ... ",
410                                                 scsi_curr_dev, blk, cnt);
411                                 n = scsi_read(scsi_curr_dev, blk, cnt, (ulong *)addr);
412                                 printf ("%ld blocks read: %s\n",n,(n==cnt) ? "OK" : "ERROR");
413                                 return 0;
414                         }
415         } /* switch */
416         printf ("Usage:\n%s\n", cmdtp->usage);
417         return 1;
418 }
419
420 /****************************************************************************************
421  * scsi_read
422  */
423
424 #define SCSI_MAX_READ_BLK 0xFFFF /* almost the maximum amount of the scsi_ext command.. */
425
426 ulong scsi_read(int device, ulong blknr, ulong blkcnt, ulong *buffer)
427 {
428         ulong start,blks, buf_addr;
429         unsigned short smallblks;
430         ccb* pccb=(ccb *)&tempccb;
431         device&=0xff;
432         /* Setup  device
433          */
434         pccb->target=scsi_dev_desc[device].target;
435         pccb->lun=scsi_dev_desc[device].lun;
436         buf_addr=(unsigned long)buffer;
437         start=blknr;
438         blks=blkcnt;
439         PRINTF("\nscsi_read: dev %d startblk %lx, blccnt %lx buffer %lx\n",device,start,blks,(unsigned long)buffer);
440         do {
441                 pccb->pdata=(unsigned char *)buf_addr;
442                 if(blks>SCSI_MAX_READ_BLK) {
443                         pccb->datalen=scsi_dev_desc[device].blksz * SCSI_MAX_READ_BLK;
444                         smallblks=SCSI_MAX_READ_BLK;
445                         scsi_setup_read_ext(pccb,start,smallblks);
446                         start+=SCSI_MAX_READ_BLK;
447                         blks-=SCSI_MAX_READ_BLK;
448                 }
449                 else {
450                         pccb->datalen=scsi_dev_desc[device].blksz * blks;
451                         smallblks=(unsigned short) blks;
452                         scsi_setup_read_ext(pccb,start,smallblks);
453                         start+=blks;
454                         blks=0;
455                 }
456                 PRINTF("scsi_read_ext: startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
457                 if(scsi_exec(pccb)!=TRUE) {
458                         scsi_print_error(pccb);
459                         blkcnt-=blks;
460                         break;
461                 }
462                 buf_addr+=pccb->datalen;
463         } while(blks!=0);
464         PRINTF("scsi_read_ext: end startblk %lx, blccnt %x buffer %lx\n",start,smallblks,buf_addr);
465         return(blkcnt);
466 }
467
468 /* copy src to dest, skipping leading and trailing blanks
469  * and null terminate the string
470  */
471 void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len)
472 {
473         int start,end;
474
475         start=0;
476         while(start<len) {
477                 if(src[start]!=' ')
478                         break;
479                 start++;
480         }
481         end=len-1;
482         while(end>start) {
483                 if(src[end]!=' ')
484                         break;
485                 end--;
486         }
487         for( ; start<=end; start++) {
488                 *dest++=src[start];
489         }
490         *dest='\0';
491 }
492
493
494 /* Trim trailing blanks, and NUL-terminate string
495  */
496 void scsi_trim_trail (unsigned char *str, unsigned int len)
497 {
498         unsigned char *p = str + len - 1;
499
500         while (len-- > 0) {
501                 *p-- = '\0';
502                 if (*p != ' ') {
503                         return;
504                 }
505         }
506 }
507
508
509 /************************************************************************************
510  * Some setup (fill-in) routines
511  */
512 void scsi_setup_test_unit_ready(ccb * pccb)
513 {
514         pccb->cmd[0]=SCSI_TST_U_RDY;
515         pccb->cmd[1]=pccb->lun<<5;
516         pccb->cmd[2]=0;
517         pccb->cmd[3]=0;
518         pccb->cmd[4]=0;
519         pccb->cmd[5]=0;
520         pccb->cmdlen=6;
521         pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
522 }
523
524 void scsi_setup_read_capacity(ccb * pccb)
525 {
526         pccb->cmd[0]=SCSI_RD_CAPAC;
527         pccb->cmd[1]=pccb->lun<<5;
528         pccb->cmd[2]=0;
529         pccb->cmd[3]=0;
530         pccb->cmd[4]=0;
531         pccb->cmd[5]=0;
532         pccb->cmd[6]=0;
533         pccb->cmd[7]=0;
534         pccb->cmd[8]=0;
535         pccb->cmd[9]=0;
536         pccb->cmdlen=10;
537         pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
538
539 }
540
541 void scsi_setup_read_ext(ccb * pccb, unsigned long start, unsigned short blocks)
542 {
543         pccb->cmd[0]=SCSI_READ10;
544         pccb->cmd[1]=pccb->lun<<5;
545         pccb->cmd[2]=((unsigned char) (start>>24))&0xff;
546         pccb->cmd[3]=((unsigned char) (start>>16))&0xff;
547         pccb->cmd[4]=((unsigned char) (start>>8))&0xff;
548         pccb->cmd[5]=((unsigned char) (start))&0xff;
549         pccb->cmd[6]=0;
550         pccb->cmd[7]=((unsigned char) (blocks>>8))&0xff;
551         pccb->cmd[8]=(unsigned char) blocks & 0xff;
552         pccb->cmd[6]=0;
553         pccb->cmdlen=10;
554         pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
555         PRINTF("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
556                 pccb->cmd[0],pccb->cmd[1],
557                 pccb->cmd[2],pccb->cmd[3],pccb->cmd[4],pccb->cmd[5],
558                 pccb->cmd[7],pccb->cmd[8]);
559 }
560
561 void scsi_setup_read6(ccb * pccb, unsigned long start, unsigned short blocks)
562 {
563         pccb->cmd[0]=SCSI_READ6;
564         pccb->cmd[1]=pccb->lun<<5 | (((unsigned char)(start>>16))&0x1f);
565         pccb->cmd[2]=((unsigned char) (start>>8))&0xff;
566         pccb->cmd[3]=((unsigned char) (start))&0xff;
567         pccb->cmd[4]=(unsigned char) blocks & 0xff;
568         pccb->cmd[5]=0;
569         pccb->cmdlen=6;
570         pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
571         PRINTF("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n",
572                 pccb->cmd[0],pccb->cmd[1],
573                 pccb->cmd[2],pccb->cmd[3],pccb->cmd[4]);
574 }
575
576
577 void scsi_setup_inquiry(ccb * pccb)
578 {
579         pccb->cmd[0]=SCSI_INQUIRY;
580         pccb->cmd[1]=pccb->lun<<5;
581         pccb->cmd[2]=0;
582         pccb->cmd[3]=0;
583         if(pccb->datalen>255)
584                 pccb->cmd[4]=255;
585         else
586                 pccb->cmd[4]=(unsigned char)pccb->datalen;
587         pccb->cmd[5]=0;
588         pccb->cmdlen=6;
589         pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
590 }
591
592 #endif /* #if (CONFIG_COMMANDS & CFG_CMD_SCSI) */