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