29 */ 30 31#include <sys/param.h> 32#include <sys/queue.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/types.h> 36#include <sys/bio.h> 37#include <sys/devicestat.h> 38#include <sys/malloc.h> 39#include <sys/conf.h> 40#include <sys/ptio.h> 41 42#include <cam/cam.h> 43#include <cam/cam_ccb.h> 44#include <cam/cam_periph.h> 45#include <cam/cam_xpt_periph.h> 46#include <cam/cam_debug.h> 47 48#include <cam/scsi/scsi_all.h> 49#include <cam/scsi/scsi_message.h> 50#include <cam/scsi/scsi_pt.h> 51 52#include "opt_pt.h" 53 54typedef enum { 55 PT_STATE_PROBE, 56 PT_STATE_NORMAL 57} pt_state; 58 59typedef enum { 60 PT_FLAG_NONE = 0x00, 61 PT_FLAG_OPEN = 0x01, 62 PT_FLAG_DEVICE_INVALID = 0x02, 63 PT_FLAG_RETRY_UA = 0x04 64} pt_flags; 65 66typedef enum { 67 PT_CCB_BUFFER_IO = 0x01, 68 PT_CCB_WAITING = 0x02, 69 PT_CCB_RETRY_UA = 0x04, 70 PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA 71} pt_ccb_state; 72 73/* Offsets into our private area for storing information */ 74#define ccb_state ppriv_field0 75#define ccb_bp ppriv_ptr1 76 77struct pt_softc { 78 struct bio_queue_head bio_queue; 79 struct devstat device_stats; 80 LIST_HEAD(, ccb_hdr) pending_ccbs; 81 pt_state state; 82 pt_flags flags; 83 union ccb saved_ccb; 84 int io_timeout; 85 dev_t dev; 86}; 87 88static d_open_t ptopen; 89static d_close_t ptclose; 90static d_strategy_t ptstrategy; 91static periph_init_t ptinit; 92static void ptasync(void *callback_arg, u_int32_t code, 93 struct cam_path *path, void *arg); 94static periph_ctor_t ptctor; 95static periph_oninv_t ptoninvalidate; 96static periph_dtor_t ptdtor; 97static periph_start_t ptstart; 98static void ptdone(struct cam_periph *periph, 99 union ccb *done_ccb); 100static d_ioctl_t ptioctl; 101static int pterror(union ccb *ccb, u_int32_t cam_flags, 102 u_int32_t sense_flags); 103 104void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 105 void (*cbfcnp)(struct cam_periph *, union ccb *), 106 u_int tag_action, int readop, u_int byte2, 107 u_int32_t xfer_len, u_int8_t *data_ptr, 108 u_int8_t sense_len, u_int32_t timeout); 109 110static struct periph_driver ptdriver = 111{ 112 ptinit, "pt", 113 TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0 114}; 115 116PERIPHDRIVER_DECLARE(pt, ptdriver); 117 118#define PT_CDEV_MAJOR 61 119 120static struct cdevsw pt_cdevsw = {
| 29 */ 30 31#include <sys/param.h> 32#include <sys/queue.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/types.h> 36#include <sys/bio.h> 37#include <sys/devicestat.h> 38#include <sys/malloc.h> 39#include <sys/conf.h> 40#include <sys/ptio.h> 41 42#include <cam/cam.h> 43#include <cam/cam_ccb.h> 44#include <cam/cam_periph.h> 45#include <cam/cam_xpt_periph.h> 46#include <cam/cam_debug.h> 47 48#include <cam/scsi/scsi_all.h> 49#include <cam/scsi/scsi_message.h> 50#include <cam/scsi/scsi_pt.h> 51 52#include "opt_pt.h" 53 54typedef enum { 55 PT_STATE_PROBE, 56 PT_STATE_NORMAL 57} pt_state; 58 59typedef enum { 60 PT_FLAG_NONE = 0x00, 61 PT_FLAG_OPEN = 0x01, 62 PT_FLAG_DEVICE_INVALID = 0x02, 63 PT_FLAG_RETRY_UA = 0x04 64} pt_flags; 65 66typedef enum { 67 PT_CCB_BUFFER_IO = 0x01, 68 PT_CCB_WAITING = 0x02, 69 PT_CCB_RETRY_UA = 0x04, 70 PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA 71} pt_ccb_state; 72 73/* Offsets into our private area for storing information */ 74#define ccb_state ppriv_field0 75#define ccb_bp ppriv_ptr1 76 77struct pt_softc { 78 struct bio_queue_head bio_queue; 79 struct devstat device_stats; 80 LIST_HEAD(, ccb_hdr) pending_ccbs; 81 pt_state state; 82 pt_flags flags; 83 union ccb saved_ccb; 84 int io_timeout; 85 dev_t dev; 86}; 87 88static d_open_t ptopen; 89static d_close_t ptclose; 90static d_strategy_t ptstrategy; 91static periph_init_t ptinit; 92static void ptasync(void *callback_arg, u_int32_t code, 93 struct cam_path *path, void *arg); 94static periph_ctor_t ptctor; 95static periph_oninv_t ptoninvalidate; 96static periph_dtor_t ptdtor; 97static periph_start_t ptstart; 98static void ptdone(struct cam_periph *periph, 99 union ccb *done_ccb); 100static d_ioctl_t ptioctl; 101static int pterror(union ccb *ccb, u_int32_t cam_flags, 102 u_int32_t sense_flags); 103 104void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 105 void (*cbfcnp)(struct cam_periph *, union ccb *), 106 u_int tag_action, int readop, u_int byte2, 107 u_int32_t xfer_len, u_int8_t *data_ptr, 108 u_int8_t sense_len, u_int32_t timeout); 109 110static struct periph_driver ptdriver = 111{ 112 ptinit, "pt", 113 TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0 114}; 115 116PERIPHDRIVER_DECLARE(pt, ptdriver); 117 118#define PT_CDEV_MAJOR 61 119 120static struct cdevsw pt_cdevsw = {
|
134}; 135 136#ifndef SCSI_PT_DEFAULT_TIMEOUT 137#define SCSI_PT_DEFAULT_TIMEOUT 60 138#endif 139 140static int 141ptopen(dev_t dev, int flags, int fmt, struct thread *td) 142{ 143 struct cam_periph *periph; 144 struct pt_softc *softc; 145 int unit; 146 int error; 147 int s; 148 149 unit = minor(dev); 150 periph = (struct cam_periph *)dev->si_drv1; 151 if (periph == NULL) 152 return (ENXIO); 153 154 softc = (struct pt_softc *)periph->softc; 155 156 s = splsoftcam(); 157 if (softc->flags & PT_FLAG_DEVICE_INVALID) { 158 splx(s); 159 return(ENXIO); 160 } 161 162 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 163 ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit)); 164 165 if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { 166 splx(s); 167 return (error); /* error code from tsleep */ 168 } 169 170 splx(s); 171 172 if ((softc->flags & PT_FLAG_OPEN) == 0) { 173 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 174 error = ENXIO; 175 else 176 softc->flags |= PT_FLAG_OPEN; 177 } else 178 error = EBUSY; 179 180 cam_periph_unlock(periph); 181 return (error); 182} 183 184static int 185ptclose(dev_t dev, int flag, int fmt, struct thread *td) 186{ 187 struct cam_periph *periph; 188 struct pt_softc *softc; 189 int error; 190 191 periph = (struct cam_periph *)dev->si_drv1; 192 if (periph == NULL) 193 return (ENXIO); 194 195 softc = (struct pt_softc *)periph->softc; 196 197 if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 198 return (error); /* error code from tsleep */ 199 200 softc->flags &= ~PT_FLAG_OPEN; 201 cam_periph_unlock(periph); 202 cam_periph_release(periph); 203 return (0); 204} 205 206/* 207 * Actually translate the requested transfer into one the physical driver 208 * can understand. The transfer is described by a buf and will include 209 * only one physical transfer. 210 */ 211static void 212ptstrategy(struct bio *bp) 213{ 214 struct cam_periph *periph; 215 struct pt_softc *softc; 216 int s; 217 218 periph = (struct cam_periph *)bp->bio_dev->si_drv1; 219 bp->bio_resid = bp->bio_bcount; 220 if (periph == NULL) { 221 biofinish(bp, NULL, ENXIO); 222 return; 223 } 224 softc = (struct pt_softc *)periph->softc; 225 226 /* 227 * Mask interrupts so that the pack cannot be invalidated until 228 * after we are in the queue. Otherwise, we might not properly 229 * clean up one of the buffers. 230 */ 231 s = splbio(); 232 233 /* 234 * If the device has been made invalid, error out 235 */ 236 if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { 237 splx(s); 238 biofinish(bp, NULL, ENXIO); 239 return; 240 } 241 242 /* 243 * Place it in the queue of disk activities for this disk 244 */ 245 bioq_insert_tail(&softc->bio_queue, bp); 246 247 splx(s); 248 249 /* 250 * Schedule ourselves for performing the work. 251 */ 252 xpt_schedule(periph, /* XXX priority */1); 253 254 return; 255} 256 257static void 258ptinit(void) 259{ 260 cam_status status; 261 struct cam_path *path; 262 263 /* 264 * Install a global async callback. This callback will 265 * receive async callbacks like "new device found". 266 */ 267 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 268 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 269 270 if (status == CAM_REQ_CMP) { 271 struct ccb_setasync csa; 272 273 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 274 csa.ccb_h.func_code = XPT_SASYNC_CB; 275 csa.event_enable = AC_FOUND_DEVICE; 276 csa.callback = ptasync; 277 csa.callback_arg = NULL; 278 xpt_action((union ccb *)&csa); 279 status = csa.ccb_h.status; 280 xpt_free_path(path); 281 } 282 283 if (status != CAM_REQ_CMP) { 284 printf("pt: Failed to attach master async callback " 285 "due to status 0x%x!\n", status); 286 } 287} 288 289static cam_status 290ptctor(struct cam_periph *periph, void *arg) 291{ 292 struct pt_softc *softc; 293 struct ccb_setasync csa; 294 struct ccb_getdev *cgd; 295 296 cgd = (struct ccb_getdev *)arg; 297 if (periph == NULL) { 298 printf("ptregister: periph was NULL!!\n"); 299 return(CAM_REQ_CMP_ERR); 300 } 301 302 if (cgd == NULL) { 303 printf("ptregister: no getdev CCB, can't register device\n"); 304 return(CAM_REQ_CMP_ERR); 305 } 306 307 softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 308 309 if (softc == NULL) { 310 printf("daregister: 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 LIST_INIT(&softc->pending_ccbs); 317 softc->state = PT_STATE_NORMAL; 318 bioq_init(&softc->bio_queue); 319 320 softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000; 321 322 periph->softc = softc; 323 324 devstat_add_entry(&softc->device_stats, "pt", 325 periph->unit_number, 0, 326 DEVSTAT_NO_BLOCKSIZE, 327 SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI, 328 DEVSTAT_PRIORITY_OTHER); 329 330 softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT, 331 GID_OPERATOR, 0600, "%s%d", periph->periph_name, 332 periph->unit_number); 333 softc->dev->si_drv1 = periph; 334 335 /* 336 * Add async callbacks for bus reset and 337 * bus device reset calls. I don't bother 338 * checking if this fails as, in most cases, 339 * the system will function just fine without 340 * them and the only alternative would be to 341 * not attach the device on failure. 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_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 346 csa.callback = ptasync; 347 csa.callback_arg = periph; 348 xpt_action((union ccb *)&csa); 349 350 /* Tell the user we've attached to the device */ 351 xpt_announce_periph(periph, NULL); 352 353 return(CAM_REQ_CMP); 354} 355 356static void 357ptoninvalidate(struct cam_periph *periph) 358{ 359 int s; 360 struct pt_softc *softc; 361 struct bio *q_bp; 362 struct ccb_setasync csa; 363 364 softc = (struct pt_softc *)periph->softc; 365 366 /* 367 * De-register any async callbacks. 368 */ 369 xpt_setup_ccb(&csa.ccb_h, periph->path, 370 /* priority */ 5); 371 csa.ccb_h.func_code = XPT_SASYNC_CB; 372 csa.event_enable = 0; 373 csa.callback = ptasync; 374 csa.callback_arg = periph; 375 xpt_action((union ccb *)&csa); 376 377 softc->flags |= PT_FLAG_DEVICE_INVALID; 378 379 /* 380 * Although the oninvalidate() routines are always called at 381 * splsoftcam, we need to be at splbio() here to keep the buffer 382 * queue from being modified while we traverse it. 383 */ 384 s = splbio(); 385 386 /* 387 * Return all queued I/O with ENXIO. 388 * XXX Handle any transactions queued to the card 389 * with XPT_ABORT_CCB. 390 */ 391 while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){ 392 bioq_remove(&softc->bio_queue, q_bp); 393 q_bp->bio_resid = q_bp->bio_bcount; 394 biofinish(q_bp, NULL, ENXIO); 395 } 396 397 splx(s); 398 399 xpt_print_path(periph->path); 400 printf("lost device\n"); 401} 402 403static void 404ptdtor(struct cam_periph *periph) 405{ 406 struct pt_softc *softc; 407 408 softc = (struct pt_softc *)periph->softc; 409 410 devstat_remove_entry(&softc->device_stats); 411 412 destroy_dev(softc->dev); 413 414 xpt_print_path(periph->path); 415 printf("removing device entry\n"); 416 free(softc, M_DEVBUF); 417} 418 419static void 420ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 421{ 422 struct cam_periph *periph; 423 424 periph = (struct cam_periph *)callback_arg; 425 switch (code) { 426 case AC_FOUND_DEVICE: 427 { 428 struct ccb_getdev *cgd; 429 cam_status status; 430 431 cgd = (struct ccb_getdev *)arg; 432 if (cgd == NULL) 433 break; 434 435 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR) 436 break; 437 438 /* 439 * Allocate a peripheral instance for 440 * this device and start the probe 441 * process. 442 */ 443 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor, 444 ptstart, "pt", CAM_PERIPH_BIO, 445 cgd->ccb_h.path, ptasync, 446 AC_FOUND_DEVICE, cgd); 447 448 if (status != CAM_REQ_CMP 449 && status != CAM_REQ_INPROG) 450 printf("ptasync: Unable to attach to new device " 451 "due to status 0x%x\n", status); 452 break; 453 } 454 case AC_SENT_BDR: 455 case AC_BUS_RESET: 456 { 457 struct pt_softc *softc; 458 struct ccb_hdr *ccbh; 459 int s; 460 461 softc = (struct pt_softc *)periph->softc; 462 s = splsoftcam(); 463 /* 464 * Don't fail on the expected unit attention 465 * that will occur. 466 */ 467 softc->flags |= PT_FLAG_RETRY_UA; 468 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 469 ccbh->ccb_state |= PT_CCB_RETRY_UA; 470 splx(s); 471 /* FALLTHROUGH */ 472 } 473 default: 474 cam_periph_async(periph, code, path, arg); 475 break; 476 } 477} 478 479static void 480ptstart(struct cam_periph *periph, union ccb *start_ccb) 481{ 482 struct pt_softc *softc; 483 struct bio *bp; 484 int s; 485 486 softc = (struct pt_softc *)periph->softc; 487 488 /* 489 * See if there is a buf with work for us to do.. 490 */ 491 s = splbio(); 492 bp = bioq_first(&softc->bio_queue); 493 if (periph->immediate_priority <= periph->pinfo.priority) { 494 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 495 ("queuing for immediate ccb\n")); 496 start_ccb->ccb_h.ccb_state = PT_CCB_WAITING; 497 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 498 periph_links.sle); 499 periph->immediate_priority = CAM_PRIORITY_NONE; 500 splx(s); 501 wakeup(&periph->ccb_list); 502 } else if (bp == NULL) { 503 splx(s); 504 xpt_release_ccb(start_ccb); 505 } else { 506 int oldspl; 507 508 bioq_remove(&softc->bio_queue, bp); 509 510 devstat_start_transaction(&softc->device_stats); 511 512 scsi_send_receive(&start_ccb->csio, 513 /*retries*/4, 514 ptdone, 515 MSG_SIMPLE_Q_TAG, 516 bp->bio_cmd == BIO_READ, 517 /*byte2*/0, 518 bp->bio_bcount, 519 bp->bio_data, 520 /*sense_len*/SSD_FULL_SIZE, 521 /*timeout*/softc->io_timeout); 522 523 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA; 524 525 /* 526 * Block out any asyncronous callbacks 527 * while we touch the pending ccb list. 528 */ 529 oldspl = splcam(); 530 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, 531 periph_links.le); 532 splx(oldspl); 533 534 start_ccb->ccb_h.ccb_bp = bp; 535 bp = bioq_first(&softc->bio_queue); 536 splx(s); 537 538 xpt_action(start_ccb); 539 540 if (bp != NULL) { 541 /* Have more work to do, so ensure we stay scheduled */ 542 xpt_schedule(periph, /* XXX priority */1); 543 } 544 } 545} 546 547static void 548ptdone(struct cam_periph *periph, union ccb *done_ccb) 549{ 550 struct pt_softc *softc; 551 struct ccb_scsiio *csio; 552 553 softc = (struct pt_softc *)periph->softc; 554 csio = &done_ccb->csio; 555 switch (csio->ccb_h.ccb_state) { 556 case PT_CCB_BUFFER_IO: 557 case PT_CCB_BUFFER_IO_UA: 558 { 559 struct bio *bp; 560 int oldspl; 561 562 bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 563 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 564 int error; 565 int s; 566 int sf; 567 568 if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0) 569 sf = SF_RETRY_UA; 570 else 571 sf = 0; 572 573 error = pterror(done_ccb, CAM_RETRY_SELTO, sf); 574 if (error == ERESTART) { 575 /* 576 * A retry was scheuled, so 577 * just return. 578 */ 579 return; 580 } 581 if (error != 0) { 582 struct bio *q_bp; 583 584 s = splbio(); 585 586 if (error == ENXIO) { 587 /* 588 * Catastrophic error. Mark our device 589 * as invalid. 590 */ 591 xpt_print_path(periph->path); 592 printf("Invalidating device\n"); 593 softc->flags |= PT_FLAG_DEVICE_INVALID; 594 } 595 596 /* 597 * return all queued I/O with EIO, so that 598 * the client can retry these I/Os in the 599 * proper order should it attempt to recover. 600 */ 601 while ((q_bp = bioq_first(&softc->bio_queue)) 602 != NULL) { 603 bioq_remove(&softc->bio_queue, q_bp); 604 q_bp->bio_resid = q_bp->bio_bcount; 605 biofinish(q_bp, NULL, EIO); 606 } 607 splx(s); 608 bp->bio_error = error; 609 bp->bio_resid = bp->bio_bcount; 610 bp->bio_flags |= BIO_ERROR; 611 } else { 612 bp->bio_resid = csio->resid; 613 bp->bio_error = 0; 614 if (bp->bio_resid != 0) { 615 /* Short transfer ??? */ 616 bp->bio_flags |= BIO_ERROR; 617 } 618 } 619 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 620 cam_release_devq(done_ccb->ccb_h.path, 621 /*relsim_flags*/0, 622 /*reduction*/0, 623 /*timeout*/0, 624 /*getcount_only*/0); 625 } else { 626 bp->bio_resid = csio->resid; 627 if (bp->bio_resid != 0) 628 bp->bio_flags |= BIO_ERROR; 629 } 630 631 /* 632 * Block out any asyncronous callbacks 633 * while we touch the pending ccb list. 634 */ 635 oldspl = splcam(); 636 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 637 splx(oldspl); 638 639 biofinish(bp, &softc->device_stats, 0); 640 break; 641 } 642 case PT_CCB_WAITING: 643 /* Caller will release the CCB */ 644 wakeup(&done_ccb->ccb_h.cbfcnp); 645 return; 646 } 647 xpt_release_ccb(done_ccb); 648} 649 650static int 651pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 652{ 653 struct pt_softc *softc; 654 struct cam_periph *periph; 655 656 periph = xpt_path_periph(ccb->ccb_h.path); 657 softc = (struct pt_softc *)periph->softc; 658 659 return(cam_periph_error(ccb, cam_flags, sense_flags, 660 &softc->saved_ccb)); 661} 662 663static int 664ptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 665{ 666 struct cam_periph *periph; 667 struct pt_softc *softc; 668 int error; 669 670 periph = (struct cam_periph *)dev->si_drv1; 671 if (periph == NULL) 672 return(ENXIO); 673 674 softc = (struct pt_softc *)periph->softc; 675 676 if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { 677 return (error); /* error code from tsleep */ 678 } 679 680 switch(cmd) { 681 case PTIOCGETTIMEOUT: 682 if (softc->io_timeout >= 1000) 683 *(int *)addr = softc->io_timeout / 1000; 684 else 685 *(int *)addr = 0; 686 break; 687 case PTIOCSETTIMEOUT: 688 { 689 int s; 690 691 if (*(int *)addr < 1) { 692 error = EINVAL; 693 break; 694 } 695 696 s = splsoftcam(); 697 softc->io_timeout = *(int *)addr * 1000; 698 splx(s); 699 700 break; 701 } 702 default: 703 error = cam_periph_ioctl(periph, cmd, addr, pterror); 704 break; 705 } 706 707 cam_periph_unlock(periph); 708 709 return(error); 710} 711 712void 713scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 714 void (*cbfcnp)(struct cam_periph *, union ccb *), 715 u_int tag_action, int readop, u_int byte2, 716 u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, 717 u_int32_t timeout) 718{ 719 struct scsi_send_receive *scsi_cmd; 720 721 scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes; 722 scsi_cmd->opcode = readop ? RECEIVE : SEND; 723 scsi_cmd->byte2 = byte2; 724 scsi_ulto3b(xfer_len, scsi_cmd->xfer_len); 725 scsi_cmd->control = 0; 726 727 cam_fill_csio(csio, 728 retries, 729 cbfcnp, 730 /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, 731 tag_action, 732 data_ptr, 733 xfer_len, 734 sense_len, 735 sizeof(*scsi_cmd), 736 timeout); 737}
| 129}; 130 131#ifndef SCSI_PT_DEFAULT_TIMEOUT 132#define SCSI_PT_DEFAULT_TIMEOUT 60 133#endif 134 135static int 136ptopen(dev_t dev, int flags, int fmt, struct thread *td) 137{ 138 struct cam_periph *periph; 139 struct pt_softc *softc; 140 int unit; 141 int error; 142 int s; 143 144 unit = minor(dev); 145 periph = (struct cam_periph *)dev->si_drv1; 146 if (periph == NULL) 147 return (ENXIO); 148 149 softc = (struct pt_softc *)periph->softc; 150 151 s = splsoftcam(); 152 if (softc->flags & PT_FLAG_DEVICE_INVALID) { 153 splx(s); 154 return(ENXIO); 155 } 156 157 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 158 ("ptopen: dev=%s (unit %d)\n", devtoname(dev), unit)); 159 160 if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { 161 splx(s); 162 return (error); /* error code from tsleep */ 163 } 164 165 splx(s); 166 167 if ((softc->flags & PT_FLAG_OPEN) == 0) { 168 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 169 error = ENXIO; 170 else 171 softc->flags |= PT_FLAG_OPEN; 172 } else 173 error = EBUSY; 174 175 cam_periph_unlock(periph); 176 return (error); 177} 178 179static int 180ptclose(dev_t dev, int flag, int fmt, struct thread *td) 181{ 182 struct cam_periph *periph; 183 struct pt_softc *softc; 184 int error; 185 186 periph = (struct cam_periph *)dev->si_drv1; 187 if (periph == NULL) 188 return (ENXIO); 189 190 softc = (struct pt_softc *)periph->softc; 191 192 if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 193 return (error); /* error code from tsleep */ 194 195 softc->flags &= ~PT_FLAG_OPEN; 196 cam_periph_unlock(periph); 197 cam_periph_release(periph); 198 return (0); 199} 200 201/* 202 * Actually translate the requested transfer into one the physical driver 203 * can understand. The transfer is described by a buf and will include 204 * only one physical transfer. 205 */ 206static void 207ptstrategy(struct bio *bp) 208{ 209 struct cam_periph *periph; 210 struct pt_softc *softc; 211 int s; 212 213 periph = (struct cam_periph *)bp->bio_dev->si_drv1; 214 bp->bio_resid = bp->bio_bcount; 215 if (periph == NULL) { 216 biofinish(bp, NULL, ENXIO); 217 return; 218 } 219 softc = (struct pt_softc *)periph->softc; 220 221 /* 222 * Mask interrupts so that the pack cannot be invalidated until 223 * after we are in the queue. Otherwise, we might not properly 224 * clean up one of the buffers. 225 */ 226 s = splbio(); 227 228 /* 229 * If the device has been made invalid, error out 230 */ 231 if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { 232 splx(s); 233 biofinish(bp, NULL, ENXIO); 234 return; 235 } 236 237 /* 238 * Place it in the queue of disk activities for this disk 239 */ 240 bioq_insert_tail(&softc->bio_queue, bp); 241 242 splx(s); 243 244 /* 245 * Schedule ourselves for performing the work. 246 */ 247 xpt_schedule(periph, /* XXX priority */1); 248 249 return; 250} 251 252static void 253ptinit(void) 254{ 255 cam_status status; 256 struct cam_path *path; 257 258 /* 259 * Install a global async callback. This callback will 260 * receive async callbacks like "new device found". 261 */ 262 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 263 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 264 265 if (status == CAM_REQ_CMP) { 266 struct ccb_setasync csa; 267 268 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 269 csa.ccb_h.func_code = XPT_SASYNC_CB; 270 csa.event_enable = AC_FOUND_DEVICE; 271 csa.callback = ptasync; 272 csa.callback_arg = NULL; 273 xpt_action((union ccb *)&csa); 274 status = csa.ccb_h.status; 275 xpt_free_path(path); 276 } 277 278 if (status != CAM_REQ_CMP) { 279 printf("pt: Failed to attach master async callback " 280 "due to status 0x%x!\n", status); 281 } 282} 283 284static cam_status 285ptctor(struct cam_periph *periph, void *arg) 286{ 287 struct pt_softc *softc; 288 struct ccb_setasync csa; 289 struct ccb_getdev *cgd; 290 291 cgd = (struct ccb_getdev *)arg; 292 if (periph == NULL) { 293 printf("ptregister: periph was NULL!!\n"); 294 return(CAM_REQ_CMP_ERR); 295 } 296 297 if (cgd == NULL) { 298 printf("ptregister: no getdev CCB, can't register device\n"); 299 return(CAM_REQ_CMP_ERR); 300 } 301 302 softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 303 304 if (softc == NULL) { 305 printf("daregister: Unable to probe new device. " 306 "Unable to allocate softc\n"); 307 return(CAM_REQ_CMP_ERR); 308 } 309 310 bzero(softc, sizeof(*softc)); 311 LIST_INIT(&softc->pending_ccbs); 312 softc->state = PT_STATE_NORMAL; 313 bioq_init(&softc->bio_queue); 314 315 softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000; 316 317 periph->softc = softc; 318 319 devstat_add_entry(&softc->device_stats, "pt", 320 periph->unit_number, 0, 321 DEVSTAT_NO_BLOCKSIZE, 322 SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI, 323 DEVSTAT_PRIORITY_OTHER); 324 325 softc->dev = make_dev(&pt_cdevsw, periph->unit_number, UID_ROOT, 326 GID_OPERATOR, 0600, "%s%d", periph->periph_name, 327 periph->unit_number); 328 softc->dev->si_drv1 = periph; 329 330 /* 331 * Add async callbacks for bus reset and 332 * bus device reset calls. I don't bother 333 * checking if this fails as, in most cases, 334 * the system will function just fine without 335 * them and the only alternative would be to 336 * not attach the device on failure. 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_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 341 csa.callback = ptasync; 342 csa.callback_arg = periph; 343 xpt_action((union ccb *)&csa); 344 345 /* Tell the user we've attached to the device */ 346 xpt_announce_periph(periph, NULL); 347 348 return(CAM_REQ_CMP); 349} 350 351static void 352ptoninvalidate(struct cam_periph *periph) 353{ 354 int s; 355 struct pt_softc *softc; 356 struct bio *q_bp; 357 struct ccb_setasync csa; 358 359 softc = (struct pt_softc *)periph->softc; 360 361 /* 362 * De-register any async callbacks. 363 */ 364 xpt_setup_ccb(&csa.ccb_h, periph->path, 365 /* priority */ 5); 366 csa.ccb_h.func_code = XPT_SASYNC_CB; 367 csa.event_enable = 0; 368 csa.callback = ptasync; 369 csa.callback_arg = periph; 370 xpt_action((union ccb *)&csa); 371 372 softc->flags |= PT_FLAG_DEVICE_INVALID; 373 374 /* 375 * Although the oninvalidate() routines are always called at 376 * splsoftcam, we need to be at splbio() here to keep the buffer 377 * queue from being modified while we traverse it. 378 */ 379 s = splbio(); 380 381 /* 382 * Return all queued I/O with ENXIO. 383 * XXX Handle any transactions queued to the card 384 * with XPT_ABORT_CCB. 385 */ 386 while ((q_bp = bioq_first(&softc->bio_queue)) != NULL){ 387 bioq_remove(&softc->bio_queue, q_bp); 388 q_bp->bio_resid = q_bp->bio_bcount; 389 biofinish(q_bp, NULL, ENXIO); 390 } 391 392 splx(s); 393 394 xpt_print_path(periph->path); 395 printf("lost device\n"); 396} 397 398static void 399ptdtor(struct cam_periph *periph) 400{ 401 struct pt_softc *softc; 402 403 softc = (struct pt_softc *)periph->softc; 404 405 devstat_remove_entry(&softc->device_stats); 406 407 destroy_dev(softc->dev); 408 409 xpt_print_path(periph->path); 410 printf("removing device entry\n"); 411 free(softc, M_DEVBUF); 412} 413 414static void 415ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 416{ 417 struct cam_periph *periph; 418 419 periph = (struct cam_periph *)callback_arg; 420 switch (code) { 421 case AC_FOUND_DEVICE: 422 { 423 struct ccb_getdev *cgd; 424 cam_status status; 425 426 cgd = (struct ccb_getdev *)arg; 427 if (cgd == NULL) 428 break; 429 430 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR) 431 break; 432 433 /* 434 * Allocate a peripheral instance for 435 * this device and start the probe 436 * process. 437 */ 438 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor, 439 ptstart, "pt", CAM_PERIPH_BIO, 440 cgd->ccb_h.path, ptasync, 441 AC_FOUND_DEVICE, cgd); 442 443 if (status != CAM_REQ_CMP 444 && status != CAM_REQ_INPROG) 445 printf("ptasync: Unable to attach to new device " 446 "due to status 0x%x\n", status); 447 break; 448 } 449 case AC_SENT_BDR: 450 case AC_BUS_RESET: 451 { 452 struct pt_softc *softc; 453 struct ccb_hdr *ccbh; 454 int s; 455 456 softc = (struct pt_softc *)periph->softc; 457 s = splsoftcam(); 458 /* 459 * Don't fail on the expected unit attention 460 * that will occur. 461 */ 462 softc->flags |= PT_FLAG_RETRY_UA; 463 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 464 ccbh->ccb_state |= PT_CCB_RETRY_UA; 465 splx(s); 466 /* FALLTHROUGH */ 467 } 468 default: 469 cam_periph_async(periph, code, path, arg); 470 break; 471 } 472} 473 474static void 475ptstart(struct cam_periph *periph, union ccb *start_ccb) 476{ 477 struct pt_softc *softc; 478 struct bio *bp; 479 int s; 480 481 softc = (struct pt_softc *)periph->softc; 482 483 /* 484 * See if there is a buf with work for us to do.. 485 */ 486 s = splbio(); 487 bp = bioq_first(&softc->bio_queue); 488 if (periph->immediate_priority <= periph->pinfo.priority) { 489 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 490 ("queuing for immediate ccb\n")); 491 start_ccb->ccb_h.ccb_state = PT_CCB_WAITING; 492 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 493 periph_links.sle); 494 periph->immediate_priority = CAM_PRIORITY_NONE; 495 splx(s); 496 wakeup(&periph->ccb_list); 497 } else if (bp == NULL) { 498 splx(s); 499 xpt_release_ccb(start_ccb); 500 } else { 501 int oldspl; 502 503 bioq_remove(&softc->bio_queue, bp); 504 505 devstat_start_transaction(&softc->device_stats); 506 507 scsi_send_receive(&start_ccb->csio, 508 /*retries*/4, 509 ptdone, 510 MSG_SIMPLE_Q_TAG, 511 bp->bio_cmd == BIO_READ, 512 /*byte2*/0, 513 bp->bio_bcount, 514 bp->bio_data, 515 /*sense_len*/SSD_FULL_SIZE, 516 /*timeout*/softc->io_timeout); 517 518 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA; 519 520 /* 521 * Block out any asyncronous callbacks 522 * while we touch the pending ccb list. 523 */ 524 oldspl = splcam(); 525 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, 526 periph_links.le); 527 splx(oldspl); 528 529 start_ccb->ccb_h.ccb_bp = bp; 530 bp = bioq_first(&softc->bio_queue); 531 splx(s); 532 533 xpt_action(start_ccb); 534 535 if (bp != NULL) { 536 /* Have more work to do, so ensure we stay scheduled */ 537 xpt_schedule(periph, /* XXX priority */1); 538 } 539 } 540} 541 542static void 543ptdone(struct cam_periph *periph, union ccb *done_ccb) 544{ 545 struct pt_softc *softc; 546 struct ccb_scsiio *csio; 547 548 softc = (struct pt_softc *)periph->softc; 549 csio = &done_ccb->csio; 550 switch (csio->ccb_h.ccb_state) { 551 case PT_CCB_BUFFER_IO: 552 case PT_CCB_BUFFER_IO_UA: 553 { 554 struct bio *bp; 555 int oldspl; 556 557 bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 558 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 559 int error; 560 int s; 561 int sf; 562 563 if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0) 564 sf = SF_RETRY_UA; 565 else 566 sf = 0; 567 568 error = pterror(done_ccb, CAM_RETRY_SELTO, sf); 569 if (error == ERESTART) { 570 /* 571 * A retry was scheuled, so 572 * just return. 573 */ 574 return; 575 } 576 if (error != 0) { 577 struct bio *q_bp; 578 579 s = splbio(); 580 581 if (error == ENXIO) { 582 /* 583 * Catastrophic error. Mark our device 584 * as invalid. 585 */ 586 xpt_print_path(periph->path); 587 printf("Invalidating device\n"); 588 softc->flags |= PT_FLAG_DEVICE_INVALID; 589 } 590 591 /* 592 * return all queued I/O with EIO, so that 593 * the client can retry these I/Os in the 594 * proper order should it attempt to recover. 595 */ 596 while ((q_bp = bioq_first(&softc->bio_queue)) 597 != NULL) { 598 bioq_remove(&softc->bio_queue, q_bp); 599 q_bp->bio_resid = q_bp->bio_bcount; 600 biofinish(q_bp, NULL, EIO); 601 } 602 splx(s); 603 bp->bio_error = error; 604 bp->bio_resid = bp->bio_bcount; 605 bp->bio_flags |= BIO_ERROR; 606 } else { 607 bp->bio_resid = csio->resid; 608 bp->bio_error = 0; 609 if (bp->bio_resid != 0) { 610 /* Short transfer ??? */ 611 bp->bio_flags |= BIO_ERROR; 612 } 613 } 614 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 615 cam_release_devq(done_ccb->ccb_h.path, 616 /*relsim_flags*/0, 617 /*reduction*/0, 618 /*timeout*/0, 619 /*getcount_only*/0); 620 } else { 621 bp->bio_resid = csio->resid; 622 if (bp->bio_resid != 0) 623 bp->bio_flags |= BIO_ERROR; 624 } 625 626 /* 627 * Block out any asyncronous callbacks 628 * while we touch the pending ccb list. 629 */ 630 oldspl = splcam(); 631 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 632 splx(oldspl); 633 634 biofinish(bp, &softc->device_stats, 0); 635 break; 636 } 637 case PT_CCB_WAITING: 638 /* Caller will release the CCB */ 639 wakeup(&done_ccb->ccb_h.cbfcnp); 640 return; 641 } 642 xpt_release_ccb(done_ccb); 643} 644 645static int 646pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 647{ 648 struct pt_softc *softc; 649 struct cam_periph *periph; 650 651 periph = xpt_path_periph(ccb->ccb_h.path); 652 softc = (struct pt_softc *)periph->softc; 653 654 return(cam_periph_error(ccb, cam_flags, sense_flags, 655 &softc->saved_ccb)); 656} 657 658static int 659ptioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 660{ 661 struct cam_periph *periph; 662 struct pt_softc *softc; 663 int error; 664 665 periph = (struct cam_periph *)dev->si_drv1; 666 if (periph == NULL) 667 return(ENXIO); 668 669 softc = (struct pt_softc *)periph->softc; 670 671 if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { 672 return (error); /* error code from tsleep */ 673 } 674 675 switch(cmd) { 676 case PTIOCGETTIMEOUT: 677 if (softc->io_timeout >= 1000) 678 *(int *)addr = softc->io_timeout / 1000; 679 else 680 *(int *)addr = 0; 681 break; 682 case PTIOCSETTIMEOUT: 683 { 684 int s; 685 686 if (*(int *)addr < 1) { 687 error = EINVAL; 688 break; 689 } 690 691 s = splsoftcam(); 692 softc->io_timeout = *(int *)addr * 1000; 693 splx(s); 694 695 break; 696 } 697 default: 698 error = cam_periph_ioctl(periph, cmd, addr, pterror); 699 break; 700 } 701 702 cam_periph_unlock(periph); 703 704 return(error); 705} 706 707void 708scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 709 void (*cbfcnp)(struct cam_periph *, union ccb *), 710 u_int tag_action, int readop, u_int byte2, 711 u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, 712 u_int32_t timeout) 713{ 714 struct scsi_send_receive *scsi_cmd; 715 716 scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes; 717 scsi_cmd->opcode = readop ? RECEIVE : SEND; 718 scsi_cmd->byte2 = byte2; 719 scsi_ulto3b(xfer_len, scsi_cmd->xfer_len); 720 scsi_cmd->control = 0; 721 722 cam_fill_csio(csio, 723 retries, 724 cbfcnp, 725 /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, 726 tag_action, 727 data_ptr, 728 xfer_len, 729 sense_len, 730 sizeof(*scsi_cmd), 731 timeout); 732}
|