scsi_pass.c revision 51196
150472Speter/* 245299Sobrien * Copyright (c) 1997, 1998 Justin T. Gibbs. 345299Sobrien * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry. 4234782Skib * All rights reserved. 5234782Skib * 645299Sobrien * Redistribution and use in source and binary forms, with or without 796488Sobrien * modification, are permitted provided that the following conditions 8169718Skan * are met: 949864Sobrien * 1. Redistributions of source code must retain the above copyright 10169718Skan * notice, this list of conditions, and the following disclaimer, 111823Sphk * without modification, immediately at the beginning of the file. 12234782Skib * 2. The name of the author may not be used to endorse or promote products 13139112Sru * derived from this software without specific prior written permission. 14234782Skib * 1552861Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16169718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17169718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18169718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1956521Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20169718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21169718Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22169718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23169718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241823Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25169718Skan * SUCH DAMAGE. 26169718Skan * 27169718Skan * $FreeBSD: head/sys/cam/scsi/scsi_pass.c 51196 1999-09-12 08:23:21Z phk $ 2896488Sobrien */ 291823Sphk 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 56typedef enum { 57 PASS_FLAG_OPEN = 0x01, 58 PASS_FLAG_LOCKED = 0x02, 59 PASS_FLAG_INVALID = 0x04 60} pass_flags; 61 62typedef enum { 63 PASS_STATE_NORMAL 64} pass_state; 65 66typedef 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 74struct 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 89static d_open_t passopen; 90static d_close_t passclose; 91static d_ioctl_t passioctl; 92static d_strategy_t passstrategy; 93 94static periph_init_t passinit; 95static periph_ctor_t passregister; 96static periph_oninv_t passoninvalidate; 97static periph_dtor_t passcleanup; 98static periph_start_t passstart; 99static void passasync(void *callback_arg, u_int32_t code, 100 struct cam_path *path, void *arg); 101static void passdone(struct cam_periph *periph, 102 union ccb *done_ccb); 103static int passerror(union ccb *ccb, u_int32_t cam_flags, 104 u_int32_t sense_flags); 105static int passsendccb(struct cam_periph *periph, union ccb *ccb, 106 union ccb *inccb); 107 108static struct periph_driver passdriver = 109{ 110 passinit, "pass", 111 TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 112}; 113 114DATA_SET(periphdriver_set, passdriver); 115 116static struct cdevsw pass_cdevsw = { 117 /* open */ passopen, 118 /* close */ passclose, 119 /* read */ physread, 120 /* write */ physwrite, 121 /* ioctl */ passioctl, 122 /* stop */ nostop, 123 /* reset */ noreset, 124 /* devtotty */ nodevtotty, 125 /* poll */ nopoll, 126 /* mmap */ nommap, 127 /* strategy */ passstrategy, 128 /* name */ "pass", 129 /* parms */ noparms, 130 /* maj */ PASS_CDEV_MAJOR, 131 /* dump */ nodump, 132 /* psize */ nopsize, 133 /* flags */ 0, 134 /* maxio */ 0, 135 /* bmaj */ -1 136}; 137 138static struct extend_array *passperiphs; 139 140static void 141passinit(void) 142{ 143 cam_status status; 144 struct cam_path *path; 145 146 /* 147 * Create our extend array for storing the devices we attach to. 148 */ 149 passperiphs = cam_extend_new(); 150 if (passperiphs == NULL) { 151 printf("passm: Failed to alloc extend array!\n"); 152 return; 153 } 154 155 /* 156 * Install a global async callback. This callback will 157 * receive async callbacks like "new device found". 158 */ 159 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 160 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 161 162 if (status == CAM_REQ_CMP) { 163 struct ccb_setasync csa; 164 165 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 166 csa.ccb_h.func_code = XPT_SASYNC_CB; 167 csa.event_enable = AC_FOUND_DEVICE; 168 csa.callback = passasync; 169 csa.callback_arg = NULL; 170 xpt_action((union ccb *)&csa); 171 status = csa.ccb_h.status; 172 xpt_free_path(path); 173 } 174 175 if (status != CAM_REQ_CMP) { 176 printf("pass: Failed to attach master async callback " 177 "due to status 0x%x!\n", status); 178 } else { 179 /* If we were successfull, register our devsw */ 180 cdevsw_add(&pass_cdevsw); 181 } 182 183} 184 185static void 186passoninvalidate(struct cam_periph *periph) 187{ 188 int s; 189 struct pass_softc *softc; 190 struct buf *q_bp; 191 struct ccb_setasync csa; 192 193 softc = (struct pass_softc *)periph->softc; 194 195 /* 196 * De-register any async callbacks. 197 */ 198 xpt_setup_ccb(&csa.ccb_h, periph->path, 199 /* priority */ 5); 200 csa.ccb_h.func_code = XPT_SASYNC_CB; 201 csa.event_enable = 0; 202 csa.callback = passasync; 203 csa.callback_arg = periph; 204 xpt_action((union ccb *)&csa); 205 206 softc->flags |= PASS_FLAG_INVALID; 207 208 /* 209 * Although the oninvalidate() routines are always called at 210 * splsoftcam, we need to be at splbio() here to keep the buffer 211 * queue from being modified while we traverse it. 212 */ 213 s = splbio(); 214 215 /* 216 * Return all queued I/O with ENXIO. 217 * XXX Handle any transactions queued to the card 218 * with XPT_ABORT_CCB. 219 */ 220 while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 221 bufq_remove(&softc->buf_queue, q_bp); 222 q_bp->b_resid = q_bp->b_bcount; 223 q_bp->b_error = ENXIO; 224 q_bp->b_flags |= B_ERROR; 225 biodone(q_bp); 226 } 227 splx(s); 228 229 if (bootverbose) { 230 xpt_print_path(periph->path); 231 printf("lost device\n"); 232 } 233 234} 235 236static void 237passcleanup(struct cam_periph *periph) 238{ 239 struct pass_softc *softc; 240 241 softc = (struct pass_softc *)periph->softc; 242 243 devstat_remove_entry(&softc->device_stats); 244 245 cam_extend_release(passperiphs, periph->unit_number); 246 247 if (bootverbose) { 248 xpt_print_path(periph->path); 249 printf("removing device entry\n"); 250 } 251 free(softc, M_DEVBUF); 252} 253 254static void 255passasync(void *callback_arg, u_int32_t code, 256 struct cam_path *path, void *arg) 257{ 258 struct cam_periph *periph; 259 260 periph = (struct cam_periph *)callback_arg; 261 262 switch (code) { 263 case AC_FOUND_DEVICE: 264 { 265 struct ccb_getdev *cgd; 266 cam_status status; 267 268 cgd = (struct ccb_getdev *)arg; 269 270 /* 271 * Allocate a peripheral instance for 272 * this device and start the probe 273 * process. 274 */ 275 status = cam_periph_alloc(passregister, passoninvalidate, 276 passcleanup, passstart, "pass", 277 CAM_PERIPH_BIO, cgd->ccb_h.path, 278 passasync, AC_FOUND_DEVICE, cgd); 279 280 if (status != CAM_REQ_CMP 281 && status != CAM_REQ_INPROG) 282 printf("passasync: Unable to attach new device " 283 "due to status 0x%x\n", status); 284 285 break; 286 } 287 default: 288 cam_periph_async(periph, code, path, arg); 289 break; 290 } 291} 292 293static cam_status 294passregister(struct cam_periph *periph, void *arg) 295{ 296 struct pass_softc *softc; 297 struct ccb_setasync csa; 298 struct ccb_getdev *cgd; 299 300 cgd = (struct ccb_getdev *)arg; 301 if (periph == NULL) { 302 printf("passregister: periph was NULL!!\n"); 303 return(CAM_REQ_CMP_ERR); 304 } 305 306 if (cgd == NULL) { 307 printf("passregister: no getdev CCB, can't register device\n"); 308 return(CAM_REQ_CMP_ERR); 309 } 310 311 softc = (struct pass_softc *)malloc(sizeof(*softc), 312 M_DEVBUF, M_NOWAIT); 313 314 if (softc == NULL) { 315 printf("passregister: Unable to probe new device. " 316 "Unable to allocate softc\n"); 317 return(CAM_REQ_CMP_ERR); 318 } 319 320 bzero(softc, sizeof(*softc)); 321 softc->state = PASS_STATE_NORMAL; 322 softc->pd_type = cgd->pd_type; 323 bufq_init(&softc->buf_queue); 324 325 periph->softc = softc; 326 327 cam_extend_set(passperiphs, periph->unit_number, periph); 328 /* 329 * We pass in 0 for a blocksize, since we don't 330 * know what the blocksize of this device is, if 331 * it even has a blocksize. 332 */ 333 devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, 334 0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, 335 cgd->pd_type | 336 DEVSTAT_TYPE_IF_SCSI | 337 DEVSTAT_TYPE_PASS, 338 DEVSTAT_PRIORITY_PASS); 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 356static int 357passopen(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 427static int 428passclose(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 */ 460static void 461passstrategy(struct buf *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->b_error = EINVAL; 474 goto bad; 475 476 /* unit = dkunit(bp->b_dev); */ 477 /* XXX KDM fix this */ 478 unit = minor(bp->b_dev) & 0xff; 479 480 periph = cam_extend_get(passperiphs, unit); 481 if (periph == NULL) { 482 bp->b_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->b_blkno < 0) { 492 bp->b_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 bufq_insert_tail(&softc->buf_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; 513bad: 514 bp->b_flags |= B_ERROR; 515 516 /* 517 * Correctly set the buf to indicate a completed xfer 518 */ 519 bp->b_resid = bp->b_bcount; 520 biodone(bp); 521 return; 522} 523 524static void 525passstart(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 buf *bp; 536 537 s = splbio(); 538 bp = bufq_first(&softc->buf_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 bufq_remove(&softc->buf_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->b_error = EIO; 564 bp->b_flags |= B_ERROR; 565 bp->b_resid = bp->b_bcount; 566 biodone(bp); 567 bp = bufq_first(&softc->buf_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} 581static void 582passdone(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 buf *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 buf *)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->b_error = error; 618 bp->b_flags |= B_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(&softc->device_stats, bp->b_bcount, 629 done_ccb->csio.tag_action & 0xf, 630 ds_flags); 631 632 biodone(bp); 633 break; 634 } 635 case PASS_CCB_WAITING: 636 { 637 /* Caller will release the CCB */ 638 wakeup(&done_ccb->ccb_h.cbfcnp); 639 return; 640 } 641 } 642 xpt_release_ccb(done_ccb); 643} 644 645static int 646passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 647{ 648 struct cam_periph *periph; 649 struct pass_softc *softc; 650 u_int8_t unit; 651 int error; 652 653 654 /* unit = dkunit(dev); */ 655 /* XXX KDM fix this */ 656 unit = minor(dev) & 0xff; 657 658 periph = cam_extend_get(passperiphs, unit); 659 660 if (periph == NULL) 661 return(ENXIO); 662 663 softc = (struct pass_softc *)periph->softc; 664 665 error = 0; 666 667 switch (cmd) { 668 669 case CAMIOCOMMAND: 670 { 671 union ccb *inccb; 672 union ccb *ccb; 673 int ccb_malloced; 674 675 inccb = (union ccb *)addr; 676 677 /* 678 * Some CCB types, like scan bus and scan lun can only go 679 * through the transport layer device. 680 */ 681 if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 682 xpt_print_path(periph->path); 683 printf("CCB function code %#x is restricted to the " 684 "XPT device\n", inccb->ccb_h.func_code); 685 error = ENODEV; 686 break; 687 } 688 689 /* 690 * Non-immediate CCBs need a CCB from the per-device pool 691 * of CCBs, which is scheduled by the transport layer. 692 * Immediate CCBs and user-supplied CCBs should just be 693 * malloced. 694 */ 695 if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 696 && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 697 ccb = cam_periph_getccb(periph, 698 inccb->ccb_h.pinfo.priority); 699 ccb_malloced = 0; 700 } else { 701 ccb = xpt_alloc_ccb(); 702 703 if (ccb != NULL) 704 xpt_setup_ccb(&ccb->ccb_h, periph->path, 705 inccb->ccb_h.pinfo.priority); 706 ccb_malloced = 1; 707 } 708 709 if (ccb == NULL) { 710 xpt_print_path(periph->path); 711 printf("unable to allocate CCB\n"); 712 error = ENOMEM; 713 break; 714 } 715 716 error = passsendccb(periph, ccb, inccb); 717 718 if (ccb_malloced) 719 xpt_free_ccb(ccb); 720 else 721 xpt_release_ccb(ccb); 722 723 break; 724 } 725 default: 726 error = cam_periph_ioctl(periph, cmd, addr, passerror); 727 break; 728 } 729 730 return(error); 731} 732 733/* 734 * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 735 * should be the CCB that is copied in from the user. 736 */ 737static int 738passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 739{ 740 struct pass_softc *softc; 741 struct cam_periph_map_info mapinfo; 742 int error, need_unmap; 743 744 softc = (struct pass_softc *)periph->softc; 745 746 need_unmap = 0; 747 748 /* 749 * There are some fields in the CCB header that need to be 750 * preserved, the rest we get from the user. 751 */ 752 xpt_merge_ccb(ccb, inccb); 753 754 /* 755 * There's no way for the user to have a completion 756 * function, so we put our own completion function in here. 757 */ 758 ccb->ccb_h.cbfcnp = passdone; 759 760 /* 761 * We only attempt to map the user memory into kernel space 762 * if they haven't passed in a physical memory pointer, 763 * and if there is actually an I/O operation to perform. 764 * Right now cam_periph_mapmem() only supports SCSI and device 765 * match CCBs. For the SCSI CCBs, we only pass the CCB in if 766 * there's actually data to map. cam_periph_mapmem() will do the 767 * right thing, even if there isn't data to map, but since CCBs 768 * without data are a reasonably common occurance (e.g. test unit 769 * ready), it will save a few cycles if we check for it here. 770 */ 771 if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) 772 && (((ccb->ccb_h.func_code == XPT_SCSI_IO) 773 && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 774 || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) { 775 776 bzero(&mapinfo, sizeof(mapinfo)); 777 778 error = cam_periph_mapmem(ccb, &mapinfo); 779 780 /* 781 * cam_periph_mapmem returned an error, we can't continue. 782 * Return the error to the user. 783 */ 784 if (error) 785 return(error); 786 787 /* 788 * We successfully mapped the memory in, so we need to 789 * unmap it when the transaction is done. 790 */ 791 need_unmap = 1; 792 } 793 794 /* 795 * If the user wants us to perform any error recovery, then honor 796 * that request. Otherwise, it's up to the user to perform any 797 * error recovery. 798 */ 799 error = cam_periph_runccb(ccb, 800 (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 801 passerror : NULL, 802 /* cam_flags */ 0, 803 /* sense_flags */SF_RETRY_UA | SF_RETRY_SELTO, 804 &softc->device_stats); 805 806 if (need_unmap != 0) 807 cam_periph_unmapmem(ccb, &mapinfo); 808 809 ccb->ccb_h.cbfcnp = NULL; 810 ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 811 bcopy(ccb, inccb, sizeof(union ccb)); 812 813 return(error); 814} 815 816static int 817passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 818{ 819 struct cam_periph *periph; 820 struct pass_softc *softc; 821 822 periph = xpt_path_periph(ccb->ccb_h.path); 823 softc = (struct pass_softc *)periph->softc; 824 825 return(cam_periph_error(ccb, cam_flags, sense_flags, 826 &softc->saved_ccb)); 827} 828