176babe50SJustin T. Gibbs /* 276babe50SJustin T. Gibbs * Implementation of SCSI Processor Target Peripheral driver for CAM. 376babe50SJustin T. Gibbs * 476babe50SJustin T. Gibbs * Copyright (c) 1998 Justin T. Gibbs. 576babe50SJustin T. Gibbs * All rights reserved. 676babe50SJustin T. Gibbs * 776babe50SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 876babe50SJustin T. Gibbs * modification, are permitted provided that the following conditions 976babe50SJustin T. Gibbs * are met: 1076babe50SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 1176babe50SJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 1276babe50SJustin T. Gibbs * without modification, immediately at the beginning of the file. 1376babe50SJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 1476babe50SJustin T. Gibbs * derived from this software without specific prior written permission. 1576babe50SJustin T. Gibbs * 1676babe50SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1776babe50SJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1876babe50SJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1976babe50SJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2076babe50SJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2176babe50SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2276babe50SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2376babe50SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2476babe50SJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2576babe50SJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2676babe50SJustin T. Gibbs * SUCH DAMAGE. 2776babe50SJustin T. Gibbs * 2822b9c86cSKenneth D. Merry * $Id: scsi_pt.c,v 1.3 1998/10/22 22:16:56 ken Exp $ 2976babe50SJustin T. Gibbs */ 3076babe50SJustin T. Gibbs 3176babe50SJustin T. Gibbs #include <sys/param.h> 3276babe50SJustin T. Gibbs #include <sys/queue.h> 3376babe50SJustin T. Gibbs #include <sys/systm.h> 3476babe50SJustin T. Gibbs #include <sys/kernel.h> 3576babe50SJustin T. Gibbs #include <sys/types.h> 3676babe50SJustin T. Gibbs #include <sys/buf.h> 3776babe50SJustin T. Gibbs #include <sys/devicestat.h> 3876babe50SJustin T. Gibbs #include <sys/malloc.h> 3976babe50SJustin T. Gibbs #include <sys/conf.h> 4076babe50SJustin T. Gibbs 4176babe50SJustin T. Gibbs #include <cam/cam.h> 4276babe50SJustin T. Gibbs #include <cam/cam_ccb.h> 4376babe50SJustin T. Gibbs #include <cam/cam_extend.h> 4476babe50SJustin T. Gibbs #include <cam/cam_periph.h> 4576babe50SJustin T. Gibbs #include <cam/cam_xpt_periph.h> 4676babe50SJustin T. Gibbs #include <cam/cam_debug.h> 4776babe50SJustin T. Gibbs 4876babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h> 4976babe50SJustin T. Gibbs #include <cam/scsi/scsi_message.h> 5076babe50SJustin T. Gibbs #include <cam/scsi/scsi_pt.h> 5176babe50SJustin T. Gibbs 5276babe50SJustin T. Gibbs typedef enum { 5376babe50SJustin T. Gibbs PT_STATE_PROBE, 5476babe50SJustin T. Gibbs PT_STATE_NORMAL 5576babe50SJustin T. Gibbs } pt_state; 5676babe50SJustin T. Gibbs 5776babe50SJustin T. Gibbs typedef enum { 5876babe50SJustin T. Gibbs PT_FLAG_NONE = 0x00, 5976babe50SJustin T. Gibbs PT_FLAG_OPEN = 0x01, 6076babe50SJustin T. Gibbs PT_FLAG_DEVICE_INVALID = 0x02, 6176babe50SJustin T. Gibbs PT_FLAG_RETRY_UA = 0x04 6276babe50SJustin T. Gibbs } pt_flags; 6376babe50SJustin T. Gibbs 6476babe50SJustin T. Gibbs typedef enum { 6576babe50SJustin T. Gibbs PT_CCB_BUFFER_IO = 0x01, 6676babe50SJustin T. Gibbs PT_CCB_WAITING = 0x02, 6776babe50SJustin T. Gibbs PT_CCB_RETRY_UA = 0x04, 6876babe50SJustin T. Gibbs PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA 6976babe50SJustin T. Gibbs } pt_ccb_state; 7076babe50SJustin T. Gibbs 7176babe50SJustin T. Gibbs /* Offsets into our private area for storing information */ 7276babe50SJustin T. Gibbs #define ccb_state ppriv_field0 7376babe50SJustin T. Gibbs #define ccb_bp ppriv_ptr1 7476babe50SJustin T. Gibbs 7576babe50SJustin T. Gibbs struct pt_softc { 7676babe50SJustin T. Gibbs struct buf_queue_head buf_queue; 7776babe50SJustin T. Gibbs struct devstat device_stats; 7876babe50SJustin T. Gibbs LIST_HEAD(, ccb_hdr) pending_ccbs; 7976babe50SJustin T. Gibbs pt_state state; 8076babe50SJustin T. Gibbs pt_flags flags; 8176babe50SJustin T. Gibbs union ccb saved_ccb; 8276babe50SJustin T. Gibbs }; 8376babe50SJustin T. Gibbs 8476babe50SJustin T. Gibbs static d_open_t ptopen; 8576babe50SJustin T. Gibbs static d_read_t ptread; 8676babe50SJustin T. Gibbs static d_write_t ptwrite; 8776babe50SJustin T. Gibbs static d_close_t ptclose; 8876babe50SJustin T. Gibbs static d_strategy_t ptstrategy; 8976babe50SJustin T. Gibbs static periph_init_t ptinit; 9076babe50SJustin T. Gibbs static void ptasync(void *callback_arg, u_int32_t code, 9176babe50SJustin T. Gibbs struct cam_path *path, void *arg); 9276babe50SJustin T. Gibbs static periph_ctor_t ptctor; 93ee9c90c7SKenneth D. Merry static periph_oninv_t ptoninvalidate; 9476babe50SJustin T. Gibbs static periph_dtor_t ptdtor; 9576babe50SJustin T. Gibbs static periph_start_t ptstart; 9676babe50SJustin T. Gibbs static void ptdone(struct cam_periph *periph, 9776babe50SJustin T. Gibbs union ccb *done_ccb); 9876babe50SJustin T. Gibbs static int pterror(union ccb *ccb, u_int32_t cam_flags, 9976babe50SJustin T. Gibbs u_int32_t sense_flags); 10076babe50SJustin T. Gibbs 10176babe50SJustin T. Gibbs void scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 10276babe50SJustin T. Gibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 10376babe50SJustin T. Gibbs u_int tag_action, int readop, u_int byte2, 10476babe50SJustin T. Gibbs u_int32_t xfer_len, u_int8_t *data_ptr, 10576babe50SJustin T. Gibbs u_int8_t sense_len, u_int32_t timeout); 10676babe50SJustin T. Gibbs 10776babe50SJustin T. Gibbs static struct periph_driver ptdriver = 10876babe50SJustin T. Gibbs { 10976babe50SJustin T. Gibbs ptinit, "pt", 11076babe50SJustin T. Gibbs TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0 11176babe50SJustin T. Gibbs }; 11276babe50SJustin T. Gibbs 11376babe50SJustin T. Gibbs DATA_SET(periphdriver_set, ptdriver); 11476babe50SJustin T. Gibbs 11576babe50SJustin T. Gibbs #define PT_CDEV_MAJOR 61 11676babe50SJustin T. Gibbs 11776babe50SJustin T. Gibbs static struct cdevsw pt_cdevsw = 11876babe50SJustin T. Gibbs { 11976babe50SJustin T. Gibbs /*d_open*/ ptopen, 12076babe50SJustin T. Gibbs /*d_close*/ ptclose, 12176babe50SJustin T. Gibbs /*d_read*/ ptread, 12276babe50SJustin T. Gibbs /*d_write*/ ptwrite, 12376babe50SJustin T. Gibbs /*d_ioctl*/ noioctl, 12476babe50SJustin T. Gibbs /*d_stop*/ nostop, 12576babe50SJustin T. Gibbs /*d_reset*/ noreset, 12676babe50SJustin T. Gibbs /*d_devtotty*/ nodevtotty, 12776babe50SJustin T. Gibbs /*d_poll*/ seltrue, 12876babe50SJustin T. Gibbs /*d_mmap*/ nommap, 12976babe50SJustin T. Gibbs /*d_strategy*/ ptstrategy, 13076babe50SJustin T. Gibbs /*d_name*/ "pt", 13176babe50SJustin T. Gibbs /*d_spare*/ NULL, 13276babe50SJustin T. Gibbs /*d_maj*/ -1, 13376babe50SJustin T. Gibbs /*d_dump*/ nodump, 13476babe50SJustin T. Gibbs /*d_psize*/ nopsize, 13576babe50SJustin T. Gibbs /*d_flags*/ 0, 13676babe50SJustin T. Gibbs /*d_maxio*/ 0, 13776babe50SJustin T. Gibbs /*b_maj*/ -1 13876babe50SJustin T. Gibbs }; 13976babe50SJustin T. Gibbs 14076babe50SJustin T. Gibbs static struct extend_array *ptperiphs; 14176babe50SJustin T. Gibbs 14276babe50SJustin T. Gibbs static int 14376babe50SJustin T. Gibbs ptopen(dev_t dev, int flags, int fmt, struct proc *p) 14476babe50SJustin T. Gibbs { 14576babe50SJustin T. Gibbs struct cam_periph *periph; 14676babe50SJustin T. Gibbs struct pt_softc *softc; 14776babe50SJustin T. Gibbs int unit; 14876babe50SJustin T. Gibbs int error; 149ee9c90c7SKenneth D. Merry int s; 15076babe50SJustin T. Gibbs 15176babe50SJustin T. Gibbs unit = minor(dev); 15276babe50SJustin T. Gibbs periph = cam_extend_get(ptperiphs, unit); 15376babe50SJustin T. Gibbs if (periph == NULL) 15476babe50SJustin T. Gibbs return (ENXIO); 15576babe50SJustin T. Gibbs 15676babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 15776babe50SJustin T. Gibbs 158ee9c90c7SKenneth D. Merry s = splsoftcam(); 159ee9c90c7SKenneth D. Merry if (softc->flags & PT_FLAG_DEVICE_INVALID) { 160ee9c90c7SKenneth D. Merry splx(s); 161ee9c90c7SKenneth D. Merry return(ENXIO); 162ee9c90c7SKenneth D. Merry } 163ee9c90c7SKenneth D. Merry 16476babe50SJustin T. Gibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 16576babe50SJustin T. Gibbs ("ptopen: dev=0x%x (unit %d)\n", dev, unit)); 16676babe50SJustin T. Gibbs 16722b9c86cSKenneth D. Merry if ((error = cam_periph_lock(periph, PRIBIO|PCATCH)) != 0) { 16822b9c86cSKenneth D. Merry splx(s); 16976babe50SJustin T. Gibbs return (error); /* error code from tsleep */ 17022b9c86cSKenneth D. Merry } 17122b9c86cSKenneth D. Merry 17222b9c86cSKenneth D. Merry splx(s); 17376babe50SJustin T. Gibbs 17476babe50SJustin T. Gibbs if ((softc->flags & PT_FLAG_OPEN) == 0) { 17576babe50SJustin T. Gibbs if (cam_periph_acquire(periph) != CAM_REQ_CMP) 17676babe50SJustin T. Gibbs error = ENXIO; 17776babe50SJustin T. Gibbs else 17876babe50SJustin T. Gibbs softc->flags |= PT_FLAG_OPEN; 17976babe50SJustin T. Gibbs } else 18076babe50SJustin T. Gibbs error = EBUSY; 18176babe50SJustin T. Gibbs 18276babe50SJustin T. Gibbs cam_periph_unlock(periph); 18376babe50SJustin T. Gibbs return (error); 18476babe50SJustin T. Gibbs } 18576babe50SJustin T. Gibbs 18676babe50SJustin T. Gibbs static int 18776babe50SJustin T. Gibbs ptclose(dev_t dev, int flag, int fmt, struct proc *p) 18876babe50SJustin T. Gibbs { 18976babe50SJustin T. Gibbs struct cam_periph *periph; 19076babe50SJustin T. Gibbs struct pt_softc *softc; 19176babe50SJustin T. Gibbs int unit; 19276babe50SJustin T. Gibbs int error; 19376babe50SJustin T. Gibbs 19476babe50SJustin T. Gibbs unit = minor(dev); 19576babe50SJustin T. Gibbs periph = cam_extend_get(ptperiphs, unit); 19676babe50SJustin T. Gibbs if (periph == NULL) 19776babe50SJustin T. Gibbs return (ENXIO); 19876babe50SJustin T. Gibbs 19976babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 20076babe50SJustin T. Gibbs 20176babe50SJustin T. Gibbs if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 20276babe50SJustin T. Gibbs return (error); /* error code from tsleep */ 20376babe50SJustin T. Gibbs 20476babe50SJustin T. Gibbs softc->flags &= ~PT_FLAG_OPEN; 20576babe50SJustin T. Gibbs cam_periph_unlock(periph); 20676babe50SJustin T. Gibbs cam_periph_release(periph); 20776babe50SJustin T. Gibbs return (0); 20876babe50SJustin T. Gibbs } 20976babe50SJustin T. Gibbs 21076babe50SJustin T. Gibbs static int 21176babe50SJustin T. Gibbs ptread(dev_t dev, struct uio *uio, int ioflag) 21276babe50SJustin T. Gibbs { 21376babe50SJustin T. Gibbs return(physio(ptstrategy, NULL, dev, 1, minphys, uio)); 21476babe50SJustin T. Gibbs } 21576babe50SJustin T. Gibbs 21676babe50SJustin T. Gibbs static int 21776babe50SJustin T. Gibbs ptwrite(dev_t dev, struct uio *uio, int ioflag) 21876babe50SJustin T. Gibbs { 21976babe50SJustin T. Gibbs return(physio(ptstrategy, NULL, dev, 0, minphys, uio)); 22076babe50SJustin T. Gibbs } 22176babe50SJustin T. Gibbs 22276babe50SJustin T. Gibbs /* 22376babe50SJustin T. Gibbs * Actually translate the requested transfer into one the physical driver 22476babe50SJustin T. Gibbs * can understand. The transfer is described by a buf and will include 22576babe50SJustin T. Gibbs * only one physical transfer. 22676babe50SJustin T. Gibbs */ 22776babe50SJustin T. Gibbs static void 22876babe50SJustin T. Gibbs ptstrategy(struct buf *bp) 22976babe50SJustin T. Gibbs { 23076babe50SJustin T. Gibbs struct cam_periph *periph; 23176babe50SJustin T. Gibbs struct pt_softc *softc; 23276babe50SJustin T. Gibbs u_int unit; 23376babe50SJustin T. Gibbs int s; 23476babe50SJustin T. Gibbs 23576babe50SJustin T. Gibbs unit = minor(bp->b_dev); 23676babe50SJustin T. Gibbs periph = cam_extend_get(ptperiphs, unit); 23776babe50SJustin T. Gibbs if (periph == NULL) { 23876babe50SJustin T. Gibbs bp->b_error = ENXIO; 23976babe50SJustin T. Gibbs goto bad; 24076babe50SJustin T. Gibbs } 24176babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 24276babe50SJustin T. Gibbs 24376babe50SJustin T. Gibbs /* 24476babe50SJustin T. Gibbs * Mask interrupts so that the pack cannot be invalidated until 24576babe50SJustin T. Gibbs * after we are in the queue. Otherwise, we might not properly 24676babe50SJustin T. Gibbs * clean up one of the buffers. 24776babe50SJustin T. Gibbs */ 24876babe50SJustin T. Gibbs s = splbio(); 24976babe50SJustin T. Gibbs 25076babe50SJustin T. Gibbs /* 25176babe50SJustin T. Gibbs * If the device has been made invalid, error out 25276babe50SJustin T. Gibbs */ 25376babe50SJustin T. Gibbs if ((softc->flags & PT_FLAG_DEVICE_INVALID)) { 25476babe50SJustin T. Gibbs splx(s); 25576babe50SJustin T. Gibbs bp->b_error = ENXIO; 25676babe50SJustin T. Gibbs goto bad; 25776babe50SJustin T. Gibbs } 25876babe50SJustin T. Gibbs 25976babe50SJustin T. Gibbs /* 26076babe50SJustin T. Gibbs * Place it in the queue of disk activities for this disk 26176babe50SJustin T. Gibbs */ 26276babe50SJustin T. Gibbs bufq_insert_tail(&softc->buf_queue, bp); 26376babe50SJustin T. Gibbs 26476babe50SJustin T. Gibbs splx(s); 26576babe50SJustin T. Gibbs 26676babe50SJustin T. Gibbs /* 26776babe50SJustin T. Gibbs * Schedule ourselves for performing the work. 26876babe50SJustin T. Gibbs */ 26976babe50SJustin T. Gibbs xpt_schedule(periph, /* XXX priority */1); 27076babe50SJustin T. Gibbs 27176babe50SJustin T. Gibbs return; 27276babe50SJustin T. Gibbs bad: 27376babe50SJustin T. Gibbs bp->b_flags |= B_ERROR; 27476babe50SJustin T. Gibbs 27576babe50SJustin T. Gibbs /* 27676babe50SJustin T. Gibbs * Correctly set the buf to indicate a completed xfer 27776babe50SJustin T. Gibbs */ 27876babe50SJustin T. Gibbs bp->b_resid = bp->b_bcount; 27976babe50SJustin T. Gibbs biodone(bp); 28076babe50SJustin T. Gibbs } 28176babe50SJustin T. Gibbs 28276babe50SJustin T. Gibbs static void 28376babe50SJustin T. Gibbs ptinit(void) 28476babe50SJustin T. Gibbs { 28576babe50SJustin T. Gibbs cam_status status; 28676babe50SJustin T. Gibbs struct cam_path *path; 28776babe50SJustin T. Gibbs 28876babe50SJustin T. Gibbs /* 28976babe50SJustin T. Gibbs * Create our extend array for storing the devices we attach to. 29076babe50SJustin T. Gibbs */ 29176babe50SJustin T. Gibbs ptperiphs = cam_extend_new(); 29276babe50SJustin T. Gibbs if (ptperiphs == NULL) { 29376babe50SJustin T. Gibbs printf("pt: Failed to alloc extend array!\n"); 29476babe50SJustin T. Gibbs return; 29576babe50SJustin T. Gibbs } 29676babe50SJustin T. Gibbs 29776babe50SJustin T. Gibbs /* 29876babe50SJustin T. Gibbs * Install a global async callback. This callback will 29976babe50SJustin T. Gibbs * receive async callbacks like "new device found". 30076babe50SJustin T. Gibbs */ 30176babe50SJustin T. Gibbs status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 30276babe50SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 30376babe50SJustin T. Gibbs 30476babe50SJustin T. Gibbs if (status == CAM_REQ_CMP) { 30576babe50SJustin T. Gibbs struct ccb_setasync csa; 30676babe50SJustin T. Gibbs 30776babe50SJustin T. Gibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 30876babe50SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 30976babe50SJustin T. Gibbs csa.event_enable = AC_FOUND_DEVICE; 31076babe50SJustin T. Gibbs csa.callback = ptasync; 31176babe50SJustin T. Gibbs csa.callback_arg = NULL; 31276babe50SJustin T. Gibbs xpt_action((union ccb *)&csa); 31376babe50SJustin T. Gibbs status = csa.ccb_h.status; 31476babe50SJustin T. Gibbs xpt_free_path(path); 31576babe50SJustin T. Gibbs } 31676babe50SJustin T. Gibbs 31776babe50SJustin T. Gibbs if (status != CAM_REQ_CMP) { 31876babe50SJustin T. Gibbs printf("pt: Failed to attach master async callback " 31976babe50SJustin T. Gibbs "due to status 0x%x!\n", status); 32076babe50SJustin T. Gibbs } else { 32176babe50SJustin T. Gibbs /* If we were successfull, register our devsw */ 32276babe50SJustin T. Gibbs dev_t dev; 32376babe50SJustin T. Gibbs 32476babe50SJustin T. Gibbs dev = makedev(PT_CDEV_MAJOR, 0); 32576babe50SJustin T. Gibbs cdevsw_add(&dev,&pt_cdevsw, NULL); 32676babe50SJustin T. Gibbs } 32776babe50SJustin T. Gibbs } 32876babe50SJustin T. Gibbs 32976babe50SJustin T. Gibbs static cam_status 33076babe50SJustin T. Gibbs ptctor(struct cam_periph *periph, void *arg) 33176babe50SJustin T. Gibbs { 33276babe50SJustin T. Gibbs struct pt_softc *softc; 33376babe50SJustin T. Gibbs struct ccb_setasync csa; 33476babe50SJustin T. Gibbs struct ccb_getdev *cgd; 33576babe50SJustin T. Gibbs 33676babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 33776babe50SJustin T. Gibbs if (periph == NULL) { 33876babe50SJustin T. Gibbs printf("ptregister: periph was NULL!!\n"); 33976babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 34076babe50SJustin T. Gibbs } 34176babe50SJustin T. Gibbs 34276babe50SJustin T. Gibbs if (cgd == NULL) { 34376babe50SJustin T. Gibbs printf("ptregister: no getdev CCB, can't register device\n"); 34476babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 34576babe50SJustin T. Gibbs } 34676babe50SJustin T. Gibbs 34776babe50SJustin T. Gibbs softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT); 34876babe50SJustin T. Gibbs 34976babe50SJustin T. Gibbs if (softc == NULL) { 35076babe50SJustin T. Gibbs printf("daregister: Unable to probe new device. " 35176babe50SJustin T. Gibbs "Unable to allocate softc\n"); 35276babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 35376babe50SJustin T. Gibbs } 35476babe50SJustin T. Gibbs 35576babe50SJustin T. Gibbs bzero(softc, sizeof(*softc)); 35676babe50SJustin T. Gibbs LIST_INIT(&softc->pending_ccbs); 35776babe50SJustin T. Gibbs softc->state = PT_STATE_NORMAL; 35876babe50SJustin T. Gibbs bufq_init(&softc->buf_queue); 35976babe50SJustin T. Gibbs 36076babe50SJustin T. Gibbs periph->softc = softc; 36176babe50SJustin T. Gibbs 36276babe50SJustin T. Gibbs cam_extend_set(ptperiphs, periph->unit_number, periph); 36376babe50SJustin T. Gibbs 36476babe50SJustin T. Gibbs /* 36576babe50SJustin T. Gibbs * The DA driver supports a blocksize, but 36676babe50SJustin T. Gibbs * we don't know the blocksize until we do 36776babe50SJustin T. Gibbs * a read capacity. So, set a flag to 36876babe50SJustin T. Gibbs * indicate that the blocksize is 36976babe50SJustin T. Gibbs * unavailable right now. We'll clear the 37076babe50SJustin T. Gibbs * flag as soon as we've done a read capacity. 37176babe50SJustin T. Gibbs */ 37276babe50SJustin T. Gibbs devstat_add_entry(&softc->device_stats, "pt", 37376babe50SJustin T. Gibbs periph->unit_number, 0, 37476babe50SJustin T. Gibbs DEVSTAT_NO_BLOCKSIZE, 37576babe50SJustin T. Gibbs cgd->pd_type | DEVSTAT_TYPE_IF_SCSI); 37676babe50SJustin T. Gibbs 37776babe50SJustin T. Gibbs /* 37876babe50SJustin T. Gibbs * Add async callbacks for bus reset and 37976babe50SJustin T. Gibbs * bus device reset calls. I don't bother 38076babe50SJustin T. Gibbs * checking if this fails as, in most cases, 38176babe50SJustin T. Gibbs * the system will function just fine without 38276babe50SJustin T. Gibbs * them and the only alternative would be to 38376babe50SJustin T. Gibbs * not attach the device on failure. 38476babe50SJustin T. Gibbs */ 38576babe50SJustin T. Gibbs xpt_setup_ccb(&csa.ccb_h, periph->path, /*priority*/5); 38676babe50SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 38776babe50SJustin T. Gibbs csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE; 38876babe50SJustin T. Gibbs csa.callback = ptasync; 38976babe50SJustin T. Gibbs csa.callback_arg = periph; 39076babe50SJustin T. Gibbs xpt_action((union ccb *)&csa); 39176babe50SJustin T. Gibbs 39276babe50SJustin T. Gibbs /* Tell the user we've attached to the device */ 39376babe50SJustin T. Gibbs xpt_announce_periph(periph, NULL); 39476babe50SJustin T. Gibbs 39576babe50SJustin T. Gibbs return(CAM_REQ_CMP); 39676babe50SJustin T. Gibbs } 39776babe50SJustin T. Gibbs 39876babe50SJustin T. Gibbs static void 399ee9c90c7SKenneth D. Merry ptoninvalidate(struct cam_periph *periph) 400ee9c90c7SKenneth D. Merry { 401ee9c90c7SKenneth D. Merry int s; 402ee9c90c7SKenneth D. Merry struct pt_softc *softc; 403ee9c90c7SKenneth D. Merry struct buf *q_bp; 404ee9c90c7SKenneth D. Merry struct ccb_setasync csa; 405ee9c90c7SKenneth D. Merry 406ee9c90c7SKenneth D. Merry softc = (struct pt_softc *)periph->softc; 407ee9c90c7SKenneth D. Merry 408ee9c90c7SKenneth D. Merry /* 409ee9c90c7SKenneth D. Merry * De-register any async callbacks. 410ee9c90c7SKenneth D. Merry */ 411ee9c90c7SKenneth D. Merry xpt_setup_ccb(&csa.ccb_h, periph->path, 412ee9c90c7SKenneth D. Merry /* priority */ 5); 413ee9c90c7SKenneth D. Merry csa.ccb_h.func_code = XPT_SASYNC_CB; 414ee9c90c7SKenneth D. Merry csa.event_enable = 0; 415ee9c90c7SKenneth D. Merry csa.callback = ptasync; 416ee9c90c7SKenneth D. Merry csa.callback_arg = periph; 417ee9c90c7SKenneth D. Merry xpt_action((union ccb *)&csa); 418ee9c90c7SKenneth D. Merry 419ee9c90c7SKenneth D. Merry softc->flags |= PT_FLAG_DEVICE_INVALID; 420ee9c90c7SKenneth D. Merry 421ee9c90c7SKenneth D. Merry /* 422ee9c90c7SKenneth D. Merry * Although the oninvalidate() routines are always called at 423ee9c90c7SKenneth D. Merry * splsoftcam, we need to be at splbio() here to keep the buffer 424ee9c90c7SKenneth D. Merry * queue from being modified while we traverse it. 425ee9c90c7SKenneth D. Merry */ 426ee9c90c7SKenneth D. Merry s = splbio(); 427ee9c90c7SKenneth D. Merry 428ee9c90c7SKenneth D. Merry /* 429ee9c90c7SKenneth D. Merry * Return all queued I/O with ENXIO. 430ee9c90c7SKenneth D. Merry * XXX Handle any transactions queued to the card 431ee9c90c7SKenneth D. Merry * with XPT_ABORT_CCB. 432ee9c90c7SKenneth D. Merry */ 433ee9c90c7SKenneth D. Merry while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 434ee9c90c7SKenneth D. Merry bufq_remove(&softc->buf_queue, q_bp); 435ee9c90c7SKenneth D. Merry q_bp->b_resid = q_bp->b_bcount; 436ee9c90c7SKenneth D. Merry q_bp->b_error = ENXIO; 437ee9c90c7SKenneth D. Merry q_bp->b_flags |= B_ERROR; 438ee9c90c7SKenneth D. Merry biodone(q_bp); 439ee9c90c7SKenneth D. Merry } 440ee9c90c7SKenneth D. Merry 441ee9c90c7SKenneth D. Merry splx(s); 442ee9c90c7SKenneth D. Merry 443ee9c90c7SKenneth D. Merry xpt_print_path(periph->path); 444ee9c90c7SKenneth D. Merry printf("lost device\n"); 445ee9c90c7SKenneth D. Merry } 446ee9c90c7SKenneth D. Merry 447ee9c90c7SKenneth D. Merry static void 44876babe50SJustin T. Gibbs ptdtor(struct cam_periph *periph) 44976babe50SJustin T. Gibbs { 450ee9c90c7SKenneth D. Merry struct pt_softc *softc; 451ee9c90c7SKenneth D. Merry 452ee9c90c7SKenneth D. Merry softc = (struct pt_softc *)periph->softc; 453ee9c90c7SKenneth D. Merry 454ee9c90c7SKenneth D. Merry devstat_remove_entry(&softc->device_stats); 455ee9c90c7SKenneth D. Merry 45676babe50SJustin T. Gibbs cam_extend_release(ptperiphs, periph->unit_number); 45776babe50SJustin T. Gibbs xpt_print_path(periph->path); 45876babe50SJustin T. Gibbs printf("removing device entry\n"); 459ee9c90c7SKenneth D. Merry free(softc, M_DEVBUF); 46076babe50SJustin T. Gibbs } 46176babe50SJustin T. Gibbs 46276babe50SJustin T. Gibbs static void 46376babe50SJustin T. Gibbs ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 46476babe50SJustin T. Gibbs { 46576babe50SJustin T. Gibbs struct cam_periph *periph; 46676babe50SJustin T. Gibbs 46776babe50SJustin T. Gibbs periph = (struct cam_periph *)callback_arg; 46876babe50SJustin T. Gibbs switch (code) { 46976babe50SJustin T. Gibbs case AC_FOUND_DEVICE: 47076babe50SJustin T. Gibbs { 47176babe50SJustin T. Gibbs struct ccb_getdev *cgd; 47276babe50SJustin T. Gibbs cam_status status; 47376babe50SJustin T. Gibbs 47476babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 47576babe50SJustin T. Gibbs 47676babe50SJustin T. Gibbs if (cgd->pd_type != T_PROCESSOR) 47776babe50SJustin T. Gibbs break; 47876babe50SJustin T. Gibbs 47976babe50SJustin T. Gibbs /* 48076babe50SJustin T. Gibbs * Allocate a peripheral instance for 48176babe50SJustin T. Gibbs * this device and start the probe 48276babe50SJustin T. Gibbs * process. 48376babe50SJustin T. Gibbs */ 484ee9c90c7SKenneth D. Merry status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor, 485ee9c90c7SKenneth D. Merry ptstart, "pt", CAM_PERIPH_BIO, 486ee9c90c7SKenneth D. Merry cgd->ccb_h.path, ptasync, 487ee9c90c7SKenneth D. Merry AC_FOUND_DEVICE, cgd); 48876babe50SJustin T. Gibbs 48976babe50SJustin T. Gibbs if (status != CAM_REQ_CMP 49076babe50SJustin T. Gibbs && status != CAM_REQ_INPROG) 49176babe50SJustin T. Gibbs printf("ptasync: Unable to attach to new device " 49276babe50SJustin T. Gibbs "due to status 0x%x\n", status); 49376babe50SJustin T. Gibbs break; 49476babe50SJustin T. Gibbs } 49576babe50SJustin T. Gibbs case AC_LOST_DEVICE: 49676babe50SJustin T. Gibbs { 49776babe50SJustin T. Gibbs cam_periph_invalidate(periph); 49876babe50SJustin T. Gibbs break; 49976babe50SJustin T. Gibbs } 50076babe50SJustin T. Gibbs case AC_SENT_BDR: 50176babe50SJustin T. Gibbs case AC_BUS_RESET: 50276babe50SJustin T. Gibbs { 50376babe50SJustin T. Gibbs struct pt_softc *softc; 50476babe50SJustin T. Gibbs struct ccb_hdr *ccbh; 50576babe50SJustin T. Gibbs int s; 50676babe50SJustin T. Gibbs 50776babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 50876babe50SJustin T. Gibbs s = splsoftcam(); 50976babe50SJustin T. Gibbs /* 51076babe50SJustin T. Gibbs * Don't fail on the expected unit attention 51176babe50SJustin T. Gibbs * that will occur. 51276babe50SJustin T. Gibbs */ 51376babe50SJustin T. Gibbs softc->flags |= PT_FLAG_RETRY_UA; 51476babe50SJustin T. Gibbs for (ccbh = LIST_FIRST(&softc->pending_ccbs); 51576babe50SJustin T. Gibbs ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le)) 51676babe50SJustin T. Gibbs ccbh->ccb_state |= PT_CCB_RETRY_UA; 51776babe50SJustin T. Gibbs splx(s); 51876babe50SJustin T. Gibbs break; 51976babe50SJustin T. Gibbs } 52076babe50SJustin T. Gibbs case AC_TRANSFER_NEG: 52176babe50SJustin T. Gibbs case AC_SCSI_AEN: 52276babe50SJustin T. Gibbs case AC_UNSOL_RESEL: 52376babe50SJustin T. Gibbs default: 52476babe50SJustin T. Gibbs break; 52576babe50SJustin T. Gibbs } 52676babe50SJustin T. Gibbs } 52776babe50SJustin T. Gibbs 52876babe50SJustin T. Gibbs static void 52976babe50SJustin T. Gibbs ptstart(struct cam_periph *periph, union ccb *start_ccb) 53076babe50SJustin T. Gibbs { 53176babe50SJustin T. Gibbs struct pt_softc *softc; 53276babe50SJustin T. Gibbs struct buf *bp; 53376babe50SJustin T. Gibbs int s; 53476babe50SJustin T. Gibbs 53576babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 53676babe50SJustin T. Gibbs 53776babe50SJustin T. Gibbs /* 53876babe50SJustin T. Gibbs * See if there is a buf with work for us to do.. 53976babe50SJustin T. Gibbs */ 54076babe50SJustin T. Gibbs s = splbio(); 54176babe50SJustin T. Gibbs bp = bufq_first(&softc->buf_queue); 54276babe50SJustin T. Gibbs if (periph->immediate_priority <= periph->pinfo.priority) { 54376babe50SJustin T. Gibbs CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE, 54476babe50SJustin T. Gibbs ("queuing for immediate ccb\n")); 54576babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_state = PT_CCB_WAITING; 54676babe50SJustin T. Gibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 54776babe50SJustin T. Gibbs periph_links.sle); 54876babe50SJustin T. Gibbs periph->immediate_priority = CAM_PRIORITY_NONE; 54976babe50SJustin T. Gibbs splx(s); 55076babe50SJustin T. Gibbs wakeup(&periph->ccb_list); 55176babe50SJustin T. Gibbs } else if (bp == NULL) { 55276babe50SJustin T. Gibbs splx(s); 55376babe50SJustin T. Gibbs xpt_release_ccb(start_ccb); 55476babe50SJustin T. Gibbs } else { 55576babe50SJustin T. Gibbs int oldspl; 55676babe50SJustin T. Gibbs 55776babe50SJustin T. Gibbs bufq_remove(&softc->buf_queue, bp); 55876babe50SJustin T. Gibbs 55976babe50SJustin T. Gibbs devstat_start_transaction(&softc->device_stats); 56076babe50SJustin T. Gibbs 56176babe50SJustin T. Gibbs scsi_send_receive(&start_ccb->csio, 56276babe50SJustin T. Gibbs /*retries*/4, 56376babe50SJustin T. Gibbs ptdone, 56476babe50SJustin T. Gibbs MSG_SIMPLE_Q_TAG, 56576babe50SJustin T. Gibbs bp->b_flags & B_READ, 56676babe50SJustin T. Gibbs /*byte2*/0, 56776babe50SJustin T. Gibbs bp->b_bcount, 56876babe50SJustin T. Gibbs bp->b_data, 56976babe50SJustin T. Gibbs /*sense_len*/SSD_FULL_SIZE, 57076babe50SJustin T. Gibbs /*timeout*/10000); 57176babe50SJustin T. Gibbs 57276babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO; 57376babe50SJustin T. Gibbs 57476babe50SJustin T. Gibbs /* 57576babe50SJustin T. Gibbs * Block out any asyncronous callbacks 57676babe50SJustin T. Gibbs * while we touch the pending ccb list. 57776babe50SJustin T. Gibbs */ 57876babe50SJustin T. Gibbs oldspl = splcam(); 57976babe50SJustin T. Gibbs LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h, 58076babe50SJustin T. Gibbs periph_links.le); 58176babe50SJustin T. Gibbs splx(oldspl); 58276babe50SJustin T. Gibbs 58376babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_bp = bp; 58476babe50SJustin T. Gibbs bp = bufq_first(&softc->buf_queue); 58576babe50SJustin T. Gibbs splx(s); 58676babe50SJustin T. Gibbs 58776babe50SJustin T. Gibbs xpt_action(start_ccb); 58876babe50SJustin T. Gibbs 58976babe50SJustin T. Gibbs if (bp != NULL) { 59076babe50SJustin T. Gibbs /* Have more work to do, so ensure we stay scheduled */ 59176babe50SJustin T. Gibbs xpt_schedule(periph, /* XXX priority */1); 59276babe50SJustin T. Gibbs } 59376babe50SJustin T. Gibbs } 59476babe50SJustin T. Gibbs } 59576babe50SJustin T. Gibbs 59676babe50SJustin T. Gibbs static void 59776babe50SJustin T. Gibbs ptdone(struct cam_periph *periph, union ccb *done_ccb) 59876babe50SJustin T. Gibbs { 59976babe50SJustin T. Gibbs struct pt_softc *softc; 60076babe50SJustin T. Gibbs struct ccb_scsiio *csio; 60176babe50SJustin T. Gibbs 60276babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 60376babe50SJustin T. Gibbs csio = &done_ccb->csio; 60476babe50SJustin T. Gibbs switch (csio->ccb_h.ccb_state) { 60576babe50SJustin T. Gibbs case PT_CCB_BUFFER_IO: 60676babe50SJustin T. Gibbs case PT_CCB_BUFFER_IO_UA: 60776babe50SJustin T. Gibbs { 60876babe50SJustin T. Gibbs struct buf *bp; 60976babe50SJustin T. Gibbs int oldspl; 61076babe50SJustin T. Gibbs 61176babe50SJustin T. Gibbs bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 61276babe50SJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 61376babe50SJustin T. Gibbs int error; 61476babe50SJustin T. Gibbs int s; 61576babe50SJustin T. Gibbs int sf; 61676babe50SJustin T. Gibbs 61776babe50SJustin T. Gibbs if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0) 61876babe50SJustin T. Gibbs sf = SF_RETRY_UA; 61976babe50SJustin T. Gibbs else 62076babe50SJustin T. Gibbs sf = 0; 62176babe50SJustin T. Gibbs 62276babe50SJustin T. Gibbs if ((error = pterror(done_ccb, 0, sf)) == ERESTART) { 62376babe50SJustin T. Gibbs /* 62476babe50SJustin T. Gibbs * A retry was scheuled, so 62576babe50SJustin T. Gibbs * just return. 62676babe50SJustin T. Gibbs */ 62776babe50SJustin T. Gibbs return; 62876babe50SJustin T. Gibbs } 62976babe50SJustin T. Gibbs if (error != 0) { 63076babe50SJustin T. Gibbs struct buf *q_bp; 63176babe50SJustin T. Gibbs 63276babe50SJustin T. Gibbs s = splbio(); 63376babe50SJustin T. Gibbs 63476babe50SJustin T. Gibbs if (error == ENXIO) { 63576babe50SJustin T. Gibbs /* 63676babe50SJustin T. Gibbs * Catastrophic error. Mark our device 63776babe50SJustin T. Gibbs * as invalid. 63876babe50SJustin T. Gibbs */ 63976babe50SJustin T. Gibbs xpt_print_path(periph->path); 64076babe50SJustin T. Gibbs printf("Invalidating device\n"); 64176babe50SJustin T. Gibbs softc->flags |= PT_FLAG_DEVICE_INVALID; 64276babe50SJustin T. Gibbs } 64376babe50SJustin T. Gibbs 64476babe50SJustin T. Gibbs /* 64576babe50SJustin T. Gibbs * return all queued I/O with EIO, so that 64676babe50SJustin T. Gibbs * the client can retry these I/Os in the 64776babe50SJustin T. Gibbs * proper order should it attempt to recover. 64876babe50SJustin T. Gibbs */ 64976babe50SJustin T. Gibbs while ((q_bp = bufq_first(&softc->buf_queue)) 65076babe50SJustin T. Gibbs != NULL) { 65176babe50SJustin T. Gibbs bufq_remove(&softc->buf_queue, q_bp); 65276babe50SJustin T. Gibbs q_bp->b_resid = q_bp->b_bcount; 65376babe50SJustin T. Gibbs q_bp->b_error = EIO; 65476babe50SJustin T. Gibbs q_bp->b_flags |= B_ERROR; 65576babe50SJustin T. Gibbs biodone(q_bp); 65676babe50SJustin T. Gibbs } 65776babe50SJustin T. Gibbs splx(s); 65876babe50SJustin T. Gibbs bp->b_error = error; 65976babe50SJustin T. Gibbs bp->b_resid = bp->b_bcount; 66076babe50SJustin T. Gibbs bp->b_flags |= B_ERROR; 66176babe50SJustin T. Gibbs } else { 66276babe50SJustin T. Gibbs bp->b_resid = csio->resid; 66376babe50SJustin T. Gibbs bp->b_error = 0; 66476babe50SJustin T. Gibbs if (bp->b_resid != 0) { 66576babe50SJustin T. Gibbs /* Short transfer ??? */ 66676babe50SJustin T. Gibbs bp->b_flags |= B_ERROR; 66776babe50SJustin T. Gibbs } 66876babe50SJustin T. Gibbs } 66976babe50SJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 67076babe50SJustin T. Gibbs cam_release_devq(done_ccb->ccb_h.path, 67176babe50SJustin T. Gibbs /*relsim_flags*/0, 67276babe50SJustin T. Gibbs /*reduction*/0, 67376babe50SJustin T. Gibbs /*timeout*/0, 67476babe50SJustin T. Gibbs /*getcount_only*/0); 67576babe50SJustin T. Gibbs } else { 67676babe50SJustin T. Gibbs bp->b_resid = csio->resid; 67776babe50SJustin T. Gibbs if (bp->b_resid != 0) 67876babe50SJustin T. Gibbs bp->b_flags |= B_ERROR; 67976babe50SJustin T. Gibbs } 68076babe50SJustin T. Gibbs 68176babe50SJustin T. Gibbs /* 68276babe50SJustin T. Gibbs * Block out any asyncronous callbacks 68376babe50SJustin T. Gibbs * while we touch the pending ccb list. 68476babe50SJustin T. Gibbs */ 68576babe50SJustin T. Gibbs oldspl = splcam(); 68676babe50SJustin T. Gibbs LIST_REMOVE(&done_ccb->ccb_h, periph_links.le); 68776babe50SJustin T. Gibbs splx(oldspl); 68876babe50SJustin T. Gibbs 68976babe50SJustin T. Gibbs devstat_end_transaction(&softc->device_stats, 69076babe50SJustin T. Gibbs bp->b_bcount - bp->b_resid, 69176babe50SJustin T. Gibbs done_ccb->csio.tag_action & 0xf, 69276babe50SJustin T. Gibbs (bp->b_flags & B_READ) ? DEVSTAT_READ 69376babe50SJustin T. Gibbs : DEVSTAT_WRITE); 69476babe50SJustin T. Gibbs 69576babe50SJustin T. Gibbs biodone(bp); 69676babe50SJustin T. Gibbs break; 69776babe50SJustin T. Gibbs } 69876babe50SJustin T. Gibbs case PT_CCB_WAITING: 69976babe50SJustin T. Gibbs /* Caller will release the CCB */ 70076babe50SJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 70176babe50SJustin T. Gibbs return; 70276babe50SJustin T. Gibbs } 70376babe50SJustin T. Gibbs xpt_release_ccb(done_ccb); 70476babe50SJustin T. Gibbs } 70576babe50SJustin T. Gibbs 70676babe50SJustin T. Gibbs static int 70776babe50SJustin T. Gibbs pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 70876babe50SJustin T. Gibbs { 70976babe50SJustin T. Gibbs struct pt_softc *softc; 71076babe50SJustin T. Gibbs struct cam_periph *periph; 71176babe50SJustin T. Gibbs 71276babe50SJustin T. Gibbs periph = xpt_path_periph(ccb->ccb_h.path); 71376babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc; 71476babe50SJustin T. Gibbs 71576babe50SJustin T. Gibbs return(cam_periph_error(ccb, cam_flags, sense_flags, 71676babe50SJustin T. Gibbs &softc->saved_ccb)); 71776babe50SJustin T. Gibbs } 71876babe50SJustin T. Gibbs 71976babe50SJustin T. Gibbs void 72076babe50SJustin T. Gibbs scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries, 72176babe50SJustin T. Gibbs void (*cbfcnp)(struct cam_periph *, union ccb *), 72276babe50SJustin T. Gibbs u_int tag_action, int readop, u_int byte2, 72376babe50SJustin T. Gibbs u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len, 72476babe50SJustin T. Gibbs u_int32_t timeout) 72576babe50SJustin T. Gibbs { 72676babe50SJustin T. Gibbs struct scsi_send_receive *scsi_cmd; 72776babe50SJustin T. Gibbs 72876babe50SJustin T. Gibbs scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes; 72976babe50SJustin T. Gibbs scsi_cmd->opcode = readop ? RECEIVE : SEND; 73076babe50SJustin T. Gibbs scsi_cmd->byte2 = byte2; 73176babe50SJustin T. Gibbs scsi_ulto3b(xfer_len, scsi_cmd->xfer_len); 73276babe50SJustin T. Gibbs scsi_cmd->control = 0; 73376babe50SJustin T. Gibbs 73476babe50SJustin T. Gibbs cam_fill_csio(csio, 73576babe50SJustin T. Gibbs retries, 73676babe50SJustin T. Gibbs cbfcnp, 73776babe50SJustin T. Gibbs /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, 73876babe50SJustin T. Gibbs tag_action, 73976babe50SJustin T. Gibbs data_ptr, 74076babe50SJustin T. Gibbs xfer_len, 74176babe50SJustin T. Gibbs sense_len, 74276babe50SJustin T. Gibbs sizeof(*scsi_cmd), 74376babe50SJustin T. Gibbs timeout); 74476babe50SJustin T. Gibbs } 745