176babe50SJustin T. Gibbs /* 276babe50SJustin T. Gibbs * Copyright (c) 1997, 1998 Justin T. Gibbs. 376babe50SJustin T. Gibbs * Copyright (c) 1997, 1998 Kenneth D. Merry. 476babe50SJustin T. Gibbs * All rights reserved. 576babe50SJustin T. Gibbs * 676babe50SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 776babe50SJustin T. Gibbs * modification, are permitted provided that the following conditions 876babe50SJustin T. Gibbs * are met: 976babe50SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 1076babe50SJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 1176babe50SJustin T. Gibbs * without modification, immediately at the beginning of the file. 1276babe50SJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products 1376babe50SJustin T. Gibbs * derived from this software without specific prior written permission. 1476babe50SJustin T. Gibbs * 1576babe50SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1676babe50SJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1776babe50SJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1876babe50SJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 1976babe50SJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2076babe50SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2176babe50SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2276babe50SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2376babe50SJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2476babe50SJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2576babe50SJustin T. Gibbs * SUCH DAMAGE. 2676babe50SJustin T. Gibbs * 27ee9c90c7SKenneth D. Merry * $Id: scsi_pass.c,v 1.3 1998/10/15 17:46:26 ken Exp $ 2876babe50SJustin T. Gibbs */ 2976babe50SJustin T. Gibbs 3076babe50SJustin T. Gibbs #include <sys/param.h> 3176babe50SJustin T. Gibbs #include <sys/queue.h> 3276babe50SJustin T. Gibbs #include <sys/systm.h> 3376babe50SJustin T. Gibbs #include <sys/kernel.h> 3476babe50SJustin T. Gibbs #include <sys/types.h> 3576babe50SJustin T. Gibbs #include <sys/buf.h> 3676babe50SJustin T. Gibbs #include <sys/dkbad.h> 3776babe50SJustin T. Gibbs #include <sys/disklabel.h> 3876babe50SJustin T. Gibbs #include <sys/diskslice.h> 3976babe50SJustin T. Gibbs #include <sys/malloc.h> 4076babe50SJustin T. Gibbs #include <sys/fcntl.h> 4176babe50SJustin T. Gibbs #include <sys/stat.h> 4276babe50SJustin T. Gibbs #include <sys/conf.h> 4376babe50SJustin T. Gibbs #include <sys/buf.h> 4476babe50SJustin T. Gibbs #include <sys/proc.h> 4576babe50SJustin T. Gibbs #include <sys/errno.h> 4676babe50SJustin T. Gibbs #include <sys/devicestat.h> 4776babe50SJustin T. Gibbs 4876babe50SJustin T. Gibbs #include <cam/cam.h> 4976babe50SJustin T. Gibbs #include <cam/cam_ccb.h> 5076babe50SJustin T. Gibbs #include <cam/cam_extend.h> 5176babe50SJustin T. Gibbs #include <cam/cam_periph.h> 5276babe50SJustin T. Gibbs #include <cam/cam_xpt_periph.h> 5376babe50SJustin T. Gibbs #include <cam/cam_debug.h> 5476babe50SJustin T. Gibbs 5576babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h> 5676babe50SJustin T. Gibbs #include <cam/scsi/scsi_message.h> 5776babe50SJustin T. Gibbs #include <cam/scsi/scsi_da.h> 5876babe50SJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 5976babe50SJustin T. Gibbs 6076babe50SJustin T. Gibbs typedef enum { 6176babe50SJustin T. Gibbs PASS_FLAG_OPEN = 0x01, 6276babe50SJustin T. Gibbs PASS_FLAG_LOCKED = 0x02, 6376babe50SJustin T. Gibbs PASS_FLAG_INVALID = 0x04 6476babe50SJustin T. Gibbs } pass_flags; 6576babe50SJustin T. Gibbs 6676babe50SJustin T. Gibbs typedef enum { 6776babe50SJustin T. Gibbs PASS_STATE_NORMAL 6876babe50SJustin T. Gibbs } pass_state; 6976babe50SJustin T. Gibbs 7076babe50SJustin T. Gibbs typedef enum { 7176babe50SJustin T. Gibbs PASS_CCB_BUFFER_IO, 7276babe50SJustin T. Gibbs PASS_CCB_WAITING 7376babe50SJustin T. Gibbs } pass_ccb_types; 7476babe50SJustin T. Gibbs 7576babe50SJustin T. Gibbs #define ccb_type ppriv_field0 7676babe50SJustin T. Gibbs #define ccb_bp ppriv_ptr1 7776babe50SJustin T. Gibbs 7876babe50SJustin T. Gibbs struct pass_softc { 7976babe50SJustin T. Gibbs pass_state state; 8076babe50SJustin T. Gibbs pass_flags flags; 8176babe50SJustin T. Gibbs u_int8_t pd_type; 8276babe50SJustin T. Gibbs struct buf_queue_head buf_queue; 8376babe50SJustin T. Gibbs union ccb saved_ccb; 8476babe50SJustin T. Gibbs struct devstat device_stats; 8576babe50SJustin T. Gibbs #ifdef DEVFS 8676babe50SJustin T. Gibbs void *pass_devfs_token; 8776babe50SJustin T. Gibbs void *ctl_devfs_token; 8876babe50SJustin T. Gibbs #endif 8976babe50SJustin T. Gibbs }; 9076babe50SJustin T. Gibbs 9176babe50SJustin T. Gibbs #ifndef MIN 9276babe50SJustin T. Gibbs #define MIN(x,y) ((x<y) ? x : y) 9376babe50SJustin T. Gibbs #endif 9476babe50SJustin T. Gibbs 9576babe50SJustin T. Gibbs #define PASS_CDEV_MAJOR 31 9676babe50SJustin T. Gibbs 9776babe50SJustin T. Gibbs static d_open_t passopen; 9876babe50SJustin T. Gibbs static d_read_t passread; 9976babe50SJustin T. Gibbs static d_write_t passwrite; 10076babe50SJustin T. Gibbs static d_close_t passclose; 10176babe50SJustin T. Gibbs static d_ioctl_t passioctl; 10276babe50SJustin T. Gibbs static d_strategy_t passstrategy; 10376babe50SJustin T. Gibbs 10476babe50SJustin T. Gibbs static periph_init_t passinit; 10576babe50SJustin T. Gibbs static periph_ctor_t passregister; 106ee9c90c7SKenneth D. Merry static periph_oninv_t passoninvalidate; 10776babe50SJustin T. Gibbs static periph_dtor_t passcleanup; 10876babe50SJustin T. Gibbs static periph_start_t passstart; 10976babe50SJustin T. Gibbs static void passasync(void *callback_arg, u_int32_t code, 11076babe50SJustin T. Gibbs struct cam_path *path, void *arg); 11176babe50SJustin T. Gibbs static void passdone(struct cam_periph *periph, 11276babe50SJustin T. Gibbs union ccb *done_ccb); 11376babe50SJustin T. Gibbs static int passerror(union ccb *ccb, u_int32_t cam_flags, 11476babe50SJustin T. Gibbs u_int32_t sense_flags); 11576babe50SJustin T. Gibbs static int passsendccb(struct cam_periph *periph, union ccb *ccb, 11676babe50SJustin T. Gibbs union ccb *inccb); 11776babe50SJustin T. Gibbs 11876babe50SJustin T. Gibbs static struct periph_driver passdriver = 11976babe50SJustin T. Gibbs { 12076babe50SJustin T. Gibbs passinit, "pass", 12176babe50SJustin T. Gibbs TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 12276babe50SJustin T. Gibbs }; 12376babe50SJustin T. Gibbs 12476babe50SJustin T. Gibbs DATA_SET(periphdriver_set, passdriver); 12576babe50SJustin T. Gibbs 12676babe50SJustin T. Gibbs static struct cdevsw pass_cdevsw = 12776babe50SJustin T. Gibbs { 12876babe50SJustin T. Gibbs /*d_open*/ passopen, 12976babe50SJustin T. Gibbs /*d_close*/ passclose, 13076babe50SJustin T. Gibbs /*d_read*/ passread, 13176babe50SJustin T. Gibbs /*d_write*/ passwrite, 13276babe50SJustin T. Gibbs /*d_ioctl*/ passioctl, 13376babe50SJustin T. Gibbs /*d_stop*/ nostop, 13476babe50SJustin T. Gibbs /*d_reset*/ noreset, 13576babe50SJustin T. Gibbs /*d_devtotty*/ nodevtotty, 13676babe50SJustin T. Gibbs /*d_poll*/ seltrue, 13776babe50SJustin T. Gibbs /*d_mmap*/ nommap, 13876babe50SJustin T. Gibbs /*d_strategy*/ passstrategy, 13976babe50SJustin T. Gibbs /*d_name*/ "pass", 14076babe50SJustin T. Gibbs /*d_spare*/ NULL, 14176babe50SJustin T. Gibbs /*d_maj*/ -1, 14276babe50SJustin T. Gibbs /*d_dump*/ nodump, 14376babe50SJustin T. Gibbs /*d_psize*/ nopsize, 14476babe50SJustin T. Gibbs /*d_flags*/ 0, 14576babe50SJustin T. Gibbs /*d_maxio*/ 0, 14676babe50SJustin T. Gibbs /*b_maj*/ -1 14776babe50SJustin T. Gibbs }; 14876babe50SJustin T. Gibbs 14976babe50SJustin T. Gibbs static struct extend_array *passperiphs; 15076babe50SJustin T. Gibbs 15176babe50SJustin T. Gibbs static void 15276babe50SJustin T. Gibbs passinit(void) 15376babe50SJustin T. Gibbs { 15476babe50SJustin T. Gibbs cam_status status; 15576babe50SJustin T. Gibbs struct cam_path *path; 15676babe50SJustin T. Gibbs 15776babe50SJustin T. Gibbs /* 15876babe50SJustin T. Gibbs * Create our extend array for storing the devices we attach to. 15976babe50SJustin T. Gibbs */ 16076babe50SJustin T. Gibbs passperiphs = cam_extend_new(); 16176babe50SJustin T. Gibbs if (passperiphs == NULL) { 16276babe50SJustin T. Gibbs printf("passm: Failed to alloc extend array!\n"); 16376babe50SJustin T. Gibbs return; 16476babe50SJustin T. Gibbs } 16576babe50SJustin T. Gibbs 16676babe50SJustin T. Gibbs /* 16776babe50SJustin T. Gibbs * Install a global async callback. This callback will 16876babe50SJustin T. Gibbs * receive async callbacks like "new device found". 16976babe50SJustin T. Gibbs */ 17076babe50SJustin T. Gibbs status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 17176babe50SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 17276babe50SJustin T. Gibbs 17376babe50SJustin T. Gibbs if (status == CAM_REQ_CMP) { 17476babe50SJustin T. Gibbs struct ccb_setasync csa; 17576babe50SJustin T. Gibbs 17676babe50SJustin T. Gibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 17776babe50SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 17876babe50SJustin T. Gibbs csa.event_enable = AC_FOUND_DEVICE; 17976babe50SJustin T. Gibbs csa.callback = passasync; 18076babe50SJustin T. Gibbs csa.callback_arg = NULL; 18176babe50SJustin T. Gibbs xpt_action((union ccb *)&csa); 18276babe50SJustin T. Gibbs status = csa.ccb_h.status; 18376babe50SJustin T. Gibbs xpt_free_path(path); 18476babe50SJustin T. Gibbs } 18576babe50SJustin T. Gibbs 18676babe50SJustin T. Gibbs if (status != CAM_REQ_CMP) { 18776babe50SJustin T. Gibbs printf("pass: Failed to attach master async callback " 18876babe50SJustin T. Gibbs "due to status 0x%x!\n", status); 18976babe50SJustin T. Gibbs } else { 19076babe50SJustin T. Gibbs dev_t dev; 19176babe50SJustin T. Gibbs 19276babe50SJustin T. Gibbs /* If we were successfull, register our devsw */ 19376babe50SJustin T. Gibbs dev = makedev(PASS_CDEV_MAJOR, 0); 19476babe50SJustin T. Gibbs cdevsw_add(&dev, &pass_cdevsw, NULL); 19576babe50SJustin T. Gibbs } 19676babe50SJustin T. Gibbs 19776babe50SJustin T. Gibbs } 19876babe50SJustin T. Gibbs 19976babe50SJustin T. Gibbs static void 200ee9c90c7SKenneth D. Merry passoninvalidate(struct cam_periph *periph) 201ee9c90c7SKenneth D. Merry { 202ee9c90c7SKenneth D. Merry int s; 203ee9c90c7SKenneth D. Merry struct pass_softc *softc; 204ee9c90c7SKenneth D. Merry struct buf *q_bp; 205ee9c90c7SKenneth D. Merry struct ccb_setasync csa; 206ee9c90c7SKenneth D. Merry 207ee9c90c7SKenneth D. Merry softc = (struct pass_softc *)periph->softc; 208ee9c90c7SKenneth D. Merry 209ee9c90c7SKenneth D. Merry /* 210ee9c90c7SKenneth D. Merry * De-register any async callbacks. 211ee9c90c7SKenneth D. Merry */ 212ee9c90c7SKenneth D. Merry xpt_setup_ccb(&csa.ccb_h, periph->path, 213ee9c90c7SKenneth D. Merry /* priority */ 5); 214ee9c90c7SKenneth D. Merry csa.ccb_h.func_code = XPT_SASYNC_CB; 215ee9c90c7SKenneth D. Merry csa.event_enable = 0; 216ee9c90c7SKenneth D. Merry csa.callback = passasync; 217ee9c90c7SKenneth D. Merry csa.callback_arg = periph; 218ee9c90c7SKenneth D. Merry xpt_action((union ccb *)&csa); 219ee9c90c7SKenneth D. Merry 220ee9c90c7SKenneth D. Merry softc->flags |= PASS_FLAG_INVALID; 221ee9c90c7SKenneth D. Merry 222ee9c90c7SKenneth D. Merry /* 223ee9c90c7SKenneth D. Merry * Although the oninvalidate() routines are always called at 224ee9c90c7SKenneth D. Merry * splsoftcam, we need to be at splbio() here to keep the buffer 225ee9c90c7SKenneth D. Merry * queue from being modified while we traverse it. 226ee9c90c7SKenneth D. Merry */ 227ee9c90c7SKenneth D. Merry s = splbio(); 228ee9c90c7SKenneth D. Merry 229ee9c90c7SKenneth D. Merry /* 230ee9c90c7SKenneth D. Merry * Return all queued I/O with ENXIO. 231ee9c90c7SKenneth D. Merry * XXX Handle any transactions queued to the card 232ee9c90c7SKenneth D. Merry * with XPT_ABORT_CCB. 233ee9c90c7SKenneth D. Merry */ 234ee9c90c7SKenneth D. Merry while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){ 235ee9c90c7SKenneth D. Merry bufq_remove(&softc->buf_queue, q_bp); 236ee9c90c7SKenneth D. Merry q_bp->b_resid = q_bp->b_bcount; 237ee9c90c7SKenneth D. Merry q_bp->b_error = ENXIO; 238ee9c90c7SKenneth D. Merry q_bp->b_flags |= B_ERROR; 239ee9c90c7SKenneth D. Merry biodone(q_bp); 240ee9c90c7SKenneth D. Merry } 241ee9c90c7SKenneth D. Merry splx(s); 242ee9c90c7SKenneth D. Merry 243ee9c90c7SKenneth D. Merry if (bootverbose) { 244ee9c90c7SKenneth D. Merry xpt_print_path(periph->path); 245ee9c90c7SKenneth D. Merry printf("lost device\n"); 246ee9c90c7SKenneth D. Merry } 247ee9c90c7SKenneth D. Merry 248ee9c90c7SKenneth D. Merry } 249ee9c90c7SKenneth D. Merry 250ee9c90c7SKenneth D. Merry static void 25176babe50SJustin T. Gibbs passcleanup(struct cam_periph *periph) 25276babe50SJustin T. Gibbs { 253ee9c90c7SKenneth D. Merry struct pass_softc *softc; 254ee9c90c7SKenneth D. Merry 255ee9c90c7SKenneth D. Merry softc = (struct pass_softc *)periph->softc; 256ee9c90c7SKenneth D. Merry 257ee9c90c7SKenneth D. Merry devstat_remove_entry(&softc->device_stats); 258ee9c90c7SKenneth D. Merry 25976babe50SJustin T. Gibbs cam_extend_release(passperiphs, periph->unit_number); 26076babe50SJustin T. Gibbs 26176babe50SJustin T. Gibbs if (bootverbose) { 26276babe50SJustin T. Gibbs xpt_print_path(periph->path); 26376babe50SJustin T. Gibbs printf("removing device entry\n"); 26476babe50SJustin T. Gibbs } 265ee9c90c7SKenneth D. Merry free(softc, M_DEVBUF); 26676babe50SJustin T. Gibbs } 26776babe50SJustin T. Gibbs 26876babe50SJustin T. Gibbs static void 26976babe50SJustin T. Gibbs passasync(void *callback_arg, u_int32_t code, 27076babe50SJustin T. Gibbs struct cam_path *path, void *arg) 27176babe50SJustin T. Gibbs { 27276babe50SJustin T. Gibbs struct cam_periph *periph; 27376babe50SJustin T. Gibbs 27476babe50SJustin T. Gibbs periph = (struct cam_periph *)callback_arg; 27576babe50SJustin T. Gibbs 27676babe50SJustin T. Gibbs switch (code) { 27776babe50SJustin T. Gibbs case AC_FOUND_DEVICE: 27876babe50SJustin T. Gibbs { 27976babe50SJustin T. Gibbs struct ccb_getdev *cgd; 28076babe50SJustin T. Gibbs cam_status status; 28176babe50SJustin T. Gibbs 28276babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 28376babe50SJustin T. Gibbs 28476babe50SJustin T. Gibbs /* 28576babe50SJustin T. Gibbs * Allocate a peripheral instance for 28676babe50SJustin T. Gibbs * this device and start the probe 28776babe50SJustin T. Gibbs * process. 28876babe50SJustin T. Gibbs */ 289ee9c90c7SKenneth D. Merry status = cam_periph_alloc(passregister, passoninvalidate, 290ee9c90c7SKenneth D. Merry passcleanup, passstart, "pass", 291ee9c90c7SKenneth D. Merry CAM_PERIPH_BIO, cgd->ccb_h.path, 292ee9c90c7SKenneth D. Merry passasync, AC_FOUND_DEVICE, cgd); 29376babe50SJustin T. Gibbs 29476babe50SJustin T. Gibbs if (status != CAM_REQ_CMP 29576babe50SJustin T. Gibbs && status != CAM_REQ_INPROG) 29676babe50SJustin T. Gibbs printf("passasync: Unable to attach new device " 29776babe50SJustin T. Gibbs "due to status 0x%x\n", status); 29876babe50SJustin T. Gibbs 29976babe50SJustin T. Gibbs break; 30076babe50SJustin T. Gibbs } 30176babe50SJustin T. Gibbs case AC_LOST_DEVICE: 30276babe50SJustin T. Gibbs cam_periph_invalidate(periph); 30376babe50SJustin T. Gibbs break; 30476babe50SJustin T. Gibbs case AC_TRANSFER_NEG: 30576babe50SJustin T. Gibbs case AC_SENT_BDR: 30676babe50SJustin T. Gibbs case AC_SCSI_AEN: 30776babe50SJustin T. Gibbs case AC_UNSOL_RESEL: 30876babe50SJustin T. Gibbs case AC_BUS_RESET: 30976babe50SJustin T. Gibbs default: 31076babe50SJustin T. Gibbs break; 31176babe50SJustin T. Gibbs } 31276babe50SJustin T. Gibbs } 31376babe50SJustin T. Gibbs 31476babe50SJustin T. Gibbs static cam_status 31576babe50SJustin T. Gibbs passregister(struct cam_periph *periph, void *arg) 31676babe50SJustin T. Gibbs { 31776babe50SJustin T. Gibbs struct pass_softc *softc; 31876babe50SJustin T. Gibbs struct ccb_setasync csa; 31976babe50SJustin T. Gibbs struct ccb_getdev *cgd; 32076babe50SJustin T. Gibbs 32176babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 32276babe50SJustin T. Gibbs if (periph == NULL) { 32376babe50SJustin T. Gibbs printf("passregister: periph was NULL!!\n"); 32476babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 32576babe50SJustin T. Gibbs } 32676babe50SJustin T. Gibbs 32776babe50SJustin T. Gibbs if (cgd == NULL) { 32876babe50SJustin T. Gibbs printf("passregister: no getdev CCB, can't register device\n"); 32976babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 33076babe50SJustin T. Gibbs } 33176babe50SJustin T. Gibbs 33276babe50SJustin T. Gibbs softc = (struct pass_softc *)malloc(sizeof(*softc), 33376babe50SJustin T. Gibbs M_DEVBUF, M_NOWAIT); 33476babe50SJustin T. Gibbs 33576babe50SJustin T. Gibbs if (softc == NULL) { 33676babe50SJustin T. Gibbs printf("passregister: Unable to probe new device. " 33776babe50SJustin T. Gibbs "Unable to allocate softc\n"); 33876babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 33976babe50SJustin T. Gibbs } 34076babe50SJustin T. Gibbs 34176babe50SJustin T. Gibbs bzero(softc, sizeof(*softc)); 34276babe50SJustin T. Gibbs softc->state = PASS_STATE_NORMAL; 34376babe50SJustin T. Gibbs softc->pd_type = cgd->pd_type; 34476babe50SJustin T. Gibbs bufq_init(&softc->buf_queue); 34576babe50SJustin T. Gibbs 34676babe50SJustin T. Gibbs periph->softc = softc; 34776babe50SJustin T. Gibbs 34876babe50SJustin T. Gibbs cam_extend_set(passperiphs, periph->unit_number, periph); 34976babe50SJustin T. Gibbs /* 35076babe50SJustin T. Gibbs * We pass in 0 for a blocksize, since we don't 35176babe50SJustin T. Gibbs * know what the blocksize of this device is, if 35276babe50SJustin T. Gibbs * it even has a blocksize. 35376babe50SJustin T. Gibbs */ 35476babe50SJustin T. Gibbs devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, 35576babe50SJustin T. Gibbs 0, DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS, 35676babe50SJustin T. Gibbs cgd->pd_type | 35776babe50SJustin T. Gibbs DEVSTAT_TYPE_IF_SCSI | 35876babe50SJustin T. Gibbs DEVSTAT_TYPE_PASS); 35976babe50SJustin T. Gibbs /* 36076babe50SJustin T. Gibbs * Add an async callback so that we get 36176babe50SJustin T. Gibbs * notified if this device goes away. 36276babe50SJustin T. Gibbs */ 36376babe50SJustin T. Gibbs xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 36476babe50SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 36576babe50SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 36676babe50SJustin T. Gibbs csa.callback = passasync; 36776babe50SJustin T. Gibbs csa.callback_arg = periph; 36876babe50SJustin T. Gibbs xpt_action((union ccb *)&csa); 36976babe50SJustin T. Gibbs 37076babe50SJustin T. Gibbs if (bootverbose) 37176babe50SJustin T. Gibbs xpt_announce_periph(periph, NULL); 37276babe50SJustin T. Gibbs 37376babe50SJustin T. Gibbs return(CAM_REQ_CMP); 37476babe50SJustin T. Gibbs } 37576babe50SJustin T. Gibbs 37676babe50SJustin T. Gibbs static int 37776babe50SJustin T. Gibbs passopen(dev_t dev, int flags, int fmt, struct proc *p) 37876babe50SJustin T. Gibbs { 37976babe50SJustin T. Gibbs struct cam_periph *periph; 38076babe50SJustin T. Gibbs struct pass_softc *softc; 38176babe50SJustin T. Gibbs int unit, error; 382ee9c90c7SKenneth D. Merry int s; 38376babe50SJustin T. Gibbs 38476babe50SJustin T. Gibbs error = 0; /* default to no error */ 38576babe50SJustin T. Gibbs 38676babe50SJustin T. Gibbs /* unit = dkunit(dev); */ 38776babe50SJustin T. Gibbs /* XXX KDM fix this */ 38876babe50SJustin T. Gibbs unit = minor(dev) & 0xff; 38976babe50SJustin T. Gibbs 39076babe50SJustin T. Gibbs periph = cam_extend_get(passperiphs, unit); 39176babe50SJustin T. Gibbs 39276babe50SJustin T. Gibbs if (periph == NULL) 39376babe50SJustin T. Gibbs return (ENXIO); 39476babe50SJustin T. Gibbs 39576babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 39676babe50SJustin T. Gibbs 397ee9c90c7SKenneth D. Merry s = splsoftcam(); 398ee9c90c7SKenneth D. Merry if (softc->flags & PASS_FLAG_INVALID) { 399ee9c90c7SKenneth D. Merry splx(s); 40076babe50SJustin T. Gibbs return(ENXIO); 401ee9c90c7SKenneth D. Merry } 402ee9c90c7SKenneth D. Merry splx(s); 40376babe50SJustin T. Gibbs 40476babe50SJustin T. Gibbs /* 40566a0780eSKenneth D. Merry * Only allow read-write access. 40666a0780eSKenneth D. Merry */ 40766a0780eSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) 40866a0780eSKenneth D. Merry return(EPERM); 40966a0780eSKenneth D. Merry 41066a0780eSKenneth D. Merry /* 41176babe50SJustin T. Gibbs * We don't allow nonblocking access. 41276babe50SJustin T. Gibbs */ 41376babe50SJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 41476babe50SJustin T. Gibbs printf("%s%d: can't do nonblocking accesss\n", 41576babe50SJustin T. Gibbs periph->periph_name, 41676babe50SJustin T. Gibbs periph->unit_number); 41776babe50SJustin T. Gibbs return(ENODEV); 41876babe50SJustin T. Gibbs } 41976babe50SJustin T. Gibbs 42076babe50SJustin T. Gibbs if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) 42176babe50SJustin T. Gibbs return (error); 42276babe50SJustin T. Gibbs 42376babe50SJustin T. Gibbs if ((softc->flags & PASS_FLAG_OPEN) == 0) { 42476babe50SJustin T. Gibbs if (cam_periph_acquire(periph) != CAM_REQ_CMP) 42576babe50SJustin T. Gibbs return(ENXIO); 42676babe50SJustin T. Gibbs softc->flags |= PASS_FLAG_OPEN; 42776babe50SJustin T. Gibbs } 42876babe50SJustin T. Gibbs 42976babe50SJustin T. Gibbs cam_periph_unlock(periph); 43076babe50SJustin T. Gibbs 43176babe50SJustin T. Gibbs return (error); 43276babe50SJustin T. Gibbs } 43376babe50SJustin T. Gibbs 43476babe50SJustin T. Gibbs static int 43576babe50SJustin T. Gibbs passclose(dev_t dev, int flag, int fmt, struct proc *p) 43676babe50SJustin T. Gibbs { 43776babe50SJustin T. Gibbs struct cam_periph *periph; 43876babe50SJustin T. Gibbs struct pass_softc *softc; 43976babe50SJustin T. Gibbs int unit, error; 44076babe50SJustin T. Gibbs 44176babe50SJustin T. Gibbs /* unit = dkunit(dev); */ 44276babe50SJustin T. Gibbs /* XXX KDM fix this */ 44376babe50SJustin T. Gibbs unit = minor(dev) & 0xff; 44476babe50SJustin T. Gibbs 44576babe50SJustin T. Gibbs periph = cam_extend_get(passperiphs, unit); 44676babe50SJustin T. Gibbs if (periph == NULL) 44776babe50SJustin T. Gibbs return (ENXIO); 44876babe50SJustin T. Gibbs 44976babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 45076babe50SJustin T. Gibbs 45176babe50SJustin T. Gibbs if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 45276babe50SJustin T. Gibbs return (error); 45376babe50SJustin T. Gibbs 45476babe50SJustin T. Gibbs softc->flags &= ~PASS_FLAG_OPEN; 45576babe50SJustin T. Gibbs 45676babe50SJustin T. Gibbs cam_periph_unlock(periph); 45776babe50SJustin T. Gibbs cam_periph_release(periph); 45876babe50SJustin T. Gibbs 45976babe50SJustin T. Gibbs return (0); 46076babe50SJustin T. Gibbs } 46176babe50SJustin T. Gibbs 46276babe50SJustin T. Gibbs static int 46376babe50SJustin T. Gibbs passread(dev_t dev, struct uio *uio, int ioflag) 46476babe50SJustin T. Gibbs { 46576babe50SJustin T. Gibbs return(physio(passstrategy, NULL, dev, 1, minphys, uio)); 46676babe50SJustin T. Gibbs } 46776babe50SJustin T. Gibbs 46876babe50SJustin T. Gibbs static int 46976babe50SJustin T. Gibbs passwrite(dev_t dev, struct uio *uio, int ioflag) 47076babe50SJustin T. Gibbs { 47176babe50SJustin T. Gibbs return(physio(passstrategy, NULL, dev, 0, minphys, uio)); 47276babe50SJustin T. Gibbs } 47376babe50SJustin T. Gibbs 47476babe50SJustin T. Gibbs /* 47576babe50SJustin T. Gibbs * Actually translate the requested transfer into one the physical driver 47676babe50SJustin T. Gibbs * can understand. The transfer is described by a buf and will include 47776babe50SJustin T. Gibbs * only one physical transfer. 47876babe50SJustin T. Gibbs */ 47976babe50SJustin T. Gibbs static void 48076babe50SJustin T. Gibbs passstrategy(struct buf *bp) 48176babe50SJustin T. Gibbs { 48276babe50SJustin T. Gibbs struct cam_periph *periph; 48376babe50SJustin T. Gibbs struct pass_softc *softc; 48476babe50SJustin T. Gibbs u_int unit; 48576babe50SJustin T. Gibbs int s; 48676babe50SJustin T. Gibbs 48776babe50SJustin T. Gibbs /* 48876babe50SJustin T. Gibbs * The read/write interface for the passthrough driver doesn't 48976babe50SJustin T. Gibbs * really work right now. So, we just pass back EINVAL to tell the 49076babe50SJustin T. Gibbs * user to go away. 49176babe50SJustin T. Gibbs */ 49276babe50SJustin T. Gibbs bp->b_error = EINVAL; 49376babe50SJustin T. Gibbs goto bad; 49476babe50SJustin T. Gibbs 49576babe50SJustin T. Gibbs /* unit = dkunit(bp->b_dev); */ 49676babe50SJustin T. Gibbs /* XXX KDM fix this */ 49776babe50SJustin T. Gibbs unit = minor(bp->b_dev) & 0xff; 49876babe50SJustin T. Gibbs 49976babe50SJustin T. Gibbs periph = cam_extend_get(passperiphs, unit); 50076babe50SJustin T. Gibbs if (periph == NULL) { 50176babe50SJustin T. Gibbs bp->b_error = ENXIO; 50276babe50SJustin T. Gibbs goto bad; 50376babe50SJustin T. Gibbs } 50476babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 50576babe50SJustin T. Gibbs 50676babe50SJustin T. Gibbs /* 50776babe50SJustin T. Gibbs * Odd number of bytes or negative offset 50876babe50SJustin T. Gibbs */ 50976babe50SJustin T. Gibbs /* valid request? */ 51076babe50SJustin T. Gibbs if (bp->b_blkno < 0) { 51176babe50SJustin T. Gibbs bp->b_error = EINVAL; 51276babe50SJustin T. Gibbs goto bad; 51376babe50SJustin T. Gibbs } 51476babe50SJustin T. Gibbs 51576babe50SJustin T. Gibbs /* 51676babe50SJustin T. Gibbs * Mask interrupts so that the pack cannot be invalidated until 51776babe50SJustin T. Gibbs * after we are in the queue. Otherwise, we might not properly 51876babe50SJustin T. Gibbs * clean up one of the buffers. 51976babe50SJustin T. Gibbs */ 52076babe50SJustin T. Gibbs s = splbio(); 52176babe50SJustin T. Gibbs 52276babe50SJustin T. Gibbs bufq_insert_tail(&softc->buf_queue, bp); 52376babe50SJustin T. Gibbs 52476babe50SJustin T. Gibbs splx(s); 52576babe50SJustin T. Gibbs 52676babe50SJustin T. Gibbs /* 52776babe50SJustin T. Gibbs * Schedule ourselves for performing the work. 52876babe50SJustin T. Gibbs */ 52976babe50SJustin T. Gibbs xpt_schedule(periph, /* XXX priority */1); 53076babe50SJustin T. Gibbs 53176babe50SJustin T. Gibbs return; 53276babe50SJustin T. Gibbs bad: 53376babe50SJustin T. Gibbs bp->b_flags |= B_ERROR; 53476babe50SJustin T. Gibbs 53576babe50SJustin T. Gibbs /* 53676babe50SJustin T. Gibbs * Correctly set the buf to indicate a completed xfer 53776babe50SJustin T. Gibbs */ 53876babe50SJustin T. Gibbs bp->b_resid = bp->b_bcount; 53976babe50SJustin T. Gibbs biodone(bp); 54076babe50SJustin T. Gibbs return; 54176babe50SJustin T. Gibbs } 54276babe50SJustin T. Gibbs 54376babe50SJustin T. Gibbs static void 54476babe50SJustin T. Gibbs passstart(struct cam_periph *periph, union ccb *start_ccb) 54576babe50SJustin T. Gibbs { 54676babe50SJustin T. Gibbs struct pass_softc *softc; 54776babe50SJustin T. Gibbs int s; 54876babe50SJustin T. Gibbs 54976babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 55076babe50SJustin T. Gibbs 55176babe50SJustin T. Gibbs switch (softc->state) { 55276babe50SJustin T. Gibbs case PASS_STATE_NORMAL: 55376babe50SJustin T. Gibbs { 55476babe50SJustin T. Gibbs struct buf *bp; 55576babe50SJustin T. Gibbs 55676babe50SJustin T. Gibbs s = splbio(); 55776babe50SJustin T. Gibbs bp = bufq_first(&softc->buf_queue); 55876babe50SJustin T. Gibbs if (periph->immediate_priority <= periph->pinfo.priority) { 55976babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; 56076babe50SJustin T. Gibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 56176babe50SJustin T. Gibbs periph_links.sle); 56276babe50SJustin T. Gibbs periph->immediate_priority = CAM_PRIORITY_NONE; 56376babe50SJustin T. Gibbs splx(s); 56476babe50SJustin T. Gibbs wakeup(&periph->ccb_list); 56576babe50SJustin T. Gibbs } else if (bp == NULL) { 56676babe50SJustin T. Gibbs splx(s); 56776babe50SJustin T. Gibbs xpt_release_ccb(start_ccb); 56876babe50SJustin T. Gibbs } else { 56976babe50SJustin T. Gibbs 57076babe50SJustin T. Gibbs bufq_remove(&softc->buf_queue, bp); 57176babe50SJustin T. Gibbs 57276babe50SJustin T. Gibbs devstat_start_transaction(&softc->device_stats); 57376babe50SJustin T. Gibbs 57476babe50SJustin T. Gibbs /* 57576babe50SJustin T. Gibbs * XXX JGibbs - 57676babe50SJustin T. Gibbs * Interpret the contents of the bp as a CCB 57776babe50SJustin T. Gibbs * and pass it to a routine shared by our ioctl 57876babe50SJustin T. Gibbs * code and passtart. 57976babe50SJustin T. Gibbs * For now, just biodone it with EIO so we don't 58076babe50SJustin T. Gibbs * hang. 58176babe50SJustin T. Gibbs */ 58276babe50SJustin T. Gibbs bp->b_error = EIO; 58376babe50SJustin T. Gibbs bp->b_flags |= B_ERROR; 58476babe50SJustin T. Gibbs bp->b_resid = bp->b_bcount; 58576babe50SJustin T. Gibbs biodone(bp); 58676babe50SJustin T. Gibbs bp = bufq_first(&softc->buf_queue); 58776babe50SJustin T. Gibbs splx(s); 58876babe50SJustin T. Gibbs 58976babe50SJustin T. Gibbs xpt_action(start_ccb); 59076babe50SJustin T. Gibbs 59176babe50SJustin T. Gibbs } 59276babe50SJustin T. Gibbs if (bp != NULL) { 59376babe50SJustin T. Gibbs /* Have more work to do, so ensure we stay scheduled */ 59476babe50SJustin T. Gibbs xpt_schedule(periph, /* XXX priority */1); 59576babe50SJustin T. Gibbs } 59676babe50SJustin T. Gibbs break; 59776babe50SJustin T. Gibbs } 59876babe50SJustin T. Gibbs } 59976babe50SJustin T. Gibbs } 60076babe50SJustin T. Gibbs static void 60176babe50SJustin T. Gibbs passdone(struct cam_periph *periph, union ccb *done_ccb) 60276babe50SJustin T. Gibbs { 60376babe50SJustin T. Gibbs struct pass_softc *softc; 60476babe50SJustin T. Gibbs struct ccb_scsiio *csio; 60576babe50SJustin T. Gibbs 60676babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 60776babe50SJustin T. Gibbs csio = &done_ccb->csio; 60876babe50SJustin T. Gibbs switch (csio->ccb_h.ccb_type) { 60976babe50SJustin T. Gibbs case PASS_CCB_BUFFER_IO: 61076babe50SJustin T. Gibbs { 61176babe50SJustin T. Gibbs struct buf *bp; 61276babe50SJustin T. Gibbs cam_status status; 61376babe50SJustin T. Gibbs u_int8_t scsi_status; 61476babe50SJustin T. Gibbs devstat_trans_flags ds_flags; 61576babe50SJustin T. Gibbs 61676babe50SJustin T. Gibbs status = done_ccb->ccb_h.status; 61776babe50SJustin T. Gibbs scsi_status = done_ccb->csio.scsi_status; 61876babe50SJustin T. Gibbs bp = (struct buf *)done_ccb->ccb_h.ccb_bp; 61976babe50SJustin T. Gibbs /* XXX handle errors */ 62076babe50SJustin T. Gibbs if (!(((status & CAM_STATUS_MASK) == CAM_REQ_CMP) 62176babe50SJustin T. Gibbs && (scsi_status == SCSI_STATUS_OK))) { 62276babe50SJustin T. Gibbs int error; 62376babe50SJustin T. Gibbs 62476babe50SJustin T. Gibbs if ((error = passerror(done_ccb, 0, 0)) == ERESTART) { 62576babe50SJustin T. Gibbs /* 62676babe50SJustin T. Gibbs * A retry was scheuled, so 62776babe50SJustin T. Gibbs * just return. 62876babe50SJustin T. Gibbs */ 62976babe50SJustin T. Gibbs return; 63076babe50SJustin T. Gibbs } 63176babe50SJustin T. Gibbs 63276babe50SJustin T. Gibbs /* 63376babe50SJustin T. Gibbs * XXX unfreeze the queue after we complete 63476babe50SJustin T. Gibbs * the abort process 63576babe50SJustin T. Gibbs */ 63676babe50SJustin T. Gibbs bp->b_error = error; 63776babe50SJustin T. Gibbs bp->b_flags |= B_ERROR; 63876babe50SJustin T. Gibbs } 63976babe50SJustin T. Gibbs 64076babe50SJustin T. Gibbs if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) 64176babe50SJustin T. Gibbs ds_flags = DEVSTAT_READ; 64276babe50SJustin T. Gibbs else if ((done_ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) 64376babe50SJustin T. Gibbs ds_flags = DEVSTAT_WRITE; 64476babe50SJustin T. Gibbs else 64576babe50SJustin T. Gibbs ds_flags = DEVSTAT_NO_DATA; 64676babe50SJustin T. Gibbs 64776babe50SJustin T. Gibbs devstat_end_transaction(&softc->device_stats, bp->b_bcount, 64876babe50SJustin T. Gibbs done_ccb->csio.tag_action & 0xf, 64976babe50SJustin T. Gibbs ds_flags); 65076babe50SJustin T. Gibbs 65176babe50SJustin T. Gibbs biodone(bp); 65276babe50SJustin T. Gibbs break; 65376babe50SJustin T. Gibbs } 65476babe50SJustin T. Gibbs case PASS_CCB_WAITING: 65576babe50SJustin T. Gibbs { 65676babe50SJustin T. Gibbs /* Caller will release the CCB */ 65776babe50SJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 65876babe50SJustin T. Gibbs return; 65976babe50SJustin T. Gibbs } 66076babe50SJustin T. Gibbs } 66176babe50SJustin T. Gibbs xpt_release_ccb(done_ccb); 66276babe50SJustin T. Gibbs } 66376babe50SJustin T. Gibbs 66476babe50SJustin T. Gibbs static int 66576babe50SJustin T. Gibbs passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 66676babe50SJustin T. Gibbs { 66776babe50SJustin T. Gibbs struct cam_periph *periph; 66876babe50SJustin T. Gibbs struct pass_softc *softc; 66976babe50SJustin T. Gibbs u_int8_t unit; 67076babe50SJustin T. Gibbs int error; 67176babe50SJustin T. Gibbs 67276babe50SJustin T. Gibbs 67376babe50SJustin T. Gibbs /* unit = dkunit(dev); */ 67476babe50SJustin T. Gibbs /* XXX KDM fix this */ 67576babe50SJustin T. Gibbs unit = minor(dev) & 0xff; 67676babe50SJustin T. Gibbs 67776babe50SJustin T. Gibbs periph = cam_extend_get(passperiphs, unit); 67876babe50SJustin T. Gibbs 67976babe50SJustin T. Gibbs if (periph == NULL) 68076babe50SJustin T. Gibbs return(ENXIO); 68176babe50SJustin T. Gibbs 68276babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 68376babe50SJustin T. Gibbs 68476babe50SJustin T. Gibbs error = 0; 68576babe50SJustin T. Gibbs 68676babe50SJustin T. Gibbs switch (cmd) { 68776babe50SJustin T. Gibbs 68876babe50SJustin T. Gibbs case CAMIOCOMMAND: 68976babe50SJustin T. Gibbs { 69076babe50SJustin T. Gibbs union ccb *inccb; 69176babe50SJustin T. Gibbs union ccb *ccb; 69276babe50SJustin T. Gibbs 69376babe50SJustin T. Gibbs inccb = (union ccb *)addr; 69476babe50SJustin T. Gibbs ccb = cam_periph_getccb(periph, inccb->ccb_h.pinfo.priority); 69576babe50SJustin T. Gibbs 69676babe50SJustin T. Gibbs error = passsendccb(periph, ccb, inccb); 69776babe50SJustin T. Gibbs 69876babe50SJustin T. Gibbs xpt_release_ccb(ccb); 69976babe50SJustin T. Gibbs 70076babe50SJustin T. Gibbs break; 70176babe50SJustin T. Gibbs } 70276babe50SJustin T. Gibbs default: 70376babe50SJustin T. Gibbs error = cam_periph_ioctl(periph, cmd, addr, passerror); 70476babe50SJustin T. Gibbs break; 70576babe50SJustin T. Gibbs } 70676babe50SJustin T. Gibbs 70776babe50SJustin T. Gibbs return(error); 70876babe50SJustin T. Gibbs } 70976babe50SJustin T. Gibbs 71076babe50SJustin T. Gibbs /* 71176babe50SJustin T. Gibbs * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 71276babe50SJustin T. Gibbs * should be the CCB that is copied in from the user. 71376babe50SJustin T. Gibbs */ 71476babe50SJustin T. Gibbs static int 71576babe50SJustin T. Gibbs passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 71676babe50SJustin T. Gibbs { 71776babe50SJustin T. Gibbs struct pass_softc *softc; 71876babe50SJustin T. Gibbs struct cam_periph_map_info mapinfo; 71976babe50SJustin T. Gibbs int error, need_unmap; 72076babe50SJustin T. Gibbs 72176babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 72276babe50SJustin T. Gibbs 72376babe50SJustin T. Gibbs need_unmap = 0; 72476babe50SJustin T. Gibbs 72576babe50SJustin T. Gibbs /* 72676babe50SJustin T. Gibbs * There are some fields in the CCB header that need to be 72776babe50SJustin T. Gibbs * preserved, the rest we get from the user. 72876babe50SJustin T. Gibbs */ 72976babe50SJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 73076babe50SJustin T. Gibbs 73176babe50SJustin T. Gibbs /* 73276babe50SJustin T. Gibbs * There's no way for the user to have a completion 73376babe50SJustin T. Gibbs * function, so we put our own completion function in here. 73476babe50SJustin T. Gibbs */ 73576babe50SJustin T. Gibbs ccb->ccb_h.cbfcnp = passdone; 73676babe50SJustin T. Gibbs 73776babe50SJustin T. Gibbs /* 73876babe50SJustin T. Gibbs * We only attempt to map the user memory into kernel space 73976babe50SJustin T. Gibbs * if they haven't passed in a physical memory pointer, 74076babe50SJustin T. Gibbs * and if there is actually an I/O operation to perform. 74176babe50SJustin T. Gibbs * Right now cam_periph_mapmem() only supports SCSI and device 74276babe50SJustin T. Gibbs * match CCBs. For the SCSI CCBs, we only pass the CCB in if 74376babe50SJustin T. Gibbs * there's actually data to map. cam_periph_mapmem() will do the 74476babe50SJustin T. Gibbs * right thing, even if there isn't data to map, but since CCBs 74576babe50SJustin T. Gibbs * without data are a reasonably common occurance (e.g. test unit 74676babe50SJustin T. Gibbs * ready), it will save a few cycles if we check for it here. 74776babe50SJustin T. Gibbs */ 74876babe50SJustin T. Gibbs if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) 74976babe50SJustin T. Gibbs && (((ccb->ccb_h.func_code == XPT_SCSI_IO) 75076babe50SJustin T. Gibbs && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 75176babe50SJustin T. Gibbs || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) { 75276babe50SJustin T. Gibbs 75376babe50SJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 75476babe50SJustin T. Gibbs 75576babe50SJustin T. Gibbs error = cam_periph_mapmem(ccb, &mapinfo); 75676babe50SJustin T. Gibbs 75776babe50SJustin T. Gibbs /* 75876babe50SJustin T. Gibbs * cam_periph_mapmem returned an error, we can't continue. 75976babe50SJustin T. Gibbs * Return the error to the user. 76076babe50SJustin T. Gibbs */ 76176babe50SJustin T. Gibbs if (error) 76276babe50SJustin T. Gibbs return(error); 76376babe50SJustin T. Gibbs 76476babe50SJustin T. Gibbs /* 76576babe50SJustin T. Gibbs * We successfully mapped the memory in, so we need to 76676babe50SJustin T. Gibbs * unmap it when the transaction is done. 76776babe50SJustin T. Gibbs */ 76876babe50SJustin T. Gibbs need_unmap = 1; 76976babe50SJustin T. Gibbs } 77076babe50SJustin T. Gibbs 77176babe50SJustin T. Gibbs /* 77276babe50SJustin T. Gibbs * If the user wants us to perform any error recovery, then honor 77376babe50SJustin T. Gibbs * that request. Otherwise, it's up to the user to perform any 77476babe50SJustin T. Gibbs * error recovery. 77576babe50SJustin T. Gibbs */ 77676babe50SJustin T. Gibbs error = cam_periph_runccb(ccb, 77776babe50SJustin T. Gibbs (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 77876babe50SJustin T. Gibbs passerror : NULL, 77976babe50SJustin T. Gibbs /* cam_flags */ 0, 78076babe50SJustin T. Gibbs /* sense_flags */SF_RETRY_UA, 78176babe50SJustin T. Gibbs &softc->device_stats); 78276babe50SJustin T. Gibbs 78376babe50SJustin T. Gibbs if (need_unmap != 0) 78476babe50SJustin T. Gibbs cam_periph_unmapmem(ccb, &mapinfo); 78576babe50SJustin T. Gibbs 78676babe50SJustin T. Gibbs ccb->ccb_h.cbfcnp = NULL; 78776babe50SJustin T. Gibbs ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 78876babe50SJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 78976babe50SJustin T. Gibbs 79076babe50SJustin T. Gibbs return(error); 79176babe50SJustin T. Gibbs } 79276babe50SJustin T. Gibbs 79376babe50SJustin T. Gibbs static int 79476babe50SJustin T. Gibbs passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 79576babe50SJustin T. Gibbs { 79676babe50SJustin T. Gibbs struct cam_periph *periph; 79776babe50SJustin T. Gibbs struct pass_softc *softc; 79876babe50SJustin T. Gibbs 79976babe50SJustin T. Gibbs periph = xpt_path_periph(ccb->ccb_h.path); 80076babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 80176babe50SJustin T. Gibbs 80276babe50SJustin T. Gibbs return(cam_periph_error(ccb, cam_flags, sense_flags, 80376babe50SJustin T. Gibbs &softc->saved_ccb)); 80476babe50SJustin T. Gibbs } 805