uas.c 32.7 KB
Newer Older
Matthew Wilcox's avatar
Matthew Wilcox committed
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * USB Attached SCSI
 * Note that this is not the same as the USB Mass Storage driver
 *
 * Copyright Matthew Wilcox for Intel Corp, 2010
 * Copyright Sarah Sharp for Intel Corp, 2010
 *
 * Distributed under the terms of the GNU GPL, version two.
 */

#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/types.h>
14
#include <linux/module.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
15
#include <linux/usb.h>
16
#include <linux/usb_usual.h>
17
#include <linux/usb/hcd.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
18
#include <linux/usb/storage.h>
19
#include <linux/usb/uas.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
20
21

#include <scsi/scsi.h>
22
#include <scsi/scsi_eh.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
23
24
25
26
27
28
#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>

29
30
#include "uas-detect.h"

Matthew Wilcox's avatar
Matthew Wilcox committed
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
 * The r00-r01c specs define this version of the SENSE IU data structure.
 * It's still in use by several different firmware releases.
 */
struct sense_iu_old {
	__u8 iu_id;
	__u8 rsvd1;
	__be16 tag;
	__be16 len;
	__u8 status;
	__u8 service_response;
	__u8 sense[SCSI_SENSE_BUFFERSIZE];
};

struct uas_dev_info {
	struct usb_interface *intf;
	struct usb_device *udev;
48
	struct usb_anchor cmd_urbs;
49
50
	struct usb_anchor sense_urbs;
	struct usb_anchor data_urbs;
51
	int qdepth, resetting;
52
	struct response_iu response;
Matthew Wilcox's avatar
Matthew Wilcox committed
53
54
55
	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
	unsigned use_streams:1;
	unsigned uas_sense_old:1;
56
	unsigned running_task:1;
Hans de Goede's avatar
Hans de Goede committed
57
	unsigned shutdown:1;
58
	struct scsi_cmnd *cmnd;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
59
	spinlock_t lock;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
60
	struct work_struct work;
61
	struct list_head inflight_list;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
62
	struct list_head dead_list;
Matthew Wilcox's avatar
Matthew Wilcox committed
63
64
65
};

enum {
66
	SUBMIT_STATUS_URB	= (1 << 1),
Matthew Wilcox's avatar
Matthew Wilcox committed
67
68
69
70
71
72
	ALLOC_DATA_IN_URB	= (1 << 2),
	SUBMIT_DATA_IN_URB	= (1 << 3),
	ALLOC_DATA_OUT_URB	= (1 << 4),
	SUBMIT_DATA_OUT_URB	= (1 << 5),
	ALLOC_CMD_URB		= (1 << 6),
	SUBMIT_CMD_URB		= (1 << 7),
73
74
75
76
	COMMAND_INFLIGHT        = (1 << 8),
	DATA_IN_URB_INFLIGHT    = (1 << 9),
	DATA_OUT_URB_INFLIGHT   = (1 << 10),
	COMMAND_COMPLETED       = (1 << 11),
77
	COMMAND_ABORTED         = (1 << 12),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
78
	UNLINK_DATA_URBS        = (1 << 13),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
79
	IS_IN_WORK_LIST         = (1 << 14),
Matthew Wilcox's avatar
Matthew Wilcox committed
80
81
82
83
84
85
86
87
88
};

/* Overrides scsi_pointer */
struct uas_cmd_info {
	unsigned int state;
	unsigned int stream;
	struct urb *cmd_urb;
	struct urb *data_in_urb;
	struct urb *data_out_urb;
89
	struct list_head list;
Matthew Wilcox's avatar
Matthew Wilcox committed
90
91
92
93
94
};

/* I hate forward declarations, but I actually have a loop */
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
				struct uas_dev_info *devinfo, gfp_t gfp);
95
static void uas_do_work(struct work_struct *work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
96
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
97
static void uas_free_streams(struct uas_dev_info *devinfo);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
98
static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller);
Matthew Wilcox's avatar
Matthew Wilcox committed
99

100
/* Must be called with devinfo->lock held, will temporary unlock the lock */
101
static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
102
103
				 struct uas_cmd_info *cmdinfo,
				 unsigned long *lock_flags)
104
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
105
106
107
108
109
110
	/*
	 * The UNLINK_DATA_URBS flag makes sure uas_try_complete
	 * (called by urb completion) doesn't release cmdinfo
	 * underneath us.
	 */
	cmdinfo->state |= UNLINK_DATA_URBS;
