uas.c 30 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/hcd.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
17
#include <linux/usb/storage.h>
18
#include <linux/usb/uas.h>
Matthew Wilcox's avatar
Matthew Wilcox committed
19
20

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

28
29
#include "uas-detect.h"

Matthew Wilcox's avatar
Matthew Wilcox committed
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
 * 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;
47
	struct usb_anchor cmd_urbs;
48
49
	struct usb_anchor sense_urbs;
	struct usb_anchor data_urbs;
50
	int qdepth, resetting;
51
	struct response_iu response;
Matthew Wilcox's avatar
Matthew Wilcox committed
52
53
54
	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
	unsigned use_streams:1;
	unsigned uas_sense_old:1;
55
	struct scsi_cmnd *cmnd;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
56
	spinlock_t lock;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
57
58
	struct work_struct work;
	struct list_head work_list;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
59
	struct list_head dead_list;
Matthew Wilcox's avatar
Matthew Wilcox committed
60
61
62
};

enum {
63
	SUBMIT_STATUS_URB	= (1 << 1),
Matthew Wilcox's avatar
Matthew Wilcox committed
64
65
66
67
68
69
	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),
70
71
72
73
	COMMAND_INFLIGHT        = (1 << 8),
	DATA_IN_URB_INFLIGHT    = (1 << 9),
	DATA_OUT_URB_INFLIGHT   = (1 << 10),
	COMMAND_COMPLETED       = (1 << 11),
74
	COMMAND_ABORTED         = (1 << 12),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
75
	UNLINK_DATA_URBS        = (1 << 13),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
76
	IS_IN_WORK_LIST         = (1 << 14),
Matthew Wilcox's avatar
Matthew Wilcox committed
77
78
79
80
81
82
83
84
85
};

/* 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;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
86
	struct list_head work;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
87
	struct list_head dead;
Matthew Wilcox's avatar
Matthew Wilcox committed
88
89
90
91
92
};

/* 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);
93
static void uas_do_work(struct work_struct *work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
94
static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller);
95
96
static void uas_configure_endpoints(struct uas_dev_info *devinfo);
static void uas_free_streams(struct uas_dev_info *devinfo);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
97
static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller);
Matthew Wilcox's avatar
Matthew Wilcox committed
98

99
/* Must be called with devinfo->lock held, will temporary unlock the lock */
100
static void uas_unlink_data_urbs(struct uas_dev_info *devinfo,
101
102
				 struct uas_cmd_info *cmdinfo,
				 unsigned long *lock_flags)
103
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
104
105
106
107
108
109
	/*
	 * 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;
110
	spin_unlock_irqrestore(&devinfo->lock, *lock_flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
111

112
113
114
115
	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
116

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

Matthew Wilcox's avatar
Matthew Wilcox committed
121
122
static void uas_do_work(struct work_struct *work)
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
123
124
	struct uas_dev_info *devinfo =
		container_of(work, struct uas_dev_info, work);
Matthew Wilcox's avatar
Matthew Wilcox committed
125
	struct uas_cmd_info *cmdinfo;
126
	struct uas_cmd_info *temp;
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
131
	spin_lock_irqsave(&devinfo->lock, flags);
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) {
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);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
135
		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
136
		if (!err) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
137
			cmdinfo->state &= ~IS_IN_WORK_LIST;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
138
139
140
			list_del(&cmdinfo->work);
		} else {
			schedule_work(&devinfo->work);
141
		}
Matthew Wilcox's avatar
Matthew Wilcox committed
142
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
143
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
144
145
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
146
147
148
149
150
151
152
static void uas_abort_work(struct uas_dev_info *devinfo)
{
	struct uas_cmd_info *cmdinfo;
	struct uas_cmd_info *temp;
	unsigned long flags;

	spin_lock_irqsave(&devinfo->lock, flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
153
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->work_list, work) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
154
		struct scsi_pointer *scp = (void *)cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
155
156
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
157
		uas_log_cmd_state(cmnd, __func__);
158
		WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
159
160
161
		cmdinfo->state |= COMMAND_ABORTED;
		cmdinfo->state &= ~IS_IN_WORK_LIST;
		list_del(&cmdinfo->work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
162
		list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
163
164
165
166
	}
	spin_unlock_irqrestore(&devinfo->lock, flags);
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
167
168
169
170
171
172
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;

173
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
174
175
176
177
178
	list_add_tail(&cmdinfo->work, &devinfo->work_list);
	cmdinfo->state |= IS_IN_WORK_LIST;
	schedule_work(&devinfo->work);
}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
179
180
181
182
183
184
185
186
187
188
189
190
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);
	list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, dead) {
		struct scsi_pointer *scp = (void *)cmdinfo;
		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd,
						      SCp);
		uas_log_cmd_state(cmnd, __func__);
191
		WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
192
193
194
195
196
197
198
199
200
		/* all urbs are killed, clear inflight bits */
		cmdinfo->state &= ~(COMMAND_INFLIGHT |
				    DATA_IN_URB_INFLIGHT |
				    DATA_OUT_URB_INFLIGHT);
		uas_try_complete(cmnd, __func__);
	}
	spin_unlock_irqrestore(&devinfo->lock, flags);
}

Matthew Wilcox's avatar
Matthew Wilcox committed
201
202
203
204
205
206
207
208
209
210
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
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;
245
246
247
248
249
250
251
}

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
252
		    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
253
254
255
256
257
258
259
260
261
262
263
		    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"   : "",
264
		    (ci->state & COMMAND_COMPLETED)     ? " done"  : "",
Gerd Hoffmann's avatar
Gerd Hoffmann committed
265
		    (ci->state & COMMAND_ABORTED)       ? " abort" : "",
Gerd Hoffmann's avatar
Gerd Hoffmann committed
266
267
		    (ci->state & UNLINK_DATA_URBS)      ? " unlink": "",
		    (ci->state & IS_IN_WORK_LIST)       ? " work"  : "");
268
269
270
271
272
}

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
273
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
274

275
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
276
277
	if (cmdinfo->state & (COMMAND_INFLIGHT |
			      DATA_IN_URB_INFLIGHT |
Gerd Hoffmann's avatar
Gerd Hoffmann committed
278
279
			      DATA_OUT_URB_INFLIGHT |
			      UNLINK_DATA_URBS))
280
		return -EBUSY;
281
	WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);
282
283
284
	cmdinfo->state |= COMMAND_COMPLETED;
	usb_free_urb(cmdinfo->data_in_urb);
	usb_free_urb(cmdinfo->data_out_urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
285
286
287
	if (cmdinfo->state & COMMAND_ABORTED) {
		scmd_printk(KERN_INFO, cmnd, "abort completed\n");
		cmnd->result = DID_ABORT << 16;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
288
		list_del(&cmdinfo->dead);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
289
	}
290
	cmnd->scsi_done(cmnd);
291
	return 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
292
293
294
}

static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
295
			  unsigned direction)
Matthew Wilcox's avatar
Matthew Wilcox committed
296
297
298
299
{
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
	int err;

300
	cmdinfo->state |= direction | SUBMIT_STATUS_URB;
Matthew Wilcox's avatar
Matthew Wilcox committed
301
302
	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
	if (err) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
303
		uas_add_work(cmdinfo);
Matthew Wilcox's avatar
Matthew Wilcox committed
304
305
306
307
308
309
	}
}

static void uas_stat_cmplt(struct urb *urb)
{
	struct iu *iu = urb->transfer_buffer;
310
311
	struct Scsi_Host *shost = urb->context;
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
Matthew Wilcox's avatar
Matthew Wilcox committed
312
	struct scsi_cmnd *cmnd;
313
	struct uas_cmd_info *cmdinfo;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
314
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
315
316
317
	u16 tag;

	if (urb->status) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
318
319
320
321
322
323
324
		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);
		}
325
		usb_free_urb(urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
326
327
328
		return;
	}

329
330
331
332
333
	if (devinfo->resetting) {
		usb_free_urb(urb);
		return;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
334
	spin_lock_irqsave(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
335
	tag = be16_to_cpup(&iu->tag) - 1;
336
337
	if (tag == 0)
		cmnd = devinfo->cmnd;
Matthew Wilcox's avatar
Matthew Wilcox committed
338
	else
339
		cmnd = scsi_host_find_tag(shost, tag - 1);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
340

341
	if (!cmnd) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
342
343
344
		if (iu->iu_id == IU_ID_RESPONSE) {
			/* store results for uas_eh_task_mgmt() */
			memcpy(&devinfo->response, iu, sizeof(devinfo->response));
345
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
346
347
348
		usb_free_urb(urb);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		return;
349
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
350

Gerd Hoffmann's avatar
Gerd Hoffmann committed
351
	cmdinfo = (void *)&cmnd->SCp;
Matthew Wilcox's avatar
Matthew Wilcox committed
352
353
	switch (iu->iu_id) {
	case IU_ID_STATUS:
354
355
356
		if (devinfo->cmnd == cmnd)
			devinfo->cmnd = NULL;

Matthew Wilcox's avatar
Matthew Wilcox committed
357
358
359
360
361
362
		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
363
364
		if (cmnd->result != 0) {
			/* cancel data transfers on error */
365
			uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
366
		}
367
368
		cmdinfo->state &= ~COMMAND_INFLIGHT;
		uas_try_complete(cmnd, __func__);
Matthew Wilcox's avatar
Matthew Wilcox committed
369
370
371
372
373
374
375
376
377
378
379
		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
380
	usb_free_urb(urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
381
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
382
383
}

384
static void uas_data_cmplt(struct urb *urb)
Matthew Wilcox's avatar
Matthew Wilcox committed
385
{
386
387
	struct scsi_cmnd *cmnd = urb->context;
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
388
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
389
	struct scsi_data_buffer *sdb = NULL;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
390
	unsigned long flags;
391

Gerd Hoffmann's avatar
Gerd Hoffmann committed
392
	spin_lock_irqsave(&devinfo->lock, flags);
393
394
395
396
397
398
399
	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;
	}
400
401
402
	if (sdb == NULL) {
		WARN_ON_ONCE(1);
	} else if (urb->status) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
403
404
405
406
407
		/* error: no data transfered */
		sdb->resid = sdb->length;
	} else {
		sdb->resid = sdb->length - urb->actual_length;
	}
408
	uas_try_complete(cmnd, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
409
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
410
411
412
}

static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
413
414
415
				      unsigned int pipe, u16 stream_id,
				      struct scsi_cmnd *cmnd,
				      enum dma_data_direction dir)
Matthew Wilcox's avatar
Matthew Wilcox committed
416
417
418
{
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
419
420
	struct scsi_data_buffer *sdb = (dir == DMA_FROM_DEVICE)
		? scsi_in(cmnd) : scsi_out(cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
421
422
423

	if (!urb)
		goto out;
424
425
	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
			  uas_data_cmplt, cmnd);
426
427
	if (devinfo->use_streams)
		urb->stream_id = stream_id;
Matthew Wilcox's avatar
Matthew Wilcox committed
428
429
430
431
432
433
434
	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
435
				       struct Scsi_Host *shost, u16 stream_id)
Matthew Wilcox's avatar
Matthew Wilcox committed
436
437
438
439
440
441
442
443
{
	struct usb_device *udev = devinfo->udev;
	struct urb *urb = usb_alloc_urb(0, gfp);
	struct sense_iu *iu;

	if (!urb)
		goto out;

444
	iu = kzalloc(sizeof(*iu), gfp);
Matthew Wilcox's avatar
Matthew Wilcox committed
445
446
447
448
	if (!iu)
		goto free;

	usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
Gerd Hoffmann's avatar
Gerd Hoffmann committed
449
						uas_stat_cmplt, shost);
Matthew Wilcox's avatar
Matthew Wilcox committed
450
451
452
453
454
455
456
457
458
459
	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,
460
					struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
461
462
463
464
465
466
467
468
469
470
471
472
473
474
{
	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);
475
	iu = kzalloc(sizeof(*iu) + len, gfp);
Matthew Wilcox's avatar
Matthew Wilcox committed
476
477
478
479
	if (!iu)
		goto free;

	iu->iu_id = IU_ID_COMMAND;
480
	if (blk_rq_tagged(cmnd->request))
481
		iu->tag = cpu_to_be16(cmnd->request->tag + 2);
482
483
	else
		iu->tag = cpu_to_be16(1);
484
	iu->prio_attr = UAS_SIMPLE_TAG;
Matthew Wilcox's avatar
Matthew Wilcox committed
485
486
487
488
489
490
491
492
493
494
495
496
497
498
	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;
}

499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
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;

533
	usb_anchor_urb(urb, &devinfo->cmd_urbs);
534
	err = usb_submit_urb(urb, gfp);
535
536
	if (err) {
		usb_unanchor_urb(urb);
537
		goto err;
538
	}
539
540
541
542
543
544
545
546

	return 0;

err:
	usb_free_urb(urb);
	return err;
}

Matthew Wilcox's avatar
Matthew Wilcox committed
547
548
549
550
551
552
/*
 * 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.
 */

Gerd Hoffmann's avatar
Gerd Hoffmann committed
553
554
static int uas_submit_sense_urb(struct Scsi_Host *shost,
				gfp_t gfp, unsigned int stream)
Matthew Wilcox's avatar
Matthew Wilcox committed
555
{
Gerd Hoffmann's avatar
Gerd Hoffmann committed
556
557
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
	struct urb *urb;
Matthew Wilcox's avatar
Matthew Wilcox committed
558

Gerd Hoffmann's avatar
Gerd Hoffmann committed
559
560
561
	urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);
	if (!urb)
		return SCSI_MLQUEUE_DEVICE_BUSY;
562
	usb_anchor_urb(urb, &devinfo->sense_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
563
	if (usb_submit_urb(urb, gfp)) {
564
		usb_unanchor_urb(urb);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
565
566
567
568
		shost_printk(KERN_INFO, shost,
			     "sense urb submission failure\n");
		usb_free_urb(urb);
		return SCSI_MLQUEUE_DEVICE_BUSY;
Matthew Wilcox's avatar
Matthew Wilcox committed
569
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
570
571
572
573
574
575
576
577
	return 0;
}

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;
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
578

579
	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));
580
	if (cmdinfo->state & SUBMIT_STATUS_URB) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
581
582
583
584
		err = uas_submit_sense_urb(cmnd->device->host, gfp,
					   cmdinfo->stream);
		if (err) {
			return err;
Matthew Wilcox's avatar
Matthew Wilcox committed
585
		}
586
		cmdinfo->state &= ~SUBMIT_STATUS_URB;
Matthew Wilcox's avatar
Matthew Wilcox committed
587
588
589
590
	}

	if (cmdinfo->state & ALLOC_DATA_IN_URB) {
		cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
591
					devinfo->data_in_pipe, cmdinfo->stream,
592
					cmnd, DMA_FROM_DEVICE);
Matthew Wilcox's avatar
Matthew Wilcox committed
593
594
595
596
597
598
		if (!cmdinfo->data_in_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_DATA_IN_URB;
	}

	if (cmdinfo->state & SUBMIT_DATA_IN_URB) {
599
		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
600
		if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) {
601
			usb_unanchor_urb(cmdinfo->data_in_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
602
603
604
605
606
			scmd_printk(KERN_INFO, cmnd,
					"data in urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
		cmdinfo->state &= ~SUBMIT_DATA_IN_URB;
607
		cmdinfo->state |= DATA_IN_URB_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
608
609
610
611
	}

	if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
		cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
612
					devinfo->data_out_pipe, cmdinfo->stream,
613
					cmnd, DMA_TO_DEVICE);
Matthew Wilcox's avatar
Matthew Wilcox committed
614
615
616
617
618
619
		if (!cmdinfo->data_out_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
	}

	if (cmdinfo->state & SUBMIT_DATA_OUT_URB) {
620
		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
621
		if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) {
622
			usb_unanchor_urb(cmdinfo->data_out_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
623
624
625
626
627
			scmd_printk(KERN_INFO, cmnd,
					"data out urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;
628
		cmdinfo->state |= DATA_OUT_URB_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
629
630
631
	}

	if (cmdinfo->state & ALLOC_CMD_URB) {
632
		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd);
Matthew Wilcox's avatar
Matthew Wilcox committed
633
634
635
636
637
638
		if (!cmdinfo->cmd_urb)
			return SCSI_MLQUEUE_DEVICE_BUSY;
		cmdinfo->state &= ~ALLOC_CMD_URB;
	}

	if (cmdinfo->state & SUBMIT_CMD_URB) {
639
		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs);
Matthew Wilcox's avatar
Matthew Wilcox committed
640
		if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) {
641
			usb_unanchor_urb(cmdinfo->cmd_urb);
Matthew Wilcox's avatar
Matthew Wilcox committed
642
643
644
645
			scmd_printk(KERN_INFO, cmnd,
					"cmd urb submission failure\n");
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
646
		cmdinfo->cmd_urb = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
647
		cmdinfo->state &= ~SUBMIT_CMD_URB;
648
		cmdinfo->state |= COMMAND_INFLIGHT;
Matthew Wilcox's avatar
Matthew Wilcox committed
649
650
651
652
653
	}

	return 0;
}

Jeff Garzik's avatar
Jeff Garzik committed
654
static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
Matthew Wilcox's avatar
Matthew Wilcox committed
655
656
657
658
659
					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
660
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
661
662
663
664
	int err;

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

665
666
667
668
669
670
	if (devinfo->resetting) {
		cmnd->result = DID_ERROR << 16;
		cmnd->scsi_done(cmnd);
		return 0;
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
671
672
673
	spin_lock_irqsave(&devinfo->lock, flags);
	if (devinfo->cmnd) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
674
		return SCSI_MLQUEUE_DEVICE_BUSY;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
675
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
676
677

	if (blk_rq_tagged(cmnd->request)) {
678
		cmdinfo->stream = cmnd->request->tag + 2;
Matthew Wilcox's avatar
Matthew Wilcox committed
679
	} else {
680
		devinfo->cmnd = cmnd;
Matthew Wilcox's avatar
Matthew Wilcox committed
681
682
683
684
685
		cmdinfo->stream = 1;
	}

	cmnd->scsi_done = done;

Gerd Hoffmann's avatar
Gerd Hoffmann committed
686
	cmdinfo->state = SUBMIT_STATUS_URB |
Matthew Wilcox's avatar
Matthew Wilcox committed
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
			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) {
702
		cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
Matthew Wilcox's avatar
Matthew Wilcox committed
703
704
705
706
707
708
		cmdinfo->stream = 0;
	}

	err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC);
	if (err) {
		/* If we did nothing, give up now */
709
		if (cmdinfo->state & SUBMIT_STATUS_URB) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
710
			spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
711
712
			return SCSI_MLQUEUE_DEVICE_BUSY;
		}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
713
		uas_add_work(cmdinfo);
Matthew Wilcox's avatar
Matthew Wilcox committed
714
715
	}

Gerd Hoffmann's avatar
Gerd Hoffmann committed
716
	spin_unlock_irqrestore(&devinfo->lock, flags);
Matthew Wilcox's avatar
Matthew Wilcox committed
717
718
719
	return 0;
}

Jeff Garzik's avatar
Jeff Garzik committed
720
721
static DEF_SCSI_QCMD(uas_queuecommand)

722
723
static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,
			    const char *fname, u8 function)
Matthew Wilcox's avatar
Matthew Wilcox committed
724
{
725
726
	struct Scsi_Host *shost = cmnd->device->host;
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
727
	u16 tag = devinfo->qdepth;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
728
	unsigned long flags;
Matthew Wilcox's avatar
Matthew Wilcox committed
729

Gerd Hoffmann's avatar
Gerd Hoffmann committed
730
	spin_lock_irqsave(&devinfo->lock, flags);
731
	memset(&devinfo->response, 0, sizeof(devinfo->response));
Gerd Hoffmann's avatar
Gerd Hoffmann committed
732
	if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) {
733
734
735
		shost_printk(KERN_INFO, shost,
			     "%s: %s: submit sense urb failed\n",
			     __func__, fname);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
736
		spin_unlock_irqrestore(&devinfo->lock, flags);
737
738
		return FAILED;
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
739
	if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) {
740
741
742
		shost_printk(KERN_INFO, shost,
			     "%s: %s: submit task mgmt urb failed\n",
			     __func__, fname);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
743
		spin_unlock_irqrestore(&devinfo->lock, flags);
744
745
		return FAILED;
	}
Gerd Hoffmann's avatar
Gerd Hoffmann committed
746
747
748
	spin_unlock_irqrestore(&devinfo->lock, flags);

	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) {
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
		shost_printk(KERN_INFO, shost,
			     "%s: %s timed out\n", __func__, fname);
		return FAILED;
	}
	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);
		return FAILED;
	}
	if (devinfo->response.response_code != RC_TMF_COMPLETE) {
		shost_printk(KERN_INFO, shost,
			     "%s: %s failed (rc 0x%x)\n", __func__,
			     fname, devinfo->response.response_code);
		return FAILED;
	}
	return SUCCESS;
Matthew Wilcox's avatar
Matthew Wilcox committed
766
767
}

768
static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
769
{
770
	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
771
772
	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata;
	unsigned long flags;
773
	int ret;
Matthew Wilcox's avatar
Matthew Wilcox committed
774

775
	uas_log_cmd_state(cmnd, __func__);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
776
	spin_lock_irqsave(&devinfo->lock, flags);
777
	WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED);
778
	cmdinfo->state |= COMMAND_ABORTED;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
779
	list_add_tail(&cmdinfo->dead, &devinfo->dead_list);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
780
	if (cmdinfo->state & IS_IN_WORK_LIST) {
Gerd Hoffmann's avatar
Gerd Hoffmann committed
781
		list_del(&cmdinfo->work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
782
783
784
785
786
787
		cmdinfo->state &= ~IS_IN_WORK_LIST;
	}
	if (cmdinfo->state & COMMAND_INFLIGHT) {
		spin_unlock_irqrestore(&devinfo->lock, flags);
		ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);
	} else {
788
		uas_unlink_data_urbs(devinfo, cmdinfo, &flags);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
789
790
791
792
		uas_try_complete(cmnd, __func__);
		spin_unlock_irqrestore(&devinfo->lock, flags);
		ret = SUCCESS;
	}
793
	return ret;
Matthew Wilcox's avatar
Matthew Wilcox committed
794
795
}

796
static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd)
Matthew Wilcox's avatar
Matthew Wilcox committed
797
{
798
799
800
	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
801
802
803
804
805
806
807
}

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;
808
	int err;
Matthew Wilcox's avatar
Matthew Wilcox committed
809

Hans de Goede's avatar
Hans de Goede committed
810
811
812
813
814
815
816
	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
817
	shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);
818
	devinfo->resetting = 1;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
819
	uas_abort_work(devinfo);
820
	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
821
822
	usb_kill_anchored_urbs(&devinfo->sense_urbs);
	usb_kill_anchored_urbs(&devinfo->data_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
823
	uas_zap_dead(devinfo);
824
825
	err = usb_reset_device(udev);
	devinfo->resetting = 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
826

Hans de Goede's avatar
Hans de Goede committed
827
828
	usb_unlock_device(udev);

829
830
831
832
	if (err) {
		shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);
		return FAILED;
	}
Matthew Wilcox's avatar
Matthew Wilcox committed
833

834
835
	shost_printk(KERN_INFO, sdev->host, "%s success\n", __func__);
	return SUCCESS;
Matthew Wilcox's avatar
Matthew Wilcox committed
836
837
838
839
840
841
842
843
844
845
846
847
}

static int uas_slave_alloc(struct scsi_device *sdev)
{
	sdev->hostdata = (void *)sdev->host->hostdata[0];
	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);
848
	scsi_activate_tcq(sdev, devinfo->qdepth - 2);
Matthew Wilcox's avatar
Matthew Wilcox committed
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
	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,
};

static struct usb_device_id uas_usb_ids[] = {
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },
	/* 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);

878
879
880
881
882
883
884
885
886
887
888
889
890
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);
}

Matthew Wilcox's avatar
Matthew Wilcox committed
891
892
893
894
895
896
897
898
899
static void uas_configure_endpoints(struct uas_dev_info *devinfo)
{
	struct usb_host_endpoint *eps[4] = { };
	struct usb_interface *intf = devinfo->intf;
	struct usb_device *udev = devinfo->udev;
	struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint;
	unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;

	devinfo->uas_sense_old = 0;
900
	devinfo->cmnd = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932

	for (i = 0; i < n_endpoints; i++) {
		unsigned char *extra = endpoint[i].extra;
		int len = endpoint[i].extralen;
		while (len > 1) {
			if (extra[1] == USB_DT_PIPE_USAGE) {
				unsigned pipe_id = extra[2];
				if (pipe_id > 0 && pipe_id < 5)
					eps[pipe_id - 1] = &endpoint[i];
				break;
			}
			len -= extra[0];
			extra += extra[0];
		}
	}

	/*
	 * Assume that if we didn't find a control pipe descriptor, we're
	 * using a device with old firmware that happens to be set up like
	 * this.
	 */
	if (!eps[0]) {
		devinfo->cmd_pipe = usb_sndbulkpipe(udev, 1);
		devinfo->status_pipe = usb_rcvbulkpipe(udev, 1);
		devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2);
		devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2);

		eps[1] = usb_pipe_endpoint(udev, devinfo->status_pipe);
		eps[2] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
		eps[3] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
	} else {
		devinfo->cmd_pipe = usb_sndbulkpipe(udev,
933
					     usb_endpoint_num(&eps[0]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
934
		devinfo->status_pipe = usb_rcvbulkpipe(udev,
935
					     usb_endpoint_num(&eps[1]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
936
		devinfo->data_in_pipe = usb_rcvbulkpipe(udev,
937
					     usb_endpoint_num(&eps[2]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
938
		devinfo->data_out_pipe = usb_sndbulkpipe(udev,
939
					     usb_endpoint_num(&eps[3]->desc));
Matthew Wilcox's avatar
Matthew Wilcox committed
940
941
942
943
944
945
946
947
948
949
950
951
	}

	devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 3, 256,
								GFP_KERNEL);
	if (devinfo->qdepth < 0) {
		devinfo->qdepth = 256;
		devinfo->use_streams = 0;
	} else {
		devinfo->use_streams = 1;
	}
}

952
953
954
955
956
957
958
959
960
961
962
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
963
964
965
966
967
968
969
970
/*
 * 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)
{
971
972
	int result = -ENOMEM;
	struct Scsi_Host *shost = NULL;
Matthew Wilcox's avatar
Matthew Wilcox committed
973
974
975
	struct uas_dev_info *devinfo;
	struct usb_device *udev = interface_to_usbdev(intf);

976
977
	if (uas_switch_interface(udev, intf))
		return -ENODEV;
Matthew Wilcox's avatar
Matthew Wilcox committed
978
979
980

	devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL);
	if (!devinfo)
981
		goto set_alt0;
Matthew Wilcox's avatar
Matthew Wilcox committed
982
983
984

	shost = scsi_host_alloc(&uas_host_template, sizeof(void *));
	if (!shost)
985
		goto set_alt0;
Matthew Wilcox's avatar
Matthew Wilcox committed
986
987
988

	shost->max_cmd_len = 16 + 252;
	shost->max_id = 1;
989
990
	shost->max_lun = 256;
	shost->max_channel = 0;
Matthew Wilcox's avatar
Matthew Wilcox committed
991
992
993
994
	shost->sg_tablesize = udev->bus->sg_tablesize;

	devinfo->intf = intf;
	devinfo->udev = udev;
995
	devinfo->resetting = 0;
996
	init_usb_anchor(&devinfo->cmd_urbs);
997
998
	init_usb_anchor(&devinfo->sense_urbs);
	init_usb_anchor(&devinfo->data_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
999
	spin_lock_init(&devinfo->lock);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1000
1001
	INIT_WORK(&devinfo->work, uas_do_work);
	INIT_LIST_HEAD(&devinfo->work_list);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1002
	INIT_LIST_HEAD(&devinfo->dead_list);
Matthew Wilcox's avatar
Matthew Wilcox committed
1003
1004
	uas_configure_endpoints(devinfo);

1005
	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
Matthew Wilcox's avatar
Matthew Wilcox committed
1006
	if (result)
1007
		goto free_streams;
1008
1009
1010

	result = scsi_add_host(shost, &intf->dev);
	if (result)
1011
		goto free_streams;
1012

Matthew Wilcox's avatar
Matthew Wilcox committed
1013
1014
1015
1016
1017
	shost->hostdata[0] = (unsigned long)devinfo;

	scsi_scan_host(shost);
	usb_set_intfdata(intf, shost);
	return result;
1018

1019
free_streams:
1020
	uas_free_streams(devinfo);
1021
1022
set_alt0:
	usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
Matthew Wilcox's avatar
Matthew Wilcox committed
1023
1024
1025
1026
1027
1028
1029
1030
	kfree(devinfo);
	if (shost)
		scsi_host_put(shost);
	return result;
}

static int uas_pre_reset(struct usb_interface *intf)
{
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
	struct Scsi_Host *shost = usb_get_intfdata(intf);
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
	unsigned long flags;

	/* Block new requests */
	spin_lock_irqsave(shost->host_lock, flags);
	scsi_block_requests(shost);
	spin_unlock_irqrestore(shost->host_lock, flags);

	/* Wait for any pending requests to complete */
	flush_work(&devinfo->work);
	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000) == 0) {
		shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__);
		return 1;
	}

	uas_free_streams(devinfo);

Matthew Wilcox's avatar
Matthew Wilcox committed
1049
1050
1051
1052
1053
	return 0;
}

static int uas_post_reset(struct usb_interface *intf)
{
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
	struct Scsi_Host *shost = usb_get_intfdata(intf);
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
	unsigned long flags;

	uas_configure_endpoints(devinfo);

	spin_lock_irqsave(shost->host_lock, flags);
	scsi_report_bus_reset(shost, 0);
	spin_unlock_irqrestore(shost->host_lock, flags);

	scsi_unblock_requests(shost);

Matthew Wilcox's avatar
Matthew Wilcox committed
1066
1067
1068
1069
1070
1071
1072
1073
	return 0;
}

static void uas_disconnect(struct usb_interface *intf)
{
	struct Scsi_Host *shost = usb_get_intfdata(intf);
	struct uas_dev_info *devinfo = (void *)shost->hostdata[0];

Gerd Hoffmann's avatar
Gerd Hoffmann committed
1074
	devinfo->resetting = 1;
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1075
	cancel_work_sync(&devinfo->work);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1076
	uas_abort_work(devinfo);
1077
	usb_kill_anchored_urbs(&devinfo->cmd_urbs);
1078
1079
	usb_kill_anchored_urbs(&devinfo->sense_urbs);
	usb_kill_anchored_urbs(&devinfo->data_urbs);
Gerd Hoffmann's avatar
Gerd Hoffmann committed
1080
	uas_zap_dead(devinfo);
Gerd Hoffmann's avatar