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