2 * SPDX-License-Identifier: BSD-2-Clause
4 * Implementation of SCSI Processor Target Peripheral driver for CAM.
6 * Copyright (c) 1998 Justin T. Gibbs.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/cdefs.h>
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>
38 #include <sys/devicestat.h>
39 #include <sys/malloc.h>
44 #include <cam/cam_ccb.h>
45 #include <cam/cam_periph.h>
46 #include <cam/cam_xpt_periph.h>
47 #include <cam/cam_debug.h>
49 #include <cam/scsi/scsi_all.h>
50 #include <cam/scsi/scsi_message.h>
51 #include <cam/scsi/scsi_pt.h>
63 PT_FLAG_DEVICE_INVALID = 0x02,
64 PT_FLAG_RETRY_UA = 0x04
68 PT_CCB_BUFFER_IO = 0x01,
69 PT_CCB_RETRY_UA = 0x04,
70 PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
73 /* Offsets into our private area for storing information */
74 #define ccb_state ppriv_field0
75 #define ccb_bp ppriv_ptr1
78 struct bio_queue_head bio_queue;
79 struct devstat *device_stats;
80 LIST_HEAD(, ccb_hdr) pending_ccbs;
87 static d_open_t ptopen;
88 static d_close_t ptclose;
89 static d_strategy_t ptstrategy;
90 static periph_init_t ptinit;
91 static void ptasync(void *callback_arg, uint32_t code,
92 struct cam_path *path, void *arg);
93 static periph_ctor_t ptctor;
94 static periph_oninv_t ptoninvalidate;
95 static periph_dtor_t ptdtor;
96 static periph_start_t ptstart;
97 static void ptdone(struct cam_periph *periph,
99 static d_ioctl_t ptioctl;
100 static int pterror(union ccb *ccb, uint32_t cam_flags,
101 uint32_t sense_flags);
103 void scsi_send_receive(struct ccb_scsiio *csio, uint32_t retries,
104 void (*cbfcnp)(struct cam_periph *, union ccb *),
105 u_int tag_action, int readop, u_int byte2,
106 uint32_t xfer_len, uint8_t *data_ptr,
107 uint8_t sense_len, uint32_t timeout);
109 static struct periph_driver ptdriver =
112 TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
115 PERIPHDRIVER_DECLARE(pt, ptdriver);
117 static struct cdevsw pt_cdevsw = {
118 .d_version = D_VERSION,
123 .d_write = physwrite,
125 .d_strategy = ptstrategy,
129 #ifndef SCSI_PT_DEFAULT_TIMEOUT
130 #define SCSI_PT_DEFAULT_TIMEOUT 60
134 ptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
136 struct cam_periph *periph;
137 struct pt_softc *softc;
140 periph = (struct cam_periph *)dev->si_drv1;
141 if (cam_periph_acquire(periph) != 0)
144 softc = (struct pt_softc *)periph->softc;
146 cam_periph_lock(periph);
147 if (softc->flags & PT_FLAG_DEVICE_INVALID) {
148 cam_periph_release_locked(periph);
149 cam_periph_unlock(periph);
153 if ((softc->flags & PT_FLAG_OPEN) == 0)
154 softc->flags |= PT_FLAG_OPEN;
157 cam_periph_release(periph);
160 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
161 ("ptopen: dev=%s\n", devtoname(dev)));
163 cam_periph_unlock(periph);
168 ptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
170 struct cam_periph *periph;
171 struct pt_softc *softc;
173 periph = (struct cam_periph *)dev->si_drv1;
174 softc = (struct pt_softc *)periph->softc;
176 cam_periph_lock(periph);
178 softc->flags &= ~PT_FLAG_OPEN;
179 cam_periph_release_locked(periph);
180 cam_periph_unlock(periph);
185 * Actually translate the requested transfer into one the physical driver
186 * can understand. The transfer is described by a buf and will include
187 * only one physical transfer.
190 ptstrategy(struct bio *bp)
192 struct cam_periph *periph;
193 struct pt_softc *softc;
195 periph = (struct cam_periph *)bp->bio_dev->si_drv1;
196 bp->bio_resid = bp->bio_bcount;
197 if (periph == NULL) {
198 biofinish(bp, NULL, ENXIO);
201 cam_periph_lock(periph);
202 softc = (struct pt_softc *)periph->softc;
205 * If the device has been made invalid, error out
207 if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
208 cam_periph_unlock(periph);
209 biofinish(bp, NULL, ENXIO);
214 * Place it in the queue of disk activities for this disk
216 bioq_insert_tail(&softc->bio_queue, bp);
219 * Schedule ourselves for performing the work.
221 xpt_schedule(periph, CAM_PRIORITY_NORMAL);
222 cam_periph_unlock(periph);
233 * Install a global async callback. This callback will
234 * receive async callbacks like "new device found".
236 status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL);
238 if (status != CAM_REQ_CMP) {
239 printf("pt: Failed to attach master async callback "
240 "due to status 0x%x!\n", status);
245 ptctor(struct cam_periph *periph, void *arg)
247 struct pt_softc *softc;
248 struct ccb_getdev *cgd;
249 struct ccb_pathinq cpi;
250 struct make_dev_args args;
253 cgd = (struct ccb_getdev *)arg;
255 printf("ptregister: no getdev CCB, can't register device\n");
256 return(CAM_REQ_CMP_ERR);
259 softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
262 printf("daregister: Unable to probe new device. "
263 "Unable to allocate softc\n");
264 return(CAM_REQ_CMP_ERR);
267 bzero(softc, sizeof(*softc));
268 LIST_INIT(&softc->pending_ccbs);
269 softc->state = PT_STATE_NORMAL;
270 bioq_init(&softc->bio_queue);
272 softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
274 periph->softc = softc;
276 xpt_path_inq(&cpi, periph->path);
278 cam_periph_unlock(periph);
280 make_dev_args_init(&args);
281 args.mda_devsw = &pt_cdevsw;
282 args.mda_unit = periph->unit_number;
283 args.mda_uid = UID_ROOT;
284 args.mda_gid = GID_OPERATOR;
285 args.mda_mode = 0600;
286 args.mda_si_drv1 = periph;
287 error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
288 periph->unit_number);
290 cam_periph_lock(periph);
291 return (CAM_REQ_CMP_ERR);
294 softc->device_stats = devstat_new_entry("pt",
295 periph->unit_number, 0,
296 DEVSTAT_NO_BLOCKSIZE,
297 SID_TYPE(&cgd->inq_data) |
298 XPORT_DEVSTAT_TYPE(cpi.transport),
299 DEVSTAT_PRIORITY_OTHER);
301 cam_periph_lock(periph);
304 * Add async callbacks for bus reset and
305 * bus device reset calls. I don't bother
306 * checking if this fails as, in most cases,
307 * the system will function just fine without
308 * them and the only alternative would be to
309 * not attach the device on failure.
311 xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
312 ptasync, periph, periph->path);
314 /* Tell the user we've attached to the device */
315 xpt_announce_periph(periph, NULL);
321 ptoninvalidate(struct cam_periph *periph)
323 struct pt_softc *softc;
325 softc = (struct pt_softc *)periph->softc;
328 * De-register any async callbacks.
330 xpt_register_async(0, ptasync, periph, periph->path);
332 softc->flags |= PT_FLAG_DEVICE_INVALID;
335 * Return all queued I/O with ENXIO.
336 * XXX Handle any transactions queued to the card
337 * with XPT_ABORT_CCB.
339 bioq_flush(&softc->bio_queue, NULL, ENXIO);
343 ptdtor(struct cam_periph *periph)
345 struct pt_softc *softc;
347 softc = (struct pt_softc *)periph->softc;
349 devstat_remove_entry(softc->device_stats);
350 cam_periph_unlock(periph);
351 destroy_dev(softc->dev);
352 cam_periph_lock(periph);
353 free(softc, M_DEVBUF);
357 ptasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
359 struct cam_periph *periph;
361 periph = (struct cam_periph *)callback_arg;
363 case AC_FOUND_DEVICE:
365 struct ccb_getdev *cgd;
368 cgd = (struct ccb_getdev *)arg;
372 if (cgd->protocol != PROTO_SCSI)
374 if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED)
376 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
380 * Allocate a peripheral instance for
381 * this device and start the probe
384 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
385 ptstart, "pt", CAM_PERIPH_BIO,
387 AC_FOUND_DEVICE, cgd);
389 if (status != CAM_REQ_CMP
390 && status != CAM_REQ_INPROG)
391 printf("ptasync: Unable to attach to new device "
392 "due to status 0x%x\n", status);
398 struct pt_softc *softc;
399 struct ccb_hdr *ccbh;
401 softc = (struct pt_softc *)periph->softc;
403 * Don't fail on the expected unit attention
406 softc->flags |= PT_FLAG_RETRY_UA;
407 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
408 ccbh->ccb_state |= PT_CCB_RETRY_UA;
412 cam_periph_async(periph, code, path, arg);
418 ptstart(struct cam_periph *periph, union ccb *start_ccb)
420 struct pt_softc *softc;
423 softc = (struct pt_softc *)periph->softc;
425 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n"));
428 * See if there is a buf with work for us to do..
430 bp = bioq_first(&softc->bio_queue);
432 xpt_release_ccb(start_ccb);
434 bioq_remove(&softc->bio_queue, bp);
436 devstat_start_transaction_bio(softc->device_stats, bp);
438 scsi_send_receive(&start_ccb->csio,
442 bp->bio_cmd == BIO_READ,
446 /*sense_len*/SSD_FULL_SIZE,
447 /*timeout*/softc->io_timeout);
449 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
452 * Block out any asynchronous callbacks
453 * while we touch the pending ccb list.
455 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
458 start_ccb->ccb_h.ccb_bp = bp;
459 bp = bioq_first(&softc->bio_queue);
461 xpt_action(start_ccb);
464 /* Have more work to do, so ensure we stay scheduled */
465 xpt_schedule(periph, CAM_PRIORITY_NORMAL);
471 ptdone(struct cam_periph *periph, union ccb *done_ccb)
473 struct pt_softc *softc;
474 struct ccb_scsiio *csio;
476 softc = (struct pt_softc *)periph->softc;
478 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n"));
480 csio = &done_ccb->csio;
481 switch (csio->ccb_h.ccb_state) {
482 case PT_CCB_BUFFER_IO:
483 case PT_CCB_BUFFER_IO_UA:
487 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
488 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
492 if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
497 error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
498 if (error == ERESTART) {
500 * A retry was scheuled, so
506 if (error == ENXIO) {
508 * Catastrophic error. Mark our device
511 xpt_print(periph->path,
512 "Invalidating device\n");
513 softc->flags |= PT_FLAG_DEVICE_INVALID;
517 * return all queued I/O with EIO, so that
518 * the client can retry these I/Os in the
519 * proper order should it attempt to recover.
521 bioq_flush(&softc->bio_queue, NULL, EIO);
522 bp->bio_error = error;
523 bp->bio_resid = bp->bio_bcount;
524 bp->bio_flags |= BIO_ERROR;
526 bp->bio_resid = csio->resid;
528 if (bp->bio_resid != 0) {
529 /* Short transfer ??? */
530 bp->bio_flags |= BIO_ERROR;
533 if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
534 cam_release_devq(done_ccb->ccb_h.path,
540 bp->bio_resid = csio->resid;
541 if (bp->bio_resid != 0)
542 bp->bio_flags |= BIO_ERROR;
546 * Block out any asynchronous callbacks
547 * while we touch the pending ccb list.
549 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
551 biofinish(bp, softc->device_stats, 0);
555 xpt_release_ccb(done_ccb);
559 pterror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
562 return(cam_periph_error(ccb, cam_flags, sense_flags));
566 ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
568 struct cam_periph *periph;
569 struct pt_softc *softc;
572 periph = (struct cam_periph *)dev->si_drv1;
573 softc = (struct pt_softc *)periph->softc;
575 cam_periph_lock(periph);
578 case PTIOCGETTIMEOUT:
579 if (softc->io_timeout >= 1000)
580 *(int *)addr = softc->io_timeout / 1000;
584 case PTIOCSETTIMEOUT:
585 if (*(int *)addr < 1) {
590 softc->io_timeout = *(int *)addr * 1000;
594 error = cam_periph_ioctl(periph, cmd, addr, pterror);
598 cam_periph_unlock(periph);
604 scsi_send_receive(struct ccb_scsiio *csio, uint32_t retries,
605 void (*cbfcnp)(struct cam_periph *, union ccb *),
606 u_int tag_action, int readop, u_int byte2,
607 uint32_t xfer_len, uint8_t *data_ptr, uint8_t sense_len,
610 struct scsi_send_receive *scsi_cmd;
612 scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
613 scsi_cmd->opcode = readop ? RECEIVE : SEND;
614 scsi_cmd->byte2 = byte2;
615 scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
616 scsi_cmd->control = 0;
621 /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,