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