111
	spin_unlock_irqrestore(&devinfo->lock, *lock_flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
112

113
114
115
116
	if (cmdinfo->data_in_urb)
		usb_unlink_urb(cmdinfo->data_in_urb);
	if (cmdinfo->data_out_urb)
		usb_unlink_urb(cmdinfo->data_out_urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
117

118
	spin_lock_irqsave(&devinfo->lock, *lock_flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
119
	cmdinfo->state &= ~UNLINK_DATA_URBS;
120
121
}

Matthew Wilcox's avatar
Matthew Wilcox committed
122
123
static void uas_do_work(struct work_struct *work)
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
124
125
	struct uas_dev_info *devinfo =
		container_of(work, struct uas_dev_info, work);
Matthew Wilcox's avatar
Matthew Wilcox committed
126
	struct uas_cmd_info *cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
127
	unsigned long flags;
128
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
129

Gerd Hoffmann's avatar
Gerd Hoffmann committed
130
	spin_lock_irqsave(&devinfo->lock, flags);
131
	list_for_each_entry(cmdinfo, &devinfo->inflight_list, list) {
Matthew Wilcox's avatar
Matthew Wilcox committed
132
		struct scsi_pointer *scp = (void *)cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
133
134
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
135
136
137
138

		if (!(cmdinfo->state & IS_IN_WORK_LIST))
			continue;

139
		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
140
		if (!err)
Gerd Hoffmann's avatar
Gerd Hoffmann committed
141
			cmdinfo->state &= ~IS_IN_WORK_LIST;
142
		else
Gerd Hoffmann's avatar
Gerd Hoffmann committed
143
			schedule_work(&devinfo->work);
Matthew Wilcox's avatar
Matthew Wilcox committed
144
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
145
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
146
147
}

148
static void uas_mark_cmd_dead(struct uas_dev_info *devinfo,
149
150
			      struct uas_cmd_info *cmdinfo,
			      int result, const char *caller)
151
152
153
154
155
156
157
158
159
{
	struct scsi_pointer *scp = (void *)cmdinfo;
	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);

	uas_log_cmd_state(cmnd, caller);
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
	WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
	cmdinfo->state |= COMMAND_ABORTED;
	cmdinfo->state &= ~IS_IN_WORK_LIST;
160
	cmnd->result = result << 16;
161
	list_move_tail(&cmdinfo->list, &devinfo->dead_list);
162
163
}

164
165
static void uas_abort_inflight(struct uas_dev_info *devinfo, int result,
			       const char *caller)
Gerd Hoffmann's avatar
Gerd Hoffmann committed
166
167
168
169
170
171
{
	struct uas_cmd_info *cmdinfo;
	struct uas_cmd_info *temp;
	unsigned long flags;

	spin_lock_irqsave(&devinfo->lock, flags);
172
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->inflight_list, list)
173
		uas_mark_cmd_dead(devinfo, cmdinfo, result, caller);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
174
175
176
	spin_unlock_irqrestore(&devinfo->lock, flags);
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
177
178
179
180
181
182
static void uas_add_work(struct uas_cmd_info *cmdinfo)
{
	struct scsi_pointer *scp = (void *)cmdinfo;
	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp);
	struct uas_dev_info *devinfo = cmnd->device->hostdata;

183
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
184
185
186
187
	cmdinfo->state |= IS_IN_WORK_LIST;
	schedule_work(&devinfo->work);
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
188
189
190
191
192
193
194
static void uas_zap_dead(struct uas_dev_info *devinfo)
{
	struct uas_cmd_info *cmdinfo;
	struct uas_cmd_info *temp;
	unsigned long flags;

	spin_lock_irqsave(&devinfo->lock, flags);
195
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, list) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
196
197
198
199
		struct scsi_pointer *scp = (void *)cmdinfo;
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
		uas_log_cmd_state(cmnd, __func__);
200
		WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
201
202
203
204
205
206
		/* all urbs are killed, clear inflight bits */
		cmdinfo->state &= ~(COMMAND_INFLIGHT |
				    DATA_IN_URB_INFLIGHT |
				    DATA_OUT_URB_INFLIGHT);
		uas_try_complete(cmnd, __func__);
	}
207
	devinfo->running_task = 0;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
208
209
210
	spin_unlock_irqrestore(&devinfo->lock, flags);
}

Matthew Wilcox's avatar
Matthew Wilcox committed
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
{
	struct sense_iu *sense_iu = urb->transfer_buffer;
	struct scsi_device *sdev = cmnd->device;

	if (urb->actual_length > 16) {
		unsigned len = be16_to_cpup(&sense_iu->len);
		if (len + 16 != urb->actual_length) {
			int newlen = min(len + 16, urb->actual_length) - 16;
			if (newlen < 0)
				newlen = 0;
			sdev_printk(KERN_INFO, sdev, "%s: urb length %d "
				"disagrees with IU sense data length %d, "
				"using %d bytes of sense data\n", __func__,
					urb->actual_length, len, newlen);
			len = newlen;
		}
		memcpy(cmnd->sense_buffer, sense_iu->sense, len);
	}

	cmnd->result = sense_iu->status;
}

