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> 5176babe50SJustin T. Gibbs 5276babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h> 5376babe50SJustin T. Gibbs #include <cam/scsi/scsi_pass.h> 5476babe50SJustin T. Gibbs 5576babe50SJustin T. Gibbs typedef enum { 5676babe50SJustin T. Gibbs PASS_FLAG_OPEN = 0x01, 5776babe50SJustin T. Gibbs PASS_FLAG_LOCKED = 0x02, 58ea37f519SKenneth D. Merry PASS_FLAG_INVALID = 0x04, 59ea37f519SKenneth D. Merry PASS_FLAG_INITIAL_PHYSPATH = 0x08 6076babe50SJustin T. Gibbs } pass_flags; 6176babe50SJustin T. Gibbs 6276babe50SJustin T. Gibbs typedef enum { 6376babe50SJustin T. Gibbs PASS_STATE_NORMAL 6476babe50SJustin T. Gibbs } pass_state; 6576babe50SJustin T. Gibbs 6676babe50SJustin T. Gibbs typedef enum { 6776babe50SJustin T. Gibbs PASS_CCB_BUFFER_IO, 6876babe50SJustin T. Gibbs PASS_CCB_WAITING 6976babe50SJustin T. Gibbs } pass_ccb_types; 7076babe50SJustin T. Gibbs 7176babe50SJustin T. Gibbs #define ccb_type ppriv_field0 7276babe50SJustin T. Gibbs #define ccb_bp ppriv_ptr1 7376babe50SJustin T. Gibbs 7476babe50SJustin T. Gibbs struct pass_softc { 7576babe50SJustin T. Gibbs pass_state state; 7676babe50SJustin T. Gibbs pass_flags flags; 7776babe50SJustin T. Gibbs u_int8_t pd_type; 7876babe50SJustin T. Gibbs union ccb saved_ccb; 7986d45c7fSKenneth D. Merry int open_count; 80a9d2245eSPoul-Henning Kamp struct devstat *device_stats; 8189c9c53dSPoul-Henning Kamp struct cdev *dev; 82416494d7SJustin T. Gibbs struct cdev *alias_dev; 83416494d7SJustin T. Gibbs struct task add_physpath_task; 8476babe50SJustin T. Gibbs }; 8576babe50SJustin T. Gibbs 8676babe50SJustin T. Gibbs 8776babe50SJustin T. Gibbs static d_open_t passopen; 8876babe50SJustin T. Gibbs static d_close_t passclose; 8976babe50SJustin T. Gibbs static d_ioctl_t passioctl; 9076babe50SJustin T. Gibbs 9176babe50SJustin T. Gibbs static periph_init_t passinit; 9276babe50SJustin T. Gibbs static periph_ctor_t passregister; 93ee9c90c7SKenneth D. Merry static periph_oninv_t passoninvalidate; 9476babe50SJustin T. Gibbs static periph_dtor_t passcleanup; 9576babe50SJustin T. Gibbs static periph_start_t passstart; 96416494d7SJustin T. Gibbs static void pass_add_physpath(void *context, int pending); 9776babe50SJustin T. Gibbs static void passasync(void *callback_arg, u_int32_t code, 9876babe50SJustin T. Gibbs struct cam_path *path, void *arg); 9976babe50SJustin T. Gibbs static void passdone(struct cam_periph *periph, 10076babe50SJustin T. Gibbs union ccb *done_ccb); 10176babe50SJustin T. Gibbs static int passerror(union ccb *ccb, u_int32_t cam_flags, 10276babe50SJustin T. Gibbs u_int32_t sense_flags); 10376babe50SJustin T. Gibbs static int passsendccb(struct cam_periph *periph, union ccb *ccb, 10476babe50SJustin T. Gibbs union ccb *inccb); 10576babe50SJustin T. Gibbs 10676babe50SJustin T. Gibbs static struct periph_driver passdriver = 10776babe50SJustin T. Gibbs { 10876babe50SJustin T. Gibbs passinit, "pass", 10976babe50SJustin T. Gibbs TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0 11076babe50SJustin T. Gibbs }; 11176babe50SJustin T. Gibbs 1120b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(pass, passdriver); 11376babe50SJustin T. Gibbs 1144e2f199eSPoul-Henning Kamp static struct cdevsw pass_cdevsw = { 115dc08ffecSPoul-Henning Kamp .d_version = D_VERSION, 116c552ebe1SKenneth D. Merry .d_flags = D_TRACKCLOSE, 1177ac40f5fSPoul-Henning Kamp .d_open = passopen, 1187ac40f5fSPoul-Henning Kamp .d_close = passclose, 1197ac40f5fSPoul-Henning Kamp .d_ioctl = passioctl, 1207ac40f5fSPoul-Henning Kamp .d_name = "pass", 12176babe50SJustin T. Gibbs }; 12276babe50SJustin T. Gibbs 12376babe50SJustin T. Gibbs static void 12476babe50SJustin T. Gibbs passinit(void) 12576babe50SJustin T. Gibbs { 12676babe50SJustin T. Gibbs cam_status status; 12776babe50SJustin T. Gibbs 12876babe50SJustin T. Gibbs /* 12976babe50SJustin T. Gibbs * Install a global async callback. This callback will 13076babe50SJustin T. Gibbs * receive async callbacks like "new device found". 13176babe50SJustin T. Gibbs */ 13285d92640SScott Long status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL); 13376babe50SJustin T. Gibbs 13476babe50SJustin T. Gibbs if (status != CAM_REQ_CMP) { 13576babe50SJustin T. Gibbs printf("pass: Failed to attach master async callback " 13676babe50SJustin T. Gibbs "due to status 0x%x!\n", status); 13776babe50SJustin T. Gibbs } 13876babe50SJustin T. Gibbs 13976babe50SJustin T. Gibbs } 14076babe50SJustin T. Gibbs 14176babe50SJustin T. Gibbs static void 142ea37f519SKenneth D. Merry passdevgonecb(void *arg) 143ea37f519SKenneth D. Merry { 14486d45c7fSKenneth D. Merry struct cam_sim *sim; 145ea37f519SKenneth D. Merry struct cam_periph *periph; 14686d45c7fSKenneth D. Merry struct pass_softc *softc; 14786d45c7fSKenneth D. Merry int i; 148ea37f519SKenneth D. Merry 149ea37f519SKenneth D. Merry periph = (struct cam_periph *)arg; 15086d45c7fSKenneth D. Merry sim = periph->sim; 15186d45c7fSKenneth D. Merry softc = (struct pass_softc *)periph->softc; 152ea37f519SKenneth D. Merry 15386d45c7fSKenneth D. Merry KASSERT(softc->open_count >= 0, ("Negative open count %d", 15486d45c7fSKenneth D. Merry softc->open_count)); 15586d45c7fSKenneth D. Merry 15686d45c7fSKenneth D. Merry mtx_lock(sim->mtx); 15786d45c7fSKenneth D. Merry 15886d45c7fSKenneth D. Merry /* 15986d45c7fSKenneth D. Merry * When we get this callback, we will get no more close calls from 16086d45c7fSKenneth D. Merry * devfs. So if we have any dangling opens, we need to release the 16186d45c7fSKenneth D. Merry * reference held for that particular context. 16286d45c7fSKenneth D. Merry */ 16386d45c7fSKenneth D. Merry for (i = 0; i < softc->open_count; i++) 16486d45c7fSKenneth D. Merry cam_periph_release_locked(periph); 16586d45c7fSKenneth D. Merry 16686d45c7fSKenneth D. Merry softc->open_count = 0; 16786d45c7fSKenneth D. Merry 16886d45c7fSKenneth D. Merry /* 16986d45c7fSKenneth D. Merry * Release the reference held for the device node, it is gone now. 17086d45c7fSKenneth D. Merry */ 17186d45c7fSKenneth D. Merry cam_periph_release_locked(periph); 17286d45c7fSKenneth D. Merry 17386d45c7fSKenneth D. Merry /* 17486d45c7fSKenneth D. Merry * We reference the SIM lock directly here, instead of using 17586d45c7fSKenneth D. Merry * cam_periph_unlock(). The reason is that the final call to 17686d45c7fSKenneth D. Merry * cam_periph_release_locked() above could result in the periph 17786d45c7fSKenneth D. Merry * getting freed. If that is the case, dereferencing the periph 17886d45c7fSKenneth D. Merry * with a cam_periph_unlock() call would cause a page fault. 17986d45c7fSKenneth D. Merry */ 18086d45c7fSKenneth D. Merry mtx_unlock(sim->mtx); 181ea37f519SKenneth D. Merry } 182ea37f519SKenneth D. Merry 183ea37f519SKenneth D. Merry static void 184ee9c90c7SKenneth D. Merry passoninvalidate(struct cam_periph *periph) 185ee9c90c7SKenneth D. Merry { 186ee9c90c7SKenneth D. Merry struct pass_softc *softc; 187ee9c90c7SKenneth D. Merry 188ee9c90c7SKenneth D. Merry softc = (struct pass_softc *)periph->softc; 189ee9c90c7SKenneth D. Merry 190ee9c90c7SKenneth D. Merry /* 191ee9c90c7SKenneth D. Merry * De-register any async callbacks. 192ee9c90c7SKenneth D. Merry */ 19385d92640SScott Long xpt_register_async(0, passasync, periph, periph->path); 194ee9c90c7SKenneth D. Merry 195ee9c90c7SKenneth D. Merry softc->flags |= PASS_FLAG_INVALID; 196ee9c90c7SKenneth D. Merry 197ee9c90c7SKenneth D. Merry /* 198ea37f519SKenneth D. Merry * Tell devfs this device has gone away, and ask for a callback 199ea37f519SKenneth D. Merry * when it has cleaned up its state. 200ea37f519SKenneth D. Merry */ 201ea37f519SKenneth D. Merry destroy_dev_sched_cb(softc->dev, passdevgonecb, periph); 202ea37f519SKenneth D. Merry 203ea37f519SKenneth D. Merry /* 2043393f8daSKenneth D. Merry * XXX Return all queued I/O with ENXIO. 205ee9c90c7SKenneth D. Merry * XXX Handle any transactions queued to the card 206ee9c90c7SKenneth D. Merry * with XPT_ABORT_CCB. 207ee9c90c7SKenneth D. Merry */ 208ee9c90c7SKenneth D. Merry 209ee9c90c7SKenneth D. Merry if (bootverbose) { 210f0d9af51SMatt Jacob xpt_print(periph->path, "lost device\n"); 211ee9c90c7SKenneth D. Merry } 212ee9c90c7SKenneth D. Merry 213ee9c90c7SKenneth D. Merry } 214ee9c90c7SKenneth D. Merry 215ee9c90c7SKenneth D. Merry static void 21676babe50SJustin T. Gibbs passcleanup(struct cam_periph *periph) 21776babe50SJustin T. Gibbs { 218ee9c90c7SKenneth D. Merry struct pass_softc *softc; 219ee9c90c7SKenneth D. Merry 220ee9c90c7SKenneth D. Merry softc = (struct pass_softc *)periph->softc; 221ee9c90c7SKenneth D. Merry 2225f3fed85SEdward Tomasz Napierala if (bootverbose) 223f0d9af51SMatt Jacob xpt_print(periph->path, "removing device entry\n"); 2245f3fed85SEdward Tomasz Napierala devstat_remove_entry(softc->device_stats); 225416494d7SJustin T. Gibbs 2265f3fed85SEdward Tomasz Napierala cam_periph_unlock(periph); 227416494d7SJustin T. Gibbs taskqueue_drain(taskqueue_thread, &softc->add_physpath_task); 228416494d7SJustin T. Gibbs 2295f3fed85SEdward Tomasz Napierala cam_periph_lock(periph); 230416494d7SJustin T. Gibbs 231ee9c90c7SKenneth D. Merry free(softc, M_DEVBUF); 23276babe50SJustin T. Gibbs } 23376babe50SJustin T. Gibbs 23476babe50SJustin T. Gibbs static void 235416494d7SJustin T. Gibbs pass_add_physpath(void *context, int pending) 236416494d7SJustin T. Gibbs { 237416494d7SJustin T. Gibbs struct cam_periph *periph; 238416494d7SJustin T. Gibbs struct pass_softc *softc; 239416494d7SJustin T. Gibbs char *physpath; 240416494d7SJustin T. Gibbs 241416494d7SJustin T. Gibbs /* 242416494d7SJustin T. Gibbs * If we have one, create a devfs alias for our 243416494d7SJustin T. Gibbs * physical path. 244416494d7SJustin T. Gibbs */ 245416494d7SJustin T. Gibbs periph = context; 246416494d7SJustin T. Gibbs softc = periph->softc; 2476884b662SAlexander Motin physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK); 248ea37f519SKenneth D. Merry cam_periph_lock(periph); 249ea37f519SKenneth D. Merry if (periph->flags & CAM_PERIPH_INVALID) { 250ea37f519SKenneth D. Merry cam_periph_unlock(periph); 2516884b662SAlexander Motin goto out; 252ea37f519SKenneth D. Merry } 253416494d7SJustin T. Gibbs if (xpt_getattr(physpath, MAXPATHLEN, 254416494d7SJustin T. Gibbs "GEOM::physpath", periph->path) == 0 255416494d7SJustin T. Gibbs && strlen(physpath) != 0) { 256416494d7SJustin T. Gibbs 2576884b662SAlexander Motin cam_periph_unlock(periph); 258416494d7SJustin T. Gibbs make_dev_physpath_alias(MAKEDEV_WAITOK, &softc->alias_dev, 259416494d7SJustin T. Gibbs softc->dev, softc->alias_dev, physpath); 2606884b662SAlexander Motin cam_periph_lock(periph); 261416494d7SJustin T. Gibbs } 262ea37f519SKenneth D. Merry 263ea37f519SKenneth D. Merry /* 264ea37f519SKenneth D. Merry * Now that we've made our alias, we no longer have to have a 265ea37f519SKenneth D. Merry * reference to the device. 266ea37f519SKenneth D. Merry */ 267ea37f519SKenneth D. Merry if ((softc->flags & PASS_FLAG_INITIAL_PHYSPATH) == 0) { 268ea37f519SKenneth D. Merry softc->flags |= PASS_FLAG_INITIAL_PHYSPATH; 269ea37f519SKenneth D. Merry cam_periph_unlock(periph); 270ea37f519SKenneth D. Merry dev_rel(softc->dev); 271ea37f519SKenneth D. Merry } 272ea37f519SKenneth D. Merry else 273ea37f519SKenneth D. Merry cam_periph_unlock(periph); 2746884b662SAlexander Motin 2756884b662SAlexander Motin out: 2766884b662SAlexander Motin free(physpath, M_DEVBUF); 277416494d7SJustin T. Gibbs } 278416494d7SJustin T. Gibbs 279416494d7SJustin T. Gibbs static void 28076babe50SJustin T. Gibbs passasync(void *callback_arg, u_int32_t code, 28176babe50SJustin T. Gibbs struct cam_path *path, void *arg) 28276babe50SJustin T. Gibbs { 28376babe50SJustin T. Gibbs struct cam_periph *periph; 28476babe50SJustin T. Gibbs 28576babe50SJustin T. Gibbs periph = (struct cam_periph *)callback_arg; 28676babe50SJustin T. Gibbs 28776babe50SJustin T. Gibbs switch (code) { 28876babe50SJustin T. Gibbs case AC_FOUND_DEVICE: 28976babe50SJustin T. Gibbs { 29076babe50SJustin T. Gibbs struct ccb_getdev *cgd; 29176babe50SJustin T. Gibbs cam_status status; 29276babe50SJustin T. Gibbs 29376babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 294c5ff3b2fSMatt Jacob if (cgd == NULL) 295c5ff3b2fSMatt Jacob break; 29676babe50SJustin T. Gibbs 29776babe50SJustin T. Gibbs /* 29876babe50SJustin T. Gibbs * Allocate a peripheral instance for 29976babe50SJustin T. Gibbs * this device and start the probe 30076babe50SJustin T. Gibbs * process. 30176babe50SJustin T. Gibbs */ 302ee9c90c7SKenneth D. Merry status = cam_periph_alloc(passregister, passoninvalidate, 303ee9c90c7SKenneth D. Merry passcleanup, passstart, "pass", 304ee9c90c7SKenneth D. Merry CAM_PERIPH_BIO, cgd->ccb_h.path, 305ee9c90c7SKenneth D. Merry passasync, AC_FOUND_DEVICE, cgd); 30676babe50SJustin T. Gibbs 30776babe50SJustin T. Gibbs if (status != CAM_REQ_CMP 3083393f8daSKenneth D. Merry && status != CAM_REQ_INPROG) { 3093393f8daSKenneth D. Merry const struct cam_status_entry *entry; 3103393f8daSKenneth D. Merry 3113393f8daSKenneth D. Merry entry = cam_fetch_status_entry(status); 3123393f8daSKenneth D. Merry 31376babe50SJustin T. Gibbs printf("passasync: Unable to attach new device " 3143393f8daSKenneth D. Merry "due to status %#x: %s\n", status, entry ? 3153393f8daSKenneth D. Merry entry->status_text : "Unknown"); 3163393f8daSKenneth D. Merry } 31776babe50SJustin T. Gibbs 31876babe50SJustin T. Gibbs break; 31976babe50SJustin T. Gibbs } 320416494d7SJustin T. Gibbs case AC_ADVINFO_CHANGED: 321416494d7SJustin T. Gibbs { 322416494d7SJustin T. Gibbs uintptr_t buftype; 323416494d7SJustin T. Gibbs 324416494d7SJustin T. Gibbs buftype = (uintptr_t)arg; 325416494d7SJustin T. Gibbs if (buftype == CDAI_TYPE_PHYS_PATH) { 326416494d7SJustin T. Gibbs struct pass_softc *softc; 327416494d7SJustin T. Gibbs 328416494d7SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 329416494d7SJustin T. Gibbs taskqueue_enqueue(taskqueue_thread, 330416494d7SJustin T. Gibbs &softc->add_physpath_task); 331416494d7SJustin T. Gibbs } 332416494d7SJustin T. Gibbs break; 333416494d7SJustin T. Gibbs } 33476babe50SJustin T. Gibbs default: 335516871c6SJustin T. Gibbs cam_periph_async(periph, code, path, arg); 33676babe50SJustin T. Gibbs break; 33776babe50SJustin T. Gibbs } 33876babe50SJustin T. Gibbs } 33976babe50SJustin T. Gibbs 34076babe50SJustin T. Gibbs static cam_status 34176babe50SJustin T. Gibbs passregister(struct cam_periph *periph, void *arg) 34276babe50SJustin T. Gibbs { 34376babe50SJustin T. Gibbs struct pass_softc *softc; 34476babe50SJustin T. Gibbs struct ccb_getdev *cgd; 345b8b6b5d3SAlexander Motin struct ccb_pathinq cpi; 3463393f8daSKenneth D. Merry int no_tags; 34776babe50SJustin T. Gibbs 34876babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg; 34976babe50SJustin T. Gibbs if (cgd == NULL) { 350ea37f519SKenneth D. Merry printf("%s: no getdev CCB, can't register device\n", __func__); 35176babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 35276babe50SJustin T. Gibbs } 35376babe50SJustin T. Gibbs 35476babe50SJustin T. Gibbs softc = (struct pass_softc *)malloc(sizeof(*softc), 35576babe50SJustin T. Gibbs M_DEVBUF, M_NOWAIT); 35676babe50SJustin T. Gibbs 35776babe50SJustin T. Gibbs if (softc == NULL) { 358ea37f519SKenneth D. Merry printf("%s: Unable to probe new device. " 359ea37f519SKenneth D. Merry "Unable to allocate softc\n", __func__); 36076babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR); 36176babe50SJustin T. Gibbs } 36276babe50SJustin T. Gibbs 36376babe50SJustin T. Gibbs bzero(softc, sizeof(*softc)); 36476babe50SJustin T. Gibbs softc->state = PASS_STATE_NORMAL; 365b8b6b5d3SAlexander Motin if (cgd->protocol == PROTO_SCSI || cgd->protocol == PROTO_ATAPI) 36610b6172aSMatt Jacob softc->pd_type = SID_TYPE(&cgd->inq_data); 367b8b6b5d3SAlexander Motin else if (cgd->protocol == PROTO_SATAPM) 368b8b6b5d3SAlexander Motin softc->pd_type = T_ENCLOSURE; 369b8b6b5d3SAlexander Motin else 370b8b6b5d3SAlexander Motin softc->pd_type = T_DIRECT; 37176babe50SJustin T. Gibbs 37276babe50SJustin T. Gibbs periph->softc = softc; 3733393f8daSKenneth D. Merry 374b8b6b5d3SAlexander Motin bzero(&cpi, sizeof(cpi)); 375b8b6b5d3SAlexander Motin xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 376b8b6b5d3SAlexander Motin cpi.ccb_h.func_code = XPT_PATH_INQ; 377b8b6b5d3SAlexander Motin xpt_action((union ccb *)&cpi); 378b8b6b5d3SAlexander Motin 37976babe50SJustin T. Gibbs /* 38076babe50SJustin T. Gibbs * We pass in 0 for a blocksize, since we don't 38176babe50SJustin T. Gibbs * know what the blocksize of this device is, if 38276babe50SJustin T. Gibbs * it even has a blocksize. 38376babe50SJustin T. Gibbs */ 384edec59d9SAlexander Motin cam_periph_unlock(periph); 3853393f8daSKenneth D. Merry no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0; 386c81d2c74SMatt Jacob softc->device_stats = devstat_new_entry("pass", 387d3ce8327SEd Schouten periph->unit_number, 0, 3883393f8daSKenneth D. Merry DEVSTAT_NO_BLOCKSIZE 3893393f8daSKenneth D. Merry | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0), 39010b6172aSMatt Jacob softc->pd_type | 391b8b6b5d3SAlexander Motin XPORT_DEVSTAT_TYPE(cpi.transport) | 3922a888f93SKenneth D. Merry DEVSTAT_TYPE_PASS, 3932a888f93SKenneth D. Merry DEVSTAT_PRIORITY_PASS); 39473d26919SKenneth D. Merry 395ea37f519SKenneth D. Merry /* 396ea37f519SKenneth D. Merry * Acquire a reference to the periph before we create the devfs 397ea37f519SKenneth D. Merry * instance for it. We'll release this reference once the devfs 398ea37f519SKenneth D. Merry * instance has been freed. 399ea37f519SKenneth D. Merry */ 400ea37f519SKenneth D. Merry if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 401ea37f519SKenneth D. Merry xpt_print(periph->path, "%s: lost periph during " 402ea37f519SKenneth D. Merry "registration!\n", __func__); 40386d45c7fSKenneth D. Merry cam_periph_lock(periph); 404ea37f519SKenneth D. Merry return (CAM_REQ_CMP_ERR); 405ea37f519SKenneth D. Merry } 406ea37f519SKenneth D. Merry 40773d26919SKenneth D. Merry /* Register the device */ 408d3ce8327SEd Schouten softc->dev = make_dev(&pass_cdevsw, periph->unit_number, 409c81d2c74SMatt Jacob UID_ROOT, GID_OPERATOR, 0600, "%s%d", 410c81d2c74SMatt Jacob periph->periph_name, periph->unit_number); 411ea37f519SKenneth D. Merry 412ea37f519SKenneth D. Merry /* 413ea37f519SKenneth D. Merry * Now that we have made the devfs instance, hold a reference to it 414ea37f519SKenneth D. Merry * until the task queue has run to setup the physical path alias. 415ea37f519SKenneth D. Merry * That way devfs won't get rid of the device before we add our 416ea37f519SKenneth D. Merry * alias. 417ea37f519SKenneth D. Merry */ 418ea37f519SKenneth D. Merry dev_ref(softc->dev); 419ea37f519SKenneth D. Merry 420edec59d9SAlexander Motin cam_periph_lock(periph); 421e2a5fdf9SNate Lawson softc->dev->si_drv1 = periph; 42273d26919SKenneth D. Merry 423416494d7SJustin T. Gibbs TASK_INIT(&softc->add_physpath_task, /*priority*/0, 424416494d7SJustin T. Gibbs pass_add_physpath, periph); 425416494d7SJustin T. Gibbs 42676babe50SJustin T. Gibbs /* 427416494d7SJustin T. Gibbs * See if physical path information is already available. 42876babe50SJustin T. Gibbs */ 429416494d7SJustin T. Gibbs taskqueue_enqueue(taskqueue_thread, &softc->add_physpath_task); 430416494d7SJustin T. Gibbs 431416494d7SJustin T. Gibbs /* 432416494d7SJustin T. Gibbs * Add an async callback so that we get notified if 433416494d7SJustin T. Gibbs * this device goes away or its physical path 434416494d7SJustin T. Gibbs * (stored in the advanced info data of the EDT) has 435416494d7SJustin T. Gibbs * changed. 436416494d7SJustin T. Gibbs */ 437416494d7SJustin T. Gibbs xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED, 438416494d7SJustin T. Gibbs passasync, periph, periph->path); 43976babe50SJustin T. Gibbs 44076babe50SJustin T. Gibbs if (bootverbose) 44176babe50SJustin T. Gibbs xpt_announce_periph(periph, NULL); 44276babe50SJustin T. Gibbs 44376babe50SJustin T. Gibbs return(CAM_REQ_CMP); 44476babe50SJustin T. Gibbs } 44576babe50SJustin T. Gibbs 44676babe50SJustin T. Gibbs static int 44789c9c53dSPoul-Henning Kamp passopen(struct cdev *dev, int flags, int fmt, struct thread *td) 44876babe50SJustin T. Gibbs { 44976babe50SJustin T. Gibbs struct cam_periph *periph; 45076babe50SJustin T. Gibbs struct pass_softc *softc; 451e2a5fdf9SNate Lawson int error; 45276babe50SJustin T. Gibbs 453e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 4542b83592fSScott Long if (cam_periph_acquire(periph) != CAM_REQ_CMP) 45576babe50SJustin T. Gibbs return (ENXIO); 45676babe50SJustin T. Gibbs 4572b83592fSScott Long cam_periph_lock(periph); 4582b83592fSScott Long 45976babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 46076babe50SJustin T. Gibbs 461ee9c90c7SKenneth D. Merry if (softc->flags & PASS_FLAG_INVALID) { 462c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 4632b83592fSScott Long cam_periph_unlock(periph); 46476babe50SJustin T. Gibbs return(ENXIO); 465ee9c90c7SKenneth D. Merry } 46622b9c86cSKenneth D. Merry 46722b9c86cSKenneth D. Merry /* 468f5ef42beSRobert Watson * Don't allow access when we're running at a high securelevel. 46922b9c86cSKenneth D. Merry */ 470a854ed98SJohn Baldwin error = securelevel_gt(td->td_ucred, 1); 471f7312ca2SRobert Watson if (error) { 472c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 4732b83592fSScott Long cam_periph_unlock(periph); 474f7312ca2SRobert Watson return(error); 47522b9c86cSKenneth D. Merry } 47676babe50SJustin T. Gibbs 47776babe50SJustin T. Gibbs /* 47866a0780eSKenneth D. Merry * Only allow read-write access. 47966a0780eSKenneth D. Merry */ 48022b9c86cSKenneth D. Merry if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) { 481c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 4822b83592fSScott Long cam_periph_unlock(periph); 48366a0780eSKenneth D. Merry return(EPERM); 48422b9c86cSKenneth D. Merry } 48566a0780eSKenneth D. Merry 48666a0780eSKenneth D. Merry /* 48776babe50SJustin T. Gibbs * We don't allow nonblocking access. 48876babe50SJustin T. Gibbs */ 48976babe50SJustin T. Gibbs if ((flags & O_NONBLOCK) != 0) { 490f0d9af51SMatt Jacob xpt_print(periph->path, "can't do nonblocking access\n"); 491c552ebe1SKenneth D. Merry cam_periph_release_locked(periph); 4922b83592fSScott Long cam_periph_unlock(periph); 49322b9c86cSKenneth D. Merry return(EINVAL); 49476babe50SJustin T. Gibbs } 49576babe50SJustin T. Gibbs 49686d45c7fSKenneth D. Merry softc->open_count++; 49786d45c7fSKenneth D. Merry 498835187bfSScott Long cam_periph_unlock(periph); 49976babe50SJustin T. Gibbs 50076babe50SJustin T. Gibbs return (error); 50176babe50SJustin T. Gibbs } 50276babe50SJustin T. Gibbs 50376babe50SJustin T. Gibbs static int 50489c9c53dSPoul-Henning Kamp passclose(struct cdev *dev, int flag, int fmt, struct thread *td) 50576babe50SJustin T. Gibbs { 50686d45c7fSKenneth D. Merry struct cam_sim *sim; 50776babe50SJustin T. Gibbs struct cam_periph *periph; 50886d45c7fSKenneth D. Merry struct pass_softc *softc; 50976babe50SJustin T. Gibbs 510e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 51176babe50SJustin T. Gibbs if (periph == NULL) 51276babe50SJustin T. Gibbs return (ENXIO); 51376babe50SJustin T. Gibbs 51486d45c7fSKenneth D. Merry sim = periph->sim; 51586d45c7fSKenneth D. Merry softc = periph->softc; 51686d45c7fSKenneth D. Merry 51786d45c7fSKenneth D. Merry mtx_lock(sim->mtx); 51886d45c7fSKenneth D. Merry 51986d45c7fSKenneth D. Merry softc->open_count--; 52086d45c7fSKenneth D. Merry 52186d45c7fSKenneth D. Merry cam_periph_release_locked(periph); 52286d45c7fSKenneth D. Merry 52386d45c7fSKenneth D. Merry /* 52486d45c7fSKenneth D. Merry * We reference the SIM lock directly here, instead of using 52586d45c7fSKenneth D. Merry * cam_periph_unlock(). The reason is that the call to 52686d45c7fSKenneth D. Merry * cam_periph_release_locked() above could result in the periph 52786d45c7fSKenneth D. Merry * getting freed. If that is the case, dereferencing the periph 52886d45c7fSKenneth D. Merry * with a cam_periph_unlock() call would cause a page fault. 52986d45c7fSKenneth D. Merry * 53086d45c7fSKenneth D. Merry * cam_periph_release() avoids this problem using the same method, 53186d45c7fSKenneth D. Merry * but we're manually acquiring and dropping the lock here to 53286d45c7fSKenneth D. Merry * protect the open count and avoid another lock acquisition and 53386d45c7fSKenneth D. Merry * release. 53486d45c7fSKenneth D. Merry */ 53586d45c7fSKenneth D. Merry mtx_unlock(sim->mtx); 53676babe50SJustin T. Gibbs 53776babe50SJustin T. Gibbs return (0); 53876babe50SJustin T. Gibbs } 53976babe50SJustin T. Gibbs 54076babe50SJustin T. Gibbs static void 54176babe50SJustin T. Gibbs passstart(struct cam_periph *periph, union ccb *start_ccb) 54276babe50SJustin T. Gibbs { 54376babe50SJustin T. Gibbs struct pass_softc *softc; 54476babe50SJustin T. Gibbs 54576babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 54676babe50SJustin T. Gibbs 54776babe50SJustin T. Gibbs switch (softc->state) { 54876babe50SJustin T. Gibbs case PASS_STATE_NORMAL: 54976babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_type = PASS_CCB_WAITING; 55076babe50SJustin T. Gibbs SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 55176babe50SJustin T. Gibbs periph_links.sle); 55276babe50SJustin T. Gibbs periph->immediate_priority = CAM_PRIORITY_NONE; 55376babe50SJustin T. Gibbs wakeup(&periph->ccb_list); 55476babe50SJustin T. Gibbs break; 55576babe50SJustin T. Gibbs } 55676babe50SJustin T. Gibbs } 5573393f8daSKenneth D. Merry 55876babe50SJustin T. Gibbs static void 55976babe50SJustin T. Gibbs passdone(struct cam_periph *periph, union ccb *done_ccb) 56076babe50SJustin T. Gibbs { 56176babe50SJustin T. Gibbs struct pass_softc *softc; 56276babe50SJustin T. Gibbs struct ccb_scsiio *csio; 56376babe50SJustin T. Gibbs 56476babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 56576babe50SJustin T. Gibbs csio = &done_ccb->csio; 56676babe50SJustin T. Gibbs switch (csio->ccb_h.ccb_type) { 56776babe50SJustin T. Gibbs case PASS_CCB_WAITING: 56876babe50SJustin T. Gibbs /* Caller will release the CCB */ 56976babe50SJustin T. Gibbs wakeup(&done_ccb->ccb_h.cbfcnp); 57076babe50SJustin T. Gibbs return; 57176babe50SJustin T. Gibbs } 57276babe50SJustin T. Gibbs xpt_release_ccb(done_ccb); 57376babe50SJustin T. Gibbs } 57476babe50SJustin T. Gibbs 57576babe50SJustin T. Gibbs static int 57689c9c53dSPoul-Henning Kamp passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 57776babe50SJustin T. Gibbs { 57876babe50SJustin T. Gibbs struct cam_periph *periph; 57976babe50SJustin T. Gibbs struct pass_softc *softc; 58076babe50SJustin T. Gibbs int error; 5818cff7eb8SAlexander Motin uint32_t priority; 58276babe50SJustin T. Gibbs 583e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1; 58476babe50SJustin T. Gibbs if (periph == NULL) 58576babe50SJustin T. Gibbs return(ENXIO); 58676babe50SJustin T. Gibbs 5872b83592fSScott Long cam_periph_lock(periph); 58876babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 58976babe50SJustin T. Gibbs 59076babe50SJustin T. Gibbs error = 0; 59176babe50SJustin T. Gibbs 59276babe50SJustin T. Gibbs switch (cmd) { 59376babe50SJustin T. Gibbs 59476babe50SJustin T. Gibbs case CAMIOCOMMAND: 59576babe50SJustin T. Gibbs { 59676babe50SJustin T. Gibbs union ccb *inccb; 59776babe50SJustin T. Gibbs union ccb *ccb; 5989deea857SKenneth D. Merry int ccb_malloced; 59976babe50SJustin T. Gibbs 60076babe50SJustin T. Gibbs inccb = (union ccb *)addr; 6019deea857SKenneth D. Merry 6029deea857SKenneth D. Merry /* 6039deea857SKenneth D. Merry * Some CCB types, like scan bus and scan lun can only go 6049deea857SKenneth D. Merry * through the transport layer device. 6059deea857SKenneth D. Merry */ 6069deea857SKenneth D. Merry if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) { 607f0d9af51SMatt Jacob xpt_print(periph->path, "CCB function code %#x is " 608f0d9af51SMatt Jacob "restricted to the XPT device\n", 609f0d9af51SMatt Jacob inccb->ccb_h.func_code); 6109deea857SKenneth D. Merry error = ENODEV; 6119deea857SKenneth D. Merry break; 6129deea857SKenneth D. Merry } 6139deea857SKenneth D. Merry 6148cff7eb8SAlexander Motin /* Compatibility for RL/priority-unaware code. */ 6158cff7eb8SAlexander Motin priority = inccb->ccb_h.pinfo.priority; 616*cccf4220SAlexander Motin if (priority <= CAM_PRIORITY_OOB) 617*cccf4220SAlexander Motin priority += CAM_PRIORITY_OOB + 1; 6188cff7eb8SAlexander Motin 6199deea857SKenneth D. Merry /* 6209deea857SKenneth D. Merry * Non-immediate CCBs need a CCB from the per-device pool 6219deea857SKenneth D. Merry * of CCBs, which is scheduled by the transport layer. 6229deea857SKenneth D. Merry * Immediate CCBs and user-supplied CCBs should just be 6239deea857SKenneth D. Merry * malloced. 6249deea857SKenneth D. Merry */ 6259deea857SKenneth D. Merry if ((inccb->ccb_h.func_code & XPT_FC_QUEUED) 6269deea857SKenneth D. Merry && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) { 6278cff7eb8SAlexander Motin ccb = cam_periph_getccb(periph, priority); 6289deea857SKenneth D. Merry ccb_malloced = 0; 6299deea857SKenneth D. Merry } else { 6308008a935SScott Long ccb = xpt_alloc_ccb_nowait(); 6319deea857SKenneth D. Merry 6329deea857SKenneth D. Merry if (ccb != NULL) 6339deea857SKenneth D. Merry xpt_setup_ccb(&ccb->ccb_h, periph->path, 6348cff7eb8SAlexander Motin priority); 6359deea857SKenneth D. Merry ccb_malloced = 1; 6369deea857SKenneth D. Merry } 6379deea857SKenneth D. Merry 6389deea857SKenneth D. Merry if (ccb == NULL) { 639f0d9af51SMatt Jacob xpt_print(periph->path, "unable to allocate CCB\n"); 6409deea857SKenneth D. Merry error = ENOMEM; 6419deea857SKenneth D. Merry break; 6429deea857SKenneth D. Merry } 64376babe50SJustin T. Gibbs 64476babe50SJustin T. Gibbs error = passsendccb(periph, ccb, inccb); 64576babe50SJustin T. Gibbs 6469deea857SKenneth D. Merry if (ccb_malloced) 6479deea857SKenneth D. Merry xpt_free_ccb(ccb); 6489deea857SKenneth D. Merry else 64976babe50SJustin T. Gibbs xpt_release_ccb(ccb); 65076babe50SJustin T. Gibbs 65176babe50SJustin T. Gibbs break; 65276babe50SJustin T. Gibbs } 65376babe50SJustin T. Gibbs default: 65476babe50SJustin T. Gibbs error = cam_periph_ioctl(periph, cmd, addr, passerror); 65576babe50SJustin T. Gibbs break; 65676babe50SJustin T. Gibbs } 65776babe50SJustin T. Gibbs 6582b83592fSScott Long cam_periph_unlock(periph); 65976babe50SJustin T. Gibbs return(error); 66076babe50SJustin T. Gibbs } 66176babe50SJustin T. Gibbs 66276babe50SJustin T. Gibbs /* 66376babe50SJustin T. Gibbs * Generally, "ccb" should be the CCB supplied by the kernel. "inccb" 66476babe50SJustin T. Gibbs * should be the CCB that is copied in from the user. 66576babe50SJustin T. Gibbs */ 66676babe50SJustin T. Gibbs static int 66776babe50SJustin T. Gibbs passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) 66876babe50SJustin T. Gibbs { 66976babe50SJustin T. Gibbs struct pass_softc *softc; 67076babe50SJustin T. Gibbs struct cam_periph_map_info mapinfo; 67176babe50SJustin T. Gibbs int error, need_unmap; 67276babe50SJustin T. Gibbs 67376babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 67476babe50SJustin T. Gibbs 67576babe50SJustin T. Gibbs need_unmap = 0; 67676babe50SJustin T. Gibbs 67776babe50SJustin T. Gibbs /* 67876babe50SJustin T. Gibbs * There are some fields in the CCB header that need to be 67976babe50SJustin T. Gibbs * preserved, the rest we get from the user. 68076babe50SJustin T. Gibbs */ 68176babe50SJustin T. Gibbs xpt_merge_ccb(ccb, inccb); 68276babe50SJustin T. Gibbs 68376babe50SJustin T. Gibbs /* 68476babe50SJustin T. Gibbs * There's no way for the user to have a completion 68576babe50SJustin T. Gibbs * function, so we put our own completion function in here. 68676babe50SJustin T. Gibbs */ 68776babe50SJustin T. Gibbs ccb->ccb_h.cbfcnp = passdone; 68876babe50SJustin T. Gibbs 68976babe50SJustin T. Gibbs /* 69076babe50SJustin T. Gibbs * We only attempt to map the user memory into kernel space 69176babe50SJustin T. Gibbs * if they haven't passed in a physical memory pointer, 69276babe50SJustin T. Gibbs * and if there is actually an I/O operation to perform. 69306e79492SKenneth D. Merry * cam_periph_mapmem() supports SCSI, ATA, SMP, ADVINFO and device 6947c103ddeSKenneth D. Merry * match CCBs. For the SCSI, ATA and ADVINFO CCBs, we only pass the 6957c103ddeSKenneth D. Merry * CCB in if there's actually data to map. cam_periph_mapmem() will 6967c103ddeSKenneth D. Merry * do the right thing, even if there isn't data to map, but since CCBs 69776babe50SJustin T. Gibbs * without data are a reasonably common occurance (e.g. test unit 69876babe50SJustin T. Gibbs * ready), it will save a few cycles if we check for it here. 699dd0b4fb6SKonstantin Belousov * 700dd0b4fb6SKonstantin Belousov * XXX What happens if a sg list is supplied? We don't filter that 701dd0b4fb6SKonstantin Belousov * out. 70276babe50SJustin T. Gibbs */ 703dd0b4fb6SKonstantin Belousov if (((ccb->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) 70452c9ce25SScott Long && (((ccb->ccb_h.func_code == XPT_SCSI_IO || 70552c9ce25SScott Long ccb->ccb_h.func_code == XPT_ATA_IO) 70676babe50SJustin T. Gibbs && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 70706e79492SKenneth D. Merry || (ccb->ccb_h.func_code == XPT_DEV_MATCH) 70806e79492SKenneth D. Merry || (ccb->ccb_h.func_code == XPT_SMP_IO) 7093501942bSJustin T. Gibbs || ((ccb->ccb_h.func_code == XPT_DEV_ADVINFO) 7103501942bSJustin T. Gibbs && (ccb->cdai.bufsiz > 0)))) { 71176babe50SJustin T. Gibbs 71276babe50SJustin T. Gibbs bzero(&mapinfo, sizeof(mapinfo)); 71376babe50SJustin T. Gibbs 7142b83592fSScott Long /* 7152b83592fSScott Long * cam_periph_mapmem calls into proc and vm functions that can 7162b83592fSScott Long * sleep as well as trigger I/O, so we can't hold the lock. 7172b83592fSScott Long * Dropping it here is reasonably safe. 7182b83592fSScott Long */ 7192b83592fSScott Long cam_periph_unlock(periph); 72076babe50SJustin T. Gibbs error = cam_periph_mapmem(ccb, &mapinfo); 7212b83592fSScott Long cam_periph_lock(periph); 72276babe50SJustin T. Gibbs 72376babe50SJustin T. Gibbs /* 72476babe50SJustin T. Gibbs * cam_periph_mapmem returned an error, we can't continue. 72576babe50SJustin T. Gibbs * Return the error to the user. 72676babe50SJustin T. Gibbs */ 72776babe50SJustin T. Gibbs if (error) 72876babe50SJustin T. Gibbs return(error); 72976babe50SJustin T. Gibbs 73076babe50SJustin T. Gibbs /* 73176babe50SJustin T. Gibbs * We successfully mapped the memory in, so we need to 73276babe50SJustin T. Gibbs * unmap it when the transaction is done. 73376babe50SJustin T. Gibbs */ 73476babe50SJustin T. Gibbs need_unmap = 1; 73576babe50SJustin T. Gibbs } 73676babe50SJustin T. Gibbs 73776babe50SJustin T. Gibbs /* 73876babe50SJustin T. Gibbs * If the user wants us to perform any error recovery, then honor 73976babe50SJustin T. Gibbs * that request. Otherwise, it's up to the user to perform any 74076babe50SJustin T. Gibbs * error recovery. 74176babe50SJustin T. Gibbs */ 7420191d9b3SAlexander Motin cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO, 7430191d9b3SAlexander Motin /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? 7440191d9b3SAlexander Motin SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT, 745a9d2245eSPoul-Henning Kamp softc->device_stats); 74676babe50SJustin T. Gibbs 74776babe50SJustin T. Gibbs if (need_unmap != 0) 74876babe50SJustin T. Gibbs cam_periph_unmapmem(ccb, &mapinfo); 74976babe50SJustin T. Gibbs 75076babe50SJustin T. Gibbs ccb->ccb_h.cbfcnp = NULL; 75176babe50SJustin T. Gibbs ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv; 75276babe50SJustin T. Gibbs bcopy(ccb, inccb, sizeof(union ccb)); 75376babe50SJustin T. Gibbs 75483c5d981SAlexander Motin return(0); 75576babe50SJustin T. Gibbs } 75676babe50SJustin T. Gibbs 75776babe50SJustin T. Gibbs static int 75876babe50SJustin T. Gibbs passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 75976babe50SJustin T. Gibbs { 76076babe50SJustin T. Gibbs struct cam_periph *periph; 76176babe50SJustin T. Gibbs struct pass_softc *softc; 76276babe50SJustin T. Gibbs 76376babe50SJustin T. Gibbs periph = xpt_path_periph(ccb->ccb_h.path); 76476babe50SJustin T. Gibbs softc = (struct pass_softc *)periph->softc; 76576babe50SJustin T. Gibbs 76676babe50SJustin T. Gibbs return(cam_periph_error(ccb, cam_flags, sense_flags, 76776babe50SJustin T. Gibbs &softc->saved_ccb)); 76876babe50SJustin T. Gibbs } 769