162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * USB Attached SCSI 462306a36Sopenharmony_ci * Note that this is not the same as the USB Mass Storage driver 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2016 762306a36Sopenharmony_ci * Copyright Matthew Wilcox for Intel Corp, 2010 862306a36Sopenharmony_ci * Copyright Sarah Sharp for Intel Corp, 2010 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/blkdev.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/usb.h> 1662306a36Sopenharmony_ci#include <linux/usb_usual.h> 1762306a36Sopenharmony_ci#include <linux/usb/hcd.h> 1862306a36Sopenharmony_ci#include <linux/usb/storage.h> 1962306a36Sopenharmony_ci#include <linux/usb/uas.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <scsi/scsi.h> 2262306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 2362306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 2462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 2562306a36Sopenharmony_ci#include <scsi/scsi_device.h> 2662306a36Sopenharmony_ci#include <scsi/scsi_host.h> 2762306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "uas-detect.h" 3062306a36Sopenharmony_ci#include "scsiglue.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define MAX_CMNDS 256 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct uas_dev_info { 3562306a36Sopenharmony_ci struct usb_interface *intf; 3662306a36Sopenharmony_ci struct usb_device *udev; 3762306a36Sopenharmony_ci struct usb_anchor cmd_urbs; 3862306a36Sopenharmony_ci struct usb_anchor sense_urbs; 3962306a36Sopenharmony_ci struct usb_anchor data_urbs; 4062306a36Sopenharmony_ci unsigned long flags; 4162306a36Sopenharmony_ci int qdepth, resetting; 4262306a36Sopenharmony_ci unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; 4362306a36Sopenharmony_ci unsigned use_streams:1; 4462306a36Sopenharmony_ci unsigned shutdown:1; 4562306a36Sopenharmony_ci struct scsi_cmnd *cmnd[MAX_CMNDS]; 4662306a36Sopenharmony_ci spinlock_t lock; 4762306a36Sopenharmony_ci struct work_struct work; 4862306a36Sopenharmony_ci struct work_struct scan_work; /* for async scanning */ 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cienum { 5262306a36Sopenharmony_ci SUBMIT_STATUS_URB = BIT(1), 5362306a36Sopenharmony_ci ALLOC_DATA_IN_URB = BIT(2), 5462306a36Sopenharmony_ci SUBMIT_DATA_IN_URB = BIT(3), 5562306a36Sopenharmony_ci ALLOC_DATA_OUT_URB = BIT(4), 5662306a36Sopenharmony_ci SUBMIT_DATA_OUT_URB = BIT(5), 5762306a36Sopenharmony_ci ALLOC_CMD_URB = BIT(6), 5862306a36Sopenharmony_ci SUBMIT_CMD_URB = BIT(7), 5962306a36Sopenharmony_ci COMMAND_INFLIGHT = BIT(8), 6062306a36Sopenharmony_ci DATA_IN_URB_INFLIGHT = BIT(9), 6162306a36Sopenharmony_ci DATA_OUT_URB_INFLIGHT = BIT(10), 6262306a36Sopenharmony_ci COMMAND_ABORTED = BIT(11), 6362306a36Sopenharmony_ci IS_IN_WORK_LIST = BIT(12), 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* Overrides scsi_pointer */ 6762306a36Sopenharmony_cistruct uas_cmd_info { 6862306a36Sopenharmony_ci unsigned int state; 6962306a36Sopenharmony_ci unsigned int uas_tag; 7062306a36Sopenharmony_ci struct urb *cmd_urb; 7162306a36Sopenharmony_ci struct urb *data_in_urb; 7262306a36Sopenharmony_ci struct urb *data_out_urb; 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* I hate forward declarations, but I actually have a loop */ 7662306a36Sopenharmony_cistatic int uas_submit_urbs(struct scsi_cmnd *cmnd, 7762306a36Sopenharmony_ci struct uas_dev_info *devinfo); 7862306a36Sopenharmony_cistatic void uas_do_work(struct work_struct *work); 7962306a36Sopenharmony_cistatic int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller); 8062306a36Sopenharmony_cistatic void uas_free_streams(struct uas_dev_info *devinfo); 8162306a36Sopenharmony_cistatic void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, 8262306a36Sopenharmony_ci int status); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * This driver needs its own workqueue, as we need to control memory allocation. 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * In the course of error handling and power management uas_wait_for_pending_cmnds() 8862306a36Sopenharmony_ci * needs to flush pending work items. In these contexts we cannot allocate memory 8962306a36Sopenharmony_ci * by doing block IO as we would deadlock. For the same reason we cannot wait 9062306a36Sopenharmony_ci * for anything allocating memory not heeding these constraints. 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * So we have to control all work items that can be on the workqueue we flush. 9362306a36Sopenharmony_ci * Hence we cannot share a queue and need our own. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_cistatic struct workqueue_struct *workqueue; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic void uas_do_work(struct work_struct *work) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct uas_dev_info *devinfo = 10062306a36Sopenharmony_ci container_of(work, struct uas_dev_info, work); 10162306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo; 10262306a36Sopenharmony_ci struct scsi_cmnd *cmnd; 10362306a36Sopenharmony_ci unsigned long flags; 10462306a36Sopenharmony_ci int i, err; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (devinfo->resetting) 10962306a36Sopenharmony_ci goto out; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci for (i = 0; i < devinfo->qdepth; i++) { 11262306a36Sopenharmony_ci if (!devinfo->cmnd[i]) 11362306a36Sopenharmony_ci continue; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci cmnd = devinfo->cmnd[i]; 11662306a36Sopenharmony_ci cmdinfo = scsi_cmd_priv(cmnd); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (!(cmdinfo->state & IS_IN_WORK_LIST)) 11962306a36Sopenharmony_ci continue; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci err = uas_submit_urbs(cmnd, cmnd->device->hostdata); 12262306a36Sopenharmony_ci if (!err) 12362306a36Sopenharmony_ci cmdinfo->state &= ~IS_IN_WORK_LIST; 12462306a36Sopenharmony_ci else 12562306a36Sopenharmony_ci queue_work(workqueue, &devinfo->work); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ciout: 12862306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void uas_scan_work(struct work_struct *work) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct uas_dev_info *devinfo = 13462306a36Sopenharmony_ci container_of(work, struct uas_dev_info, scan_work); 13562306a36Sopenharmony_ci struct Scsi_Host *shost = usb_get_intfdata(devinfo->intf); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci dev_dbg(&devinfo->intf->dev, "starting scan\n"); 13862306a36Sopenharmony_ci scsi_scan_host(shost); 13962306a36Sopenharmony_ci dev_dbg(&devinfo->intf->dev, "scan complete\n"); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void uas_add_work(struct scsi_cmnd *cmnd) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 14562306a36Sopenharmony_ci struct uas_dev_info *devinfo = cmnd->device->hostdata; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci lockdep_assert_held(&devinfo->lock); 14862306a36Sopenharmony_ci cmdinfo->state |= IS_IN_WORK_LIST; 14962306a36Sopenharmony_ci queue_work(workqueue, &devinfo->work); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void uas_zap_pending(struct uas_dev_info *devinfo, int result) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo; 15562306a36Sopenharmony_ci struct scsi_cmnd *cmnd; 15662306a36Sopenharmony_ci unsigned long flags; 15762306a36Sopenharmony_ci int i, err; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 16062306a36Sopenharmony_ci for (i = 0; i < devinfo->qdepth; i++) { 16162306a36Sopenharmony_ci if (!devinfo->cmnd[i]) 16262306a36Sopenharmony_ci continue; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci cmnd = devinfo->cmnd[i]; 16562306a36Sopenharmony_ci cmdinfo = scsi_cmd_priv(cmnd); 16662306a36Sopenharmony_ci uas_log_cmd_state(cmnd, __func__, 0); 16762306a36Sopenharmony_ci /* Sense urbs were killed, clear COMMAND_INFLIGHT manually */ 16862306a36Sopenharmony_ci cmdinfo->state &= ~COMMAND_INFLIGHT; 16962306a36Sopenharmony_ci cmnd->result = result << 16; 17062306a36Sopenharmony_ci err = uas_try_complete(cmnd, __func__); 17162306a36Sopenharmony_ci WARN_ON(err != 0); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct sense_iu *sense_iu = urb->transfer_buffer; 17962306a36Sopenharmony_ci struct scsi_device *sdev = cmnd->device; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (urb->actual_length > 16) { 18262306a36Sopenharmony_ci unsigned len = be16_to_cpup(&sense_iu->len); 18362306a36Sopenharmony_ci if (len + 16 != urb->actual_length) { 18462306a36Sopenharmony_ci int newlen = min(len + 16, urb->actual_length) - 16; 18562306a36Sopenharmony_ci if (newlen < 0) 18662306a36Sopenharmony_ci newlen = 0; 18762306a36Sopenharmony_ci sdev_printk(KERN_INFO, sdev, "%s: urb length %d " 18862306a36Sopenharmony_ci "disagrees with IU sense data length %d, " 18962306a36Sopenharmony_ci "using %d bytes of sense data\n", __func__, 19062306a36Sopenharmony_ci urb->actual_length, len, newlen); 19162306a36Sopenharmony_ci len = newlen; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci memcpy(cmnd->sense_buffer, sense_iu->sense, len); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci cmnd->result = sense_iu->status; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix, 20062306a36Sopenharmony_ci int status) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct uas_cmd_info *ci = scsi_cmd_priv(cmnd); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (status == -ENODEV) /* too late */ 20562306a36Sopenharmony_ci return; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci scmd_printk(KERN_INFO, cmnd, 20862306a36Sopenharmony_ci "%s %d uas-tag %d inflight:%s%s%s%s%s%s%s%s%s%s%s%s ", 20962306a36Sopenharmony_ci prefix, status, ci->uas_tag, 21062306a36Sopenharmony_ci (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "", 21162306a36Sopenharmony_ci (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "", 21262306a36Sopenharmony_ci (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "", 21362306a36Sopenharmony_ci (ci->state & ALLOC_DATA_OUT_URB) ? " a-out" : "", 21462306a36Sopenharmony_ci (ci->state & SUBMIT_DATA_OUT_URB) ? " s-out" : "", 21562306a36Sopenharmony_ci (ci->state & ALLOC_CMD_URB) ? " a-cmd" : "", 21662306a36Sopenharmony_ci (ci->state & SUBMIT_CMD_URB) ? " s-cmd" : "", 21762306a36Sopenharmony_ci (ci->state & COMMAND_INFLIGHT) ? " CMD" : "", 21862306a36Sopenharmony_ci (ci->state & DATA_IN_URB_INFLIGHT) ? " IN" : "", 21962306a36Sopenharmony_ci (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT" : "", 22062306a36Sopenharmony_ci (ci->state & COMMAND_ABORTED) ? " abort" : "", 22162306a36Sopenharmony_ci (ci->state & IS_IN_WORK_LIST) ? " work" : ""); 22262306a36Sopenharmony_ci scsi_print_command(cmnd); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic void uas_free_unsubmitted_urbs(struct scsi_cmnd *cmnd) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (!cmnd) 23062306a36Sopenharmony_ci return; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci cmdinfo = scsi_cmd_priv(cmnd); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (cmdinfo->state & SUBMIT_CMD_URB) 23562306a36Sopenharmony_ci usb_free_urb(cmdinfo->cmd_urb); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* data urbs may have never gotten their submit flag set */ 23862306a36Sopenharmony_ci if (!(cmdinfo->state & DATA_IN_URB_INFLIGHT)) 23962306a36Sopenharmony_ci usb_free_urb(cmdinfo->data_in_urb); 24062306a36Sopenharmony_ci if (!(cmdinfo->state & DATA_OUT_URB_INFLIGHT)) 24162306a36Sopenharmony_ci usb_free_urb(cmdinfo->data_out_urb); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 24762306a36Sopenharmony_ci struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci lockdep_assert_held(&devinfo->lock); 25062306a36Sopenharmony_ci if (cmdinfo->state & (COMMAND_INFLIGHT | 25162306a36Sopenharmony_ci DATA_IN_URB_INFLIGHT | 25262306a36Sopenharmony_ci DATA_OUT_URB_INFLIGHT | 25362306a36Sopenharmony_ci COMMAND_ABORTED)) 25462306a36Sopenharmony_ci return -EBUSY; 25562306a36Sopenharmony_ci devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL; 25662306a36Sopenharmony_ci uas_free_unsubmitted_urbs(cmnd); 25762306a36Sopenharmony_ci scsi_done(cmnd); 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, 26262306a36Sopenharmony_ci unsigned direction) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 26562306a36Sopenharmony_ci int err; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci cmdinfo->state |= direction | SUBMIT_STATUS_URB; 26862306a36Sopenharmony_ci err = uas_submit_urbs(cmnd, cmnd->device->hostdata); 26962306a36Sopenharmony_ci if (err) { 27062306a36Sopenharmony_ci uas_add_work(cmnd); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic bool uas_evaluate_response_iu(struct response_iu *riu, struct scsi_cmnd *cmnd) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci u8 response_code = riu->response_code; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci switch (response_code) { 27962306a36Sopenharmony_ci case RC_INCORRECT_LUN: 28062306a36Sopenharmony_ci set_host_byte(cmnd, DID_BAD_TARGET); 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci case RC_TMF_SUCCEEDED: 28362306a36Sopenharmony_ci set_host_byte(cmnd, DID_OK); 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci case RC_TMF_NOT_SUPPORTED: 28662306a36Sopenharmony_ci set_host_byte(cmnd, DID_BAD_TARGET); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci default: 28962306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "response iu", response_code); 29062306a36Sopenharmony_ci set_host_byte(cmnd, DID_ERROR); 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return response_code == RC_TMF_SUCCEEDED; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void uas_stat_cmplt(struct urb *urb) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct iu *iu = urb->transfer_buffer; 30062306a36Sopenharmony_ci struct Scsi_Host *shost = urb->context; 30162306a36Sopenharmony_ci struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; 30262306a36Sopenharmony_ci struct urb *data_in_urb = NULL; 30362306a36Sopenharmony_ci struct urb *data_out_urb = NULL; 30462306a36Sopenharmony_ci struct scsi_cmnd *cmnd; 30562306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo; 30662306a36Sopenharmony_ci unsigned long flags; 30762306a36Sopenharmony_ci unsigned int idx; 30862306a36Sopenharmony_ci int status = urb->status; 30962306a36Sopenharmony_ci bool success; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (devinfo->resetting) 31462306a36Sopenharmony_ci goto out; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (status) { 31762306a36Sopenharmony_ci if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN) 31862306a36Sopenharmony_ci dev_err(&urb->dev->dev, "stat urb: status %d\n", status); 31962306a36Sopenharmony_ci goto out; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci idx = be16_to_cpup(&iu->tag) - 1; 32362306a36Sopenharmony_ci if (idx >= MAX_CMNDS || !devinfo->cmnd[idx]) { 32462306a36Sopenharmony_ci dev_err(&urb->dev->dev, 32562306a36Sopenharmony_ci "stat urb: no pending cmd for uas-tag %d\n", idx + 1); 32662306a36Sopenharmony_ci goto out; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci cmnd = devinfo->cmnd[idx]; 33062306a36Sopenharmony_ci cmdinfo = scsi_cmd_priv(cmnd); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (!(cmdinfo->state & COMMAND_INFLIGHT)) { 33362306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "unexpected status cmplt", 0); 33462306a36Sopenharmony_ci goto out; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci switch (iu->iu_id) { 33862306a36Sopenharmony_ci case IU_ID_STATUS: 33962306a36Sopenharmony_ci uas_sense(urb, cmnd); 34062306a36Sopenharmony_ci if (cmnd->result != 0) { 34162306a36Sopenharmony_ci /* cancel data transfers on error */ 34262306a36Sopenharmony_ci data_in_urb = usb_get_urb(cmdinfo->data_in_urb); 34362306a36Sopenharmony_ci data_out_urb = usb_get_urb(cmdinfo->data_out_urb); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci cmdinfo->state &= ~COMMAND_INFLIGHT; 34662306a36Sopenharmony_ci uas_try_complete(cmnd, __func__); 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci case IU_ID_READ_READY: 34962306a36Sopenharmony_ci if (!cmdinfo->data_in_urb || 35062306a36Sopenharmony_ci (cmdinfo->state & DATA_IN_URB_INFLIGHT)) { 35162306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "unexpected read rdy", 0); 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB); 35562306a36Sopenharmony_ci break; 35662306a36Sopenharmony_ci case IU_ID_WRITE_READY: 35762306a36Sopenharmony_ci if (!cmdinfo->data_out_urb || 35862306a36Sopenharmony_ci (cmdinfo->state & DATA_OUT_URB_INFLIGHT)) { 35962306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "unexpected write rdy", 0); 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB); 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci case IU_ID_RESPONSE: 36562306a36Sopenharmony_ci cmdinfo->state &= ~COMMAND_INFLIGHT; 36662306a36Sopenharmony_ci success = uas_evaluate_response_iu((struct response_iu *)iu, cmnd); 36762306a36Sopenharmony_ci if (!success) { 36862306a36Sopenharmony_ci /* Error, cancel data transfers */ 36962306a36Sopenharmony_ci data_in_urb = usb_get_urb(cmdinfo->data_in_urb); 37062306a36Sopenharmony_ci data_out_urb = usb_get_urb(cmdinfo->data_out_urb); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci uas_try_complete(cmnd, __func__); 37362306a36Sopenharmony_ci break; 37462306a36Sopenharmony_ci default: 37562306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "bogus IU", iu->iu_id); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ciout: 37862306a36Sopenharmony_ci usb_free_urb(urb); 37962306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Unlinking of data urbs must be done without holding the lock */ 38262306a36Sopenharmony_ci if (data_in_urb) { 38362306a36Sopenharmony_ci usb_unlink_urb(data_in_urb); 38462306a36Sopenharmony_ci usb_put_urb(data_in_urb); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci if (data_out_urb) { 38762306a36Sopenharmony_ci usb_unlink_urb(data_out_urb); 38862306a36Sopenharmony_ci usb_put_urb(data_out_urb); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic void uas_data_cmplt(struct urb *urb) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct scsi_cmnd *cmnd = urb->context; 39562306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 39662306a36Sopenharmony_ci struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; 39762306a36Sopenharmony_ci struct scsi_data_buffer *sdb = &cmnd->sdb; 39862306a36Sopenharmony_ci unsigned long flags; 39962306a36Sopenharmony_ci int status = urb->status; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (cmdinfo->data_in_urb == urb) { 40462306a36Sopenharmony_ci cmdinfo->state &= ~DATA_IN_URB_INFLIGHT; 40562306a36Sopenharmony_ci cmdinfo->data_in_urb = NULL; 40662306a36Sopenharmony_ci } else if (cmdinfo->data_out_urb == urb) { 40762306a36Sopenharmony_ci cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT; 40862306a36Sopenharmony_ci cmdinfo->data_out_urb = NULL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (devinfo->resetting) 41262306a36Sopenharmony_ci goto out; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* Data urbs should not complete before the cmd urb is submitted */ 41562306a36Sopenharmony_ci if (cmdinfo->state & SUBMIT_CMD_URB) { 41662306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "unexpected data cmplt", 0); 41762306a36Sopenharmony_ci goto out; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (status) { 42162306a36Sopenharmony_ci if (status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN) 42262306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "data cmplt err", status); 42362306a36Sopenharmony_ci /* error: no data transfered */ 42462306a36Sopenharmony_ci scsi_set_resid(cmnd, sdb->length); 42562306a36Sopenharmony_ci } else { 42662306a36Sopenharmony_ci scsi_set_resid(cmnd, sdb->length - urb->actual_length); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci uas_try_complete(cmnd, __func__); 42962306a36Sopenharmony_ciout: 43062306a36Sopenharmony_ci usb_free_urb(urb); 43162306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void uas_cmd_cmplt(struct urb *urb) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci if (urb->status) 43762306a36Sopenharmony_ci dev_err(&urb->dev->dev, "cmd cmplt err %d\n", urb->status); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci usb_free_urb(urb); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, 44362306a36Sopenharmony_ci struct scsi_cmnd *cmnd, 44462306a36Sopenharmony_ci enum dma_data_direction dir) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct usb_device *udev = devinfo->udev; 44762306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 44862306a36Sopenharmony_ci struct urb *urb = usb_alloc_urb(0, gfp); 44962306a36Sopenharmony_ci struct scsi_data_buffer *sdb = &cmnd->sdb; 45062306a36Sopenharmony_ci unsigned int pipe = (dir == DMA_FROM_DEVICE) 45162306a36Sopenharmony_ci ? devinfo->data_in_pipe : devinfo->data_out_pipe; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (!urb) 45462306a36Sopenharmony_ci goto out; 45562306a36Sopenharmony_ci usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, 45662306a36Sopenharmony_ci uas_data_cmplt, cmnd); 45762306a36Sopenharmony_ci if (devinfo->use_streams) 45862306a36Sopenharmony_ci urb->stream_id = cmdinfo->uas_tag; 45962306a36Sopenharmony_ci urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; 46062306a36Sopenharmony_ci urb->sg = sdb->table.sgl; 46162306a36Sopenharmony_ci out: 46262306a36Sopenharmony_ci return urb; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, 46662306a36Sopenharmony_ci struct scsi_cmnd *cmnd) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct usb_device *udev = devinfo->udev; 46962306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 47062306a36Sopenharmony_ci struct urb *urb = usb_alloc_urb(0, gfp); 47162306a36Sopenharmony_ci struct sense_iu *iu; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (!urb) 47462306a36Sopenharmony_ci goto out; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci iu = kzalloc(sizeof(*iu), gfp); 47762306a36Sopenharmony_ci if (!iu) 47862306a36Sopenharmony_ci goto free; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), 48162306a36Sopenharmony_ci uas_stat_cmplt, cmnd->device->host); 48262306a36Sopenharmony_ci if (devinfo->use_streams) 48362306a36Sopenharmony_ci urb->stream_id = cmdinfo->uas_tag; 48462306a36Sopenharmony_ci urb->transfer_flags |= URB_FREE_BUFFER; 48562306a36Sopenharmony_ci out: 48662306a36Sopenharmony_ci return urb; 48762306a36Sopenharmony_ci free: 48862306a36Sopenharmony_ci usb_free_urb(urb); 48962306a36Sopenharmony_ci return NULL; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, 49362306a36Sopenharmony_ci struct scsi_cmnd *cmnd) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct usb_device *udev = devinfo->udev; 49662306a36Sopenharmony_ci struct scsi_device *sdev = cmnd->device; 49762306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 49862306a36Sopenharmony_ci struct urb *urb = usb_alloc_urb(0, gfp); 49962306a36Sopenharmony_ci struct command_iu *iu; 50062306a36Sopenharmony_ci int len; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (!urb) 50362306a36Sopenharmony_ci goto out; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci len = cmnd->cmd_len - 16; 50662306a36Sopenharmony_ci if (len < 0) 50762306a36Sopenharmony_ci len = 0; 50862306a36Sopenharmony_ci len = ALIGN(len, 4); 50962306a36Sopenharmony_ci iu = kzalloc(sizeof(*iu) + len, gfp); 51062306a36Sopenharmony_ci if (!iu) 51162306a36Sopenharmony_ci goto free; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci iu->iu_id = IU_ID_COMMAND; 51462306a36Sopenharmony_ci iu->tag = cpu_to_be16(cmdinfo->uas_tag); 51562306a36Sopenharmony_ci iu->prio_attr = UAS_SIMPLE_TAG; 51662306a36Sopenharmony_ci iu->len = len; 51762306a36Sopenharmony_ci int_to_scsilun(sdev->lun, &iu->lun); 51862306a36Sopenharmony_ci memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len, 52162306a36Sopenharmony_ci uas_cmd_cmplt, NULL); 52262306a36Sopenharmony_ci urb->transfer_flags |= URB_FREE_BUFFER; 52362306a36Sopenharmony_ci out: 52462306a36Sopenharmony_ci return urb; 52562306a36Sopenharmony_ci free: 52662306a36Sopenharmony_ci usb_free_urb(urb); 52762306a36Sopenharmony_ci return NULL; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci/* 53162306a36Sopenharmony_ci * Why should I request the Status IU before sending the Command IU? Spec 53262306a36Sopenharmony_ci * says to, but also says the device may receive them in any order. Seems 53362306a36Sopenharmony_ci * daft to me. 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic struct urb *uas_submit_sense_urb(struct scsi_cmnd *cmnd, gfp_t gfp) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct uas_dev_info *devinfo = cmnd->device->hostdata; 53962306a36Sopenharmony_ci struct urb *urb; 54062306a36Sopenharmony_ci int err; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci urb = uas_alloc_sense_urb(devinfo, gfp, cmnd); 54362306a36Sopenharmony_ci if (!urb) 54462306a36Sopenharmony_ci return NULL; 54562306a36Sopenharmony_ci usb_anchor_urb(urb, &devinfo->sense_urbs); 54662306a36Sopenharmony_ci err = usb_submit_urb(urb, gfp); 54762306a36Sopenharmony_ci if (err) { 54862306a36Sopenharmony_ci usb_unanchor_urb(urb); 54962306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "sense submit err", err); 55062306a36Sopenharmony_ci usb_free_urb(urb); 55162306a36Sopenharmony_ci return NULL; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci return urb; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int uas_submit_urbs(struct scsi_cmnd *cmnd, 55762306a36Sopenharmony_ci struct uas_dev_info *devinfo) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 56062306a36Sopenharmony_ci struct urb *urb; 56162306a36Sopenharmony_ci int err; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci lockdep_assert_held(&devinfo->lock); 56462306a36Sopenharmony_ci if (cmdinfo->state & SUBMIT_STATUS_URB) { 56562306a36Sopenharmony_ci urb = uas_submit_sense_urb(cmnd, GFP_ATOMIC); 56662306a36Sopenharmony_ci if (!urb) 56762306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 56862306a36Sopenharmony_ci cmdinfo->state &= ~SUBMIT_STATUS_URB; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (cmdinfo->state & ALLOC_DATA_IN_URB) { 57262306a36Sopenharmony_ci cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, GFP_ATOMIC, 57362306a36Sopenharmony_ci cmnd, DMA_FROM_DEVICE); 57462306a36Sopenharmony_ci if (!cmdinfo->data_in_urb) 57562306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 57662306a36Sopenharmony_ci cmdinfo->state &= ~ALLOC_DATA_IN_URB; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (cmdinfo->state & SUBMIT_DATA_IN_URB) { 58062306a36Sopenharmony_ci usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs); 58162306a36Sopenharmony_ci err = usb_submit_urb(cmdinfo->data_in_urb, GFP_ATOMIC); 58262306a36Sopenharmony_ci if (err) { 58362306a36Sopenharmony_ci usb_unanchor_urb(cmdinfo->data_in_urb); 58462306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "data in submit err", err); 58562306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci cmdinfo->state &= ~SUBMIT_DATA_IN_URB; 58862306a36Sopenharmony_ci cmdinfo->state |= DATA_IN_URB_INFLIGHT; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (cmdinfo->state & ALLOC_DATA_OUT_URB) { 59262306a36Sopenharmony_ci cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, GFP_ATOMIC, 59362306a36Sopenharmony_ci cmnd, DMA_TO_DEVICE); 59462306a36Sopenharmony_ci if (!cmdinfo->data_out_urb) 59562306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 59662306a36Sopenharmony_ci cmdinfo->state &= ~ALLOC_DATA_OUT_URB; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (cmdinfo->state & SUBMIT_DATA_OUT_URB) { 60062306a36Sopenharmony_ci usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs); 60162306a36Sopenharmony_ci err = usb_submit_urb(cmdinfo->data_out_urb, GFP_ATOMIC); 60262306a36Sopenharmony_ci if (err) { 60362306a36Sopenharmony_ci usb_unanchor_urb(cmdinfo->data_out_urb); 60462306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "data out submit err", err); 60562306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci cmdinfo->state &= ~SUBMIT_DATA_OUT_URB; 60862306a36Sopenharmony_ci cmdinfo->state |= DATA_OUT_URB_INFLIGHT; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (cmdinfo->state & ALLOC_CMD_URB) { 61262306a36Sopenharmony_ci cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, GFP_ATOMIC, cmnd); 61362306a36Sopenharmony_ci if (!cmdinfo->cmd_urb) 61462306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 61562306a36Sopenharmony_ci cmdinfo->state &= ~ALLOC_CMD_URB; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (cmdinfo->state & SUBMIT_CMD_URB) { 61962306a36Sopenharmony_ci usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs); 62062306a36Sopenharmony_ci err = usb_submit_urb(cmdinfo->cmd_urb, GFP_ATOMIC); 62162306a36Sopenharmony_ci if (err) { 62262306a36Sopenharmony_ci usb_unanchor_urb(cmdinfo->cmd_urb); 62362306a36Sopenharmony_ci uas_log_cmd_state(cmnd, "cmd submit err", err); 62462306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci cmdinfo->cmd_urb = NULL; 62762306a36Sopenharmony_ci cmdinfo->state &= ~SUBMIT_CMD_URB; 62862306a36Sopenharmony_ci cmdinfo->state |= COMMAND_INFLIGHT; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic int uas_queuecommand_lck(struct scsi_cmnd *cmnd) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct scsi_device *sdev = cmnd->device; 63762306a36Sopenharmony_ci struct uas_dev_info *devinfo = sdev->hostdata; 63862306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 63962306a36Sopenharmony_ci unsigned long flags; 64062306a36Sopenharmony_ci int idx, err; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* Re-check scsi_block_requests now that we've the host-lock */ 64362306a36Sopenharmony_ci if (cmnd->device->host->host_self_blocked) 64462306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if ((devinfo->flags & US_FL_NO_ATA_1X) && 64762306a36Sopenharmony_ci (cmnd->cmnd[0] == ATA_12 || cmnd->cmnd[0] == ATA_16)) { 64862306a36Sopenharmony_ci memcpy(cmnd->sense_buffer, usb_stor_sense_invalidCDB, 64962306a36Sopenharmony_ci sizeof(usb_stor_sense_invalidCDB)); 65062306a36Sopenharmony_ci cmnd->result = SAM_STAT_CHECK_CONDITION; 65162306a36Sopenharmony_ci scsi_done(cmnd); 65262306a36Sopenharmony_ci return 0; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (devinfo->resetting) { 65862306a36Sopenharmony_ci set_host_byte(cmnd, DID_ERROR); 65962306a36Sopenharmony_ci scsi_done(cmnd); 66062306a36Sopenharmony_ci goto zombie; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* Find a free uas-tag */ 66462306a36Sopenharmony_ci for (idx = 0; idx < devinfo->qdepth; idx++) { 66562306a36Sopenharmony_ci if (!devinfo->cmnd[idx]) 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci if (idx == devinfo->qdepth) { 66962306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 67062306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci memset(cmdinfo, 0, sizeof(*cmdinfo)); 67462306a36Sopenharmony_ci cmdinfo->uas_tag = idx + 1; /* uas-tag == usb-stream-id, so 1 based */ 67562306a36Sopenharmony_ci cmdinfo->state = SUBMIT_STATUS_URB | ALLOC_CMD_URB | SUBMIT_CMD_URB; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci switch (cmnd->sc_data_direction) { 67862306a36Sopenharmony_ci case DMA_FROM_DEVICE: 67962306a36Sopenharmony_ci cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci case DMA_BIDIRECTIONAL: 68262306a36Sopenharmony_ci cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; 68362306a36Sopenharmony_ci fallthrough; 68462306a36Sopenharmony_ci case DMA_TO_DEVICE: 68562306a36Sopenharmony_ci cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB; 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci case DMA_NONE: 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (!devinfo->use_streams) 69262306a36Sopenharmony_ci cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci err = uas_submit_urbs(cmnd, devinfo); 69562306a36Sopenharmony_ci /* 69662306a36Sopenharmony_ci * in case of fatal errors the SCSI layer is peculiar 69762306a36Sopenharmony_ci * a command that has finished is a success for the purpose 69862306a36Sopenharmony_ci * of queueing, no matter how fatal the error 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci if (err == -ENODEV) { 70162306a36Sopenharmony_ci set_host_byte(cmnd, DID_ERROR); 70262306a36Sopenharmony_ci scsi_done(cmnd); 70362306a36Sopenharmony_ci goto zombie; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci if (err) { 70662306a36Sopenharmony_ci /* If we did nothing, give up now */ 70762306a36Sopenharmony_ci if (cmdinfo->state & SUBMIT_STATUS_URB) { 70862306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 70962306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci uas_add_work(cmnd); 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci devinfo->cmnd[idx] = cmnd; 71562306a36Sopenharmony_cizombie: 71662306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic DEF_SCSI_QCMD(uas_queuecommand) 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci/* 72362306a36Sopenharmony_ci * For now we do not support actually sending an abort to the device, so 72462306a36Sopenharmony_ci * this eh always fails. Still we must define it to make sure that we've 72562306a36Sopenharmony_ci * dropped all references to the cmnd in question once this function exits. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_cistatic int uas_eh_abort_handler(struct scsi_cmnd *cmnd) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct uas_cmd_info *cmdinfo = scsi_cmd_priv(cmnd); 73062306a36Sopenharmony_ci struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; 73162306a36Sopenharmony_ci struct urb *data_in_urb = NULL; 73262306a36Sopenharmony_ci struct urb *data_out_urb = NULL; 73362306a36Sopenharmony_ci unsigned long flags; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci uas_log_cmd_state(cmnd, __func__, 0); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* Ensure that try_complete does not call scsi_done */ 74062306a36Sopenharmony_ci cmdinfo->state |= COMMAND_ABORTED; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* Drop all refs to this cmnd, kill data urbs to break their ref */ 74362306a36Sopenharmony_ci devinfo->cmnd[cmdinfo->uas_tag - 1] = NULL; 74462306a36Sopenharmony_ci if (cmdinfo->state & DATA_IN_URB_INFLIGHT) 74562306a36Sopenharmony_ci data_in_urb = usb_get_urb(cmdinfo->data_in_urb); 74662306a36Sopenharmony_ci if (cmdinfo->state & DATA_OUT_URB_INFLIGHT) 74762306a36Sopenharmony_ci data_out_urb = usb_get_urb(cmdinfo->data_out_urb); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci uas_free_unsubmitted_urbs(cmnd); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (data_in_urb) { 75462306a36Sopenharmony_ci usb_kill_urb(data_in_urb); 75562306a36Sopenharmony_ci usb_put_urb(data_in_urb); 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci if (data_out_urb) { 75862306a36Sopenharmony_ci usb_kill_urb(data_out_urb); 75962306a36Sopenharmony_ci usb_put_urb(data_out_urb); 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci return FAILED; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct scsi_device *sdev = cmnd->device; 76862306a36Sopenharmony_ci struct uas_dev_info *devinfo = sdev->hostdata; 76962306a36Sopenharmony_ci struct usb_device *udev = devinfo->udev; 77062306a36Sopenharmony_ci unsigned long flags; 77162306a36Sopenharmony_ci int err; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci err = usb_lock_device_for_reset(udev, devinfo->intf); 77462306a36Sopenharmony_ci if (err) { 77562306a36Sopenharmony_ci shost_printk(KERN_ERR, sdev->host, 77662306a36Sopenharmony_ci "%s FAILED to get lock err %d\n", __func__, err); 77762306a36Sopenharmony_ci return FAILED; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 78362306a36Sopenharmony_ci devinfo->resetting = 1; 78462306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci usb_kill_anchored_urbs(&devinfo->cmd_urbs); 78762306a36Sopenharmony_ci usb_kill_anchored_urbs(&devinfo->sense_urbs); 78862306a36Sopenharmony_ci usb_kill_anchored_urbs(&devinfo->data_urbs); 78962306a36Sopenharmony_ci uas_zap_pending(devinfo, DID_RESET); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci err = usb_reset_device(udev); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 79462306a36Sopenharmony_ci devinfo->resetting = 0; 79562306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci usb_unlock_device(udev); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (err) { 80062306a36Sopenharmony_ci shost_printk(KERN_INFO, sdev->host, "%s FAILED err %d\n", 80162306a36Sopenharmony_ci __func__, err); 80262306a36Sopenharmony_ci return FAILED; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__); 80662306a36Sopenharmony_ci return SUCCESS; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic int uas_target_alloc(struct scsi_target *starget) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct uas_dev_info *devinfo = (struct uas_dev_info *) 81262306a36Sopenharmony_ci dev_to_shost(starget->dev.parent)->hostdata; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (devinfo->flags & US_FL_NO_REPORT_LUNS) 81562306a36Sopenharmony_ci starget->no_report_luns = 1; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return 0; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic int uas_slave_alloc(struct scsi_device *sdev) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct uas_dev_info *devinfo = 82362306a36Sopenharmony_ci (struct uas_dev_info *)sdev->host->hostdata; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci sdev->hostdata = devinfo; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* 82862306a36Sopenharmony_ci * The protocol has no requirements on alignment in the strict sense. 82962306a36Sopenharmony_ci * Controllers may or may not have alignment restrictions. 83062306a36Sopenharmony_ci * As this is not exported, we use an extremely conservative guess. 83162306a36Sopenharmony_ci */ 83262306a36Sopenharmony_ci blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (devinfo->flags & US_FL_MAX_SECTORS_64) 83562306a36Sopenharmony_ci blk_queue_max_hw_sectors(sdev->request_queue, 64); 83662306a36Sopenharmony_ci else if (devinfo->flags & US_FL_MAX_SECTORS_240) 83762306a36Sopenharmony_ci blk_queue_max_hw_sectors(sdev->request_queue, 240); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci return 0; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cistatic int uas_slave_configure(struct scsi_device *sdev) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci struct uas_dev_info *devinfo = sdev->hostdata; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (devinfo->flags & US_FL_NO_REPORT_OPCODES) 84762306a36Sopenharmony_ci sdev->no_report_opcodes = 1; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci /* A few buggy USB-ATA bridges don't understand FUA */ 85062306a36Sopenharmony_ci if (devinfo->flags & US_FL_BROKEN_FUA) 85162306a36Sopenharmony_ci sdev->broken_fua = 1; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* UAS also needs to support FL_ALWAYS_SYNC */ 85462306a36Sopenharmony_ci if (devinfo->flags & US_FL_ALWAYS_SYNC) { 85562306a36Sopenharmony_ci sdev->skip_ms_page_3f = 1; 85662306a36Sopenharmony_ci sdev->skip_ms_page_8 = 1; 85762306a36Sopenharmony_ci sdev->wce_default_on = 1; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* Some disks cannot handle READ_CAPACITY_16 */ 86162306a36Sopenharmony_ci if (devinfo->flags & US_FL_NO_READ_CAPACITY_16) 86262306a36Sopenharmony_ci sdev->no_read_capacity_16 = 1; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* Some disks cannot handle WRITE_SAME */ 86562306a36Sopenharmony_ci if (devinfo->flags & US_FL_NO_SAME) 86662306a36Sopenharmony_ci sdev->no_write_same = 1; 86762306a36Sopenharmony_ci /* 86862306a36Sopenharmony_ci * Some disks return the total number of blocks in response 86962306a36Sopenharmony_ci * to READ CAPACITY rather than the highest block number. 87062306a36Sopenharmony_ci * If this device makes that mistake, tell the sd driver. 87162306a36Sopenharmony_ci */ 87262306a36Sopenharmony_ci if (devinfo->flags & US_FL_FIX_CAPACITY) 87362306a36Sopenharmony_ci sdev->fix_capacity = 1; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* 87662306a36Sopenharmony_ci * in some cases we have to guess 87762306a36Sopenharmony_ci */ 87862306a36Sopenharmony_ci if (devinfo->flags & US_FL_CAPACITY_HEURISTICS) 87962306a36Sopenharmony_ci sdev->guess_capacity = 1; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* 88262306a36Sopenharmony_ci * Some devices report generic values until the media has been 88362306a36Sopenharmony_ci * accessed. Force a READ(10) prior to querying device 88462306a36Sopenharmony_ci * characteristics. 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_ci sdev->read_before_ms = 1; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* 88962306a36Sopenharmony_ci * Some devices don't like MODE SENSE with page=0x3f, 89062306a36Sopenharmony_ci * which is the command used for checking if a device 89162306a36Sopenharmony_ci * is write-protected. Now that we tell the sd driver 89262306a36Sopenharmony_ci * to do a 192-byte transfer with this command the 89362306a36Sopenharmony_ci * majority of devices work fine, but a few still can't 89462306a36Sopenharmony_ci * handle it. The sd driver will simply assume those 89562306a36Sopenharmony_ci * devices are write-enabled. 89662306a36Sopenharmony_ci */ 89762306a36Sopenharmony_ci if (devinfo->flags & US_FL_NO_WP_DETECT) 89862306a36Sopenharmony_ci sdev->skip_ms_page_3f = 1; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci scsi_change_queue_depth(sdev, devinfo->qdepth - 2); 90162306a36Sopenharmony_ci return 0; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cistatic const struct scsi_host_template uas_host_template = { 90562306a36Sopenharmony_ci .module = THIS_MODULE, 90662306a36Sopenharmony_ci .name = "uas", 90762306a36Sopenharmony_ci .queuecommand = uas_queuecommand, 90862306a36Sopenharmony_ci .target_alloc = uas_target_alloc, 90962306a36Sopenharmony_ci .slave_alloc = uas_slave_alloc, 91062306a36Sopenharmony_ci .slave_configure = uas_slave_configure, 91162306a36Sopenharmony_ci .eh_abort_handler = uas_eh_abort_handler, 91262306a36Sopenharmony_ci .eh_device_reset_handler = uas_eh_device_reset_handler, 91362306a36Sopenharmony_ci .this_id = -1, 91462306a36Sopenharmony_ci .skip_settle_delay = 1, 91562306a36Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 91662306a36Sopenharmony_ci .cmd_size = sizeof(struct uas_cmd_info), 91762306a36Sopenharmony_ci}; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 92062306a36Sopenharmony_ci vendorName, productName, useProtocol, useTransport, \ 92162306a36Sopenharmony_ci initFunction, flags) \ 92262306a36Sopenharmony_ci{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 92362306a36Sopenharmony_ci .driver_info = (flags) } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic struct usb_device_id uas_usb_ids[] = { 92662306a36Sopenharmony_ci# include "unusual_uas.h" 92762306a36Sopenharmony_ci { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) }, 92862306a36Sopenharmony_ci { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) }, 92962306a36Sopenharmony_ci { } 93062306a36Sopenharmony_ci}; 93162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, uas_usb_ids); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci#undef UNUSUAL_DEV 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic int uas_switch_interface(struct usb_device *udev, 93662306a36Sopenharmony_ci struct usb_interface *intf) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci struct usb_host_interface *alt; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci alt = uas_find_uas_alt_setting(intf); 94162306a36Sopenharmony_ci if (!alt) 94262306a36Sopenharmony_ci return -ENODEV; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci return usb_set_interface(udev, alt->desc.bInterfaceNumber, 94562306a36Sopenharmony_ci alt->desc.bAlternateSetting); 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic int uas_configure_endpoints(struct uas_dev_info *devinfo) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct usb_host_endpoint *eps[4] = { }; 95162306a36Sopenharmony_ci struct usb_device *udev = devinfo->udev; 95262306a36Sopenharmony_ci int r; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps); 95562306a36Sopenharmony_ci if (r) 95662306a36Sopenharmony_ci return r; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci devinfo->cmd_pipe = usb_sndbulkpipe(udev, 95962306a36Sopenharmony_ci usb_endpoint_num(&eps[0]->desc)); 96062306a36Sopenharmony_ci devinfo->status_pipe = usb_rcvbulkpipe(udev, 96162306a36Sopenharmony_ci usb_endpoint_num(&eps[1]->desc)); 96262306a36Sopenharmony_ci devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 96362306a36Sopenharmony_ci usb_endpoint_num(&eps[2]->desc)); 96462306a36Sopenharmony_ci devinfo->data_out_pipe = usb_sndbulkpipe(udev, 96562306a36Sopenharmony_ci usb_endpoint_num(&eps[3]->desc)); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci if (udev->speed < USB_SPEED_SUPER) { 96862306a36Sopenharmony_ci devinfo->qdepth = 32; 96962306a36Sopenharmony_ci devinfo->use_streams = 0; 97062306a36Sopenharmony_ci } else { 97162306a36Sopenharmony_ci devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 97262306a36Sopenharmony_ci 3, MAX_CMNDS, GFP_NOIO); 97362306a36Sopenharmony_ci if (devinfo->qdepth < 0) 97462306a36Sopenharmony_ci return devinfo->qdepth; 97562306a36Sopenharmony_ci devinfo->use_streams = 1; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci return 0; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic void uas_free_streams(struct uas_dev_info *devinfo) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci struct usb_device *udev = devinfo->udev; 98462306a36Sopenharmony_ci struct usb_host_endpoint *eps[3]; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); 98762306a36Sopenharmony_ci eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); 98862306a36Sopenharmony_ci eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); 98962306a36Sopenharmony_ci usb_free_streams(devinfo->intf, eps, 3, GFP_NOIO); 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci int result = -ENOMEM; 99562306a36Sopenharmony_ci struct Scsi_Host *shost = NULL; 99662306a36Sopenharmony_ci struct uas_dev_info *devinfo; 99762306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 99862306a36Sopenharmony_ci unsigned long dev_flags; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (!uas_use_uas_driver(intf, id, &dev_flags)) 100162306a36Sopenharmony_ci return -ENODEV; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (uas_switch_interface(udev, intf)) 100462306a36Sopenharmony_ci return -ENODEV; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci shost = scsi_host_alloc(&uas_host_template, 100762306a36Sopenharmony_ci sizeof(struct uas_dev_info)); 100862306a36Sopenharmony_ci if (!shost) 100962306a36Sopenharmony_ci goto set_alt0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci shost->max_cmd_len = 16 + 252; 101262306a36Sopenharmony_ci shost->max_id = 1; 101362306a36Sopenharmony_ci shost->max_lun = 256; 101462306a36Sopenharmony_ci shost->max_channel = 0; 101562306a36Sopenharmony_ci shost->sg_tablesize = udev->bus->sg_tablesize; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci devinfo = (struct uas_dev_info *)shost->hostdata; 101862306a36Sopenharmony_ci devinfo->intf = intf; 101962306a36Sopenharmony_ci devinfo->udev = udev; 102062306a36Sopenharmony_ci devinfo->resetting = 0; 102162306a36Sopenharmony_ci devinfo->shutdown = 0; 102262306a36Sopenharmony_ci devinfo->flags = dev_flags; 102362306a36Sopenharmony_ci init_usb_anchor(&devinfo->cmd_urbs); 102462306a36Sopenharmony_ci init_usb_anchor(&devinfo->sense_urbs); 102562306a36Sopenharmony_ci init_usb_anchor(&devinfo->data_urbs); 102662306a36Sopenharmony_ci spin_lock_init(&devinfo->lock); 102762306a36Sopenharmony_ci INIT_WORK(&devinfo->work, uas_do_work); 102862306a36Sopenharmony_ci INIT_WORK(&devinfo->scan_work, uas_scan_work); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci result = uas_configure_endpoints(devinfo); 103162306a36Sopenharmony_ci if (result) 103262306a36Sopenharmony_ci goto set_alt0; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* 103562306a36Sopenharmony_ci * 1 tag is reserved for untagged commands + 103662306a36Sopenharmony_ci * 1 tag to avoid off by one errors in some bridge firmwares 103762306a36Sopenharmony_ci */ 103862306a36Sopenharmony_ci shost->can_queue = devinfo->qdepth - 2; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci usb_set_intfdata(intf, shost); 104162306a36Sopenharmony_ci result = scsi_add_host(shost, &intf->dev); 104262306a36Sopenharmony_ci if (result) 104362306a36Sopenharmony_ci goto free_streams; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* Submit the delayed_work for SCSI-device scanning */ 104662306a36Sopenharmony_ci schedule_work(&devinfo->scan_work); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci return result; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cifree_streams: 105162306a36Sopenharmony_ci uas_free_streams(devinfo); 105262306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 105362306a36Sopenharmony_ciset_alt0: 105462306a36Sopenharmony_ci usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); 105562306a36Sopenharmony_ci if (shost) 105662306a36Sopenharmony_ci scsi_host_put(shost); 105762306a36Sopenharmony_ci return result; 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_cistatic int uas_cmnd_list_empty(struct uas_dev_info *devinfo) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci unsigned long flags; 106362306a36Sopenharmony_ci int i, r = 1; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci for (i = 0; i < devinfo->qdepth; i++) { 106862306a36Sopenharmony_ci if (devinfo->cmnd[i]) { 106962306a36Sopenharmony_ci r = 0; /* Not empty */ 107062306a36Sopenharmony_ci break; 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return r; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci/* 108062306a36Sopenharmony_ci * Wait for any pending cmnds to complete, on usb-2 sense_urbs may temporarily 108162306a36Sopenharmony_ci * get empty while there still is more work to do due to sense-urbs completing 108262306a36Sopenharmony_ci * with a READ/WRITE_READY iu code, so keep waiting until the list gets empty. 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_cistatic int uas_wait_for_pending_cmnds(struct uas_dev_info *devinfo) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci unsigned long start_time; 108762306a36Sopenharmony_ci int r; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci start_time = jiffies; 109062306a36Sopenharmony_ci do { 109162306a36Sopenharmony_ci flush_work(&devinfo->work); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci r = usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000); 109462306a36Sopenharmony_ci if (r == 0) 109562306a36Sopenharmony_ci return -ETIME; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci r = usb_wait_anchor_empty_timeout(&devinfo->data_urbs, 500); 109862306a36Sopenharmony_ci if (r == 0) 109962306a36Sopenharmony_ci return -ETIME; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (time_after(jiffies, start_time + 5 * HZ)) 110262306a36Sopenharmony_ci return -ETIME; 110362306a36Sopenharmony_ci } while (!uas_cmnd_list_empty(devinfo)); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci return 0; 110662306a36Sopenharmony_ci} 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_cistatic int uas_pre_reset(struct usb_interface *intf) 110962306a36Sopenharmony_ci{ 111062306a36Sopenharmony_ci struct Scsi_Host *shost = usb_get_intfdata(intf); 111162306a36Sopenharmony_ci struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; 111262306a36Sopenharmony_ci unsigned long flags; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci if (devinfo->shutdown) 111562306a36Sopenharmony_ci return 0; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* Block new requests */ 111862306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 111962306a36Sopenharmony_ci scsi_block_requests(shost); 112062306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (uas_wait_for_pending_cmnds(devinfo) != 0) { 112362306a36Sopenharmony_ci shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__); 112462306a36Sopenharmony_ci scsi_unblock_requests(shost); 112562306a36Sopenharmony_ci return 1; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci uas_free_streams(devinfo); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci return 0; 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic int uas_post_reset(struct usb_interface *intf) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci struct Scsi_Host *shost = usb_get_intfdata(intf); 113662306a36Sopenharmony_ci struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; 113762306a36Sopenharmony_ci unsigned long flags; 113862306a36Sopenharmony_ci int err; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci if (devinfo->shutdown) 114162306a36Sopenharmony_ci return 0; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci err = uas_configure_endpoints(devinfo); 114462306a36Sopenharmony_ci if (err && err != -ENODEV) 114562306a36Sopenharmony_ci shost_printk(KERN_ERR, shost, 114662306a36Sopenharmony_ci "%s: alloc streams error %d after reset", 114762306a36Sopenharmony_ci __func__, err); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci /* we must unblock the host in every case lest we deadlock */ 115062306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 115162306a36Sopenharmony_ci scsi_report_bus_reset(shost, 0); 115262306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci scsi_unblock_requests(shost); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci return err ? 1 : 0; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic int uas_suspend(struct usb_interface *intf, pm_message_t message) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci struct Scsi_Host *shost = usb_get_intfdata(intf); 116262306a36Sopenharmony_ci struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (uas_wait_for_pending_cmnds(devinfo) != 0) { 116562306a36Sopenharmony_ci shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__); 116662306a36Sopenharmony_ci return -ETIME; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci return 0; 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic int uas_resume(struct usb_interface *intf) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci return 0; 117562306a36Sopenharmony_ci} 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cistatic int uas_reset_resume(struct usb_interface *intf) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci struct Scsi_Host *shost = usb_get_intfdata(intf); 118062306a36Sopenharmony_ci struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; 118162306a36Sopenharmony_ci unsigned long flags; 118262306a36Sopenharmony_ci int err; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci err = uas_configure_endpoints(devinfo); 118562306a36Sopenharmony_ci if (err) { 118662306a36Sopenharmony_ci shost_printk(KERN_ERR, shost, 118762306a36Sopenharmony_ci "%s: alloc streams error %d after reset", 118862306a36Sopenharmony_ci __func__, err); 118962306a36Sopenharmony_ci return -EIO; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 119362306a36Sopenharmony_ci scsi_report_bus_reset(shost, 0); 119462306a36Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci return 0; 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic void uas_disconnect(struct usb_interface *intf) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci struct Scsi_Host *shost = usb_get_intfdata(intf); 120262306a36Sopenharmony_ci struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; 120362306a36Sopenharmony_ci unsigned long flags; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci spin_lock_irqsave(&devinfo->lock, flags); 120662306a36Sopenharmony_ci devinfo->resetting = 1; 120762306a36Sopenharmony_ci spin_unlock_irqrestore(&devinfo->lock, flags); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci cancel_work_sync(&devinfo->work); 121062306a36Sopenharmony_ci usb_kill_anchored_urbs(&devinfo->cmd_urbs); 121162306a36Sopenharmony_ci usb_kill_anchored_urbs(&devinfo->sense_urbs); 121262306a36Sopenharmony_ci usb_kill_anchored_urbs(&devinfo->data_urbs); 121362306a36Sopenharmony_ci uas_zap_pending(devinfo, DID_NO_CONNECT); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci /* 121662306a36Sopenharmony_ci * Prevent SCSI scanning (if it hasn't started yet) 121762306a36Sopenharmony_ci * or wait for the SCSI-scanning routine to stop. 121862306a36Sopenharmony_ci */ 121962306a36Sopenharmony_ci cancel_work_sync(&devinfo->scan_work); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci scsi_remove_host(shost); 122262306a36Sopenharmony_ci uas_free_streams(devinfo); 122362306a36Sopenharmony_ci scsi_host_put(shost); 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci/* 122762306a36Sopenharmony_ci * Put the device back in usb-storage mode on shutdown, as some BIOS-es 122862306a36Sopenharmony_ci * hang on reboot when the device is still in uas mode. Note the reset is 122962306a36Sopenharmony_ci * necessary as some devices won't revert to usb-storage mode without it. 123062306a36Sopenharmony_ci */ 123162306a36Sopenharmony_cistatic void uas_shutdown(struct device *dev) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci struct usb_interface *intf = to_usb_interface(dev); 123462306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 123562306a36Sopenharmony_ci struct Scsi_Host *shost = usb_get_intfdata(intf); 123662306a36Sopenharmony_ci struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (system_state != SYSTEM_RESTART) 123962306a36Sopenharmony_ci return; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci devinfo->shutdown = 1; 124262306a36Sopenharmony_ci uas_free_streams(devinfo); 124362306a36Sopenharmony_ci usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); 124462306a36Sopenharmony_ci usb_reset_device(udev); 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_cistatic struct usb_driver uas_driver = { 124862306a36Sopenharmony_ci .name = "uas", 124962306a36Sopenharmony_ci .probe = uas_probe, 125062306a36Sopenharmony_ci .disconnect = uas_disconnect, 125162306a36Sopenharmony_ci .pre_reset = uas_pre_reset, 125262306a36Sopenharmony_ci .post_reset = uas_post_reset, 125362306a36Sopenharmony_ci .suspend = uas_suspend, 125462306a36Sopenharmony_ci .resume = uas_resume, 125562306a36Sopenharmony_ci .reset_resume = uas_reset_resume, 125662306a36Sopenharmony_ci .drvwrap.driver.shutdown = uas_shutdown, 125762306a36Sopenharmony_ci .id_table = uas_usb_ids, 125862306a36Sopenharmony_ci}; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic int __init uas_init(void) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci int rv; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci workqueue = alloc_workqueue("uas", WQ_MEM_RECLAIM, 0); 126562306a36Sopenharmony_ci if (!workqueue) 126662306a36Sopenharmony_ci return -ENOMEM; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci rv = usb_register(&uas_driver); 126962306a36Sopenharmony_ci if (rv) { 127062306a36Sopenharmony_ci destroy_workqueue(workqueue); 127162306a36Sopenharmony_ci return -ENOMEM; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci return 0; 127562306a36Sopenharmony_ci} 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_cistatic void __exit uas_exit(void) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci usb_deregister(&uas_driver); 128062306a36Sopenharmony_ci destroy_workqueue(workqueue); 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cimodule_init(uas_init); 128462306a36Sopenharmony_cimodule_exit(uas_exit); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 128762306a36Sopenharmony_ciMODULE_IMPORT_NS(USB_STORAGE); 128862306a36Sopenharmony_ciMODULE_AUTHOR( 128962306a36Sopenharmony_ci "Hans de Goede <hdegoede@redhat.com>, Matthew Wilcox and Sarah Sharp"); 1290