static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
{
	struct sense_iu_old *sense_iu = urb->transfer_buffer;
	struct scsi_device *sdev = cmnd->device;

	if (urb->actual_length > 8) {
		unsigned len = be16_to_cpup(&sense_iu->len) - 2;
		if (len + 8 != urb->actual_length) {
			int newlen = min(len + 8, urb->actual_length) - 8;
			if (newlen < 0)
				newlen = 0;
			sdev_printk(KERN_INFO, sdev, "%s: urb length %d "
				"disagrees with IU sense data length %d, "
				"using %d bytes of sense data\n", __func__,
					urb->actual_length, len, newlen);
			len = newlen;
		}
		memcpy(cmnd->sense_buffer, sense_iu->sense, len);
	}

	cmnd->result = sense_iu->status;
255
256
257
258
259
260
261
}

static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller)
{
	struct uas_cmd_info *ci = (void *)&cmnd->SCp;

	scmd_printk(KERN_INFO, cmnd, "%s %p tag %d, inflight:"
Gerd Hoffmann's avatar
Gerd Hoffmann committed
262
		    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
263
264
265
266
267
268
269
270
271
272
273
		    caller, cmnd, cmnd->request->tag,
		    (ci->state & SUBMIT_STATUS_URB)     ? " s-st"  : "",
		    (ci->state & ALLOC_DATA_IN_URB)     ? " a-in"  : "",
		    (ci->state & SUBMIT_DATA_IN_URB)    ? " s-in"  : "",
		    (ci->state & ALLOC_DATA_OUT_URB)    ? " a-out" : "",
		    (ci->state & SUBMIT_DATA_OUT_URB)   ? " s-out" : "",
		    (ci->state & ALLOC_CMD_URB)         ? " a-cmd" : "",
		    (ci->state & SUBMIT_CMD_URB)        ? " s-cmd" : "",
		    (ci->state & COMMAND_INFLIGHT)      ? " CMD"   : "",
		    (ci->state & DATA_IN_URB_INFLIGHT)  ? " IN"    : "",
		    (ci->state & DATA_OUT_URB_INFLIGHT) ? " OUT"   : "",
274
		    (ci->state & COMMAND_COMPLETED)     ? " done"  : "",
Gerd Hoffmann's avatar
Gerd Hoffmann committed
275
		    (ci->state & COMMAND_ABORTED)       ? " abort" : "",
Gerd Hoffmann's avatar
Gerd Hoffmann committed
276
277
		    (ci->state & UNLINK_DATA_URBS)      ? " unlink": "",
		    (ci->state & IS_IN_WORK_LIST)       ? " work"  : "");
278
279
280
281
282
}

static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)
{
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
283
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
284

285
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
286
287
	if (cmdinfo->state & (COMMAND_INFLIGHT |
			      DATA_IN_URB_INFLIGHT |
Gerd Hoffmann's avatar
Gerd Hoffmann committed
288
289
			      DATA_OUT_URB_INFLIGHT |
			      UNLINK_DATA_URBS))
290
		return -EBUSY;
291
	WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
292
293
294
	cmdinfo->state |= COMMAND_COMPLETED;
	usb_free_urb(cmdinfo->data_in_urb);
	usb_free_urb(cmdinfo->data_out_urb);
295
	if (cmdinfo->state & COMMAND_ABORTED)
Gerd Hoffmann's avatar
Gerd Hoffmann committed
296
		scmd_printk(KERN_INFO, cmnd, "abort completed\n");
297
	list_del(&cmdinfo->list);
298
	cmnd->scsi_done(cmnd);
299
	return 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
300
301
302
}

static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
303
			  unsigned direction)
Matthew Wilcox's avatar
Matthew Wilcox committed
304
305
306
307
{
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
	int err;

308
	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
Matthew Wilcox's avatar
Matthew Wilcox committed
309
310
	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
	if (err) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
311
		uas_add_work(cmdinfo);
Matthew Wilcox's avatar
Matthew Wilcox committed
312
313
314
315
316
317
	}
}

static void uas_stat_cmplt(struct urb *urb)
{
	struct iu *iu = urb->transfer_buffer;
318
	struct Scsi_Host *shost = urb->context;
Hans de Goede's avatar
Hans de Goede committed
319
	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
Matthew Wilcox's avatar
Matthew Wilcox committed
320
	struct scsi_cmnd *cmnd;
321
	struct uas_cmd_info *cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
322
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
323
324
325
	u16 tag;

	if (urb->status) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
326
327
328
329
330
331
332
		if (urb->status == -ENOENT) {
			dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n",
				urb->stream_id);
		} else {
			dev_err(&urb->dev->dev, "stat urb: status %d\n",
				urb->status);
		}
333
		usb_free_urb(urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
334
335
336
		return;
	}

