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