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