# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.848 -> 1.849 # drivers/usb/storage/transport.c 1.12 -> 1.13 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/08/14 roland@topspin.com 1.849 # [PATCH] USB storage: get rid of DMA to stack # # Here is the non-controversial part of the patch I posted last week. # It just gets rid of a few places where DMA is done to variables on the # stack. After discussion on lkml, I think we agreed that DMA into the # middle of kmalloc()'ed structs is wrong and should be fixed with # alignment macros. I'll send out a separate patch to do that. # -------------------------------------------- # diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Wed Aug 14 23:17:44 2002 +++ b/drivers/usb/storage/transport.c Wed Aug 14 23:17:44 2002 @@ -1040,10 +1040,15 @@ /* Determine what the maximum LUN supported is */ int usb_stor_Bulk_max_lun(struct us_data *us) { - unsigned char data; + unsigned char *data; int result; int pipe; + data = kmalloc(sizeof *data, GFP_KERNEL); + if (!data) { + return 0; + } + /* issue the command -- use usb_control_msg() because * the state machine is not yet alive */ pipe = usb_rcvctrlpipe(us->pusb_dev, 0); @@ -1051,14 +1056,19 @@ US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, &data, sizeof(data), HZ); + 0, us->ifnum, data, sizeof(data), HZ); US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", - result, data); + result, *data); /* if we have a successful request, return the result */ - if (result == 1) - return data; + if (result == 1) { + result = *data; + kfree(data); + return result; + } else { + kfree(data); + } /* if we get a STALL, clear the stall */ if (result == -EPIPE) { @@ -1077,41 +1087,54 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) { - struct bulk_cb_wrap bcb; - struct bulk_cs_wrap bcs; + struct bulk_cb_wrap *bcb; + struct bulk_cs_wrap *bcs; int result; int pipe; int partial; + int ret = USB_STOR_TRANSPORT_ERROR; + + bcb = kmalloc(sizeof *bcb, in_interrupt() ? GFP_ATOMIC : GFP_NOIO); + if (!bcb) { + return USB_STOR_TRANSPORT_ERROR; + } + bcs = kmalloc(sizeof *bcs, in_interrupt() ? GFP_ATOMIC : GFP_NOIO); + if (!bcs) { + kfree(bcb); + return USB_STOR_TRANSPORT_ERROR; + } /* set up the command wrapper */ - bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); - bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; - bcb.Tag = srb->serial_number; - bcb.Lun = srb->cmnd[1] >> 5; + bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); + bcb->DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); + bcb->Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; + bcb->Tag = srb->serial_number; + bcb->Lun = srb->cmnd[1] >> 5; if (us->flags & US_FL_SCM_MULT_TARG) - bcb.Lun |= srb->target << 4; - bcb.Length = srb->cmd_len; + bcb->Lun |= srb->target << 4; + bcb->Length = srb->cmd_len; /* construct the pipe handle */ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* copy the command payload */ - memset(bcb.CDB, 0, sizeof(bcb.CDB)); - memcpy(bcb.CDB, srb->cmnd, bcb.Length); + memset(bcb->CDB, 0, sizeof(bcb->CDB)); + memcpy(bcb->CDB, srb->cmnd, bcb->Length); /* send it to out endpoint */ US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", - le32_to_cpu(bcb.Signature), bcb.Tag, - (bcb.Lun >> 4), (bcb.Lun & 0x0F), - bcb.DataTransferLength, bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, + le32_to_cpu(bcb->Signature), bcb->Tag, + (bcb->Lun >> 4), (bcb->Lun & 0x0F), + bcb->DataTransferLength, bcb->Flags, bcb->Length); + result = usb_stor_bulk_msg(us, bcb, pipe, US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + if (result == -ENOENT) { + ret = USB_STOR_TRANSPORT_ABORTED; + goto out; + } /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { @@ -1119,25 +1142,30 @@ result = usb_stor_clear_halt(us, pipe); /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + if (result == -ENOENT) { + ret = USB_STOR_TRANSPORT_ABORTED; + goto out; + } result = -EPIPE; } else if (result) { /* unknown error -- we've got a problem */ - return USB_STOR_TRANSPORT_ERROR; + ret = USB_STOR_TRANSPORT_ERROR; + goto out; } /* if the command transfered well, then we go to the data stage */ if (result == 0) { /* send/receive data payload, if there is any */ - if (bcb.DataTransferLength) { + if (bcb->DataTransferLength) { usb_stor_transfer(srb, us); result = srb->result; US_DEBUGP("Bulk data transfer result 0x%x\n", result); /* if it was aborted, we need to indicate that */ - if (result == US_BULK_TRANSFER_ABORTED) - return USB_STOR_TRANSPORT_ABORTED; + if (result == US_BULK_TRANSFER_ABORTED) { + ret = USB_STOR_TRANSPORT_ABORTED; + goto out; + } } } @@ -1150,12 +1178,14 @@ /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, + result = usb_stor_bulk_msg(us, bcs, pipe, US_BULK_CS_WRAP_LEN, &partial); /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + if (result == -ENOENT) { + ret = USB_STOR_TRANSPORT_ABORTED; + goto out; + } /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { @@ -1163,17 +1193,21 @@ result = usb_stor_clear_halt(us, pipe); /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + if (result == -ENOENT) { + ret = USB_STOR_TRANSPORT_ABORTED; + goto out; + } /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, + result = usb_stor_bulk_msg(us, bcs, pipe, US_BULK_CS_WRAP_LEN, &partial); /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; + if (result == -ENOENT) { + ret = USB_STOR_TRANSPORT_ABORTED; + goto out; + } /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { @@ -1181,48 +1215,60 @@ result = usb_stor_clear_halt(us, pipe); /* if the command was aborted, indicate that */ - if (result == -ENOENT) - return USB_STOR_TRANSPORT_ABORTED; - return USB_STOR_TRANSPORT_ERROR; + if (result == -ENOENT) { + ret = USB_STOR_TRANSPORT_ABORTED; + } else { + ret = USB_STOR_TRANSPORT_ERROR; + } + goto out; } } /* if we still have a failure at this point, we're in trouble */ US_DEBUGP("Bulk status result = %d\n", result); if (result) { - return USB_STOR_TRANSPORT_ERROR; + ret = USB_STOR_TRANSPORT_ERROR; + goto out; } /* check bulk status */ US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", - le32_to_cpu(bcs.Signature), bcs.Tag, - bcs.Residue, bcs.Status); - if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || - bcs.Tag != bcb.Tag || - bcs.Status > US_BULK_STAT_PHASE || partial != 13) { + le32_to_cpu(bcs->Signature), bcs->Tag, + bcs->Residue, bcs->Status); + if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) || + bcs->Tag != bcb->Tag || + bcs->Status > US_BULK_STAT_PHASE || partial != 13) { US_DEBUGP("Bulk logical error\n"); - return USB_STOR_TRANSPORT_ERROR; + ret = USB_STOR_TRANSPORT_ERROR; + goto out; } /* based on the status code, we report good or bad */ - switch (bcs.Status) { + switch (bcs->Status) { case US_BULK_STAT_OK: /* command good -- note that data could be short */ - return USB_STOR_TRANSPORT_GOOD; + ret = USB_STOR_TRANSPORT_GOOD; + goto out; case US_BULK_STAT_FAIL: /* command failed */ - return USB_STOR_TRANSPORT_FAILED; + ret = USB_STOR_TRANSPORT_FAILED; + goto out; case US_BULK_STAT_PHASE: /* phase error -- note that a transport reset will be * invoked by the invoke_transport() function */ - return USB_STOR_TRANSPORT_ERROR; + ret = USB_STOR_TRANSPORT_ERROR; + goto out; } /* we should never get here, but if we do, we're in trouble */ - return USB_STOR_TRANSPORT_ERROR; + + out: + kfree(bcb); + kfree(bcs); + return ret; } /***********************************************************************