X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=common%2Fusb_storage.c;h=69d195af605539875fee45da3d87a38458e7b448;hb=2c61f14c60ccc5a1c90205991bf555872887a831;hp=70890361bb0e36934c8751f9036316422eee98f0;hpb=149dded2b178bc0fb62cb6f61b87968d914b580a;p=u-boot diff --git a/common/usb_storage.c b/common/usb_storage.c index 70890361bb..69d195af60 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -1,12 +1,19 @@ /* - * (C) Copyright 2001 - * Denis Peter, MPL AG Switzerland + * Most of this source has been derived from the Linux USB + * project: + * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) + * (c) 1999 Michael Gee (michael@linuxspecific.com) + * (c) 2000 Yggdrasil Computing, Inc. + * + * + * Adapted for U-Boot: + * (C) Copyright 2001 Denis Peter, MPL AG Switzerland * * For BBB support (C) Copyright 2003 * Gary Jennejohn, DENX Software Engineering * - * Most of this source has been derived from the Linux USB - * project. BBB support based on /sys/dev/usb/umass.c from + * BBB support based on /sys/dev/usb/umass.c from * FreeBSD. * * See file CREDITS for list of people who contributed to this @@ -19,7 +26,7 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License @@ -53,10 +60,12 @@ #ifdef CONFIG_USB_STORAGE -#undef USB_STOR_DEBUG +#undef USB_STOR_DEBUG +#undef BBB_COMDAT_TRACE +#undef BBB_XPORT_TRACE #ifdef USB_STOR_DEBUG -#define USB_STOR_PRINTF(fmt,args...) printf (fmt ,##args) +#define USB_STOR_PRINTF(fmt,args...) printf (fmt ,##args) #else #define USB_STOR_PRINTF(fmt,args...) #endif @@ -102,7 +111,7 @@ typedef struct { # define CBWCDBLENGTH 16 __u8 CBWCDB[CBWCDBLENGTH]; } umass_bbb_cbw_t; -#define UMASS_BBB_CBW_SIZE 31 +#define UMASS_BBB_CBW_SIZE 31 static __u32 CBWTag = 0; /* Command Status Wrapper */ @@ -113,13 +122,13 @@ typedef struct { __u32 dCSWDataResidue; __u8 bCSWStatus; # define CSWSTATUS_GOOD 0x0 -# define CSWSTATUS_FAILED 0x1 +# define CSWSTATUS_FAILED 0x1 # define CSWSTATUS_PHASE 0x2 } umass_bbb_csw_t; -#define UMASS_BBB_CSW_SIZE 13 +#define UMASS_BBB_CSW_SIZE 13 #define USB_MAX_STOR_DEV 5 -static int usb_max_devs; /* number of highest available usb device */ +static int usb_max_devs = 0; /* number of highest available usb device */ static block_dev_desc_t usb_dev_desc[USB_MAX_STOR_DEV]; @@ -128,7 +137,7 @@ typedef int (*trans_cmnd)(ccb*, struct us_data*); typedef int (*trans_reset)(struct us_data*); struct us_data { - struct usb_device *pusb_dev; /* this usb_device */ + struct usb_device *pusb_dev; /* this usb_device */ unsigned int flags; /* from filter initially */ unsigned char ifnum; /* interface number */ unsigned char ep_in; /* in endpoint */ @@ -136,14 +145,14 @@ struct us_data { unsigned char ep_int; /* interrupt . */ unsigned char subclass; /* as in overview */ unsigned char protocol; /* .............. */ - unsigned char attention_done; /* force attn on first cmd */ + unsigned char attention_done; /* force attn on first cmd */ unsigned short ip_data; /* interrupt data */ int action; /* what to do */ int ip_wanted; /* needed */ int *irq_handle; /* for USB int requests */ unsigned int irqpipe; /* pipe for release_irq */ unsigned char irqmaxp; /* max packed for irq Pipe */ - unsigned char irqinterval; /* Intervall for IRQ Pipe */ + unsigned char irqinterval; /* Intervall for IRQ Pipe */ ccb *srb; /* current srb */ trans_reset transport_reset; /* reset routine */ trans_cmnd transport; /* transport routine */ @@ -152,7 +161,7 @@ struct us_data { static struct us_data usb_stor[USB_MAX_STOR_DEV]; -#define USB_STOR_TRANSPORT_GOOD 0 +#define USB_STOR_TRANSPORT_GOOD 0 #define USB_STOR_TRANSPORT_FAILED -1 #define USB_STOR_TRANSPORT_ERROR -2 @@ -175,7 +184,24 @@ void usb_show_progress(void) } /********************************************************************************* - * (re)-scan the usb and reports device info + * show info on storage devices; 'usb start/init' must be invoked earlier + * as we only retrieve structures populated during devices initialization + */ +void usb_stor_info(void) +{ + int i; + + if (usb_max_devs > 0) + for (i = 0; i < usb_max_devs; i++) { + printf (" Device %d: ", i); + dev_print(&usb_dev_desc[i]); + } + else + printf("No storage devices, perhaps not 'usb start'ed..?\n"); +} + +/********************************************************************************* + * scan the usb and reports device info * to the user if mode = 1 * returns current device or -1 if no */ @@ -188,7 +214,7 @@ int usb_stor_scan(int mode) memset(usb_stor_buf, 0, sizeof(usb_stor_buf)); if(mode==1) { - printf("scanning bus for storage devices...\n"); + printf(" scanning bus for storage devices... "); } usb_disable_asynch(1); /* asynch transfer not allowed */ @@ -200,6 +226,7 @@ int usb_stor_scan(int mode) usb_dev_desc[i].part_type=PART_TYPE_UNKNOWN; usb_dev_desc[i].block_read=usb_stor_read; } + usb_max_devs=0; for(i=0;i0) return 0; else @@ -365,11 +388,13 @@ static int usb_stor_BBB_reset(struct us_data *us) result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_BBB_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT*5); + if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { USB_STOR_PRINTF("RESET:stall\n"); return -1; } + /* long wait for reset */ wait_ms(150); USB_STOR_PRINTF("BBB_reset result %d: status %X reset\n",result,us->pusb_dev->status); @@ -517,45 +542,47 @@ int usb_stor_CB_comdat(ccb *srb, struct us_data *us) } -int usb_stor_CBI_get_status(ccb *srb, struct us_data *us) +int usb_stor_CBI_get_status (ccb * srb, struct us_data *us) { int timeout; - us->ip_wanted=1; - submit_int_msg(us->pusb_dev,us->irqpipe, - (void *)&us->ip_data,us->irqmaxp ,us->irqinterval); - timeout=1000; - while(timeout--) { - if((volatile int *)us->ip_wanted==0) + us->ip_wanted = 1; + submit_int_msg (us->pusb_dev, us->irqpipe, + (void *) &us->ip_data, us->irqmaxp, us->irqinterval); + timeout = 1000; + while (timeout--) { + if ((volatile int *) us->ip_wanted == 0) break; - wait_ms(10); + wait_ms (10); } if (us->ip_wanted) { - printf(" Did not get interrupt on CBI\n"); + printf (" Did not get interrupt on CBI\n"); us->ip_wanted = 0; return USB_STOR_TRANSPORT_ERROR; } - USB_STOR_PRINTF("Got interrupt data 0x%x, transfered %d status 0x%lX\n", us->ip_data,us->pusb_dev->irq_act_len,us->pusb_dev->irq_status); + USB_STOR_PRINTF + ("Got interrupt data 0x%x, transfered %d status 0x%lX\n", + us->ip_data, us->pusb_dev->irq_act_len, + us->pusb_dev->irq_status); /* UFI gives us ASC and ASCQ, like a request sense */ if (us->subclass == US_SC_UFI) { if (srb->cmd[0] == SCSI_REQ_SENSE || srb->cmd[0] == SCSI_INQUIRY) return USB_STOR_TRANSPORT_GOOD; /* Good */ + else if (us->ip_data) + return USB_STOR_TRANSPORT_FAILED; else - if (us->ip_data) - return USB_STOR_TRANSPORT_FAILED; - else - return USB_STOR_TRANSPORT_GOOD; + return USB_STOR_TRANSPORT_GOOD; } /* otherwise, we interpret the data normally */ switch (us->ip_data) { - case 0x0001: - return USB_STOR_TRANSPORT_GOOD; - case 0x0002: - return USB_STOR_TRANSPORT_FAILED; - default: - return USB_STOR_TRANSPORT_ERROR; - } /* switch */ + case 0x0001: + return USB_STOR_TRANSPORT_GOOD; + case 0x0002: + return USB_STOR_TRANSPORT_FAILED; + default: + return USB_STOR_TRANSPORT_ERROR; + } /* switch */ return USB_STOR_TRANSPORT_ERROR; } @@ -601,11 +628,11 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us) pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* DATA phase + error handling */ - USB_STOR_PRINTF("DATA phase\n"); data_actlen = 0; /* no data, go immediately to the STATUS phase */ if (srb->datalen == 0) goto st; + USB_STOR_PRINTF("DATA phase\n"); if (dir_in) pipe = pipein; else @@ -613,7 +640,7 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us) result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT*5); /* special handling of STALL in DATA phase */ if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { - printf("DATA:stall\n"); + USB_STOR_PRINTF("DATA:stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_BBB_clear_endpt_stall(us, dir_in? us->ep_in : us->ep_out); if (result >= 0) @@ -636,7 +663,9 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us) retry = 0; again: USB_STOR_PRINTF("STATUS phase\n"); - result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); + result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, + &actlen, USB_CNTL_TIMEOUT*5); + /* special handling of STALL in STATUS phase */ if((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED)) { USB_STOR_PRINTF("STATUS:stall\n"); @@ -732,7 +761,7 @@ do_retry: } if((us->protocol==US_PR_CBI) && ((srb->cmd[0]==SCSI_REQ_SENSE) || - (srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */ + (srb->cmd[0]==SCSI_INQUIRY))) { /* do not issue an autorequest after request sense */ USB_STOR_PRINTF("No auto request and good\n"); return USB_STOR_TRANSPORT_GOOD; } @@ -749,7 +778,7 @@ do_retry: USB_STOR_PRINTF("auto request returned %d\n",result); /* if this is an CBI Protocol, get IRQ */ if(us->protocol==US_PR_CBI) { - status=usb_stor_CBI_get_status(psrb,us); + status=usb_stor_CBI_get_status(psrb,us); } if((result<0)&&!(us->pusb_dev->status & USB_ST_STALLED)) { USB_STOR_PRINTF(" AUTO REQUEST ERROR %d\n",us->pusb_dev->status); @@ -765,7 +794,7 @@ do_retry: switch(srb->sense_buf[2]) { case 0x01: /* Recovered Error */ return USB_STOR_TRANSPORT_GOOD; - break; + break; case 0x02: /* Not Ready */ if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) { printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n", @@ -793,7 +822,7 @@ do_retry: static int usb_inquiry(ccb *srb,struct us_data *ss) { int retry,i; - retry=3; + retry=5; do { memset(&srb->cmd[0],0,12); srb->cmd[0]=SCSI_INQUIRY; @@ -817,7 +846,7 @@ static int usb_inquiry(ccb *srb,struct us_data *ss) static int usb_request_sense(ccb *srb,struct us_data *ss) { char *ptr; - return 0; + ptr=srb->pdata; memset(&srb->cmd[0],0,12); srb->cmd[0]=SCSI_REQ_SENSE; @@ -834,7 +863,7 @@ static int usb_request_sense(ccb *srb,struct us_data *ss) static int usb_test_unit_ready(ccb *srb,struct us_data *ss) { - int retries=10; + int retries = 10; do { memset(&srb->cmd[0],0,12); @@ -845,6 +874,8 @@ static int usb_test_unit_ready(ccb *srb,struct us_data *ss) if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) { return 0; } + usb_request_sense (srb, ss); + wait_ms (100); } while(retries--); return -1; @@ -853,7 +884,7 @@ static int usb_test_unit_ready(ccb *srb,struct us_data *ss) static int usb_read_capacity(ccb *srb,struct us_data *ss) { int retry; - retry=2; /* retries */ + retry = 3; /* retries */ do { memset(&srb->cmd[0],0,12); srb->cmd[0]=SCSI_RD_CAPAC; @@ -893,8 +924,12 @@ unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcn unsigned short smallblks; struct usb_device *dev; int retry,i; - ccb *srb=&usb_ccb; - device&=0xff; + ccb *srb = &usb_ccb; + + if (blkcnt == 0) + return 0; + + device &= 0xff; /* Setup device */ USB_STOR_PRINTF("\nusb_read: dev %d \n",device); @@ -962,9 +997,6 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data int protocol = 0; int subclass = 0; - - memset(ss, 0, sizeof(struct us_data)); - /* let's examine the device now */ iface = &dev->config.if_desc[ifnum]; @@ -986,6 +1018,8 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data return 0; } + memset(ss, 0, sizeof(struct us_data)); + /* At this point, we know we've got a live one */ USB_STOR_PRINTF("\n\nUSB Mass Storage device detected\n"); @@ -1026,7 +1060,7 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data ss->transport_reset = usb_stor_BBB_reset; break; default: - printf("USB Starage Transport unknown / not yet implemented\n"); + printf("USB Storage Transport unknown / not yet implemented\n"); return 0; break; } @@ -1069,8 +1103,10 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data /* set class specific stuff */ /* We only handle certain protocols. Currently, these are * the only ones. + * The SFF8070 accepts the requests used in u-boot */ - if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI) { + if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI && + ss->subclass != US_SC_8070) { printf("Sorry, protocol %d not yet supported.\n",ss->subclass); return 0; } @@ -1081,8 +1117,8 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe); dev->irq_handle=usb_stor_irq; - dev->privptr=(void *)ss; } + dev->privptr=(void *)ss; return 1; } @@ -1091,47 +1127,62 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t unsigned char perq,modi; unsigned long cap[2]; unsigned long *capacity,*blksz; - ccb *pccb=&usb_ccb; + ccb *pccb = &usb_ccb; + + /* for some reasons a couple of devices would not survive this reset */ + if ( + /* Sony USM256E */ + (dev->descriptor.idVendor == 0x054c && + dev->descriptor.idProduct == 0x019e) + + || + /* USB007 Mini-USB2 Flash Drive */ + (dev->descriptor.idVendor == 0x066f && + dev->descriptor.idProduct == 0x2010) + ) + USB_STOR_PRINTF("usb_stor_get_info: skipping RESET..\n"); + else + ss->transport_reset(ss); - ss->transport_reset(ss); - pccb->pdata=usb_stor_buf; + pccb->pdata = usb_stor_buf; - dev_desc->target=dev->devnum; - pccb->lun=dev_desc->lun; + dev_desc->target = dev->devnum; + pccb->lun = dev_desc->lun; USB_STOR_PRINTF(" address %d\n",dev_desc->target); if(usb_inquiry(pccb,ss)) return -1; - perq=usb_stor_buf[0]; - modi=usb_stor_buf[1]; - if((perq & 0x1f)==0x1f) { + + perq = usb_stor_buf[0]; + modi = usb_stor_buf[1]; + if((perq & 0x1f) == 0x1f) { return 0; /* skip unknown devices */ } - if((modi&0x80)==0x80) {/* drive is removable */ - dev_desc->removable=1; + if((modi&0x80) == 0x80) {/* drive is removable */ + dev_desc->removable = 1; } memcpy(&dev_desc->vendor[0], &usb_stor_buf[8], 8); memcpy(&dev_desc->product[0], &usb_stor_buf[16], 16); memcpy(&dev_desc->revision[0], &usb_stor_buf[32], 4); - dev_desc->vendor[8]=0; - dev_desc->product[16]=0; - dev_desc->revision[4]=0; + dev_desc->vendor[8] = 0; + dev_desc->product[16] = 0; + dev_desc->revision[4] = 0; USB_STOR_PRINTF("ISO Vers %X, Response Data %X\n",usb_stor_buf[2],usb_stor_buf[3]); if(usb_test_unit_ready(pccb,ss)) { printf("Device NOT ready\n Request Sense returned %02X %02X %02X\n",pccb->sense_buf[2],pccb->sense_buf[12],pccb->sense_buf[13]); - if(dev_desc->removable==1) { - dev_desc->type=perq; + if(dev_desc->removable == 1) { + dev_desc->type = perq; return 1; } else return 0; } - pccb->pdata=(unsigned char *)&cap[0]; + pccb->pdata = (unsigned char *)&cap[0]; memset(pccb->pdata,0,8); - if(usb_read_capacity(pccb,ss)!=0) { + if(usb_read_capacity(pccb,ss) != 0) { printf("READ_CAP ERROR\n"); - cap[0]=2880; - cap[1]=0x200; + cap[0] = 2880; + cap[1] = 0x200; } USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n",cap[0],cap[1]); #if 0 @@ -1151,13 +1202,13 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t (((unsigned long)(cap[1]) & (unsigned long)0xff000000UL) >> 24) )); #endif /* this assumes bigendian! */ - cap[0]+=1; - capacity=&cap[0]; - blksz=&cap[1]; + cap[0] += 1; + capacity = &cap[0]; + blksz = &cap[1]; USB_STOR_PRINTF("Capacity = 0x%lx, blocksz = 0x%lx\n",*capacity,*blksz); - dev_desc->lba=*capacity; - dev_desc->blksz=*blksz; - dev_desc->type=perq; + dev_desc->lba = *capacity; + dev_desc->blksz = *blksz; + dev_desc->type = perq; USB_STOR_PRINTF(" address %d\n",dev_desc->target); USB_STOR_PRINTF("partype: %d\n",dev_desc->part_type);