blob: a972e53656f5d95cec5c25f3a2442779a7d9a5ec [file] [log] [blame]
Matthew Wilcox115bb1f2010-10-07 13:05:23 +02001/*
2 * USB Attached SCSI
3 * Note that this is not the same as the USB Mass Storage driver
4 *
5 * Copyright Matthew Wilcox for Intel Corp, 2010
6 * Copyright Sarah Sharp for Intel Corp, 2010
7 *
8 * Distributed under the terms of the GNU GPL, version two.
9 */
10
11#include <linux/blkdev.h>
12#include <linux/slab.h>
13#include <linux/types.h>
Paul Gortmaker6eb0de82011-07-03 16:09:31 -040014#include <linux/module.h>
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020015#include <linux/usb.h>
Sebastian Andrzej Siewiorc898add2012-01-11 12:42:32 +010016#include <linux/usb/hcd.h>
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020017#include <linux/usb/storage.h>
Sebastian Andrzej Siewior348748b2012-01-11 12:45:56 +010018#include <linux/usb/uas.h>
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020019
20#include <scsi/scsi.h>
21#include <scsi/scsi_dbg.h>
22#include <scsi/scsi_cmnd.h>
23#include <scsi/scsi_device.h>
24#include <scsi/scsi_host.h>
25#include <scsi/scsi_tcq.h>
26
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020027/*
28 * The r00-r01c specs define this version of the SENSE IU data structure.
29 * It's still in use by several different firmware releases.
30 */
31struct sense_iu_old {
32 __u8 iu_id;
33 __u8 rsvd1;
34 __be16 tag;
35 __be16 len;
36 __u8 status;
37 __u8 service_response;
38 __u8 sense[SCSI_SENSE_BUFFERSIZE];
39};
40
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020041struct uas_dev_info {
42 struct usb_interface *intf;
43 struct usb_device *udev;
Gerd Hoffmanna0e39e32012-09-25 10:47:04 +020044 struct usb_anchor cmd_urbs;
Gerd Hoffmannbdd000f2012-06-19 09:54:53 +020045 struct usb_anchor sense_urbs;
46 struct usb_anchor data_urbs;
Gerd Hoffmann023b5152012-06-19 09:54:54 +020047 int qdepth, resetting;
48 struct response_ui response;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020049 unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
50 unsigned use_streams:1;
51 unsigned uas_sense_old:1;
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +010052 struct scsi_cmnd *cmnd;
Gerd Hoffmanne0648522012-09-25 10:47:08 +020053 spinlock_t lock;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020054};
55
56enum {
Matthew Wilcox92a3f762010-12-15 15:44:04 -050057 SUBMIT_STATUS_URB = (1 << 1),
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020058 ALLOC_DATA_IN_URB = (1 << 2),
59 SUBMIT_DATA_IN_URB = (1 << 3),
60 ALLOC_DATA_OUT_URB = (1 << 4),
61 SUBMIT_DATA_OUT_URB = (1 << 5),
62 ALLOC_CMD_URB = (1 << 6),
63 SUBMIT_CMD_URB = (1 << 7),
Gerd Hoffmannb1d67692012-06-19 09:54:51 +020064 COMMAND_INFLIGHT = (1 << 8),
65 DATA_IN_URB_INFLIGHT = (1 << 9),
66 DATA_OUT_URB_INFLIGHT = (1 << 10),
67 COMMAND_COMPLETED = (1 << 11),
Gerd Hoffmannef018cc92012-09-25 10:47:06 +020068 COMMAND_ABORTED = (1 << 12),
Gerd Hoffmannb06e48a2012-11-30 11:54:41 +010069 UNLINK_DATA_URBS = (1 << 13),
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020070};
71
72/* Overrides scsi_pointer */
73struct uas_cmd_info {
74 unsigned int state;
75 unsigned int stream;
76 struct urb *cmd_urb;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020077 struct urb *data_in_urb;
78 struct urb *data_out_urb;
79 struct list_head list;
80};
81
82/* I hate forward declarations, but I actually have a loop */
83static int uas_submit_urbs(struct scsi_cmnd *cmnd,
84 struct uas_dev_info *devinfo, gfp_t gfp);
Sarah Sharpea9da1c2011-12-02 11:55:44 -080085static void uas_do_work(struct work_struct *work);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020086
Sarah Sharpea9da1c2011-12-02 11:55:44 -080087static DECLARE_WORK(uas_work, uas_do_work);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +020088static DEFINE_SPINLOCK(uas_work_lock);
89static LIST_HEAD(uas_work_list);
90
Gerd Hoffmannaa8f6122012-11-30 11:54:40 +010091static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
92 struct uas_cmd_info *cmdinfo)
93{
Gerd Hoffmannb06e48a2012-11-30 11:54:41 +010094 unsigned long flags;
95
96 /*
97 * The UNLINK_DATA_URBS flag makes sure uas_try_complete
98 * (called by urb completion) doesn't release cmdinfo
99 * underneath us.
100 */
101 spin_lock_irqsave(&devinfo->lock, flags);
102 cmdinfo->state |= UNLINK_DATA_URBS;
103 spin_unlock_irqrestore(&devinfo->lock, flags);
104
Gerd Hoffmannaa8f6122012-11-30 11:54:40 +0100105 if (cmdinfo->data_in_urb)
106 usb_unlink_urb(cmdinfo->data_in_urb);
107 if (cmdinfo->data_out_urb)
108 usb_unlink_urb(cmdinfo->data_out_urb);
Gerd Hoffmannb06e48a2012-11-30 11:54:41 +0100109
110 spin_lock_irqsave(&devinfo->lock, flags);
111 cmdinfo->state &= ~UNLINK_DATA_URBS;
112 spin_unlock_irqrestore(&devinfo->lock, flags);
Gerd Hoffmannaa8f6122012-11-30 11:54:40 +0100113}
114
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200115static void uas_do_work(struct work_struct *work)
116{
117 struct uas_cmd_info *cmdinfo;
Sarah Sharpea9da1c2011-12-02 11:55:44 -0800118 struct uas_cmd_info *temp;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200119 struct list_head list;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200120 unsigned long flags;
Sarah Sharpea9da1c2011-12-02 11:55:44 -0800121 int err;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200122
123 spin_lock_irq(&uas_work_lock);
124 list_replace_init(&uas_work_list, &list);
125 spin_unlock_irq(&uas_work_lock);
126
Sarah Sharpea9da1c2011-12-02 11:55:44 -0800127 list_for_each_entry_safe(cmdinfo, temp, &list, list) {
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200128 struct scsi_pointer *scp = (void *)cmdinfo;
129 struct scsi_cmnd *cmnd = container_of(scp,
130 struct scsi_cmnd, SCp);
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200131 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
132 spin_lock_irqsave(&devinfo->lock, flags);
133 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
134 spin_unlock_irqrestore(&devinfo->lock, flags);
Sarah Sharpea9da1c2011-12-02 11:55:44 -0800135 if (err) {
136 list_del(&cmdinfo->list);
137 spin_lock_irq(&uas_work_lock);
138 list_add_tail(&cmdinfo->list, &uas_work_list);
139 spin_unlock_irq(&uas_work_lock);
140 schedule_work(&uas_work);
141 }
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200142 }
143}
144
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200145static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
146{
147 struct sense_iu *sense_iu = urb->transfer_buffer;
148 struct scsi_device *sdev = cmnd->device;
149
150 if (urb->actual_length > 16) {
151 unsigned len = be16_to_cpup(&sense_iu->len);
152 if (len + 16 != urb->actual_length) {
153 int newlen = min(len + 16, urb->actual_length) - 16;
154 if (newlen < 0)
155 newlen = 0;
156 sdev_printk(KERN_INFO, sdev, "%s: urb length %d "
157 "disagrees with IU sense data length %d, "
158 "using %d bytes of sense data\n", __func__,
159 urb->actual_length, len, newlen);
160 len = newlen;
161 }
162 memcpy(cmnd->sense_buffer, sense_iu->sense, len);
163 }
164
165 cmnd->result = sense_iu->status;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200166}
167
168static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
169{
170 struct sense_iu_old *sense_iu = urb->transfer_buffer;
171 struct scsi_device *sdev = cmnd->device;
172
173 if (urb->actual_length > 8) {
174 unsigned len = be16_to_cpup(&sense_iu->len) - 2;
175 if (len + 8 != urb->actual_length) {
176 int newlen = min(len + 8, urb->actual_length) - 8;
177 if (newlen < 0)
178 newlen = 0;
179 sdev_printk(KERN_INFO, sdev, "%s: urb length %d "
180 "disagrees with IU sense data length %d, "
181 "using %d bytes of sense data\n", __func__,
182 urb->actual_length, len, newlen);
183 len = newlen;
184 }
185 memcpy(cmnd->sense_buffer, sense_iu->sense, len);
186 }
187
188 cmnd->result = sense_iu->status;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200189}
190
191static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
192{
193 struct uas_cmd_info *ci = (void *)&cmnd->SCp;
194
195 scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
Gerd Hoffmannb06e48a2012-11-30 11:54:41 +0100196 "%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200197 caller, cmnd, cmnd->request->tag,
198 (ci->state & SUBMIT_STATUS_URB) ? " s-st" : "",
199 (ci->state & ALLOC_DATA_IN_URB) ? " a-in" : "",
200 (ci->state & SUBMIT_DATA_IN_URB) ? " s-in" : "",
201 (ci->state & ALLOC_DATA_OUT_URB) ? " a-out" : "",
202 (ci->state & SUBMIT_DATA_OUT_URB) ? " s-out" : "",
203 (ci->state & ALLOC_CMD_URB) ? " a-cmd" : "",
204 (ci->state & SUBMIT_CMD_URB) ? " s-cmd" : "",
205 (ci->state & COMMAND_INFLIGHT) ? " CMD" : "",
206 (ci->state & DATA_IN_URB_INFLIGHT) ? " IN" : "",
207 (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT" : "",
Gerd Hoffmannef018cc92012-09-25 10:47:06 +0200208 (ci->state & COMMAND_COMPLETED) ? " done" : "",
Gerd Hoffmannb06e48a2012-11-30 11:54:41 +0100209 (ci->state & COMMAND_ABORTED) ? " abort" : "",
210 (ci->state & UNLINK_DATA_URBS) ? " unlink": "");
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200211}
212
213static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
214{
215 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200216 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200217
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200218 WARN_ON(!spin_is_locked(&devinfo->lock));
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200219 if (cmdinfo->state & (COMMAND_INFLIGHT |
220 DATA_IN_URB_INFLIGHT |
Gerd Hoffmannb06e48a2012-11-30 11:54:41 +0100221 DATA_OUT_URB_INFLIGHT |
222 UNLINK_DATA_URBS))
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200223 return -EBUSY;
224 BUG_ON(cmdinfo->state & COMMAND_COMPLETED);
225 cmdinfo->state |= COMMAND_COMPLETED;
226 usb_free_urb(cmdinfo->data_in_urb);
227 usb_free_urb(cmdinfo->data_out_urb);
Gerd Hoffmann0871d7d2012-09-25 10:47:07 +0200228 if (cmdinfo->state & COMMAND_ABORTED) {
229 scmd_printk(KERN_INFO, cmnd, "abort completed\n");
230 cmnd->result = DID_ABORT << 16;
231 }
Gerd Hoffmannc621a812012-06-19 09:54:48 +0200232 cmnd->scsi_done(cmnd);
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200233 return 0;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200234}
235
236static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200237 unsigned direction)
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200238{
239 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
240 int err;
241
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200242 cmdinfo->state |= direction | SUBMIT_STATUS_URB;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200243 err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
244 if (err) {
245 spin_lock(&uas_work_lock);
246 list_add_tail(&cmdinfo->list, &uas_work_list);
247 spin_unlock(&uas_work_lock);
248 schedule_work(&uas_work);
249 }
250}
251
252static void uas_stat_cmplt(struct urb *urb)
253{
254 struct iu *iu = urb->transfer_buffer;
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +0100255 struct Scsi_Host *shost = urb->context;
256 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200257 struct scsi_cmnd *cmnd;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200258 struct uas_cmd_info *cmdinfo;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200259 unsigned long flags;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200260 u16 tag;
261
262 if (urb->status) {
263 dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
Gerd Hoffmanndb32de12012-06-19 09:54:49 +0200264 usb_free_urb(urb);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200265 return;
266 }
267
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200268 if (devinfo->resetting) {
269 usb_free_urb(urb);
270 return;
271 }
272
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200273 spin_lock_irqsave(&devinfo->lock, flags);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200274 tag = be16_to_cpup(&iu->tag) - 1;
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +0100275 if (tag == 0)
276 cmnd = devinfo->cmnd;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200277 else
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +0100278 cmnd = scsi_host_find_tag(shost, tag - 1);
Gerd Hoffmanne0423de2012-09-26 10:29:03 +0200279
Sarah Sharp96c1eb92011-12-02 11:55:48 -0800280 if (!cmnd) {
Gerd Hoffmanne0423de2012-09-26 10:29:03 +0200281 if (iu->iu_id == IU_ID_RESPONSE) {
282 /* store results for uas_eh_task_mgmt() */
283 memcpy(&devinfo->response, iu, sizeof(devinfo->response));
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200284 }
Gerd Hoffmanne0423de2012-09-26 10:29:03 +0200285 usb_free_urb(urb);
286 spin_unlock_irqrestore(&devinfo->lock, flags);
287 return;
Sarah Sharp96c1eb92011-12-02 11:55:48 -0800288 }
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200289
Gerd Hoffmanne0423de2012-09-26 10:29:03 +0200290 cmdinfo = (void *)&cmnd->SCp;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200291 switch (iu->iu_id) {
292 case IU_ID_STATUS:
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +0100293 if (devinfo->cmnd == cmnd)
294 devinfo->cmnd = NULL;
295
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200296 if (urb->actual_length < 16)
297 devinfo->uas_sense_old = 1;
298 if (devinfo->uas_sense_old)
299 uas_sense_old(urb, cmnd);
300 else
301 uas_sense(urb, cmnd);
Gerd Hoffmann8aac8632012-06-19 09:54:52 +0200302 if (cmnd->result != 0) {
303 /* cancel data transfers on error */
Gerd Hoffmannaa8f6122012-11-30 11:54:40 +0100304 spin_unlock_irqrestore(&devinfo->lock, flags);
305 uas_unlink_data_urbs(devinfo, cmdinfo);
306 spin_lock_irqsave(&devinfo->lock, flags);
Gerd Hoffmann8aac8632012-06-19 09:54:52 +0200307 }
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200308 cmdinfo->state &= ~COMMAND_INFLIGHT;
309 uas_try_complete(cmnd, __func__);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200310 break;
311 case IU_ID_READ_READY:
312 uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
313 break;
314 case IU_ID_WRITE_READY:
315 uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
316 break;
317 default:
318 scmd_printk(KERN_ERR, cmnd,
319 "Bogus IU (%d) received on status pipe\n", iu->iu_id);
320 }
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200321 usb_free_urb(urb);
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200322 spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200323}
324
Gerd Hoffmannc621a812012-06-19 09:54:48 +0200325static void uas_data_cmplt(struct urb *urb)
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200326{
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200327 struct scsi_cmnd *cmnd = urb->context;
328 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200329 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200330 struct scsi_data_buffer *sdb = NULL;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200331 unsigned long flags;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200332
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200333 spin_lock_irqsave(&devinfo->lock, flags);
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200334 if (cmdinfo->data_in_urb == urb) {
335 sdb = scsi_in(cmnd);
336 cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
337 } else if (cmdinfo->data_out_urb == urb) {
338 sdb = scsi_out(cmnd);
339 cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
340 }
341 BUG_ON(sdb == NULL);
Gerd Hoffmann8aac8632012-06-19 09:54:52 +0200342 if (urb->status) {
343 /* error: no data transfered */
344 sdb->resid = sdb->length;
345 } else {
346 sdb->resid = sdb->length - urb->actual_length;
347 }
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200348 uas_try_complete(cmnd, __func__);
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200349 spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200350}
351
352static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200353 unsigned int pipe, u16 stream_id,
354 struct scsi_cmnd *cmnd,
355 enum dma_data_direction dir)
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200356{
357 struct usb_device *udev = devinfo->udev;
358 struct urb *urb = usb_alloc_urb(0, gfp);
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200359 struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
360 ? scsi_in(cmnd) : scsi_out(cmnd);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200361
362 if (!urb)
363 goto out;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200364 usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
365 uas_data_cmplt, cmnd);
Gerd Hoffmannc621a812012-06-19 09:54:48 +0200366 if (devinfo->use_streams)
367 urb->stream_id = stream_id;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200368 urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
369 urb->sg = sdb->table.sgl;
370 out:
371 return urb;
372}
373
374static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200375 struct Scsi_Host *shost, u16 stream_id)
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200376{
377 struct usb_device *udev = devinfo->udev;
378 struct urb *urb = usb_alloc_urb(0, gfp);
379 struct sense_iu *iu;
380
381 if (!urb)
382 goto out;
383
Matthew Wilcoxac563cf2010-12-15 15:44:03 -0500384 iu = kzalloc(sizeof(*iu), gfp);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200385 if (!iu)
386 goto free;
387
388 usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200389 uas_stat_cmplt, shost);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200390 urb->stream_id = stream_id;
391 urb->transfer_flags |= URB_FREE_BUFFER;
392 out:
393 return urb;
394 free:
395 usb_free_urb(urb);
396 return NULL;
397}
398
399static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
400 struct scsi_cmnd *cmnd, u16 stream_id)
401{
402 struct usb_device *udev = devinfo->udev;
403 struct scsi_device *sdev = cmnd->device;
404 struct urb *urb = usb_alloc_urb(0, gfp);
405 struct command_iu *iu;
406 int len;
407
408 if (!urb)
409 goto out;
410
411 len = cmnd->cmd_len - 16;
412 if (len < 0)
413 len = 0;
414 len = ALIGN(len, 4);
Matthew Wilcoxac563cf2010-12-15 15:44:03 -0500415 iu = kzalloc(sizeof(*iu) + len, gfp);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200416 if (!iu)
417 goto free;
418
419 iu->iu_id = IU_ID_COMMAND;
Sarah Sharp9eb44542011-12-02 11:55:46 -0800420 if (blk_rq_tagged(cmnd->request))
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +0100421 iu->tag = cpu_to_be16(cmnd->request->tag + 2);
Sarah Sharp9eb44542011-12-02 11:55:46 -0800422 else
423 iu->tag = cpu_to_be16(1);
Christoph Hellwig02e031c2010-11-10 14:54:09 +0100424 iu->prio_attr = UAS_SIMPLE_TAG;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200425 iu->len = len;
426 int_to_scsilun(sdev->lun, &iu->lun);
427 memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);
428
429 usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len,
430 usb_free_urb, NULL);
431 urb->transfer_flags |= URB_FREE_BUFFER;
432 out:
433 return urb;
434 free:
435 usb_free_urb(urb);
436 return NULL;
437}
438
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200439static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
440 u8 function, u16 stream_id)
441{
442 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
443 struct usb_device *udev = devinfo->udev;
444 struct urb *urb = usb_alloc_urb(0, gfp);
445 struct task_mgmt_iu *iu;
446 int err = -ENOMEM;
447
448 if (!urb)
449 goto err;
450
451 iu = kzalloc(sizeof(*iu), gfp);
452 if (!iu)
453 goto err;
454
455 iu->iu_id = IU_ID_TASK_MGMT;
456 iu->tag = cpu_to_be16(stream_id);
457 int_to_scsilun(cmnd->device->lun, &iu->lun);
458
459 iu->function = function;
460 switch (function) {
461 case TMF_ABORT_TASK:
462 if (blk_rq_tagged(cmnd->request))
463 iu->task_tag = cpu_to_be16(cmnd->request->tag + 2);
464 else
465 iu->task_tag = cpu_to_be16(1);
466 break;
467 }
468
469 usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu),
470 usb_free_urb, NULL);
471 urb->transfer_flags |= URB_FREE_BUFFER;
472
473 err = usb_submit_urb(urb, gfp);
474 if (err)
475 goto err;
Gerd Hoffmanna0e39e32012-09-25 10:47:04 +0200476 usb_anchor_urb(urb, &devinfo->cmd_urbs);
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200477
478 return 0;
479
480err:
481 usb_free_urb(urb);
482 return err;
483}
484
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200485/*
486 * Why should I request the Status IU before sending the Command IU? Spec
487 * says to, but also says the device may receive them in any order. Seems
488 * daft to me.
489 */
490
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200491static int uas_submit_sense_urb(struct Scsi_Host *shost,
492 gfp_t gfp, unsigned int stream)
493{
494 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
495 struct urb *urb;
496
497 urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
498 if (!urb)
499 return SCSI_MLQUEUE_DEVICE_BUSY;
500 if (usb_submit_urb(urb, gfp)) {
501 shost_printk(KERN_INFO, shost,
502 "sense urb submission failure\n");
503 usb_free_urb(urb);
504 return SCSI_MLQUEUE_DEVICE_BUSY;
505 }
Gerd Hoffmannbdd000f2012-06-19 09:54:53 +0200506 usb_anchor_urb(urb, &devinfo->sense_urbs);
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200507 return 0;
508}
509
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200510static int uas_submit_urbs(struct scsi_cmnd *cmnd,
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200511 struct uas_dev_info *devinfo, gfp_t gfp)
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200512{
513 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200514 int err;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200515
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200516 WARN_ON(!spin_is_locked(&devinfo->lock));
Matthew Wilcox92a3f762010-12-15 15:44:04 -0500517 if (cmdinfo->state & SUBMIT_STATUS_URB) {
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200518 err = uas_submit_sense_urb(cmnd->device->host, gfp,
519 cmdinfo->stream);
520 if (err) {
521 return err;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200522 }
Matthew Wilcox92a3f762010-12-15 15:44:04 -0500523 cmdinfo->state &= ~SUBMIT_STATUS_URB;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200524 }
525
526 if (cmdinfo->state & ALLOC_DATA_IN_URB) {
527 cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
Gerd Hoffmannc621a812012-06-19 09:54:48 +0200528 devinfo->data_in_pipe, cmdinfo->stream,
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200529 cmnd, DMA_FROM_DEVICE);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200530 if (!cmdinfo->data_in_urb)
531 return SCSI_MLQUEUE_DEVICE_BUSY;
532 cmdinfo->state &= ~ALLOC_DATA_IN_URB;
533 }
534
535 if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
536 if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) {
537 scmd_printk(KERN_INFO, cmnd,
538 "data in urb submission failure\n");
539 return SCSI_MLQUEUE_DEVICE_BUSY;
540 }
541 cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200542 cmdinfo->state |= DATA_IN_URB_INFLIGHT;
Gerd Hoffmannbdd000f2012-06-19 09:54:53 +0200543 usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200544 }
545
546 if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
547 cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
Gerd Hoffmannc621a812012-06-19 09:54:48 +0200548 devinfo->data_out_pipe, cmdinfo->stream,
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200549 cmnd, DMA_TO_DEVICE);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200550 if (!cmdinfo->data_out_urb)
551 return SCSI_MLQUEUE_DEVICE_BUSY;
552 cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
553 }
554
555 if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
556 if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) {
557 scmd_printk(KERN_INFO, cmnd,
558 "data out urb submission failure\n");
559 return SCSI_MLQUEUE_DEVICE_BUSY;
560 }
561 cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200562 cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
Gerd Hoffmannbdd000f2012-06-19 09:54:53 +0200563 usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200564 }
565
566 if (cmdinfo->state & ALLOC_CMD_URB) {
567 cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd,
Gerd Hoffmanna0e39e32012-09-25 10:47:04 +0200568 cmdinfo->stream);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200569 if (!cmdinfo->cmd_urb)
570 return SCSI_MLQUEUE_DEVICE_BUSY;
571 cmdinfo->state &= ~ALLOC_CMD_URB;
572 }
573
574 if (cmdinfo->state & SUBMIT_CMD_URB) {
Gerd Hoffmanna0e39e32012-09-25 10:47:04 +0200575 usb_get_urb(cmdinfo->cmd_urb);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200576 if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) {
577 scmd_printk(KERN_INFO, cmnd,
578 "cmd urb submission failure\n");
579 return SCSI_MLQUEUE_DEVICE_BUSY;
580 }
Gerd Hoffmanna0e39e32012-09-25 10:47:04 +0200581 usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
582 usb_put_urb(cmdinfo->cmd_urb);
583 cmdinfo->cmd_urb = NULL;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200584 cmdinfo->state &= ~SUBMIT_CMD_URB;
Gerd Hoffmannb1d67692012-06-19 09:54:51 +0200585 cmdinfo->state |= COMMAND_INFLIGHT;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200586 }
587
588 return 0;
589}
590
Jeff Garzikf2812332010-11-16 02:10:29 -0500591static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200592 void (*done)(struct scsi_cmnd *))
593{
594 struct scsi_device *sdev = cmnd->device;
595 struct uas_dev_info *devinfo = sdev->hostdata;
596 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200597 unsigned long flags;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200598 int err;
599
600 BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
601
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200602 spin_lock_irqsave(&devinfo->lock, flags);
603 if (devinfo->cmnd) {
604 spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200605 return SCSI_MLQUEUE_DEVICE_BUSY;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200606 }
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200607
608 if (blk_rq_tagged(cmnd->request)) {
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +0100609 cmdinfo->stream = cmnd->request->tag + 2;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200610 } else {
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +0100611 devinfo->cmnd = cmnd;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200612 cmdinfo->stream = 1;
613 }
614
615 cmnd->scsi_done = done;
616
Gerd Hoffmanne9bd7e12012-06-19 09:54:50 +0200617 cmdinfo->state = SUBMIT_STATUS_URB |
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200618 ALLOC_CMD_URB | SUBMIT_CMD_URB;
619
620 switch (cmnd->sc_data_direction) {
621 case DMA_FROM_DEVICE:
622 cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
623 break;
624 case DMA_BIDIRECTIONAL:
625 cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
626 case DMA_TO_DEVICE:
627 cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB;
628 case DMA_NONE:
629 break;
630 }
631
632 if (!devinfo->use_streams) {
Gerd Hoffmanndb32de12012-06-19 09:54:49 +0200633 cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200634 cmdinfo->stream = 0;
635 }
636
637 err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
638 if (err) {
639 /* If we did nothing, give up now */
Matthew Wilcox92a3f762010-12-15 15:44:04 -0500640 if (cmdinfo->state & SUBMIT_STATUS_URB) {
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200641 spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200642 return SCSI_MLQUEUE_DEVICE_BUSY;
643 }
644 spin_lock(&uas_work_lock);
645 list_add_tail(&cmdinfo->list, &uas_work_list);
646 spin_unlock(&uas_work_lock);
647 schedule_work(&uas_work);
648 }
649
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200650 spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200651 return 0;
652}
653
Jeff Garzikf2812332010-11-16 02:10:29 -0500654static DEF_SCSI_QCMD(uas_queuecommand)
655
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200656static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
657 const char *fname, u8 function)
658{
659 struct Scsi_Host *shost = cmnd->device->host;
660 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
Gerd Hoffmann03939862012-09-25 10:47:05 +0200661 u16 tag = devinfo->qdepth - 1;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200662 unsigned long flags;
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200663
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200664 spin_lock_irqsave(&devinfo->lock, flags);
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200665 memset(&devinfo->response, 0, sizeof(devinfo->response));
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200666 if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) {
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200667 shost_printk(KERN_INFO, shost,
668 "%s: %s: submit sense urb failed\n",
669 __func__, fname);
Gerd Hoffmann1994ff42012-09-26 10:28:58 +0200670 spin_unlock_irqrestore(&devinfo->lock, flags);
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200671 return FAILED;
672 }
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200673 if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200674 shost_printk(KERN_INFO, shost,
675 "%s: %s: submit task mgmt urb failed\n",
676 __func__, fname);
Gerd Hoffmann1994ff42012-09-26 10:28:58 +0200677 spin_unlock_irqrestore(&devinfo->lock, flags);
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200678 return FAILED;
679 }
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200680 spin_unlock_irqrestore(&devinfo->lock, flags);
681
682 if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200683 shost_printk(KERN_INFO, shost,
684 "%s: %s timed out\n", __func__, fname);
685 return FAILED;
686 }
687 if (be16_to_cpu(devinfo->response.tag) != tag) {
688 shost_printk(KERN_INFO, shost,
689 "%s: %s failed (wrong tag %d/%d)\n", __func__,
690 fname, be16_to_cpu(devinfo->response.tag), tag);
691 return FAILED;
692 }
693 if (devinfo->response.response_code != RC_TMF_COMPLETE) {
694 shost_printk(KERN_INFO, shost,
695 "%s: %s failed (rc 0x%x)\n", __func__,
696 fname, devinfo->response.response_code);
697 return FAILED;
698 }
699 return SUCCESS;
700}
701
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200702static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
703{
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200704 struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200705 struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
706 unsigned long flags;
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200707 int ret;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200708
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200709 uas_log_cmd_state(cmnd, __func__);
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200710 spin_lock_irqsave(&devinfo->lock, flags);
Gerd Hoffmannef018cc92012-09-25 10:47:06 +0200711 cmdinfo->state |= COMMAND_ABORTED;
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200712 spin_unlock_irqrestore(&devinfo->lock, flags);
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200713 ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200714 return ret;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200715}
716
717static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
718{
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200719 sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__);
720 return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET",
721 TMF_LOGICAL_UNIT_RESET);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200722}
723
724static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
725{
726 struct scsi_device *sdev = cmnd->device;
727 struct uas_dev_info *devinfo = sdev->hostdata;
728 struct usb_device *udev = devinfo->udev;
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200729 int err;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200730
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200731 devinfo->resetting = 1;
Gerd Hoffmanna0e39e32012-09-25 10:47:04 +0200732 usb_kill_anchored_urbs(&devinfo->cmd_urbs);
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200733 usb_kill_anchored_urbs(&devinfo->sense_urbs);
734 usb_kill_anchored_urbs(&devinfo->data_urbs);
735 err = usb_reset_device(udev);
736 devinfo->resetting = 0;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200737
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200738 if (err) {
739 shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
740 return FAILED;
741 }
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200742
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200743 shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
744 return SUCCESS;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200745}
746
747static int uas_slave_alloc(struct scsi_device *sdev)
748{
749 sdev->hostdata = (void *)sdev->host->hostdata[0];
750 return 0;
751}
752
753static int uas_slave_configure(struct scsi_device *sdev)
754{
755 struct uas_dev_info *devinfo = sdev->hostdata;
756 scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
Gerd Hoffmann03939862012-09-25 10:47:05 +0200757 scsi_activate_tcq(sdev, devinfo->qdepth - 3);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200758 return 0;
759}
760
761static struct scsi_host_template uas_host_template = {
762 .module = THIS_MODULE,
763 .name = "uas",
764 .queuecommand = uas_queuecommand,
765 .slave_alloc = uas_slave_alloc,
766 .slave_configure = uas_slave_configure,
767 .eh_abort_handler = uas_eh_abort_handler,
768 .eh_device_reset_handler = uas_eh_device_reset_handler,
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200769 .eh_bus_reset_handler = uas_eh_bus_reset_handler,
770 .can_queue = 65536, /* Is there a limit on the _host_ ? */
771 .this_id = -1,
772 .sg_tablesize = SG_NONE,
773 .cmd_per_lun = 1, /* until we override it */
774 .skip_settle_delay = 1,
775 .ordered_tag = 1,
776};
777
778static struct usb_device_id uas_usb_ids[] = {
779 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
780 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },
781 /* 0xaa is a prototype device I happen to have access to */
782 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, 0xaa) },
783 { }
784};
785MODULE_DEVICE_TABLE(usb, uas_usb_ids);
786
Matthew Wilcox89dc2902010-12-15 15:44:05 -0500787static int uas_is_interface(struct usb_host_interface *intf)
788{
789 return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE &&
790 intf->desc.bInterfaceSubClass == USB_SC_SCSI &&
791 intf->desc.bInterfaceProtocol == USB_PR_UAS);
792}
793
Sebastian Andrzej Siewiorc898add2012-01-11 12:42:32 +0100794static int uas_isnt_supported(struct usb_device *udev)
795{
796 struct usb_hcd *hcd = bus_to_hcd(udev->bus);
797
798 dev_warn(&udev->dev, "The driver for the USB controller %s does not "
799 "support scatter-gather which is\n",
800 hcd->driver->description);
801 dev_warn(&udev->dev, "required by the UAS driver. Please try an"
802 "alternative USB controller if you wish to use UAS.\n");
803 return -ENODEV;
804}
805
Matthew Wilcox89dc2902010-12-15 15:44:05 -0500806static int uas_switch_interface(struct usb_device *udev,
807 struct usb_interface *intf)
808{
809 int i;
Sebastian Andrzej Siewiorc898add2012-01-11 12:42:32 +0100810 int sg_supported = udev->bus->sg_tablesize != 0;
Matthew Wilcox89dc2902010-12-15 15:44:05 -0500811
812 for (i = 0; i < intf->num_altsetting; i++) {
813 struct usb_host_interface *alt = &intf->altsetting[i];
Sebastian Andrzej Siewiorc898add2012-01-11 12:42:32 +0100814
815 if (uas_is_interface(alt)) {
816 if (!sg_supported)
817 return uas_isnt_supported(udev);
Matthew Wilcox89dc2902010-12-15 15:44:05 -0500818 return usb_set_interface(udev,
819 alt->desc.bInterfaceNumber,
820 alt->desc.bAlternateSetting);
Sebastian Andrzej Siewiorc898add2012-01-11 12:42:32 +0100821 }
Matthew Wilcox89dc2902010-12-15 15:44:05 -0500822 }
823
824 return -ENODEV;
825}
826
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200827static void uas_configure_endpoints(struct uas_dev_info *devinfo)
828{
829 struct usb_host_endpoint *eps[4] = { };
830 struct usb_interface *intf = devinfo->intf;
831 struct usb_device *udev = devinfo->udev;
832 struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint;
833 unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;
834
835 devinfo->uas_sense_old = 0;
Sebastian Andrzej Siewior22188f42011-12-19 20:22:39 +0100836 devinfo->cmnd = NULL;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200837
838 for (i = 0; i < n_endpoints; i++) {
839 unsigned char *extra = endpoint[i].extra;
840 int len = endpoint[i].extralen;
841 while (len > 1) {
842 if (extra[1] == USB_DT_PIPE_USAGE) {
843 unsigned pipe_id = extra[2];
844 if (pipe_id > 0 && pipe_id < 5)
845 eps[pipe_id - 1] = &endpoint[i];
846 break;
847 }
848 len -= extra[0];
849 extra += extra[0];
850 }
851 }
852
853 /*
854 * Assume that if we didn't find a control pipe descriptor, we're
855 * using a device with old firmware that happens to be set up like
856 * this.
857 */
858 if (!eps[0]) {
859 devinfo->cmd_pipe = usb_sndbulkpipe(udev, 1);
860 devinfo->status_pipe = usb_rcvbulkpipe(udev, 1);
861 devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2);
862 devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2);
863
864 eps[1] = usb_pipe_endpoint(udev, devinfo->status_pipe);
865 eps[2] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
866 eps[3] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
867 } else {
868 devinfo->cmd_pipe = usb_sndbulkpipe(udev,
869 eps[0]->desc.bEndpointAddress);
870 devinfo->status_pipe = usb_rcvbulkpipe(udev,
871 eps[1]->desc.bEndpointAddress);
872 devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
873 eps[2]->desc.bEndpointAddress);
874 devinfo->data_out_pipe = usb_sndbulkpipe(udev,
875 eps[3]->desc.bEndpointAddress);
876 }
877
878 devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 3, 256,
879 GFP_KERNEL);
880 if (devinfo->qdepth < 0) {
881 devinfo->qdepth = 256;
882 devinfo->use_streams = 0;
883 } else {
884 devinfo->use_streams = 1;
885 }
886}
887
Sebastian Andrzej Siewiordae51542011-12-19 17:06:08 +0100888static void uas_free_streams(struct uas_dev_info *devinfo)
889{
890 struct usb_device *udev = devinfo->udev;
891 struct usb_host_endpoint *eps[3];
892
893 eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
894 eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
895 eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
896 usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
897}
898
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200899/*
900 * XXX: What I'd like to do here is register a SCSI host for each USB host in
901 * the system. Follow usb-storage's design of registering a SCSI host for
902 * each USB device for the moment. Can implement this by walking up the
903 * USB hierarchy until we find a USB host.
904 */
905static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
906{
907 int result;
908 struct Scsi_Host *shost;
909 struct uas_dev_info *devinfo;
910 struct usb_device *udev = interface_to_usbdev(intf);
911
Matthew Wilcox89dc2902010-12-15 15:44:05 -0500912 if (uas_switch_interface(udev, intf))
913 return -ENODEV;
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200914
915 devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL);
916 if (!devinfo)
917 return -ENOMEM;
918
919 result = -ENOMEM;
920 shost = scsi_host_alloc(&uas_host_template, sizeof(void *));
921 if (!shost)
922 goto free;
923
924 shost->max_cmd_len = 16 + 252;
925 shost->max_id = 1;
926 shost->sg_tablesize = udev->bus->sg_tablesize;
927
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200928 devinfo->intf = intf;
929 devinfo->udev = udev;
Gerd Hoffmann023b5152012-06-19 09:54:54 +0200930 devinfo->resetting = 0;
Gerd Hoffmanna0e39e32012-09-25 10:47:04 +0200931 init_usb_anchor(&devinfo->cmd_urbs);
Gerd Hoffmannbdd000f2012-06-19 09:54:53 +0200932 init_usb_anchor(&devinfo->sense_urbs);
933 init_usb_anchor(&devinfo->data_urbs);
Gerd Hoffmanne0648522012-09-25 10:47:08 +0200934 spin_lock_init(&devinfo->lock);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200935 uas_configure_endpoints(devinfo);
936
Gerd Hoffmann03939862012-09-25 10:47:05 +0200937 result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3);
Sebastian Andrzej Siewiordae51542011-12-19 17:06:08 +0100938 if (result)
939 goto free;
940
941 result = scsi_add_host(shost, &intf->dev);
942 if (result)
943 goto deconfig_eps;
944
945 shost->hostdata[0] = (unsigned long)devinfo;
946
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200947 scsi_scan_host(shost);
948 usb_set_intfdata(intf, shost);
949 return result;
Sebastian Andrzej Siewiordae51542011-12-19 17:06:08 +0100950
951deconfig_eps:
952 uas_free_streams(devinfo);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200953 free:
954 kfree(devinfo);
955 if (shost)
956 scsi_host_put(shost);
957 return result;
958}
959
960static int uas_pre_reset(struct usb_interface *intf)
961{
962/* XXX: Need to return 1 if it's not our device in error handling */
963 return 0;
964}
965
966static int uas_post_reset(struct usb_interface *intf)
967{
968/* XXX: Need to return 1 if it's not our device in error handling */
969 return 0;
970}
971
972static void uas_disconnect(struct usb_interface *intf)
973{
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200974 struct Scsi_Host *shost = usb_get_intfdata(intf);
975 struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
976
977 scsi_remove_host(shost);
Gerd Hoffmanna0e39e32012-09-25 10:47:04 +0200978 usb_kill_anchored_urbs(&devinfo->cmd_urbs);
Gerd Hoffmannbdd000f2012-06-19 09:54:53 +0200979 usb_kill_anchored_urbs(&devinfo->sense_urbs);
980 usb_kill_anchored_urbs(&devinfo->data_urbs);
Sebastian Andrzej Siewiordae51542011-12-19 17:06:08 +0100981 uas_free_streams(devinfo);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200982 kfree(devinfo);
983}
984
985/*
986 * XXX: Should this plug into libusual so we can auto-upgrade devices from
987 * Bulk-Only to UAS?
988 */
989static struct usb_driver uas_driver = {
990 .name = "uas",
991 .probe = uas_probe,
992 .disconnect = uas_disconnect,
993 .pre_reset = uas_pre_reset,
994 .post_reset = uas_post_reset,
995 .id_table = uas_usb_ids,
996};
997
Greg Kroah-Hartman65db4302011-11-18 09:34:02 -0800998module_usb_driver(uas_driver);
Matthew Wilcox115bb1f2010-10-07 13:05:23 +0200999
1000MODULE_LICENSE("GPL");
1001MODULE_AUTHOR("Matthew Wilcox and Sarah Sharp");