Annotation of sys/scsi/ch.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ch.c,v 1.32 2006/11/28 16:56:50 dlg Exp $ */
2: /* $NetBSD: ch.c,v 1.26 1997/02/21 22:06:52 thorpej Exp $ */
3:
4: /*
5: * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com>
6: * All rights reserved.
7: *
8: * Partially based on an autochanger driver written by Stefan Grefen
9: * and on an autochanger driver written by the Systems Programming Group
10: * at the University of Utah Computer Science Department.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgements:
22: * This product includes software developed by Jason R. Thorpe
23: * for And Communications, http://www.and.com/
24: * 4. The name of the author may not be used to endorse or promote products
25: * derived from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
34: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37: * SUCH DAMAGE.
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/errno.h>
43: #include <sys/ioctl.h>
44: #include <sys/buf.h>
45: #include <sys/proc.h>
46: #include <sys/user.h>
47: #include <sys/chio.h>
48: #include <sys/device.h>
49: #include <sys/malloc.h>
50: #include <sys/conf.h>
51: #include <sys/fcntl.h>
52:
53: #include <scsi/scsi_all.h>
54: #include <scsi/scsi_changer.h>
55: #include <scsi/scsiconf.h>
56:
57: #define CHRETRIES 2
58: #define CHUNIT(x) (minor((x)))
59:
60: struct ch_softc {
61: struct device sc_dev; /* generic device info */
62: struct scsi_link *sc_link; /* link in the SCSI bus */
63:
64: int sc_picker; /* current picker */
65:
66: /*
67: * The following information is obtained from the
68: * element address assignment page.
69: */
70: int sc_firsts[4]; /* firsts, indexed by CHET_* */
71: int sc_counts[4]; /* counts, indexed by CHET_* */
72:
73: /*
74: * The following mask defines the legal combinations
75: * of elements for the MOVE MEDIUM command.
76: */
77: u_int8_t sc_movemask[4];
78:
79: /*
80: * As above, but for EXCHANGE MEDIUM.
81: */
82: u_int8_t sc_exchangemask[4];
83:
84: int flags; /* misc. info */
85:
86: /*
87: * Quirks; see below.
88: */
89: int sc_settledelay; /* delay for settle */
90:
91: };
92:
93: /* sc_flags */
94: #define CHF_ROTATE 0x01 /* picker can rotate */
95:
96: /* Autoconfiguration glue */
97: int chmatch(struct device *, void *, void *);
98: void chattach(struct device *, struct device *, void *);
99:
100: struct cfattach ch_ca = {
101: sizeof(struct ch_softc), chmatch, chattach
102: };
103:
104: struct cfdriver ch_cd = {
105: NULL, "ch", DV_DULL
106: };
107:
108: const struct scsi_inquiry_pattern ch_patterns[] = {
109: {T_CHANGER, T_REMOV,
110: "", "", ""},
111: };
112:
113: int ch_move(struct ch_softc *, struct changer_move *);
114: int ch_exchange(struct ch_softc *, struct changer_exchange *);
115: int ch_position(struct ch_softc *, struct changer_position *);
116: int ch_usergetelemstatus(struct ch_softc *,
117: struct changer_element_status_request *);
118: int ch_getelemstatus(struct ch_softc *, int, int, caddr_t, size_t, int);
119: int ch_get_params(struct ch_softc *, int);
120: int ch_interpret_sense(struct scsi_xfer *xs);
121: void ch_get_quirks(struct ch_softc *, struct scsi_inquiry_data *);
122:
123: /* SCSI glue */
124: struct scsi_device ch_switch = {
125: ch_interpret_sense,
126: NULL,
127: NULL,
128: NULL
129: };
130:
131: /*
132: * SCSI changer quirks.
133: */
134: struct chquirk {
135: struct scsi_inquiry_pattern cq_match; /* device id pattern */
136: int cq_settledelay; /* settle delay, in seconds */
137: };
138:
139: struct chquirk chquirks[] = {
140: {{T_CHANGER, T_REMOV,
141: "SPECTRA", "9000", "0200"},
142: 75},
143: };
144:
145: int
146: chmatch(parent, match, aux)
147: struct device *parent;
148: void *match, *aux;
149: {
150: struct scsi_attach_args *sa = aux;
151: int priority;
152:
153: (void)scsi_inqmatch(sa->sa_inqbuf,
154: ch_patterns, sizeof(ch_patterns)/sizeof(ch_patterns[0]),
155: sizeof(ch_patterns[0]), &priority);
156:
157: return (priority);
158: }
159:
160: void
161: chattach(parent, self, aux)
162: struct device *parent, *self;
163: void *aux;
164: {
165: struct ch_softc *sc = (struct ch_softc *)self;
166: struct scsi_attach_args *sa = aux;
167: struct scsi_link *link = sa->sa_sc_link;
168:
169: /* Glue into the SCSI bus */
170: sc->sc_link = link;
171: link->device = &ch_switch;
172: link->device_softc = sc;
173: link->openings = 1;
174:
175: printf("\n");
176:
177: /*
178: * Store our our device's quirks.
179: */
180: ch_get_quirks(sc, sa->sa_inqbuf);
181:
182: }
183:
184: int
185: chopen(dev, flags, fmt, p)
186: dev_t dev;
187: int flags, fmt;
188: struct proc *p;
189: {
190: struct ch_softc *sc;
191: int oldcounts[4];
192: int i, unit, error = 0;
193:
194: unit = CHUNIT(dev);
195: if ((unit >= ch_cd.cd_ndevs) ||
196: ((sc = ch_cd.cd_devs[unit]) == NULL))
197: return (ENXIO);
198:
199: /*
200: * Only allow one open at a time.
201: */
202: if (sc->sc_link->flags & SDEV_OPEN)
203: return (EBUSY);
204:
205: sc->sc_link->flags |= SDEV_OPEN;
206:
207: /*
208: * Absorb any unit attention errors. We must notice
209: * "Not ready" errors as a changer will report "In the
210: * process of getting ready" any time it must rescan
211: * itself to determine the state of the changer.
212: */
213: error = scsi_test_unit_ready(sc->sc_link, TEST_READY_RETRIES,
214: SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
215: if (error)
216: goto bad;
217:
218: /*
219: * Get information about the device. Save old information
220: * so we can decide whether to be verbose about new parameters.
221: */
222: for (i = 0; i < 4; i++) {
223: oldcounts[i] = sc->sc_counts[i];
224: }
225: error = ch_get_params(sc, scsi_autoconf);
226: if (error)
227: goto bad;
228:
229: for (i = 0; i < 4; i++) {
230: if (oldcounts[i] != sc->sc_counts[i]) {
231: break;
232: }
233: }
234: if (i < 4) {
235: #ifdef CHANGER_DEBUG
236: #define PLURAL(c) (c) == 1 ? "" : "s"
237: printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n",
238: sc->sc_dev.dv_xname,
239: sc->sc_counts[CHET_ST], PLURAL(sc->sc_counts[CHET_ST]),
240: sc->sc_counts[CHET_DT], PLURAL(sc->sc_counts[CHET_DT]),
241: sc->sc_counts[CHET_MT], PLURAL(sc->sc_counts[CHET_MT]),
242: sc->sc_counts[CHET_IE], PLURAL(sc->sc_counts[CHET_IE]));
243: #undef PLURAL
244: printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
245: sc->sc_dev.dv_xname,
246: sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST],
247: sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]);
248: printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
249: sc->sc_dev.dv_xname,
250: sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST],
251: sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]);
252: #endif /* CHANGER_DEBUG */
253: }
254:
255: /* Default the current picker. */
256: sc->sc_picker = sc->sc_firsts[CHET_MT];
257:
258: return (0);
259:
260: bad:
261: sc->sc_link->flags &= ~SDEV_OPEN;
262: return (error);
263: }
264:
265: int
266: chclose(dev, flags, fmt, p)
267: dev_t dev;
268: int flags, fmt;
269: struct proc *p;
270: {
271: struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
272:
273: sc->sc_link->flags &= ~SDEV_OPEN;
274: return (0);
275: }
276:
277: int
278: chioctl(dev, cmd, data, flags, p)
279: dev_t dev;
280: u_long cmd;
281: caddr_t data;
282: int flags;
283: struct proc *p;
284: {
285: struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
286: int error = 0;
287:
288: /*
289: * If this command can change the device's state, we must
290: * have the device open for writing.
291: */
292: switch (cmd) {
293: case CHIOGPICKER:
294: case CHIOGPARAMS:
295: case CHIOGSTATUS:
296: break;
297:
298: default:
299: if ((flags & FWRITE) == 0)
300: return (EBADF);
301: }
302:
303: switch (cmd) {
304: case CHIOMOVE:
305: error = ch_move(sc, (struct changer_move *)data);
306: break;
307:
308: case CHIOEXCHANGE:
309: error = ch_exchange(sc, (struct changer_exchange *)data);
310: break;
311:
312: case CHIOPOSITION:
313: error = ch_position(sc, (struct changer_position *)data);
314: break;
315:
316: case CHIOGPICKER:
317: *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT];
318: break;
319:
320: case CHIOSPICKER: {
321: int new_picker = *(int *)data;
322:
323: if (new_picker > (sc->sc_counts[CHET_MT] - 1))
324: return (EINVAL);
325: sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker;
326: break; }
327:
328: case CHIOGPARAMS: {
329: struct changer_params *cp = (struct changer_params *)data;
330:
331: cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT];
332: cp->cp_npickers = sc->sc_counts[CHET_MT];
333: cp->cp_nslots = sc->sc_counts[CHET_ST];
334: cp->cp_nportals = sc->sc_counts[CHET_IE];
335: cp->cp_ndrives = sc->sc_counts[CHET_DT];
336: break; }
337:
338: case CHIOGSTATUS: {
339: struct changer_element_status_request *cesr =
340: (struct changer_element_status_request *)data;
341:
342: error = ch_usergetelemstatus(sc, cesr);
343: break; }
344:
345: /* Implement prevent/allow? */
346:
347: default:
348: error = scsi_do_ioctl(sc->sc_link, dev, cmd, data,
349: flags, p);
350: break;
351: }
352:
353: return (error);
354: }
355:
356: int
357: ch_move(sc, cm)
358: struct ch_softc *sc;
359: struct changer_move *cm;
360: {
361: struct scsi_move_medium cmd;
362: u_int16_t fromelem, toelem;
363:
364: /*
365: * Check arguments.
366: */
367: if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
368: return (EINVAL);
369: if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
370: (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
371: return (ENODEV);
372:
373: /*
374: * Check the request against the changer's capabilities.
375: */
376: if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
377: return (EINVAL);
378:
379: /*
380: * Calculate the source and destination elements.
381: */
382: fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
383: toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
384:
385: /*
386: * Build the SCSI command.
387: */
388: bzero(&cmd, sizeof(cmd));
389: cmd.opcode = MOVE_MEDIUM;
390: _lto2b(sc->sc_picker, cmd.tea);
391: _lto2b(fromelem, cmd.src);
392: _lto2b(toelem, cmd.dst);
393: if (cm->cm_flags & CM_INVERT)
394: cmd.flags |= MOVE_MEDIUM_INVERT;
395:
396: /*
397: * Send command to changer.
398: */
399: return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
400: sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
401: }
402:
403: int
404: ch_exchange(sc, ce)
405: struct ch_softc *sc;
406: struct changer_exchange *ce;
407: {
408: struct scsi_exchange_medium cmd;
409: u_int16_t src, dst1, dst2;
410:
411: /*
412: * Check arguments.
413: */
414: if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
415: (ce->ce_sdsttype > CHET_DT))
416: return (EINVAL);
417: if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
418: (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
419: (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
420: return (ENODEV);
421:
422: /*
423: * Check the request against the changer's capabilities.
424: */
425: if (((sc->sc_exchangemask[ce->ce_srctype] &
426: (1 << ce->ce_fdsttype)) == 0) ||
427: ((sc->sc_exchangemask[ce->ce_fdsttype] &
428: (1 << ce->ce_sdsttype)) == 0))
429: return (EINVAL);
430:
431: /*
432: * Calculate the source and destination elements.
433: */
434: src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
435: dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
436: dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
437:
438: /*
439: * Build the SCSI command.
440: */
441: bzero(&cmd, sizeof(cmd));
442: cmd.opcode = EXCHANGE_MEDIUM;
443: _lto2b(sc->sc_picker, cmd.tea);
444: _lto2b(src, cmd.src);
445: _lto2b(dst1, cmd.fdst);
446: _lto2b(dst2, cmd.sdst);
447: if (ce->ce_flags & CE_INVERT1)
448: cmd.flags |= EXCHANGE_MEDIUM_INV1;
449: if (ce->ce_flags & CE_INVERT2)
450: cmd.flags |= EXCHANGE_MEDIUM_INV2;
451:
452: /*
453: * Send command to changer.
454: */
455: return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
456: sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
457: }
458:
459: int
460: ch_position(sc, cp)
461: struct ch_softc *sc;
462: struct changer_position *cp;
463: {
464: struct scsi_position_to_element cmd;
465: u_int16_t dst;
466:
467: /*
468: * Check arguments.
469: */
470: if (cp->cp_type > CHET_DT)
471: return (EINVAL);
472: if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
473: return (ENODEV);
474:
475: /*
476: * Calculate the destination element.
477: */
478: dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;
479:
480: /*
481: * Build the SCSI command.
482: */
483: bzero(&cmd, sizeof(cmd));
484: cmd.opcode = POSITION_TO_ELEMENT;
485: _lto2b(sc->sc_picker, cmd.tea);
486: _lto2b(dst, cmd.dst);
487: if (cp->cp_flags & CP_INVERT)
488: cmd.flags |= POSITION_TO_ELEMENT_INVERT;
489:
490: /*
491: * Send command to changer.
492: */
493: return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
494: sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
495: }
496:
497: /*
498: * Copy a volume tag to a volume_tag struct, converting SCSI byte order
499: * to host native byte order in the volume serial number. The volume
500: * label as returned by the changer is transferred to user mode as
501: * nul-terminated string. Volume labels are truncated at the first
502: * space, as suggested by SCSI-2.
503: */
504: static void
505: copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
506: {
507: int i;
508:
509: for (i=0; i<CH_VOLTAG_MAXLEN; i++) {
510: char c = voltag->vif[i];
511: if (c && c != ' ')
512: uvoltag->cv_volid[i] = c;
513: else
514: break;
515: }
516: uvoltag->cv_volid[i] = '\0';
517: uvoltag->cv_serial = _2btol(voltag->vsn);
518: }
519:
520: /*
521: * Copy an an element status descriptor to a user-mode
522: * changer_element_status structure.
523: */
524: static void
525: copy_element_status(int flags, struct read_element_status_descriptor *desc,
526: struct changer_element_status *ces)
527: {
528: ces->ces_flags = desc->flags1;
529:
530: if (flags & READ_ELEMENT_STATUS_PVOLTAG)
531: copy_voltag(&ces->ces_pvoltag, &desc->pvoltag);
532: if (flags & READ_ELEMENT_STATUS_AVOLTAG)
533: copy_voltag(&ces->ces_avoltag, &desc->avoltag);
534: }
535:
536: /*
537: * Perform a READ ELEMENT STATUS on behalf of the user, and return to
538: * the user only the data the user is interested in (i.e. an array of
539: * changer_element_status structures)
540: */
541: int
542: ch_usergetelemstatus(sc, cesr)
543: struct ch_softc *sc;
544: struct changer_element_status_request *cesr;
545: {
546: struct changer_element_status *user_data = NULL;
547: struct read_element_status_header *st_hdr;
548: struct read_element_status_page_header *pg_hdr;
549: struct read_element_status_descriptor *desc;
550: caddr_t data = NULL;
551: size_t size, desclen, udsize;
552: int chet = cesr->cesr_type;
553: int avail, i, error = 0;
554: int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0;
555:
556: /*
557: * If there are no elements of the requested type in the changer,
558: * the request is invalid.
559: */
560: if (sc->sc_counts[chet] == 0)
561: return (EINVAL);
562:
563: /*
564: * Request one descriptor for the given element type. This
565: * is used to determine the size of the descriptor so that
566: * we can allocate enough storage for all of them. We assume
567: * that the first one can fit into 1k.
568: */
569: data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
570: error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024,
571: want_voltags);
572: if (error)
573: goto done;
574:
575: st_hdr = (struct read_element_status_header *)data;
576: pg_hdr = (struct read_element_status_page_header *)((u_long)st_hdr +
577: sizeof(struct read_element_status_header));
578: desclen = _2btol(pg_hdr->edl);
579:
580: size = sizeof(struct read_element_status_header) +
581: sizeof(struct read_element_status_page_header) +
582: (desclen * sc->sc_counts[chet]);
583:
584: /*
585: * Reallocate storage for descriptors and get them from the
586: * device.
587: */
588: free(data, M_DEVBUF);
589: data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
590: error = ch_getelemstatus(sc, sc->sc_firsts[chet],
591: sc->sc_counts[chet], data, size, want_voltags);
592: if (error)
593: goto done;
594:
595: /*
596: * Fill in the user status array.
597: */
598: st_hdr = (struct read_element_status_header *)data;
599: pg_hdr = (struct read_element_status_page_header *)((u_long)data +
600: sizeof(struct read_element_status_header));
601:
602: avail = _2btol(st_hdr->count);
603: if (avail != sc->sc_counts[chet]) {
604: error = EINVAL;
605: goto done;
606: }
607: udsize = avail * sizeof(struct changer_element_status);
608:
609: user_data = malloc(udsize, M_DEVBUF, M_WAITOK);
610: bzero(user_data, udsize);
611:
612: desc = (struct read_element_status_descriptor *)((u_long)data +
613: sizeof(struct read_element_status_header) +
614: sizeof(struct read_element_status_page_header));
615: for (i = 0; i < avail; ++i) {
616: struct changer_element_status *ces = &(user_data[i]);
617: copy_element_status(pg_hdr->flags, desc, ces);
618: (u_long)desc += desclen;
619: }
620:
621: /* Copy array out to userspace. */
622: error = copyout(user_data, cesr->cesr_data, udsize);
623:
624: done:
625: if (data != NULL)
626: free(data, M_DEVBUF);
627: if (user_data != NULL)
628: free(user_data, M_DEVBUF);
629: return (error);
630: }
631:
632: int
633: ch_getelemstatus(sc, first, count, data, datalen, voltag)
634: struct ch_softc *sc;
635: int first;
636: int count;
637: caddr_t data;
638: size_t datalen;
639: int voltag;
640: {
641: struct scsi_read_element_status cmd;
642:
643: /*
644: * Build SCSI command.
645: */
646: bzero(&cmd, sizeof(cmd));
647: cmd.opcode = READ_ELEMENT_STATUS;
648: _lto2b(first, cmd.sea);
649: _lto2b(count, cmd.count);
650: _lto3b(datalen, cmd.len);
651: if (voltag)
652: cmd.byte2 |= READ_ELEMENT_STATUS_VOLTAG;
653:
654: /*
655: * Send command to changer.
656: */
657: return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
658: sizeof(cmd), (u_char *)data, datalen, CHRETRIES, 100000, NULL, SCSI_DATA_IN));
659: }
660:
661:
662: /*
663: * Ask the device about itself and fill in the parameters in our
664: * softc.
665: */
666: int
667: ch_get_params(sc, flags)
668: struct ch_softc *sc;
669: int flags;
670: {
671: union scsi_mode_sense_buf *data;
672: struct page_element_address_assignment *ea;
673: struct page_device_capabilities *cap;
674: int error, from;
675: u_int8_t *moves, *exchanges;
676:
677: data = malloc(sizeof(*data), M_TEMP, M_NOWAIT);
678: if (data == NULL)
679: return (ENOMEM);
680:
681: /*
682: * Grab info from the element address assignment page (0x1d).
683: */
684: error = scsi_do_mode_sense(sc->sc_link, 0x1d, data,
685: (void **)&ea, NULL, NULL, NULL, sizeof(*ea), flags, NULL);
686: if (error == 0 && ea == NULL)
687: error = EIO;
688: if (error != 0) {
689: #ifdef CHANGER_DEBUG
690: printf("%s: could not sense element address page\n",
691: sc->sc_dev.dv_xname);
692: #endif
693: free(data, M_TEMP);
694: return (error);
695: }
696:
697: sc->sc_firsts[CHET_MT] = _2btol(ea->mtea);
698: sc->sc_counts[CHET_MT] = _2btol(ea->nmte);
699: sc->sc_firsts[CHET_ST] = _2btol(ea->fsea);
700: sc->sc_counts[CHET_ST] = _2btol(ea->nse);
701: sc->sc_firsts[CHET_IE] = _2btol(ea->fieea);
702: sc->sc_counts[CHET_IE] = _2btol(ea->niee);
703: sc->sc_firsts[CHET_DT] = _2btol(ea->fdtea);
704: sc->sc_counts[CHET_DT] = _2btol(ea->ndte);
705:
706: /* XXX Ask for transport geometry page. */
707:
708: /*
709: * Grab info from the capabilities page (0x1f).
710: */
711: error = scsi_do_mode_sense(sc->sc_link, 0x1f, data,
712: (void **)&cap, NULL, NULL, NULL, sizeof(*cap), flags, NULL);
713: if (cap == NULL)
714: error = EIO;
715: if (error != 0) {
716: #ifdef CHANGER_DEBUG
717: printf("%s: could not sense capabilities page\n",
718: sc->sc_dev.dv_xname);
719: #endif
720: free(data, M_TEMP);
721: return (error);
722: }
723:
724: bzero(sc->sc_movemask, sizeof(sc->sc_movemask));
725: bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask));
726: moves = &cap->move_from_mt;
727: exchanges = &cap->exchange_with_mt;
728: for (from = CHET_MT; from <= CHET_DT; ++from) {
729: sc->sc_movemask[from] = moves[from];
730: sc->sc_exchangemask[from] = exchanges[from];
731: }
732:
733: sc->sc_link->flags |= SDEV_MEDIA_LOADED;
734: free(data, M_TEMP);
735: return (0);
736: }
737:
738: void
739: ch_get_quirks(sc, inqbuf)
740: struct ch_softc *sc;
741: struct scsi_inquiry_data *inqbuf;
742: {
743: const struct chquirk *match;
744: int priority;
745:
746: sc->sc_settledelay = 0;
747:
748: match = (const struct chquirk *)scsi_inqmatch(inqbuf,
749: (caddr_t)chquirks,
750: sizeof(chquirks) / sizeof(chquirks[0]),
751: sizeof(chquirks[0]), &priority);
752: if (priority != 0) {
753: sc->sc_settledelay = match->cq_settledelay;
754: }
755: }
756:
757: /*
758: * Look at the returned sense and act on the error and detirmine
759: * The unix error number to pass back... (0 = report no error)
760: * (-1 = continue processing)
761: */
762: int
763: ch_interpret_sense(xs)
764: struct scsi_xfer *xs;
765: {
766: struct scsi_sense_data *sense = &xs->sense;
767: struct scsi_link *sc_link = xs->sc_link;
768: u_int8_t serr = sense->error_code & SSD_ERRCODE;
769: u_int8_t skey = sense->flags & SSD_KEY;
770:
771: if (((sc_link->flags & SDEV_OPEN) == 0) ||
772: (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED))
773: return (EJUSTRETURN); /* let the generic code handle it */
774:
775: switch (skey) {
776:
777: /*
778: * We do custom processing in ch for the unit becoming ready case.
779: * in this case we do not allow xs->retries to be decremented
780: * only on the "Unit Becoming Ready" case. This is because tape
781: * changers report "Unit Becoming Ready" when they rescan their
782: * state (i.e. when the door got opened) and can take a long time
783: * for large units. Rather than having a massive timeout for
784: * all operations (which would cause other problems) we allow
785: * changers to wait (but be interruptable with Ctrl-C) forever
786: * as long as they are reporting that they are becoming ready.
787: * all other cases are handled as per the default.
788: */
789: case SKEY_NOT_READY:
790: if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0)
791: return (0);
792: switch (ASC_ASCQ(sense)) {
793: case SENSE_NOT_READY_BECOMING_READY:
794: SC_DEBUG(sc_link, SDEV_DB1, ("not ready: busy (%#x)\n",
795: sense->add_sense_code_qual));
796: /* don't count this as a retry */
797: xs->retries++;
798: return (scsi_delay(xs, 1));
799: default:
800: return (EJUSTRETURN);
801: }
802: default:
803: return (EJUSTRETURN);
804: }
805: }
CVSweb