1 /* 2 * Copyright (c) 1997 Justin T. Gibbs. 3 * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer, 11 * without modification, immediately at the beginning of the file. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 /* 30 * Derived from the NetBSD SCSI changer driver. 31 * 32 * $NetBSD: ch.c,v 1.32 1998/01/12 09:49:12 thorpej Exp $ 33 * 34 */ 35 /* 36 * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com> 37 * All rights reserved. 38 * 39 * Partially based on an autochanger driver written by Stefan Grefen 40 * and on an autochanger driver written by the Systems Programming Group 41 * at the University of Utah Computer Science Department. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. All advertising materials mentioning features or use of this software 52 * must display the following acknowledgements: 53 * This product includes software developed by Jason R. Thorpe 54 * for And Communications, http://www.and.com/ 55 * 4. The name of the author may not be used to endorse or promote products 56 * derived from this software without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 59 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 60 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 61 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 62 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 63 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 64 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 65 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 66 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71 #include <sys/param.h> 72 #include <sys/queue.h> 73 #include <sys/systm.h> 74 #include <sys/kernel.h> 75 #include <sys/types.h> 76 #include <sys/malloc.h> 77 #include <sys/fcntl.h> 78 #include <sys/conf.h> 79 #include <sys/chio.h> 80 #include <sys/errno.h> 81 #include <sys/devicestat.h> 82 83 #include <cam/cam.h> 84 #include <cam/cam_ccb.h> 85 #include <cam/cam_periph.h> 86 #include <cam/cam_xpt_periph.h> 87 #include <cam/cam_debug.h> 88 89 #include <cam/scsi/scsi_all.h> 90 #include <cam/scsi/scsi_message.h> 91 #include <cam/scsi/scsi_ch.h> 92 93 /* 94 * Timeout definitions for various changer related commands. They may 95 * be too short for some devices (especially the timeout for INITIALIZE 96 * ELEMENT STATUS). 97 */ 98 99 static const u_int32_t CH_TIMEOUT_MODE_SENSE = 6000; 100 static const u_int32_t CH_TIMEOUT_MOVE_MEDIUM = 100000; 101 static const u_int32_t CH_TIMEOUT_EXCHANGE_MEDIUM = 100000; 102 static const u_int32_t CH_TIMEOUT_POSITION_TO_ELEMENT = 100000; 103 static const u_int32_t CH_TIMEOUT_READ_ELEMENT_STATUS = 10000; 104 static const u_int32_t CH_TIMEOUT_SEND_VOLTAG = 10000; 105 static const u_int32_t CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS = 500000; 106 107 typedef enum { 108 CH_FLAG_INVALID = 0x001, 109 CH_FLAG_OPEN = 0x002 110 } ch_flags; 111 112 typedef enum { 113 CH_STATE_PROBE, 114 CH_STATE_NORMAL 115 } ch_state; 116 117 typedef enum { 118 CH_CCB_PROBE, 119 CH_CCB_WAITING 120 } ch_ccb_types; 121 122 typedef enum { 123 CH_Q_NONE = 0x00, 124 CH_Q_NO_DBD = 0x01 125 } ch_quirks; 126 127 #define ccb_state ppriv_field0 128 #define ccb_bp ppriv_ptr1 129 130 struct scsi_mode_sense_data { 131 struct scsi_mode_header_6 header; 132 struct scsi_mode_blk_desc blk_desc; 133 union { 134 struct page_element_address_assignment ea; 135 struct page_transport_geometry_parameters tg; 136 struct page_device_capabilities cap; 137 } pages; 138 }; 139 140 struct ch_softc { 141 ch_flags flags; 142 ch_state state; 143 ch_quirks quirks; 144 union ccb saved_ccb; 145 struct devstat device_stats; 146 dev_t dev; 147 148 int sc_picker; /* current picker */ 149 150 /* 151 * The following information is obtained from the 152 * element address assignment page. 153 */ 154 int sc_firsts[4]; /* firsts, indexed by CHET_* */ 155 int sc_counts[4]; /* counts, indexed by CHET_* */ 156 157 /* 158 * The following mask defines the legal combinations 159 * of elements for the MOVE MEDIUM command. 160 */ 161 u_int8_t sc_movemask[4]; 162 163 /* 164 * As above, but for EXCHANGE MEDIUM. 165 */ 166 u_int8_t sc_exchangemask[4]; 167 168 /* 169 * Quirks; see below. XXX KDM not implemented yet 170 */ 171 int sc_settledelay; /* delay for settle */ 172 }; 173 174 #define CHUNIT(x) (minor((x))) 175 #define CH_CDEV_MAJOR 17 176 177 static d_open_t chopen; 178 static d_close_t chclose; 179 static d_ioctl_t chioctl; 180 static periph_init_t chinit; 181 static periph_ctor_t chregister; 182 static periph_oninv_t choninvalidate; 183 static periph_dtor_t chcleanup; 184 static periph_start_t chstart; 185 static void chasync(void *callback_arg, u_int32_t code, 186 struct cam_path *path, void *arg); 187 static void chdone(struct cam_periph *periph, 188 union ccb *done_ccb); 189 static int cherror(union ccb *ccb, u_int32_t cam_flags, 190 u_int32_t sense_flags); 191 static int chmove(struct cam_periph *periph, 192 struct changer_move *cm); 193 static int chexchange(struct cam_periph *periph, 194 struct changer_exchange *ce); 195 static int chposition(struct cam_periph *periph, 196 struct changer_position *cp); 197 static int chgetelemstatus(struct cam_periph *periph, 198 struct changer_element_status_request *csr); 199 static int chsetvoltag(struct cam_periph *periph, 200 struct changer_set_voltag_request *csvr); 201 static int chielem(struct cam_periph *periph, 202 unsigned int timeout); 203 static int chgetparams(struct cam_periph *periph); 204 205 static struct periph_driver chdriver = 206 { 207 chinit, "ch", 208 TAILQ_HEAD_INITIALIZER(chdriver.units), /* generation */ 0 209 }; 210 211 PERIPHDRIVER_DECLARE(ch, chdriver); 212 213 static struct cdevsw ch_cdevsw = { 214 .d_open = chopen, 215 .d_close = chclose, 216 .d_ioctl = chioctl, 217 .d_name = "ch", 218 .d_maj = CH_CDEV_MAJOR, 219 }; 220 221 static void 222 chinit(void) 223 { 224 cam_status status; 225 struct cam_path *path; 226 227 /* 228 * Install a global async callback. This callback will 229 * receive async callbacks like "new device found". 230 */ 231 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 232 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 233 234 if (status == CAM_REQ_CMP) { 235 struct ccb_setasync csa; 236 237 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 238 csa.ccb_h.func_code = XPT_SASYNC_CB; 239 csa.event_enable = AC_FOUND_DEVICE; 240 csa.callback = chasync; 241 csa.callback_arg = NULL; 242 xpt_action((union ccb *)&csa); 243 status = csa.ccb_h.status; 244 xpt_free_path(path); 245 } 246 247 if (status != CAM_REQ_CMP) { 248 printf("ch: Failed to attach master async callback " 249 "due to status 0x%x!\n", status); 250 } 251 } 252 253 static void 254 choninvalidate(struct cam_periph *periph) 255 { 256 struct ch_softc *softc; 257 struct ccb_setasync csa; 258 259 softc = (struct ch_softc *)periph->softc; 260 261 /* 262 * De-register any async callbacks. 263 */ 264 xpt_setup_ccb(&csa.ccb_h, periph->path, 265 /* priority */ 5); 266 csa.ccb_h.func_code = XPT_SASYNC_CB; 267 csa.event_enable = 0; 268 csa.callback = chasync; 269 csa.callback_arg = periph; 270 xpt_action((union ccb *)&csa); 271 272 softc->flags |= CH_FLAG_INVALID; 273 274 xpt_print_path(periph->path); 275 printf("lost device\n"); 276 277 } 278 279 static void 280 chcleanup(struct cam_periph *periph) 281 { 282 struct ch_softc *softc; 283 284 softc = (struct ch_softc *)periph->softc; 285 286 devstat_remove_entry(&softc->device_stats); 287 destroy_dev(softc->dev); 288 xpt_print_path(periph->path); 289 printf("removing device entry\n"); 290 free(softc, M_DEVBUF); 291 } 292 293 static void 294 chasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 295 { 296 struct cam_periph *periph; 297 298 periph = (struct cam_periph *)callback_arg; 299 300 switch(code) { 301 case AC_FOUND_DEVICE: 302 { 303 struct ccb_getdev *cgd; 304 cam_status status; 305 306 cgd = (struct ccb_getdev *)arg; 307 if (cgd == NULL) 308 break; 309 310 if (SID_TYPE(&cgd->inq_data)!= T_CHANGER) 311 break; 312 313 /* 314 * Allocate a peripheral instance for 315 * this device and start the probe 316 * process. 317 */ 318 status = cam_periph_alloc(chregister, choninvalidate, 319 chcleanup, chstart, "ch", 320 CAM_PERIPH_BIO, cgd->ccb_h.path, 321 chasync, AC_FOUND_DEVICE, cgd); 322 323 if (status != CAM_REQ_CMP 324 && status != CAM_REQ_INPROG) 325 printf("chasync: Unable to probe new device " 326 "due to status 0x%x\n", status); 327 328 break; 329 330 } 331 default: 332 cam_periph_async(periph, code, path, arg); 333 break; 334 } 335 } 336 337 static cam_status 338 chregister(struct cam_periph *periph, void *arg) 339 { 340 struct ch_softc *softc; 341 struct ccb_setasync csa; 342 struct ccb_getdev *cgd; 343 344 cgd = (struct ccb_getdev *)arg; 345 if (periph == NULL) { 346 printf("chregister: periph was NULL!!\n"); 347 return(CAM_REQ_CMP_ERR); 348 } 349 350 if (cgd == NULL) { 351 printf("chregister: no getdev CCB, can't register device\n"); 352 return(CAM_REQ_CMP_ERR); 353 } 354 355 softc = (struct ch_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 356 357 if (softc == NULL) { 358 printf("chregister: Unable to probe new device. " 359 "Unable to allocate softc\n"); 360 return(CAM_REQ_CMP_ERR); 361 } 362 363 bzero(softc, sizeof(*softc)); 364 softc->state = CH_STATE_PROBE; 365 periph->softc = softc; 366 softc->quirks = CH_Q_NONE; 367 368 /* 369 * Changers don't have a blocksize, and obviously don't support 370 * tagged queueing. 371 */ 372 devstat_add_entry(&softc->device_stats, "ch", 373 periph->unit_number, 0, 374 DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, 375 SID_TYPE(&cgd->inq_data)| DEVSTAT_TYPE_IF_SCSI, 376 DEVSTAT_PRIORITY_OTHER); 377 378 /* Register the device */ 379 softc->dev = make_dev(&ch_cdevsw, periph->unit_number, UID_ROOT, 380 GID_OPERATOR, 0600, "%s%d", periph->periph_name, 381 periph->unit_number); 382 softc->dev->si_drv1 = periph; 383 384 /* 385 * Add an async callback so that we get 386 * notified if this device goes away. 387 */ 388 xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 389 csa.ccb_h.func_code = XPT_SASYNC_CB; 390 csa.event_enable = AC_LOST_DEVICE; 391 csa.callback = chasync; 392 csa.callback_arg = periph; 393 xpt_action((union ccb *)&csa); 394 395 /* 396 * Lock this peripheral until we are setup. 397 * This first call can't block 398 */ 399 (void)cam_periph_lock(periph, PRIBIO); 400 xpt_schedule(periph, /*priority*/5); 401 402 return(CAM_REQ_CMP); 403 } 404 405 static int 406 chopen(dev_t dev, int flags, int fmt, struct thread *td) 407 { 408 struct cam_periph *periph; 409 struct ch_softc *softc; 410 int error; 411 int s; 412 413 periph = (struct cam_periph *)dev->si_drv1; 414 if (periph == NULL) 415 return(ENXIO); 416 417 softc = (struct ch_softc *)periph->softc; 418 419 s = splsoftcam(); 420 if (softc->flags & CH_FLAG_INVALID) { 421 splx(s); 422 return(ENXIO); 423 } 424 425 if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 426 splx(s); 427 return (error); 428 } 429 430 splx(s); 431 432 if ((softc->flags & CH_FLAG_OPEN) == 0) { 433 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 434 return(ENXIO); 435 softc->flags |= CH_FLAG_OPEN; 436 } 437 438 /* 439 * Load information about this changer device into the softc. 440 */ 441 if ((error = chgetparams(periph)) != 0) { 442 softc->flags &= ~CH_FLAG_OPEN; 443 cam_periph_unlock(periph); 444 cam_periph_release(periph); 445 return(error); 446 } 447 448 cam_periph_unlock(periph); 449 450 return(error); 451 } 452 453 static int 454 chclose(dev_t dev, int flag, int fmt, struct thread *td) 455 { 456 struct cam_periph *periph; 457 struct ch_softc *softc; 458 int error; 459 460 error = 0; 461 462 periph = (struct cam_periph *)dev->si_drv1; 463 if (periph == NULL) 464 return(ENXIO); 465 466 softc = (struct ch_softc *)periph->softc; 467 468 if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 469 return(error); 470 471 softc->flags &= ~CH_FLAG_OPEN; 472 473 cam_periph_unlock(periph); 474 cam_periph_release(periph); 475 476 return(0); 477 } 478 479 static void 480 chstart(struct cam_periph *periph, union ccb *start_ccb) 481 { 482 struct ch_softc *softc; 483 int s; 484 485 softc = (struct ch_softc *)periph->softc; 486 487 switch (softc->state) { 488 case CH_STATE_NORMAL: 489 { 490 s = splbio(); 491 if (periph->immediate_priority <= periph->pinfo.priority){ 492 start_ccb->ccb_h.ccb_state = CH_CCB_WAITING; 493 494 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 495 periph_links.sle); 496 periph->immediate_priority = CAM_PRIORITY_NONE; 497 splx(s); 498 wakeup(&periph->ccb_list); 499 } else 500 splx(s); 501 break; 502 } 503 case CH_STATE_PROBE: 504 { 505 int mode_buffer_len; 506 void *mode_buffer; 507 508 /* 509 * Include the block descriptor when calculating the mode 510 * buffer length, 511 */ 512 mode_buffer_len = sizeof(struct scsi_mode_header_6) + 513 sizeof(struct scsi_mode_blk_desc) + 514 sizeof(struct page_element_address_assignment); 515 516 mode_buffer = malloc(mode_buffer_len, M_TEMP, M_NOWAIT); 517 518 if (mode_buffer == NULL) { 519 printf("chstart: couldn't malloc mode sense data\n"); 520 break; 521 } 522 bzero(mode_buffer, mode_buffer_len); 523 524 /* 525 * Get the element address assignment page. 526 */ 527 scsi_mode_sense(&start_ccb->csio, 528 /* retries */ 1, 529 /* cbfcnp */ chdone, 530 /* tag_action */ MSG_SIMPLE_Q_TAG, 531 /* dbd */ (softc->quirks & CH_Q_NO_DBD) ? 532 FALSE : TRUE, 533 /* page_code */ SMS_PAGE_CTRL_CURRENT, 534 /* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE, 535 /* param_buf */ (u_int8_t *)mode_buffer, 536 /* param_len */ mode_buffer_len, 537 /* sense_len */ SSD_FULL_SIZE, 538 /* timeout */ CH_TIMEOUT_MODE_SENSE); 539 540 start_ccb->ccb_h.ccb_bp = NULL; 541 start_ccb->ccb_h.ccb_state = CH_CCB_PROBE; 542 xpt_action(start_ccb); 543 break; 544 } 545 } 546 } 547 548 static void 549 chdone(struct cam_periph *periph, union ccb *done_ccb) 550 { 551 struct ch_softc *softc; 552 struct ccb_scsiio *csio; 553 554 softc = (struct ch_softc *)periph->softc; 555 csio = &done_ccb->csio; 556 557 switch(done_ccb->ccb_h.ccb_state) { 558 case CH_CCB_PROBE: 559 { 560 struct scsi_mode_header_6 *mode_header; 561 struct page_element_address_assignment *ea; 562 char announce_buf[80]; 563 564 565 mode_header = (struct scsi_mode_header_6 *)csio->data_ptr; 566 567 ea = (struct page_element_address_assignment *) 568 find_mode_page_6(mode_header); 569 570 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP){ 571 572 softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea); 573 softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte); 574 softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea); 575 softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse); 576 softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea); 577 softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee); 578 softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea); 579 softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte); 580 softc->sc_picker = softc->sc_firsts[CHET_MT]; 581 582 #define PLURAL(c) (c) == 1 ? "" : "s" 583 snprintf(announce_buf, sizeof(announce_buf), 584 "%d slot%s, %d drive%s, " 585 "%d picker%s, %d portal%s", 586 softc->sc_counts[CHET_ST], 587 PLURAL(softc->sc_counts[CHET_ST]), 588 softc->sc_counts[CHET_DT], 589 PLURAL(softc->sc_counts[CHET_DT]), 590 softc->sc_counts[CHET_MT], 591 PLURAL(softc->sc_counts[CHET_MT]), 592 softc->sc_counts[CHET_IE], 593 PLURAL(softc->sc_counts[CHET_IE])); 594 #undef PLURAL 595 } else { 596 int error; 597 598 error = cherror(done_ccb, CAM_RETRY_SELTO, 599 SF_RETRY_UA | SF_NO_PRINT); 600 /* 601 * Retry any UNIT ATTENTION type errors. They 602 * are expected at boot. 603 */ 604 if (error == ERESTART) { 605 /* 606 * A retry was scheuled, so 607 * just return. 608 */ 609 return; 610 } else if (error != 0) { 611 int retry_scheduled; 612 struct scsi_mode_sense_6 *sms; 613 614 sms = (struct scsi_mode_sense_6 *) 615 done_ccb->csio.cdb_io.cdb_bytes; 616 617 /* 618 * Check to see if block descriptors were 619 * disabled. Some devices don't like that. 620 * We're taking advantage of the fact that 621 * the first few bytes of the 6 and 10 byte 622 * mode sense commands are the same. If 623 * block descriptors were disabled, enable 624 * them and re-send the command. 625 */ 626 if (sms->byte2 & SMS_DBD) { 627 sms->byte2 &= ~SMS_DBD; 628 xpt_action(done_ccb); 629 softc->quirks |= CH_Q_NO_DBD; 630 retry_scheduled = 1; 631 } else 632 retry_scheduled = 0; 633 634 /* Don't wedge this device's queue */ 635 cam_release_devq(done_ccb->ccb_h.path, 636 /*relsim_flags*/0, 637 /*reduction*/0, 638 /*timeout*/0, 639 /*getcount_only*/0); 640 641 if (retry_scheduled) 642 return; 643 644 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) 645 == CAM_SCSI_STATUS_ERROR) 646 scsi_sense_print(&done_ccb->csio); 647 else { 648 xpt_print_path(periph->path); 649 printf("got CAM status %#x\n", 650 done_ccb->ccb_h.status); 651 } 652 xpt_print_path(periph->path); 653 printf("fatal error, failed to attach to" 654 " device\n"); 655 656 cam_periph_invalidate(periph); 657 658 announce_buf[0] = '\0'; 659 } 660 } 661 if (announce_buf[0] != '\0') 662 xpt_announce_periph(periph, announce_buf); 663 softc->state = CH_STATE_NORMAL; 664 free(mode_header, M_TEMP); 665 /* 666 * Since our peripheral may be invalidated by an error 667 * above or an external event, we must release our CCB 668 * before releasing the probe lock on the peripheral. 669 * The peripheral will only go away once the last lock 670 * is removed, and we need it around for the CCB release 671 * operation. 672 */ 673 xpt_release_ccb(done_ccb); 674 cam_periph_unlock(periph); 675 return; 676 } 677 case CH_CCB_WAITING: 678 { 679 /* Caller will release the CCB */ 680 wakeup(&done_ccb->ccb_h.cbfcnp); 681 return; 682 } 683 default: 684 break; 685 } 686 xpt_release_ccb(done_ccb); 687 } 688 689 static int 690 cherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 691 { 692 struct ch_softc *softc; 693 struct cam_periph *periph; 694 695 periph = xpt_path_periph(ccb->ccb_h.path); 696 softc = (struct ch_softc *)periph->softc; 697 698 return (cam_periph_error(ccb, cam_flags, sense_flags, 699 &softc->saved_ccb)); 700 } 701 702 static int 703 chioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 704 { 705 struct cam_periph *periph; 706 struct ch_softc *softc; 707 int error; 708 709 periph = (struct cam_periph *)dev->si_drv1; 710 if (periph == NULL) 711 return(ENXIO); 712 713 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering chioctl\n")); 714 715 softc = (struct ch_softc *)periph->softc; 716 717 error = 0; 718 719 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 720 ("trying to do ioctl %#lx\n", cmd)); 721 722 /* 723 * If this command can change the device's state, we must 724 * have the device open for writing. 725 */ 726 switch (cmd) { 727 case CHIOGPICKER: 728 case CHIOGPARAMS: 729 case CHIOGSTATUS: 730 break; 731 732 default: 733 if ((flag & FWRITE) == 0) 734 return (EBADF); 735 } 736 737 switch (cmd) { 738 case CHIOMOVE: 739 error = chmove(periph, (struct changer_move *)addr); 740 break; 741 742 case CHIOEXCHANGE: 743 error = chexchange(periph, (struct changer_exchange *)addr); 744 break; 745 746 case CHIOPOSITION: 747 error = chposition(periph, (struct changer_position *)addr); 748 break; 749 750 case CHIOGPICKER: 751 *(int *)addr = softc->sc_picker - softc->sc_firsts[CHET_MT]; 752 break; 753 754 case CHIOSPICKER: 755 { 756 int new_picker = *(int *)addr; 757 758 if (new_picker > (softc->sc_counts[CHET_MT] - 1)) 759 return (EINVAL); 760 softc->sc_picker = softc->sc_firsts[CHET_MT] + new_picker; 761 break; 762 } 763 case CHIOGPARAMS: 764 { 765 struct changer_params *cp = (struct changer_params *)addr; 766 767 cp->cp_npickers = softc->sc_counts[CHET_MT]; 768 cp->cp_nslots = softc->sc_counts[CHET_ST]; 769 cp->cp_nportals = softc->sc_counts[CHET_IE]; 770 cp->cp_ndrives = softc->sc_counts[CHET_DT]; 771 break; 772 } 773 case CHIOIELEM: 774 error = chielem(periph, *(unsigned int *)addr); 775 break; 776 777 case CHIOGSTATUS: 778 { 779 error = chgetelemstatus(periph, 780 (struct changer_element_status_request *) addr); 781 break; 782 } 783 784 case CHIOSETVOLTAG: 785 { 786 error = chsetvoltag(periph, 787 (struct changer_set_voltag_request *) addr); 788 break; 789 } 790 791 /* Implement prevent/allow? */ 792 793 default: 794 error = cam_periph_ioctl(periph, cmd, addr, cherror); 795 break; 796 } 797 798 return (error); 799 } 800 801 static int 802 chmove(struct cam_periph *periph, struct changer_move *cm) 803 { 804 struct ch_softc *softc; 805 u_int16_t fromelem, toelem; 806 union ccb *ccb; 807 int error; 808 809 error = 0; 810 softc = (struct ch_softc *)periph->softc; 811 812 /* 813 * Check arguments. 814 */ 815 if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT)) 816 return (EINVAL); 817 if ((cm->cm_fromunit > (softc->sc_counts[cm->cm_fromtype] - 1)) || 818 (cm->cm_tounit > (softc->sc_counts[cm->cm_totype] - 1))) 819 return (ENODEV); 820 821 /* 822 * Check the request against the changer's capabilities. 823 */ 824 if ((softc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0) 825 return (ENODEV); 826 827 /* 828 * Calculate the source and destination elements. 829 */ 830 fromelem = softc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit; 831 toelem = softc->sc_firsts[cm->cm_totype] + cm->cm_tounit; 832 833 ccb = cam_periph_getccb(periph, /*priority*/ 1); 834 835 scsi_move_medium(&ccb->csio, 836 /* retries */ 1, 837 /* cbfcnp */ chdone, 838 /* tag_action */ MSG_SIMPLE_Q_TAG, 839 /* tea */ softc->sc_picker, 840 /* src */ fromelem, 841 /* dst */ toelem, 842 /* invert */ (cm->cm_flags & CM_INVERT) ? TRUE : FALSE, 843 /* sense_len */ SSD_FULL_SIZE, 844 /* timeout */ CH_TIMEOUT_MOVE_MEDIUM); 845 846 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO, 847 /*sense_flags*/ SF_RETRY_UA, 848 &softc->device_stats); 849 850 xpt_release_ccb(ccb); 851 852 return(error); 853 } 854 855 static int 856 chexchange(struct cam_periph *periph, struct changer_exchange *ce) 857 { 858 struct ch_softc *softc; 859 u_int16_t src, dst1, dst2; 860 union ccb *ccb; 861 int error; 862 863 error = 0; 864 softc = (struct ch_softc *)periph->softc; 865 /* 866 * Check arguments. 867 */ 868 if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) || 869 (ce->ce_sdsttype > CHET_DT)) 870 return (EINVAL); 871 if ((ce->ce_srcunit > (softc->sc_counts[ce->ce_srctype] - 1)) || 872 (ce->ce_fdstunit > (softc->sc_counts[ce->ce_fdsttype] - 1)) || 873 (ce->ce_sdstunit > (softc->sc_counts[ce->ce_sdsttype] - 1))) 874 return (ENODEV); 875 876 /* 877 * Check the request against the changer's capabilities. 878 */ 879 if (((softc->sc_exchangemask[ce->ce_srctype] & 880 (1 << ce->ce_fdsttype)) == 0) || 881 ((softc->sc_exchangemask[ce->ce_fdsttype] & 882 (1 << ce->ce_sdsttype)) == 0)) 883 return (ENODEV); 884 885 /* 886 * Calculate the source and destination elements. 887 */ 888 src = softc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit; 889 dst1 = softc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit; 890 dst2 = softc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit; 891 892 ccb = cam_periph_getccb(periph, /*priority*/ 1); 893 894 scsi_exchange_medium(&ccb->csio, 895 /* retries */ 1, 896 /* cbfcnp */ chdone, 897 /* tag_action */ MSG_SIMPLE_Q_TAG, 898 /* tea */ softc->sc_picker, 899 /* src */ src, 900 /* dst1 */ dst1, 901 /* dst2 */ dst2, 902 /* invert1 */ (ce->ce_flags & CE_INVERT1) ? 903 TRUE : FALSE, 904 /* invert2 */ (ce->ce_flags & CE_INVERT2) ? 905 TRUE : FALSE, 906 /* sense_len */ SSD_FULL_SIZE, 907 /* timeout */ CH_TIMEOUT_EXCHANGE_MEDIUM); 908 909 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO, 910 /*sense_flags*/ SF_RETRY_UA, 911 &softc->device_stats); 912 913 xpt_release_ccb(ccb); 914 915 return(error); 916 } 917 918 static int 919 chposition(struct cam_periph *periph, struct changer_position *cp) 920 { 921 struct ch_softc *softc; 922 u_int16_t dst; 923 union ccb *ccb; 924 int error; 925 926 error = 0; 927 softc = (struct ch_softc *)periph->softc; 928 929 /* 930 * Check arguments. 931 */ 932 if (cp->cp_type > CHET_DT) 933 return (EINVAL); 934 if (cp->cp_unit > (softc->sc_counts[cp->cp_type] - 1)) 935 return (ENODEV); 936 937 /* 938 * Calculate the destination element. 939 */ 940 dst = softc->sc_firsts[cp->cp_type] + cp->cp_unit; 941 942 ccb = cam_periph_getccb(periph, /*priority*/ 1); 943 944 scsi_position_to_element(&ccb->csio, 945 /* retries */ 1, 946 /* cbfcnp */ chdone, 947 /* tag_action */ MSG_SIMPLE_Q_TAG, 948 /* tea */ softc->sc_picker, 949 /* dst */ dst, 950 /* invert */ (cp->cp_flags & CP_INVERT) ? 951 TRUE : FALSE, 952 /* sense_len */ SSD_FULL_SIZE, 953 /* timeout */ CH_TIMEOUT_POSITION_TO_ELEMENT); 954 955 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 956 /*sense_flags*/ SF_RETRY_UA, 957 &softc->device_stats); 958 959 xpt_release_ccb(ccb); 960 961 return(error); 962 } 963 964 /* 965 * Copy a volume tag to a volume_tag struct, converting SCSI byte order 966 * to host native byte order in the volume serial number. The volume 967 * label as returned by the changer is transferred to user mode as 968 * nul-terminated string. Volume labels are truncated at the first 969 * space, as suggested by SCSI-2. 970 */ 971 static void 972 copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag) 973 { 974 int i; 975 for (i=0; i<CH_VOLTAG_MAXLEN; i++) { 976 char c = voltag->vif[i]; 977 if (c && c != ' ') 978 uvoltag->cv_volid[i] = c; 979 else 980 break; 981 } 982 uvoltag->cv_serial = scsi_2btoul(voltag->vsn); 983 } 984 985 /* 986 * Copy an an element status descriptor to a user-mode 987 * changer_element_status structure. 988 */ 989 990 static void 991 copy_element_status(struct ch_softc *softc, 992 u_int16_t flags, 993 struct read_element_status_descriptor *desc, 994 struct changer_element_status *ces) 995 { 996 u_int16_t eaddr = scsi_2btoul(desc->eaddr); 997 u_int16_t et; 998 999 ces->ces_int_addr = eaddr; 1000 /* set up logical address in element status */ 1001 for (et = CHET_MT; et <= CHET_DT; et++) { 1002 if ((softc->sc_firsts[et] <= eaddr) 1003 && ((softc->sc_firsts[et] + softc->sc_counts[et]) 1004 > eaddr)) { 1005 ces->ces_addr = eaddr - softc->sc_firsts[et]; 1006 ces->ces_type = et; 1007 break; 1008 } 1009 } 1010 1011 ces->ces_flags = desc->flags1; 1012 1013 ces->ces_sensecode = desc->sense_code; 1014 ces->ces_sensequal = desc->sense_qual; 1015 1016 if (desc->flags2 & READ_ELEMENT_STATUS_INVERT) 1017 ces->ces_flags |= CES_INVERT; 1018 1019 if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) { 1020 1021 eaddr = scsi_2btoul(desc->ssea); 1022 1023 /* convert source address to logical format */ 1024 for (et = CHET_MT; et <= CHET_DT; et++) { 1025 if ((softc->sc_firsts[et] <= eaddr) 1026 && ((softc->sc_firsts[et] + softc->sc_counts[et]) 1027 > eaddr)) { 1028 ces->ces_source_addr = 1029 eaddr - softc->sc_firsts[et]; 1030 ces->ces_source_type = et; 1031 ces->ces_flags |= CES_SOURCE_VALID; 1032 break; 1033 } 1034 } 1035 1036 if (!(ces->ces_flags & CES_SOURCE_VALID)) 1037 printf("ch: warning: could not map element source " 1038 "address %ud to a valid element type\n", 1039 eaddr); 1040 } 1041 1042 1043 if (flags & READ_ELEMENT_STATUS_PVOLTAG) 1044 copy_voltag(&(ces->ces_pvoltag), &(desc->pvoltag)); 1045 if (flags & READ_ELEMENT_STATUS_AVOLTAG) 1046 copy_voltag(&(ces->ces_avoltag), &(desc->avoltag)); 1047 1048 if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_IDVALID) { 1049 ces->ces_flags |= CES_SCSIID_VALID; 1050 ces->ces_scsi_id = desc->dt_scsi_addr; 1051 } 1052 1053 if (desc->dt_scsi_addr & READ_ELEMENT_STATUS_DT_LUVALID) { 1054 ces->ces_flags |= CES_LUN_VALID; 1055 ces->ces_scsi_lun = 1056 desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_LUNMASK; 1057 } 1058 } 1059 1060 static int 1061 chgetelemstatus(struct cam_periph *periph, 1062 struct changer_element_status_request *cesr) 1063 { 1064 struct read_element_status_header *st_hdr; 1065 struct read_element_status_page_header *pg_hdr; 1066 struct read_element_status_descriptor *desc; 1067 caddr_t data = NULL; 1068 size_t size, desclen; 1069 int avail, i, error = 0; 1070 struct changer_element_status *user_data = NULL; 1071 struct ch_softc *softc; 1072 union ccb *ccb; 1073 int chet = cesr->cesr_element_type; 1074 int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0; 1075 1076 softc = (struct ch_softc *)periph->softc; 1077 1078 /* perform argument checking */ 1079 1080 /* 1081 * Perform a range check on the cesr_element_{base,count} 1082 * request argument fields. 1083 */ 1084 if ((softc->sc_counts[chet] - cesr->cesr_element_base) <= 0 1085 || (cesr->cesr_element_base + cesr->cesr_element_count) 1086 > softc->sc_counts[chet]) 1087 return (EINVAL); 1088 1089 /* 1090 * Request one descriptor for the given element type. This 1091 * is used to determine the size of the descriptor so that 1092 * we can allocate enough storage for all of them. We assume 1093 * that the first one can fit into 1k. 1094 */ 1095 data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK); 1096 1097 ccb = cam_periph_getccb(periph, /*priority*/ 1); 1098 1099 scsi_read_element_status(&ccb->csio, 1100 /* retries */ 1, 1101 /* cbfcnp */ chdone, 1102 /* tag_action */ MSG_SIMPLE_Q_TAG, 1103 /* voltag */ want_voltags, 1104 /* sea */ softc->sc_firsts[chet], 1105 /* count */ 1, 1106 /* data_ptr */ data, 1107 /* dxfer_len */ 1024, 1108 /* sense_len */ SSD_FULL_SIZE, 1109 /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS); 1110 1111 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 1112 /*sense_flags*/ SF_RETRY_UA, 1113 &softc->device_stats); 1114 1115 if (error) 1116 goto done; 1117 1118 st_hdr = (struct read_element_status_header *)data; 1119 pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr + 1120 sizeof(struct read_element_status_header)); 1121 desclen = scsi_2btoul(pg_hdr->edl); 1122 1123 size = sizeof(struct read_element_status_header) + 1124 sizeof(struct read_element_status_page_header) + 1125 (desclen * cesr->cesr_element_count); 1126 1127 /* 1128 * Reallocate storage for descriptors and get them from the 1129 * device. 1130 */ 1131 free(data, M_DEVBUF); 1132 data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK); 1133 1134 scsi_read_element_status(&ccb->csio, 1135 /* retries */ 1, 1136 /* cbfcnp */ chdone, 1137 /* tag_action */ MSG_SIMPLE_Q_TAG, 1138 /* voltag */ want_voltags, 1139 /* sea */ softc->sc_firsts[chet] 1140 + cesr->cesr_element_base, 1141 /* count */ cesr->cesr_element_count, 1142 /* data_ptr */ data, 1143 /* dxfer_len */ size, 1144 /* sense_len */ SSD_FULL_SIZE, 1145 /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS); 1146 1147 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 1148 /*sense_flags*/ SF_RETRY_UA, 1149 &softc->device_stats); 1150 1151 if (error) 1152 goto done; 1153 1154 /* 1155 * Fill in the user status array. 1156 */ 1157 st_hdr = (struct read_element_status_header *)data; 1158 avail = scsi_2btoul(st_hdr->count); 1159 1160 if (avail != cesr->cesr_element_count) { 1161 xpt_print_path(periph->path); 1162 printf("warning, READ ELEMENT STATUS avail != count\n"); 1163 } 1164 1165 user_data = (struct changer_element_status *) 1166 malloc(avail * sizeof(struct changer_element_status), 1167 M_DEVBUF, M_WAITOK | M_ZERO); 1168 1169 desc = (struct read_element_status_descriptor *)((uintptr_t)data + 1170 sizeof(struct read_element_status_header) + 1171 sizeof(struct read_element_status_page_header)); 1172 /* 1173 * Set up the individual element status structures 1174 */ 1175 for (i = 0; i < avail; ++i) { 1176 struct changer_element_status *ces = &(user_data[i]); 1177 1178 copy_element_status(softc, pg_hdr->flags, desc, ces); 1179 1180 desc = (struct read_element_status_descriptor *) 1181 ((uintptr_t)desc + desclen); 1182 } 1183 1184 /* Copy element status structures out to userspace. */ 1185 error = copyout(user_data, 1186 cesr->cesr_element_status, 1187 avail * sizeof(struct changer_element_status)); 1188 1189 done: 1190 xpt_release_ccb(ccb); 1191 1192 if (data != NULL) 1193 free(data, M_DEVBUF); 1194 if (user_data != NULL) 1195 free(user_data, M_DEVBUF); 1196 1197 return (error); 1198 } 1199 1200 static int 1201 chielem(struct cam_periph *periph, 1202 unsigned int timeout) 1203 { 1204 union ccb *ccb; 1205 struct ch_softc *softc; 1206 int error; 1207 1208 if (!timeout) { 1209 timeout = CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS; 1210 } else { 1211 timeout *= 1000; 1212 } 1213 1214 error = 0; 1215 softc = (struct ch_softc *)periph->softc; 1216 1217 ccb = cam_periph_getccb(periph, /*priority*/ 1); 1218 1219 scsi_initialize_element_status(&ccb->csio, 1220 /* retries */ 1, 1221 /* cbfcnp */ chdone, 1222 /* tag_action */ MSG_SIMPLE_Q_TAG, 1223 /* sense_len */ SSD_FULL_SIZE, 1224 /* timeout */ timeout); 1225 1226 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 1227 /*sense_flags*/ SF_RETRY_UA, 1228 &softc->device_stats); 1229 1230 xpt_release_ccb(ccb); 1231 1232 return(error); 1233 } 1234 1235 static int 1236 chsetvoltag(struct cam_periph *periph, 1237 struct changer_set_voltag_request *csvr) 1238 { 1239 union ccb *ccb; 1240 struct ch_softc *softc; 1241 u_int16_t ea; 1242 u_int8_t sac; 1243 struct scsi_send_volume_tag_parameters ssvtp; 1244 int error; 1245 int i; 1246 1247 error = 0; 1248 softc = (struct ch_softc *)periph->softc; 1249 1250 bzero(&ssvtp, sizeof(ssvtp)); 1251 for (i=0; i<sizeof(ssvtp.vitf); i++) { 1252 ssvtp.vitf[i] = ' '; 1253 } 1254 1255 /* 1256 * Check arguments. 1257 */ 1258 if (csvr->csvr_type > CHET_DT) 1259 return EINVAL; 1260 if (csvr->csvr_addr > (softc->sc_counts[csvr->csvr_type] - 1)) 1261 return ENODEV; 1262 1263 ea = softc->sc_firsts[csvr->csvr_type] + csvr->csvr_addr; 1264 1265 if (csvr->csvr_flags & CSVR_ALTERNATE) { 1266 switch (csvr->csvr_flags & CSVR_MODE_MASK) { 1267 case CSVR_MODE_SET: 1268 sac = SEND_VOLUME_TAG_ASSERT_ALTERNATE; 1269 break; 1270 case CSVR_MODE_REPLACE: 1271 sac = SEND_VOLUME_TAG_REPLACE_ALTERNATE; 1272 break; 1273 case CSVR_MODE_CLEAR: 1274 sac = SEND_VOLUME_TAG_UNDEFINED_ALTERNATE; 1275 break; 1276 default: 1277 error = EINVAL; 1278 goto out; 1279 } 1280 } else { 1281 switch (csvr->csvr_flags & CSVR_MODE_MASK) { 1282 case CSVR_MODE_SET: 1283 sac = SEND_VOLUME_TAG_ASSERT_PRIMARY; 1284 break; 1285 case CSVR_MODE_REPLACE: 1286 sac = SEND_VOLUME_TAG_REPLACE_PRIMARY; 1287 break; 1288 case CSVR_MODE_CLEAR: 1289 sac = SEND_VOLUME_TAG_UNDEFINED_PRIMARY; 1290 break; 1291 default: 1292 error = EINVAL; 1293 goto out; 1294 } 1295 } 1296 1297 memcpy(ssvtp.vitf, csvr->csvr_voltag.cv_volid, 1298 min(strlen(csvr->csvr_voltag.cv_volid), sizeof(ssvtp.vitf))); 1299 scsi_ulto2b(csvr->csvr_voltag.cv_serial, ssvtp.minvsn); 1300 1301 ccb = cam_periph_getccb(periph, /*priority*/ 1); 1302 1303 scsi_send_volume_tag(&ccb->csio, 1304 /* retries */ 1, 1305 /* cbfcnp */ chdone, 1306 /* tag_action */ MSG_SIMPLE_Q_TAG, 1307 /* element_address */ ea, 1308 /* send_action_code */ sac, 1309 /* parameters */ &ssvtp, 1310 /* sense_len */ SSD_FULL_SIZE, 1311 /* timeout */ CH_TIMEOUT_SEND_VOLTAG); 1312 1313 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 1314 /*sense_flags*/ SF_RETRY_UA, 1315 &softc->device_stats); 1316 1317 xpt_release_ccb(ccb); 1318 1319 out: 1320 return error; 1321 } 1322 1323 static int 1324 chgetparams(struct cam_periph *periph) 1325 { 1326 union ccb *ccb; 1327 struct ch_softc *softc; 1328 void *mode_buffer; 1329 int mode_buffer_len; 1330 struct page_element_address_assignment *ea; 1331 struct page_device_capabilities *cap; 1332 int error, from, dbd; 1333 u_int8_t *moves, *exchanges; 1334 1335 error = 0; 1336 1337 softc = (struct ch_softc *)periph->softc; 1338 1339 ccb = cam_periph_getccb(periph, /*priority*/ 1); 1340 1341 /* 1342 * The scsi_mode_sense_data structure is just a convenience 1343 * structure that allows us to easily calculate the worst-case 1344 * storage size of the mode sense buffer. 1345 */ 1346 mode_buffer_len = sizeof(struct scsi_mode_sense_data); 1347 1348 mode_buffer = malloc(mode_buffer_len, M_TEMP, M_NOWAIT); 1349 1350 if (mode_buffer == NULL) { 1351 printf("chgetparams: couldn't malloc mode sense data\n"); 1352 return(ENOSPC); 1353 } 1354 1355 bzero(mode_buffer, mode_buffer_len); 1356 1357 if (softc->quirks & CH_Q_NO_DBD) 1358 dbd = FALSE; 1359 else 1360 dbd = TRUE; 1361 1362 /* 1363 * Get the element address assignment page. 1364 */ 1365 scsi_mode_sense(&ccb->csio, 1366 /* retries */ 1, 1367 /* cbfcnp */ chdone, 1368 /* tag_action */ MSG_SIMPLE_Q_TAG, 1369 /* dbd */ dbd, 1370 /* page_code */ SMS_PAGE_CTRL_CURRENT, 1371 /* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE, 1372 /* param_buf */ (u_int8_t *)mode_buffer, 1373 /* param_len */ mode_buffer_len, 1374 /* sense_len */ SSD_FULL_SIZE, 1375 /* timeout */ CH_TIMEOUT_MODE_SENSE); 1376 1377 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 1378 /* sense_flags */ SF_RETRY_UA|SF_NO_PRINT, 1379 &softc->device_stats); 1380 1381 if (error) { 1382 if (dbd) { 1383 struct scsi_mode_sense_6 *sms; 1384 1385 sms = (struct scsi_mode_sense_6 *) 1386 ccb->csio.cdb_io.cdb_bytes; 1387 1388 sms->byte2 &= ~SMS_DBD; 1389 error = cam_periph_runccb(ccb, cherror, 1390 /*cam_flags*/ CAM_RETRY_SELTO, 1391 /*sense_flags*/ SF_RETRY_UA, 1392 &softc->device_stats); 1393 } else { 1394 /* 1395 * Since we disabled sense printing above, print 1396 * out the sense here since we got an error. 1397 */ 1398 scsi_sense_print(&ccb->csio); 1399 } 1400 1401 if (error) { 1402 xpt_print_path(periph->path); 1403 printf("chgetparams: error getting element " 1404 "address page\n"); 1405 xpt_release_ccb(ccb); 1406 free(mode_buffer, M_TEMP); 1407 return(error); 1408 } 1409 } 1410 1411 ea = (struct page_element_address_assignment *) 1412 find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer); 1413 1414 softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea); 1415 softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte); 1416 softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea); 1417 softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse); 1418 softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea); 1419 softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee); 1420 softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea); 1421 softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte); 1422 1423 bzero(mode_buffer, mode_buffer_len); 1424 1425 /* 1426 * Now get the device capabilities page. 1427 */ 1428 scsi_mode_sense(&ccb->csio, 1429 /* retries */ 1, 1430 /* cbfcnp */ chdone, 1431 /* tag_action */ MSG_SIMPLE_Q_TAG, 1432 /* dbd */ dbd, 1433 /* page_code */ SMS_PAGE_CTRL_CURRENT, 1434 /* page */ CH_DEVICE_CAP_PAGE, 1435 /* param_buf */ (u_int8_t *)mode_buffer, 1436 /* param_len */ mode_buffer_len, 1437 /* sense_len */ SSD_FULL_SIZE, 1438 /* timeout */ CH_TIMEOUT_MODE_SENSE); 1439 1440 error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO, 1441 /* sense_flags */ SF_RETRY_UA | SF_NO_PRINT, 1442 &softc->device_stats); 1443 1444 if (error) { 1445 if (dbd) { 1446 struct scsi_mode_sense_6 *sms; 1447 1448 sms = (struct scsi_mode_sense_6 *) 1449 ccb->csio.cdb_io.cdb_bytes; 1450 1451 sms->byte2 &= ~SMS_DBD; 1452 error = cam_periph_runccb(ccb, cherror, 1453 /*cam_flags*/ CAM_RETRY_SELTO, 1454 /*sense_flags*/ SF_RETRY_UA, 1455 &softc->device_stats); 1456 } else { 1457 /* 1458 * Since we disabled sense printing above, print 1459 * out the sense here since we got an error. 1460 */ 1461 scsi_sense_print(&ccb->csio); 1462 } 1463 1464 if (error) { 1465 xpt_print_path(periph->path); 1466 printf("chgetparams: error getting device " 1467 "capabilities page\n"); 1468 xpt_release_ccb(ccb); 1469 free(mode_buffer, M_TEMP); 1470 return(error); 1471 } 1472 } 1473 1474 xpt_release_ccb(ccb); 1475 1476 cap = (struct page_device_capabilities *) 1477 find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer); 1478 1479 bzero(softc->sc_movemask, sizeof(softc->sc_movemask)); 1480 bzero(softc->sc_exchangemask, sizeof(softc->sc_exchangemask)); 1481 moves = &cap->move_from_mt; 1482 exchanges = &cap->exchange_with_mt; 1483 for (from = CHET_MT; from <= CHET_DT; ++from) { 1484 softc->sc_movemask[from] = moves[from]; 1485 softc->sc_exchangemask[from] = exchanges[from]; 1486 } 1487 1488 free(mode_buffer, M_TEMP); 1489 1490 return(error); 1491 } 1492 1493 void 1494 scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries, 1495 void (*cbfcnp)(struct cam_periph *, union ccb *), 1496 u_int8_t tag_action, u_int32_t tea, u_int32_t src, 1497 u_int32_t dst, int invert, u_int8_t sense_len, 1498 u_int32_t timeout) 1499 { 1500 struct scsi_move_medium *scsi_cmd; 1501 1502 scsi_cmd = (struct scsi_move_medium *)&csio->cdb_io.cdb_bytes; 1503 bzero(scsi_cmd, sizeof(*scsi_cmd)); 1504 1505 scsi_cmd->opcode = MOVE_MEDIUM; 1506 1507 scsi_ulto2b(tea, scsi_cmd->tea); 1508 scsi_ulto2b(src, scsi_cmd->src); 1509 scsi_ulto2b(dst, scsi_cmd->dst); 1510 1511 if (invert) 1512 scsi_cmd->invert |= MOVE_MEDIUM_INVERT; 1513 1514 cam_fill_csio(csio, 1515 retries, 1516 cbfcnp, 1517 /*flags*/ CAM_DIR_NONE, 1518 tag_action, 1519 /*data_ptr*/ NULL, 1520 /*dxfer_len*/ 0, 1521 sense_len, 1522 sizeof(*scsi_cmd), 1523 timeout); 1524 } 1525 1526 void 1527 scsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries, 1528 void (*cbfcnp)(struct cam_periph *, union ccb *), 1529 u_int8_t tag_action, u_int32_t tea, u_int32_t src, 1530 u_int32_t dst1, u_int32_t dst2, int invert1, 1531 int invert2, u_int8_t sense_len, u_int32_t timeout) 1532 { 1533 struct scsi_exchange_medium *scsi_cmd; 1534 1535 scsi_cmd = (struct scsi_exchange_medium *)&csio->cdb_io.cdb_bytes; 1536 bzero(scsi_cmd, sizeof(*scsi_cmd)); 1537 1538 scsi_cmd->opcode = EXCHANGE_MEDIUM; 1539 1540 scsi_ulto2b(tea, scsi_cmd->tea); 1541 scsi_ulto2b(src, scsi_cmd->src); 1542 scsi_ulto2b(dst1, scsi_cmd->fdst); 1543 scsi_ulto2b(dst2, scsi_cmd->sdst); 1544 1545 if (invert1) 1546 scsi_cmd->invert |= EXCHANGE_MEDIUM_INV1; 1547 1548 if (invert2) 1549 scsi_cmd->invert |= EXCHANGE_MEDIUM_INV2; 1550 1551 cam_fill_csio(csio, 1552 retries, 1553 cbfcnp, 1554 /*flags*/ CAM_DIR_NONE, 1555 tag_action, 1556 /*data_ptr*/ NULL, 1557 /*dxfer_len*/ 0, 1558 sense_len, 1559 sizeof(*scsi_cmd), 1560 timeout); 1561 } 1562 1563 void 1564 scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries, 1565 void (*cbfcnp)(struct cam_periph *, union ccb *), 1566 u_int8_t tag_action, u_int32_t tea, u_int32_t dst, 1567 int invert, u_int8_t sense_len, u_int32_t timeout) 1568 { 1569 struct scsi_position_to_element *scsi_cmd; 1570 1571 scsi_cmd = (struct scsi_position_to_element *)&csio->cdb_io.cdb_bytes; 1572 bzero(scsi_cmd, sizeof(*scsi_cmd)); 1573 1574 scsi_cmd->opcode = POSITION_TO_ELEMENT; 1575 1576 scsi_ulto2b(tea, scsi_cmd->tea); 1577 scsi_ulto2b(dst, scsi_cmd->dst); 1578 1579 if (invert) 1580 scsi_cmd->invert |= POSITION_TO_ELEMENT_INVERT; 1581 1582 cam_fill_csio(csio, 1583 retries, 1584 cbfcnp, 1585 /*flags*/ CAM_DIR_NONE, 1586 tag_action, 1587 /*data_ptr*/ NULL, 1588 /*dxfer_len*/ 0, 1589 sense_len, 1590 sizeof(*scsi_cmd), 1591 timeout); 1592 } 1593 1594 void 1595 scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries, 1596 void (*cbfcnp)(struct cam_periph *, union ccb *), 1597 u_int8_t tag_action, int voltag, u_int32_t sea, 1598 u_int32_t count, u_int8_t *data_ptr, 1599 u_int32_t dxfer_len, u_int8_t sense_len, 1600 u_int32_t timeout) 1601 { 1602 struct scsi_read_element_status *scsi_cmd; 1603 1604 scsi_cmd = (struct scsi_read_element_status *)&csio->cdb_io.cdb_bytes; 1605 bzero(scsi_cmd, sizeof(*scsi_cmd)); 1606 1607 scsi_cmd->opcode = READ_ELEMENT_STATUS; 1608 1609 scsi_ulto2b(sea, scsi_cmd->sea); 1610 scsi_ulto2b(count, scsi_cmd->count); 1611 scsi_ulto3b(dxfer_len, scsi_cmd->len); 1612 1613 if (voltag) 1614 scsi_cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG; 1615 1616 cam_fill_csio(csio, 1617 retries, 1618 cbfcnp, 1619 /*flags*/ CAM_DIR_IN, 1620 tag_action, 1621 data_ptr, 1622 dxfer_len, 1623 sense_len, 1624 sizeof(*scsi_cmd), 1625 timeout); 1626 } 1627 1628 void 1629 scsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries, 1630 void (*cbfcnp)(struct cam_periph *, union ccb *), 1631 u_int8_t tag_action, u_int8_t sense_len, 1632 u_int32_t timeout) 1633 { 1634 struct scsi_initialize_element_status *scsi_cmd; 1635 1636 scsi_cmd = (struct scsi_initialize_element_status *) 1637 &csio->cdb_io.cdb_bytes; 1638 bzero(scsi_cmd, sizeof(*scsi_cmd)); 1639 1640 scsi_cmd->opcode = INITIALIZE_ELEMENT_STATUS; 1641 1642 cam_fill_csio(csio, 1643 retries, 1644 cbfcnp, 1645 /*flags*/ CAM_DIR_NONE, 1646 tag_action, 1647 /* data_ptr */ NULL, 1648 /* dxfer_len */ 0, 1649 sense_len, 1650 sizeof(*scsi_cmd), 1651 timeout); 1652 } 1653 1654 void 1655 scsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries, 1656 void (*cbfcnp)(struct cam_periph *, union ccb *), 1657 u_int8_t tag_action, 1658 u_int16_t element_address, 1659 u_int8_t send_action_code, 1660 struct scsi_send_volume_tag_parameters *parameters, 1661 u_int8_t sense_len, u_int32_t timeout) 1662 { 1663 struct scsi_send_volume_tag *scsi_cmd; 1664 1665 scsi_cmd = (struct scsi_send_volume_tag *) &csio->cdb_io.cdb_bytes; 1666 bzero(scsi_cmd, sizeof(*scsi_cmd)); 1667 1668 scsi_cmd->opcode = SEND_VOLUME_TAG; 1669 scsi_ulto2b(element_address, scsi_cmd->ea); 1670 scsi_cmd->sac = send_action_code; 1671 scsi_ulto2b(sizeof(*parameters), scsi_cmd->pll); 1672 1673 cam_fill_csio(csio, 1674 retries, 1675 cbfcnp, 1676 /*flags*/ CAM_DIR_OUT, 1677 tag_action, 1678 /* data_ptr */ (u_int8_t *) parameters, 1679 sizeof(*parameters), 1680 sense_len, 1681 sizeof(*scsi_cmd), 1682 timeout); 1683 } 1684