176babe50SJustin T. Gibbs /* 23393f8daSKenneth D. Merry * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. 32a888f93SKenneth D. Merry * Copyright (c) 1997, 1998, 1999 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 * 27c3aac50fSPeter Wemm * $FreeBSD$ 2876babe50SJustin T. Gibbs */ 2976babe50SJustin T. Gibbs 3076babe50SJustin T. Gibbs #include <sys/param.h> 3176babe50SJustin T. Gibbs #include <sys/systm.h> 3276babe50SJustin T. Gibbs #include <sys/kernel.h> 3376babe50SJustin T. Gibbs #include <sys/types.h> 349626b608SPoul-Henning Kamp #include <sys/bio.h> 3576babe50SJustin T. Gibbs #include <sys/malloc.h> 3676babe50SJustin T. Gibbs #include <sys/fcntl.h> 3776babe50SJustin T. Gibbs #include <sys/conf.h> 3876babe50SJustin T. Gibbs #include <sys/errno.h> 3976babe50SJustin T. Gibbs #include <sys/devicestat.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> 453393f8daSKenneth D. Merry #include <cam/cam_queue.h> 4676babe50SJustin T. Gibbs #include <cam/cam_xpt_periph.h> 4776babe50SJustin T. Gibbs #include <cam/cam_debug.h> 4876babe50SJustin T. Gibbs 4976babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h> 5076babe50SJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 5176babe50SJustin T. Gibbs 5276babe50SJustin T. Gibbs typedef enum { 5376babe50SJustin T. Gibbs PASS_FLAG_OPEN = 0x01, 5476babe50SJustin T. Gibbs PASS_FLAG_LOCKED = 0x02, 5576babe50SJustin T. Gibbs PASS_FLAG_INVALID = 0x04 5676babe50SJustin T. Gibbs } pass_flags; 5776babe50SJustin T. Gibbs 5876babe50SJustin T. Gibbs typedef enum { 5976babe50SJustin T. Gibbs PASS_STATE_NORMAL 6076babe50SJustin T. Gibbs } pass_state; 6176babe50SJustin T. Gibbs 6276babe50SJustin T. Gibbs typedef enum { 6376babe50SJustin T. Gibbs PASS_CCB_BUFFER_IO, 6476babe50SJustin T. Gibbs PASS_CCB_WAITING 6576babe50SJustin T. Gibbs } pass_ccb_types; 6676babe50SJustin T. Gibbs 6776babe50SJustin T. Gibbs #define ccb_type ppriv_field0 6876babe50SJustin T. Gibbs #define ccb_bp ppriv_ptr1 6976babe50SJustin T. Gibbs 7076babe50SJustin T. Gibbs struct pass_softc { 7176babe50SJustin T. Gibbs pass_state state; 7276babe50SJustin T. Gibbs pass_flags flags; 7376babe50SJustin T. Gibbs u_int8_t pd_type; 7476babe50SJustin T. Gibbs union ccb saved_ccb; 7576babe50SJustin T. Gibbs struct devstat device_stats; 7673d26919SKenneth D. Merry dev_t dev; 7776babe50SJustin T. Gibbs }; 7876babe50SJustin T. Gibbs 7976babe50SJustin T. Gibbs #ifndef MIN 8076babe50SJustin T. Gibbs #define MIN(x,y) ((x<y) ? x : y) 8176babe50SJustin T. Gibbs #endif 8276babe50SJustin T. Gibbs 8376babe50SJustin T. Gibbs #define PASS_CDEV_MAJOR 31 8476babe50SJustin T. Gibbs 8576babe50SJustin T. Gibbs static d_open_t passopen; 8676babe50SJustin T. Gibbs static d_close_t passclose; 8776babe50SJustin T. Gibbs static d_ioctl_t passioctl; 8876babe50SJustin T. Gibbs 8976babe50SJustin T. Gibbs static periph_init_t passinit; 9076babe50SJustin T. Gibbs static periph_ctor_t passregister; 91ee9c90c7SKenneth D. Merry static periph_oninv_t passoninvalidate; 9276babe50SJustin T. Gibbs static periph_dtor_t passcleanup; 9376babe50SJustin T. Gibbs static periph_start_t passstart; 9476babe50SJustin T. Gibbs static void passasync(void *callback_arg, u_int32_t code, 9576babe50SJustin T. Gibbs struct cam_path *path, void *arg); 9676babe50SJustin T. Gibbs static void passdone(struct cam_periph *periph, 9776babe50SJustin T. Gibbs union ccb *done_ccb); 9876babe50SJustin T. Gibbs static int passerror(union ccb *ccb, u_int32_t cam_flags, 9976babe50SJustin T. Gibbs u_int32_t sense_flags); 10076babe50SJustin T. Gibbs static int passsendccb(struct cam_periph *periph, union ccb *ccb, 10176babe50SJustin T. Gibbs union ccb *inccb); 10276babe50SJustin T. Gibbs 10376babe50SJustin T. Gibbs static struct periph_driver passdriver = 10476babe50SJustin T. Gibbs { 10576babe50SJustin T. Gibbs passinit, "pass", 10676babe50SJustin T. Gibbs TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 10776babe50SJustin T. Gibbs }; 10876babe50SJustin T. Gibbs 1090b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(pass, passdriver); 11076babe50SJustin T. Gibbs 1114e2f199eSPoul-Henning Kamp static struct cdevsw pass_cdevsw = { 1124e2f199eSPoul-Henning Kamp /* open */ passopen, 1134e2f199eSPoul-Henning Kamp /* close */ passclose, 1143393f8daSKenneth D. Merry /* read */ noread, 1153393f8daSKenneth D. Merry /* write */ nowrite, 1164e2f199eSPoul-Henning Kamp /* ioctl */ passioctl, 1174e2f199eSPoul-Henning Kamp /* poll */ nopoll, 1184e2f199eSPoul-Henning Kamp /* mmap */ nommap, 1193393f8daSKenneth D. Merry /* strategy */ nostrategy, 1204e2f199eSPoul-Henning Kamp /* name */ "pass", 1214e2f199eSPoul-Henning Kamp /* maj */ PASS_CDEV_MAJOR, 1224e2f199eSPoul-Henning Kamp /* dump */ nodump, 1234e2f199eSPoul-Henning Kamp /* psize */ nopsize, 1244e2f199eSPoul-Henning Kamp /* flags */ 0, 12576babe50SJustin T. Gibbs }; 12676babe50SJustin T. Gibbs 12776babe50SJustin T. Gibbs static struct extend_array *passperiphs; 12876babe50SJustin T. Gibbs 12976babe50SJustin T. Gibbs static void 13076babe50SJustin T. Gibbs passinit(void) 13176babe50SJustin T. Gibbs { 13276babe50SJustin T. Gibbs cam_status status; 13376babe50SJustin T. Gibbs struct cam_path *path; 13476babe50SJustin T. Gibbs 13576babe50SJustin T. Gibbs /* 13676babe50SJustin T. Gibbs * Create our extend array for storing the devices we attach to. 13776babe50SJustin T. Gibbs */ 13876babe50SJustin T. Gibbs passperiphs = cam_extend_new(); 13976babe50SJustin T. Gibbs if (passperiphs == NULL) { 14076babe50SJustin T. Gibbs printf("passm: Failed to alloc extend array!\n"); 14176babe50SJustin T. Gibbs return; 14276babe50SJustin T. Gibbs } 14376babe50SJustin T. Gibbs 14476babe50SJustin T. Gibbs /* 14576babe50SJustin T. Gibbs * Install a global async callback. This callback will 14676babe50SJustin T. Gibbs * receive async callbacks like "new device found". 14776babe50SJustin T. Gibbs */ 14876babe50SJustin T. Gibbs status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 14976babe50SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 15076babe50SJustin T. Gibbs 15176babe50SJustin T. Gibbs if (status == CAM_REQ_CMP) { 15276babe50SJustin T. Gibbs struct ccb_setasync csa; 15376babe50SJustin T. Gibbs 15476babe50SJustin T. Gibbs xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 15576babe50SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 15676babe50SJustin T. Gibbs csa.event_enable = AC_FOUND_DEVICE; 15776babe50SJustin T. Gibbs csa.callback = passasync; 15876babe50SJustin T. Gibbs csa.callback_arg = NULL; 15976babe50SJustin T. Gibbs xpt_action((union ccb *)&csa); 16076babe50SJustin T. Gibbs status = csa.ccb_h.status; 16176babe50SJustin T. Gibbs xpt_free_path(path); 16276babe50SJustin T. Gibbs } 16376babe50SJustin T. Gibbs 16476babe50SJustin T. Gibbs if (status != CAM_REQ_CMP) { 16576babe50SJustin T. Gibbs printf("pass: Failed to attach master async callback " 16676babe50SJustin T. Gibbs "due to status 0x%x!\n", status); 16776babe50SJustin T. Gibbs } 16876babe50SJustin T. Gibbs 16976babe50SJustin T. Gibbs } 17076babe50SJustin T. Gibbs 17176babe50SJustin T. Gibbs static void 172ee9c90c7SKenneth D. Merry passoninvalidate(struct cam_periph *periph) 173ee9c90c7SKenneth D. Merry { 174ee9c90c7SKenneth D. Merry struct pass_softc *softc; 175ee9c90c7SKenneth D. Merry struct ccb_setasync csa; 176ee9c90c7SKenneth D. Merry 177ee9c90c7SKenneth D. Merry softc = (struct pass_softc *)periph->softc; 178ee9c90c7SKenneth D. Merry 179ee9c90c7SKenneth D. Merry /* 180ee9c90c7SKenneth D. Merry * De-register any async callbacks. 181ee9c90c7SKenneth D. Merry */ 182ee9c90c7SKenneth D. Merry xpt_setup_ccb(&csa.ccb_h, periph->path, 183ee9c90c7SKenneth D. Merry /* priority */ 5); 184ee9c90c7SKenneth D. Merry csa.ccb_h.func_code = XPT_SASYNC_CB; 185ee9c90c7SKenneth D. Merry csa.event_enable = 0; 186ee9c90c7SKenneth D. Merry csa.callback = passasync; 187ee9c90c7SKenneth D. Merry csa.callback_arg = periph; 188ee9c90c7SKenneth D. Merry xpt_action((union ccb *)&csa); 189ee9c90c7SKenneth D. Merry 190ee9c90c7SKenneth D. Merry softc->flags |= PASS_FLAG_INVALID; 191ee9c90c7SKenneth D. Merry 192ee9c90c7SKenneth D. Merry /* 1933393f8daSKenneth D. Merry * XXX Return all queued I/O with ENXIO. 194ee9c90c7SKenneth D. Merry * XXX Handle any transactions queued to the card 195ee9c90c7SKenneth D. Merry * with XPT_ABORT_CCB. 196ee9c90c7SKenneth D. Merry */ 197ee9c90c7SKenneth D. Merry 198ee9c90c7SKenneth D. Merry if (bootverbose) { 199ee9c90c7SKenneth D. Merry xpt_print_path(periph->path); 200ee9c90c7SKenneth D. Merry printf("lost device\n"); 201ee9c90c7SKenneth D. Merry } 202ee9c90c7SKenneth D. Merry 203ee9c90c7SKenneth D. Merry } 204ee9c90c7SKenneth D. Merry 205ee9c90c7SKenneth D. Merry static void 20676babe50SJustin T. Gibbs passcleanup(struct cam_periph *periph) 20776babe50SJustin T. Gibbs { 208ee9c90c7SKenneth D. Merry struct pass_softc *softc; 209ee9c90c7SKenneth D. Merry 210ee9c90c7SKenneth D. Merry softc = (struct pass_softc *)periph->softc; 211ee9c90c7SKenneth D. Merry 212ee9c90c7SKenneth D. Merry devstat_remove_entry(&softc->device_stats); 213ee9c90c7SKenneth D. Merry 21473d26919SKenneth D. Merry destroy_dev(softc->dev); 21573d26919SKenneth D. Merry 21676babe50SJustin T. Gibbs cam_extend_release(passperiphs, periph->unit_number); 21776babe50SJustin T. Gibbs 21876babe50SJustin T. Gibbs if (bootverbose) { 21976babe50SJustin T. Gibbs xpt_print_path(periph->path); 22076babe50SJustin T. Gibbs printf("removing device entry\n"); 22176babe50SJustin T. Gibbs } 222ee9c90c7SKenneth D. Merry free(softc, M_DEVBUF); 22376babe50SJustin T. Gibbs } 22476babe50SJustin T. Gibbs 22576babe50SJustin T. Gibbs static void 22676babe50SJustin T. Gibbs passasync(void *callback_arg, u_int32_t code, 22776babe50SJustin T. Gibbs struct cam_path *path, void *arg) 22876babe50SJustin T. Gibbs { 22976babe50SJustin T. Gibbs struct cam_periph *periph; 23076babe50SJustin T. Gibbs 23176babe50SJustin T. Gibbs periph = (struct cam_periph *)callback_arg; 23276babe50SJustin T. Gibbs 23376babe50SJustin T. Gibbs switch (code) { 23476babe50SJustin T. Gibbs case AC_FOUND_DEVICE: 23576babe50SJustin T. Gibbs { 23676babe50SJustin T. Gibbs struct ccb_getdev *cgd; 23776babe50SJustin T. Gibbs cam_status status; 23876babe50SJustin T. Gibbs 23976babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 24076babe50SJustin T. Gibbs 24176babe50SJustin T. Gibbs /* 24276babe50SJustin T. Gibbs * Allocate a peripheral instance for 24376babe50SJustin T. Gibbs * this device and start the probe 24476babe50SJustin T. Gibbs * process. 24576babe50SJustin T. Gibbs */ 246ee9c90c7SKenneth D. Merry status = cam_periph_alloc(passregister, passoninvalidate, 247ee9c90c7SKenneth D. Merry passcleanup, passstart, "pass", 248ee9c90c7SKenneth D. Merry CAM_PERIPH_BIO, cgd->ccb_h.path, 249ee9c90c7SKenneth D. Merry passasync, AC_FOUND_DEVICE, cgd); 25076babe50SJustin T. Gibbs 25176babe50SJustin T. Gibbs if (status != CAM_REQ_CMP 2523393f8daSKenneth D. Merry && status != CAM_REQ_INPROG) { 2533393f8daSKenneth D. Merry const struct cam_status_entry *entry; 2543393f8daSKenneth D. Merry 2553393f8daSKenneth D. Merry entry = cam_fetch_status_entry(status); 2563393f8daSKenneth D. Merry 25776babe50SJustin T. Gibbs printf("passasync: Unable to attach new device " 2583393f8daSKenneth D. Merry "due to status %#x: %s\n", status, entry ? 2593393f8daSKenneth D. Merry entry->status_text : "Unknown"); 2603393f8daSKenneth D. Merry } 26176babe50SJustin T. Gibbs 26276babe50SJustin T. Gibbs break; 26376babe50SJustin T. Gibbs } 26476babe50SJustin T. Gibbs default: 265516871c6SJustin T. Gibbs cam_periph_async(periph, code, path, arg); 26676babe50SJustin T. Gibbs break; 26776babe50SJustin T. Gibbs } 26876babe50SJustin T. Gibbs } 26976babe50SJustin T. Gibbs 27076babe50SJustin T. Gibbs static cam_status 27176babe50SJustin T. Gibbs passregister(struct cam_periph *periph, void *arg) 27276babe50SJustin T. Gibbs { 27376babe50SJustin T. Gibbs struct pass_softc *softc; 27476babe50SJustin T. Gibbs struct ccb_setasync csa; 27576babe50SJustin T. Gibbs struct ccb_getdev *cgd; 2763393f8daSKenneth D. Merry int no_tags; 27776babe50SJustin T. Gibbs 27876babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 27976babe50SJustin T. Gibbs if (periph == NULL) { 28076babe50SJustin T. Gibbs printf("passregister: periph was NULL!!\n"); 28176babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 28276babe50SJustin T. Gibbs } 28376babe50SJustin T. Gibbs 28476babe50SJustin T. Gibbs if (cgd == NULL) { 28576babe50SJustin T. Gibbs printf("passregister: no getdev CCB, can't register device\n"); 28676babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 28776babe50SJustin T. Gibbs } 28876babe50SJustin T. Gibbs 28976babe50SJustin T. Gibbs softc = (struct pass_softc *)malloc(sizeof(*softc), 29076babe50SJustin T. Gibbs M_DEVBUF, M_NOWAIT); 29176babe50SJustin T. Gibbs 29276babe50SJustin T. Gibbs if (softc == NULL) { 29376babe50SJustin T. Gibbs printf("passregister: Unable to probe new device. " 29476babe50SJustin T. Gibbs "Unable to allocate softc\n"); 29576babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 29676babe50SJustin T. Gibbs } 29776babe50SJustin T. Gibbs 29876babe50SJustin T. Gibbs bzero(softc, sizeof(*softc)); 29976babe50SJustin T. Gibbs softc->state = PASS_STATE_NORMAL; 30010b6172aSMatt Jacob softc->pd_type = SID_TYPE(&cgd->inq_data); 30176babe50SJustin T. Gibbs 30276babe50SJustin T. Gibbs periph->softc = softc; 30376babe50SJustin T. Gibbs cam_extend_set(passperiphs, periph->unit_number, periph); 3043393f8daSKenneth D. Merry 30576babe50SJustin T. Gibbs /* 30676babe50SJustin T. Gibbs * We pass in 0 for a blocksize, since we don't 30776babe50SJustin T. Gibbs * know what the blocksize of this device is, if 30876babe50SJustin T. Gibbs * it even has a blocksize. 30976babe50SJustin T. Gibbs */ 3103393f8daSKenneth D. Merry no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0; 3113393f8daSKenneth D. Merry devstat_add_entry(&softc->device_stats, "pass", periph->unit_number, 0, 3123393f8daSKenneth D. Merry DEVSTAT_NO_BLOCKSIZE 3133393f8daSKenneth D. Merry | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0), 31410b6172aSMatt Jacob softc->pd_type | 31576babe50SJustin T. Gibbs DEVSTAT_TYPE_IF_SCSI | 3162a888f93SKenneth D. Merry DEVSTAT_TYPE_PASS, 3172a888f93SKenneth D. Merry DEVSTAT_PRIORITY_PASS); 31873d26919SKenneth D. Merry 31973d26919SKenneth D. Merry /* Register the device */ 32073d26919SKenneth D. Merry softc->dev = make_dev(&pass_cdevsw, periph->unit_number, UID_ROOT, 32173d26919SKenneth D. Merry GID_OPERATOR, 0600, "%s%d", periph->periph_name, 32273d26919SKenneth D. Merry periph->unit_number); 32373d26919SKenneth D. Merry 32476babe50SJustin T. Gibbs /* 32576babe50SJustin T. Gibbs * Add an async callback so that we get 32676babe50SJustin T. Gibbs * notified if this device goes away. 32776babe50SJustin T. Gibbs */ 32876babe50SJustin T. Gibbs xpt_setup_ccb(&csa.ccb_h, periph->path, /* priority */ 5); 32976babe50SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 33076babe50SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 33176babe50SJustin T. Gibbs csa.callback = passasync; 33276babe50SJustin T. Gibbs csa.callback_arg = periph; 33376babe50SJustin T. Gibbs xpt_action((union ccb *)&csa); 33476babe50SJustin T. Gibbs 33576babe50SJustin T. Gibbs if (bootverbose) 33676babe50SJustin T. Gibbs xpt_announce_periph(periph, NULL); 33776babe50SJustin T. Gibbs 33876babe50SJustin T. Gibbs return(CAM_REQ_CMP); 33976babe50SJustin T. Gibbs } 34076babe50SJustin T. Gibbs 34176babe50SJustin T. Gibbs static int 34276babe50SJustin T. Gibbs passopen(dev_t dev, int flags, int fmt, struct proc *p) 34376babe50SJustin T. Gibbs { 34476babe50SJustin T. Gibbs struct cam_periph *periph; 34576babe50SJustin T. Gibbs struct pass_softc *softc; 34676babe50SJustin T. Gibbs int unit, error; 347ee9c90c7SKenneth D. Merry int s; 34876babe50SJustin T. Gibbs 34976babe50SJustin T. Gibbs error = 0; /* default to no error */ 35076babe50SJustin T. Gibbs 35176babe50SJustin T. Gibbs /* unit = dkunit(dev); */ 35276babe50SJustin T. Gibbs /* XXX KDM fix this */ 35376babe50SJustin T. Gibbs unit = minor(dev) & 0xff; 35476babe50SJustin T. Gibbs 35576babe50SJustin T. Gibbs periph = cam_extend_get(passperiphs, unit); 35676babe50SJustin T. Gibbs 35776babe50SJustin T. Gibbs if (periph == NULL) 35876babe50SJustin T. Gibbs return (ENXIO); 35976babe50SJustin T. Gibbs 36076babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 36176babe50SJustin T. Gibbs 362ee9c90c7SKenneth D. Merry s = splsoftcam(); 363ee9c90c7SKenneth D. Merry if (softc->flags & PASS_FLAG_INVALID) { 364ee9c90c7SKenneth D. Merry splx(s); 36576babe50SJustin T. Gibbs return(ENXIO); 366ee9c90c7SKenneth D. Merry } 36722b9c86cSKenneth D. Merry 36822b9c86cSKenneth D. Merry /* 36922b9c86cSKenneth D. Merry * Don't allow access when we're running at a high securelvel. 37022b9c86cSKenneth D. Merry */ 37122b9c86cSKenneth D. Merry if (securelevel > 1) { 372ee9c90c7SKenneth D. Merry splx(s); 37322b9c86cSKenneth D. Merry return(EPERM); 37422b9c86cSKenneth D. Merry } 37576babe50SJustin T. Gibbs 37676babe50SJustin T. Gibbs /* 37766a0780eSKenneth D. Merry * Only allow read-write access. 37866a0780eSKenneth D. Merry */ 37922b9c86cSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) { 38022b9c86cSKenneth D. Merry splx(s); 38166a0780eSKenneth D. Merry return(EPERM); 38222b9c86cSKenneth D. Merry } 38366a0780eSKenneth D. Merry 38466a0780eSKenneth D. Merry /* 38576babe50SJustin T. Gibbs * We don't allow nonblocking access. 38676babe50SJustin T. Gibbs */ 38776babe50SJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 38822b9c86cSKenneth D. Merry xpt_print_path(periph->path); 38922b9c86cSKenneth D. Merry printf("can't do nonblocking accesss\n"); 39022b9c86cSKenneth D. Merry splx(s); 39122b9c86cSKenneth D. Merry return(EINVAL); 39276babe50SJustin T. Gibbs } 39376babe50SJustin T. Gibbs 39422b9c86cSKenneth D. Merry if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) { 39522b9c86cSKenneth D. Merry splx(s); 39676babe50SJustin T. Gibbs return (error); 39722b9c86cSKenneth D. Merry } 39822b9c86cSKenneth D. Merry 39922b9c86cSKenneth D. Merry splx(s); 40076babe50SJustin T. Gibbs 40176babe50SJustin T. Gibbs if ((softc->flags & PASS_FLAG_OPEN) == 0) { 40276babe50SJustin T. Gibbs if (cam_periph_acquire(periph) != CAM_REQ_CMP) 40376babe50SJustin T. Gibbs return(ENXIO); 40476babe50SJustin T. Gibbs softc->flags |= PASS_FLAG_OPEN; 40576babe50SJustin T. Gibbs } 40676babe50SJustin T. Gibbs 40776babe50SJustin T. Gibbs cam_periph_unlock(periph); 40876babe50SJustin T. Gibbs 40976babe50SJustin T. Gibbs return (error); 41076babe50SJustin T. Gibbs } 41176babe50SJustin T. Gibbs 41276babe50SJustin T. Gibbs static int 41376babe50SJustin T. Gibbs passclose(dev_t dev, int flag, int fmt, struct proc *p) 41476babe50SJustin T. Gibbs { 41576babe50SJustin T. Gibbs struct cam_periph *periph; 41676babe50SJustin T. Gibbs struct pass_softc *softc; 41776babe50SJustin T. Gibbs int unit, error; 41876babe50SJustin T. Gibbs 41976babe50SJustin T. Gibbs /* unit = dkunit(dev); */ 42076babe50SJustin T. Gibbs /* XXX KDM fix this */ 42176babe50SJustin T. Gibbs unit = minor(dev) & 0xff; 42276babe50SJustin T. Gibbs 42376babe50SJustin T. Gibbs periph = cam_extend_get(passperiphs, unit); 42476babe50SJustin T. Gibbs if (periph == NULL) 42576babe50SJustin T. Gibbs return (ENXIO); 42676babe50SJustin T. Gibbs 42776babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 42876babe50SJustin T. Gibbs 42976babe50SJustin T. Gibbs if ((error = cam_periph_lock(periph, PRIBIO)) != 0) 43076babe50SJustin T. Gibbs return (error); 43176babe50SJustin T. Gibbs 43276babe50SJustin T. Gibbs softc->flags &= ~PASS_FLAG_OPEN; 43376babe50SJustin T. Gibbs 43476babe50SJustin T. Gibbs cam_periph_unlock(periph); 43576babe50SJustin T. Gibbs cam_periph_release(periph); 43676babe50SJustin T. Gibbs 43776babe50SJustin T. Gibbs return (0); 43876babe50SJustin T. Gibbs } 43976babe50SJustin T. Gibbs 44076babe50SJustin T. Gibbs static void 44176babe50SJustin T. Gibbs passstart(struct cam_periph *periph, union ccb *start_ccb) 44276babe50SJustin T. Gibbs { 44376babe50SJustin T. Gibbs struct pass_softc *softc; 44476babe50SJustin T. Gibbs int s; 44576babe50SJustin T. Gibbs 44676babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 44776babe50SJustin T. Gibbs 44876babe50SJustin T. Gibbs switch (softc->state) { 44976babe50SJustin T. Gibbs case PASS_STATE_NORMAL: 45076babe50SJustin T. Gibbs s = splbio(); 45176babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; 45276babe50SJustin T. Gibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 45376babe50SJustin T. Gibbs periph_links.sle); 45476babe50SJustin T. Gibbs periph->immediate_priority = CAM_PRIORITY_NONE; 45576babe50SJustin T. Gibbs splx(s); 45676babe50SJustin T. Gibbs wakeup(&periph->ccb_list); 45776babe50SJustin T. Gibbs break; 45876babe50SJustin T. Gibbs } 45976babe50SJustin T. Gibbs } 4603393f8daSKenneth D. Merry 46176babe50SJustin T. Gibbs static void 46276babe50SJustin T. Gibbs passdone(struct cam_periph *periph, union ccb *done_ccb) 46376babe50SJustin T. Gibbs { 46476babe50SJustin T. Gibbs struct pass_softc *softc; 46576babe50SJustin T. Gibbs struct ccb_scsiio *csio; 46676babe50SJustin T. Gibbs 46776babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 46876babe50SJustin T. Gibbs csio = &done_ccb->csio; 46976babe50SJustin T. Gibbs switch (csio->ccb_h.ccb_type) { 47076babe50SJustin T. Gibbs case PASS_CCB_WAITING: 47176babe50SJustin T. Gibbs /* Caller will release the CCB */ 47276babe50SJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 47376babe50SJustin T. Gibbs return; 47476babe50SJustin T. Gibbs } 47576babe50SJustin T. Gibbs xpt_release_ccb(done_ccb); 47676babe50SJustin T. Gibbs } 47776babe50SJustin T. Gibbs 47876babe50SJustin T. Gibbs static int 47976babe50SJustin T. Gibbs passioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 48076babe50SJustin T. Gibbs { 48176babe50SJustin T. Gibbs struct cam_periph *periph; 48276babe50SJustin T. Gibbs struct pass_softc *softc; 48376babe50SJustin T. Gibbs u_int8_t unit; 48476babe50SJustin T. Gibbs int error; 48576babe50SJustin T. Gibbs 48676babe50SJustin T. Gibbs 48776babe50SJustin T. Gibbs /* unit = dkunit(dev); */ 48876babe50SJustin T. Gibbs /* XXX KDM fix this */ 48976babe50SJustin T. Gibbs unit = minor(dev) & 0xff; 49076babe50SJustin T. Gibbs 49176babe50SJustin T. Gibbs periph = cam_extend_get(passperiphs, unit); 49276babe50SJustin T. Gibbs 49376babe50SJustin T. Gibbs if (periph == NULL) 49476babe50SJustin T. Gibbs return(ENXIO); 49576babe50SJustin T. Gibbs 49676babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 49776babe50SJustin T. Gibbs 49876babe50SJustin T. Gibbs error = 0; 49976babe50SJustin T. Gibbs 50076babe50SJustin T. Gibbs switch (cmd) { 50176babe50SJustin T. Gibbs 50276babe50SJustin T. Gibbs case CAMIOCOMMAND: 50376babe50SJustin T. Gibbs { 50476babe50SJustin T. Gibbs union ccb *inccb; 50576babe50SJustin T. Gibbs union ccb *ccb; 5069deea857SKenneth D. Merry int ccb_malloced; 50776babe50SJustin T. Gibbs 50876babe50SJustin T. Gibbs inccb = (union ccb *)addr; 5099deea857SKenneth D. Merry 5109deea857SKenneth D. Merry /* 5119deea857SKenneth D. Merry * Some CCB types, like scan bus and scan lun can only go 5129deea857SKenneth D. Merry * through the transport layer device. 5139deea857SKenneth D. Merry */ 5149deea857SKenneth D. Merry if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 5159deea857SKenneth D. Merry xpt_print_path(periph->path); 5169deea857SKenneth D. Merry printf("CCB function code %#x is restricted to the " 5179deea857SKenneth D. Merry "XPT device\n", inccb->ccb_h.func_code); 5189deea857SKenneth D. Merry error = ENODEV; 5199deea857SKenneth D. Merry break; 5209deea857SKenneth D. Merry } 5219deea857SKenneth D. Merry 5229deea857SKenneth D. Merry /* 5239deea857SKenneth D. Merry * Non-immediate CCBs need a CCB from the per-device pool 5249deea857SKenneth D. Merry * of CCBs, which is scheduled by the transport layer. 5259deea857SKenneth D. Merry * Immediate CCBs and user-supplied CCBs should just be 5269deea857SKenneth D. Merry * malloced. 5279deea857SKenneth D. Merry */ 5289deea857SKenneth D. Merry if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 5299deea857SKenneth D. Merry && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 5309deea857SKenneth D. Merry ccb = cam_periph_getccb(periph, 5319deea857SKenneth D. Merry inccb->ccb_h.pinfo.priority); 5329deea857SKenneth D. Merry ccb_malloced = 0; 5339deea857SKenneth D. Merry } else { 5349deea857SKenneth D. Merry ccb = xpt_alloc_ccb(); 5359deea857SKenneth D. Merry 5369deea857SKenneth D. Merry if (ccb != NULL) 5379deea857SKenneth D. Merry xpt_setup_ccb(&ccb->ccb_h, periph->path, 5389deea857SKenneth D. Merry inccb->ccb_h.pinfo.priority); 5399deea857SKenneth D. Merry ccb_malloced = 1; 5409deea857SKenneth D. Merry } 5419deea857SKenneth D. Merry 5429deea857SKenneth D. Merry if (ccb == NULL) { 5439deea857SKenneth D. Merry xpt_print_path(periph->path); 5449deea857SKenneth D. Merry printf("unable to allocate CCB\n"); 5459deea857SKenneth D. Merry error = ENOMEM; 5469deea857SKenneth D. Merry break; 5479deea857SKenneth D. Merry } 54876babe50SJustin T. Gibbs 54976babe50SJustin T. Gibbs error = passsendccb(periph, ccb, inccb); 55076babe50SJustin T. Gibbs 5519deea857SKenneth D. Merry if (ccb_malloced) 5529deea857SKenneth D. Merry xpt_free_ccb(ccb); 5539deea857SKenneth D. Merry else 55476babe50SJustin T. Gibbs xpt_release_ccb(ccb); 55576babe50SJustin T. Gibbs 55676babe50SJustin T. Gibbs break; 55776babe50SJustin T. Gibbs } 55876babe50SJustin T. Gibbs default: 55976babe50SJustin T. Gibbs error = cam_periph_ioctl(periph, cmd, addr, passerror); 56076babe50SJustin T. Gibbs break; 56176babe50SJustin T. Gibbs } 56276babe50SJustin T. Gibbs 56376babe50SJustin T. Gibbs return(error); 56476babe50SJustin T. Gibbs } 56576babe50SJustin T. Gibbs 56676babe50SJustin T. Gibbs /* 56776babe50SJustin T. Gibbs * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 56876babe50SJustin T. Gibbs * should be the CCB that is copied in from the user. 56976babe50SJustin T. Gibbs */ 57076babe50SJustin T. Gibbs static int 57176babe50SJustin T. Gibbs passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 57276babe50SJustin T. Gibbs { 57376babe50SJustin T. Gibbs struct pass_softc *softc; 57476babe50SJustin T. Gibbs struct cam_periph_map_info mapinfo; 57576babe50SJustin T. Gibbs int error, need_unmap; 57676babe50SJustin T. Gibbs 57776babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 57876babe50SJustin T. Gibbs 57976babe50SJustin T. Gibbs need_unmap = 0; 58076babe50SJustin T. Gibbs 58176babe50SJustin T. Gibbs /* 58276babe50SJustin T. Gibbs * There are some fields in the CCB header that need to be 58376babe50SJustin T. Gibbs * preserved, the rest we get from the user. 58476babe50SJustin T. Gibbs */ 58576babe50SJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 58676babe50SJustin T. Gibbs 58776babe50SJustin T. Gibbs /* 58876babe50SJustin T. Gibbs * There's no way for the user to have a completion 58976babe50SJustin T. Gibbs * function, so we put our own completion function in here. 59076babe50SJustin T. Gibbs */ 59176babe50SJustin T. Gibbs ccb->ccb_h.cbfcnp = passdone; 59276babe50SJustin T. Gibbs 59376babe50SJustin T. Gibbs /* 59476babe50SJustin T. Gibbs * We only attempt to map the user memory into kernel space 59576babe50SJustin T. Gibbs * if they haven't passed in a physical memory pointer, 59676babe50SJustin T. Gibbs * and if there is actually an I/O operation to perform. 59776babe50SJustin T. Gibbs * Right now cam_periph_mapmem() only supports SCSI and device 59876babe50SJustin T. Gibbs * match CCBs. For the SCSI CCBs, we only pass the CCB in if 59976babe50SJustin T. Gibbs * there's actually data to map. cam_periph_mapmem() will do the 60076babe50SJustin T. Gibbs * right thing, even if there isn't data to map, but since CCBs 60176babe50SJustin T. Gibbs * without data are a reasonably common occurance (e.g. test unit 60276babe50SJustin T. Gibbs * ready), it will save a few cycles if we check for it here. 60376babe50SJustin T. Gibbs */ 60476babe50SJustin T. Gibbs if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0) 60576babe50SJustin T. Gibbs && (((ccb->ccb_h.func_code == XPT_SCSI_IO) 60676babe50SJustin T. Gibbs && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 60776babe50SJustin T. Gibbs || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) { 60876babe50SJustin T. Gibbs 60976babe50SJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 61076babe50SJustin T. Gibbs 61176babe50SJustin T. Gibbs error = cam_periph_mapmem(ccb, &mapinfo); 61276babe50SJustin T. Gibbs 61376babe50SJustin T. Gibbs /* 61476babe50SJustin T. Gibbs * cam_periph_mapmem returned an error, we can't continue. 61576babe50SJustin T. Gibbs * Return the error to the user. 61676babe50SJustin T. Gibbs */ 61776babe50SJustin T. Gibbs if (error) 61876babe50SJustin T. Gibbs return(error); 61976babe50SJustin T. Gibbs 62076babe50SJustin T. Gibbs /* 62176babe50SJustin T. Gibbs * We successfully mapped the memory in, so we need to 62276babe50SJustin T. Gibbs * unmap it when the transaction is done. 62376babe50SJustin T. Gibbs */ 62476babe50SJustin T. Gibbs need_unmap = 1; 62576babe50SJustin T. Gibbs } 62676babe50SJustin T. Gibbs 62776babe50SJustin T. Gibbs /* 62876babe50SJustin T. Gibbs * If the user wants us to perform any error recovery, then honor 62976babe50SJustin T. Gibbs * that request. Otherwise, it's up to the user to perform any 63076babe50SJustin T. Gibbs * error recovery. 63176babe50SJustin T. Gibbs */ 63276babe50SJustin T. Gibbs error = cam_periph_runccb(ccb, 63376babe50SJustin T. Gibbs (ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 63476babe50SJustin T. Gibbs passerror : NULL, 6353393f8daSKenneth D. Merry /* cam_flags */ CAM_RETRY_SELTO, 6363393f8daSKenneth D. Merry /* sense_flags */SF_RETRY_UA, 63776babe50SJustin T. Gibbs &softc->device_stats); 63876babe50SJustin T. Gibbs 63976babe50SJustin T. Gibbs if (need_unmap != 0) 64076babe50SJustin T. Gibbs cam_periph_unmapmem(ccb, &mapinfo); 64176babe50SJustin T. Gibbs 64276babe50SJustin T. Gibbs ccb->ccb_h.cbfcnp = NULL; 64376babe50SJustin T. Gibbs ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 64476babe50SJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 64576babe50SJustin T. Gibbs 64676babe50SJustin T. Gibbs return(error); 64776babe50SJustin T. Gibbs } 64876babe50SJustin T. Gibbs 64976babe50SJustin T. Gibbs static int 65076babe50SJustin T. Gibbs passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 65176babe50SJustin T. Gibbs { 65276babe50SJustin T. Gibbs struct cam_periph *periph; 65376babe50SJustin T. Gibbs struct pass_softc *softc; 65476babe50SJustin T. Gibbs 65576babe50SJustin T. Gibbs periph = xpt_path_periph(ccb->ccb_h.path); 65676babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 65776babe50SJustin T. Gibbs 65876babe50SJustin T. Gibbs return(cam_periph_error(ccb, cam_flags, sense_flags, 65976babe50SJustin T. Gibbs &softc->saved_ccb)); 66076babe50SJustin T. Gibbs } 661