337
338
339
340
341
	if (devinfo->resetting) {
		usb_free_urb(urb);
		return;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
342
	spin_lock_irqsave(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
343
	tag = be16_to_cpup(&iu->tag) - 1;
344
345
	if (tag == 0)
		cmnd = devinfo->cmnd;
Matthew Wilcox's avatar
Matthew Wilcox committed
346
	else
347
		cmnd = scsi_host_find_tag(shost, tag - 1);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
348

349
	if (!cmnd) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
350
		if (iu->iu_id == IU_ID_RESPONSE) {
351
352
353
			if (!devinfo->running_task)
				dev_warn(&urb->dev->dev,
				    "stat urb: recv unexpected response iu\n");
Gerd Hoffmann's avatar
Gerd Hoffmann committed
354
355
			/* store results for uas_eh_task_mgmt() */
			memcpy(&devinfo->response, iu, sizeof(devinfo->response));
356
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
357
358
359
		usb_free_urb(urb);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return;
360
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
361

Gerd Hoffmann's avatar
Gerd Hoffmann committed
362
	cmdinfo = (void *)&cmnd->SCp;
Matthew Wilcox's avatar
Matthew Wilcox committed
363
364
	switch (iu->iu_id) {
	case IU_ID_STATUS:
365
366
367
		if (devinfo->cmnd == cmnd)
			devinfo->cmnd = NULL;

Matthew Wilcox's avatar
Matthew Wilcox committed
368
369
370
371
372
373
		if (urb->actual_length < 16)
			devinfo->uas_sense_old = 1;
		if (devinfo->uas_sense_old)
			uas_sense_old(urb, cmnd);
		else
			uas_sense(urb, cmnd);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
374
375
		if (cmnd->result != 0) {
			/* cancel data transfers on error */
376
			uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
377
		}
378
379
		cmdinfo->state &= ~COMMAND_INFLIGHT;
		uas_try_complete(cmnd, __func__);
Matthew Wilcox's avatar
Matthew Wilcox committed
380
381
382
383
384
385
386
387
388
389
390
		break;
	case IU_ID_READ_READY:
		uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);
		break;
	case IU_ID_WRITE_READY:
		uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);
		break;
	default:
		scmd_printk(KERN_ERR, cmnd,
			"Bogus IU (%d) received on status pipe\n", iu->iu_id);
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
391
	usb_free_urb(urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
392
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
393
394
}

395
static void uas_data_cmplt(struct urb *urb)
Matthew Wilcox's avatar
Matthew Wilcox committed
396
{
397
398
	struct scsi_cmnd *cmnd = urb->context;
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
399
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
400
	struct scsi_data_buffer *sdb = NULL;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
401
	unsigned long flags;
402

Gerd Hoffmann's avatar
Gerd Hoffmann committed
403
	spin_lock_irqsave(&devinfo->lock, flags);
404
405
406
407
408
409
410
	if (cmdinfo->data_in_urb == urb) {
		sdb = scsi_in(cmnd);
		cmdinfo->state &= ~DATA_IN_URB_INFLIGHT;
	} else if (cmdinfo->data_out_urb == urb) {
		sdb = scsi_out(cmnd);
		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;
	}
411
412
413
	if (sdb == NULL) {
		WARN_ON_ONCE(1);
	} else if (urb->status) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
414
415
416
417
418
		/* error: no data transfered */
		sdb->resid = sdb->length;
	} else {
		sdb->resid = sdb->length - urb->actual_length;
	}
419
	uas_try_complete(cmnd, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
420
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
421
422
423
}

static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
424
425
426
				      unsigned int pipe, u16 stream_id,
				      struct scsi_cmnd *cmnd,
				      enum dma_data_direction dir)
Matthew Wilcox's avatar
Matthew Wilcox committed
427
428
429
{
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
430
431
	struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
		? scsi_in(cmnd) : scsi_out(cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
432
433
434

	if (!urb)
		goto out;
435
436
	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
			  uas_data_cmplt, cmnd);
437
	urb->stream_id = stream_id;
Matthew Wilcox's avatar
Matthew Wilcox committed
438
439
440
441
442
443
444
	urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
	urb->sg = sdb->table.sgl;
 out:
	return urb;
}

static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
Gerd Hoffmann's avatar
Gerd Hoffmann committed
445
				       struct Scsi_Host *shost, u16 stream_id)
Matthew Wilcox's avatar
Matthew Wilcox committed
446
447
448
449
450
451
452
453
{
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
	struct sense_iu *iu;

	if (!urb)
		goto out;

454
	iu = kzalloc(sizeof(*iu), gfp);
Matthew Wilcox's avatar
Matthew Wilcox committed
455
456
457
458
	if (!iu)
		goto free;

	usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
459
						uas_stat_cmplt, shost);
Matthew Wilcox's avatar
Matthew Wilcox committed
460
461
462
463
464
465
466
467
468
469
	urb->stream_id = stream_id;
	urb->transfer_flags |= URB_FREE_BUFFER;
 out:
	return urb;
 free:
	usb_free_urb(urb);
	return NULL;
}

static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
470
					struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
