Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754739Ab0LJKwb (ORCPT ); Fri, 10 Dec 2010 05:52:31 -0500 Received: from web31816.mail.mud.yahoo.com ([68.142.206.169]:35062 "HELO web31816.mail.mud.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1754444Ab0LJKw1 convert rfc822-to-8bit (ORCPT ); Fri, 10 Dec 2010 05:52:27 -0500 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.com; h=Message-ID:X-YMail-OSG:Received:X-Mailer:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type:Content-Transfer-Encoding; b=o6cSQLyF0ri+v36ikZqGcyIseFE7Edg9guN0KyzOR0+ZLvIPCs0TzleIPEx2mLY7KCGEC/rcDBSuuCPIjbCRDWre9oWTos8BXL1XH2cl2nyfMPJffjgpZHZ/6qrAMsPxRleoV//xQrUul4qy/WjuqgpJzE5rQlk8f+mjgFiV4Vs=; Message-ID: <681149.61182.qm@web31816.mail.mud.yahoo.com> X-YMail-OSG: oeVvXwwVM1mIGHWQXzRZ1uKOggGk3YNBOk49uml4ZEaxGUf 11Ou7Hg5_ X-Mailer: YahooMailClassic/11.4.20 YahooMailWebService/0.8.107.289296 Date: Fri, 10 Dec 2010 02:52:24 -0800 (PST) From: Luben Tuikov Reply-To: ltuikov@yahoo.com Subject: Re: [PATCH] [USB] UAS: Achitecture; TMF; more To: Greg KH , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Matthew Wilcox MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8BIT Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 49566 Lines: 2052 Patch retracted for this still-born driver. Instead please use superior uasp.c which was recently submitted. --- On Fri, 11/5/10, Luben Tuikov wrote: > From: Luben Tuikov > Subject: [PATCH] [USB] UAS: Achitecture; TMF; more > To: "Greg KH" , linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, "Matthew Wilcox" > Date: Friday, November 5, 2010, 9:46 PM > * Fix sense IU layout > > * Command delivery to the service delivery subsystem > should > ???be an atomic transaction. Fix this in > this driver by > ???removing the work thread which retried > allocating and > ???sending urbs. First allocate the urbs > we'll need up > ???front; second recycle them > (sense<-RRIU in High-Speed > ???UAS); third if any operation with the SDS > fails, report > ???this to the application client. > > * Rename uas_dev_info->uas_tport_info to more > correctly > ???portray the capabilities of the target > port. Decouple > ???that from the sdev structure as it now > has a uas_lu_info > ???(new) which assists in TMF processing and > error > ???recovery. So now uas_cmd_info lives in > scsi_cmd; > ???uas_lu_info lives in scsi_device and > uas_tport_info lives > ???in scsi_host. > > * Redo uas_sense. Make it more general and print a more > ???informative message if the sense data > were short. > > * uas_xfer_data for High-Speed doesn't retry but fails if > ???the SDS is down. This means that we > cannot reach the > ???target port, so we let error recovery > kick in. > > * Add common urb initializers/fillers for the command and > ???status pipe. This generalizes output > transactions on the > ???command pipe to always free the urb and > the buffer, and > ???input transactions on the status pipe to > always have a > ???buffer holding the max size of struct > sense_iu and > ???complete in the same place, > uas_stat_cmplt, in order to > ???accommodate both High-Speed devices and > SuperSpeed > ???(USB3.0) devices. > > * Gracefully free the urbs if the SDS is down or we have > no > ???memory for all urbs, at queuecommand > entry. > > * Fix a shortcoming of SCSI Core where some commands > coming > ???into the driver are NOT tagged and some > are tagged. The > ???SDS (UAS) needs everything to be tagged > and tagged > ???correctly. Use tag 1 for untagged > commands and tags 2 to > ???FFEFh for tagged commands. In practice we > use much less > ???and target ports will report much less > than that. > > * If the target port is SuperSpeed request a macro > defined > ???number of streams (128) for this I_T > nexus. Target ports > ???will report less. If usb_alloc_streams > complains, we know > ???we can handle at least one stream. Else > if the port is > ???High-Speed, set the number of tags we use > to some sane > ???value (32). Else the desired number of > tags is set. > > * Implement TMF. All TMFs are supported. As we're not in > ???control of the tags, nor can we, at the > time of this > ???commit, request a free tag from the block > layer, we > ???allocate tags for TMFs with range [130, > 1153] > ???(130+1024-1), as an increasing sequence. > > Signed-off-by: Luben Tuikov > --- > > This patch changes 86% of the driver. More is to come, but > this is > a self-contained patch so it can be applied. > > drivers/usb/storage/uas.c |? 970 > ++++++++++++++++++++++++++++++--------------- > 1 files changed, 656 insertions(+), 314 deletions(-) > > diff --git a/drivers/usb/storage/uas.c > b/drivers/usb/storage/uas.c > index ef6e707..ed1a82f 100644 > --- a/drivers/usb/storage/uas.c > +++ b/drivers/usb/storage/uas.c > @@ -4,6 +4,7 @@ > ? * > ? * Copyright Matthew Wilcox for Intel Corp, 2010 > ? * Copyright Sarah Sharp for Intel Corp, 2010 > + * Copyright Luben Tuikov, 2010 > ? * > ? * Distributed under the terms of the GNU GPL, > version two. > ? */ > @@ -13,6 +14,7 @@ > #include > #include > #include > +#include > > #include > #include > @@ -29,12 +31,18 @@ > #define UAS_DPRINTK(fmt, ...) > #endif > > +/* Define the number of streams to ask to allocate, > essentially > + * the maximum number of tags which we are asking to be > able to send > + * to the device.? Devices may report much less. > + */ > +#define UAS_MAX_STREAMS??? 128 > + > /* Common header for all IUs */ > struct iu { > ??? __u8 iu_id; > ??? __u8 rsvd1; > ??? __be16 tag; > -}; > +} __packed; > > enum { > ??? IU_ID_COMMAND??? > ??? = 0x01, > @@ -55,7 +63,7 @@ struct command_iu { > ??? __u8 rsvd7; > ??? struct scsi_lun lun; > ??? __u8 cdb[16];??? /* XXX: > Overflow-checking tools may misunderstand */ > -}; > +} __packed; > > struct sense_iu { > ??? __u8 iu_id; > @@ -63,11 +71,12 @@ struct sense_iu { > ??? __be16 tag; > ??? __be16 status_qual; > ??? __u8 status; > -??? __u8 service_response; > -??? __u8 rsvd8[6]; > +??? __u8 rsvd8[7]; > ??? __be16 len; > ??? __u8 sense[SCSI_SENSE_BUFFERSIZE]; > -}; > +} __packed; > + > +#define SENSE_IU_SIZE??? sizeof(struct > sense_iu) > > /* > ? * The r00-r01c specs define this version of the > SENSE IU data structure. > @@ -81,6 +90,56 @@ struct sense_iu_old { > ??? __u8 status; > ??? __u8 service_response; > ??? __u8 sense[SCSI_SENSE_BUFFERSIZE]; > +} __packed; > + > +struct tmf_iu { > +??? __u8??? iu_id; > +??? __u8? ? rsvd1; > +??? __be16??? tag; > +??? __u8??? tmf; > +??? __u8??? rsvd5; > +??? __u16??? ttbm; > +??? struct scsi_lun lun; > +} __packed; > + > +enum { > +??? TMF_ABORT_TASK = 1, > +??? TMF_ABORT_TASK_SET = 2, > +??? TMF_CLEAR_TASK_SET = 4, > +??? TMF_LU_RESET = 8, > +??? TMF_IT_NEXUS_RESET = 0x10, > +??? TMF_CLEAR_ACA = 0x40, > +??? TMF_QUERY_TASK = 0x80, > +??? TMF_QUERY_TASK_SET = 0x81, > +??? TMF_QUERY_ASYNC_EVENT = 0x82, > +}; > + > +struct resp_iu { > +??? __u8??? iu_id; > +??? __u8? ? rsvd1; > +??? __be16??? tag; > +??? __be32??? resp; > +} __packed; > + > +#define TMR_RESPONSE_CODE_MASK??? 0xFF > +#define TMR_RESPONSE_CODE_SHIFT 0 > +#define TMR_RESPONSE_INFO_MASK? 0xFFFFFF00 > +#define TMR_RESPONSE_INFO_SHIFT 8 > + > +#define TMR_RESPONSE_CODE(__Val)??? > ??? ??? ??? > ??? \ > +??? (((__Val) & TMR_RESPONSE_CODE_MASK) > >> TMR_RESPONSE_CODE_SHIFT) > + > +#define TMR_RESPONSE_INFO(__Val)??? > ??? ??? ??? > ??? \ > +??? (((__Val) & TMR_RESPONSE_INFO_MASK) > >> TMR_RESPONSE_INFO_SHIFT) > + > +enum tmf_resp_code { > +??? TMR_COMPLETE??? = 0, > +??? TMR_IIU??? > ??? = 2, > +??? TMR_UNSUPP??? = 4, > +??? TMR_FAILED??? = 5, > +??? TMR_SUCC??? = 8, > +??? TMR_ILUN??? = 9, > +??? TMR_OLAP??? = 0xA, > }; > > enum { > @@ -95,89 +154,73 @@ enum { > ??? UAS_ACA??? > ??? ??? = 4, > }; > > -struct uas_dev_info { > +/* Lives in the SCSI host, hostdata points to it. > + */ > +struct uas_tport_info { > ??? struct usb_interface *intf; > ??? struct usb_device *udev; > -??? int qdepth; > +??? int num_tags; > ??? unsigned cmd_pipe, status_pipe, > data_in_pipe, data_out_pipe; > ??? unsigned use_streams:1; > ??? unsigned uas_sense_old:1; > }; > > -enum { > -??? ALLOC_STATUS_URB??? = (1 > << 0), > -??? SUBMIT_STATUS_URB??? = > (1 << 1), > -??? ALLOC_DATA_IN_URB??? = > (1 << 2), > -??? SUBMIT_DATA_IN_URB??? = > (1 << 3), > -??? ALLOC_DATA_OUT_URB??? = > (1 << 4), > -??? SUBMIT_DATA_OUT_URB??? = > (1 << 5), > -??? ALLOC_CMD_URB??? > ??? = (1 << 6), > -??? SUBMIT_CMD_URB??? > ??? = (1 << 7), > +/* Lives in the scsi device, hostdata points to it. > + */ > +struct uas_lu_info { > +??? struct completion tmf_completion; > +??? struct resp_iu resp; > +??? struct urb *freed_urb; > }; > > -/* Overrides scsi_pointer */ > +/* Lives in the scsi command, overrides SCp. > + */ > struct uas_cmd_info { > -??? unsigned int state; > -??? unsigned int stream; > +??? int tag; > ??? struct urb *cmd_urb; > ??? struct urb *status_urb; > ??? struct urb *data_in_urb; > ??? struct urb *data_out_urb; > -??? struct list_head list; > }; > > -static int uas_submit_urbs(struct scsi_cmnd *cmnd, > -??? ??? ??? > ??? struct uas_dev_info *devinfo, gfp_t > gfp); > +#define UAS_CMD_INFO(__Scmd) ((struct uas_cmd_info > *)(&(__Scmd)->SCp)) > +#define UAS_TPORT_INFO(__Scmd) \ > +??? ((struct uas_tport_info > *)((__Scmd)->device->host->hostdata[0])) > +#define SDEV_TPORT_INFO(__Sdev)? \ > +??? ((struct uas_tport_info > *)((__Sdev)->host->hostdata[0])) > > -static DEFINE_SPINLOCK(uas_work_lock); > -static LIST_HEAD(uas_work_list); > +#define SDEV_LU_INFO(__Sdev) ((struct uas_lu_info > *)((__Sdev)->hostdata)) > > -static void uas_do_work(struct work_struct *work) > -{ > -??? struct uas_cmd_info *cmdinfo; > -??? struct list_head list; > -??? int res; > - > -??? spin_lock_irq(&uas_work_lock); > -??? list_replace_init(&uas_work_list, > &list); > -??? spin_unlock_irq(&uas_work_lock); > - > -??? list_for_each_entry(cmdinfo, &list, > list) { > -??? ??? struct scsi_pointer > *scp = (void *)cmdinfo; > -??? ??? struct scsi_cmnd > *cmnd = container_of(scp, > -??? ??? ??? > ??? ??? ??? > ? ? ? struct scsi_cmnd, SCp); > -??? ??? res = > uas_submit_urbs(cmnd, cmnd->device->hostdata, > GFP_KERNEL); > -??? ??? UAS_DPRINTK("%s: > cmd:%p, res:%d, state:0x%x\n", __FUNCTION__, > -??? ??? ??? > ? ? cmnd, res, cmdinfo->state); > -??? } > -} > - > -static DECLARE_WORK(uas_work, uas_do_work); > +/* ---------- IU processors ---------- */ > > -static void uas_sense(struct urb *urb, struct scsi_cmnd > *cmnd) > +static void uas_sense(struct urb *urb, struct scsi_cmnd > *cmd) > { > ??? struct sense_iu *sense_iu = > urb->transfer_buffer; > -??? struct scsi_device *sdev = > cmnd->device; > +??? struct scsi_device *sdev = > cmd->device; > + > +??? cmd->result = sense_iu->status; > > ??? if (urb->actual_length > 16) { > -??? ??? unsigned len = > be16_to_cpup(&sense_iu->len); > -??? ??? if (len + 16 != > urb->actual_length) { > -??? ??? ??? > int newlen = min(len + 16, urb->actual_length) - 16; > -??? ??? ??? > if (newlen < 0) > -??? ??? ??? > ??? newlen = 0; > -??? ??? ??? > sdev_printk(KERN_INFO, sdev, "%s: urb length %d " > -??? ??? ??? > ??? "disagrees with IU sense data length %d, > " > -??? ??? ??? > ??? "using %d bytes of sense data\n", > __func__, > -??? ??? ??? > ??? ??? urb->actual_length, > len, newlen); > -??? ??? ??? > len = newlen; > +??? ??? unsigned slen = > be16_to_cpup(&sense_iu->len); > + > +??? ??? if > (urb->actual_length >= 16 + slen) { > +??? ??? ??? > slen = min(slen, (unsigned) SCSI_SENSE_BUFFERSIZE); > +??? ??? } else { > +??? ??? ??? > unsigned dlen = slen; > + > +??? ??? ??? > slen = min(urb->actual_length - 16, > +??? ??? ??? > ??? ???(unsigned) > SCSI_SENSE_BUFFERSIZE); > + > +??? ??? ??? > sdev_printk(KERN_INFO, sdev, > +??? ??? ??? > ??? ? ? "%s: short SENSE IU by %d > bytes, " > +??? ??? ??? > ??? ? ? "using %d/%d bytes of sense > data\n", > +??? ??? ??? > ??? ? ? __func__, 16 + slen - > urb->actual_length, > +??? ??? ??? > ??? ? ? slen, dlen); > ??? ??? } > -??? ??? > memcpy(cmnd->sense_buffer, sense_iu->sense, len); > +??? ??? > memcpy(cmd->sense_buffer, sense_iu->sense, slen); > ??? } > - > -??? cmnd->result = sense_iu->status; > -??? if (sdev->current_cmnd) > -??? ??? > sdev->current_cmnd = NULL; > -??? cmnd->scsi_done(cmnd); > +??? sdev->current_cmnd = NULL; > +??? cmd->scsi_done(cmd); > ??? usb_free_urb(urb); > } > > @@ -200,73 +243,105 @@ static void uas_sense_old(struct urb > *urb, struct scsi_cmnd *cmnd) > ??? ??? } > ??? ??? > memcpy(cmnd->sense_buffer, sense_iu->sense, len); > ??? } > - > ??? cmnd->result = sense_iu->status; > -??? if (sdev->current_cmnd) > -??? ??? > sdev->current_cmnd = NULL; > +??? sdev->current_cmnd = NULL; > ??? cmnd->scsi_done(cmnd); > ??? usb_free_urb(urb); > } > > -static void uas_xfer_data(struct urb *urb, struct > scsi_cmnd *cmnd, > -??? ??? ??? > ? unsigned direction) > +/* Let High-Speed devices fail here instead of > accommodating EAGAIN > + * and racing with the error handler, if EAGAIN takes > longer than the > + * command completion timeout.? SuperSpeed devices > never get here. > + */ > +static void uas_xfer_data(struct urb *urb, struct > scsi_cmnd *cmd, > +??? ??? ??? > ? struct uas_tport_info *tpinfo, > +??? ??? ??? > ? enum dma_data_direction dir, int tag) > { > -??? struct uas_cmd_info *cmdinfo = (void > *)&cmnd->SCp; > -??? int err; > +??? struct uas_cmd_info *cmdinfo = > UAS_CMD_INFO(cmd); > +??? int res = 0; > + > +??? res = usb_submit_urb(urb, GFP_ATOMIC); > > -??? cmdinfo->state = direction | > SUBMIT_STATUS_URB; > -??? err = uas_submit_urbs(cmnd, > cmnd->device->hostdata, GFP_ATOMIC); > -??? UAS_DPRINTK("%s: cmd:%p, err:%d, > state:0x%x\n", __FUNCTION__, > -??? ??? ? ? cmnd, > err, cmdinfo->state); > -??? if (err) { > -??? ??? > spin_lock(&uas_work_lock); > -??? ??? > list_add_tail(&cmdinfo->list, &uas_work_list); > -??? ??? > spin_unlock(&uas_work_lock); > -??? ??? > schedule_work(&uas_work); > +??? if (res == 0) { > +??? ??? if (dir == > DMA_FROM_DEVICE) > +??? ??? ??? > res = usb_submit_urb(cmdinfo->data_in_urb, GFP_ATOMIC); > +??? ??? else > +??? ??? ??? > res = usb_submit_urb(cmdinfo->data_out_urb,GFP_ATOMIC); > ??? } > + > +??? UAS_DPRINTK("%s: cmd:%p res:%d > tag:%d\n", __func__, cmd, res, > +??? ??? ? ? > cmdinfo->tag); > } > > +/** > + * uas_stat_cmplt -- Status pipe urb completion > + * @urb: the URB that completed > + * > + * Anything we expect to come back on the status pipe > + * comes here. > + */ > static void uas_stat_cmplt(struct urb *urb) > { > ??? struct iu *iu = > urb->transfer_buffer; > ??? struct scsi_device *sdev = > urb->context; > -??? struct uas_dev_info *devinfo = > sdev->hostdata; > +??? struct uas_tport_info *tpinfo = > SDEV_TPORT_INFO(sdev); > ??? struct scsi_cmnd *cmnd; > -??? u16 tag; > +??? int tag; > + > +??? UAS_DPRINTK("%s: IU ID:%d tag:%d\n", > __func__, iu->iu_id, > +??? ??? ? ? > be16_to_cpup(&iu->tag)); > > ??? if (urb->status) { > ??? ??? > dev_err(&urb->dev->dev, "%s: URB BAD STATUS > %d\n", > -??? ??? ??? > __FUNCTION__, urb->status); > +??? ??? ??? > __func__, urb->status); > +??? ??? usb_free_urb(urb); > +??? ??? return; > +??? } > + > +??? if (iu->iu_id == IU_ID_RESPONSE) { > +??? ??? struct uas_lu_info > *luinfo = SDEV_LU_INFO(sdev); > + > +??? ??? > memcpy(&luinfo->resp, urb->transfer_buffer, > +??? ??? ? ? > ???sizeof(struct resp_iu)); > +??? ??? > complete(&luinfo->tmf_completion); > +??? ??? luinfo->freed_urb > = urb; > ??? ??? usb_free_urb(urb); > ??? ??? return; > ??? } > > -??? tag = be16_to_cpup(&iu->tag) - > 1; > +??? tag = be16_to_cpup(&iu->tag); > ??? if (sdev->current_cmnd) > ??? ??? cmnd = > sdev->current_cmnd; > ??? else > -??? ??? cmnd = > scsi_find_tag(sdev, tag); > -??? if (!cmnd) > +??? ??? cmnd = > scsi_find_tag(sdev, tag-2); > + > +??? if (!cmnd) { > +??? ??? UAS_DPRINTK("%s: No > command!?\n", __func__); > +??? ??? usb_free_urb(urb); > ??? ??? return; > +??? } > > ??? switch (iu->iu_id) { > ??? case IU_ID_STATUS: > -??? ??? if > (urb->actual_length < 16) > -??? ??? ??? > devinfo->uas_sense_old = 1; > -??? ??? if > (devinfo->uas_sense_old) > +??? ??? if > (unlikely(urb->actual_length < 16)) > +??? ??? ??? > tpinfo->uas_sense_old = 1; > +??? ??? if > (unlikely(tpinfo->uas_sense_old)) > ??? ??? ??? > uas_sense_old(urb, cmnd); > ??? ??? else > ??? ??? ??? > uas_sense(urb, cmnd); > ??? ??? break; > ??? case IU_ID_READ_READY: > -??? ??? uas_xfer_data(urb, > cmnd, SUBMIT_DATA_IN_URB); > +??? ??? uas_xfer_data(urb, > cmnd, tpinfo, DMA_FROM_DEVICE, tag); > ??? ??? break; > ??? case IU_ID_WRITE_READY: > -??? ??? uas_xfer_data(urb, > cmnd, SUBMIT_DATA_OUT_URB); > +??? ??? uas_xfer_data(urb, > cmnd, tpinfo, DMA_TO_DEVICE, tag); > ??? ??? break; > ??? default: > ??? ??? > scmd_printk(KERN_ERR, cmnd, > -??? ??? ??? > "Bogus IU (%d) received on status pipe\n", iu->iu_id); > +??? ??? ??? > ? ? "Unknown IU ID %d received on the status > pipe\n", > +??? ??? ??? > ? ? iu->iu_id); > +??? ??? usb_free_urb(urb); > +??? ??? break; > ??? } > } > > @@ -274,333 +349,594 @@ static void uas_data_cmplt(struct > urb *urb) > { > ??? struct scsi_data_buffer *sdb = > urb->context; > > -??? if (urb->status) { > +??? if (!urb->status) > +??? ??? sdb->resid = > sdb->length - urb->actual_length; > +??? else > ??? ??? > dev_err(&urb->dev->dev, "%s: URB BAD STATUS > %d\n", > -??? ??? ??? > __FUNCTION__, urb->status); > -??? ??? usb_free_urb(urb); > -??? ??? return; > -??? } > -??? > -??? sdb->resid = sdb->length - > urb->actual_length; > +??? ??? ??? > __func__, urb->status); > + > ??? usb_free_urb(urb); > } > > -static struct urb *uas_alloc_data_urb(struct uas_dev_info > *devinfo, gfp_t gfp, > -??? ??? ??? > ??? unsigned int pipe, u16 stream_id, > -??? ??? ??? > ??? struct scsi_data_buffer *sdb, > -??? ??? ??? > ??? enum dma_data_direction dir) > +/* ---------- URB allocators and submission ---------- */ > + > +/** > + * uas_fill_cmdp_urb -- Fill in a command pipe urb > + * @urb: the urb > + * @tpinfo: the UAS device info struct > + * @transfer_buffer: the IU > + * @buffer_length: the size of the IU > + * > + * A unified place to initialize a command pipe urb so > that > + * all command pipe urbs are freed in the same manner. > + */ > +static void uas_fill_cmdp_urb(struct urb *urb, struct > uas_tport_info *tpinfo, > +??? ??? ??? > ? ? ? void *transfer_buffer, int > buffer_length) > +{ > +??? usb_fill_bulk_urb(urb, tpinfo->udev, > tpinfo->cmd_pipe, > +??? ??? ??? > ? transfer_buffer, buffer_length, > +??? ??? ??? > ? usb_free_urb, NULL); > +??? urb->transfer_flags |= > URB_FREE_BUFFER; > +} > + > +/** > + * uas_fill_statp_urb -- Fill in a status pipe urb > + * @urb: the urb > + * @dev: the scsi device > + * @transfer_buffer: the transfer buffer of size > SENSE_IU_SIZE > + * @tag: the tag > + * > + * The callback is responsible to free/recycle the urb and > the > + * transfer buffer. > + */ > +static void uas_fill_statp_urb(struct urb *urb, struct > scsi_device *sdev, > +??? ??? ??? > ? ? ???void *transfer_buffer, int > tag) > +{ > +??? struct uas_tport_info *tpinfo = > SDEV_TPORT_INFO(sdev); > + > +??? usb_fill_bulk_urb(urb, tpinfo->udev, > tpinfo->status_pipe, > +??? ??? ??? > ? transfer_buffer, SENSE_IU_SIZE, > +??? ??? ??? > ? uas_stat_cmplt, sdev); > +??? urb->transfer_flags |= > URB_FREE_BUFFER; > +??? if (tpinfo->use_streams) > +??? ??? urb->stream_id = > tag; > +} > + > +static struct urb *uas_alloc_data_urb(struct > uas_tport_info *tpinfo, gfp_t gfp, > +??? ??? ??? > ??? ? ? ? unsigned int > data_pipe, u16 tag, > +??? ??? ??? > ??? ? ? ? struct > scsi_data_buffer *sdb) > { > -??? struct usb_device *udev = > devinfo->udev; > +??? struct usb_device *udev = > tpinfo->udev; > ??? struct urb *urb = usb_alloc_urb(0, > gfp); > > ??? if (!urb) > -??? ??? goto out; > -??? usb_fill_bulk_urb(urb, udev, pipe, > NULL, sdb->length, uas_data_cmplt, > -??? ??? ??? > ??? ??? ??? > ??? ??? ??? > sdb); > -??? if (devinfo->use_streams) > -??? ??? urb->stream_id = > stream_id; > +??? ??? goto Out; > + > +??? usb_fill_bulk_urb(urb, udev, data_pipe, > NULL, sdb->length, > +??? ??? ??? > ? uas_data_cmplt, sdb); > +??? if (tpinfo->use_streams) > +??? ??? urb->stream_id = > tag; > ??? urb->num_sgs = > udev->bus->sg_tablesize ? sdb->table.nents : 0; > ??? urb->sg = sdb->table.sgl; > - out: > + Out: > ??? return urb; > } > > -static struct urb *uas_alloc_sense_urb(struct uas_dev_info > *devinfo, gfp_t gfp, > -??? ??? ??? > ??? ??? struct scsi_cmnd > *cmnd, u16 stream_id) > +static struct urb *uas_alloc_status_urb(struct scsi_cmnd > *cmd, gfp_t gfp) > +??? ??? ??? > ??? ??? > { > -??? struct usb_device *udev = > devinfo->udev; > -??? struct urb *urb = usb_alloc_urb(0, > gfp); > -??? struct sense_iu *iu; > +??? struct sense_iu *siu; > +??? struct urb *urb; > > +??? urb = usb_alloc_urb(0, gfp); > ??? if (!urb) > -??? ??? goto out; > +??? ??? return NULL; > > -??? iu = kzalloc(sizeof(*iu), gfp); > -??? if (!iu) > -??? ??? goto free; > +??? siu = kzalloc(SENSE_IU_SIZE, gfp); > +??? if (!siu) > +??? ??? goto Out_free; > + > +??? uas_fill_statp_urb(urb, cmd->device, > siu, UAS_CMD_INFO(cmd)->tag); > > -??? usb_fill_bulk_urb(urb, udev, > devinfo->status_pipe, iu, sizeof(*iu), > -??? ??? ??? > ??? ??? ??? > uas_stat_cmplt, cmnd->device); > -??? urb->stream_id = stream_id; > -??? urb->transfer_flags |= > URB_FREE_BUFFER; > - out: > ??? return urb; > - free: > + Out_free: > ??? usb_free_urb(urb); > ??? return NULL; > } > > -static struct urb *uas_alloc_cmd_urb(struct uas_dev_info > *devinfo, gfp_t gfp, > -??? ??? ??? > ??? ??? struct scsi_cmnd > *cmnd, u16 stream_id) > +static struct urb *uas_alloc_cmd_urb(struct scsi_cmnd > *cmd, gfp_t gfp) > { > -??? struct usb_device *udev = > devinfo->udev; > -??? struct scsi_device *sdev = > cmnd->device; > +??? struct uas_cmd_info *cmdinfo = > UAS_CMD_INFO(cmd); > +??? struct uas_tport_info *tpinfo = > UAS_TPORT_INFO(cmd); > +??? struct usb_device *udev = > tpinfo->udev; > +??? struct scsi_device *sdev = > cmd->device; > ??? struct urb *urb = usb_alloc_urb(0, > gfp); > -??? struct command_iu *iu; > +??? struct command_iu *ciu; > ??? int len; > > ??? if (!urb) > -??? ??? goto out; > +??? ??? return NULL; > > -??? len = cmnd->cmd_len - 16; > +??? len = cmd->cmd_len - 16; > ??? if (len < 0) > ??? ??? len = 0; > -??? len = ALIGN(len, 4); > -??? iu = kzalloc(sizeof(*iu) + len, gfp); > -??? if (!iu) > +??? else > +??? ??? len = ALIGN(len, > 4); > + > +??? ciu = kzalloc(sizeof(*ciu) + len, > gfp); > +??? if (!ciu) > ??? ??? goto free; > > -??? iu->iu_id = IU_ID_COMMAND; > -??? iu->tag = cpu_to_be16(stream_id); > -??? if (sdev->ordered_tags && > (cmnd->request->cmd_flags & REQ_HARDBARRIER)) > -??? ??? iu->prio_attr = > UAS_ORDERED_TAG; > +??? ciu->iu_id = IU_ID_COMMAND; > +??? ciu->tag = > cpu_to_be16(cmdinfo->tag); > +??? if (sdev->ordered_tags && > (cmd->request->cmd_flags & REQ_HARDBARRIER)) > +??? ??? ciu->prio_attr = > UAS_ORDERED_TAG; > ??? else > -??? ??? iu->prio_attr = > UAS_SIMPLE_TAG; > -??? iu->len = len; > -??? int_to_scsilun(sdev->lun, > &iu->lun); > -??? memcpy(iu->cdb, cmnd->cmnd, > cmnd->cmd_len); > +??? ??? ciu->prio_attr = > UAS_SIMPLE_TAG; > +??? ciu->len = len; > +??? int_to_scsilun(sdev->lun, > &ciu->lun); > +??? memcpy(ciu->cdb, cmd->cmnd, > cmd->cmd_len); > > -??? usb_fill_bulk_urb(urb, udev, > devinfo->cmd_pipe, iu, sizeof(*iu) + len, > +??? usb_fill_bulk_urb(urb, udev, > tpinfo->cmd_pipe, ciu, sizeof(*ciu) + len, > ??? ??? ??? > ? usb_free_urb, NULL); > ??? urb->transfer_flags |= > URB_FREE_BUFFER; > - out: > ??? return urb; > ? free: > ??? usb_free_urb(urb); > ??? return NULL; > } > > -/* > - * Why should I request the Status IU before sending the > Command IU?? Spec > - * says to, but also says the device may receive them in > any order.? Seems > - * daft to me. > - */ > - > -static int uas_submit_urbs(struct scsi_cmnd *cmnd, > -??? ??? ??? > ???struct uas_dev_info *devinfo, gfp_t gfp) > +static int uas_alloc_urbs(struct scsi_cmnd *cmd, gfp_t > gfp) > { > -??? struct uas_cmd_info *cmdinfo = (void > *)&cmnd->SCp; > -??? int res; > +??? struct uas_cmd_info *cmdinfo = > UAS_CMD_INFO(cmd); > +??? struct uas_tport_info *tpinfo = > UAS_TPORT_INFO(cmd); > > -??? if (cmdinfo->state & > ALLOC_STATUS_URB) { > -??? ??? > cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, > cmnd, > -??? ??? ??? > ??? ??? ??? > ??? ? cmdinfo->stream); > -??? ??? if > (!cmdinfo->status_urb) > -??? ??? ??? > return -ENOMEM; > -??? ??? cmdinfo->state > &= ~ALLOC_STATUS_URB; > -??? } > +??? cmdinfo->status_urb = NULL; > +??? cmdinfo->data_in_urb = NULL; > +??? cmdinfo->data_out_urb = NULL; > +??? cmdinfo->cmd_urb = NULL; > > -??? if (cmdinfo->state & > SUBMIT_STATUS_URB) { > -??? ??? res = > usb_submit_urb(cmdinfo->status_urb, gfp); > -??? ??? if (res) { > -??? ??? ??? > scmd_printk(KERN_INFO, cmnd, > -??? ??? ??? > ??? ? ? "sense urb submission > failure (%d)\n", > -??? ??? ??? > ??? ? ? res); > -??? ??? ??? > return res; > +??? cmdinfo->status_urb = > uas_alloc_status_urb(cmd, gfp); > +??? cmdinfo->cmd_urb = > uas_alloc_cmd_urb(cmd, gfp); > +??? if (!cmdinfo->cmd_urb || > !cmdinfo->status_urb) > +??? ??? goto Out_err1; > + > +??? switch (cmd->sc_data_direction) { > +??? case DMA_BIDIRECTIONAL: > +??? case DMA_TO_DEVICE: > +??? ??? > cmdinfo->data_out_urb = > +??? ??? ??? > uas_alloc_data_urb(tpinfo, gfp, > +??? ??? ??? > ??? ??? > ???tpinfo->data_out_pipe, > +??? ??? ??? > ??? ??? > ???cmdinfo->tag, > +??? ??? ??? > ??? ??? > ???scsi_out(cmd)); > +??? ??? if > (!cmdinfo->data_out_urb) > +??? ??? ??? > goto Out_err2; > +??? ??? if > (cmd->sc_data_direction != DMA_BIDIRECTIONAL) > +??? ??? ??? > break; > +??? ??? else { > +??? case DMA_FROM_DEVICE: > +??? ??? > cmdinfo->data_in_urb = > +??? ??? ??? > uas_alloc_data_urb(tpinfo, gfp, > +??? ??? ??? > ??? ??? > ???tpinfo->data_in_pipe, > +??? ??? ??? > ??? ??? > ???cmdinfo->tag, > +??? ??? ??? > ??? ??? > ???scsi_in(cmd)); > +??? ??? if > (!cmdinfo->data_in_urb) > +??? ??? ??? > goto Out_err2; > ??? ??? } > -??? ??? cmdinfo->state > &= ~SUBMIT_STATUS_URB; > +??? ??? break; > +??? case DMA_NONE: > +??? ??? break; > ??? } > > -??? if (cmdinfo->state & > ALLOC_DATA_IN_URB) { > -??? ??? > cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, > -??? ??? ??? > ??? ??? > devinfo->data_in_pipe, cmdinfo->stream, > -??? ??? ??? > ??? ??? scsi_in(cmnd), > DMA_FROM_DEVICE); > -??? ??? if > (!cmdinfo->data_in_urb) > -??? ??? ??? > return -ENOMEM; > -??? ??? cmdinfo->state > &= ~ALLOC_DATA_IN_URB; > +??? return 0; > +??? > + Out_err2: > +??? usb_free_urb(cmdinfo->data_in_urb); > +??? > usb_free_urb(cmdinfo->data_out_urb); > + Out_err1: > +??? usb_free_urb(cmdinfo->cmd_urb); > +??? return -ENOMEM; > +} > + > +static int uas_submit_urbs(struct scsi_cmnd *cmd, gfp_t > gfp) > +{ > +??? struct uas_cmd_info *cmdinfo = > UAS_CMD_INFO(cmd); > +??? struct uas_tport_info *tpinfo = > UAS_TPORT_INFO(cmd); > +??? int res; > + > +??? UAS_DPRINTK("%s: cmd:%p (0x%02x) > tag:%d\n", __func__, > +??? ??? ? ? cmd, > cmd->cmnd[0], cmdinfo->tag); > + > +??? res = > usb_submit_urb(cmdinfo->status_urb, gfp); > +??? if (res) { > +??? ??? > scmd_printk(KERN_INFO, cmd, > +??? ??? ??? > ? ? "sense urb submission failure (%d)\n", res); > +??? ??? return res; > ??? } > > -??? if (cmdinfo->state & > SUBMIT_DATA_IN_URB) { > +??? if (cmdinfo->data_in_urb && > tpinfo->use_streams) { > ??? ??? res = > usb_submit_urb(cmdinfo->data_in_urb, gfp); > ??? ??? if (res) { > -??? ??? ??? > scmd_printk(KERN_INFO, cmnd, > +??? ??? ??? > scmd_printk(KERN_INFO, cmd, > ??? ??? ??? > ??? ? ? "data in urb submission > failure (%d)\n", > ??? ??? ??? > ??? ? ? res); > ??? ??? ??? > return res; > ??? ??? } > -??? ??? cmdinfo->state > &= ~SUBMIT_DATA_IN_URB; > ??? } > > -??? if (cmdinfo->state & > ALLOC_DATA_OUT_URB) { > -??? ??? > cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, > -??? ??? ??? > ??? ??? > devinfo->data_out_pipe, cmdinfo->stream, > -??? ??? ??? > ??? ??? scsi_out(cmnd), > DMA_TO_DEVICE); > -??? ??? if > (!cmdinfo->data_out_urb) > -??? ??? ??? > return -ENOMEM; > -??? ??? cmdinfo->state > &= ~ALLOC_DATA_OUT_URB; > -??? } > - > -??? if (cmdinfo->state & > SUBMIT_DATA_OUT_URB) { > +??? if (cmdinfo->data_out_urb && > tpinfo->use_streams) { > ??? ??? res = > usb_submit_urb(cmdinfo->data_out_urb, gfp); > ??? ??? if (res) { > -??? ??? ??? > scmd_printk(KERN_INFO, cmnd, > +??? ??? ??? > scmd_printk(KERN_INFO, cmd, > ??? ??? ??? > ??? ? ? "data out urb submission > failure (%d)\n", > ??? ??? ??? > ??? ? ? res); > ??? ??? ??? > return res; > ??? ??? } > -??? ??? cmdinfo->state > &= ~SUBMIT_DATA_OUT_URB; > -??? } > - > -??? if (cmdinfo->state & > ALLOC_CMD_URB) { > -??? ??? cmdinfo->cmd_urb > = uas_alloc_cmd_urb(devinfo, gfp, cmnd, > -??? ??? ??? > ??? ??? ??? > ??? cmdinfo->stream); > -??? ??? if > (!cmdinfo->cmd_urb) > -??? ??? ??? > return -ENOMEM; > -??? ??? cmdinfo->state > &= ~ALLOC_CMD_URB; > ??? } > > -??? if (cmdinfo->state & > SUBMIT_CMD_URB) { > -??? ??? res = > usb_submit_urb(cmdinfo->cmd_urb, gfp); > -??? ??? if (res) { > -??? ??? ??? > scmd_printk(KERN_INFO, cmnd, > -??? ??? ??? > ??? ? ? "cmd urb submission failure > (%d)\n", res); > -??? ??? ??? > return res; > -??? ??? } > -??? ??? cmdinfo->state > &= ~SUBMIT_CMD_URB; > +??? res = > usb_submit_urb(cmdinfo->cmd_urb, gfp); > +??? if (res) { > +??? ??? > scmd_printk(KERN_INFO, cmd, > +??? ??? ??? > ? ? "cmd urb submission failure (%d)\n", res); > +??? ??? return res; > ??? } > > ??? return 0; > } > > -static int uas_queuecommand(struct scsi_cmnd *cmnd, > +static void uas_free_urbs(struct scsi_cmnd *cmd) > +{ > +??? struct uas_cmd_info *cmdinfo = > UAS_CMD_INFO(cmd); > +??? int res; > + > +??? if (cmdinfo->cmd_urb) { > +??? ??? res = > usb_unlink_urb(cmdinfo->cmd_urb); > +??? ??? if (res != > -EINPROGRESS) > +??? ??? ??? > usb_free_urb(cmdinfo->cmd_urb); > +??? } > +??? if (cmdinfo->status_urb) { > +??? ??? res = > usb_unlink_urb(cmdinfo->status_urb); > +??? ??? if (res != > -EINPROGRESS) > +??? ??? ??? > usb_free_urb(cmdinfo->status_urb); > +??? } > +??? if (cmdinfo->data_in_urb) { > +??? ??? res = > usb_unlink_urb(cmdinfo->data_in_urb); > +??? ??? if (res != > -EINPROGRESS) > +??? ??? ??? > usb_free_urb(cmdinfo->data_in_urb); > +??? } > +??? if (cmdinfo->data_out_urb) { > +??? ??? res = > usb_unlink_urb(cmdinfo->data_out_urb); > +??? ??? if (res != > -EINPROGRESS) > +??? ??? ??? > usb_free_urb(cmdinfo->data_out_urb); > +??? } > +} > + > +static int uas_queuecommand(struct scsi_cmnd *cmd, > ??? ??? ??? > ? ? void (*done)(struct scsi_cmnd *)) > { > -??? struct scsi_device *sdev = > cmnd->device; > -??? struct uas_dev_info *devinfo = > sdev->hostdata; > -??? struct uas_cmd_info *cmdinfo = (void > *)&cmnd->SCp; > +??? struct scsi_device *sdev = > cmd->device; > +??? struct uas_cmd_info *cmdinfo = > UAS_CMD_INFO(cmd); > ??? int res; > > ??? BUILD_BUG_ON(sizeof(struct > uas_cmd_info) > sizeof(struct scsi_pointer)); > > -??? if (!cmdinfo->status_urb && > sdev->current_cmnd) > -??? ??? return > SCSI_MLQUEUE_DEVICE_BUSY; > - > -??? if (blk_rq_tagged(cmnd->request)) { > -??? ??? cmdinfo->stream = > cmnd->request->tag + 1; > +??? /* If LLDD are NOT to maintain their > own tags, (but the block > +?????* layer would), THEN ANY AND > ALL scsi_cmnds passed to the > +?????* queuecommand entry of a > LLDD MUST HAVE A VALID, > +?????* REVERSE-MAPPABLE tag, > REGARDLESS of where the command came > +?????* from, regardless of > whether the device supports tags, and > +?????* regardless of how many > tags it supports. > +?????*/ > +??? if (blk_rq_tagged(cmd->request)) { > +??? ??? cmdinfo->tag = > cmd->request->tag + 2; > +??? } else if (sdev->current_cmnd == > NULL) { > +??? ??? > sdev->current_cmnd = cmd; /* Hilarious, isn't it?! */ > +??? ??? cmdinfo->tag = > 1; > ??? } else { > -??? ??? > sdev->current_cmnd = cmnd; > -??? ??? cmdinfo->stream = > 1; > +??? ??? cmd->result = > DID_ABORT << 16; > +??? ??? goto Out_err; > ??? } > > -??? cmnd->scsi_done = done; > - > -??? cmdinfo->state = ALLOC_STATUS_URB | > SUBMIT_STATUS_URB | > -??? ??? ??? > ALLOC_CMD_URB | SUBMIT_CMD_URB; > +??? cmd->scsi_done = done; > > -??? switch (cmnd->sc_data_direction) { > -??? case DMA_FROM_DEVICE: > -??? ??? cmdinfo->state |= > ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; > -??? ??? break; > -??? case DMA_BIDIRECTIONAL: > -??? ??? cmdinfo->state |= > ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; > -??? case DMA_TO_DEVICE: > -??? ??? cmdinfo->state |= > ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB; > -??? case DMA_NONE: > -??? ??? break; > +??? res = uas_alloc_urbs(cmd, GFP_ATOMIC); > +??? if (res) { > +??? ??? cmd->result = > DID_ABORT << 16; > +??? ??? goto Out_err; > ??? } > > -??? if (!devinfo->use_streams) { > -??? ??? cmdinfo->state > &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); > -??? ??? cmdinfo->stream = > 0; > +??? res = uas_submit_urbs(cmd, > GFP_ATOMIC); > +??? if (res) { > +??? ??? cmd->result = > DID_NO_CONNECT << 16; > +??? ??? uas_free_urbs(cmd); > +??? ??? goto Out_err; > ??? } > +??? > +??? UAS_DPRINTK("%s: cmd:%p (0x%02x) res:%d > tag:%d\n", > +??? ??? ? ? > __func__, cmd, cmd->cmnd[0], res, cmdinfo->tag); > > -??? res = uas_submit_urbs(cmnd, devinfo, > GFP_ATOMIC); > -??? UAS_DPRINTK("%s: cmd:%p (0x%02x), > err:%d, state:0x%x\n", __FUNCTION__, > -??? ??? ? ? cmnd, > cmnd->cmnd[0], res, cmdinfo->state); > -??? if (res) { > -??? ??? > usb_unlink_urb(cmdinfo->status_urb); > -??? ??? > usb_unlink_urb(cmdinfo->data_in_urb); > -??? ??? > usb_unlink_urb(cmdinfo->data_out_urb); > -??? ??? > usb_unlink_urb(cmdinfo->cmd_urb); > +??? return 0; > + Out_err: > +??? sdev->current_cmnd = NULL; > +??? done(cmd); > + > +??? return 0; > +} > > -??? ??? > sdev->current_cmnd = NULL; > +/* ---------- Error Recovery ---------- */ > > -??? ??? cmnd->result = > DID_NO_CONNECT << 16; > -??? ??? done(cmnd); > -??? } > +/* [1, UAS_MAX_STREAMS+1] belong to commands. > + * [UAS_MAX_STREAMS+2, UAS_MAX_STREAMS+2+TMF_MAX_TAGS) > belong to TMFs. > + */ > +#define TMF_TAG_FIRST ??? (UAS_MAX_STREAMS > + 2) > +#define TMF_MAX_TAGS??? 1024 > + > +static int uas_get_tmf_tag(void) > +{ > +??? static int tmf_tag = 0; > +??? int res; > + > +??? /* [TMF_TAG_FIRST, TMF_MAX_TAGS + > TMF_MAX_TAGS) */ > +??? res = tmf_tag + TMF_TAG_FIRST; > + > +??? tmf_tag += 1; > +??? tmf_tag %= TMF_MAX_TAGS; /* > [0,TMF_MAX_TAGS) */ > + > +??? return res; > +} > + > +static int uas_alloc_tmf_urb(struct urb **urb, struct > uas_tport_info *tpinfo, > +??? ??? ??? > ? ???u8 tmf, u16 ttbm, struct scsi_lun > *lun) > +{ > +??? struct tmf_iu *tmf_iu; > +??? > +??? *urb = usb_alloc_urb(0, GFP_KERNEL); > +??? if (!*urb) > +??? ??? return -ENOMEM; > +??? tmf_iu = kzalloc(sizeof(*tmf_iu), > GFP_KERNEL); > +??? if (!tmf_iu) > +??? ??? goto Out_err; > + > +??? /* If LLDD are NOT to maintain their > own tags, (but the block > +?????* layer would), THEN LLDDs > must be able to call a function of > +?????* some sort and reserve a > tag from the same pool and obtain > +?????* it for their own use, as > well as being able to free it back > +?????* later. > +?????*/ > +??? tmf_iu->iu_id = IU_ID_TASK_MGMT; > +??? tmf_iu->tag = > cpu_to_be16(uas_get_tmf_tag()); > +??? tmf_iu->tmf = tmf; > +??? tmf_iu->ttbm = cpu_to_be16(ttbm); > +??? tmf_iu->lun = *lun; > + > +??? uas_fill_cmdp_urb(*urb, tpinfo, tmf_iu, > sizeof(*tmf_iu)); > > ??? return 0; > + Out_err: > +??? usb_free_urb(*urb); > +??? return -ENOMEM; > } > > -static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) > +static int uas_alloc_resp_urb(struct urb **urb, struct > scsi_device *sdev, > +??? ??? ??? > ? ? ? struct resp_iu *resp, int tag) > { > -??? struct scsi_device *sdev = > cmnd->device; > -??? sdev_printk(KERN_INFO, sdev, "%s tag > %d\n", __func__, > -??? ??? ??? > ??? ??? ??? > ??? cmnd->request->tag); > +??? *urb = usb_alloc_urb(0, GFP_KERNEL); > +??? if (!*urb) > +??? ??? return -ENOMEM; > > -/* XXX: Send ABORT TASK Task Management command */ > -??? return FAILED; > +??? uas_fill_statp_urb(*urb, sdev, resp, > tag); > + > +??? return 0; > } > > -static int uas_eh_device_reset_handler(struct scsi_cmnd > *cmnd) > +#define UAS_TMF_TIMEOUT??? (5*HZ) > + > +/** > + * uas_do_tmf -- Execute the desired TMF > + * @sdev: the device to which we should send the TMF > + * @tmf:? the task management function to execute > + * @ttbm: the tag of task to be managed > + * > + * This function returns a negative value on error > (-ENOMEM, etc), or > + * an integer with bytes 3, 2 and 1 being the high to low > byte of the > + * Additional Response Information field and byte 0 being > the Response > + * code of the Response IU. > + * > + * If the response code is 0xFF, then the TMF timed out. > + */ > +static int uas_do_tmf(struct scsi_cmnd *cmd, u8 tmf, u8 > ttbm) > { > -??? struct scsi_device *sdev = > cmnd->device; > -??? sdev_printk(KERN_INFO, sdev, "%s tag > %d\n", __func__, > -??? ??? ??? > ??? ??? ??? > ??? cmnd->request->tag); > +??? struct scsi_device *sdev = > cmd->device; > +??? struct uas_tport_info *tpinfo = > SDEV_TPORT_INFO(sdev); > +??? struct > uas_lu_info???*luinfo= SDEV_LU_INFO(sdev); > +??? struct uas_cmd_info *cmdinfo = > UAS_CMD_INFO(cmd); > +??? struct urb *tmf_urb = NULL; > +??? struct urb *resp_urb = NULL; > +??? struct scsi_lun lun; > +??? long???timeout; > +??? int res; > > -/* XXX: Send LOGICAL UNIT RESET Task Management command > */ > -??? return FAILED; > +??? /* scsi_dev should contain u8[8] for a > LUN, not an unsigned int! > +?????*/ > +??? int_to_scsilun(sdev->lun, > &lun); > +??? res = uas_alloc_tmf_urb(&tmf_urb, > tpinfo, tmf, ttbm, &lun); > +??? if (res) > +??? ??? return -ENOMEM; > + > +??? /* If we're not using streams, we'll > get the Response IU via > +?????* the sense urb we previosly > submitted, so there is no need > +?????* to allocate a response > urb. > +?????* If we're using streams, we > need a response urb. > +?????* Or we need a response urb > if we've previosly executed a TMF > +?????* which used up the sense > urb as a response urb. > +?????*/ > +??? if (tpinfo->use_streams || > luinfo->freed_urb == cmdinfo->status_urb) { > +??? ??? struct tmf_iu > *tmf_iu; > +??? ??? struct resp_iu *resp > = NULL; > + > +??? ??? resp = > kzalloc(SENSE_IU_SIZE, GFP_KERNEL); > +??? ??? if (!resp) { > +??? ??? ??? > usb_free_urb(tmf_urb); > +??? ??? ??? > return -ENOMEM; > +??? ??? } > + > +??? ??? tmf_iu = > tmf_urb->transfer_buffer; > +??? ??? res = > uas_alloc_resp_urb(&resp_urb, sdev, resp, > +??? ??? ??? > ??? > ?????be16_to_cpu(tmf_iu->tag)); > +??? ??? if (res) { > +??? ??? ??? > usb_free_urb(tmf_urb); > +??? ??? ??? > kfree(resp); > +??? ??? ??? > return -ENOMEM; > +??? ??? } > +??? } > + > +??? /* Now submit them */ > + > +??? > init_completion(&luinfo->tmf_completion); > +??? luinfo->resp.resp = 0xFFFFFFFF; > + > +??? if (tpinfo->use_streams || > luinfo->freed_urb == cmdinfo->status_urb) { > +??? ??? res = > usb_submit_urb(resp_urb, GFP_KERNEL); > +??? ??? if (res) { > +??? ??? ??? > complete(&luinfo->tmf_completion); > +??? ??? ??? > usb_free_urb(tmf_urb); > +??? ??? ??? > res = usb_unlink_urb(resp_urb); > +??? ??? ??? > if (res != -EINPROGRESS) > +??? ??? ??? > ??? usb_free_urb(resp_urb); > +??? ??? ??? > return res; > +??? ??? } > +??? } > + > +??? res = usb_submit_urb(tmf_urb, > GFP_KERNEL); > +??? if (res) { > +??? ??? > complete(&luinfo->tmf_completion); > +??? ??? res = > usb_unlink_urb(tmf_urb); > +??? ??? if (res != > -EINPROGRESS) > +??? ??? ??? > usb_free_urb(tmf_urb); > +??? ??? if > (tpinfo->use_streams || > +??? ??? ? ? > luinfo->freed_urb == cmdinfo->status_urb) { > +??? ??? ??? > res = usb_unlink_urb(resp_urb); > +??? ??? ??? > if (res != -EINPROGRESS) > +??? ??? ??? > ??? usb_free_urb(resp_urb); > +??? ??? ??? > return res; > +??? ??? } > +??? } > + > +??? timeout = > wait_for_completion_timeout(&luinfo->tmf_completion, > +??? ??? ??? > ??? ??? ? ? ? > UAS_TMF_TIMEOUT); > +??? if (timeout && > luinfo->resp.iu_id == IU_ID_RESPONSE && > +??? ? ? > be16_to_cpup(&luinfo->resp.tag) >= TMF_TAG_FIRST) > { > +??? ??? res = > be32_to_cpup(&luinfo->resp.resp); > +??? } else { > +??? ??? res = 0xFF; > +??? } > +??? return res; > } > > -static int uas_eh_target_reset_handler(struct scsi_cmnd > *cmnd) > +static int uas_er_tmf(struct scsi_cmnd *cmd, u8 tmf) > { > -??? struct scsi_device *sdev = > cmnd->device; > -??? sdev_printk(KERN_INFO, sdev, "%s tag > %d\n", __func__, > -??? ??? ??? > ??? ??? ??? > ??? cmnd->request->tag); > +??? struct scsi_device *sdev = > cmd->device; > +??? int tag; > +??? int res; > > -/* XXX: Can we reset just the one USB interface? > - * Would calling usb_set_interface() have the right > effect? > - */ > -??? return FAILED; > +??? if (sdev->current_cmnd == cmd) > +??? ??? tag = 1; > +??? else > +??? ??? tag = > cmd->request->tag + 2; > + > +??? res = uas_do_tmf(cmd, tmf, tag); > + > +??? UAS_DPRINTK("%s: cmd:%p (0x%02x) tag:%d > tmf:0x%02x resp:0x%08x\n", > +??? ??? ? ? > __func__, cmd, cmd->cmnd[0], tag, tmf, res); > + > +??? switch (TMR_RESPONSE_CODE(res)) { > +??? case TMR_COMPLETE: > +??? case TMR_SUCC: > +??? ??? return SUCCESS; > +??? default: > +??? ??? return FAILED; > +??? } > } > > -static int uas_eh_bus_reset_handler(struct scsi_cmnd > *cmnd) > +static int uas_eh_abort_handler(struct scsi_cmnd *cmd) > { > -??? struct scsi_device *sdev = > cmnd->device; > -??? struct uas_dev_info *devinfo = > sdev->hostdata; > -??? struct usb_device *udev = > devinfo->udev; > +??? return uas_er_tmf(cmd, > TMF_ABORT_TASK); > +} > + > +static int uas_eh_device_reset_handler(struct scsi_cmnd > *cmd) > +{ > +??? return uas_er_tmf(cmd, TMF_LU_RESET); > +} > > -??? sdev_printk(KERN_INFO, sdev, "%s tag > %d\n", __func__, > -??? ??? ??? > ??? ??? ??? > ??? cmnd->request->tag); > +static int uas_eh_target_reset_handler(struct scsi_cmnd > *cmd) > +{ > +??? return uas_er_tmf(cmd, > TMF_IT_NEXUS_RESET); > +} > + > +static int uas_eh_bus_reset_handler(struct scsi_cmnd > *cmd) > +{ > +??? struct scsi_device *sdev = > cmd->device; > +??? struct uas_tport_info *tpinfo = > SDEV_TPORT_INFO(sdev); > +??? struct usb_device *udev = > tpinfo->udev; > +??? int res; > + > +??? res = usb_reset_device(udev); > > -??? if (usb_reset_device(udev)) > +??? UAS_DPRINTK("%s: cmd:%p (0x%02x) > res:0x%08x\n", > +??? ??? ? ? > __func__, cmd, cmd->cmnd[0], res); > + > +??? if (res) > ??? ??? return SUCCESS; > > ??? return FAILED; > } > > +/* ---------- SCSI Host support ---------- */ > + > static int uas_slave_alloc(struct scsi_device *sdev) > { > -??? sdev->hostdata = (void > *)sdev->host->hostdata[0]; > +??? sdev->hostdata = > kzalloc(sizeof(struct uas_lu_info), GFP_KERNEL); > +??? if (sdev->hostdata == NULL) > +??? ??? return -ENOMEM; > ??? return 0; > } > > static int uas_slave_configure(struct scsi_device *sdev) > { > -??? struct uas_dev_info *devinfo = > sdev->hostdata; > +??? struct uas_tport_info *tpinfo = > SDEV_TPORT_INFO(sdev); > + > ??? scsi_set_tag_type(sdev, > MSG_ORDERED_TAG); > -??? scsi_activate_tcq(sdev, > devinfo->qdepth - 1); > +??? scsi_activate_tcq(sdev, > tpinfo->num_tags); > + > ??? return 0; > } > > +static void uas_slave_destroy(struct scsi_device *sdev) > +{ > +??? kfree(sdev->hostdata); > +} > + > static struct scsi_host_template uas_host_template = { > ??? .module = THIS_MODULE, > ??? .name = "uas", > ??? .queuecommand = uas_queuecommand, > ??? .slave_alloc = uas_slave_alloc, > ??? .slave_configure = > uas_slave_configure, > +??? .slave_destroy = uas_slave_destroy, > ??? .eh_abort_handler = > uas_eh_abort_handler, > ??? .eh_device_reset_handler = > uas_eh_device_reset_handler, > ??? .eh_target_reset_handler = > uas_eh_target_reset_handler, > ??? .eh_bus_reset_handler = > uas_eh_bus_reset_handler, > -??? .can_queue = 65536,??? > /* Is there a limit on the _host_ ? */ > +??? .can_queue = 0xFFEF,??? > ? /* [1, 0xFFF0) */ > ??? .this_id = -1, > ??? .sg_tablesize = SG_NONE, > -??? .cmd_per_lun = 1,??? /* > until we override it */ > +??? .cmd_per_lun = 1,??? > ? /* until we override it */ > ??? .skip_settle_delay = 1, > ??? .ordered_tag = 1, > }; > > +/* ---------- USB related ---------- */ > + > static struct usb_device_id uas_usb_ids[] = { > ??? { > USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, > USB_PR_BULK) }, > ??? { > USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, > USB_PR_UAS) }, > @@ -610,15 +946,15 @@ static struct usb_device_id > uas_usb_ids[] = { > }; > MODULE_DEVICE_TABLE(usb, uas_usb_ids); > > -static void uas_configure_endpoints(struct uas_dev_info > *devinfo) > +static void uas_configure_endpoints(struct uas_tport_info > *tpinfo) > { > ??? struct usb_host_endpoint *eps[4] = { > }; > -??? struct usb_interface *intf = > devinfo->intf; > -??? struct usb_device *udev = > devinfo->udev; > +??? struct usb_interface *intf = > tpinfo->intf; > +??? struct usb_device *udev = > tpinfo->udev; > ??? struct usb_host_endpoint *endpoint = > intf->cur_altsetting->endpoint; > ??? unsigned i, n_endpoints = > intf->cur_altsetting->desc.bNumEndpoints; > > -??? devinfo->uas_sense_old = 0; > +??? tpinfo->uas_sense_old = 0; > > ??? for (i = 0; i < n_endpoints; i++) { > ??? ??? unsigned char *extra > = endpoint[i].extra; > @@ -641,32 +977,38 @@ static void > uas_configure_endpoints(struct uas_dev_info *devinfo) > ?????* this. > ?????*/ > ??? if (!eps[0]) { > -??? ??? devinfo->cmd_pipe > = usb_sndbulkpipe(udev, 1); > -??? ??? > devinfo->status_pipe = usb_rcvbulkpipe(udev, 1); > -??? ??? > devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2); > -??? ??? > devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2); > - > -??? ??? eps[1] = > usb_pipe_endpoint(udev, devinfo->status_pipe); > -??? ??? eps[2] = > usb_pipe_endpoint(udev, devinfo->data_in_pipe); > -??? ??? eps[3] = > usb_pipe_endpoint(udev, devinfo->data_out_pipe); > +??? ??? tpinfo->cmd_pipe > = usb_sndbulkpipe(udev, 1); > +??? ??? > tpinfo->status_pipe = usb_rcvbulkpipe(udev, 1); > +??? ??? > tpinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2); > +??? ??? > tpinfo->data_out_pipe = usb_sndbulkpipe(udev, 2); > + > +??? ??? eps[1] = > usb_pipe_endpoint(udev, tpinfo->status_pipe); > +??? ??? eps[2] = > usb_pipe_endpoint(udev, tpinfo->data_in_pipe); > +??? ??? eps[3] = > usb_pipe_endpoint(udev, tpinfo->data_out_pipe); > ??? } else { > -??? ??? devinfo->cmd_pipe > = usb_sndbulkpipe(udev, > +??? ??? tpinfo->cmd_pipe > = usb_sndbulkpipe(udev, > ??? ??? ??? > ??? ??? ??? > eps[0]->desc.bEndpointAddress); > -??? ??? > devinfo->status_pipe = usb_rcvbulkpipe(udev, > +??? ??? > tpinfo->status_pipe = usb_rcvbulkpipe(udev, > ??? ??? ??? > ??? ??? ??? > eps[1]->desc.bEndpointAddress); > -??? ??? > devinfo->data_in_pipe = usb_rcvbulkpipe(udev, > +??? ??? > tpinfo->data_in_pipe = usb_rcvbulkpipe(udev, > ??? ??? ??? > ??? ??? ??? > eps[2]->desc.bEndpointAddress); > -??? ??? > devinfo->data_out_pipe = usb_sndbulkpipe(udev, > +??? ??? > tpinfo->data_out_pipe = usb_sndbulkpipe(udev, > ??? ??? ??? > ??? ??? ??? > eps[3]->desc.bEndpointAddress); > ??? } > > -??? devinfo->qdepth = > usb_alloc_streams(devinfo->intf, eps + 1, 3, 256, > -??? ??? ??? > ??? ??? ??? > ??? ??? GFP_KERNEL); > -??? if (devinfo->qdepth < 0) { > -??? ??? devinfo->qdepth = > 256; > -??? ??? > devinfo->use_streams = 0; > +??? if (udev->speed == USB_SPEED_SUPER) > { > +??? ??? > tpinfo->use_streams = 1; > +??? ??? tpinfo->num_tags > = usb_alloc_streams(tpinfo->intf, > +??? ??? ??? > ??? ??? ??? > ? ???eps + 1, 3, > +??? ??? ??? > ??? ??? ??? > ? ???UAS_MAX_STREAMS, > +??? ??? ??? > ??? ??? ??? > ? ???GFP_KERNEL); > +??? ??? ??? > +??? ??? if > (tpinfo->num_tags <= 0) > +??? ??? ??? > tpinfo->num_tags = 1; > ??? } else { > -??? ??? > devinfo->use_streams = 1; > +??? ??? /* Be conservative > */ > +??? ??? tpinfo->num_tags > = 32; > +??? ??? > tpinfo->use_streams = 0; > ??? } > } > > @@ -680,7 +1022,7 @@ static int uas_probe(struct > usb_interface *intf, const struct usb_device_id *id) > { > ??? int result; > ??? struct Scsi_Host *shost; > -??? struct uas_dev_info *devinfo; > +??? struct uas_tport_info *tpinfo; > ??? struct usb_device *udev = > interface_to_usbdev(intf); > > ??? if (id->bInterfaceProtocol == 0x50) > { > @@ -691,8 +1033,8 @@ static int uas_probe(struct > usb_interface *intf, const struct usb_device_id *id) > ??? ??? ??? > return -ENODEV; > ??? } > > -??? devinfo = kzalloc(sizeof(struct > uas_dev_info), GFP_KERNEL); > -??? if (!devinfo) > +??? tpinfo = kzalloc(sizeof(struct > uas_tport_info), GFP_KERNEL); > +??? if (!tpinfo) > ??? ??? return -ENOMEM; > > ??? result = -ENOMEM; > @@ -707,17 +1049,17 @@ static int uas_probe(struct > usb_interface *intf, const struct usb_device_id *id) > ??? result = scsi_add_host(shost, > &intf->dev); > ??? if (result) > ??? ??? goto free; > -??? shost->hostdata[0] = (unsigned > long)devinfo; > +??? shost->hostdata[0] = (unsigned > long)tpinfo; > > -??? devinfo->intf = intf; > -??? devinfo->udev = udev; > -??? uas_configure_endpoints(devinfo); > +??? tpinfo->intf = intf; > +??? tpinfo->udev = udev; > +??? uas_configure_endpoints(tpinfo); > > ??? scsi_scan_host(shost); > ??? usb_set_intfdata(intf, shost); > ??? return result; > ? free: > -??? kfree(devinfo); > +??? kfree(tpinfo); > ??? if (shost) > ??? ??? > scsi_host_put(shost); > ??? return result; > @@ -740,16 +1082,16 @@ static void uas_disconnect(struct > usb_interface *intf) > ??? struct usb_device *udev = > interface_to_usbdev(intf); > ??? struct usb_host_endpoint *eps[3]; > ??? struct Scsi_Host *shost = > usb_get_intfdata(intf); > -??? struct uas_dev_info *devinfo = (void > *)shost->hostdata[0]; > +??? struct uas_tport_info *tpinfo = (void > *)shost->hostdata[0]; > > ??? scsi_remove_host(shost); > > -??? eps[0] = usb_pipe_endpoint(udev, > devinfo->status_pipe); > -??? eps[1] = usb_pipe_endpoint(udev, > devinfo->data_in_pipe); > -??? eps[2] = usb_pipe_endpoint(udev, > devinfo->data_out_pipe); > +??? eps[0] = usb_pipe_endpoint(udev, > tpinfo->status_pipe); > +??? eps[1] = usb_pipe_endpoint(udev, > tpinfo->data_in_pipe); > +??? eps[2] = usb_pipe_endpoint(udev, > tpinfo->data_out_pipe); > ??? usb_free_streams(intf, eps, 3, > GFP_KERNEL); > > -??? kfree(devinfo); > +??? kfree(tpinfo); > } > > /* > -- > 1.7.0.1 > > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/