1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Implementation of SCSI Processor Target Peripheral driver for CAM. 5 * 6 * Copyright (c) 1998 Justin T. Gibbs. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions, and the following disclaimer, 14 * without modification, immediately at the beginning of the file. 15 * 2. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/queue.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/types.h> 39 #include <sys/bio.h> 40 #include <sys/devicestat.h> 41 #include <sys/malloc.h> 42 #include <sys/conf.h> 43 #include <sys/ptio.h> 44 45 #include <cam/cam.h> 46 #include <cam/cam_ccb.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_pt.h> 54 55 #include "opt_pt.h" 56 57 typedef enum { 58 PT_STATE_PROBE, 59 PT_STATE_NORMAL 60 } pt_state; 61 62 typedef enum { 63 PT_FLAG_NONE = 0x00, 64 PT_FLAG_OPEN = 0x01, 65 PT_FLAG_DEVICE_INVALID = 0x02, 66 PT_FLAG_RETRY_UA = 0x04 67 } pt_flags; 68 69 typedef enum { 70 PT_CCB_BUFFER_IO = 0x01, 71 PT_CCB_RETRY_UA = 0x04, 72 PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA 73 } pt_ccb_state; 74 75 /* Offsets into our private area for storing information */ 76 #define ccb_state ppriv_field0 77 #define ccb_bp ppriv_ptr1 78 79 struct pt_softc { 80 struct bio_queue_head bio_queue; 81 struct devstat *device_stats; 82 LIST_HEAD(, ccb_hdr) pending_ccbs; 83 pt_state state; 84 pt_flags flags; 85 union ccb saved_ccb; 86 int io_timeout; 87 struct cdev *dev; 88 }; 89 90 static d_open_t ptopen; 91 static d_close_t ptclose; 92 static d_strategy_t ptstrategy; 93 static periph_init_t ptinit; 94 static void ptasync(void *callback_arg, u_int32_t code, 95 struct cam_path *path, void *arg); 96 static periph_ctor_t ptctor; 97 static periph_oninv_t ptoninvalidate; 98 static periph_dtor_t ptdtor; 99 static periph_start_t ptstart; 100 static void ptdone(struct cam_periph *periph, 101 union ccb *done_ccb); 102 static d_ioctl_t ptioctl; 103 static int pterror(union ccb *ccb, u_int32_t cam_flags, 104 u_int32_t sense_flags); 105 106 void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 107 void (*cbfcnp)(struct cam_periph *, union ccb *), 108 u_int tag_action, int readop, u_int byte2, 109 u_int32_t xfer_len, u_int8_t *data_ptr, 110 u_int8_t sense_len, u_int32_t timeout); 111 112 static struct periph_driver ptdriver = 113 { 114 ptinit, "pt", 115 TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0 116 }; 117 118 PERIPHDRIVER_DECLARE(pt, ptdriver); 119 120 static struct cdevsw pt_cdevsw = { 121 .d_version = D_VERSION, 122 .d_flags = 0, 123 .d_open = ptopen, 124 .d_close = ptclose, 125 .d_read = physread, 126 .d_write = physwrite, 127 .d_ioctl = ptioctl, 128 .d_strategy = ptstrategy, 129 .d_name = "pt", 130 }; 131 132 #ifndef SCSI_PT_DEFAULT_TIMEOUT 133 #define SCSI_PT_DEFAULT_TIMEOUT 60 134 #endif 135 136 static int 137 ptopen(struct cdev *dev, int flags, int fmt, struct thread *td) 138 { 139 struct cam_periph *periph; 140 struct pt_softc *softc; 141 int error = 0; 142 143 periph = (struct cam_periph *)dev->si_drv1; 144 if (cam_periph_acquire(periph) != 0) 145 return (ENXIO); 146 147 softc = (struct pt_softc *)periph->softc; 148 149 cam_periph_lock(periph); 150 if (softc->flags & PT_FLAG_DEVICE_INVALID) { 151 cam_periph_release_locked(periph); 152 cam_periph_unlock(periph); 153 return(ENXIO); 154 } 155 156 if ((softc->flags & PT_FLAG_OPEN) == 0) 157 softc->flags |= PT_FLAG_OPEN; 158 else { 159 error = EBUSY; 160 cam_periph_release(periph); 161 } 162 163 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 164 ("ptopen: dev=%s\n", devtoname(dev))); 165 166 cam_periph_unlock(periph); 167 return (error); 168 } 169 170 static int 171 ptclose(struct cdev *dev, int flag, int fmt, struct thread *td) 172 { 173 struct cam_periph *periph; 174 struct pt_softc *softc; 175 176 periph = (struct cam_periph *)dev->si_drv1; 177 softc = (struct pt_softc *)periph->softc; 178 179 cam_periph_lock(periph); 180 181 softc->flags &= ~PT_FLAG_OPEN; 182 cam_periph_release_locked(periph); 183 cam_periph_unlock(periph); 184 return (0); 185 } 186 187 /* 188 * Actually translate the requested transfer into one the physical driver 189 * can understand. The transfer is described by a buf and will include 190 * only one physical transfer. 191 */ 192 static void 193 ptstrategy(struct bio *bp) 194 { 195 struct cam_periph *periph; 196 struct pt_softc *softc; 197 198 periph = (struct cam_periph *)bp->bio_dev->si_drv1; 199 bp->bio_resid = bp->bio_bcount; 200 if (periph == NULL) { 201 biofinish(bp, NULL, ENXIO); 202 return; 203 } 204 cam_periph_lock(periph); 205 softc = (struct pt_softc *)periph->softc; 206 207 /* 208 * If the device has been made invalid, error out 209 */ 210 if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { 211 cam_periph_unlock(periph); 212 biofinish(bp, NULL, ENXIO); 213 return; 214 } 215 216 /* 217 * Place it in the queue of disk activities for this disk 218 */ 219 bioq_insert_tail(&softc->bio_queue, bp); 220 221 /* 222 * Schedule ourselves for performing the work. 223 */ 224 xpt_schedule(periph, CAM_PRIORITY_NORMAL); 225 cam_periph_unlock(periph); 226 227 return; 228 } 229 230 static void 231 ptinit(void) 232 { 233 cam_status status; 234 235 /* 236 * Install a global async callback. This callback will 237 * receive async callbacks like "new device found". 238 */ 239 status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL); 240 241 if (status != CAM_REQ_CMP) { 242 printf("pt: Failed to attach master async callback " 243 "due to status 0x%x!\n", status); 244 } 245 } 246 247 static cam_status 248 ptctor(struct cam_periph *periph, void *arg) 249 { 250 struct pt_softc *softc; 251 struct ccb_getdev *cgd; 252 struct ccb_pathinq cpi; 253 struct make_dev_args args; 254 int error; 255 256 cgd = (struct ccb_getdev *)arg; 257 if (cgd == NULL) { 258 printf("ptregister: no getdev CCB, can't register device\n"); 259 return(CAM_REQ_CMP_ERR); 260 } 261 262 softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 263 264 if (softc == NULL) { 265 printf("daregister: Unable to probe new device. " 266 "Unable to allocate softc\n"); 267 return(CAM_REQ_CMP_ERR); 268 } 269 270 bzero(softc, sizeof(*softc)); 271 LIST_INIT(&softc->pending_ccbs); 272 softc->state = PT_STATE_NORMAL; 273 bioq_init(&softc->bio_queue); 274 275 softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000; 276 277 periph->softc = softc; 278 279 xpt_path_inq(&cpi, periph->path); 280 281 cam_periph_unlock(periph); 282 283 make_dev_args_init(&args); 284 args.mda_devsw = &pt_cdevsw; 285 args.mda_unit = periph->unit_number; 286 args.mda_uid = UID_ROOT; 287 args.mda_gid = GID_OPERATOR; 288 args.mda_mode = 0600; 289 args.mda_si_drv1 = periph; 290 error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name, 291 periph->unit_number); 292 if (error != 0) { 293 cam_periph_lock(periph); 294 return (CAM_REQ_CMP_ERR); 295 } 296 297 softc->device_stats = devstat_new_entry("pt", 298 periph->unit_number, 0, 299 DEVSTAT_NO_BLOCKSIZE, 300 SID_TYPE(&cgd->inq_data) | 301 XPORT_DEVSTAT_TYPE(cpi.transport), 302 DEVSTAT_PRIORITY_OTHER); 303 304 cam_periph_lock(periph); 305 306 /* 307 * Add async callbacks for bus reset and 308 * bus device reset calls. I don't bother 309 * checking if this fails as, in most cases, 310 * the system will function just fine without 311 * them and the only alternative would be to 312 * not attach the device on failure. 313 */ 314 xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE, 315 ptasync, periph, periph->path); 316 317 /* Tell the user we've attached to the device */ 318 xpt_announce_periph(periph, NULL); 319 320 return(CAM_REQ_CMP); 321 } 322 323 static void 324 ptoninvalidate(struct cam_periph *periph) 325 { 326 struct pt_softc *softc; 327 328 softc = (struct pt_softc *)periph->softc; 329 330 /* 331 * De-register any async callbacks. 332 */ 333 xpt_register_async(0, ptasync, periph, periph->path); 334 335 softc->flags |= PT_FLAG_DEVICE_INVALID; 336 337 /* 338 * Return all queued I/O with ENXIO. 339 * XXX Handle any transactions queued to the card 340 * with XPT_ABORT_CCB. 341 */ 342 bioq_flush(&softc->bio_queue, NULL, ENXIO); 343 } 344 345 static void 346 ptdtor(struct cam_periph *periph) 347 { 348 struct pt_softc *softc; 349 350 softc = (struct pt_softc *)periph->softc; 351 352 devstat_remove_entry(softc->device_stats); 353 cam_periph_unlock(periph); 354 destroy_dev(softc->dev); 355 cam_periph_lock(periph); 356 free(softc, M_DEVBUF); 357 } 358 359 static void 360 ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 361 { 362 struct cam_periph *periph; 363 364 periph = (struct cam_periph *)callback_arg; 365 switch (code) { 366 case AC_FOUND_DEVICE: 367 { 368 struct ccb_getdev *cgd; 369 cam_status status; 370 371 cgd = (struct ccb_getdev *)arg; 372 if (cgd == NULL) 373 break; 374 375 if (cgd->protocol != PROTO_SCSI) 376 break; 377 if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED) 378 break; 379 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR) 380 break; 381 382 /* 383 * Allocate a peripheral instance for 384 * this device and start the probe 385 * process. 386 */ 387 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor, 388 ptstart, "pt", CAM_PERIPH_BIO, 389 path, ptasync, 390 AC_FOUND_DEVICE, cgd); 391 392 if (status != CAM_REQ_CMP 393 && status != CAM_REQ_INPROG) 394 printf("ptasync: Unable to attach to new device " 395 "due to status 0x%x\n", status); 396 break; 397 } 398 case AC_SENT_BDR: 399 case AC_BUS_RESET: 400 { 401 struct pt_softc *softc; 402 struct ccb_hdr *ccbh; 403 404 softc = (struct pt_softc *)periph->softc; 405 /* 406 * Don't fail on the expected unit attention 407 * that will occur. 408 */ 409 softc->flags |= PT_FLAG_RETRY_UA; 410 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 411 ccbh->ccb_state |= PT_CCB_RETRY_UA; 412 } 413 /* FALLTHROUGH */ 414 default: 415 cam_periph_async(periph, code, path, arg); 416 break; 417 } 418 } 419 420 static void 421 ptstart(struct cam_periph *periph, union ccb *start_ccb) 422 { 423 struct pt_softc *softc; 424 struct bio *bp; 425 426 softc = (struct pt_softc *)periph->softc; 427 428 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n")); 429 430 /* 431 * See if there is a buf with work for us to do.. 432 */ 433 bp = bioq_first(&softc->bio_queue); 434 if (bp == NULL) { 435 xpt_release_ccb(start_ccb); 436 } else { 437 bioq_remove(&softc->bio_queue, bp); 438 439 devstat_start_transaction_bio(softc->device_stats, bp); 440 441 scsi_send_receive(&start_ccb->csio, 442 /*retries*/4, 443 ptdone, 444 MSG_SIMPLE_Q_TAG, 445 bp->bio_cmd == BIO_READ, 446 /*byte2*/0, 447 bp->bio_bcount, 448 bp->bio_data, 449 /*sense_len*/SSD_FULL_SIZE, 450 /*timeout*/softc->io_timeout); 451 452 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA; 453 454 /* 455 * Block out any asynchronous callbacks 456 * while we touch the pending ccb list. 457 */ 458 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, 459 periph_links.le); 460 461 start_ccb->ccb_h.ccb_bp = bp; 462 bp = bioq_first(&softc->bio_queue); 463 464 xpt_action(start_ccb); 465 466 if (bp != NULL) { 467 /* Have more work to do, so ensure we stay scheduled */ 468 xpt_schedule(periph, CAM_PRIORITY_NORMAL); 469 } 470 } 471 } 472 473 static void 474 ptdone(struct cam_periph *periph, union ccb *done_ccb) 475 { 476 struct pt_softc *softc; 477 struct ccb_scsiio *csio; 478 479 softc = (struct pt_softc *)periph->softc; 480 481 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n")); 482 483 csio = &done_ccb->csio; 484 switch (csio->ccb_h.ccb_state) { 485 case PT_CCB_BUFFER_IO: 486 case PT_CCB_BUFFER_IO_UA: 487 { 488 struct bio *bp; 489 490 bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 491 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 492 int error; 493 int sf; 494 495 if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0) 496 sf = SF_RETRY_UA; 497 else 498 sf = 0; 499 500 error = pterror(done_ccb, CAM_RETRY_SELTO, sf); 501 if (error == ERESTART) { 502 /* 503 * A retry was scheuled, so 504 * just return. 505 */ 506 return; 507 } 508 if (error != 0) { 509 if (error == ENXIO) { 510 /* 511 * Catastrophic error. Mark our device 512 * as invalid. 513 */ 514 xpt_print(periph->path, 515 "Invalidating device\n"); 516 softc->flags |= PT_FLAG_DEVICE_INVALID; 517 } 518 519 /* 520 * return all queued I/O with EIO, so that 521 * the client can retry these I/Os in the 522 * proper order should it attempt to recover. 523 */ 524 bioq_flush(&softc->bio_queue, NULL, EIO); 525 bp->bio_error = error; 526 bp->bio_resid = bp->bio_bcount; 527 bp->bio_flags |= BIO_ERROR; 528 } else { 529 bp->bio_resid = csio->resid; 530 bp->bio_error = 0; 531 if (bp->bio_resid != 0) { 532 /* Short transfer ??? */ 533 bp->bio_flags |= BIO_ERROR; 534 } 535 } 536 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 537 cam_release_devq(done_ccb->ccb_h.path, 538 /*relsim_flags*/0, 539 /*reduction*/0, 540 /*timeout*/0, 541 /*getcount_only*/0); 542 } else { 543 bp->bio_resid = csio->resid; 544 if (bp->bio_resid != 0) 545 bp->bio_flags |= BIO_ERROR; 546 } 547 548 /* 549 * Block out any asynchronous callbacks 550 * while we touch the pending ccb list. 551 */ 552 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 553 554 biofinish(bp, softc->device_stats, 0); 555 break; 556 } 557 } 558 xpt_release_ccb(done_ccb); 559 } 560 561 static int 562 pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 563 { 564 struct pt_softc *softc; 565 struct cam_periph *periph; 566 567 periph = xpt_path_periph(ccb->ccb_h.path); 568 softc = (struct pt_softc *)periph->softc; 569 570 return(cam_periph_error(ccb, cam_flags, sense_flags)); 571 } 572 573 static int 574 ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 575 { 576 struct cam_periph *periph; 577 struct pt_softc *softc; 578 int error = 0; 579 580 periph = (struct cam_periph *)dev->si_drv1; 581 softc = (struct pt_softc *)periph->softc; 582 583 cam_periph_lock(periph); 584 585 switch(cmd) { 586 case PTIOCGETTIMEOUT: 587 if (softc->io_timeout >= 1000) 588 *(int *)addr = softc->io_timeout / 1000; 589 else 590 *(int *)addr = 0; 591 break; 592 case PTIOCSETTIMEOUT: 593 if (*(int *)addr < 1) { 594 error = EINVAL; 595 break; 596 } 597 598 softc->io_timeout = *(int *)addr * 1000; 599 600 break; 601 default: 602 error = cam_periph_ioctl(periph, cmd, addr, pterror); 603 break; 604 } 605 606 cam_periph_unlock(periph); 607 608 return(error); 609 } 610 611 void 612 scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 613 void (*cbfcnp)(struct cam_periph *, union ccb *), 614 u_int tag_action, int readop, u_int byte2, 615 u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, 616 u_int32_t timeout) 617 { 618 struct scsi_send_receive *scsi_cmd; 619 620 scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes; 621 scsi_cmd->opcode = readop ? RECEIVE : SEND; 622 scsi_cmd->byte2 = byte2; 623 scsi_ulto3b(xfer_len, scsi_cmd->xfer_len); 624 scsi_cmd->control = 0; 625 626 cam_fill_csio(csio, 627 retries, 628 cbfcnp, 629 /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, 630 tag_action, 631 data_ptr, 632 xfer_len, 633 sense_len, 634 sizeof(*scsi_cmd), 635 timeout); 636 } 637