471
472
473
474
475
476
477
478
479
480
481
482
483
484
{
	struct usb_device *udev = devinfo->udev;
	struct scsi_device *sdev = cmnd->device;
	struct urb *urb = usb_alloc_urb(0, gfp);
	struct command_iu *iu;
	int len;

	if (!urb)
		goto out;

	len = cmnd->cmd_len - 16;
	if (len < 0)
		len = 0;
	len = ALIGN(len, 4);
485
	iu = kzalloc(sizeof(*iu) + len, gfp);
Matthew Wilcox's avatar
Matthew Wilcox committed
486
487
488
489
	if (!iu)
		goto free;

	iu->iu_id = IU_ID_COMMAND;
490
	if (blk_rq_tagged(cmnd->request))
491
		iu->tag = cpu_to_be16(cmnd->request->tag + 2);
492
493
	else
		iu->tag = cpu_to_be16(1);
494
	iu->prio_attr = UAS_SIMPLE_TAG;
Matthew Wilcox's avatar
Matthew Wilcox committed
495
496
497
498
499
500
501
502
503
504
505
506
507
508
	iu->len = len;
	int_to_scsilun(sdev->lun, &iu->lun);
	memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);

	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len,
							usb_free_urb, NULL);
	urb->transfer_flags |= URB_FREE_BUFFER;
 out:
	return urb;
 free:
	usb_free_urb(urb);
	return NULL;
}

509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,
			       u8 function, u16 stream_id)
{
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
	struct task_mgmt_iu *iu;
	int err = -ENOMEM;

	if (!urb)
		goto err;

	iu = kzalloc(sizeof(*iu), gfp);
	if (!iu)
		goto err;

	iu->iu_id = IU_ID_TASK_MGMT;
	iu->tag = cpu_to_be16(stream_id);
	int_to_scsilun(cmnd->device->lun, &iu->lun);

	iu->function = function;
	switch (function) {
	case TMF_ABORT_TASK:
		if (blk_rq_tagged(cmnd->request))
			iu->task_tag = cpu_to_be16(cmnd->request->tag + 2);
		else
			iu->task_tag = cpu_to_be16(1);
		break;
	}

	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu),
			  usb_free_urb, NULL);
	urb->transfer_flags |= URB_FREE_BUFFER;

543
	usb_anchor_urb(urb, &devinfo->cmd_urbs);
544
	err = usb_submit_urb(urb, gfp);
545
546
	if (err) {
		usb_unanchor_urb(urb);
547
		goto err;
548
	}
549
550
551
552
553
554
555
556

	return 0;

err:
	usb_free_urb(urb);
	return err;
}

Matthew Wilcox's avatar
Matthew Wilcox committed
557
558
559
560
561
562
/*
 * Why should I request the Status IU before sending the Command IU?  Spec
 * says to, but also says the device may receive them in any order.  Seems
 * daft to me.
 */

563
564
static struct urb *uas_submit_sense_urb(struct Scsi_Host *shost,
					gfp_t gfp, unsigned int stream)
