1/*- 2 * Implementation of SCSI Processor Target Peripheral driver for CAM. 3 * 4 * Copyright (c) 1998 Justin T. Gibbs. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 13 unchanged lines hidden (view full) --- 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_pt.c 168752 2007-04-15 08:49:19Z scottl $"); |
31 32#include <sys/param.h> 33#include <sys/queue.h> 34#include <sys/systm.h> 35#include <sys/kernel.h> 36#include <sys/types.h> 37#include <sys/bio.h> 38#include <sys/devicestat.h> --- 75 unchanged lines hidden (view full) --- 114 TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0 115}; 116 117PERIPHDRIVER_DECLARE(pt, ptdriver); 118 119 120static 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 136static int 137ptopen(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) != CAM_REQ_CMP) |
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_unlock(periph); 152 cam_periph_release(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 170static int 171ptclose(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 if (periph == NULL) 178 return (ENXIO); 179 180 softc = (struct pt_softc *)periph->softc; 181 |
182 cam_periph_lock(periph); |
183 184 softc->flags &= ~PT_FLAG_OPEN; 185 cam_periph_unlock(periph); 186 cam_periph_release(periph); 187 return (0); 188} 189 190/* 191 * Actually translate the requested transfer into one the physical driver 192 * can understand. The transfer is described by a buf and will include 193 * only one physical transfer. 194 */ 195static void 196ptstrategy(struct bio *bp) 197{ 198 struct cam_periph *periph; 199 struct pt_softc *softc; |
200 201 periph = (struct cam_periph *)bp->bio_dev->si_drv1; 202 bp->bio_resid = bp->bio_bcount; 203 if (periph == NULL) { 204 biofinish(bp, NULL, ENXIO); 205 return; 206 } |
207 cam_periph_lock(periph); |
208 softc = (struct pt_softc *)periph->softc; 209 210 /* |
211 * If the device has been made invalid, error out 212 */ 213 if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { |
214 cam_periph_unlock(periph); |
215 biofinish(bp, NULL, ENXIO); 216 return; 217 } 218 219 /* 220 * Place it in the queue of disk activities for this disk 221 */ 222 bioq_insert_tail(&softc->bio_queue, bp); 223 |
224 /* 225 * Schedule ourselves for performing the work. 226 */ 227 xpt_schedule(periph, /* XXX priority */1); |
228 cam_periph_unlock(periph); |
229 230 return; 231} 232 233static void 234ptinit(void) 235{ 236 cam_status status; --- 90 unchanged lines hidden (view full) --- 327 xpt_announce_periph(periph, NULL); 328 329 return(CAM_REQ_CMP); 330} 331 332static void 333ptoninvalidate(struct cam_periph *periph) 334{ |
335 struct pt_softc *softc; 336 struct ccb_setasync csa; 337 338 softc = (struct pt_softc *)periph->softc; 339 340 /* 341 * De-register any async callbacks. 342 */ 343 xpt_setup_ccb(&csa.ccb_h, periph->path, 344 /* priority */ 5); 345 csa.ccb_h.func_code = XPT_SASYNC_CB; 346 csa.event_enable = 0; 347 csa.callback = ptasync; 348 csa.callback_arg = periph; 349 xpt_action((union ccb *)&csa); 350 351 softc->flags |= PT_FLAG_DEVICE_INVALID; 352 353 /* |
354 * Return all queued I/O with ENXIO. 355 * XXX Handle any transactions queued to the card 356 * with XPT_ABORT_CCB. 357 */ 358 bioq_flush(&softc->bio_queue, NULL, ENXIO); 359 |
360 xpt_print(periph->path, "lost device\n"); 361} 362 363static void 364ptdtor(struct cam_periph *periph) 365{ 366 struct pt_softc *softc; 367 --- 42 unchanged lines hidden (view full) --- 410 "due to status 0x%x\n", status); 411 break; 412 } 413 case AC_SENT_BDR: 414 case AC_BUS_RESET: 415 { 416 struct pt_softc *softc; 417 struct ccb_hdr *ccbh; |
418 419 softc = (struct pt_softc *)periph->softc; |
420 /* 421 * Don't fail on the expected unit attention 422 * that will occur. 423 */ 424 softc->flags |= PT_FLAG_RETRY_UA; 425 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le) 426 ccbh->ccb_state |= PT_CCB_RETRY_UA; |
427 } 428 /* FALLTHROUGH */ 429 default: 430 cam_periph_async(periph, code, path, arg); 431 break; 432 } 433} 434 435static void 436ptstart(struct cam_periph *periph, union ccb *start_ccb) 437{ 438 struct pt_softc *softc; 439 struct bio *bp; |
440 441 softc = (struct pt_softc *)periph->softc; 442 443 /* 444 * See if there is a buf with work for us to do.. 445 */ |
446 bp = bioq_first(&softc->bio_queue); 447 if (periph->immediate_priority <= periph->pinfo.priority) { 448 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 449 ("queuing for immediate ccb\n")); 450 start_ccb->ccb_h.ccb_state = PT_CCB_WAITING; 451 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 452 periph_links.sle); 453 periph->immediate_priority = CAM_PRIORITY_NONE; |
454 wakeup(&periph->ccb_list); 455 } else if (bp == NULL) { |
456 xpt_release_ccb(start_ccb); 457 } else { |
458 bioq_remove(&softc->bio_queue, bp); 459 460 devstat_start_transaction_bio(softc->device_stats, bp); 461 462 scsi_send_receive(&start_ccb->csio, 463 /*retries*/4, 464 ptdone, 465 MSG_SIMPLE_Q_TAG, --- 5 unchanged lines hidden (view full) --- 471 /*timeout*/softc->io_timeout); 472 473 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA; 474 475 /* 476 * Block out any asyncronous callbacks 477 * while we touch the pending ccb list. 478 */ |
479 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, 480 periph_links.le); |
481 482 start_ccb->ccb_h.ccb_bp = bp; 483 bp = bioq_first(&softc->bio_queue); |
484 485 xpt_action(start_ccb); 486 487 if (bp != NULL) { 488 /* Have more work to do, so ensure we stay scheduled */ 489 xpt_schedule(periph, /* XXX priority */1); 490 } 491 } --- 7 unchanged lines hidden (view full) --- 499 500 softc = (struct pt_softc *)periph->softc; 501 csio = &done_ccb->csio; 502 switch (csio->ccb_h.ccb_state) { 503 case PT_CCB_BUFFER_IO: 504 case PT_CCB_BUFFER_IO_UA: 505 { 506 struct bio *bp; |
507 508 bp = (struct bio *)done_ccb->ccb_h.ccb_bp; 509 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 510 int error; |
511 int sf; 512 513 if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0) 514 sf = SF_RETRY_UA; 515 else 516 sf = 0; 517 518 error = pterror(done_ccb, CAM_RETRY_SELTO, sf); 519 if (error == ERESTART) { 520 /* 521 * A retry was scheuled, so 522 * just return. 523 */ 524 return; 525 } 526 if (error != 0) { |
527 if (error == ENXIO) { 528 /* 529 * Catastrophic error. Mark our device 530 * as invalid. 531 */ 532 xpt_print(periph->path, 533 "Invalidating device\n"); 534 softc->flags |= PT_FLAG_DEVICE_INVALID; 535 } 536 537 /* 538 * return all queued I/O with EIO, so that 539 * the client can retry these I/Os in the 540 * proper order should it attempt to recover. 541 */ 542 bioq_flush(&softc->bio_queue, NULL, EIO); |
543 bp->bio_error = error; 544 bp->bio_resid = bp->bio_bcount; 545 bp->bio_flags |= BIO_ERROR; 546 } else { 547 bp->bio_resid = csio->resid; 548 bp->bio_error = 0; 549 if (bp->bio_resid != 0) { 550 /* Short transfer ??? */ --- 11 unchanged lines hidden (view full) --- 562 if (bp->bio_resid != 0) 563 bp->bio_flags |= BIO_ERROR; 564 } 565 566 /* 567 * Block out any asyncronous callbacks 568 * while we touch the pending ccb list. 569 */ |
570 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); |
571 572 biofinish(bp, softc->device_stats, 0); 573 break; 574 } 575 case PT_CCB_WAITING: 576 /* Caller will release the CCB */ 577 wakeup(&done_ccb->ccb_h.cbfcnp); 578 return; --- 14 unchanged lines hidden (view full) --- 593 &softc->saved_ccb)); 594} 595 596static int 597ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 598{ 599 struct cam_periph *periph; 600 struct pt_softc *softc; |
601 int error = 0; |
602 603 periph = (struct cam_periph *)dev->si_drv1; 604 if (periph == NULL) 605 return(ENXIO); 606 607 softc = (struct pt_softc *)periph->softc; 608 |
609 cam_periph_lock(periph); |
610 611 switch(cmd) { 612 case PTIOCGETTIMEOUT: 613 if (softc->io_timeout >= 1000) 614 *(int *)addr = softc->io_timeout / 1000; 615 else 616 *(int *)addr = 0; 617 break; 618 case PTIOCSETTIMEOUT: |
619 if (*(int *)addr < 1) { 620 error = EINVAL; 621 break; 622 } 623 |
624 softc->io_timeout = *(int *)addr * 1000; |
625 626 break; |
627 default: 628 error = cam_periph_ioctl(periph, cmd, addr, pterror); 629 break; 630 } 631 632 cam_periph_unlock(periph); 633 634 return(error); --- 28 unchanged lines hidden --- |