1 /* $OpenBSD: ch.c,v 1.37 2009/01/10 21:36:49 beck 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 caddr_t 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 = 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 *) (st_hdr + 1); 577 desclen = _2btol(pg_hdr->edl); 578 579 size = sizeof(struct read_element_status_header) + 580 sizeof(struct read_element_status_page_header) + 581 (desclen * sc->sc_counts[chet]); 582 583 /* 584 * Reallocate storage for descriptors and get them from the 585 * device. 586 */ 587 free(data, M_DEVBUF); 588 data = malloc(size, M_DEVBUF, M_WAITOK); 589 error = ch_getelemstatus(sc, sc->sc_firsts[chet], 590 sc->sc_counts[chet], data, size, want_voltags); 591 if (error) 592 goto done; 593 594 /* 595 * Fill in the user status array. 596 */ 597 st_hdr = (struct read_element_status_header *)data; 598 pg_hdr = (struct read_element_status_page_header *) (st_hdr + 1); 599 600 avail = _2btol(st_hdr->count); 601 if (avail != sc->sc_counts[chet]) { 602 error = EINVAL; 603 goto done; 604 } 605 udsize = avail * sizeof(struct changer_element_status); 606 607 user_data = malloc(udsize, M_DEVBUF, M_WAITOK | M_ZERO); 608 609 desc = (caddr_t)(pg_hdr + 1); 610 for (i = 0; i < avail; ++i) { 611 struct changer_element_status *ces = &(user_data[i]); 612 copy_element_status(pg_hdr->flags, 613 (struct read_element_status_descriptor *)desc, ces); 614 desc += desclen; 615 } 616 617 /* Copy array out to userspace. */ 618 error = copyout(user_data, cesr->cesr_data, udsize); 619 620 done: 621 if (data != NULL) 622 free(data, M_DEVBUF); 623 if (user_data != NULL) 624 free(user_data, M_DEVBUF); 625 return (error); 626 } 627 628 int 629 ch_getelemstatus(sc, first, count, data, datalen, voltag) 630 struct ch_softc *sc; 631 int first; 632 int count; 633 caddr_t data; 634 size_t datalen; 635 int voltag; 636 { 637 struct scsi_read_element_status cmd; 638 639 /* 640 * Build SCSI command. 641 */ 642 bzero(&cmd, sizeof(cmd)); 643 cmd.opcode = READ_ELEMENT_STATUS; 644 _lto2b(first, cmd.sea); 645 _lto2b(count, cmd.count); 646 _lto3b(datalen, cmd.len); 647 if (voltag) 648 cmd.byte2 |= READ_ELEMENT_STATUS_VOLTAG; 649 650 /* 651 * Send command to changer. 652 */ 653 return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd, 654 sizeof(cmd), (u_char *)data, datalen, CHRETRIES, 100000, NULL, 655 SCSI_DATA_IN)); 656 } 657 658 659 /* 660 * Ask the device about itself and fill in the parameters in our 661 * softc. 662 */ 663 int 664 ch_get_params(sc, flags) 665 struct ch_softc *sc; 666 int flags; 667 { 668 union scsi_mode_sense_buf *data; 669 struct page_element_address_assignment *ea; 670 struct page_device_capabilities *cap; 671 int error, from; 672 u_int8_t *moves, *exchanges; 673 674 data = malloc(sizeof(*data), M_TEMP, M_NOWAIT); 675 if (data == NULL) 676 return (ENOMEM); 677 678 /* 679 * Grab info from the element address assignment page (0x1d). 680 */ 681 error = scsi_do_mode_sense(sc->sc_link, 0x1d, data, 682 (void **)&ea, NULL, NULL, NULL, sizeof(*ea), flags, NULL); 683 if (error == 0 && ea == NULL) 684 error = EIO; 685 if (error != 0) { 686 #ifdef CHANGER_DEBUG 687 printf("%s: could not sense element address page\n", 688 sc->sc_dev.dv_xname); 689 #endif 690 free(data, M_TEMP); 691 return (error); 692 } 693 694 sc->sc_firsts[CHET_MT] = _2btol(ea->mtea); 695 sc->sc_counts[CHET_MT] = _2btol(ea->nmte); 696 sc->sc_firsts[CHET_ST] = _2btol(ea->fsea); 697 sc->sc_counts[CHET_ST] = _2btol(ea->nse); 698 sc->sc_firsts[CHET_IE] = _2btol(ea->fieea); 699 sc->sc_counts[CHET_IE] = _2btol(ea->niee); 700 sc->sc_firsts[CHET_DT] = _2btol(ea->fdtea); 701 sc->sc_counts[CHET_DT] = _2btol(ea->ndte); 702 703 /* XXX Ask for transport geometry page. */ 704 705 /* 706 * Grab info from the capabilities page (0x1f). 707 */ 708 error = scsi_do_mode_sense(sc->sc_link, 0x1f, data, 709 (void **)&cap, NULL, NULL, NULL, sizeof(*cap), flags, NULL); 710 if (cap == NULL) 711 error = EIO; 712 if (error != 0) { 713 #ifdef CHANGER_DEBUG 714 printf("%s: could not sense capabilities page\n", 715 sc->sc_dev.dv_xname); 716 #endif 717 free(data, M_TEMP); 718 return (error); 719 } 720 721 bzero(sc->sc_movemask, sizeof(sc->sc_movemask)); 722 bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask)); 723 moves = &cap->move_from_mt; 724 exchanges = &cap->exchange_with_mt; 725 for (from = CHET_MT; from <= CHET_DT; ++from) { 726 sc->sc_movemask[from] = moves[from]; 727 sc->sc_exchangemask[from] = exchanges[from]; 728 } 729 730 sc->sc_link->flags |= SDEV_MEDIA_LOADED; 731 free(data, M_TEMP); 732 return (0); 733 } 734 735 void 736 ch_get_quirks(sc, inqbuf) 737 struct ch_softc *sc; 738 struct scsi_inquiry_data *inqbuf; 739 { 740 const struct chquirk *match; 741 int priority; 742 743 sc->sc_settledelay = 0; 744 745 match = (const struct chquirk *)scsi_inqmatch(inqbuf, 746 (caddr_t)chquirks, 747 sizeof(chquirks) / sizeof(chquirks[0]), 748 sizeof(chquirks[0]), &priority); 749 if (priority != 0) { 750 sc->sc_settledelay = match->cq_settledelay; 751 } 752 } 753 754 /* 755 * Look at the returned sense and act on the error and detirmine 756 * The unix error number to pass back... (0 = report no error) 757 * (-1 = continue processing) 758 */ 759 int 760 ch_interpret_sense(xs) 761 struct scsi_xfer *xs; 762 { 763 struct scsi_sense_data *sense = &xs->sense; 764 struct scsi_link *sc_link = xs->sc_link; 765 u_int8_t serr = sense->error_code & SSD_ERRCODE; 766 u_int8_t skey = sense->flags & SSD_KEY; 767 768 if (((sc_link->flags & SDEV_OPEN) == 0) || 769 (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED)) 770 return (EJUSTRETURN); /* let the generic code handle it */ 771 772 switch (skey) { 773 774 /* 775 * We do custom processing in ch for the unit becoming ready case. 776 * in this case we do not allow xs->retries to be decremented 777 * only on the "Unit Becoming Ready" case. This is because tape 778 * changers report "Unit Becoming Ready" when they rescan their 779 * state (i.e. when the door got opened) and can take a long time 780 * for large units. Rather than having a massive timeout for 781 * all operations (which would cause other problems) we allow 782 * changers to wait (but be interruptable with Ctrl-C) forever 783 * as long as they are reporting that they are becoming ready. 784 * all other cases are handled as per the default. 785 */ 786 case SKEY_NOT_READY: 787 if ((xs->flags & SCSI_IGNORE_NOT_READY) != 0) 788 return (0); 789 switch (ASC_ASCQ(sense)) { 790 case SENSE_NOT_READY_BECOMING_READY: 791 SC_DEBUG(sc_link, SDEV_DB1, ("not ready: busy (%#x)\n", 792 sense->add_sense_code_qual)); 793 /* don't count this as a retry */ 794 xs->retries++; 795 return (scsi_delay(xs, 1)); 796 default: 797 return (EJUSTRETURN); 798 } 799 default: 800 return (EJUSTRETURN); 801 } 802 } 803