Matthew Wilcox's avatar
Matthew Wilcox committed
565
{
Hans de Goede's avatar
Hans de Goede committed
566
	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
567
	struct urb *urb;
Matthew Wilcox's avatar
Matthew Wilcox committed
568

Gerd Hoffmann's avatar
Gerd Hoffmann committed
569
570
	urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
	if (!urb)
571
		return NULL;
572
	usb_anchor_urb(urb, &devinfo->sense_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
573
	if (usb_submit_urb(urb, gfp)) {
574
		usb_unanchor_urb(urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
575
576
577
		shost_printk(KERN_INFO, shost,
			     "sense urb submission failure\n");
		usb_free_urb(urb);
578
		return NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
579
	}
580
	return urb;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
581
582
583
584
585
586
}

static int uas_submit_urbs(struct scsi_cmnd *cmnd,
			   struct uas_dev_info *devinfo, gfp_t gfp)
{
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
587
	struct urb *urb;
Matthew Wilcox's avatar
Matthew Wilcox committed
588

589
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
590
	if (cmdinfo->state & SUBMIT_STATUS_URB) {
591
		urb = uas_submit_sense_urb(cmnd->device->host, gfp,
Gerd Hoffmann's avatar
Gerd Hoffmann committed
592
					   cmdinfo->stream);
593
594
		if (!urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
595
		cmdinfo->state &= ~SUBMIT_STATUS_URB;
Matthew Wilcox's avatar
Matthew Wilcox committed
596
597
598
599
	}

	if (cmdinfo->state & ALLOC_DATA_IN_URB) {
		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
600
					devinfo->data_in_pipe, cmdinfo->stream,
601
					cmnd, DMA_FROM_DEVICE);
Matthew Wilcox's avatar
Matthew Wilcox committed
602
603
604
605
606
607
		if (!cmdinfo->data_in_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_DATA_IN_URB;
	}

	if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
608
		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
609
		if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) {
610
			usb_unanchor_urb(cmdinfo->data_in_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
611
612
613
614
615
			scmd_printk(KERN_INFO, cmnd,
					"data in urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
		cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
616
		cmdinfo->state |= DATA_IN_URB_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
617
618
619
620
	}

	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
621
					devinfo->data_out_pipe, cmdinfo->stream,
622
					cmnd, DMA_TO_DEVICE);
Matthew Wilcox's avatar
Matthew Wilcox committed
623
624
625
626
627
628
		if (!cmdinfo->data_out_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
	}

	if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
629
		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
630
		if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) {
631
			usb_unanchor_urb(cmdinfo->data_out_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
632
633
634
635
636
			scmd_printk(KERN_INFO, cmnd,
					"data out urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
637
		cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
638
639
640
	}

	if (cmdinfo->state & ALLOC_CMD_URB) {
641
		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
642
643
644
645
646
647
		if (!cmdinfo->cmd_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_CMD_URB;
	}

	if (cmdinfo->state & SUBMIT_CMD_URB) {
648
		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
649
		if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) {
650
			usb_unanchor_urb(cmdinfo->cmd_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
651
652
653
654
			scmd_printk(KERN_INFO, cmnd,
					"cmd urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
655
		cmdinfo->cmd_urb = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
656
		cmdinfo->state &= ~SUBMIT_CMD_URB;
657
		cmdinfo->state |= COMMAND_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
658
659
660
661
662
	}

	return 0;
}

Jeff Garzik's avatar
Jeff Garzik committed
663
static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
Matthew Wilcox's avatar
Matthew Wilcox committed
664
665
666
667
668
					void (*done)(struct scsi_cmnd *))
{
	struct scsi_device *sdev = cmnd->device;
	struct uas_dev_info *devinfo = sdev->hostdata;
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
669
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
670
671
672
673
	int err;

	BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));

674
675
	spin_lock_irqsave(&devinfo->lock, flags);

676
677
678
	if (devinfo->resetting) {
		cmnd->result = DID_ERROR << 16;
		cmnd->scsi_done(cmnd);
679
		spin_unlock_irqrestore(&devinfo->lock, flags);
680
681
682
		return 0;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
683
684
	if (devinfo->cmnd) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
685
		return SCSI_MLQUEUE_DEVICE_BUSY;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
686
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
687

688
689
	memset(cmdinfo, 0, sizeof(*cmdinfo));

Matthew Wilcox's avatar
Matthew Wilcox committed
690
	if (blk_rq_tagged(cmnd->request)) {
691
		cmdinfo->stream = cmnd->request->tag + 2;
Matthew Wilcox's avatar
Matthew Wilcox committed
692
	} else {
693
		devinfo->cmnd = cmnd;
Matthew Wilcox's avatar
Matthew Wilcox committed
694
695
696
697
698
		cmdinfo->stream = 1;
	}

	cmnd->scsi_done = done;

Gerd Hoffmann's avatar
Gerd Hoffmann committed
699
	cmdinfo->state = SUBMIT_STATUS_URB |
Matthew Wilcox's avatar
Matthew Wilcox committed
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
			ALLOC_CMD_URB | SUBMIT_CMD_URB;

	switch (cmnd->sc_data_direction) {
	case DMA_FROM_DEVICE:
		cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
		break;
	case DMA_BIDIRECTIONAL:
		cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB;
	case DMA_TO_DEVICE:
		cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB;
	case DMA_NONE:
		break;
	}

	if (!devinfo->use_streams) {
715
		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
Matthew Wilcox's avatar
Matthew Wilcox committed
716
717
718
719
720
721
		cmdinfo->stream = 0;
	}

	err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
	if (err) {
		/* If we did nothing, give up now */
722
		if (cmdinfo->state & SUBMIT_STATUS_URB) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
723
			spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
724
725
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
726
		uas_add_work(cmdinfo);
Matthew Wilcox's avatar
Matthew Wilcox committed
727
728
	}

729
	list_add_tail(&cmdinfo->list, &devinfo->inflight_list);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
730
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
731
732
733
	return 0;
}

Jeff Garzik's avatar
Jeff Garzik committed
734
735
static DEF_SCSI_QCMD(uas_queuecommand)

736
737
static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
			    const char *fname, u8 function)
Matthew Wilcox's avatar
Matthew Wilcox committed
738
{
739
	struct Scsi_Host *shost = cmnd->device->host;
Hans de Goede's avatar
Hans de Goede committed
740
	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;
741
	u16 tag = devinfo->qdepth;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
742
	unsigned long flags;
743
	struct urb *sense_urb;
744
	int result = SUCCESS;
Matthew Wilcox's avatar
Matthew Wilcox committed
745

Gerd Hoffmann's avatar
Gerd Hoffmann committed
746
	spin_lock_irqsave(&devinfo->lock, flags);
747

748
749
750
751
752
	if (devinfo->resetting) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return FAILED;
	}

753
754
755
756
757
758
759
760
761
	if (devinfo->running_task) {
		shost_printk(KERN_INFO, shost,
			     "%s: %s: error already running a task\n",
			     __func__, fname);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return FAILED;
	}

	devinfo->running_task = 1;
762
	memset(&devinfo->response, 0, sizeof(devinfo->response));
763
764
	sense_urb = uas_submit_sense_urb(shost, GFP_NOIO,
					 devinfo->use_streams ? tag : 0);
765
	if (!sense_urb) {
766
767
768
		shost_printk(KERN_INFO, shost,
			     "%s: %s: submit sense urb failed\n",
			     __func__, fname);
769
		devinfo->running_task = 0;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
770
		spin_unlock_irqrestore(&devinfo->lock, flags);
771
772
		return FAILED;
	}
773
	if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) {
774
775
776
		shost_printk(KERN_INFO, shost,
			     "%s: %s: submit task mgmt urb failed\n",
			     __func__, fname);
777
		devinfo->running_task = 0;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
778
		spin_unlock_irqrestore(&devinfo->lock, flags);
779
		usb_kill_urb(sense_urb);
780
781
		return FAILED;
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
782
783
784
	spin_unlock_irqrestore(&devinfo->lock, flags);

	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
785
786
787
788
789
790
		/*
		 * Note we deliberately do not clear running_task here. If we
		 * allow new tasks to be submitted, there is no way to figure
		 * out if a received response_iu is for the failed task or for
		 * the new one. A bus-reset will eventually clear running_task.
		 */
791
792
793
794
		shost_printk(KERN_INFO, shost,
			     "%s: %s timed out\n", __func__, fname);
		return FAILED;
	}
795
796
797

	spin_lock_irqsave(&devinfo->lock, flags);
	devinfo->running_task = 0;
798
799
800
801
	if (be16_to_cpu(devinfo->response.tag) != tag) {
		shost_printk(KERN_INFO, shost,
			     "%s: %s failed (wrong tag %d/%d)\n", __func__,
			     fname, be16_to_cpu(devinfo->response.tag), tag);
802
803
		result = FAILED;
	} else if (devinfo->response.response_code != RC_TMF_COMPLETE) {
804
805
806
		shost_printk(KERN_INFO, shost,
			     "%s: %s failed (rc 0x%x)\n", __func__,
			     fname, devinfo->response.response_code);
807
		result = FAILED;
808
	}
809
810
811
	spin_unlock_irqrestore(&devinfo->lock, flags);

	return result;
Matthew Wilcox's avatar
Matthew Wilcox committed
812
813
}

814
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
815
{
816
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
817
818
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
	unsigned long flags;
819
	int ret;
Matthew Wilcox's avatar
Matthew Wilcox committed
820

Gerd Hoffmann's avatar
Gerd Hoffmann committed
821
	spin_lock_irqsave(&devinfo->lock, flags);
822
823
824
825
826
827

	if (devinfo->resetting) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return FAILED;
	}

828
	uas_mark_cmd_dead(devinfo, cmdinfo, DID_ABORT, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
829
830
831
832
	if (cmdinfo->state & COMMAND_INFLIGHT) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
		ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
	} else {
833
		uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
834
835
836
837
		uas_try_complete(cmnd, __func__);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		ret = SUCCESS;
	}
838
	return ret;
Matthew Wilcox's avatar
Matthew Wilcox committed
839
840
}

841
static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
842
{
843
844
845
	sdev_printk(KERN_INFO, cmnd->device, "%s\n", __func__);
	return uas_eh_task_mgmt(cmnd, "LOGICAL UNIT RESET",
				TMF_LOGICAL_UNIT_RESET);
Matthew Wilcox's avatar
Matthew Wilcox committed
846
847
848
849
850
851
852
}

static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)
{
	struct scsi_device *sdev = cmnd->device;
	struct uas_dev_info *devinfo = sdev->hostdata;
	struct usb_device *udev = devinfo->udev;
853
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
854

Hans de Goede's avatar
Hans de Goede committed
855
856
857
858
859
860
861
	err = usb_lock_device_for_reset(udev, devinfo->intf);
	if (err) {
		shost_printk(KERN_ERR, sdev->host,
			     "%s FAILED to get lock err %d\n", __func__, err);
		return FAILED;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
862
	shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
863
	devinfo->resetting = 1;
864
	uas_abort_inflight(devinfo, DID_RESET, __func__);
865
	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
866
867
	usb_kill_anchored_urbs(&devinfo->sense_urbs);
	usb_kill_anchored_urbs(&devinfo->data_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
868
	uas_zap_dead(devinfo);
869
870
	err = usb_reset_device(udev);
	devinfo->resetting = 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
871

Hans de Goede's avatar
Hans de Goede committed
872
873
	usb_unlock_device(udev);

874
875
876
877
	if (err) {
		shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
		return FAILED;
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
878

879
880
	shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
	return SUCCESS;
Matthew Wilcox's avatar
Matthew Wilcox committed
881
882
883
884
}

static int uas_slave_alloc(struct scsi_device *sdev)
{
Hans de Goede's avatar
Hans de Goede committed
885
	sdev->hostdata = (void *)sdev->host->hostdata;
Matthew Wilcox's avatar
Matthew Wilcox committed
886
887
888
889
890
891
892
	return 0;
}

static int uas_slave_configure(struct scsi_device *sdev)
{
	struct uas_dev_info *devinfo = sdev->hostdata;
	scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
893
	scsi_activate_tcq(sdev, devinfo->qdepth - 2);
Matthew Wilcox's avatar
Matthew Wilcox committed
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
	return 0;
}

static struct scsi_host_template uas_host_template = {
	.module = THIS_MODULE,
	.name = "uas",
	.queuecommand = uas_queuecommand,
	.slave_alloc = uas_slave_alloc,
	.slave_configure = uas_slave_configure,
	.eh_abort_handler = uas_eh_abort_handler,
	.eh_device_reset_handler = uas_eh_device_reset_handler,
	.eh_bus_reset_handler = uas_eh_bus_reset_handler,
	.can_queue = 65536,	/* Is there a limit on the _host_ ? */
	.this_id = -1,
	.sg_tablesize = SG_NONE,
	.cmd_per_lun = 1,	/* until we override it */
	.skip_settle_delay = 1,
	.ordered_tag = 1,
};

914
915
916
917
918
919
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
		    vendorName, productName, useProtocol, useTransport, \
		    initFunction, flags) \
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
	.driver_info = (flags) }

Matthew Wilcox's avatar
Matthew Wilcox committed
920
static struct usb_device_id uas_usb_ids[] = {
921
#	include "unusual_uas.h"
Matthew Wilcox's avatar
Matthew Wilcox committed
922
923
924
925
926
927
928
929
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },
	/* 0xaa is a prototype device I happen to have access to */
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, 0xaa) },
	{ }
};
MODULE_DEVICE_TABLE(usb, uas_usb_ids);

