/* FIXME: we also need a CBI_command which sets up the completion * interrupt, and waits for it */ int usb_stor_CB_comdat(ccb *srb, struct us_data *us) { int result = 0; int dir_in,retry; unsigned int pipe; unsigned long status; retry=5; dir_in=US_DIRECTION(srb->cmd[0]); if(dir_in) pipe=usb_rcvbulkpipe(us->pusb_dev, us->ep_in); else pipe=usb_sndbulkpipe(us->pusb_dev, us->ep_out); while(retry--) { USB_STOR_PRINTF("CBI gets a command: Try %d\n",5-retry); #ifdef USB_STOR_DEBUG usb_show_srb(srb); #endif /* let's send the command via the control pipe */ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmd, srb->cmdlen, USB_CNTL_TIMEOUT*5); USB_STOR_PRINTF("CB_transport: control msg returned %d, status %X\n",result,us->pusb_dev->status); /* check the return code for the command */ if (result < 0) { if(us->pusb_dev->status & USB_ST_STALLED) { status=us->pusb_dev->status; USB_STOR_PRINTF(" stall during command found, clear pipe\n"); usb_clear_halt(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0)); us->pusb_dev->status=status; } USB_STOR_PRINTF(" error during command %02X Stat = %X\n",srb->cmd[0],us->pusb_dev->status); return result; } /* transfer the data payload for this command, if one exists*/ USB_STOR_PRINTF("CB_transport: control msg returned %d, direction is %s to go 0x%lx\n",result,dir_in ? "IN" : "OUT",srb->datalen); if (srb->datalen) { result = us_one_transfer(us, pipe, (char *)srb->pdata,srb->datalen); USB_STOR_PRINTF("CBI attempted to transfer data, result is %d status %lX, len %d\n", result,us->pusb_dev->status,us->pusb_dev->act_len); if(!(us->pusb_dev->status & USB_ST_NAK_REC)) break; } /* if (srb->datalen) */ else break; } /* return result */ return result; }
/* * Set up the command for a BBB device. Note that the actual SCSI * command is copied into cbw.CBWCDB. */ static int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) { int result; int actlen; int dir_in; unsigned int pipe; ALLOC_CACHE_ALIGN_BUFFER(umass_bbb_cbw_t, cbw_buf, 1); umass_bbb_cbw_t *cbw = (umass_bbb_cbw_t *)KSEG1ADDR(cbw_buf); dir_in = US_DIRECTION(srb->cmd[0]); #ifdef BBB_COMDAT_TRACE printf("dir %d lun %d cmdlen %d cmd %p datalen %lu pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata); if (srb->cmdlen) { for (result = 0; result < srb->cmdlen; result++) printf("cmd[%d] %#x ", result, srb->cmd[result]); printf("\n"); } #endif /* sanity checks */ if (!(srb->cmdlen <= CBWCDBLENGTH)) { USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n"); return -1; } /* always OUT to the ep */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE); cbw->dCBWTag = cpu_to_le32(CBWTag++); cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen); cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT); cbw->bCBWLUN = srb->lun; cbw->bCDBLength = srb->cmdlen; /* copy the command data into the CBW command data buffer */ /* DST SRC LEN!!! */ memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen); result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT * 5); if (result < 0) USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n"); return result; }
/* * Set up the command for a BBB device. Note that the actual SCSI * command is copied into cbw.CBWCDB. */ int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) { int result; int actlen; int dir_in; unsigned int pipe; umass_bbb_cbw_t cbw; dir_in = US_DIRECTION(srb->cmd[0]); #ifdef BBB_COMDAT_TRACE printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata); if (srb->cmdlen) { for(result = 0; result < srb->cmdlen; result++) printf("cmd[%d] %#x ", result, srb->cmd[result]); printf("\n"); } printf(" us->ep_in %d us->ep_out %d dir_in %d \n", us->ep_in, us->ep_out,dir_in); #endif /* sanity checks */ if (!(srb->cmdlen <= CBWCDBLENGTH)) { USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n"); return -1; } /* always OUT to the ep */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); cbw.dCBWSignature = swap_32(CBWSIGNATURE); cbw.dCBWTag = swap_32(CBWTag++); cbw.dCBWDataTransferLength = swap_32(srb->datalen); cbw.bCBWFlags = (dir_in? CBWFLAGS_IN : CBWFLAGS_OUT); cbw.bCBWLUN = srb->lun; cbw.bCDBLength = srb->cmdlen; /* copy the command data into the CBW command data buffer */ /* DST SRC LEN!!! */ memcpy(cbw.CBWCDB, srb->cmd, 0x10); result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT);//Charles return 0 ; }
int usb_stor_BBB_transport(ccb *srb, struct us_data *us) { int result, retry; int dir_in; int actlen, data_actlen; unsigned int pipe, pipein, pipeout; #ifdef BBB_XPORT_TRACE unsigned char *ptr; int index; #endif dir_in = US_DIRECTION(srb->cmd[0]); /* COMMAND phase */ USB_STOR_PRINTF("COMMAND phase\n"); result = usb_stor_BBB_comdat(srb, us); if (result < 0) { USB_STOR_PRINTF("failed to send CBW status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* DATA phase + error handling */ 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 pipe = pipeout; 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)) { 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) /* continue on to STATUS phase */ goto st; } if (result < 0) { USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } #ifdef BBB_XPORT_TRACE for (index = 0; index < data_actlen; index++) printf("pdata[%d] %#x ", index, srb->pdata[index]); printf("\n"); #endif /* STATUS phase + error handling */ st: 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); /* 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"); /* clear the STALL on the endpoint */ result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in); if (result >= 0 && (retry++ < 1)) /* do a retry */ goto again; } if (result < 0) { USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", us->pusb_dev->status); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } #ifdef BBB_XPORT_TRACE ptr = (unsigned char *)&csw; for (index = 0; index < UMASS_BBB_CSW_SIZE; index++) printf("ptr[%d] %#x ", index, ptr[index]); printf("\n"); #endif /* misuse pipe to get the residue */ pipe = swap_32(csw.dCSWDataResidue); if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0) pipe = srb->datalen - data_actlen; if (CSWSIGNATURE != swap_32(csw.dCSWSignature)) { USB_STOR_PRINTF("!CSWSIGNATURE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if ((CBWTag - 1) != swap_32(csw.dCSWTag)) { USB_STOR_PRINTF("!Tag\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (csw.bCSWStatus > CSWSTATUS_PHASE) { USB_STOR_PRINTF(">PHASE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (csw.bCSWStatus == CSWSTATUS_PHASE) { USB_STOR_PRINTF("=PHASE\n"); usb_stor_BBB_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (data_actlen > srb->datalen) { USB_STOR_PRINTF("transferred %dB instead of %dB\n", data_actlen, srb->datalen); return USB_STOR_TRANSPORT_FAILED; } else if (csw.bCSWStatus == CSWSTATUS_FAILED) { USB_STOR_PRINTF("FAILED\n"); return USB_STOR_TRANSPORT_FAILED; } return result; }
int usb_stor_Bulk_transport(ccb *srb, struct us_data *us) { struct bulk_cb_wrap cbw; struct bulk_cs_wrap csw; int actlen, data_actlen; int result; unsigned int residue; unsigned int pipein = usb_rcvbulkpipe(us->pusb_dev, us->recv_bulk_ep); unsigned int pipeout = usb_sndbulkpipe(us->pusb_dev, us->send_bulk_ep); int dir_in = US_DIRECTION(srb->cmd[0]); srb->trans_bytes = 0; /* set up the command wrapper */ cbw.Signature = cpu_to_le32(US_BULK_CB_SIGN); cbw.DataTransferLength = cpu_to_le32(srb->datalen); cbw.Flags = (dir_in ? US_BULK_FLAG_IN : US_BULK_FLAG_OUT); cbw.Tag = ++cbw_tag; cbw.Lun = srb->lun; cbw.Length = srb->cmdlen; /* copy the command payload */ memcpy(cbw.CDB, srb->cmd, cbw.Length); /* send it to out endpoint */ US_DEBUGP("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n", le32_to_cpu(cbw.Signature), cbw.Tag, le32_to_cpu(cbw.DataTransferLength), cbw.Flags, (cbw.Lun >> 4), (cbw.Lun & 0x0F), cbw.Length); result = usb_bulk_msg(us->pusb_dev, pipeout, &cbw, US_BULK_CB_WRAP_LEN, &actlen, USB_BULK_TO); US_DEBUGP("Bulk command transfer result=%d\n", result); if (result < 0) { usb_stor_Bulk_reset(us); return USB_STOR_TRANSPORT_FAILED; } /* DATA STAGE */ /* send/receive data payload, if there is any */ wait_ms(1); data_actlen = 0; if (srb->datalen) { unsigned int pipe = dir_in ? pipein : pipeout; result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_BULK_TO); US_DEBUGP("Bulk data transfer result 0x%x\n", result); /* special handling of STALL in DATA phase */ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { US_DEBUGP("DATA: stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_Bulk_clear_endpt_stall(us, pipe); } if (result < 0) { US_DEBUGP("Device status: %lx\n", us->pusb_dev->status); usb_stor_Bulk_reset(us); return USB_STOR_TRANSPORT_FAILED; } } /* STATUS phase + error handling */ US_DEBUGP("Attempting to get CSW...\n"); result = usb_bulk_msg(us->pusb_dev, pipein, &csw, US_BULK_CS_WRAP_LEN, &actlen, USB_BULK_TO); /* did the endpoint stall? */ if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { US_DEBUGP("STATUS: stall\n"); /* clear the STALL on the endpoint */ result = usb_stor_Bulk_clear_endpt_stall(us, pipein); if (result >= 0) { US_DEBUGP("Attempting to get CSW...\n"); result = usb_bulk_msg(us->pusb_dev, pipein, &csw, US_BULK_CS_WRAP_LEN, &actlen, USB_BULK_TO); } } if (result < 0) { US_DEBUGP("Device status: %lx\n", us->pusb_dev->status); usb_stor_Bulk_reset(us); return USB_STOR_TRANSPORT_FAILED; } /* check bulk status */ residue = le32_to_cpu(csw.Residue); US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", le32_to_cpu(csw.Signature), csw.Tag, residue, csw.Status); if (csw.Signature != cpu_to_le32(US_BULK_CS_SIGN)) { US_DEBUGP("Bad CSW signature\n"); usb_stor_Bulk_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (csw.Tag != cbw_tag) { US_DEBUGP("Mismatching tag\n"); usb_stor_Bulk_reset(us); return USB_STOR_TRANSPORT_FAILED; } else if (csw.Status >= US_BULK_STAT_PHASE) { US_DEBUGP("Status >= phase\n"); usb_stor_Bulk_reset(us); return USB_STOR_TRANSPORT_ERROR; } else if (residue > srb->datalen) { US_DEBUGP("residue (%uB) > req data (%luB)\n", residue, srb->datalen); return USB_STOR_TRANSPORT_FAILED; } else if (csw.Status == US_BULK_STAT_FAIL) { US_DEBUGP("FAILED\n"); return USB_STOR_TRANSPORT_FAILED; } srb->trans_bytes = min(srb->datalen - residue, (ulong)data_actlen); return 0; }