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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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