930
931
#undef UNUSUAL_DEV

932
933
934
935
936
937
938
939
940
941
942
943
944
static int uas_switch_interface(struct usb_device *udev,
				struct usb_interface *intf)
{
	int alt;

	alt = uas_find_uas_alt_setting(intf);
	if (alt < 0)
		return alt;

	return usb_set_interface(udev,
			intf->altsetting[0].desc.bInterfaceNumber, alt);
}

945
static int uas_configure_endpoints(struct uas_dev_info *devinfo)
946
947
948
949
950
951
952
953
954
{
	struct usb_host_endpoint *eps[4] = { };
	struct usb_device *udev = devinfo->udev;
	int r;

	devinfo->uas_sense_old = 0;
	devinfo->cmnd = NULL;

	r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps);
955
956
957
958
959
960
961
962
963
964
965
	if (r)
		return r;

	devinfo->cmd_pipe = usb_sndbulkpipe(udev,
					    usb_endpoint_num(&eps[0]->desc));
	devinfo->status_pipe = usb_rcvbulkpipe(udev,
					    usb_endpoint_num(&eps[1]->desc));
	devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
					    usb_endpoint_num(&eps[2]->desc));
	devinfo->data_out_pipe = usb_sndbulkpipe(udev,
					    usb_endpoint_num(&eps[3]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
966

967
	if (udev->speed != USB_SPEED_SUPER) {
Matthew Wilcox's avatar
Matthew Wilcox committed
968
969
970
		devinfo->qdepth = 256;
		devinfo->use_streams = 0;
	} else {
971
972
973
974
		devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1,
						    3, 256, GFP_KERNEL);
		if (devinfo->qdepth < 0)
			return devinfo->qdepth;
Matthew Wilcox's avatar
Matthew Wilcox committed
975
976
		devinfo->use_streams = 1;
	}
977
978

	return 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
979
980
}

