1 /* 2 * Copyright (c) 1997, 1998 Justin T. Gibbs. 3 * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer, 11 * without modification, immediately at the beginning of the file. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/types.h> 34 #include <sys/buf.h> 35 #include <sys/malloc.h> 36 #include <sys/fcntl.h> 37 #include <sys/stat.h> 38 #include <sys/conf.h> 39 #include <sys/proc.h> 40 #include <sys/errno.h> 41 #include <sys/devicestat.h> 42 43 #include <cam/cam.h> 44 #include <cam/cam_ccb.h> 45 #include <cam/cam_extend.h> 46 #include <cam/cam_periph.h> 47 #include <cam/cam_xpt_periph.h> 48 #include <cam/cam_debug.h> 49 50 #include <cam/scsi/scsi_all.h> 51 #include <cam/scsi/scsi_message.h> 52 #include <cam/scsi/scsi_da.h> 53 #include <cam/scsi/scsi_pass.h> 54 55 typedef enum { 56 PASS_FLAG_OPEN = 0x01, 57 PASS_FLAG_LOCKED = 0x02, 58 PASS_FLAG_INVALID = 0x04 59 } pass_flags; 60 61 typedef enum { 62 PASS_STATE_NORMAL 63 } pass_state; 64 65 typedef enum { 66 PASS_CCB_BUFFER_IO, 67 PASS_CCB_WAITING 68 } pass_ccb_types; 69 70 #define ccb_type ppriv_field0 71 #define ccb_bp ppriv_ptr1 72 73 struct pass_softc { 74 pass_state state; 75 pass_flags flags; 76 u_int8_t pd_type; 77 struct bio_queue_head bio_queue; 78 union ccb saved_ccb; 79 struct devstat device_stats; 80 dev_t dev; 81 }; 82 83 #ifndef MIN 84 #define MIN(x,y) ((x<y) ? x : y) 85 #endif 86 87 #define PASS_CDEV_MAJOR 31 88 89 static d_open_t passopen; 90 static d_close_t passclose; 91 static d_ioctl_t passioctl; 92 static d_strategy_t passstrategy; 93 94 static periph_init_t passinit; 95 static periph_ctor_t passregister; 96 static periph_oninv_t passoninvalidate; 97 static periph_dtor_t passcleanup; 98 static periph_start_t passstart; 99 static void passasync(void *callback_arg, u_int32_t code, 100 struct cam_path *path, void *arg); 101 static void passdone(struct cam_periph *periph, 102 union ccb *done_ccb); 103 static int passerror(union ccb *ccb, u_int32_t cam_flags, 104 u_int32_t sense_flags); 105 static int passsendccb(struct cam_periph *periph, union ccb *ccb, 106 union ccb *inccb); 107 108 static struct periph_driver passdriver = 109 { 110 passinit, "pass", 111 TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 112 }; 113 114 DATA_SET(periphdriver_set, passdriver); 115 116 static struct cdevsw pass_cdevsw = { 117 /* open */ passopen, 118 /* close */ passclose, 119 /* read */ physread, 120 /* write */ physwrite, 121 /* ioctl */ passioctl, 122 /* poll */ nopoll, 123 /* mmap */ nommap, 124 /* strategy */ passstrategy, 125 /* name */ "pass", 126 /* maj */ PASS_CDEV_MAJOR, 127 /* dump */ nodump, 128 /* psize */ nopsize, 129 /* flags */ 0, 130 /* bmaj */ -1 131 }; 132 133 static struct extend_array *passperiphs; 134 135 static void 136 passinit(void) 137 { 138 cam_status status; 139 struct cam_path *path; 140 141 /* 142 * Create our extend array for storing the devices we attach to. 143 */ 144 passperiphs = cam_extend_new(); 145 if (passperiphs == NULL) { 146 printf("passm: Failed to alloc extend array!\n"); 147 return; 148 } 149 150 /* 151 * Install a global async callback. This callback will 152 * receive async callbacks like "new device found". 153 */ 154 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 155 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 156 157 if (status == CAM_REQ_CMP) { 158 struct ccb_setasync csa; 159 160 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 161 csa.ccb_h.func_code = XPT_SASYNC_CB; 162 csa.event_enable = AC_FOUND_DEVICE; 163 csa.callback = passasync; 164 csa.callback_arg = NULL; 165 xpt_action((union ccb *)&csa); 166 status = csa.ccb_h.status; 167 xpt_free_path(path); 168 } 169 170 if (status != CAM_REQ_CMP) { 171 printf("pass: Failed to attach master async callback " 172 "due to status 0x%x!\n", status); 173 } 174 175 } 176 177 static void 178 passoninvalidate(struct cam_periph *periph) 179 { 180 int s; 181 struct pass_softc *softc; 182 struct bio *q_bp; 183 struct ccb_setasync csa; 184 185 softc = (struct pass_softc *)periph->softc; 186 187 /* 188 * De-register any async callbacks. 189 */ 190 xpt_setup_ccb(&csa.ccb_h, periph->path, 191 /* priority */ 5); 192 csa.ccb_h.func_code = XPT_SASYNC_CB; 193 csa.event_enable = 0; 194 csa.callback = passasync; 195 csa.callback_arg = periph; 196 xpt_action((union ccb *)&csa); 197 198 softc->flags |= PASS_FLAG_INVALID; 199 200 /* 201 * Although the oninvalidate() routines are always called at 202 * splsoftcam, we need to be at splbio() here to keep the buffer 203 * queue from being modified while we traverse it. 204 */ 205 s = splbio(); 206 207 /* 208 * Return all queued I/O with ENXIO. 209 * XXX Handle any transactions queued to the card 210 * with XPT_ABORT_CCB. 211 */ 212 while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){ 213 bioq_remove(&softc->bio_queue, q_bp); 214 q_bp->bio_resid = q_bp->bio_bcount; 215 q_bp->bio_error = ENXIO; 216 q_bp->bio_flags |= BIO_ERROR; 217 biodone(q_bp); 218 } 219 splx(s); 220 221 if (bootverbose) { 222 xpt_print_path(periph->path); 223 printf("lost device\n"); 224 } 225 226 } 227 228 static void 229 passcleanup(struct cam_periph *periph) 230 { 231 struct pass_softc *softc; 232 233 softc = (struct pass_softc *)periph->softc; 234 235 devstat_remove_entry(&softc->device_stats); 236 237 destroy_dev(softc->dev); 238 239 cam_extend_release(passperiphs, periph->unit_number); 240 241 if (bootverbose) { 242 xpt_print_path(periph->path); 243 printf("removing device entry\n"); 244 } 245 free(softc, M_DEVBUF); 246 } 247 248 static void 249 passasync(void *callback_arg, u_int32_t code, 250 struct cam_path *path, void *arg) 251 { 252 struct cam_periph *periph; 253 254 periph = (struct cam_periph *)callback_arg; 255 256 switch (code) { 257 case AC_FOUND_DEVICE: 258 { 259 struct ccb_getdev *cgd; 260 cam_status status; 261 262 cgd = (struct ccb_getdev *)arg; 263 264 /* 265 * Allocate a peripheral instance for 266 * this device and start the probe 267 * process. 268 */ 269 status = cam_periph_alloc(passregister, passoninvalidate, 270 passcleanup, passstart, "pass", 271 CAM_PERIPH_BIO, cgd->ccb_h.path, 272 passasync, AC_FOUND_DEVICE, cgd); 273 274 if (status != CAM_REQ_CMP 275 && status != CAM_REQ_INPROG) 276 printf("passasync: Unable to attach new device " 277 "due to status 0x%x\n", status); 278 279 break; 280 } 281 default: 282 cam_periph_async(periph, code, path, arg); 283 break; 284 } 285 } 286 287 static cam_status 288 passregister(struct cam_periph *periph, void *arg) 289 { 290 struct pass_softc *softc; 291 struct ccb_setasync csa; 292 struct ccb_getdev *cgd; 293 294 cgd = (struct ccb_getdev *)arg; 295 if (periph == NULL) { 296 printf("passregister: periph was NULL!!\n"); 297 return(CAM_REQ_CMP_ERR); 298 } 299 300 if (cgd == NULL) { 301 printf("passregister: no getdev CCB, can't register device\n"); 302 return(CAM_REQ_CMP_ERR); 303 } 304 305 softc = (struct pass_softc *)malloc(sizeof(*softc), 306 M_DEVBUF, M_NOWAIT); 307 308 if (softc == NULL) { 309 printf("passregister: Unable to probe new device. " 310 "Unable to allocate softc\n"); 311 return(CAM_REQ_CMP_ERR); 312 } 313 314 bzero(softc, sizeof(*softc)); 315 softc->state = PASS_STATE_NORMAL; 316 softc->pd_type = SID_TYPE(&cgd->inq_data); 317 bioq_init(&softc->bio_queue); 318 319 periph->softc = softc; 320 321 cam_extend_set(passperiphs, periph->unit_number, periph); 322 /* 323 * We pass in 0 for a blocksize, since we don't 324 * know what the blocksize of this device is, if 325 * it even has a blocksize. 326 */ 327 devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, 328 0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, 329 softc->pd_type | 330 DEVSTAT_TYPE_IF_SCSI | 331 DEVSTAT_TYPE_PASS, 332 DEVSTAT_PRIORITY_PASS); 333 334 /* Register the device */ 335 softc->dev = make_dev(&pass_cdevsw, periph->unit_number, UID_ROOT, 336 GID_OPERATOR, 0600, "%s%d", periph->periph_name, 337 periph->unit_number); 338 339 /* 340 * Add an async callback so that we get 341 * notified if this device goes away. 342 */ 343 xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 344 csa.ccb_h.func_code = XPT_SASYNC_CB; 345 csa.event_enable = AC_LOST_DEVICE; 346 csa.callback = passasync; 347 csa.callback_arg = periph; 348 xpt_action((union ccb *)&csa); 349 350 if (bootverbose) 351 xpt_announce_periph(periph, NULL); 352 353 return(CAM_REQ_CMP); 354 } 355 356 static int 357 passopen(dev_t dev, int flags, int fmt, struct proc *p) 358 { 359 struct cam_periph *periph; 360 struct pass_softc *softc; 361 int unit, error; 362 int s; 363 364 error = 0; /* default to no error */ 365 366 /* unit = dkunit(dev); */ 367 /* XXX KDM fix this */ 368 unit = minor(dev) & 0xff; 369 370 periph = cam_extend_get(passperiphs, unit); 371 372 if (periph == NULL) 373 return (ENXIO); 374 375 softc = (struct pass_softc *)periph->softc; 376 377 s = splsoftcam(); 378 if (softc->flags & PASS_FLAG_INVALID) { 379 splx(s); 380 return(ENXIO); 381 } 382 383 /* 384 * Don't allow access when we're running at a high securelvel. 385 */ 386 if (securelevel > 1) { 387 splx(s); 388 return(EPERM); 389 } 390 391 /* 392 * Only allow read-write access. 393 */ 394 if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) { 395 splx(s); 396 return(EPERM); 397 } 398 399 /* 400 * We don't allow nonblocking access. 401 */ 402 if ((flags & O_NONBLOCK) != 0) { 403 xpt_print_path(periph->path); 404 printf("can't do nonblocking accesss\n"); 405 splx(s); 406 return(EINVAL); 407 } 408 409 if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 410 splx(s); 411 return (error); 412 } 413 414 splx(s); 415 416 if ((softc->flags & PASS_FLAG_OPEN) == 0) { 417 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 418 return(ENXIO); 419 softc->flags |= PASS_FLAG_OPEN; 420 } 421 422 cam_periph_unlock(periph); 423 424 return (error); 425 } 426 427 static int 428 passclose(dev_t dev, int flag, int fmt, struct proc *p) 429 { 430 struct cam_periph *periph; 431 struct pass_softc *softc; 432 int unit, error; 433 434 /* unit = dkunit(dev); */ 435 /* XXX KDM fix this */ 436 unit = minor(dev) & 0xff; 437 438 periph = cam_extend_get(passperiphs, unit); 439 if (periph == NULL) 440 return (ENXIO); 441 442 softc = (struct pass_softc *)periph->softc; 443 444 if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 445 return (error); 446 447 softc->flags &= ~PASS_FLAG_OPEN; 448 449 cam_periph_unlock(periph); 450 cam_periph_release(periph); 451 452 return (0); 453 } 454 455 /* 456 * Actually translate the requested transfer into one the physical driver 457 * can understand. The transfer is described by a buf and will include 458 * only one physical transfer. 459 */ 460 static void 461 passstrategy(struct bio *bp) 462 { 463 struct cam_periph *periph; 464 struct pass_softc *softc; 465 u_int unit; 466 int s; 467 468 /* 469 * The read/write interface for the passthrough driver doesn't 470 * really work right now. So, we just pass back EINVAL to tell the 471 * user to go away. 472 */ 473 bp->bio_error = EINVAL; 474 goto bad; 475 476 /* unit = dkunit(bp->bio_dev); */ 477 /* XXX KDM fix this */ 478 unit = minor(bp->bio_dev) & 0xff; 479 480 periph = cam_extend_get(passperiphs, unit); 481 if (periph == NULL) { 482 bp->bio_error = ENXIO; 483 goto bad; 484 } 485 softc = (struct pass_softc *)periph->softc; 486 487 /* 488 * Odd number of bytes or negative offset 489 */ 490 /* valid request? */ 491 if (bp->bio_blkno < 0) { 492 bp->bio_error = EINVAL; 493 goto bad; 494 } 495 496 /* 497 * Mask interrupts so that the pack cannot be invalidated until 498 * after we are in the queue. Otherwise, we might not properly 499 * clean up one of the buffers. 500 */ 501 s = splbio(); 502 503 bioq_insert_tail(&softc->bio_queue, bp); 504 505 splx(s); 506 507 /* 508 * Schedule ourselves for performing the work. 509 */ 510 xpt_schedule(periph, /* XXX priority */1); 511 512 return; 513 bad: 514 bp->bio_flags |= BIO_ERROR; 515 516 /* 517 * Correctly set the buf to indicate a completed xfer 518 */ 519 bp->bio_resid = bp->bio_bcount; 520 biodone(bp); 521 return; 522 } 523 524 static void 525 passstart(struct cam_periph *periph, union ccb *start_ccb) 526 { 527 struct pass_softc *softc; 528 int s; 529 530 softc = (struct pass_softc *)periph->softc; 531 532 switch (softc->state) { 533 case PASS_STATE_NORMAL: 534 { 535 struct bio *bp; 536 537 s = splbio(); 538 bp = bioq_first(&softc->bio_queue); 539 if (periph->immediate_priority <= periph->pinfo.priority) { 540 start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; 541 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 542 periph_links.sle); 543 periph->immediate_priority = CAM_PRIORITY_NONE; 544 splx(s); 545 wakeup(&periph->ccb_list); 546 } else if (bp == NULL) { 547 splx(s); 548 xpt_release_ccb(start_ccb); 549 } else { 550 551 bioq_remove(&softc->bio_queue, bp); 552 553 devstat_start_transaction(&softc->device_stats); 554 555 /* 556 * XXX JGibbs - 557 * Interpret the contents of the bp as a CCB 558 * and pass it to a routine shared by our ioctl 559 * code and passtart. 560 * For now, just biodone it with EIO so we don't 561 * hang. 562 */ 563 bp->bio_error = EIO; 564 bp->bio_flags |= BIO_ERROR; 565 bp->bio_resid = bp->bio_bcount; 566 biodone(bp); 567 bp = bioq_first(&softc->bio_queue); 568 splx(s); 569 570 xpt_action(start_ccb); 571 572 } 573 if (bp != NULL) { 574 /* Have more work to do, so ensure we stay scheduled */ 575 xpt_schedule(periph, /* XXX priority */1); 576 } 577 break; 578 } 579 } 580 } 581 static void 582 passdone(struct cam_periph *periph, union ccb *done_ccb) 583 { 584 struct pass_softc *softc; 585 struct ccb_scsiio *csio; 586 587 softc = (struct pass_softc *)periph->softc; 588 csio = &done_ccb->csio; 589 switch (csio->ccb_h.ccb_type) { 590 case PASS_CCB_BUFFER_IO: 591 { 592 struct bio *bp; 593 cam_status status; 594 u_int8_t scsi_status; 595 devstat_trans_flags ds_flags; 596 597 status = done_ccb->ccb_h.status; 598 scsi_status = done_ccb->csio.scsi_status; 599 bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 600 /* XXX handle errors */ 601 if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP) 602 && (scsi_status == SCSI_STATUS_OK))) { 603 int error; 604 605 if ((error = passerror(done_ccb, 0, 0)) == ERESTART) { 606 /* 607 * A retry was scheuled, so 608 * just return. 609 */ 610 return; 611 } 612 613 /* 614 * XXX unfreeze the queue after we complete 615 * the abort process 616 */ 617 bp->bio_error = error; 618 bp->bio_flags |= BIO_ERROR; 619 } 620 621 if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 622 ds_flags = DEVSTAT_READ; 623 else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 624 ds_flags = DEVSTAT_WRITE; 625 else 626 ds_flags = DEVSTAT_NO_DATA; 627 628 devstat_end_transaction_bio(&softc->device_stats, bp); 629 biodone(bp); 630 break; 631 } 632 case PASS_CCB_WAITING: 633 { 634 /* Caller will release the CCB */ 635 wakeup(&done_ccb->ccb_h.cbfcnp); 636 return; 637 } 638 } 639 xpt_release_ccb(done_ccb); 640 } 641 642 static int 643 passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 644 { 645 struct cam_periph *periph; 646 struct pass_softc *softc; 647 u_int8_t unit; 648 int error; 649 650 651 /* unit = dkunit(dev); */ 652 /* XXX KDM fix this */ 653 unit = minor(dev) & 0xff; 654 655 periph = cam_extend_get(passperiphs, unit); 656 657 if (periph == NULL) 658 return(ENXIO); 659 660 softc = (struct pass_softc *)periph->softc; 661 662 error = 0; 663 664 switch (cmd) { 665 666 case CAMIOCOMMAND: 667 { 668 union ccb *inccb; 669 union ccb *ccb; 670 int ccb_malloced; 671 672 inccb = (union ccb *)addr; 673 674 /* 675 * Some CCB types, like scan bus and scan lun can only go 676 * through the transport layer device. 677 */ 678 if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 679 xpt_print_path(periph->path); 680 printf("CCB function code %#x is restricted to the " 681 "XPT device\n", inccb->ccb_h.func_code); 682 error = ENODEV; 683 break; 684 } 685 686 /* 687 * Non-immediate CCBs need a CCB from the per-device pool 688 * of CCBs, which is scheduled by the transport layer. 689 * Immediate CCBs and user-supplied CCBs should just be 690 * malloced. 691 */ 692 if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 693 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 694 ccb = cam_periph_getccb(periph, 695 inccb->ccb_h.pinfo.priority); 696 ccb_malloced = 0; 697 } else { 698 ccb = xpt_alloc_ccb(); 699 700 if (ccb != NULL) 701 xpt_setup_ccb(&ccb->ccb_h, periph->path, 702 inccb->ccb_h.pinfo.priority); 703 ccb_malloced = 1; 704 } 705 706 if (ccb == NULL) { 707 xpt_print_path(periph->path); 708 printf("unable to allocate CCB\n"); 709 error = ENOMEM; 710 break; 711 } 712 713 error = passsendccb(periph, ccb, inccb); 714 715 if (ccb_malloced) 716 xpt_free_ccb(ccb); 717 else 718 xpt_release_ccb(ccb); 719 720 break; 721 } 722 default: 723 error = cam_periph_ioctl(periph, cmd, addr, passerror); 724 break; 725 } 726 727 return(error); 728 } 729 730 /* 731 * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 732 * should be the CCB that is copied in from the user. 733 */ 734 static int 735 passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 736 { 737 struct pass_softc *softc; 738 struct cam_periph_map_info mapinfo; 739 int error, need_unmap; 740 741 softc = (struct pass_softc *)periph->softc; 742 743 need_unmap = 0; 744 745 /* 746 * There are some fields in the CCB header that need to be 747 * preserved, the rest we get from the user. 748 */ 749 xpt_merge_ccb(ccb, inccb); 750 751 /* 752 * There's no way for the user to have a completion 753 * function, so we put our own completion function in here. 754 */ 755 ccb->ccb_h.cbfcnp = passdone; 756 757 /* 758 * We only attempt to map the user memory into kernel space 759 * if they haven't passed in a physical memory pointer, 760 * and if there is actually an I/O operation to perform. 761 * Right now cam_periph_mapmem() only supports SCSI and device 762 * match CCBs. For the SCSI CCBs, we only pass the CCB in if 763 * there's actually data to map. cam_periph_mapmem() will do the 764 * right thing, even if there isn't data to map, but since CCBs 765 * without data are a reasonably common occurance (e.g. test unit 766 * ready), it will save a few cycles if we check for it here. 767 */ 768 if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) 769 && (((ccb->ccb_h.func_code == XPT_SCSI_IO) 770 && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 771 || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) { 772 773 bzero(&mapinfo, sizeof(mapinfo)); 774 775 error = cam_periph_mapmem(ccb, &mapinfo); 776 777 /* 778 * cam_periph_mapmem returned an error, we can't continue. 779 * Return the error to the user. 780 */ 781 if (error) 782 return(error); 783 784 /* 785 * We successfully mapped the memory in, so we need to 786 * unmap it when the transaction is done. 787 */ 788 need_unmap = 1; 789 } 790 791 /* 792 * If the user wants us to perform any error recovery, then honor 793 * that request. Otherwise, it's up to the user to perform any 794 * error recovery. 795 */ 796 error = cam_periph_runccb(ccb, 797 (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 798 passerror : NULL, 799 /* cam_flags */ 0, 800 /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO, 801 &softc->device_stats); 802 803 if (need_unmap != 0) 804 cam_periph_unmapmem(ccb, &mapinfo); 805 806 ccb->ccb_h.cbfcnp = NULL; 807 ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 808 bcopy(ccb, inccb, sizeof(union ccb)); 809 810 return(error); 811 } 812 813 static int 814 passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 815 { 816 struct cam_periph *periph; 817 struct pass_softc *softc; 818 819 periph = xpt_path_periph(ccb->ccb_h.path); 820 softc = (struct pass_softc *)periph->softc; 821 822 return(cam_periph_error(ccb, cam_flags, sense_flags, 823 &softc->saved_ccb)); 824 } 825