📄 transport.c
字号:
up(&(us->current_urb_sem)); wait_for_completion(&urb_done); down(&(us->current_urb_sem)); /* return the actual length of the data transferred if no error*/ status = us->current_urb->status; if (status >= 0) status = us->current_urb->actual_length; /* release the lock and return status */ up(&(us->current_urb_sem)); kfree(dr); return status;}/* This is our function to emulate usb_bulk_msg() but give us enough * access to make aborts/resets work */int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, unsigned int len, unsigned int *act_len){ struct completion urb_done; int status; /* set up data structures for the wakeup system */ init_completion(&urb_done); /* lock the URB */ down(&(us->current_urb_sem)); /* fill the URB */ FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len, usb_stor_blocking_completion, &urb_done); us->current_urb->actual_length = 0; us->current_urb->error_count = 0; us->current_urb->transfer_flags = USB_ASYNC_UNLINK; /* submit the URB */ status = usb_submit_urb(us->current_urb); if (status) { /* something went wrong */ up(&(us->current_urb_sem)); return status; } /* wait for the completion of the URB */ up(&(us->current_urb_sem)); wait_for_completion(&urb_done); down(&(us->current_urb_sem)); /* return the actual length of the data transferred */ *act_len = us->current_urb->actual_length; /* release the lock and return status */ up(&(us->current_urb_sem)); return us->current_urb->status;}/* * Transfer one SCSI scatter-gather buffer via bulk transfer * * Note that this function is necessary because we want the ability to * use scatter-gather memory. Good performance is achieved by a combination * of scatter-gather and clustering (which makes each chunk bigger). * * Note that the lower layer will always retry when a NAK occurs, up to the * timeout limit. Thus we don't have to worry about it for individual * packets. */int usb_stor_transfer_partial(struct us_data *us, char *buf, int length){ int result; int partial; int pipe; /* calculate the appropriate pipe information */ if (us->srb->sc_data_direction == SCSI_DATA_READ) pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); else pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* transfer the data */ US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length); result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n", result, partial, length); /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); usb_stor_clear_halt(us->pusb_dev, pipe); } /* did we send all the data? */ if (partial == length) { US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n"); return US_BULK_TRANSFER_GOOD; } /* uh oh... we have an error code, so something went wrong. */ if (result) { /* NAK - that means we've retried a few times already */ if (result == -ETIMEDOUT) { US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); return US_BULK_TRANSFER_FAILED; } /* -ENOENT -- we canceled this transfer */ if (result == -ENOENT) { US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); return US_BULK_TRANSFER_ABORTED; } /* the catch-all case */ US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); return US_BULK_TRANSFER_FAILED; } /* no error code, so we must have transferred some data, * just not all of it */ return US_BULK_TRANSFER_SHORT;}/* * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us){ int i; int result = -1; struct scatterlist *sg; unsigned int total_transferred = 0; unsigned int transfer_amount; /* calculate how much we want to transfer */ transfer_amount = usb_stor_transfer_length(srb); /* was someone foolish enough to request more data than available * buffer space? */ if (transfer_amount > srb->request_bufflen) transfer_amount = srb->request_bufflen; /* are we scatter-gathering? */ if (srb->use_sg) { /* loop over all the scatter gather structures and * make the appropriate requests for each, until done */ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) { /* transfer the lesser of the next buffer or the * remaining data */ if (transfer_amount - total_transferred >= sg[i].length) { result = usb_stor_transfer_partial(us, sg[i].address, sg[i].length); total_transferred += sg[i].length; } else result = usb_stor_transfer_partial(us, sg[i].address, transfer_amount - total_transferred); /* if we get an error, end the loop here */ if (result) break; } } else /* no scatter-gather, just make the request */ result = usb_stor_transfer_partial(us, srb->request_buffer, transfer_amount); /* return the result in the data structure itself */ srb->result = result;}/*********************************************************************** * Transport routines ***********************************************************************//* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and recieve the response. */void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us){ int need_auto_sense; int result; /* send the command to the transport layer */ result = us->transport(srb, us); /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ if (result == USB_STOR_TRANSPORT_ABORTED) { US_DEBUGP("-- transport indicates command was aborted\n"); srb->result = DID_ABORT << 16; return; } /* Determine if we need to auto-sense * * I normally don't use a flag like this, but it's almost impossible * to understand what's going on here if I don't. */ need_auto_sense = 0; /* * If we're running the CB transport, which is incapable * of determining status on it's own, we need to auto-sense almost * every time. */ if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; /* There are some exceptions to this. Notably, if this is * a UFI device and the command is REQUEST_SENSE or INQUIRY, * then it is impossible to truly determine status. */ if (us->subclass == US_SC_UFI && ((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY))) { US_DEBUGP("** no auto-sense for a special command\n"); need_auto_sense = 0; } } /* * If we have an error, we're going to do a REQUEST_SENSE * automatically. Note that we differentiate between a command * "failure" and an "error" in the transport mechanism. */ if (result == USB_STOR_TRANSPORT_FAILED) { US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; } if (result == USB_STOR_TRANSPORT_ERROR) { us->transport_reset(us); US_DEBUGP("-- transport indicates transport failure\n"); need_auto_sense = 0; srb->result = DID_ERROR << 16; return; } /* * Also, if we have a short transfer on a command that can't have * a short transfer, we're going to do this. */ if ((srb->result == US_BULK_TRANSFER_SHORT) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { US_DEBUGP("-- unexpectedly short transfer\n"); need_auto_sense = 1; } /* Now, if we need to do the auto-sense, let's do it */ if (need_auto_sense) { int temp_result; void* old_request_buffer; unsigned short old_sg; unsigned old_request_bufflen; unsigned char old_sc_data_direction; unsigned char old_cmnd[MAX_COMMAND_SIZE]; US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); /* save the old command */ memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE); /* set the command and the LUN */ srb->cmnd[0] = REQUEST_SENSE; srb->cmnd[1] = old_cmnd[1] & 0xE0; srb->cmnd[2] = 0; srb->cmnd[3] = 0; srb->cmnd[4] = 18; srb->cmnd[5] = 0; /* set the transfer direction */ old_sc_data_direction = srb->sc_data_direction; srb->sc_data_direction = SCSI_DATA_READ; /* use the new buffer we have */ old_request_buffer = srb->request_buffer; srb->request_buffer = srb->sense_buffer; /* set the buffer length for transfer */ old_request_bufflen = srb->request_bufflen; srb->request_bufflen = 18; /* set up for no scatter-gather use */ old_sg = srb->use_sg; srb->use_sg = 0; /* issue the auto-sense command */ temp_result = us->transport(us->srb, us); if (temp_result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("-- auto-sense failure\n"); /* we skip the reset if this happens to be a * multi-target device, since failure of an * auto-sense is perfectly valid */ if (!(us->flags & US_FL_SCM_MULT_TARG)) { us->transport_reset(us); } srb->result = DID_ERROR << 16; return; } US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", srb->sense_buffer[0], srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]);#ifdef CONFIG_USB_STORAGE_DEBUG usb_stor_show_sense( srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]);#endif /* set the result so the higher layers expect this data */ srb->result = CHECK_CONDITION << 1; /* we're done here, let's clean up */ srb->request_buffer = old_request_buffer; srb->request_bufflen = old_request_bufflen; srb->use_sg = old_sg; srb->sc_data_direction = old_sc_data_direction; memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) srb->result = GOOD << 1; } else /* if (need_auto_sense) */ srb->result = GOOD << 1; /* Regardless of auto-sense, if we _know_ we have an error * condition, show that in the result code */ if (result == USB_STOR_TRANSPORT_FAILED) srb->result = CHECK_CONDITION << 1; /* If we think we're good, then make sure the sense data shows it. * This is necessary because the auto-sense for some devices always * sets byte 0 == 0x70, even if there is no error */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && (result == USB_STOR_TRANSPORT_GOOD) && ((srb->sense_buffer[2] & 0xf) == 0x0)) srb->sense_buffer[0] = 0x0;}/* * Control/Bulk/Interrupt transport *//* The interrupt handler for CBI devices */void usb_stor_CBI_irq(struct urb *urb){ struct us_data *us = (struct us_data *)urb->context; US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no); US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length); US_DEBUGP("-- IRQ state is %d\n", urb->status); US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n", us->irqbuf[0], us->irqbuf[1]); /* reject improper IRQs */ if (urb->actual_length != 2) { US_DEBUGP("-- IRQ too short\n"); return; } /* is the device removed? */ if (urb->status == -ENOENT) { US_DEBUGP("-- device has been removed\n"); return; } /* was this a command-completion interrupt? */ if (us->irqbuf[0] && (us->subclass != US_SC_UFI)) { US_DEBUGP("-- not a command-completion IRQ\n"); return; } /* was this a wanted interrupt? */ if (!atomic_read(us->ip_wanted)) { US_DEBUGP("ERROR: Unwanted interrupt received!\n"); return; } /* adjust the flag */ atomic_set(us->ip_wanted, 0); /* copy the valid data */ us->irqdata[0] = us->irqbuf[0]; us->irqdata[1] = us->irqbuf[1]; /* wake up the command thread */ US_DEBUGP("-- Current value of ip_waitq is: %d\n", atomic_read(&us->ip_waitq.count)); up(&(us->ip_waitq));}int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us){ int result; /* Set up for status notification */ atomic_set(us->ip_wanted, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -