Annotation of sys/dev/usb/umass_scsi.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: umass_scsi.c,v 1.18 2007/06/13 10:33:52 mbalmer Exp $ */
2: /* $NetBSD: umass_scsipi.c,v 1.9 2003/02/16 23:14:08 augustss Exp $ */
3: /*
4: * Copyright (c) 2001 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Lennart Augustsson (lennart@augustsson.net) at
9: * Carlstedt Research & Technology.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include "atapiscsi.h"
41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/kernel.h>
45: #include <sys/conf.h>
46: #include <sys/buf.h>
47: #include <sys/device.h>
48: #include <sys/ioctl.h>
49: #include <sys/malloc.h>
50:
51: #include <dev/usb/usb.h>
52: #include <dev/usb/usbdi.h>
53: #include <dev/usb/usbdi_util.h>
54: #include <dev/usb/usbdevs.h>
55:
56: #include <dev/usb/umassvar.h>
57: #include <dev/usb/umass_scsi.h>
58:
59: #include <scsi/scsi_all.h>
60: #include <scsi/scsiconf.h>
61: #include <scsi/scsi_disk.h>
62: #include <machine/bus.h>
63:
64: struct umass_scsi_softc {
65: struct umassbus_softc base;
66: struct scsi_link sc_link;
67: struct scsi_adapter sc_adapter;
68:
69: struct scsi_sense sc_sense_cmd;
70: };
71:
72:
73: #define UMASS_SCSIID_HOST 0x00
74: #define UMASS_SCSIID_DEVICE 0x01
75:
76: #define UMASS_ATAPI_DRIVE 0
77:
78: int umass_scsi_cmd(struct scsi_xfer *);
79: void umass_scsi_minphys(struct buf *);
80:
81: void umass_scsi_cb(struct umass_softc *sc, void *priv, int residue,
82: int status);
83: void umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue,
84: int status);
85: struct umass_scsi_softc *umass_scsi_setup(struct umass_softc *);
86:
87: struct scsi_device umass_scsi_dev = { NULL, NULL, NULL, NULL, };
88:
89: #if NATAPISCSI > 0
90: struct scsi_device umass_atapiscsi_dev = { NULL, NULL, NULL, NULL, };
91: #endif
92:
93: int
94: umass_scsi_attach(struct umass_softc *sc)
95: {
96: struct scsibus_attach_args saa;
97: struct umass_scsi_softc *scbus;
98:
99: scbus = umass_scsi_setup(sc);
100: scbus->sc_link.adapter_target = UMASS_SCSIID_HOST;
101: scbus->sc_link.luns = sc->maxlun + 1;
102: scbus->sc_link.flags &= ~SDEV_ATAPI;
103: scbus->sc_link.flags |= SDEV_UMASS;
104: scbus->sc_link.device = &umass_scsi_dev;
105:
106: bzero(&saa, sizeof(saa));
107: saa.saa_sc_link = &scbus->sc_link;
108:
109: DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: SCSI\n"
110: "sc = 0x%x, scbus = 0x%x\n",
111: sc->sc_dev.dv_xname, sc, scbus));
112:
113: sc->sc_refcnt++;
114: scbus->base.sc_child =
115: config_found((struct device *)sc, &saa, scsiprint);
116: if (--sc->sc_refcnt < 0)
117: usb_detach_wakeup(&sc->sc_dev);
118:
119: return (0);
120: }
121:
122: #if NATAPISCSI > 0
123: int
124: umass_atapi_attach(struct umass_softc *sc)
125: {
126: struct scsibus_attach_args saa;
127: struct umass_scsi_softc *scbus;
128:
129: scbus = umass_scsi_setup(sc);
130: scbus->sc_link.adapter_target = UMASS_SCSIID_HOST;
131: scbus->sc_link.luns = 1;
132: scbus->sc_link.openings = 1;
133: scbus->sc_link.flags |= SDEV_ATAPI;
134: scbus->sc_link.device = &umass_atapiscsi_dev;
135:
136: bzero(&saa, sizeof(saa));
137: saa.saa_sc_link = &scbus->sc_link;
138:
139: DPRINTF(UDMASS_USB, ("%s: umass_attach_bus: ATAPI\n"
140: "sc = 0x%x, scbus = 0x%x\n",
141: sc->sc_dev.dv_xname, sc, scbus));
142:
143: sc->sc_refcnt++;
144: scbus->base.sc_child = config_found((struct device *)sc,
145: &saa, scsiprint);
146: if (--sc->sc_refcnt < 0)
147: usb_detach_wakeup(&sc->sc_dev);
148:
149: return (0);
150: }
151: #endif
152:
153: struct umass_scsi_softc *
154: umass_scsi_setup(struct umass_softc *sc)
155: {
156: struct umass_scsi_softc *scbus;
157:
158: scbus = malloc(sizeof(struct umass_scsi_softc), M_DEVBUF, M_WAITOK);
159: memset(&scbus->sc_link, 0, sizeof(struct scsi_link));
160: memset(&scbus->sc_adapter, 0, sizeof(struct scsi_adapter));
161:
162: sc->bus = (struct umassbus_softc *)scbus;
163:
164: /* Fill in the adapter. */
165: scbus->sc_adapter.scsi_cmd = umass_scsi_cmd;
166: scbus->sc_adapter.scsi_minphys = umass_scsi_minphys;
167:
168: /* Fill in the link. */
169: scbus->sc_link.adapter_buswidth = 2;
170: scbus->sc_link.adapter = &scbus->sc_adapter;
171: scbus->sc_link.adapter_softc = sc;
172: scbus->sc_link.openings = 1;
173: scbus->sc_link.quirks |= SDEV_ONLYBIG | sc->sc_busquirks;
174:
175: return (scbus);
176: }
177:
178: int
179: umass_scsi_cmd(struct scsi_xfer *xs)
180: {
181: struct scsi_link *sc_link = xs->sc_link;
182: struct umass_softc *sc = sc_link->adapter_softc;
183:
184: struct scsi_generic *cmd;
185: int cmdlen, dir, s;
186:
187: #ifdef UMASS_DEBUG
188: microtime(&sc->tv);
189: #endif
190:
191: DIF(UDMASS_UPPER, sc_link->flags |= SCSIDEBUG_LEVEL);
192:
193: DPRINTF(UDMASS_CMD, ("%s: umass_scsi_cmd: at %lu.%06lu: %d:%d "
194: "xs=%p cmd=0x%02x datalen=%d (quirks=0x%x, poll=%d)\n",
195: sc->sc_dev.dv_xname, sc->tv.tv_sec, sc->tv.tv_usec,
196: sc_link->target, sc_link->lun, xs, xs->cmd->opcode,
197: xs->datalen, sc_link->quirks, xs->flags & SCSI_POLL));
198:
199: #if defined(USB_DEBUG) && defined(SCSIDEBUG)
200: if (umassdebug & UDMASS_SCSI)
201: show_scsi_xs(xs);
202: else if (umassdebug & ~UDMASS_CMD)
203: show_scsi_cmd(xs);
204: #endif
205:
206: if (sc->sc_dying) {
207: xs->error = XS_DRIVER_STUFFUP;
208: goto done;
209: }
210:
211: #if defined(UMASS_DEBUG)
212: if (sc_link->target != UMASS_SCSIID_DEVICE) {
213: DPRINTF(UDMASS_SCSI, ("%s: wrong SCSI ID %d\n",
214: sc->sc_dev.dv_xname, sc_link->target));
215: xs->error = XS_DRIVER_STUFFUP;
216: goto done;
217: }
218: #endif
219:
220: cmd = xs->cmd;
221: cmdlen = xs->cmdlen;
222:
223: dir = DIR_NONE;
224: if (xs->datalen) {
225: switch (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
226: case SCSI_DATA_IN:
227: dir = DIR_IN;
228: break;
229: case SCSI_DATA_OUT:
230: dir = DIR_OUT;
231: break;
232: }
233: }
234:
235: if (xs->datalen > UMASS_MAX_TRANSFER_SIZE) {
236: printf("umass_cmd: large datalen, %d\n", xs->datalen);
237: xs->error = XS_DRIVER_STUFFUP;
238: goto done;
239: }
240:
241: if (xs->flags & SCSI_POLL) {
242: DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: sync dir=%d\n", dir));
243: usbd_set_polling(sc->sc_udev, 1);
244: sc->sc_xfer_flags = USBD_SYNCHRONOUS;
245: sc->polled_xfer_status = USBD_INVAL;
246: sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen,
247: xs->data, xs->datalen, dir,
248: xs->timeout, umass_scsi_cb, xs);
249: sc->sc_xfer_flags = 0;
250: DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done err=%d\n",
251: sc->polled_xfer_status));
252: if (xs->error == XS_NOERROR) {
253: switch (sc->polled_xfer_status) {
254: case USBD_NORMAL_COMPLETION:
255: xs->error = XS_NOERROR;
256: break;
257: case USBD_TIMEOUT:
258: xs->error = XS_TIMEOUT;
259: break;
260: default:
261: xs->error = XS_DRIVER_STUFFUP;
262: break;
263: }
264: }
265: usbd_set_polling(sc->sc_udev, 0);
266: DPRINTF(UDMASS_SCSI, ("umass_scsi_cmd: done, error=%d\n",
267: xs->error));
268: } else {
269: DPRINTF(UDMASS_SCSI,
270: ("umass_scsi_cmd: async dir=%d, cmdlen=%d"
271: " datalen=%d\n",
272: dir, cmdlen, xs->datalen));
273: sc->sc_methods->wire_xfer(sc, sc_link->lun, cmd, cmdlen,
274: xs->data, xs->datalen, dir,
275: xs->timeout, umass_scsi_cb, xs);
276: return (SUCCESSFULLY_QUEUED);
277: }
278:
279: /* Return if command finishes early. */
280: done:
281: xs->flags |= ITSDONE;
282:
283: s = splbio();
284: scsi_done(xs);
285: splx(s);
286: if (xs->flags & SCSI_POLL)
287: return (COMPLETE);
288: else
289: return (SUCCESSFULLY_QUEUED);
290: }
291:
292: void
293: umass_scsi_minphys(struct buf *bp)
294: {
295: if (bp->b_bcount > UMASS_MAX_TRANSFER_SIZE)
296: bp->b_bcount = UMASS_MAX_TRANSFER_SIZE;
297:
298: minphys(bp);
299: }
300:
301: void
302: umass_scsi_cb(struct umass_softc *sc, void *priv, int residue, int status)
303: {
304: struct umass_scsi_softc *scbus = (struct umass_scsi_softc *)sc->bus;
305: struct scsi_xfer *xs = priv;
306: struct scsi_link *link = xs->sc_link;
307: int cmdlen;
308: int s;
309: #ifdef UMASS_DEBUG
310: struct timeval tv;
311: u_int delta;
312: microtime(&tv);
313: delta = (tv.tv_sec - sc->tv.tv_sec) * 1000000 +
314: tv.tv_usec - sc->tv.tv_usec;
315: #endif
316:
317: DPRINTF(UDMASS_CMD,
318: ("umass_scsi_cb: at %lu.%06lu, delta=%u: xs=%p residue=%d"
319: " status=%d\n", tv.tv_sec, tv.tv_usec, delta, xs, residue,
320: status));
321:
322: xs->resid = residue;
323:
324: switch (status) {
325: case STATUS_CMD_OK:
326: xs->error = XS_NOERROR;
327: break;
328:
329: case STATUS_CMD_UNKNOWN:
330: DPRINTF(UDMASS_CMD, ("umass_scsi_cb: status cmd unknown\n"));
331: /* we can't issue REQUEST SENSE */
332: if (xs->sc_link->quirks & ADEV_NOSENSE) {
333: /*
334: * If no residue and no other USB error,
335: * command succeeded.
336: */
337: if (residue == 0) {
338: xs->error = XS_NOERROR;
339: break;
340: }
341:
342: /*
343: * Some devices return a short INQUIRY
344: * response, omitting response data from the
345: * "vendor specific data" on...
346: */
347: if (xs->cmd->opcode == INQUIRY &&
348: residue < xs->datalen) {
349: xs->error = XS_NOERROR;
350: break;
351: }
352:
353: xs->error = XS_DRIVER_STUFFUP;
354: break;
355: }
356: /* FALLTHROUGH */
357: case STATUS_CMD_FAILED:
358: DPRINTF(UDMASS_CMD, ("umass_scsi_cb: status cmd failed for "
359: "scsi op 0x%02x\n", xs->cmd->opcode));
360: /* fetch sense data */
361: sc->sc_sense = 1;
362: memset(&scbus->sc_sense_cmd, 0, sizeof(scbus->sc_sense_cmd));
363: scbus->sc_sense_cmd.opcode = REQUEST_SENSE;
364: scbus->sc_sense_cmd.byte2 = link->lun << SCSI_CMD_LUN_SHIFT;
365: scbus->sc_sense_cmd.length = sizeof(xs->sense);
366:
367: cmdlen = sizeof(scbus->sc_sense_cmd);
368: sc->sc_methods->wire_xfer(sc, link->lun,
369: &scbus->sc_sense_cmd, cmdlen,
370: &xs->sense, sizeof(xs->sense),
371: DIR_IN, xs->timeout,
372: umass_scsi_sense_cb, xs);
373: return;
374:
375: case STATUS_WIRE_FAILED:
376: xs->error = XS_RESET;
377: break;
378:
379: default:
380: panic("%s: Unknown status %d in umass_scsi_cb",
381: sc->sc_dev.dv_xname, status);
382: }
383:
384: if (xs->flags & SCSI_POLL)
385: return;
386:
387: xs->flags |= ITSDONE;
388:
389: DPRINTF(UDMASS_CMD,("umass_scsi_cb: at %lu.%06lu: return error=%d, "
390: "status=0x%x resid=%d\n",
391: tv.tv_sec, tv.tv_usec,
392: xs->error, xs->status, xs->resid));
393:
394: s = splbio();
395: scsi_done(xs);
396: splx(s);
397: }
398:
399: /*
400: * Finalise a completed autosense operation
401: */
402: void
403: umass_scsi_sense_cb(struct umass_softc *sc, void *priv, int residue,
404: int status)
405: {
406: struct scsi_xfer *xs = priv;
407: int s;
408:
409: DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: xs=%p residue=%d "
410: "status=%d\n", xs, residue, status));
411:
412: sc->sc_sense = 0;
413: switch (status) {
414: case STATUS_CMD_OK:
415: case STATUS_CMD_UNKNOWN:
416: /* getting sense data succeeded */
417: if (residue == 0 || residue == 14)/* XXX */
418: xs->error = XS_SENSE;
419: else
420: xs->error = XS_SHORTSENSE;
421: break;
422: default:
423: DPRINTF(UDMASS_SCSI, ("%s: Autosense failed, status %d\n",
424: sc->sc_dev.dv_xname, status));
425: xs->error = XS_DRIVER_STUFFUP;
426: break;
427: }
428:
429: xs->flags |= ITSDONE;
430:
431: DPRINTF(UDMASS_CMD,("umass_scsi_sense_cb: return xs->error=%d, "
432: "xs->flags=0x%x xs->resid=%d\n", xs->error, xs->status,
433: xs->resid));
434:
435: s = splbio();
436: scsi_done(xs);
437: splx(s);
438: }
439:
CVSweb