ch.c revision 1.40
1/* $NetBSD: ch.c,v 1.40 1999/09/30 22:57:53 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 1996, 1997, 1998, 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/errno.h> 44#include <sys/ioctl.h> 45#include <sys/buf.h> 46#include <sys/proc.h> 47#include <sys/user.h> 48#include <sys/chio.h> 49#include <sys/device.h> 50#include <sys/malloc.h> 51#include <sys/conf.h> 52#include <sys/fcntl.h> 53#include <sys/vnode.h> 54#include <sys/time.h> 55#include <sys/select.h> 56#include <sys/poll.h> 57 58#include <dev/scsipi/scsipi_all.h> 59#include <dev/scsipi/scsi_all.h> 60#include <dev/scsipi/scsi_changer.h> 61#include <dev/scsipi/scsiconf.h> 62 63#define CHRETRIES 2 64#define CHUNIT(x) (minor((x))) 65 66struct ch_softc { 67 struct device sc_dev; /* generic device info */ 68 struct scsipi_link *sc_link; /* link in the SCSI bus */ 69 70 u_int sc_events; /* event bitmask */ 71 struct selinfo sc_selq; /* select/poll queue for events */ 72 73 int sc_flags; /* misc. info */ 74 75 int sc_picker; /* current picker */ 76 77 /* 78 * The following information is obtained from the 79 * element address assignment page. 80 */ 81 int sc_firsts[4]; /* firsts, indexed by CHET_* */ 82 int sc_counts[4]; /* counts, indexed by CHET_* */ 83 84 /* 85 * The following mask defines the legal combinations 86 * of elements for the MOVE MEDIUM command. 87 */ 88 u_int8_t sc_movemask[4]; 89 90 /* 91 * As above, but for EXCHANGE MEDIUM. 92 */ 93 u_int8_t sc_exchangemask[4]; 94 95 /* 96 * Quirks; see below. 97 */ 98 int sc_settledelay; /* delay for settle */ 99 100}; 101 102/* sc_flags */ 103#define CHF_ROTATE 0x01 /* picker can rotate */ 104 105/* Autoconfiguration glue */ 106int chmatch __P((struct device *, struct cfdata *, void *)); 107void chattach __P((struct device *, struct device *, void *)); 108 109struct cfattach ch_ca = { 110 sizeof(struct ch_softc), chmatch, chattach 111}; 112 113extern struct cfdriver ch_cd; 114 115struct scsipi_inquiry_pattern ch_patterns[] = { 116 {T_CHANGER, T_REMOV, 117 "", "", ""}, 118}; 119 120/* SCSI glue */ 121int ch_interpret_sense __P((struct scsipi_xfer *)); 122 123struct scsipi_device ch_switch = { 124 ch_interpret_sense, /* check our error handler first */ 125 NULL, /* no queue; our commands are synchronous */ 126 NULL, /* have no async handler */ 127 NULL, /* nothing to be done when xfer is done */ 128}; 129 130int ch_move __P((struct ch_softc *, struct changer_move_request *)); 131int ch_exchange __P((struct ch_softc *, struct changer_exchange_request *)); 132int ch_position __P((struct ch_softc *, struct changer_position_request *)); 133int ch_ielem __P((struct ch_softc *)); 134int ch_ousergetelemstatus __P((struct ch_softc *, int, u_int8_t *)); 135int ch_usergetelemstatus __P((struct ch_softc *, 136 struct changer_element_status_request *)); 137int ch_getelemstatus __P((struct ch_softc *, int, int, void *, 138 size_t, int)); 139int ch_setvoltag __P((struct ch_softc *, 140 struct changer_set_voltag_request *)); 141int ch_get_params __P((struct ch_softc *, int)); 142void ch_get_quirks __P((struct ch_softc *, 143 struct scsipi_inquiry_pattern *)); 144void ch_event __P((struct ch_softc *, u_int)); 145int ch_map_element __P((struct ch_softc *, u_int16_t, int *, int *)); 146 147void ch_voltag_convert_in __P((const struct changer_volume_tag *, 148 struct changer_voltag *)); 149int ch_voltag_convert_out __P((const struct changer_voltag *, 150 struct changer_volume_tag *)); 151 152/* 153 * SCSI changer quirks. 154 */ 155struct chquirk { 156 struct scsipi_inquiry_pattern cq_match; /* device id pattern */ 157 int cq_settledelay; /* settle delay, in seconds */ 158}; 159 160struct chquirk chquirks[] = { 161 {{T_CHANGER, T_REMOV, 162 "SPECTRA", "9000", "0200"}, 163 75}, 164}; 165 166int 167chmatch(parent, match, aux) 168 struct device *parent; 169 struct cfdata *match; 170 void *aux; 171{ 172 struct scsipibus_attach_args *sa = aux; 173 int priority; 174 175 (void)scsipi_inqmatch(&sa->sa_inqbuf, 176 (caddr_t)ch_patterns, sizeof(ch_patterns) / sizeof(ch_patterns[0]), 177 sizeof(ch_patterns[0]), &priority); 178 179 return (priority); 180} 181 182void 183chattach(parent, self, aux) 184 struct device *parent, *self; 185 void *aux; 186{ 187 struct ch_softc *sc = (struct ch_softc *)self; 188 struct scsipibus_attach_args *sa = aux; 189 struct scsipi_link *link = sa->sa_sc_link; 190 191 /* Glue into the SCSI bus */ 192 sc->sc_link = link; 193 link->device = &ch_switch; 194 link->device_softc = sc; 195 link->openings = 1; 196 197 printf("\n"); 198 199 /* 200 * Find out our device's quirks. 201 */ 202 ch_get_quirks(sc, &sa->sa_inqbuf); 203 204 /* 205 * Some changers require a long time to settle out, to do 206 * tape inventory, for instance. 207 */ 208 if (sc->sc_settledelay) { 209 printf("%s: waiting %d seconds for changer to settle...\n", 210 sc->sc_dev.dv_xname, sc->sc_settledelay); 211 delay(1000000 * sc->sc_settledelay); 212 } 213 214 /* 215 * Get information about the device. Note we can't use 216 * interrupts yet. 217 */ 218 if (ch_get_params(sc, XS_CTL_DISCOVERY|XS_CTL_IGNORE_MEDIA_CHANGE)) 219 printf("%s: offline\n", sc->sc_dev.dv_xname); 220 else { 221#define PLURAL(c) (c) == 1 ? "" : "s" 222 printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n", 223 sc->sc_dev.dv_xname, 224 sc->sc_counts[CHET_ST], PLURAL(sc->sc_counts[CHET_ST]), 225 sc->sc_counts[CHET_DT], PLURAL(sc->sc_counts[CHET_DT]), 226 sc->sc_counts[CHET_MT], PLURAL(sc->sc_counts[CHET_MT]), 227 sc->sc_counts[CHET_IE], PLURAL(sc->sc_counts[CHET_IE])); 228#undef PLURAL 229#ifdef CHANGER_DEBUG 230 printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n", 231 sc->sc_dev.dv_xname, 232 sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST], 233 sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]); 234 printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n", 235 sc->sc_dev.dv_xname, 236 sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST], 237 sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]); 238#endif /* CHANGER_DEBUG */ 239 } 240 241 /* Default the current picker. */ 242 sc->sc_picker = sc->sc_firsts[CHET_MT]; 243} 244 245int 246chopen(dev, flags, fmt, p) 247 dev_t dev; 248 int flags, fmt; 249 struct proc *p; 250{ 251 struct ch_softc *sc; 252 int unit, error; 253 254 unit = CHUNIT(dev); 255 if ((unit >= ch_cd.cd_ndevs) || 256 ((sc = ch_cd.cd_devs[unit]) == NULL)) 257 return (ENXIO); 258 259 /* 260 * Only allow one open at a time. 261 */ 262 if (sc->sc_link->flags & SDEV_OPEN) 263 return (EBUSY); 264 265 if ((error = scsipi_adapter_addref(sc->sc_link)) != 0) 266 return (error); 267 268 sc->sc_link->flags |= SDEV_OPEN; 269 270 /* 271 * Make sure the unit is on-line. If a UNIT ATTENTION 272 * occurs, we will mark that an Init-Element-Status is 273 * needed in ch_get_params(). 274 * 275 * We ignore NOT READY in case e.g a magazine isn't actually 276 * loaded into the changer or a tape isn't in the drive. 277 */ 278 error = scsipi_test_unit_ready(sc->sc_link, XS_CTL_IGNORE_NOT_READY); 279 if (error) 280 goto bad; 281 282 /* 283 * Make sure our parameters are up to date. 284 */ 285 if ((error = ch_get_params(sc, 0)) != 0) 286 goto bad; 287 288 return (0); 289 290 bad: 291 scsipi_adapter_delref(sc->sc_link); 292 sc->sc_link->flags &= ~SDEV_OPEN; 293 return (error); 294} 295 296int 297chclose(dev, flags, fmt, p) 298 dev_t dev; 299 int flags, fmt; 300 struct proc *p; 301{ 302 struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)]; 303 304 scsipi_wait_drain(sc->sc_link); 305 306 scsipi_adapter_delref(sc->sc_link); 307 308 sc->sc_events = 0; 309 310 sc->sc_link->flags &= ~SDEV_OPEN; 311 return (0); 312} 313 314int 315chread(dev, uio, flags) 316 dev_t dev; 317 struct uio *uio; 318 int flags; 319{ 320 struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)]; 321 int error; 322 323 if (uio->uio_resid != CHANGER_EVENT_SIZE) 324 return (EINVAL); 325 326 /* 327 * Read never blocks; if there are no events pending, we just 328 * return an all-clear bitmask. 329 */ 330 error = uiomove(&sc->sc_events, CHANGER_EVENT_SIZE, uio); 331 if (error == 0) 332 sc->sc_events = 0; 333 return (error); 334} 335 336int 337chioctl(dev, cmd, data, flags, p) 338 dev_t dev; 339 u_long cmd; 340 caddr_t data; 341 int flags; 342 struct proc *p; 343{ 344 struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)]; 345 int error = 0; 346 347 /* 348 * If this command can change the device's state, we must 349 * have the device open for writing. 350 */ 351 switch (cmd) { 352 case CHIOGPICKER: 353 case CHIOGPARAMS: 354 case OCHIOGSTATUS: 355 break; 356 357 default: 358 if ((flags & FWRITE) == 0) 359 return (EBADF); 360 } 361 362 switch (cmd) { 363 case CHIOMOVE: 364 error = ch_move(sc, (struct changer_move_request *)data); 365 break; 366 367 case CHIOEXCHANGE: 368 error = ch_exchange(sc, 369 (struct changer_exchange_request *)data); 370 break; 371 372 case CHIOPOSITION: 373 error = ch_position(sc, 374 (struct changer_position_request *)data); 375 break; 376 377 case CHIOGPICKER: 378 *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT]; 379 break; 380 381 case CHIOSPICKER: 382 { 383 int new_picker = *(int *)data; 384 385 if (new_picker > (sc->sc_counts[CHET_MT] - 1)) 386 return (EINVAL); 387 sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker; 388 break; 389 } 390 391 case CHIOGPARAMS: 392 { 393 struct changer_params *cp = (struct changer_params *)data; 394 395 cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT]; 396 cp->cp_npickers = sc->sc_counts[CHET_MT]; 397 cp->cp_nslots = sc->sc_counts[CHET_ST]; 398 cp->cp_nportals = sc->sc_counts[CHET_IE]; 399 cp->cp_ndrives = sc->sc_counts[CHET_DT]; 400 break; 401 } 402 403 case CHIOIELEM: 404 error = ch_ielem(sc); 405 break; 406 407 case OCHIOGSTATUS: 408 { 409 struct ochanger_element_status_request *cesr = 410 (struct ochanger_element_status_request *)data; 411 412 error = ch_ousergetelemstatus(sc, cesr->cesr_type, 413 cesr->cesr_data); 414 break; 415 } 416 417 case CHIOGSTATUS: 418 error = ch_usergetelemstatus(sc, 419 (struct changer_element_status_request *)data); 420 break; 421 422 case CHIOSVOLTAG: 423 error = ch_setvoltag(sc, 424 (struct changer_set_voltag_request *)data); 425 break; 426 427 /* Implement prevent/allow? */ 428 429 default: 430 error = scsipi_do_ioctl(sc->sc_link, dev, cmd, data, flags, p); 431 break; 432 } 433 434 return (error); 435} 436 437int 438chpoll(dev, events, p) 439 dev_t dev; 440 int events; 441 struct proc *p; 442{ 443 struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)]; 444 int revents; 445 446 revents = events & (POLLOUT | POLLWRNORM); 447 448 if ((events & (POLLIN | POLLRDNORM)) == 0) 449 return (revents); 450 451 if (sc->sc_events == 0) 452 revents |= events & (POLLIN | POLLRDNORM); 453 else 454 selrecord(p, &sc->sc_selq); 455 456 return (revents); 457} 458 459int 460ch_interpret_sense(xs) 461 struct scsipi_xfer *xs; 462{ 463 struct scsipi_link *sc_link = xs->sc_link; 464 struct scsipi_sense_data *sense = &xs->sense.scsi_sense; 465 struct ch_softc *sc = sc_link->device_softc; 466 int error, retval = SCSIRET_CONTINUE; 467 468 /* 469 * If it isn't an extended or extended/defered error, let 470 * the generic code handle it. 471 */ 472 if ((sense->error_code & SSD_ERRCODE) != 0x70 && 473 (sense->error_code & SSD_ERRCODE) != 0x71) 474 return (retval); 475 476 if ((sense->flags & SSD_KEY) == SKEY_UNIT_ATTENTION) { 477 /* 478 * The element status has possibly changed, usually because 479 * an operator has opened the door. We need to initialize 480 * the element status. If we haven't gotten our params yet, 481 * then we are about to (we are getting here via chopen()). 482 * Just notify ch_get_params() that we need to do an 483 * Init-Element-Status. Otherwise, we need to call 484 * ch_get_params() ourselves. 485 */ 486 retval = SCSIRET_RETRY; 487 if (sc->sc_link->flags & SDEV_MEDIA_LOADED) { 488 sc->sc_link->flags &= ~SDEV_MEDIA_LOADED; 489 if ((xs->xs_control & 490 XS_CTL_IGNORE_MEDIA_CHANGE) == 0) { 491 error = ch_get_params(sc, 0); 492 if (error) 493 retval = error; 494 } 495 } 496 497 /* 498 * Enqueue an Element-Status-Changed event, and wake up 499 * any processes waiting for them. 500 */ 501 if ((xs->xs_control & XS_CTL_IGNORE_MEDIA_CHANGE) == 0) 502 ch_event(sc, CHEV_ELEMENT_STATUS_CHANGED); 503 } 504 505 return (retval); 506} 507 508void 509ch_event(sc, event) 510 struct ch_softc *sc; 511 u_int event; 512{ 513 514 sc->sc_events |= event; 515 selwakeup(&sc->sc_selq); 516} 517 518int 519ch_move(sc, cm) 520 struct ch_softc *sc; 521 struct changer_move_request *cm; 522{ 523 struct scsi_move_medium cmd; 524 u_int16_t fromelem, toelem; 525 526 /* 527 * Check arguments. 528 */ 529 if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT)) 530 return (EINVAL); 531 if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) || 532 (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1))) 533 return (ENODEV); 534 535 /* 536 * Check the request against the changer's capabilities. 537 */ 538 if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0) 539 return (ENODEV); 540 541 /* 542 * Calculate the source and destination elements. 543 */ 544 fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit; 545 toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit; 546 547 /* 548 * Build the SCSI command. 549 */ 550 bzero(&cmd, sizeof(cmd)); 551 cmd.opcode = MOVE_MEDIUM; 552 _lto2b(sc->sc_picker, cmd.tea); 553 _lto2b(fromelem, cmd.src); 554 _lto2b(toelem, cmd.dst); 555 if (cm->cm_flags & CM_INVERT) 556 cmd.flags |= MOVE_MEDIUM_INVERT; 557 558 /* 559 * Send command to changer. 560 */ 561 return (scsipi_command(sc->sc_link, 562 (struct scsipi_generic *)&cmd, sizeof(cmd), NULL, 0, CHRETRIES, 563 100000, NULL, 0)); 564} 565 566int 567ch_exchange(sc, ce) 568 struct ch_softc *sc; 569 struct changer_exchange_request *ce; 570{ 571 struct scsi_exchange_medium cmd; 572 u_int16_t src, dst1, dst2; 573 574 /* 575 * Check arguments. 576 */ 577 if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) || 578 (ce->ce_sdsttype > CHET_DT)) 579 return (EINVAL); 580 if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) || 581 (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) || 582 (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1))) 583 return (ENODEV); 584 585 /* 586 * Check the request against the changer's capabilities. 587 */ 588 if (((sc->sc_exchangemask[ce->ce_srctype] & 589 (1 << ce->ce_fdsttype)) == 0) || 590 ((sc->sc_exchangemask[ce->ce_fdsttype] & 591 (1 << ce->ce_sdsttype)) == 0)) 592 return (ENODEV); 593 594 /* 595 * Calculate the source and destination elements. 596 */ 597 src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit; 598 dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit; 599 dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit; 600 601 /* 602 * Build the SCSI command. 603 */ 604 bzero(&cmd, sizeof(cmd)); 605 cmd.opcode = EXCHANGE_MEDIUM; 606 _lto2b(sc->sc_picker, cmd.tea); 607 _lto2b(src, cmd.src); 608 _lto2b(dst1, cmd.fdst); 609 _lto2b(dst2, cmd.sdst); 610 if (ce->ce_flags & CE_INVERT1) 611 cmd.flags |= EXCHANGE_MEDIUM_INV1; 612 if (ce->ce_flags & CE_INVERT2) 613 cmd.flags |= EXCHANGE_MEDIUM_INV2; 614 615 /* 616 * Send command to changer. 617 */ 618 return (scsipi_command(sc->sc_link, 619 (struct scsipi_generic *)&cmd, sizeof(cmd), NULL, 0, CHRETRIES, 620 100000, NULL, 0)); 621} 622 623int 624ch_position(sc, cp) 625 struct ch_softc *sc; 626 struct changer_position_request *cp; 627{ 628 struct scsi_position_to_element cmd; 629 u_int16_t dst; 630 631 /* 632 * Check arguments. 633 */ 634 if (cp->cp_type > CHET_DT) 635 return (EINVAL); 636 if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1)) 637 return (ENODEV); 638 639 /* 640 * Calculate the destination element. 641 */ 642 dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit; 643 644 /* 645 * Build the SCSI command. 646 */ 647 bzero(&cmd, sizeof(cmd)); 648 cmd.opcode = POSITION_TO_ELEMENT; 649 _lto2b(sc->sc_picker, cmd.tea); 650 _lto2b(dst, cmd.dst); 651 if (cp->cp_flags & CP_INVERT) 652 cmd.flags |= POSITION_TO_ELEMENT_INVERT; 653 654 /* 655 * Send command to changer. 656 */ 657 return (scsipi_command(sc->sc_link, 658 (struct scsipi_generic *)&cmd, sizeof(cmd), NULL, 0, CHRETRIES, 659 100000, NULL, 0)); 660} 661 662/* 663 * Perform a READ ELEMENT STATUS on behalf of the user, and return to 664 * the user only the data the user is interested in. This returns the 665 * old data format. 666 */ 667int 668ch_ousergetelemstatus(sc, chet, uptr) 669 struct ch_softc *sc; 670 int chet; 671 u_int8_t *uptr; 672{ 673 struct read_element_status_header *st_hdrp, st_hdr; 674 struct read_element_status_page_header *pg_hdrp; 675 struct read_element_status_descriptor *desc; 676 size_t size, desclen; 677 caddr_t data; 678 int avail, i, error = 0; 679 u_int8_t user_data; 680 681 /* 682 * If there are no elements of the requested type in the changer, 683 * the request is invalid. 684 */ 685 if (sc->sc_counts[chet] == 0) 686 return (EINVAL); 687 688 /* 689 * Do the request the user wants, but only read the status header. 690 * This will tell us the amount of storage we must allocate in 691 * order to read all data. 692 */ 693 error = ch_getelemstatus(sc, sc->sc_firsts[chet], 694 sc->sc_counts[chet], &st_hdr, sizeof(st_hdr), 0); 695 if (error) 696 return (error); 697 698 size = sizeof(struct read_element_status_header) + 699 _3btol(st_hdr.nbytes); 700 701 /* 702 * We must have at least room for the status header and 703 * one page header (since we only ask for one element type 704 * at a time). 705 */ 706 if (size < (sizeof(struct read_element_status_header) + 707 sizeof(struct read_element_status_page_header))) 708 return (EIO); 709 710 /* 711 * Allocate the storage and do the request again. 712 */ 713 data = malloc(size, M_DEVBUF, M_WAITOK); 714 error = ch_getelemstatus(sc, sc->sc_firsts[chet], 715 sc->sc_counts[chet], data, size, 0); 716 if (error) 717 goto done; 718 719 st_hdrp = (struct read_element_status_header *)data; 720 pg_hdrp = (struct read_element_status_page_header *)((u_long)st_hdrp + 721 sizeof(struct read_element_status_header)); 722 desclen = _2btol(pg_hdrp->edl); 723 724 /* 725 * Fill in the user status array. 726 */ 727 avail = _2btol(st_hdrp->count); 728 729 if (avail != sc->sc_counts[chet]) 730 printf("%s: warning, READ ELEMENT STATUS avail != count\n", 731 sc->sc_dev.dv_xname); 732 733 desc = (struct read_element_status_descriptor *)((u_long)data + 734 sizeof(struct read_element_status_header) + 735 sizeof(struct read_element_status_page_header)); 736 for (i = 0; i < avail; ++i) { 737 user_data = desc->flags1; 738 error = copyout(&user_data, &uptr[i], avail); 739 if (error) 740 break; 741 (u_long)desc += desclen; 742 } 743 744 done: 745 if (data != NULL) 746 free(data, M_DEVBUF); 747 return (error); 748} 749 750/* 751 * Perform a READ ELEMENT STATUS on behalf of the user. This returns 752 * the new (more complete) data format. 753 */ 754int 755ch_usergetelemstatus(sc, cesr) 756 struct ch_softc *sc; 757 struct changer_element_status_request *cesr; 758{ 759 struct scsibus_softc *parent; 760 struct scsipi_link *dtlink; 761 struct device *dtdev; 762 struct read_element_status_header *st_hdrp, st_hdr; 763 struct read_element_status_page_header *pg_hdrp; 764 struct read_element_status_descriptor *desc; 765 struct changer_volume_tag *avol, *pvol; 766 size_t size, desclen, stddesclen, offset; 767 int first, avail, i, error = 0; 768 caddr_t data; 769 void *uvendptr; 770 struct changer_element_status ces; 771 772 /* 773 * Check arguments. 774 */ 775 if (cesr->cesr_type > CHET_DT) 776 return (EINVAL); 777 if (sc->sc_counts[cesr->cesr_type] == 0) 778 return (ENODEV); 779 if (cesr->cesr_unit > (sc->sc_counts[cesr->cesr_type] - 1)) 780 return (ENODEV); 781 if (cesr->cesr_count > 782 (sc->sc_counts[cesr->cesr_type] + cesr->cesr_unit)) 783 return (EINVAL); 784 785 /* 786 * Do the request the user wants, but only read the status header. 787 * This will tell us the amount of storage we must allocate 788 * in order to read all the data. 789 */ 790 error = ch_getelemstatus(sc, sc->sc_firsts[cesr->cesr_type] + 791 cesr->cesr_unit, cesr->cesr_count, &st_hdr, sizeof(st_hdr), 792 cesr->cesr_flags); 793 if (error) 794 return (error); 795 796 size = sizeof(struct read_element_status_header) + 797 _3btol(st_hdr.nbytes); 798 799 /* 800 * We must have at least room for the status header and 801 * one page header (since we only ask for oen element type 802 * at a time). 803 */ 804 if (size < (sizeof(struct read_element_status_header) + 805 sizeof(struct read_element_status_page_header))) 806 return (EIO); 807 808 /* 809 * Allocate the storage and do the request again. 810 */ 811 data = malloc(size, M_DEVBUF, M_WAITOK); 812 error = ch_getelemstatus(sc, sc->sc_firsts[cesr->cesr_type] + 813 cesr->cesr_unit, cesr->cesr_count, data, size, cesr->cesr_flags); 814 if (error) 815 goto done; 816 817 st_hdrp = (struct read_element_status_header *)data; 818 pg_hdrp = (struct read_element_status_page_header *)((u_long)st_hdrp + 819 sizeof(struct read_element_status_header)); 820 desclen = _2btol(pg_hdrp->edl); 821 822 /* 823 * Fill in the user status array. 824 */ 825 first = _2btol(st_hdrp->fear); 826 if (first < (sc->sc_firsts[cesr->cesr_type] + cesr->cesr_unit) || 827 first >= (sc->sc_firsts[cesr->cesr_type] + cesr->cesr_unit + 828 cesr->cesr_count)) { 829 error = EIO; 830 goto done; 831 } 832 first -= sc->sc_firsts[cesr->cesr_type] + cesr->cesr_unit; 833 834 avail = _2btol(st_hdrp->count); 835 if (avail <= 0 || avail > cesr->cesr_count) { 836 error = EIO; 837 goto done; 838 } 839 840 offset = sizeof(struct read_element_status_header) + 841 sizeof(struct read_element_status_page_header); 842 843 for (i = 0; i < cesr->cesr_count; i++) { 844 memset(&ces, 0, sizeof(ces)); 845 if (i < first || i >= (first + avail)) { 846 error = copyout(&ces, &cesr->cesr_data[i], 847 sizeof(ces)); 848 if (error) 849 goto done; 850 } 851 852 desc = (struct read_element_status_descriptor *) 853 (data + offset); 854 stddesclen = sizeof(struct read_element_status_descriptor); 855 offset += desclen; 856 857 ces.ces_flags = CESTATUS_STATUS_VALID; 858 859 /* 860 * The SCSI flags conveniently map directly to the 861 * chio API flags. 862 */ 863 ces.ces_flags |= (desc->flags1 & 0x3f); 864 865 ces.ces_asc = desc->sense_code; 866 ces.ces_ascq = desc->sense_qual; 867 868 /* 869 * For Data Transport elemenets, get the SCSI ID and LUN, 870 * and attempt to map them to a device name if they're 871 * on the same SCSI bus. 872 */ 873 if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_IDVALID) { 874 ces.ces_target = desc->dt_scsi_addr; 875 ces.ces_flags |= CESTATUS_TARGET_VALID; 876 } 877 if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_LUVALID) { 878 ces.ces_lun = desc->dt_scsi_flags & 879 READ_ELEMENT_STATUS_DT_LUNMASK; 880 ces.ces_flags |= CESTATUS_LUN_VALID; 881 } 882 if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_NOTBUS) 883 ces.ces_flags |= CESTATUS_NOTBUS; 884 else if ((ces.ces_flags & 885 (CESTATUS_TARGET_VALID|CESTATUS_LUN_VALID)) == 886 (CESTATUS_TARGET_VALID|CESTATUS_LUN_VALID)) { 887 parent = (struct scsibus_softc *)sc->sc_dev.dv_parent; 888 if (ces.ces_target <= parent->sc_maxtarget && 889 ces.ces_lun <= parent->sc_maxlun && 890 (dtlink = 891 parent->sc_link[ces.ces_target][ces.ces_lun]) 892 != NULL && 893 (dtdev = dtlink->device_softc) != NULL) { 894 strcpy(ces.ces_xname, dtdev->dv_xname); 895 ces.ces_flags |= CESTATUS_XNAME_VALID; 896 } 897 } 898 899 if (desc->flags2 & READ_ELEMENT_STATUS_INVERT) 900 ces.ces_flags |= CESTATUS_INVERTED; 901 902 if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) { 903 if (ch_map_element(sc, _2btol(desc->ssea), 904 &ces.ces_from_type, &ces.ces_from_unit)) 905 ces.ces_flags |= CESTATUS_FROM_VALID; 906 } 907 908 /* 909 * Extract volume tag information. 910 */ 911 switch (pg_hdrp->flags & 912 (READ_ELEMENT_STATUS_PVOLTAG|READ_ELEMENT_STATUS_AVOLTAG)) { 913 case (READ_ELEMENT_STATUS_PVOLTAG|READ_ELEMENT_STATUS_AVOLTAG): 914 pvol = (struct changer_volume_tag *)(desc + 1); 915 avol = pvol + 1; 916 break; 917 918 case READ_ELEMENT_STATUS_PVOLTAG: 919 pvol = (struct changer_volume_tag *)(desc + 1); 920 avol = NULL; 921 break; 922 923 case READ_ELEMENT_STATUS_AVOLTAG: 924 pvol = NULL; 925 avol = (struct changer_volume_tag *)(desc + 1); 926 break; 927 928 default: 929 avol = pvol = NULL; 930 break; 931 } 932 933 if (pvol != NULL) { 934 ch_voltag_convert_in(pvol, &ces.ces_pvoltag); 935 ces.ces_flags |= CESTATUS_PVOL_VALID; 936 stddesclen += sizeof(struct changer_volume_tag); 937 } 938 if (avol != NULL) { 939 ch_voltag_convert_in(avol, &ces.ces_avoltag); 940 ces.ces_flags |= CESTATUS_AVOL_VALID; 941 stddesclen += sizeof(struct changer_volume_tag); 942 } 943 944 /* 945 * Compute vendor-specific length. Note the 4 reserved 946 * bytes between the volume tags and the vendor-specific 947 * data. Copy it out of the user wants it. 948 */ 949 stddesclen += 4; 950 if (desclen > stddesclen) 951 ces.ces_vendor_len = desclen - stddesclen; 952 953 if (ces.ces_vendor_len != 0 && cesr->cesr_vendor_data != NULL) { 954 error = copyin(&cesr->cesr_vendor_data[i], &uvendptr, 955 sizeof(uvendptr)); 956 if (error) 957 goto done; 958 error = copyout((void *)((u_long)desc + stddesclen), 959 uvendptr, ces.ces_vendor_len); 960 if (error) 961 goto done; 962 } 963 964 /* 965 * Now copy out the status descriptor we've constructed. 966 */ 967 error = copyout(&ces, &cesr->cesr_data[i], sizeof(ces)); 968 if (error) 969 goto done; 970 } 971 972 done: 973 if (data != NULL) 974 free(data, M_DEVBUF); 975 return (error); 976} 977 978int 979ch_getelemstatus(sc, first, count, data, datalen, flags) 980 struct ch_softc *sc; 981 int first, count; 982 void *data; 983 size_t datalen; 984 int flags; 985{ 986 struct scsi_read_element_status cmd; 987 988 /* 989 * Build SCSI command. 990 */ 991 bzero(&cmd, sizeof(cmd)); 992 cmd.opcode = READ_ELEMENT_STATUS; 993 cmd.byte2 = ELEMENT_TYPE_ALL; 994 if (flags & CESR_VOLTAGS) 995 cmd.byte2 |= READ_ELEMENT_STATUS_VOLTAG; 996 _lto2b(first, cmd.sea); 997 _lto2b(count, cmd.count); 998 _lto3b(datalen, cmd.len); 999 1000 /* 1001 * Send command to changer. 1002 */ 1003 return (scsipi_command(sc->sc_link, 1004 (struct scsipi_generic *)&cmd, sizeof(cmd), 1005 (u_char *)data, datalen, CHRETRIES, 100000, NULL, XS_CTL_DATA_IN)); 1006} 1007 1008int 1009ch_setvoltag(sc, csvr) 1010 struct ch_softc *sc; 1011 struct changer_set_voltag_request *csvr; 1012{ 1013 struct scsi_send_volume_tag cmd; 1014 struct changer_volume_tag voltag; 1015 void *data = NULL; 1016 size_t datalen = 0; 1017 int error; 1018 u_int16_t dst; 1019 1020 /* 1021 * Check arguments. 1022 */ 1023 if (csvr->csvr_type > CHET_DT) 1024 return (EINVAL); 1025 if (csvr->csvr_unit > (sc->sc_counts[csvr->csvr_type] - 1)) 1026 return (ENODEV); 1027 1028 dst = sc->sc_firsts[csvr->csvr_type] + csvr->csvr_unit; 1029 1030 /* 1031 * Build the SCSI command. 1032 */ 1033 bzero(&cmd, sizeof(cmd)); 1034 cmd.opcode = SEND_VOLUME_TAG; 1035 _lto2b(dst, cmd.eaddr); 1036 1037#define ALTERNATE (csvr->csvr_flags & CSVR_ALTERNATE) 1038 1039 switch (csvr->csvr_flags & CSVR_MODE_MASK) { 1040 case CSVR_MODE_SET: 1041 cmd.sac = ALTERNATE ? SAC_ASSERT_ALT : SAC_ASSERT_PRIMARY; 1042 break; 1043 1044 case CSVR_MODE_REPLACE: 1045 cmd.sac = ALTERNATE ? SAC_REPLACE_ALT : SAC_REPLACE_PRIMARY; 1046 break; 1047 1048 case CSVR_MODE_CLEAR: 1049 cmd.sac = ALTERNATE ? SAC_UNDEFINED_ALT : SAC_UNDEFINED_PRIMARY; 1050 break; 1051 1052 default: 1053 return (EINVAL); 1054 } 1055 1056#undef ALTERNATE 1057 1058 if (cmd.sac < SAC_UNDEFINED_PRIMARY) { 1059 error = ch_voltag_convert_out(&csvr->csvr_voltag, &voltag); 1060 if (error) 1061 return (error); 1062 data = &voltag; 1063 datalen = sizeof(voltag); 1064 _lto2b(datalen, cmd.length); 1065 } 1066 1067 /* 1068 * Send command to changer. 1069 */ 1070 return (scsipi_command(sc->sc_link, 1071 (struct scsipi_generic *)&cmd, sizeof(cmd), 1072 (u_char *)data, datalen, CHRETRIES, 100000, NULL, 1073 datalen ? XS_CTL_DATA_OUT : 0)); 1074} 1075 1076int 1077ch_ielem(sc) 1078 struct ch_softc *sc; 1079{ 1080 int tmo; 1081 struct scsi_initialize_element_status cmd; 1082 1083 /* 1084 * Build SCSI command. 1085 */ 1086 bzero(&cmd, sizeof(cmd)); 1087 cmd.opcode = INITIALIZE_ELEMENT_STATUS; 1088 1089 /* 1090 * Send command to changer. 1091 * 1092 * The problem is, how long to allow for the command? 1093 * It can take a *really* long time, and also depends 1094 * on unknowable factors such as whether there are 1095 * *almost* readable labels on tapes that a barcode 1096 * reader is trying to decipher. 1097 * 1098 * I'm going to make this long enough to allow 5 minutes 1099 * per element plus an initial 10 minute wait. 1100 */ 1101 tmo = sc->sc_counts[CHET_MT] + 1102 sc->sc_counts[CHET_ST] + 1103 sc->sc_counts[CHET_IE] + 1104 sc->sc_counts[CHET_DT]; 1105 tmo *= 5 * 60 * 1000; 1106 tmo += (10 * 60 * 1000); 1107 1108 return (scsipi_command(sc->sc_link, 1109 (struct scsipi_generic *)&cmd, sizeof(cmd), 1110 NULL, 0, CHRETRIES, tmo, NULL, XS_CTL_IGNORE_ILLEGAL_REQUEST)); 1111} 1112 1113/* 1114 * Ask the device about itself and fill in the parameters in our 1115 * softc. 1116 */ 1117int 1118ch_get_params(sc, scsiflags) 1119 struct ch_softc *sc; 1120 int scsiflags; 1121{ 1122 struct scsi_mode_sense cmd; 1123 struct scsi_mode_sense_data { 1124 struct scsi_mode_header header; 1125 union { 1126 struct page_element_address_assignment ea; 1127 struct page_transport_geometry_parameters tg; 1128 struct page_device_capabilities cap; 1129 } pages; 1130 } sense_data; 1131 int error, from; 1132 u_int8_t *moves, *exchanges; 1133 1134 /* 1135 * Grab info from the element address assignment page. 1136 */ 1137 bzero(&cmd, sizeof(cmd)); 1138 bzero(&sense_data, sizeof(sense_data)); 1139 cmd.opcode = SCSI_MODE_SENSE; 1140 cmd.byte2 |= 0x08; /* disable block descriptors */ 1141 cmd.page = 0x1d; 1142 cmd.length = (sizeof(sense_data) & 0xff); 1143 error = scsipi_command(sc->sc_link, 1144 (struct scsipi_generic *)&cmd, sizeof(cmd), (u_char *)&sense_data, 1145 sizeof(sense_data), CHRETRIES, 6000, NULL, 1146 scsiflags | XS_CTL_DATA_IN); 1147 if (error) { 1148 printf("%s: could not sense element address page\n", 1149 sc->sc_dev.dv_xname); 1150 return (error); 1151 } 1152 1153 sc->sc_firsts[CHET_MT] = _2btol(sense_data.pages.ea.mtea); 1154 sc->sc_counts[CHET_MT] = _2btol(sense_data.pages.ea.nmte); 1155 sc->sc_firsts[CHET_ST] = _2btol(sense_data.pages.ea.fsea); 1156 sc->sc_counts[CHET_ST] = _2btol(sense_data.pages.ea.nse); 1157 sc->sc_firsts[CHET_IE] = _2btol(sense_data.pages.ea.fieea); 1158 sc->sc_counts[CHET_IE] = _2btol(sense_data.pages.ea.niee); 1159 sc->sc_firsts[CHET_DT] = _2btol(sense_data.pages.ea.fdtea); 1160 sc->sc_counts[CHET_DT] = _2btol(sense_data.pages.ea.ndte); 1161 1162 /* XXX ask for page trasport geom */ 1163 1164 /* 1165 * Grab info from the capabilities page. 1166 */ 1167 bzero(&cmd, sizeof(cmd)); 1168 bzero(&sense_data, sizeof(sense_data)); 1169 cmd.opcode = SCSI_MODE_SENSE; 1170 /* 1171 * XXX: Note: not all changers can deal with disabled block descriptors 1172 */ 1173 cmd.byte2 = 0x08; /* disable block descriptors */ 1174 cmd.page = 0x1f; 1175 cmd.length = (sizeof(sense_data) & 0xff); 1176 error = scsipi_command(sc->sc_link, 1177 (struct scsipi_generic *)&cmd, sizeof(cmd), (u_char *)&sense_data, 1178 sizeof(sense_data), CHRETRIES, 6000, NULL, 1179 scsiflags | XS_CTL_DATA_IN); 1180 if (error) { 1181 printf("%s: could not sense capabilities page\n", 1182 sc->sc_dev.dv_xname); 1183 return (error); 1184 } 1185 1186 bzero(sc->sc_movemask, sizeof(sc->sc_movemask)); 1187 bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask)); 1188 moves = &sense_data.pages.cap.move_from_mt; 1189 exchanges = &sense_data.pages.cap.exchange_with_mt; 1190 for (from = CHET_MT; from <= CHET_DT; ++from) { 1191 sc->sc_movemask[from] = moves[from]; 1192 sc->sc_exchangemask[from] = exchanges[from]; 1193 } 1194 1195 /* 1196 * If we need to do an Init-Element-Status, do that now that 1197 * we know what's in the changer. 1198 */ 1199 if ((scsiflags & XS_CTL_IGNORE_MEDIA_CHANGE) == 0) { 1200 if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) == 0) 1201 error = ch_ielem(sc); 1202 if (error == 0) 1203 sc->sc_link->flags |= SDEV_MEDIA_LOADED; 1204 else 1205 sc->sc_link->flags &= ~SDEV_MEDIA_LOADED; 1206 } 1207 return (error); 1208} 1209 1210void 1211ch_get_quirks(sc, inqbuf) 1212 struct ch_softc *sc; 1213 struct scsipi_inquiry_pattern *inqbuf; 1214{ 1215 struct chquirk *match; 1216 int priority; 1217 1218 sc->sc_settledelay = 0; 1219 1220 match = (struct chquirk *)scsipi_inqmatch(inqbuf, 1221 (caddr_t)chquirks, 1222 sizeof(chquirks) / sizeof(chquirks[0]), 1223 sizeof(chquirks[0]), &priority); 1224 if (priority != 0) 1225 sc->sc_settledelay = match->cq_settledelay; 1226} 1227 1228int 1229ch_map_element(sc, elem, typep, unitp) 1230 struct ch_softc *sc; 1231 u_int16_t elem; 1232 int *typep, *unitp; 1233{ 1234 int chet; 1235 1236 for (chet = CHET_MT; chet <= CHET_DT; chet++) { 1237 if (elem >= sc->sc_firsts[chet] && 1238 elem < (sc->sc_firsts[chet] + sc->sc_counts[chet])) { 1239 *typep = chet; 1240 *unitp = elem - sc->sc_firsts[chet]; 1241 return (1); 1242 } 1243 } 1244 return (0); 1245} 1246 1247void 1248ch_voltag_convert_in(sv, cv) 1249 const struct changer_volume_tag *sv; 1250 struct changer_voltag *cv; 1251{ 1252 int i; 1253 1254 memset(cv, 0, sizeof(struct changer_voltag)); 1255 1256 /* 1257 * Copy the volume tag string from the SCSI representation. 1258 * Per the SCSI-2 spec, we stop at the first blank character. 1259 */ 1260 for (i = 0; i < sizeof(sv->volid); i++) { 1261 if (sv->volid[i] == ' ') 1262 break; 1263 cv->cv_tag[i] = sv->volid[i]; 1264 } 1265 cv->cv_tag[i] = '\0'; 1266 1267 cv->cv_serial = _2btol(sv->volseq); 1268} 1269 1270int 1271ch_voltag_convert_out(cv, sv) 1272 const struct changer_voltag *cv; 1273 struct changer_volume_tag *sv; 1274{ 1275 int i; 1276 1277 memset(sv, ' ', sizeof(struct changer_volume_tag)); 1278 1279 for (i = 0; i < sizeof(sv->volid); i++) { 1280 if (cv->cv_tag[i] == '\0') 1281 break; 1282 /* 1283 * Limit the character set to what is suggested in 1284 * the SCSI-2 spec. 1285 */ 1286 if ((cv->cv_tag[i] < '0' || cv->cv_tag[i] > '9') && 1287 (cv->cv_tag[i] < 'A' || cv->cv_tag[i] > 'Z') && 1288 (cv->cv_tag[i] != '_')) 1289 return (EINVAL); 1290 sv->volid[i] = cv->cv_tag[i]; 1291 } 1292 1293 _lto2b(cv->cv_serial, sv->volseq); 1294 1295 return (0); 1296} 1297