981
982
983
984
985
986
987
988
989
990
991
static void uas_free_streams(struct uas_dev_info *devinfo)
{
	struct usb_device *udev = devinfo->udev;
	struct usb_host_endpoint *eps[3];

	eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
	eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
	eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
	usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
}

Matthew Wilcox's avatar
Matthew Wilcox committed
992
993
994
995
996
997
998
999
/*
 * XXX: What I'd like to do here is register a SCSI host for each USB host in
 * the system.  Follow usb-storage's design of registering a SCSI host for
 * each USB device for the moment.  Can implement this by walking up the
 * USB hierarchy until we find a USB host.
 */
static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
1000
1001
	int result = -ENOMEM;
	struct Scsi_Host *shost = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
1002
1003
1004
	struct uas_dev_info *devinfo;
	struct usb_device *udev = interface_to_usbdev(intf);

1005
1006
1007
	if (!uas_use_uas_driver(intf, id))
		return -ENODEV;

1008
1009
	if (uas_switch_interface(udev, intf))
		return -ENODEV;
Matthew Wilcox's avatar
Matthew Wilcox committed
1010

Hans de Goede's avatar
Hans de Goede committed
1011
1012
	shost = scsi_host_alloc(&uas_host_template,
				sizeof(struct uas_dev_info));
Matthew Wilcox's avatar
Matthew Wilcox committed
1013
	if (!shost)
1014
		goto set_alt0;
Matthew Wilcox's avatar
Matthew Wilcox committed
1015
1016
1017

	shost->max_cmd_len = 16 +