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