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 }; 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 } else { 174 /* If we were successfull, register our devsw */ 175 cdevsw_add(&pass_cdevsw); 176 } 177 178 } 179 180 static void 181 passoninvalidate(struct cam_periph *periph) 182 { 183 int s; 184 struct pass_softc *softc; 185 struct buf *q_bp; 186 struct ccb_setasync csa; 187 188 softc = (struct pass_softc *)periph->softc; 189 190 /* 191 * De-register any async callbacks. 192 */ 193 xpt_setup_ccb(&csa.ccb_h, periph->path, 194 /* priority */ 5); 195 csa.ccb_h.func_code = XPT_SASYNC_CB; 196 csa.event_enable = 0; 197 csa.callback = passasync; 198 csa.callback_arg = periph; 199 xpt_action((union ccb *)&csa); 200 201 softc->flags |= PASS_FLAG_INVALID; 202 203 /* 204 * Although the oninvalidate() routines are always called at 205 * splsoftcam, we need to be at splbio() here to keep the buffer 206 * queue from being modified while we traverse it. 207 */ 208 s = splbio(); 209 210 /* 211 * Return all queued I/O with ENXIO. 212 * XXX Handle any transactions queued to the card 213 * with XPT_ABORT_CCB. 214 */ 215 while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 216 bufq_remove(&softc->buf_queue, q_bp); 217 q_bp->b_resid = q_bp->b_bcount; 218 q_bp->b_error = ENXIO; 219 q_bp->b_flags |= B_ERROR; 220 biodone(q_bp); 221 } 222 splx(s); 223 224 if (bootverbose) { 225 xpt_print_path(periph->path); 226 printf("lost device\n"); 227 } 228 229 } 230 231 static void 232 passcleanup(struct cam_periph *periph) 233 { 234 struct pass_softc *softc; 235 236 softc = (struct pass_softc *)periph->softc; 237 238 devstat_remove_entry(&softc->device_stats); 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 * Add an async callback so that we get 336 * notified if this device goes away. 337 */ 338 xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 339 csa.ccb_h.func_code = XPT_SASYNC_CB; 340 csa.event_enable = AC_LOST_DEVICE; 341 csa.callback = passasync; 342 csa.callback_arg = periph; 343 xpt_action((union ccb *)&csa); 344 345 if (bootverbose) 346 xpt_announce_periph(periph, NULL); 347 348 return(CAM_REQ_CMP); 349 } 350 351 static int 352 passopen(dev_t dev, int flags, int fmt, struct proc *p) 353 { 354 struct cam_periph *periph; 355 struct pass_softc *softc; 356 int unit, error; 357 int s; 358 359 error = 0; /* default to no error */ 360 361 /* unit = dkunit(dev); */ 362 /* XXX KDM fix this */ 363 unit = minor(dev) & 0xff; 364 365 periph = cam_extend_get(passperiphs, unit); 366 367 if (periph == NULL) 368 return (ENXIO); 369 370 softc = (struct pass_softc *)periph->softc; 371 372 s = splsoftcam(); 373 if (softc->flags & PASS_FLAG_INVALID) { 374 splx(s); 375 return(ENXIO); 376 } 377 378 /* 379 * Don't allow access when we're running at a high securelvel. 380 */ 381 if (securelevel > 1) { 382 splx(s); 383 return(EPERM); 384 } 385 386 /* 387 * Only allow read-write access. 388 */ 389 if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) { 390 splx(s); 391 return(EPERM); 392 } 393 394 /* 395 * We don't allow nonblocking access. 396 */ 397 if ((flags & O_NONBLOCK) != 0) { 398 xpt_print_path(periph->path); 399 printf("can't do nonblocking accesss\n"); 400 splx(s); 401 return(EINVAL); 402 } 403 404 if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 405 splx(s); 406 return (error); 407 } 408 409 splx(s); 410 411 if ((softc->flags & PASS_FLAG_OPEN) == 0) { 412 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 413 return(ENXIO); 414 softc->flags |= PASS_FLAG_OPEN; 415 } 416 417 cam_periph_unlock(periph); 418 419 return (error); 420 } 421 422 static int 423 passclose(dev_t dev, int flag, int fmt, struct proc *p) 424 { 425 struct cam_periph *periph; 426 struct pass_softc *softc; 427 int unit, error; 428 429 /* unit = dkunit(dev); */ 430 /* XXX KDM fix this */ 431 unit = minor(dev) & 0xff; 432 433 periph = cam_extend_get(passperiphs, unit); 434 if (periph == NULL) 435 return (ENXIO); 436 437 softc = (struct pass_softc *)periph->softc; 438 439 if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 440 return (error); 441 442 softc->flags &= ~PASS_FLAG_OPEN; 443 444 cam_periph_unlock(periph); 445 cam_periph_release(periph); 446 447 return (0); 448 } 449 450 /* 451 * Actually translate the requested transfer into one the physical driver 452 * can understand. The transfer is described by a buf and will include 453 * only one physical transfer. 454 */ 455 static void 456 passstrategy(struct buf *bp) 457 { 458 struct cam_periph *periph; 459 struct pass_softc *softc; 460 u_int unit; 461 int s; 462 463 /* 464 * The read/write interface for the passthrough driver doesn't 465 * really work right now. So, we just pass back EINVAL to tell the 466 * user to go away. 467 */ 468 bp->b_error = EINVAL; 469 goto bad; 470 471 /* unit = dkunit(bp->b_dev); */ 472 /* XXX KDM fix this */ 473 unit = minor(bp->b_dev) & 0xff; 474 475 periph = cam_extend_get(passperiphs, unit); 476 if (periph == NULL) { 477 bp->b_error = ENXIO; 478 goto bad; 479 } 480 softc = (struct pass_softc *)periph->softc; 481 482 /* 483 * Odd number of bytes or negative offset 484 */ 485 /* valid request? */ 486 if (bp->b_blkno < 0) { 487 bp->b_error = EINVAL; 488 goto bad; 489 } 490 491 /* 492 * Mask interrupts so that the pack cannot be invalidated until 493 * after we are in the queue. Otherwise, we might not properly 494 * clean up one of the buffers. 495 */ 496 s = splbio(); 497 498 bufq_insert_tail(&softc->buf_queue, bp); 499 500 splx(s); 501 502 /* 503 * Schedule ourselves for performing the work. 504 */ 505 xpt_schedule(periph, /* XXX priority */1); 506 507 return; 508 bad: 509 bp->b_flags |= B_ERROR; 510 511 /* 512 * Correctly set the buf to indicate a completed xfer 513 */ 514 bp->b_resid = bp->b_bcount; 515 biodone(bp); 516 return; 517 } 518 519 static void 520 passstart(struct cam_periph *periph, union ccb *start_ccb) 521 { 522 struct pass_softc *softc; 523 int s; 524 525 softc = (struct pass_softc *)periph->softc; 526 527 switch (softc->state) { 528 case PASS_STATE_NORMAL: 529 { 530 struct buf *bp; 531 532 s = splbio(); 533 bp = bufq_first(&softc->buf_queue); 534 if (periph->immediate_priority <= periph->pinfo.priority) { 535 start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; 536 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 537 periph_links.sle); 538 periph->immediate_priority = CAM_PRIORITY_NONE; 539 splx(s); 540 wakeup(&periph->ccb_list); 541 } else if (bp == NULL) { 542 splx(s); 543 xpt_release_ccb(start_ccb); 544 } else { 545 546 bufq_remove(&softc->buf_queue, bp); 547 548 devstat_start_transaction(&softc->device_stats); 549 550 /* 551 * XXX JGibbs - 552 * Interpret the contents of the bp as a CCB 553 * and pass it to a routine shared by our ioctl 554 * code and passtart. 555 * For now, just biodone it with EIO so we don't 556 * hang. 557 */ 558 bp->b_error = EIO; 559 bp->b_flags |= B_ERROR; 560 bp->b_resid = bp->b_bcount; 561 biodone(bp); 562 bp = bufq_first(&softc->buf_queue); 563 splx(s); 564 565 xpt_action(start_ccb); 566 567 } 568 if (bp != NULL) { 569 /* Have more work to do, so ensure we stay scheduled */ 570 xpt_schedule(periph, /* XXX priority */1); 571 } 572 break; 573 } 574 } 575 } 576 static void 577 passdone(struct cam_periph *periph, union ccb *done_ccb) 578 { 579 struct pass_softc *softc; 580 struct ccb_scsiio *csio; 581 582 softc = (struct pass_softc *)periph->softc; 583 csio = &done_ccb->csio; 584 switch (csio->ccb_h.ccb_type) { 585 case PASS_CCB_BUFFER_IO: 586 { 587 struct buf *bp; 588 cam_status status; 589 u_int8_t scsi_status; 590 devstat_trans_flags ds_flags; 591 592 status = done_ccb->ccb_h.status; 593 scsi_status = done_ccb->csio.scsi_status; 594 bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 595 /* XXX handle errors */ 596 if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP) 597 && (scsi_status == SCSI_STATUS_OK))) { 598 int error; 599 600 if ((error = passerror(done_ccb, 0, 0)) == ERESTART) { 601 /* 602 * A retry was scheuled, so 603 * just return. 604 */ 605 return; 606 } 607 608 /* 609 * XXX unfreeze the queue after we complete 610 * the abort process 611 */ 612 bp->b_error = error; 613 bp->b_flags |= B_ERROR; 614 } 615 616 if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 617 ds_flags = DEVSTAT_READ; 618 else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 619 ds_flags = DEVSTAT_WRITE; 620 else 621 ds_flags = DEVSTAT_NO_DATA; 622 623 devstat_end_transaction_buf(&softc->device_stats, bp); 624 biodone(bp); 625 break; 626 } 627 case PASS_CCB_WAITING: 628 { 629 /* Caller will release the CCB */ 630 wakeup(&done_ccb->ccb_h.cbfcnp); 631 return; 632 } 633 } 634 xpt_release_ccb(done_ccb); 635 } 636 637 static int 638 passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 639 { 640 struct cam_periph *periph; 641 struct pass_softc *softc; 642 u_int8_t unit; 643 int error; 644 645 646 /* unit = dkunit(dev); */ 647 /* XXX KDM fix this */ 648 unit = minor(dev) & 0xff; 649 650 periph = cam_extend_get(passperiphs, unit); 651 652 if (periph == NULL) 653 return(ENXIO); 654 655 softc = (struct pass_softc *)periph->softc; 656 657 error = 0; 658 659 switch (cmd) { 660 661 case CAMIOCOMMAND: 662 { 663 union ccb *inccb; 664 union ccb *ccb; 665 int ccb_malloced; 666 667 inccb = (union ccb *)addr; 668 669 /* 670 * Some CCB types, like scan bus and scan lun can only go 671 * through the transport layer device. 672 */ 673 if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 674 xpt_print_path(periph->path); 675 printf("CCB function code %#x is restricted to the " 676 "XPT device\n", inccb->ccb_h.func_code); 677 error = ENODEV; 678 break; 679 } 680 681 /* 682 * Non-immediate CCBs need a CCB from the per-device pool 683 * of CCBs, which is scheduled by the transport layer. 684 * Immediate CCBs and user-supplied CCBs should just be 685 * malloced. 686 */ 687 if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 688 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 689 ccb = cam_periph_getccb(periph, 690 inccb->ccb_h.pinfo.priority); 691 ccb_malloced = 0; 692 } else { 693 ccb = xpt_alloc_ccb(); 694 695 if (ccb != NULL) 696 xpt_setup_ccb(&ccb->ccb_h, periph->path, 697 inccb->ccb_h.pinfo.priority); 698 ccb_malloced = 1; 699 } 700 701 if (ccb == NULL) { 702 xpt_print_path(periph->path); 703 printf("unable to allocate CCB\n"); 704 error = ENOMEM; 705 break; 706 } 707 708 error = passsendccb(periph, ccb, inccb); 709 710 if (ccb_malloced) 711 xpt_free_ccb(ccb); 712 else 713 xpt_release_ccb(ccb); 714 715 break; 716 } 717 default: 718 error = cam_periph_ioctl(periph, cmd, addr, passerror); 719 break; 720 } 721 722 return(error); 723 } 724 725 /* 726 * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 727 * should be the CCB that is copied in from the user. 728 */ 729 static int 730 passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 731 { 732 struct pass_softc *softc; 733 struct cam_periph_map_info mapinfo; 734 int error, need_unmap; 735 736 softc = (struct pass_softc *)periph->softc; 737 738 need_unmap = 0; 739 740 /* 741 * There are some fields in the CCB header that need to be 742 * preserved, the rest we get from the user. 743 */ 744 xpt_merge_ccb(ccb, inccb); 745 746 /* 747 * There's no way for the user to have a completion 748 * function, so we put our own completion function in here. 749 */ 750 ccb->ccb_h.cbfcnp = passdone; 751 752 /* 753 * We only attempt to map the user memory into kernel space 754 * if they haven't passed in a physical memory pointer, 755 * and if there is actually an I/O operation to perform. 756 * Right now cam_periph_mapmem() only supports SCSI and device 757 * match CCBs. For the SCSI CCBs, we only pass the CCB in if 758 * there's actually data to map. cam_periph_mapmem() will do the 759 * right thing, even if there isn't data to map, but since CCBs 760 * without data are a reasonably common occurance (e.g. test unit 761 * ready), it will save a few cycles if we check for it here. 762 */ 763 if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) 764 && (((ccb->ccb_h.func_code == XPT_SCSI_IO) 765 && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 766 || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) { 767 768 bzero(&mapinfo, sizeof(mapinfo)); 769 770 error = cam_periph_mapmem(ccb, &mapinfo); 771 772 /* 773 * cam_periph_mapmem returned an error, we can't continue. 774 * Return the error to the user. 775 */ 776 if (error) 777 return(error); 778 779 /* 780 * We successfully mapped the memory in, so we need to 781 * unmap it when the transaction is done. 782 */ 783 need_unmap = 1; 784 } 785 786 /* 787 * If the user wants us to perform any error recovery, then honor 788 * that request. Otherwise, it's up to the user to perform any 789 * error recovery. 790 */ 791 error = cam_periph_runccb(ccb, 792 (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 793 passerror : NULL, 794 /* cam_flags */ 0, 795 /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO, 796 &softc->device_stats); 797 798 if (need_unmap != 0) 799 cam_periph_unmapmem(ccb, &mapinfo); 800 801 ccb->ccb_h.cbfcnp = NULL; 802 ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 803 bcopy(ccb, inccb, sizeof(union ccb)); 804 805 return(error); 806 } 807 808 static int 809 passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 810 { 811 struct cam_periph *periph; 812 struct pass_softc *softc; 813 814 periph = xpt_path_periph(ccb->ccb_h.path); 815 softc = (struct pass_softc *)periph->softc; 816 817 return(cam_periph_error(ccb, cam_flags, sense_flags, 818 &softc->saved_ccb)); 819 } 820