// SPDX-License-Identifier: GPL-2.0
/*
* USB Attached SCSI
* Note that this is not the same as the USB Mass Storage driver
*
* Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013 - 2016
* Copyright Matthew Wilcox for Intel Corp, 2010
* Copyright Sarah Sharp for Intel Corp, 2010
*/
#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/usb/hcd.h>
#include <linux/usb/storage.h>
#include <linux/usb/uas.h>
#include <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include "uas-detect.h"
#include "scsiglue.h"
#define MAX_CMNDS 256
struct uas_dev_info {
struct usb_interface *intf;
struct usb_device *udev;
struct usb_anchor cmd_urbs;
struct usb_anchor sense_urbs;
struct usb_anchor data_urbs;
unsigned long flags;
int qdepth, resetting;
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
unsigned use_streams:1;
unsigned shutdown:1;
struct scsi_cmnd *cmnd[MAX_CMNDS];
spinlock_t lock;
struct work_struct work;
struct work_struct scan_work; /* for async scanning */
};
enum {
SUBMIT_STATUS_URB = BIT(1),
ALLOC_DATA_IN_URB = BIT(2),
SUBMIT_DATA_IN_URB = BIT(3),
ALLOC_DATA_OUT_URB = BIT(4),
SUBMIT_DATA_OUT_URB = BIT(5),
ALLOC_CMD_URB = BIT(6),
SUBMIT_CMD_URB = BIT(7),
COMMAND_INFLIGHT = BIT(8),
DATA_IN_URB_INFLIGHT = BIT(9),
DATA_OUT_URB_INFLIGHT = BIT(10),
COMMAND_ABORTED = BIT(11),
IS_IN_WORK_LIST = BIT(12),
};
/* Overrides scsi_pointer */
struct uas_cmd_info {
unsigned int state;
unsigned int uas_tag;
struct urb *cmd_urb;
struct urb *data_in_urb;
struct urb *data_out_urb;
};
/* I hate forward declarations, but I actually have a loop */
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo);
static void uas_do_work(struct work_struct *work);
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
static void uas_free_streams(struct uas_dev_info *devinfo);
static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *prefix,
int status);
/*
* This driver needs its own workqueue, as we need to control memory allocation.
*
* In the course of error handling and power management uas_wait_for_pending_cmnds()
* needs to flush pending work items. In these contexts we cannot allocate memory
* by doing block IO as we would deadlock. For the same reason we cannot wait
* for anything allocating memory not heeding these constraints.
*
* So we have to control all work items that can be on the workqueue we flush.
* Hence we cannot share a queue and need our own.
*/
static struct workqueue_struct *workqueue;
static void uas_do_work(struct work_struct *work)
{
struct uas_dev_info *devinfo =
container_of(work, struct uas_dev_info, work);
struct uas_cmd_info *cmdinfo;
struct scsi_cmnd *cmnd;
unsigned long flags;
int i, err;
spin_lock_irqsave(&devinfo->lock, flags);