1898b0535SWarner Losh /*- 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 */ 2776babe50SJustin T. Gibbs 28ee709e70SDavid E. O'Brien #include <sys/cdefs.h> 29ee709e70SDavid E. O'Brien __FBSDID("$FreeBSD$"); 30ee709e70SDavid E. O'Brien 3176babe50SJustin T. Gibbs #include <sys/param.h> 3276babe50SJustin T. Gibbs #include <sys/systm.h> 3376babe50SJustin T. Gibbs #include <sys/kernel.h> 3476babe50SJustin T. Gibbs #include <sys/types.h> 359626b608SPoul-Henning Kamp #include <sys/bio.h> 3676babe50SJustin T. Gibbs #include <sys/malloc.h> 3776babe50SJustin T. Gibbs #include <sys/fcntl.h> 3876babe50SJustin T. Gibbs #include <sys/conf.h> 3976babe50SJustin T. Gibbs #include <sys/errno.h> 4076babe50SJustin T. Gibbs #include <sys/devicestat.h> 41f7312ca2SRobert Watson #include <sys/proc.h> 42416494d7SJustin T. Gibbs #include <sys/taskqueue.h> 4376babe50SJustin T. Gibbs 4476babe50SJustin T. Gibbs #include <cam/cam.h> 4576babe50SJustin T. Gibbs #include <cam/cam_ccb.h> 4676babe50SJustin T. Gibbs #include <cam/cam_periph.h> 473393f8daSKenneth D. Merry #include <cam/cam_queue.h> 4876babe50SJustin T. Gibbs #include <cam/cam_xpt_periph.h> 4976babe50SJustin T. Gibbs #include <cam/cam_debug.h> 502b83592fSScott Long #include <cam/cam_sim.h> 5125a2902cSScott Long #include <cam/cam_compat.h> 5276babe50SJustin T. Gibbs 5376babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h> 5476babe50SJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 5576babe50SJustin T. Gibbs 5676babe50SJustin T. Gibbs typedef enum { 5776babe50SJustin T. Gibbs PASS_FLAG_OPEN = 0x01, 5876babe50SJustin T. Gibbs PASS_FLAG_LOCKED = 0x02, 59ea37f519SKenneth D. Merry PASS_FLAG_INVALID = 0x04, 60ea37f519SKenneth D. Merry PASS_FLAG_INITIAL_PHYSPATH = 0x08 6176babe50SJustin T. Gibbs } pass_flags; 6276babe50SJustin T. Gibbs 6376babe50SJustin T. Gibbs typedef enum { 6476babe50SJustin T. Gibbs PASS_STATE_NORMAL 6576babe50SJustin T. Gibbs } pass_state; 6676babe50SJustin T. Gibbs 6776babe50SJustin T. Gibbs typedef enum { 6876babe50SJustin T. Gibbs PASS_CCB_BUFFER_IO, 6976babe50SJustin T. Gibbs PASS_CCB_WAITING 7076babe50SJustin T. Gibbs } pass_ccb_types; 7176babe50SJustin T. Gibbs 7276babe50SJustin T. Gibbs #define ccb_type ppriv_field0 7376babe50SJustin T. Gibbs #define ccb_bp ppriv_ptr1 7476babe50SJustin T. Gibbs 7576babe50SJustin T. Gibbs struct pass_softc { 7676babe50SJustin T. Gibbs pass_state state; 7776babe50SJustin T. Gibbs pass_flags flags; 7876babe50SJustin T. Gibbs u_int8_t pd_type; 7976babe50SJustin T. Gibbs union ccb saved_ccb; 8086d45c7fSKenneth D. Merry int open_count; 81a9d2245eSPoul-Henning Kamp struct devstat *device_stats; 8289c9c53dSPoul-Henning Kamp struct cdev *dev; 83416494d7SJustin T. Gibbs struct cdev *alias_dev; 84416494d7SJustin T. Gibbs struct task add_physpath_task; 8576babe50SJustin T. Gibbs }; 8676babe50SJustin T. Gibbs 8776babe50SJustin T. Gibbs 8876babe50SJustin T. Gibbs static d_open_t passopen; 8976babe50SJustin T. Gibbs static d_close_t passclose; 9076babe50SJustin T. Gibbs static d_ioctl_t passioctl; 9125a2902cSScott Long static d_ioctl_t passdoioctl; 9276babe50SJustin T. Gibbs 9376babe50SJustin T. Gibbs static periph_init_t passinit; 9476babe50SJustin T. Gibbs static periph_ctor_t passregister; 95ee9c90c7SKenneth D. Merry static periph_oninv_t passoninvalidate; 9676babe50SJustin T. Gibbs static periph_dtor_t passcleanup; 9776babe50SJustin T. Gibbs static periph_start_t passstart; 98416494d7SJustin T. Gibbs static void pass_add_physpath(void *context, int pending); 9976babe50SJustin T. Gibbs static void passasync(void *callback_arg, u_int32_t code, 10076babe50SJustin T. Gibbs struct cam_path *path, void *arg); 10176babe50SJustin T. Gibbs static void passdone(struct cam_periph *periph, 10276babe50SJustin T. Gibbs union ccb *done_ccb); 10376babe50SJustin T. Gibbs static int passerror(union ccb *ccb, u_int32_t cam_flags, 10476babe50SJustin T. Gibbs u_int32_t sense_flags); 10576babe50SJustin T. Gibbs static int passsendccb(struct cam_periph *periph, union ccb *ccb, 10676babe50SJustin T. Gibbs union ccb *inccb); 10776babe50SJustin T. Gibbs 10876babe50SJustin T. Gibbs static struct periph_driver passdriver = 10976babe50SJustin T. Gibbs { 11076babe50SJustin T. Gibbs passinit, "pass", 11176babe50SJustin T. Gibbs TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 11276babe50SJustin T. Gibbs }; 11376babe50SJustin T. Gibbs 1140b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(pass, passdriver); 11576babe50SJustin T. Gibbs 1164e2f199eSPoul-Henning Kamp static struct cdevsw pass_cdevsw = { 117dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 118c552ebe1SKenneth D. Merry .d_flags = D_TRACKCLOSE, 1197ac40f5fSPoul-Henning Kamp .d_open = passopen, 1207ac40f5fSPoul-Henning Kamp .d_close = passclose, 1217ac40f5fSPoul-Henning Kamp .d_ioctl = passioctl, 1227ac40f5fSPoul-Henning Kamp .d_name = "pass", 12376babe50SJustin T. Gibbs }; 12476babe50SJustin T. Gibbs 12576babe50SJustin T. Gibbs static void 12676babe50SJustin T. Gibbs passinit(void) 12776babe50SJustin T. Gibbs { 12876babe50SJustin T. Gibbs cam_status status; 12976babe50SJustin T. Gibbs 13076babe50SJustin T. Gibbs /* 13176babe50SJustin T. Gibbs * Install a global async callback. This callback will 13276babe50SJustin T. Gibbs * receive async callbacks like "new device found". 13376babe50SJustin T. Gibbs */ 13485d92640SScott Long status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL); 13576babe50SJustin T. Gibbs 13676babe50SJustin T. Gibbs if (status != CAM_REQ_CMP) { 13776babe50SJustin T. Gibbs printf("pass: Failed to attach master async callback " 13876babe50SJustin T. Gibbs "due to status 0x%x!\n", status); 13976babe50SJustin T. Gibbs } 14076babe50SJustin T. Gibbs 14176babe50SJustin T. Gibbs } 14276babe50SJustin T. Gibbs 14376babe50SJustin T. Gibbs static void 144ea37f519SKenneth D. Merry passdevgonecb(void *arg) 145ea37f519SKenneth D. Merry { 14686d45c7fSKenneth D. Merry struct cam_sim *sim; 147ea37f519SKenneth D. Merry struct cam_periph *periph; 14886d45c7fSKenneth D. Merry struct pass_softc *softc; 14986d45c7fSKenneth D. Merry int i; 150ea37f519SKenneth D. Merry 151ea37f519SKenneth D. Merry periph = (struct cam_periph *)arg; 15286d45c7fSKenneth D. Merry sim = periph->sim; 15386d45c7fSKenneth D. Merry softc = (struct pass_softc *)periph->softc; 154ea37f519SKenneth D. Merry 15586d45c7fSKenneth D. Merry KASSERT(softc->open_count >= 0, ("Negative open count %d", 15686d45c7fSKenneth D. Merry softc->open_count)); 15786d45c7fSKenneth D. Merry 15886d45c7fSKenneth D. Merry mtx_lock(sim->mtx); 15986d45c7fSKenneth D. Merry 16086d45c7fSKenneth D. Merry /* 16186d45c7fSKenneth D. Merry * When we get this callback, we will get no more close calls from 16286d45c7fSKenneth D. Merry * devfs. So if we have any dangling opens, we need to release the 16386d45c7fSKenneth D. Merry * reference held for that particular context. 16486d45c7fSKenneth D. Merry */ 16586d45c7fSKenneth D. Merry for (i = 0; i < softc->open_count; i++) 16686d45c7fSKenneth D. Merry cam_periph_release_locked(periph); 16786d45c7fSKenneth D. Merry 16886d45c7fSKenneth D. Merry softc->open_count = 0; 16986d45c7fSKenneth D. Merry 17086d45c7fSKenneth D. Merry /* 17186d45c7fSKenneth D. Merry * Release the reference held for the device node, it is gone now. 17286d45c7fSKenneth D. Merry */ 17386d45c7fSKenneth D. Merry cam_periph_release_locked(periph); 17486d45c7fSKenneth D. Merry 17586d45c7fSKenneth D. Merry /* 17686d45c7fSKenneth D. Merry * We reference the SIM lock directly here, instead of using 17786d45c7fSKenneth D. Merry * cam_periph_unlock(). The reason is that the final call to 17886d45c7fSKenneth D. Merry * cam_periph_release_locked() above could result in the periph 17986d45c7fSKenneth D. Merry * getting freed. If that is the case, dereferencing the periph 18086d45c7fSKenneth D. Merry * with a cam_periph_unlock() call would cause a page fault. 18186d45c7fSKenneth D. Merry */ 18286d45c7fSKenneth D. Merry mtx_unlock(sim->mtx); 183ea37f519SKenneth D. Merry } 184ea37f519SKenneth D. Merry 185ea37f519SKenneth D. Merry static void 186ee9c90c7SKenneth D. Merry passoninvalidate(struct cam_periph *periph) 187ee9c90c7SKenneth D. Merry { 188ee9c90c7SKenneth D. Merry struct pass_softc *softc; 189ee9c90c7SKenneth D. Merry 190ee9c90c7SKenneth D. Merry softc = (struct pass_softc *)periph->softc; 191ee9c90c7SKenneth D. Merry 192ee9c90c7SKenneth D. Merry /* 193ee9c90c7SKenneth D. Merry * De-register any async callbacks. 194ee9c90c7SKenneth D. Merry */ 19585d92640SScott Long xpt_register_async(0, passasync, periph, periph->path); 196ee9c90c7SKenneth D. Merry 197ee9c90c7SKenneth D. Merry softc->flags |= PASS_FLAG_INVALID; 198ee9c90c7SKenneth D. Merry 199ee9c90c7SKenneth D. Merry /* 200ea37f519SKenneth D. Merry * Tell devfs this device has gone away, and ask for a callback 201ea37f519SKenneth D. Merry * when it has cleaned up its state. 202ea37f519SKenneth D. Merry */ 203ea37f519SKenneth D. Merry destroy_dev_sched_cb(softc->dev, passdevgonecb, periph); 204ea37f519SKenneth D. Merry 205ea37f519SKenneth D. Merry /* 2063393f8daSKenneth D. Merry * XXX Return all queued I/O with ENXIO. 207ee9c90c7SKenneth D. Merry * XXX Handle any transactions queued to the card 208ee9c90c7SKenneth D. Merry * with XPT_ABORT_CCB. 209ee9c90c7SKenneth D. Merry */ 210ee9c90c7SKenneth D. Merry 211ee9c90c7SKenneth D. Merry if (bootverbose) { 212f0d9af51SMatt Jacob xpt_print(periph->path, "lost device\n"); 213ee9c90c7SKenneth D. Merry } 214ee9c90c7SKenneth D. Merry 215ee9c90c7SKenneth D. Merry } 216ee9c90c7SKenneth D. Merry 217ee9c90c7SKenneth D. Merry static void 21876babe50SJustin T. Gibbs passcleanup(struct cam_periph *periph) 21976babe50SJustin T. Gibbs { 220ee9c90c7SKenneth D. Merry struct pass_softc *softc; 221ee9c90c7SKenneth D. Merry 222ee9c90c7SKenneth D. Merry softc = (struct pass_softc *)periph->softc; 223ee9c90c7SKenneth D. Merry 2245f3fed85SEdward Tomasz Napierala if (bootverbose) 225f0d9af51SMatt Jacob xpt_print(periph->path, "removing device entry\n"); 2265f3fed85SEdward Tomasz Napierala devstat_remove_entry(softc->device_stats); 227416494d7SJustin T. Gibbs 2285f3fed85SEdward Tomasz Napierala cam_periph_unlock(periph); 229416494d7SJustin T. Gibbs taskqueue_drain(taskqueue_thread, &softc->add_physpath_task); 230416494d7SJustin T. Gibbs 2315f3fed85SEdward Tomasz Napierala cam_periph_lock(periph); 232416494d7SJustin T. Gibbs 233ee9c90c7SKenneth D. Merry free(softc, M_DEVBUF); 23476babe50SJustin T. Gibbs } 23576babe50SJustin T. Gibbs 23676babe50SJustin T. Gibbs static void 237416494d7SJustin T. Gibbs pass_add_physpath(void *context, int pending) 238416494d7SJustin T. Gibbs { 239416494d7SJustin T. Gibbs struct cam_periph *periph; 240416494d7SJustin T. Gibbs struct pass_softc *softc; 241416494d7SJustin T. Gibbs char *physpath; 242416494d7SJustin T. Gibbs 243416494d7SJustin T. Gibbs /* 244416494d7SJustin T. Gibbs * If we have one, create a devfs alias for our 245416494d7SJustin T. Gibbs * physical path. 246416494d7SJustin T. Gibbs */ 247416494d7SJustin T. Gibbs periph = context; 248416494d7SJustin T. Gibbs softc = periph->softc; 2496884b662SAlexander Motin physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK); 250ea37f519SKenneth D. Merry cam_periph_lock(periph); 251ea37f519SKenneth D. Merry if (periph->flags & CAM_PERIPH_INVALID) { 252ea37f519SKenneth D. Merry cam_periph_unlock(periph); 2536884b662SAlexander Motin goto out; 254ea37f519SKenneth D. Merry } 255416494d7SJustin T. Gibbs if (xpt_getattr(physpath, MAXPATHLEN, 256416494d7SJustin T. Gibbs "GEOM::physpath", periph->path) == 0 257416494d7SJustin T. Gibbs && strlen(physpath) != 0) { 258416494d7SJustin T. Gibbs 2596884b662SAlexander Motin cam_periph_unlock(periph); 260416494d7SJustin T. Gibbs make_dev_physpath_alias(MAKEDEV_WAITOK, &softc->alias_dev, 261416494d7SJustin T. Gibbs softc->dev, softc->alias_dev, physpath); 2626884b662SAlexander Motin cam_periph_lock(periph); 263416494d7SJustin T. Gibbs } 264ea37f519SKenneth D. Merry 265ea37f519SKenneth D. Merry /* 266ea37f519SKenneth D. Merry * Now that we've made our alias, we no longer have to have a 267ea37f519SKenneth D. Merry * reference to the device. 268ea37f519SKenneth D. Merry */ 269ea37f519SKenneth D. Merry if ((softc->flags & PASS_FLAG_INITIAL_PHYSPATH) == 0) { 270ea37f519SKenneth D. Merry softc->flags |= PASS_FLAG_INITIAL_PHYSPATH; 271ea37f519SKenneth D. Merry cam_periph_unlock(periph); 272ea37f519SKenneth D. Merry dev_rel(softc->dev); 273ea37f519SKenneth D. Merry } 274ea37f519SKenneth D. Merry else 275ea37f519SKenneth D. Merry cam_periph_unlock(periph); 2766884b662SAlexander Motin 2776884b662SAlexander Motin out: 2786884b662SAlexander Motin free(physpath, M_DEVBUF); 279416494d7SJustin T. Gibbs } 280416494d7SJustin T. Gibbs 281416494d7SJustin T. Gibbs static void 28276babe50SJustin T. Gibbs passasync(void *callback_arg, u_int32_t code, 28376babe50SJustin T. Gibbs struct cam_path *path, void *arg) 28476babe50SJustin T. Gibbs { 28576babe50SJustin T. Gibbs struct cam_periph *periph; 28676babe50SJustin T. Gibbs 28776babe50SJustin T. Gibbs periph = (struct cam_periph *)callback_arg; 28876babe50SJustin T. Gibbs 28976babe50SJustin T. Gibbs switch (code) { 29076babe50SJustin T. Gibbs case AC_FOUND_DEVICE: 29176babe50SJustin T. Gibbs { 29276babe50SJustin T. Gibbs struct ccb_getdev *cgd; 29376babe50SJustin T. Gibbs cam_status status; 29476babe50SJustin T. Gibbs 29576babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 296c5ff3b2fSMatt Jacob if (cgd == NULL) 297c5ff3b2fSMatt Jacob break; 29876babe50SJustin T. Gibbs 29976babe50SJustin T. Gibbs /* 30076babe50SJustin T. Gibbs * Allocate a peripheral instance for 30176babe50SJustin T. Gibbs * this device and start the probe 30276babe50SJustin T. Gibbs * process. 30376babe50SJustin T. Gibbs */ 304ee9c90c7SKenneth D. Merry status = cam_periph_alloc(passregister, passoninvalidate, 305ee9c90c7SKenneth D. Merry passcleanup, passstart, "pass", 306ee9c90c7SKenneth D. Merry CAM_PERIPH_BIO, cgd->ccb_h.path, 307ee9c90c7SKenneth D. Merry passasync, AC_FOUND_DEVICE, cgd); 30876babe50SJustin T. Gibbs 30976babe50SJustin T. Gibbs if (status != CAM_REQ_CMP 3103393f8daSKenneth D. Merry && status != CAM_REQ_INPROG) { 3113393f8daSKenneth D. Merry const struct cam_status_entry *entry; 3123393f8daSKenneth D. Merry 3133393f8daSKenneth D. Merry entry = cam_fetch_status_entry(status); 3143393f8daSKenneth D. Merry 31576babe50SJustin T. Gibbs printf("passasync: Unable to attach new device " 3163393f8daSKenneth D. Merry "due to status %#x: %s\n", status, entry ? 3173393f8daSKenneth D. Merry entry->status_text : "Unknown"); 3183393f8daSKenneth D. Merry } 31976babe50SJustin T. Gibbs 32076babe50SJustin T. Gibbs break; 32176babe50SJustin T. Gibbs } 322416494d7SJustin T. Gibbs case AC_ADVINFO_CHANGED: 323416494d7SJustin T. Gibbs { 324416494d7SJustin T. Gibbs uintptr_t buftype; 325416494d7SJustin T. Gibbs 326416494d7SJustin T. Gibbs buftype = (uintptr_t)arg; 327416494d7SJustin T. Gibbs if (buftype == CDAI_TYPE_PHYS_PATH) { 328416494d7SJustin T. Gibbs struct pass_softc *softc; 329416494d7SJustin T. Gibbs 330416494d7SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 331416494d7SJustin T. Gibbs taskqueue_enqueue(taskqueue_thread, 332416494d7SJustin T. Gibbs &softc->add_physpath_task); 333416494d7SJustin T. Gibbs } 334416494d7SJustin T. Gibbs break; 335416494d7SJustin T. Gibbs } 33676babe50SJustin T. Gibbs default: 337516871c6SJustin T. Gibbs cam_periph_async(periph, code, path, arg); 33876babe50SJustin T. Gibbs break; 33976babe50SJustin T. Gibbs } 34076babe50SJustin T. Gibbs } 34176babe50SJustin T. Gibbs 34276babe50SJustin T. Gibbs static cam_status 34376babe50SJustin T. Gibbs passregister(struct cam_periph *periph, void *arg) 34476babe50SJustin T. Gibbs { 34576babe50SJustin T. Gibbs struct pass_softc *softc; 34676babe50SJustin T. Gibbs struct ccb_getdev *cgd; 347b8b6b5d3SAlexander Motin struct ccb_pathinq cpi; 3483393f8daSKenneth D. Merry int no_tags; 34976babe50SJustin T. Gibbs 35076babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 35176babe50SJustin T. Gibbs if (cgd == NULL) { 352ea37f519SKenneth D. Merry printf("%s: no getdev CCB, can't register device\n", __func__); 35376babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 35476babe50SJustin T. Gibbs } 35576babe50SJustin T. Gibbs 35676babe50SJustin T. Gibbs softc = (struct pass_softc *)malloc(sizeof(*softc), 35776babe50SJustin T. Gibbs M_DEVBUF, M_NOWAIT); 35876babe50SJustin T. Gibbs 35976babe50SJustin T. Gibbs if (softc == NULL) { 360ea37f519SKenneth D. Merry printf("%s: Unable to probe new device. " 361ea37f519SKenneth D. Merry "Unable to allocate softc\n", __func__); 36276babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 36376babe50SJustin T. Gibbs } 36476babe50SJustin T. Gibbs 36576babe50SJustin T. Gibbs bzero(softc, sizeof(*softc)); 36676babe50SJustin T. Gibbs softc->state = PASS_STATE_NORMAL; 367b8b6b5d3SAlexander Motin if (cgd->protocol == PROTO_SCSI || cgd->protocol == PROTO_ATAPI) 36810b6172aSMatt Jacob softc->pd_type = SID_TYPE(&cgd->inq_data); 369b8b6b5d3SAlexander Motin else if (cgd->protocol == PROTO_SATAPM) 370b8b6b5d3SAlexander Motin softc->pd_type = T_ENCLOSURE; 371b8b6b5d3SAlexander Motin else 372b8b6b5d3SAlexander Motin softc->pd_type = T_DIRECT; 37376babe50SJustin T. Gibbs 37476babe50SJustin T. Gibbs periph->softc = softc; 3753393f8daSKenneth D. Merry 376b8b6b5d3SAlexander Motin bzero(&cpi, sizeof(cpi)); 377b8b6b5d3SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 378b8b6b5d3SAlexander Motin cpi.ccb_h.func_code = XPT_PATH_INQ; 379b8b6b5d3SAlexander Motin xpt_action((union ccb *)&cpi); 380b8b6b5d3SAlexander Motin 38176babe50SJustin T. Gibbs /* 38276babe50SJustin T. Gibbs * We pass in 0 for a blocksize, since we don't 38376babe50SJustin T. Gibbs * know what the blocksize of this device is, if 38476babe50SJustin T. Gibbs * it even has a blocksize. 38576babe50SJustin T. Gibbs */ 386edec59d9SAlexander Motin cam_periph_unlock(periph); 3873393f8daSKenneth D. Merry no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0; 388c81d2c74SMatt Jacob softc->device_stats = devstat_new_entry("pass", 389d3ce8327SEd Schouten periph->unit_number, 0, 3903393f8daSKenneth D. Merry DEVSTAT_NO_BLOCKSIZE 3913393f8daSKenneth D. Merry | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0), 39210b6172aSMatt Jacob softc->pd_type | 393b8b6b5d3SAlexander Motin XPORT_DEVSTAT_TYPE(cpi.transport) | 3942a888f93SKenneth D. Merry DEVSTAT_TYPE_PASS, 3952a888f93SKenneth D. Merry DEVSTAT_PRIORITY_PASS); 39673d26919SKenneth D. Merry 397ea37f519SKenneth D. Merry /* 398ea37f519SKenneth D. Merry * Acquire a reference to the periph before we create the devfs 399ea37f519SKenneth D. Merry * instance for it. We'll release this reference once the devfs 400ea37f519SKenneth D. Merry * instance has been freed. 401ea37f519SKenneth D. Merry */ 402ea37f519SKenneth D. Merry if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 403ea37f519SKenneth D. Merry xpt_print(periph->path, "%s: lost periph during " 404ea37f519SKenneth D. Merry "registration!\n", __func__); 40586d45c7fSKenneth D. Merry cam_periph_lock(periph); 406ea37f519SKenneth D. Merry return (CAM_REQ_CMP_ERR); 407ea37f519SKenneth D. Merry } 408ea37f519SKenneth D. Merry 40973d26919SKenneth D. Merry /* Register the device */ 410d3ce8327SEd Schouten softc->dev = make_dev(&pass_cdevsw, periph->unit_number, 411c81d2c74SMatt Jacob UID_ROOT, GID_OPERATOR, 0600, "%s%d", 412c81d2c74SMatt Jacob periph->periph_name, periph->unit_number); 413ea37f519SKenneth D. Merry 414ea37f519SKenneth D. Merry /* 415ea37f519SKenneth D. Merry * Now that we have made the devfs instance, hold a reference to it 416ea37f519SKenneth D. Merry * until the task queue has run to setup the physical path alias. 417ea37f519SKenneth D. Merry * That way devfs won't get rid of the device before we add our 418ea37f519SKenneth D. Merry * alias. 419ea37f519SKenneth D. Merry */ 420ea37f519SKenneth D. Merry dev_ref(softc->dev); 421ea37f519SKenneth D. Merry 422edec59d9SAlexander Motin cam_periph_lock(periph); 423e2a5fdf9SNate Lawson softc->dev->si_drv1 = periph; 42473d26919SKenneth D. Merry 425416494d7SJustin T. Gibbs TASK_INIT(&softc->add_physpath_task, /*priority*/0, 426416494d7SJustin T. Gibbs pass_add_physpath, periph); 427416494d7SJustin T. Gibbs 42876babe50SJustin T. Gibbs /* 429416494d7SJustin T. Gibbs * See if physical path information is already available. 43076babe50SJustin T. Gibbs */ 431416494d7SJustin T. Gibbs taskqueue_enqueue(taskqueue_thread, &softc->add_physpath_task); 432416494d7SJustin T. Gibbs 433416494d7SJustin T. Gibbs /* 434416494d7SJustin T. Gibbs * Add an async callback so that we get notified if 435416494d7SJustin T. Gibbs * this device goes away or its physical path 436416494d7SJustin T. Gibbs * (stored in the advanced info data of the EDT) has 437416494d7SJustin T. Gibbs * changed. 438416494d7SJustin T. Gibbs */ 439416494d7SJustin T. Gibbs xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED, 440416494d7SJustin T. Gibbs passasync, periph, periph->path); 44176babe50SJustin T. Gibbs 44276babe50SJustin T. Gibbs if (bootverbose) 44376babe50SJustin T. Gibbs xpt_announce_periph(periph, NULL); 44476babe50SJustin T. Gibbs 44576babe50SJustin T. Gibbs return(CAM_REQ_CMP); 44676babe50SJustin T. Gibbs } 44776babe50SJustin T. Gibbs 44876babe50SJustin T. Gibbs static int 44989c9c53dSPoul-Henning Kamp passopen(struct cdev *dev, int flags, int fmt, struct thread *td) 45076babe50SJustin T. Gibbs { 45176babe50SJustin T. Gibbs struct cam_periph *periph; 45276babe50SJustin T. Gibbs struct pass_softc *softc; 453e2a5fdf9SNate Lawson int error; 45476babe50SJustin T. Gibbs 455e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 4562b83592fSScott Long if (cam_periph_acquire(periph) != CAM_REQ_CMP) 45776babe50SJustin T. Gibbs return (ENXIO); 45876babe50SJustin T. Gibbs 4592b83592fSScott Long cam_periph_lock(periph); 4602b83592fSScott Long 46176babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 46276babe50SJustin T. Gibbs 463ee9c90c7SKenneth D. Merry if (softc->flags & PASS_FLAG_INVALID) { 464c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 4652b83592fSScott Long cam_periph_unlock(periph); 46676babe50SJustin T. Gibbs return(ENXIO); 467ee9c90c7SKenneth D. Merry } 46822b9c86cSKenneth D. Merry 46922b9c86cSKenneth D. Merry /* 470f5ef42beSRobert Watson * Don't allow access when we're running at a high securelevel. 47122b9c86cSKenneth D. Merry */ 472a854ed98SJohn Baldwin error = securelevel_gt(td->td_ucred, 1); 473f7312ca2SRobert Watson if (error) { 474c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 4752b83592fSScott Long cam_periph_unlock(periph); 476f7312ca2SRobert Watson return(error); 47722b9c86cSKenneth D. Merry } 47876babe50SJustin T. Gibbs 47976babe50SJustin T. Gibbs /* 48066a0780eSKenneth D. Merry * Only allow read-write access. 48166a0780eSKenneth D. Merry */ 48222b9c86cSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) { 483c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 4842b83592fSScott Long cam_periph_unlock(periph); 48566a0780eSKenneth D. Merry return(EPERM); 48622b9c86cSKenneth D. Merry } 48766a0780eSKenneth D. Merry 48866a0780eSKenneth D. Merry /* 48976babe50SJustin T. Gibbs * We don't allow nonblocking access. 49076babe50SJustin T. Gibbs */ 49176babe50SJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 492f0d9af51SMatt Jacob xpt_print(periph->path, "can't do nonblocking access\n"); 493c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 4942b83592fSScott Long cam_periph_unlock(periph); 49522b9c86cSKenneth D. Merry return(EINVAL); 49676babe50SJustin T. Gibbs } 49776babe50SJustin T. Gibbs 49886d45c7fSKenneth D. Merry softc->open_count++; 49986d45c7fSKenneth D. Merry 500835187bfSScott Long cam_periph_unlock(periph); 50176babe50SJustin T. Gibbs 50276babe50SJustin T. Gibbs return (error); 50376babe50SJustin T. Gibbs } 50476babe50SJustin T. Gibbs 50576babe50SJustin T. Gibbs static int 50689c9c53dSPoul-Henning Kamp passclose(struct cdev *dev, int flag, int fmt, struct thread *td) 50776babe50SJustin T. Gibbs { 50886d45c7fSKenneth D. Merry struct cam_sim *sim; 50976babe50SJustin T. Gibbs struct cam_periph *periph; 51086d45c7fSKenneth D. Merry struct pass_softc *softc; 51176babe50SJustin T. Gibbs 512e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 51376babe50SJustin T. Gibbs if (periph == NULL) 51476babe50SJustin T. Gibbs return (ENXIO); 51576babe50SJustin T. Gibbs 51686d45c7fSKenneth D. Merry sim = periph->sim; 51786d45c7fSKenneth D. Merry softc = periph->softc; 51886d45c7fSKenneth D. Merry 51986d45c7fSKenneth D. Merry mtx_lock(sim->mtx); 52086d45c7fSKenneth D. Merry 52186d45c7fSKenneth D. Merry softc->open_count--; 52286d45c7fSKenneth D. Merry 52386d45c7fSKenneth D. Merry cam_periph_release_locked(periph); 52486d45c7fSKenneth D. Merry 52586d45c7fSKenneth D. Merry /* 52686d45c7fSKenneth D. Merry * We reference the SIM lock directly here, instead of using 52786d45c7fSKenneth D. Merry * cam_periph_unlock(). The reason is that the call to 52886d45c7fSKenneth D. Merry * cam_periph_release_locked() above could result in the periph 52986d45c7fSKenneth D. Merry * getting freed. If that is the case, dereferencing the periph 53086d45c7fSKenneth D. Merry * with a cam_periph_unlock() call would cause a page fault. 53186d45c7fSKenneth D. Merry * 53286d45c7fSKenneth D. Merry * cam_periph_release() avoids this problem using the same method, 53386d45c7fSKenneth D. Merry * but we're manually acquiring and dropping the lock here to 53486d45c7fSKenneth D. Merry * protect the open count and avoid another lock acquisition and 53586d45c7fSKenneth D. Merry * release. 53686d45c7fSKenneth D. Merry */ 53786d45c7fSKenneth D. Merry mtx_unlock(sim->mtx); 53876babe50SJustin T. Gibbs 53976babe50SJustin T. Gibbs return (0); 54076babe50SJustin T. Gibbs } 54176babe50SJustin T. Gibbs 54276babe50SJustin T. Gibbs static void 54376babe50SJustin T. Gibbs passstart(struct cam_periph *periph, union ccb *start_ccb) 54476babe50SJustin T. Gibbs { 54576babe50SJustin T. Gibbs struct pass_softc *softc; 54676babe50SJustin T. Gibbs 54776babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 54876babe50SJustin T. Gibbs 54976babe50SJustin T. Gibbs switch (softc->state) { 55076babe50SJustin T. Gibbs case PASS_STATE_NORMAL: 55176babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; 55276babe50SJustin T. Gibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 55376babe50SJustin T. Gibbs periph_links.sle); 55476babe50SJustin T. Gibbs periph->immediate_priority = CAM_PRIORITY_NONE; 55576babe50SJustin T. Gibbs wakeup(&periph->ccb_list); 55676babe50SJustin T. Gibbs break; 55776babe50SJustin T. Gibbs } 55876babe50SJustin T. Gibbs } 5593393f8daSKenneth D. Merry 56076babe50SJustin T. Gibbs static void 56176babe50SJustin T. Gibbs passdone(struct cam_periph *periph, union ccb *done_ccb) 56276babe50SJustin T. Gibbs { 56376babe50SJustin T. Gibbs struct pass_softc *softc; 56476babe50SJustin T. Gibbs struct ccb_scsiio *csio; 56576babe50SJustin T. Gibbs 56676babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 56776babe50SJustin T. Gibbs csio = &done_ccb->csio; 56876babe50SJustin T. Gibbs switch (csio->ccb_h.ccb_type) { 56976babe50SJustin T. Gibbs case PASS_CCB_WAITING: 57076babe50SJustin T. Gibbs /* Caller will release the CCB */ 57176babe50SJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 57276babe50SJustin T. Gibbs return; 57376babe50SJustin T. Gibbs } 57476babe50SJustin T. Gibbs xpt_release_ccb(done_ccb); 57576babe50SJustin T. Gibbs } 57676babe50SJustin T. Gibbs 57776babe50SJustin T. Gibbs static int 57889c9c53dSPoul-Henning Kamp passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 57976babe50SJustin T. Gibbs { 58025a2902cSScott Long int error; 58125a2902cSScott Long 58225a2902cSScott Long if ((error = passdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) { 583*f564de00SScott Long error = cam_compat_ioctl(dev, cmd, addr, flag, td, passdoioctl); 58425a2902cSScott Long } 58525a2902cSScott Long return (error); 58625a2902cSScott Long } 58725a2902cSScott Long 58825a2902cSScott Long static int 58925a2902cSScott Long passdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 59025a2902cSScott Long { 59176babe50SJustin T. Gibbs struct cam_periph *periph; 59276babe50SJustin T. Gibbs struct pass_softc *softc; 59376babe50SJustin T. Gibbs int error; 5948cff7eb8SAlexander Motin uint32_t priority; 59576babe50SJustin T. Gibbs 596e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 59776babe50SJustin T. Gibbs if (periph == NULL) 59876babe50SJustin T. Gibbs return(ENXIO); 59976babe50SJustin T. Gibbs 6002b83592fSScott Long cam_periph_lock(periph); 60176babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 60276babe50SJustin T. Gibbs 60376babe50SJustin T. Gibbs error = 0; 60476babe50SJustin T. Gibbs 60576babe50SJustin T. Gibbs switch (cmd) { 60676babe50SJustin T. Gibbs 60776babe50SJustin T. Gibbs case CAMIOCOMMAND: 60876babe50SJustin T. Gibbs { 60976babe50SJustin T. Gibbs union ccb *inccb; 61076babe50SJustin T. Gibbs union ccb *ccb; 6119deea857SKenneth D. Merry int ccb_malloced; 61276babe50SJustin T. Gibbs 61376babe50SJustin T. Gibbs inccb = (union ccb *)addr; 6149deea857SKenneth D. Merry 6159deea857SKenneth D. Merry /* 6169deea857SKenneth D. Merry * Some CCB types, like scan bus and scan lun can only go 6179deea857SKenneth D. Merry * through the transport layer device. 6189deea857SKenneth D. Merry */ 6199deea857SKenneth D. Merry if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 620f0d9af51SMatt Jacob xpt_print(periph->path, "CCB function code %#x is " 621f0d9af51SMatt Jacob "restricted to the XPT device\n", 622f0d9af51SMatt Jacob inccb->ccb_h.func_code); 6239deea857SKenneth D. Merry error = ENODEV; 6249deea857SKenneth D. Merry break; 6259deea857SKenneth D. Merry } 6269deea857SKenneth D. Merry 6278cff7eb8SAlexander Motin /* Compatibility for RL/priority-unaware code. */ 6288cff7eb8SAlexander Motin priority = inccb->ccb_h.pinfo.priority; 629cccf4220SAlexander Motin if (priority <= CAM_PRIORITY_OOB) 630cccf4220SAlexander Motin priority += CAM_PRIORITY_OOB + 1; 6318cff7eb8SAlexander Motin 6329deea857SKenneth D. Merry /* 6339deea857SKenneth D. Merry * Non-immediate CCBs need a CCB from the per-device pool 6349deea857SKenneth D. Merry * of CCBs, which is scheduled by the transport layer. 6359deea857SKenneth D. Merry * Immediate CCBs and user-supplied CCBs should just be 6369deea857SKenneth D. Merry * malloced. 6379deea857SKenneth D. Merry */ 6389deea857SKenneth D. Merry if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 6399deea857SKenneth D. Merry && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 6408cff7eb8SAlexander Motin ccb = cam_periph_getccb(periph, priority); 6419deea857SKenneth D. Merry ccb_malloced = 0; 6429deea857SKenneth D. Merry } else { 6438008a935SScott Long ccb = xpt_alloc_ccb_nowait(); 6449deea857SKenneth D. Merry 6459deea857SKenneth D. Merry if (ccb != NULL) 6469deea857SKenneth D. Merry xpt_setup_ccb(&ccb->ccb_h, periph->path, 6478cff7eb8SAlexander Motin priority); 6489deea857SKenneth D. Merry ccb_malloced = 1; 6499deea857SKenneth D. Merry } 6509deea857SKenneth D. Merry 6519deea857SKenneth D. Merry if (ccb == NULL) { 652f0d9af51SMatt Jacob xpt_print(periph->path, "unable to allocate CCB\n"); 6539deea857SKenneth D. Merry error = ENOMEM; 6549deea857SKenneth D. Merry break; 6559deea857SKenneth D. Merry } 65676babe50SJustin T. Gibbs 65776babe50SJustin T. Gibbs error = passsendccb(periph, ccb, inccb); 65876babe50SJustin T. Gibbs 6599deea857SKenneth D. Merry if (ccb_malloced) 6609deea857SKenneth D. Merry xpt_free_ccb(ccb); 6619deea857SKenneth D. Merry else 66276babe50SJustin T. Gibbs xpt_release_ccb(ccb); 66376babe50SJustin T. Gibbs 66476babe50SJustin T. Gibbs break; 66576babe50SJustin T. Gibbs } 66676babe50SJustin T. Gibbs default: 66776babe50SJustin T. Gibbs error = cam_periph_ioctl(periph, cmd, addr, passerror); 66876babe50SJustin T. Gibbs break; 66976babe50SJustin T. Gibbs } 67076babe50SJustin T. Gibbs 6712b83592fSScott Long cam_periph_unlock(periph); 67276babe50SJustin T. Gibbs return(error); 67376babe50SJustin T. Gibbs } 67476babe50SJustin T. Gibbs 67576babe50SJustin T. Gibbs /* 67676babe50SJustin T. Gibbs * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 67776babe50SJustin T. Gibbs * should be the CCB that is copied in from the user. 67876babe50SJustin T. Gibbs */ 67976babe50SJustin T. Gibbs static int 68076babe50SJustin T. Gibbs passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 68176babe50SJustin T. Gibbs { 68276babe50SJustin T. Gibbs struct pass_softc *softc; 68376babe50SJustin T. Gibbs struct cam_periph_map_info mapinfo; 68495fbded6SScott Long xpt_opcode fc; 68595fbded6SScott Long int error; 68676babe50SJustin T. Gibbs 68776babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 68876babe50SJustin T. Gibbs 68976babe50SJustin T. Gibbs /* 69076babe50SJustin T. Gibbs * There are some fields in the CCB header that need to be 69176babe50SJustin T. Gibbs * preserved, the rest we get from the user. 69276babe50SJustin T. Gibbs */ 69376babe50SJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 69476babe50SJustin T. Gibbs 69576babe50SJustin T. Gibbs /* 69676babe50SJustin T. Gibbs * There's no way for the user to have a completion 69776babe50SJustin T. Gibbs * function, so we put our own completion function in here. 69876babe50SJustin T. Gibbs */ 69976babe50SJustin T. Gibbs ccb->ccb_h.cbfcnp = passdone; 70076babe50SJustin T. Gibbs 70176babe50SJustin T. Gibbs /* 70295fbded6SScott Long * Let cam_periph_mapmem do a sanity check on the data pointer format. 70395fbded6SScott Long * Even if no data transfer is needed, it's a cheap check and it 70495fbded6SScott Long * simplifies the code. 70576babe50SJustin T. Gibbs */ 70695fbded6SScott Long fc = ccb->ccb_h.func_code; 70795fbded6SScott Long if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO) 70895fbded6SScott Long || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO)) { 70976babe50SJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 71076babe50SJustin T. Gibbs 7112b83592fSScott Long /* 7122b83592fSScott Long * cam_periph_mapmem calls into proc and vm functions that can 7132b83592fSScott Long * sleep as well as trigger I/O, so we can't hold the lock. 7142b83592fSScott Long * Dropping it here is reasonably safe. 7152b83592fSScott Long */ 7162b83592fSScott Long cam_periph_unlock(periph); 71776babe50SJustin T. Gibbs error = cam_periph_mapmem(ccb, &mapinfo); 7182b83592fSScott Long cam_periph_lock(periph); 71976babe50SJustin T. Gibbs 72076babe50SJustin T. Gibbs /* 72176babe50SJustin T. Gibbs * cam_periph_mapmem returned an error, we can't continue. 72276babe50SJustin T. Gibbs * Return the error to the user. 72376babe50SJustin T. Gibbs */ 72476babe50SJustin T. Gibbs if (error) 72576babe50SJustin T. Gibbs return(error); 72695fbded6SScott Long } else 72795fbded6SScott Long /* Ensure that the unmap call later on is a no-op. */ 72895fbded6SScott Long mapinfo.num_bufs_used = 0; 72976babe50SJustin T. Gibbs 73076babe50SJustin T. Gibbs /* 73176babe50SJustin T. Gibbs * If the user wants us to perform any error recovery, then honor 73276babe50SJustin T. Gibbs * that request. Otherwise, it's up to the user to perform any 73376babe50SJustin T. Gibbs * error recovery. 73476babe50SJustin T. Gibbs */ 7350191d9b3SAlexander Motin cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO, 7360191d9b3SAlexander Motin /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 7370191d9b3SAlexander Motin SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT, 738a9d2245eSPoul-Henning Kamp softc->device_stats); 73976babe50SJustin T. Gibbs 74076babe50SJustin T. Gibbs cam_periph_unmapmem(ccb, &mapinfo); 74176babe50SJustin T. Gibbs 74276babe50SJustin T. Gibbs ccb->ccb_h.cbfcnp = NULL; 74376babe50SJustin T. Gibbs ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 74476babe50SJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 74576babe50SJustin T. Gibbs 74683c5d981SAlexander Motin return(0); 74776babe50SJustin T. Gibbs } 74876babe50SJustin T. Gibbs 74976babe50SJustin T. Gibbs static int 75076babe50SJustin T. Gibbs passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 75176babe50SJustin T. Gibbs { 75276babe50SJustin T. Gibbs struct cam_periph *periph; 75376babe50SJustin T. Gibbs struct pass_softc *softc; 75476babe50SJustin T. Gibbs 75576babe50SJustin T. Gibbs periph = xpt_path_periph(ccb->ccb_h.path); 75676babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 75776babe50SJustin T. Gibbs 75876babe50SJustin T. Gibbs return(cam_periph_error(ccb, cam_flags, sense_flags, 75976babe50SJustin T. Gibbs &softc->saved_ccb)); 76076babe50SJustin T. Gibbs } 761