1139743Simp/*- 2107178Snjl * Generic SCSI Target Kernel Mode Driver 339213Sgibbs * 4107178Snjl * Copyright (c) 2002 Nate Lawson. 5107178Snjl * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs. 639213Sgibbs * All rights reserved. 739213Sgibbs * 839213Sgibbs * Redistribution and use in source and binary forms, with or without 939213Sgibbs * modification, are permitted provided that the following conditions 1039213Sgibbs * are met: 1139213Sgibbs * 1. Redistributions of source code must retain the above copyright 1239213Sgibbs * notice, this list of conditions, and the following disclaimer, 1339213Sgibbs * without modification, immediately at the beginning of the file. 1439213Sgibbs * 2. The name of the author may not be used to endorse or promote products 1539213Sgibbs * derived from this software without specific prior written permission. 1639213Sgibbs * 1739213Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1839213Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1939213Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2039213Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2139213Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2239213Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2339213Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2439213Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2539213Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2639213Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2739213Sgibbs * SUCH DAMAGE. 2839213Sgibbs */ 2939213Sgibbs 30116162Sobrien#include <sys/cdefs.h> 31116162Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/cam/scsi/scsi_target.c 288817 2015-10-05 11:45:28Z mav $"); 32116162Sobrien 33158885Smjacob 3439213Sgibbs#include <sys/param.h> 3539213Sgibbs#include <sys/systm.h> 3639213Sgibbs#include <sys/kernel.h> 3739213Sgibbs#include <sys/conf.h> 3839213Sgibbs#include <sys/malloc.h> 3939213Sgibbs#include <sys/poll.h> 40107178Snjl#include <sys/vnode.h> 41107240Snjl#include <sys/lock.h> 42107240Snjl#include <sys/mutex.h> 43107178Snjl#include <sys/devicestat.h> 44158883Smjacob#include <sys/proc.h> 45197332Smjacob/* Includes to support callout */ 46197332Smjacob#include <sys/types.h> 47197332Smjacob#include <sys/systm.h> 4839213Sgibbs 4939213Sgibbs#include <cam/cam.h> 5039213Sgibbs#include <cam/cam_ccb.h> 5139213Sgibbs#include <cam/cam_periph.h> 5239213Sgibbs#include <cam/cam_xpt_periph.h> 53168752Sscottl#include <cam/cam_sim.h> 5439213Sgibbs#include <cam/scsi/scsi_targetio.h> 5539213Sgibbs 56197332Smjacob 57107178Snjl/* Transaction information attached to each CCB sent by the user */ 58107178Snjlstruct targ_cmd_descr { 59107178Snjl struct cam_periph_map_info mapinfo; 60107178Snjl TAILQ_ENTRY(targ_cmd_descr) tqe; 61107178Snjl union ccb *user_ccb; 62107178Snjl int priority; 63107178Snjl int func_code; 64107178Snjl}; 6539213Sgibbs 66107178Snjl/* Offset into the private CCB area for storing our descriptor */ 67107178Snjl#define targ_descr periph_priv.entries[1].ptr 6839213Sgibbs 69107178SnjlTAILQ_HEAD(descr_queue, targ_cmd_descr); 70107178Snjl 7139213Sgibbstypedef enum { 72107178Snjl TARG_STATE_RESV = 0x00, /* Invalid state */ 73107178Snjl TARG_STATE_OPENED = 0x01, /* Device opened, softc initialized */ 74107178Snjl TARG_STATE_LUN_ENABLED = 0x02 /* Device enabled for a path */ 75107178Snjl} targ_state; 7639213Sgibbs 77107178Snjl/* Per-instance device software context */ 7839213Sgibbsstruct targ_softc { 79107178Snjl /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */ 80107178Snjl struct ccb_queue pending_ccb_queue; 8149929Sgibbs 82107178Snjl /* Command descriptors awaiting CTIO resources from the XPT */ 83107178Snjl struct descr_queue work_queue; 8449929Sgibbs 85107178Snjl /* Command descriptors that have been aborted back to the user. */ 86107178Snjl struct descr_queue abort_queue; 8749929Sgibbs 8849929Sgibbs /* 89107178Snjl * Queue of CCBs that have been copied out to userland, but our 90107178Snjl * userland daemon has not yet seen. 9149929Sgibbs */ 92107178Snjl struct ccb_queue user_ccb_queue; 9349929Sgibbs 94107178Snjl struct cam_periph *periph; 95107178Snjl struct cam_path *path; 96107178Snjl targ_state state; 97288817Smav u_int maxio; 98107178Snjl struct selinfo read_select; 99107178Snjl struct devstat device_stats; 10039213Sgibbs}; 10139213Sgibbs 102107178Snjlstatic d_open_t targopen; 103107178Snjlstatic d_read_t targread; 104107178Snjlstatic d_write_t targwrite; 105107178Snjlstatic d_ioctl_t targioctl; 106107178Snjlstatic d_poll_t targpoll; 107107178Snjlstatic d_kqfilter_t targkqfilter; 108107178Snjlstatic void targreadfiltdetach(struct knote *kn); 109107178Snjlstatic int targreadfilt(struct knote *kn, long hint); 110197134Srwatsonstatic struct filterops targread_filtops = { 111197134Srwatson .f_isfd = 1, 112197134Srwatson .f_detach = targreadfiltdetach, 113197134Srwatson .f_event = targreadfilt, 114197134Srwatson}; 11539213Sgibbs 11639213Sgibbsstatic struct cdevsw targ_cdevsw = { 117126080Sphk .d_version = D_VERSION, 118126080Sphk .d_flags = D_NEEDGIANT, 119111815Sphk .d_open = targopen, 120111815Sphk .d_read = targread, 121111815Sphk .d_write = targwrite, 122111815Sphk .d_ioctl = targioctl, 123111815Sphk .d_poll = targpoll, 124111815Sphk .d_name = "targ", 125111815Sphk .d_kqfilter = targkqfilter 12639213Sgibbs}; 12739213Sgibbs 128107178Snjlstatic cam_status targendislun(struct cam_path *path, int enable, 129107178Snjl int grp6_len, int grp7_len); 130107178Snjlstatic cam_status targenable(struct targ_softc *softc, 131107178Snjl struct cam_path *path, 132107178Snjl int grp6_len, int grp7_len); 133107178Snjlstatic cam_status targdisable(struct targ_softc *softc); 134107178Snjlstatic periph_ctor_t targctor; 135107178Snjlstatic periph_dtor_t targdtor; 136107178Snjlstatic periph_start_t targstart; 137107178Snjlstatic int targusermerge(struct targ_softc *softc, 138107178Snjl struct targ_cmd_descr *descr, 139107178Snjl union ccb *ccb); 140107178Snjlstatic int targsendccb(struct targ_softc *softc, union ccb *ccb, 141107178Snjl struct targ_cmd_descr *descr); 142107178Snjlstatic void targdone(struct cam_periph *periph, 143107178Snjl union ccb *done_ccb); 144107178Snjlstatic int targreturnccb(struct targ_softc *softc, 145107178Snjl union ccb *ccb); 146107178Snjlstatic union ccb * targgetccb(struct targ_softc *softc, xpt_opcode type, 147107178Snjl int priority); 148107178Snjlstatic void targfreeccb(struct targ_softc *softc, union ccb *ccb); 149107178Snjlstatic struct targ_cmd_descr * 150107178Snjl targgetdescr(struct targ_softc *softc); 15139213Sgibbsstatic periph_init_t targinit; 15239213Sgibbsstatic void targasync(void *callback_arg, u_int32_t code, 153107178Snjl struct cam_path *path, void *arg); 154107178Snjlstatic void abort_all_pending(struct targ_softc *softc); 155107178Snjlstatic void notify_user(struct targ_softc *softc); 156107178Snjlstatic int targcamstatus(cam_status status); 157107178Snjlstatic size_t targccblen(xpt_opcode func_code); 158107178Snjl 15939213Sgibbsstatic struct periph_driver targdriver = 16039213Sgibbs{ 16139213Sgibbs targinit, "targ", 16239213Sgibbs TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0 16339213Sgibbs}; 16472119SpeterPERIPHDRIVER_DECLARE(targ, targdriver); 16539213Sgibbs 166107178Snjlstatic MALLOC_DEFINE(M_TARG, "TARG", "TARG data"); 16739213Sgibbs 168228481Sed/* Disable LUN if enabled and teardown softc */ 169228481Sedstatic void 170228481Sedtargcdevdtor(void *data) 17139213Sgibbs{ 17249929Sgibbs struct targ_softc *softc; 173228481Sed struct cam_periph *periph; 17439213Sgibbs 175228481Sed softc = data; 176197332Smjacob if (softc->periph == NULL) { 177228481Sed printf("%s: destroying non-enabled target\n", __func__); 178184205Sdes free(softc, M_TARG); 179228481Sed return; 180168752Sscottl } 181168752Sscottl 182168752Sscottl /* 183168752Sscottl * Acquire a hold on the periph so that it doesn't go away before 184168752Sscottl * we are ready at the end of the function. 185168752Sscottl */ 186168752Sscottl periph = softc->periph; 187168752Sscottl cam_periph_acquire(periph); 188168752Sscottl cam_periph_lock(periph); 189228481Sed (void)targdisable(softc); 190197332Smjacob if (softc->periph != NULL) { 191197332Smjacob cam_periph_invalidate(softc->periph); 192197332Smjacob softc->periph = NULL; 19339213Sgibbs } 194168752Sscottl cam_periph_unlock(periph); 195168752Sscottl cam_periph_release(periph); 196197332Smjacob free(softc, M_TARG); 197228481Sed} 198197332Smjacob 199228481Sed/* 200228481Sed * Create softc and initialize it. There is no locking here because a 201228481Sed * periph doesn't get created until an ioctl is issued to do so, and 202228481Sed * that can't happen until this method returns. 203228481Sed */ 204228481Sedstatic int 205228481Sedtargopen(struct cdev *dev, int flags, int fmt, struct thread *td) 206228481Sed{ 207228481Sed struct targ_softc *softc; 208228481Sed 209228481Sed /* Allocate its softc, initialize it */ 210228481Sed softc = malloc(sizeof(*softc), M_TARG, 211228481Sed M_WAITOK | M_ZERO); 212228481Sed softc->state = TARG_STATE_OPENED; 213228481Sed softc->periph = NULL; 214228481Sed softc->path = NULL; 215228481Sed 216228481Sed TAILQ_INIT(&softc->pending_ccb_queue); 217228481Sed TAILQ_INIT(&softc->work_queue); 218228481Sed TAILQ_INIT(&softc->abort_queue); 219228481Sed TAILQ_INIT(&softc->user_ccb_queue); 220228481Sed knlist_init_mtx(&softc->read_select.si_note, NULL); 221228481Sed 222228481Sed devfs_set_cdevpriv(softc, targcdevdtor); 223228481Sed return (0); 224107178Snjl} 22539213Sgibbs 226107178Snjl/* Enable/disable LUNs, set debugging level */ 227107178Snjlstatic int 228130585Sphktargioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 229107178Snjl{ 230107178Snjl struct targ_softc *softc; 231107178Snjl cam_status status; 23239213Sgibbs 233228481Sed devfs_get_cdevpriv((void **)&softc); 23439213Sgibbs 235107178Snjl switch (cmd) { 236107178Snjl case TARGIOCENABLE: 237107178Snjl { 238107178Snjl struct ioc_enable_lun *new_lun; 239107178Snjl struct cam_path *path; 24039213Sgibbs 241107178Snjl new_lun = (struct ioc_enable_lun *)addr; 242260387Sscottl status = xpt_create_path(&path, /*periph*/NULL, 243260387Sscottl new_lun->path_id, 244260387Sscottl new_lun->target_id, 245260387Sscottl new_lun->lun_id); 246107178Snjl if (status != CAM_REQ_CMP) { 247107178Snjl printf("Couldn't create path, status %#x\n", status); 24839213Sgibbs break; 24939213Sgibbs } 250260387Sscottl xpt_path_lock(path); 251107178Snjl status = targenable(softc, path, new_lun->grp6_len, 252107178Snjl new_lun->grp7_len); 253260387Sscottl xpt_path_unlock(path); 254107178Snjl xpt_free_path(path); 255107178Snjl break; 25639213Sgibbs } 257107178Snjl case TARGIOCDISABLE: 258168752Sscottl if (softc->periph == NULL) { 259168752Sscottl status = CAM_DEV_NOT_THERE; 260168752Sscottl break; 261168752Sscottl } 262168752Sscottl cam_periph_lock(softc->periph); 263107178Snjl status = targdisable(softc); 264168752Sscottl cam_periph_unlock(softc->periph); 265107178Snjl break; 266107178Snjl case TARGIOCDEBUG: 267107178Snjl { 268107178Snjl struct ccb_debug cdbg; 26939213Sgibbs 270168752Sscottl /* If no periph available, disallow debugging changes */ 271168752Sscottl if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { 272168752Sscottl status = CAM_DEV_NOT_THERE; 273168752Sscottl break; 274168752Sscottl } 275107178Snjl bzero(&cdbg, sizeof cdbg); 276107178Snjl if (*((int *)addr) != 0) 277107178Snjl cdbg.flags = CAM_DEBUG_PERIPH; 278107178Snjl else 279107178Snjl cdbg.flags = CAM_DEBUG_NONE; 280198382Smav xpt_setup_ccb(&cdbg.ccb_h, softc->path, CAM_PRIORITY_NORMAL); 281107178Snjl cdbg.ccb_h.func_code = XPT_DEBUG; 282107178Snjl cdbg.ccb_h.cbfcnp = targdone; 283107178Snjl xpt_action((union ccb *)&cdbg); 284107178Snjl status = cdbg.ccb_h.status & CAM_STATUS_MASK; 285107178Snjl break; 28639213Sgibbs } 287107178Snjl default: 288107178Snjl status = CAM_PROVIDE_FAIL; 289107178Snjl break; 29039213Sgibbs } 29139213Sgibbs 292107178Snjl return (targcamstatus(status)); 29339213Sgibbs} 29439213Sgibbs 295107178Snjl/* Writes are always ready, reads wait for user_ccb_queue or abort_queue */ 296107178Snjlstatic int 297130585Sphktargpoll(struct cdev *dev, int poll_events, struct thread *td) 29841815Sgibbs{ 29941815Sgibbs struct targ_softc *softc; 300107178Snjl int revents; 30141815Sgibbs 302228481Sed devfs_get_cdevpriv((void **)&softc); 30341815Sgibbs 304107178Snjl /* Poll for write() is always ok. */ 305107178Snjl revents = poll_events & (POLLOUT | POLLWRNORM); 306107178Snjl if ((poll_events & (POLLIN | POLLRDNORM)) != 0) { 307107178Snjl /* Poll for read() depends on user and abort queues. */ 308168752Sscottl cam_periph_lock(softc->periph); 309107178Snjl if (!TAILQ_EMPTY(&softc->user_ccb_queue) || 310107178Snjl !TAILQ_EMPTY(&softc->abort_queue)) { 311107178Snjl revents |= poll_events & (POLLIN | POLLRDNORM); 312107178Snjl } 313168752Sscottl cam_periph_unlock(softc->periph); 314107178Snjl /* Only sleep if the user didn't poll for write. */ 315107178Snjl if (revents == 0) 316107178Snjl selrecord(td, &softc->read_select); 31741815Sgibbs } 31841815Sgibbs 319107178Snjl return (revents); 32041815Sgibbs} 32141815Sgibbs 322107178Snjlstatic int 323130585Sphktargkqfilter(struct cdev *dev, struct knote *kn) 32441815Sgibbs{ 325107178Snjl struct targ_softc *softc; 32641815Sgibbs 327228481Sed devfs_get_cdevpriv((void **)&softc); 328107178Snjl kn->kn_hook = (caddr_t)softc; 329107178Snjl kn->kn_fop = &targread_filtops; 330133741Sjmg knlist_add(&softc->read_select.si_note, kn, 0); 331107178Snjl return (0); 33241815Sgibbs} 33341815Sgibbs 33439213Sgibbsstatic void 335107178Snjltargreadfiltdetach(struct knote *kn) 33639213Sgibbs{ 337107178Snjl struct targ_softc *softc; 33839213Sgibbs 339107178Snjl softc = (struct targ_softc *)kn->kn_hook; 340133741Sjmg knlist_remove(&softc->read_select.si_note, kn, 0); 34139213Sgibbs} 34239213Sgibbs 343107178Snjl/* Notify the user's kqueue when the user queue or abort queue gets a CCB */ 34439213Sgibbsstatic int 345107178Snjltargreadfilt(struct knote *kn, long hint) 34639213Sgibbs{ 347107178Snjl struct targ_softc *softc; 348107178Snjl int retval; 34939213Sgibbs 350107178Snjl softc = (struct targ_softc *)kn->kn_hook; 351168752Sscottl cam_periph_lock(softc->periph); 352107178Snjl retval = !TAILQ_EMPTY(&softc->user_ccb_queue) || 353107178Snjl !TAILQ_EMPTY(&softc->abort_queue); 354168752Sscottl cam_periph_unlock(softc->periph); 355107178Snjl return (retval); 35639213Sgibbs} 35739213Sgibbs 358107178Snjl/* Send the HBA the enable/disable message */ 359107178Snjlstatic cam_status 360107178Snjltargendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len) 36139213Sgibbs{ 362107178Snjl struct ccb_en_lun en_ccb; 363107178Snjl cam_status status; 36439213Sgibbs 365107178Snjl /* Tell the lun to begin answering selects */ 366198382Smav xpt_setup_ccb(&en_ccb.ccb_h, path, CAM_PRIORITY_NORMAL); 367107178Snjl en_ccb.ccb_h.func_code = XPT_EN_LUN; 368107178Snjl /* Don't need support for any vendor specific commands */ 369107178Snjl en_ccb.grp6_len = grp6_len; 370107178Snjl en_ccb.grp7_len = grp7_len; 371107178Snjl en_ccb.enable = enable ? 1 : 0; 372107178Snjl xpt_action((union ccb *)&en_ccb); 373107178Snjl status = en_ccb.ccb_h.status & CAM_STATUS_MASK; 374107178Snjl if (status != CAM_REQ_CMP) { 375164906Smjacob xpt_print(path, "%sable lun CCB rejected, status %#x\n", 376164906Smjacob enable ? "en" : "dis", status); 37741815Sgibbs } 378107178Snjl return (status); 37939213Sgibbs} 38039213Sgibbs 381107178Snjl/* Enable target mode on a LUN, given its path */ 382107178Snjlstatic cam_status 383107178Snjltargenable(struct targ_softc *softc, struct cam_path *path, int grp6_len, 384107178Snjl int grp7_len) 38544504Sgibbs{ 386107178Snjl struct cam_periph *periph; 38744504Sgibbs struct ccb_pathinq cpi; 388107178Snjl cam_status status; 38944504Sgibbs 390107178Snjl if ((softc->state & TARG_STATE_LUN_ENABLED) != 0) 391107178Snjl return (CAM_LUN_ALRDY_ENA); 39252575Smjacob 393107178Snjl /* Make sure SIM supports target mode */ 394198382Smav xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL); 39544504Sgibbs cpi.ccb_h.func_code = XPT_PATH_INQ; 39644504Sgibbs xpt_action((union ccb *)&cpi); 397107178Snjl status = cpi.ccb_h.status & CAM_STATUS_MASK; 39844504Sgibbs if (status != CAM_REQ_CMP) { 399107178Snjl printf("pathinq failed, status %#x\n", status); 400107178Snjl goto enable_fail; 40144504Sgibbs } 40244504Sgibbs if ((cpi.target_sprt & PIT_PROCESSOR) == 0) { 403107178Snjl printf("controller does not support target mode\n"); 404107178Snjl status = CAM_FUNC_NOTAVAIL; 405107178Snjl goto enable_fail; 40644504Sgibbs } 407288817Smav if (cpi.maxio == 0) 408288817Smav softc->maxio = DFLTPHYS; /* traditional default */ 409288817Smav else if (cpi.maxio > MAXPHYS) 410288817Smav softc->maxio = MAXPHYS; /* for safety */ 411288817Smav else 412288817Smav softc->maxio = cpi.maxio; /* real value */ 41344504Sgibbs 414107178Snjl /* Destroy any periph on our path if it is disabled */ 415107178Snjl periph = cam_periph_find(path, "targ"); 416107178Snjl if (periph != NULL) { 417107178Snjl struct targ_softc *del_softc; 41844504Sgibbs 419107178Snjl del_softc = (struct targ_softc *)periph->softc; 420107178Snjl if ((del_softc->state & TARG_STATE_LUN_ENABLED) == 0) { 421107178Snjl cam_periph_invalidate(del_softc->periph); 422107178Snjl del_softc->periph = NULL; 423107178Snjl } else { 424107178Snjl printf("Requested path still in use by targ%d\n", 425107178Snjl periph->unit_number); 426107178Snjl status = CAM_LUN_ALRDY_ENA; 427107178Snjl goto enable_fail; 428107178Snjl } 42980574Smjacob } 43080574Smjacob 431107178Snjl /* Create a periph instance attached to this path */ 43244504Sgibbs status = cam_periph_alloc(targctor, NULL, targdtor, targstart, 433107178Snjl "targ", CAM_PERIPH_BIO, path, targasync, 0, softc); 434107178Snjl if (status != CAM_REQ_CMP) { 435107178Snjl printf("cam_periph_alloc failed, status %#x\n", status); 436107178Snjl goto enable_fail; 437107178Snjl } 43844504Sgibbs 439107178Snjl /* Ensure that the periph now exists. */ 440107178Snjl if (cam_periph_find(path, "targ") == NULL) { 441107178Snjl panic("targenable: succeeded but no periph?"); 442107178Snjl /* NOTREACHED */ 443107178Snjl } 44444504Sgibbs 445107178Snjl /* Send the enable lun message */ 446107178Snjl status = targendislun(path, /*enable*/1, grp6_len, grp7_len); 447107178Snjl if (status != CAM_REQ_CMP) { 448107178Snjl printf("enable lun failed, status %#x\n", status); 449107178Snjl goto enable_fail; 45044504Sgibbs } 451107178Snjl softc->state |= TARG_STATE_LUN_ENABLED; 45246437Sgibbs 453107178Snjlenable_fail: 454107178Snjl return (status); 455107178Snjl} 45646437Sgibbs 457107178Snjl/* Disable this softc's target instance if enabled */ 458107178Snjlstatic cam_status 459107178Snjltargdisable(struct targ_softc *softc) 460107178Snjl{ 461107178Snjl cam_status status; 462107178Snjl 463107178Snjl if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) 464107178Snjl return (CAM_REQ_CMP); 465107178Snjl 466107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targdisable\n")); 467107178Snjl 468107178Snjl /* Abort any ccbs pending on the controller */ 469107178Snjl abort_all_pending(softc); 470107178Snjl 471107178Snjl /* Disable this lun */ 472107178Snjl status = targendislun(softc->path, /*enable*/0, 473107178Snjl /*grp6_len*/0, /*grp7_len*/0); 474107178Snjl if (status == CAM_REQ_CMP) 475107178Snjl softc->state &= ~TARG_STATE_LUN_ENABLED; 476107178Snjl else 477107178Snjl printf("Disable lun failed, status %#x\n", status); 478107178Snjl 479107178Snjl return (status); 48044504Sgibbs} 48144504Sgibbs 482107178Snjl/* Initialize a periph (called from cam_periph_alloc) */ 483107178Snjlstatic cam_status 484107178Snjltargctor(struct cam_periph *periph, void *arg) 48544504Sgibbs{ 48644504Sgibbs struct targ_softc *softc; 48744504Sgibbs 488107178Snjl /* Store pointer to softc for periph-driven routines */ 489107178Snjl softc = (struct targ_softc *)arg; 490107178Snjl periph->softc = softc; 491107178Snjl softc->periph = periph; 492107178Snjl softc->path = periph->path; 493107178Snjl return (CAM_REQ_CMP); 494107178Snjl} 49544504Sgibbs 496107178Snjlstatic void 497107178Snjltargdtor(struct cam_periph *periph) 498107178Snjl{ 499107178Snjl struct targ_softc *softc; 500107178Snjl struct ccb_hdr *ccb_h; 501107178Snjl struct targ_cmd_descr *descr; 50244504Sgibbs 503107178Snjl softc = (struct targ_softc *)periph->softc; 504107178Snjl 505107178Snjl /* 506107178Snjl * targdisable() aborts CCBs back to the user and leaves them 507107178Snjl * on user_ccb_queue and abort_queue in case the user is still 508107178Snjl * interested in them. We free them now. 509107178Snjl */ 510107178Snjl while ((ccb_h = TAILQ_FIRST(&softc->user_ccb_queue)) != NULL) { 511107178Snjl TAILQ_REMOVE(&softc->user_ccb_queue, ccb_h, periph_links.tqe); 512107178Snjl targfreeccb(softc, (union ccb *)ccb_h); 51344504Sgibbs } 514107178Snjl while ((descr = TAILQ_FIRST(&softc->abort_queue)) != NULL) { 515107178Snjl TAILQ_REMOVE(&softc->abort_queue, descr, tqe); 516184205Sdes free(descr, M_TARG); 517107178Snjl } 51844504Sgibbs 519107178Snjl softc->periph = NULL; 520107178Snjl softc->path = NULL; 521107178Snjl periph->softc = NULL; 52244504Sgibbs} 52344504Sgibbs 524107178Snjl/* Receive CCBs from user mode proc and send them to the HBA */ 52544504Sgibbsstatic int 526130585Sphktargwrite(struct cdev *dev, struct uio *uio, int ioflag) 52739213Sgibbs{ 528107178Snjl union ccb *user_ccb; 52939213Sgibbs struct targ_softc *softc; 530107178Snjl struct targ_cmd_descr *descr; 531107178Snjl int write_len, error; 532107178Snjl int func_code, priority; 53339213Sgibbs 534228481Sed devfs_get_cdevpriv((void **)&softc); 535107178Snjl write_len = error = 0; 536107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 537194990Skib ("write - uio_resid %zd\n", uio->uio_resid)); 538107178Snjl while (uio->uio_resid >= sizeof(user_ccb) && error == 0) { 539107178Snjl union ccb *ccb; 540107178Snjl 541107178Snjl error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); 542107178Snjl if (error != 0) { 543107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 544107178Snjl ("write - uiomove failed (%d)\n", error)); 54544504Sgibbs break; 546107178Snjl } 547120663Ssimokawa priority = fuword32(&user_ccb->ccb_h.pinfo.priority); 548198382Smav if (priority == CAM_PRIORITY_NONE) { 549107178Snjl error = EINVAL; 55044504Sgibbs break; 551107178Snjl } 552120663Ssimokawa func_code = fuword32(&user_ccb->ccb_h.func_code); 553107178Snjl switch (func_code) { 554107178Snjl case XPT_ACCEPT_TARGET_IO: 555107178Snjl case XPT_IMMED_NOTIFY: 556255120Smav case XPT_IMMEDIATE_NOTIFY: 557168752Sscottl cam_periph_lock(softc->periph); 558107178Snjl ccb = targgetccb(softc, func_code, priority); 559107178Snjl descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr; 560107178Snjl descr->user_ccb = user_ccb; 561107178Snjl descr->func_code = func_code; 562107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 563107178Snjl ("Sent ATIO/INOT (%p)\n", user_ccb)); 564107178Snjl xpt_action(ccb); 565107178Snjl TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, 566107178Snjl &ccb->ccb_h, 567107178Snjl periph_links.tqe); 568168752Sscottl cam_periph_unlock(softc->periph); 569107178Snjl break; 57044504Sgibbs default: 571168752Sscottl cam_periph_lock(softc->periph); 572107178Snjl if ((func_code & XPT_FC_QUEUED) != 0) { 573107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 574107178Snjl ("Sending queued ccb %#x (%p)\n", 575107178Snjl func_code, user_ccb)); 576107178Snjl descr = targgetdescr(softc); 577107178Snjl descr->user_ccb = user_ccb; 578107178Snjl descr->priority = priority; 579107178Snjl descr->func_code = func_code; 580107178Snjl TAILQ_INSERT_TAIL(&softc->work_queue, 581107178Snjl descr, tqe); 582107178Snjl xpt_schedule(softc->periph, priority); 583107178Snjl } else { 584107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 585107178Snjl ("Sending inline ccb %#x (%p)\n", 586107178Snjl func_code, user_ccb)); 587107178Snjl ccb = targgetccb(softc, func_code, priority); 588107178Snjl descr = (struct targ_cmd_descr *) 589107178Snjl ccb->ccb_h.targ_descr; 590107178Snjl descr->user_ccb = user_ccb; 591107178Snjl descr->priority = priority; 592107178Snjl descr->func_code = func_code; 593107178Snjl if (targusermerge(softc, descr, ccb) != EFAULT) 594107178Snjl targsendccb(softc, ccb, descr); 595107178Snjl targreturnccb(softc, ccb); 596107178Snjl } 597168752Sscottl cam_periph_unlock(softc->periph); 59844504Sgibbs break; 59944504Sgibbs } 600107178Snjl write_len += sizeof(user_ccb); 601107178Snjl } 602107178Snjl 603107178Snjl /* 604107178Snjl * If we've successfully taken in some amount of 605107178Snjl * data, return success for that data first. If 606107178Snjl * an error is persistent, it will be reported 607107178Snjl * on the next write. 608107178Snjl */ 609107178Snjl if (error != 0 && write_len == 0) 61044504Sgibbs return (error); 611107178Snjl if (write_len == 0 && uio->uio_resid != 0) 612107178Snjl return (ENOSPC); 613107178Snjl return (0); 614107178Snjl} 61544504Sgibbs 616107178Snjl/* Process requests (descrs) via the periph-supplied CCBs */ 617107178Snjlstatic void 618107178Snjltargstart(struct cam_periph *periph, union ccb *start_ccb) 619107178Snjl{ 620107178Snjl struct targ_softc *softc; 621107178Snjl struct targ_cmd_descr *descr, *next_descr; 622107178Snjl int error; 623107178Snjl 62439213Sgibbs softc = (struct targ_softc *)periph->softc; 625107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb)); 62639213Sgibbs 627107178Snjl descr = TAILQ_FIRST(&softc->work_queue); 628107178Snjl if (descr == NULL) { 629107178Snjl xpt_release_ccb(start_ccb); 630107178Snjl } else { 631107178Snjl TAILQ_REMOVE(&softc->work_queue, descr, tqe); 632107178Snjl next_descr = TAILQ_FIRST(&softc->work_queue); 63339213Sgibbs 634107178Snjl /* Initiate a transaction using the descr and supplied CCB */ 635107178Snjl error = targusermerge(softc, descr, start_ccb); 636107178Snjl if (error == 0) 637107178Snjl error = targsendccb(softc, start_ccb, descr); 638107178Snjl if (error != 0) { 639164906Smjacob xpt_print(periph->path, 640164906Smjacob "targsendccb failed, err %d\n", error); 641107178Snjl xpt_release_ccb(start_ccb); 642107178Snjl suword(&descr->user_ccb->ccb_h.status, 643107178Snjl CAM_REQ_CMP_ERR); 644107178Snjl TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe); 645107178Snjl notify_user(softc); 64639213Sgibbs } 64739213Sgibbs 648107178Snjl /* If we have more work to do, stay scheduled */ 649107178Snjl if (next_descr != NULL) 650107178Snjl xpt_schedule(periph, next_descr->priority); 65139213Sgibbs } 652107178Snjl} 65339213Sgibbs 654107178Snjlstatic int 655107178Snjltargusermerge(struct targ_softc *softc, struct targ_cmd_descr *descr, 656107178Snjl union ccb *ccb) 657107178Snjl{ 658107178Snjl struct ccb_hdr *u_ccbh, *k_ccbh; 659107178Snjl size_t ccb_len; 660107178Snjl int error; 66139213Sgibbs 662107178Snjl u_ccbh = &descr->user_ccb->ccb_h; 663107178Snjl k_ccbh = &ccb->ccb_h; 66439213Sgibbs 665107178Snjl /* 666107178Snjl * There are some fields in the CCB header that need to be 667107178Snjl * preserved, the rest we get from the user ccb. (See xpt_merge_ccb) 668107178Snjl */ 669107178Snjl xpt_setup_ccb(k_ccbh, softc->path, descr->priority); 670120663Ssimokawa k_ccbh->retry_count = fuword32(&u_ccbh->retry_count); 671107178Snjl k_ccbh->func_code = descr->func_code; 672120663Ssimokawa k_ccbh->flags = fuword32(&u_ccbh->flags); 673120663Ssimokawa k_ccbh->timeout = fuword32(&u_ccbh->timeout); 674107178Snjl ccb_len = targccblen(k_ccbh->func_code) - sizeof(struct ccb_hdr); 675107178Snjl error = copyin(u_ccbh + 1, k_ccbh + 1, ccb_len); 676107178Snjl if (error != 0) { 677107178Snjl k_ccbh->status = CAM_REQ_CMP_ERR; 678107178Snjl return (error); 67939213Sgibbs } 68039213Sgibbs 681107178Snjl /* Translate usermode abort_ccb pointer to its kernel counterpart */ 682107178Snjl if (k_ccbh->func_code == XPT_ABORT) { 683107178Snjl struct ccb_abort *cab; 684107178Snjl struct ccb_hdr *ccb_h; 685107178Snjl 686107178Snjl cab = (struct ccb_abort *)ccb; 687107178Snjl TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, 688107178Snjl periph_links.tqe) { 689107178Snjl struct targ_cmd_descr *ab_descr; 690107178Snjl 691107178Snjl ab_descr = (struct targ_cmd_descr *)ccb_h->targ_descr; 692107178Snjl if (ab_descr->user_ccb == cab->abort_ccb) { 693107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 694107178Snjl ("Changing abort for %p to %p\n", 695107178Snjl cab->abort_ccb, ccb_h)); 696107178Snjl cab->abort_ccb = (union ccb *)ccb_h; 697107178Snjl break; 698107178Snjl } 69939213Sgibbs } 700107178Snjl /* CCB not found, set appropriate status */ 701107178Snjl if (ccb_h == NULL) { 702107178Snjl k_ccbh->status = CAM_PATH_INVALID; 703107178Snjl error = ESRCH; 70439213Sgibbs } 70539213Sgibbs } 706107178Snjl 70739213Sgibbs return (error); 70839213Sgibbs} 70939213Sgibbs 710107178Snjl/* Build and send a kernel CCB formed from descr->user_ccb */ 71139213Sgibbsstatic int 712107178Snjltargsendccb(struct targ_softc *softc, union ccb *ccb, 713107178Snjl struct targ_cmd_descr *descr) 71439213Sgibbs{ 715107178Snjl struct cam_periph_map_info *mapinfo; 716107178Snjl struct ccb_hdr *ccb_h; 717107178Snjl int error; 71839213Sgibbs 719107178Snjl ccb_h = &ccb->ccb_h; 720107178Snjl mapinfo = &descr->mapinfo; 721107178Snjl mapinfo->num_bufs_used = 0; 72239213Sgibbs 72339213Sgibbs /* 72439213Sgibbs * There's no way for the user to have a completion 72539213Sgibbs * function, so we put our own completion function in here. 726107178Snjl * We also stash in a reference to our descriptor so targreturnccb() 727107178Snjl * can find our mapping info. 72839213Sgibbs */ 729107178Snjl ccb_h->cbfcnp = targdone; 730107178Snjl ccb_h->targ_descr = descr; 73139213Sgibbs 732251479Sscottl if ((ccb_h->func_code == XPT_CONT_TARGET_IO) || 733251479Sscottl (ccb_h->func_code == XPT_DEV_MATCH)) { 73439213Sgibbs 735288817Smav error = cam_periph_mapmem(ccb, mapinfo, softc->maxio); 73639213Sgibbs 73739213Sgibbs /* 73839213Sgibbs * cam_periph_mapmem returned an error, we can't continue. 73939213Sgibbs * Return the error to the user. 74039213Sgibbs */ 741107178Snjl if (error) { 742107178Snjl ccb_h->status = CAM_REQ_CMP_ERR; 743107178Snjl mapinfo->num_bufs_used = 0; 744107178Snjl return (error); 745107178Snjl } 74639213Sgibbs } 74739213Sgibbs 74839213Sgibbs /* 74949929Sgibbs * Once queued on the pending CCB list, this CCB will be protected 750107178Snjl * by our error recovery handler. 75139213Sgibbs */ 752107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb)); 753107178Snjl if (XPT_FC_IS_QUEUED(ccb)) { 754107178Snjl TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h, 755107178Snjl periph_links.tqe); 75649929Sgibbs } 757107178Snjl xpt_action(ccb); 75849929Sgibbs 759107178Snjl return (0); 76039213Sgibbs} 76139213Sgibbs 762107178Snjl/* Completion routine for CCBs (called at splsoftcam) */ 763107178Snjlstatic void 764107178Snjltargdone(struct cam_periph *periph, union ccb *done_ccb) 76539213Sgibbs{ 76639213Sgibbs struct targ_softc *softc; 767107178Snjl cam_status status; 76839213Sgibbs 769107178Snjl CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb)); 77039213Sgibbs softc = (struct targ_softc *)periph->softc; 771107178Snjl TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h, 772107178Snjl periph_links.tqe); 773107178Snjl status = done_ccb->ccb_h.status & CAM_STATUS_MASK; 77439213Sgibbs 775107178Snjl /* If we're no longer enabled, throw away CCB */ 776107178Snjl if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { 777107178Snjl targfreeccb(softc, done_ccb); 778107178Snjl return; 77939213Sgibbs } 780107178Snjl /* abort_all_pending() waits for pending queue to be empty */ 781107178Snjl if (TAILQ_EMPTY(&softc->pending_ccb_queue)) 782107178Snjl wakeup(&softc->pending_ccb_queue); 78339213Sgibbs 784107178Snjl switch (done_ccb->ccb_h.func_code) { 785107178Snjl /* All FC_*_QUEUED CCBs go back to userland */ 786107178Snjl case XPT_IMMED_NOTIFY: 787255120Smav case XPT_IMMEDIATE_NOTIFY: 788107178Snjl case XPT_ACCEPT_TARGET_IO: 789107178Snjl case XPT_CONT_TARGET_IO: 790107178Snjl TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h, 791107178Snjl periph_links.tqe); 792197332Smjacob cam_periph_unlock(softc->periph); 793107178Snjl notify_user(softc); 794197332Smjacob cam_periph_lock(softc->periph); 795107178Snjl break; 796107178Snjl default: 797107178Snjl panic("targdone: impossible xpt opcode %#x", 798107178Snjl done_ccb->ccb_h.func_code); 799107178Snjl /* NOTREACHED */ 80039213Sgibbs } 80139213Sgibbs} 80239213Sgibbs 803107178Snjl/* Return CCBs to the user from the user queue and abort queue */ 80439213Sgibbsstatic int 805130585Sphktargread(struct cdev *dev, struct uio *uio, int ioflag) 80639213Sgibbs{ 807107178Snjl struct descr_queue *abort_queue; 808107178Snjl struct targ_cmd_descr *user_descr; 809107178Snjl struct targ_softc *softc; 810107178Snjl struct ccb_queue *user_queue; 811107178Snjl struct ccb_hdr *ccb_h; 812107178Snjl union ccb *user_ccb; 813107178Snjl int read_len, error; 81444504Sgibbs 815107178Snjl error = 0; 816107178Snjl read_len = 0; 817228481Sed devfs_get_cdevpriv((void **)&softc); 818107178Snjl user_queue = &softc->user_ccb_queue; 819107178Snjl abort_queue = &softc->abort_queue; 820107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n")); 82139213Sgibbs 822107178Snjl /* If no data is available, wait or return immediately */ 823168752Sscottl cam_periph_lock(softc->periph); 824107178Snjl ccb_h = TAILQ_FIRST(user_queue); 825107178Snjl user_descr = TAILQ_FIRST(abort_queue); 826107178Snjl while (ccb_h == NULL && user_descr == NULL) { 827107178Snjl if ((ioflag & IO_NDELAY) == 0) { 828260387Sscottl error = cam_periph_sleep(softc->periph, user_queue, 829167082Sjhb PRIBIO | PCATCH, "targrd", 0); 830107178Snjl ccb_h = TAILQ_FIRST(user_queue); 831107178Snjl user_descr = TAILQ_FIRST(abort_queue); 832107178Snjl if (error != 0) { 833107178Snjl if (error == ERESTART) { 834107178Snjl continue; 835107178Snjl } else { 836107178Snjl goto read_fail; 837107178Snjl } 838107178Snjl } 839107178Snjl } else { 840168752Sscottl cam_periph_unlock(softc->periph); 841107178Snjl return (EAGAIN); 842107178Snjl } 84339213Sgibbs } 84439213Sgibbs 845107178Snjl /* Data is available so fill the user's buffer */ 846107178Snjl while (ccb_h != NULL) { 847107178Snjl struct targ_cmd_descr *descr; 84844504Sgibbs 849107178Snjl if (uio->uio_resid < sizeof(user_ccb)) 850107178Snjl break; 851107178Snjl TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe); 852107178Snjl descr = (struct targ_cmd_descr *)ccb_h->targ_descr; 853107178Snjl user_ccb = descr->user_ccb; 854107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 855107178Snjl ("targread ccb %p (%p)\n", ccb_h, user_ccb)); 856107178Snjl error = targreturnccb(softc, (union ccb *)ccb_h); 857107178Snjl if (error != 0) 858107178Snjl goto read_fail; 859168752Sscottl cam_periph_unlock(softc->periph); 860107178Snjl error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); 861168752Sscottl cam_periph_lock(softc->periph); 862107178Snjl if (error != 0) 863107178Snjl goto read_fail; 864107178Snjl read_len += sizeof(user_ccb); 86544504Sgibbs 866107178Snjl ccb_h = TAILQ_FIRST(user_queue); 86739213Sgibbs } 86839213Sgibbs 869107178Snjl /* Flush out any aborted descriptors */ 870107178Snjl while (user_descr != NULL) { 871107178Snjl if (uio->uio_resid < sizeof(user_ccb)) 872107178Snjl break; 873107178Snjl TAILQ_REMOVE(abort_queue, user_descr, tqe); 874107178Snjl user_ccb = user_descr->user_ccb; 875107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 876107178Snjl ("targread aborted descr %p (%p)\n", 877107178Snjl user_descr, user_ccb)); 878107178Snjl suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED); 879168752Sscottl cam_periph_unlock(softc->periph); 880107178Snjl error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); 881168752Sscottl cam_periph_lock(softc->periph); 882107178Snjl if (error != 0) 883107178Snjl goto read_fail; 884107178Snjl read_len += sizeof(user_ccb); 885107178Snjl 886107178Snjl user_descr = TAILQ_FIRST(abort_queue); 88739213Sgibbs } 88839213Sgibbs 88939213Sgibbs /* 890107178Snjl * If we've successfully read some amount of data, don't report an 891107178Snjl * error. If the error is persistent, it will be reported on the 892107178Snjl * next read(). 89339213Sgibbs */ 894107178Snjl if (read_len == 0 && uio->uio_resid != 0) 895107178Snjl error = ENOSPC; 89639213Sgibbs 897107178Snjlread_fail: 898168752Sscottl cam_periph_unlock(softc->periph); 899107178Snjl return (error); 90039213Sgibbs} 90139213Sgibbs 902107178Snjl/* Copy completed ccb back to the user */ 903107178Snjlstatic int 904107178Snjltargreturnccb(struct targ_softc *softc, union ccb *ccb) 90539213Sgibbs{ 906107178Snjl struct targ_cmd_descr *descr; 907107178Snjl struct ccb_hdr *u_ccbh; 908107178Snjl size_t ccb_len; 909107178Snjl int error; 91039213Sgibbs 911107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targreturnccb %p\n", ccb)); 912107178Snjl descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr; 913107178Snjl u_ccbh = &descr->user_ccb->ccb_h; 91439213Sgibbs 915107178Snjl /* Copy out the central portion of the ccb_hdr */ 916107178Snjl copyout(&ccb->ccb_h.retry_count, &u_ccbh->retry_count, 917107178Snjl offsetof(struct ccb_hdr, periph_priv) - 918107178Snjl offsetof(struct ccb_hdr, retry_count)); 91939213Sgibbs 920107178Snjl /* Copy out the rest of the ccb (after the ccb_hdr) */ 921107178Snjl ccb_len = targccblen(ccb->ccb_h.func_code) - sizeof(struct ccb_hdr); 922107178Snjl if (descr->mapinfo.num_bufs_used != 0) 923107178Snjl cam_periph_unmapmem(ccb, &descr->mapinfo); 924107178Snjl error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len); 925107178Snjl if (error != 0) { 926164906Smjacob xpt_print(softc->path, 927164906Smjacob "targreturnccb - CCB copyout failed (%d)\n", error); 92839213Sgibbs } 929107178Snjl /* Free CCB or send back to devq. */ 930107178Snjl targfreeccb(softc, ccb); 93139213Sgibbs 932107178Snjl return (error); 93339213Sgibbs} 93439213Sgibbs 935107178Snjlstatic union ccb * 936107178Snjltarggetccb(struct targ_softc *softc, xpt_opcode type, int priority) 93739213Sgibbs{ 938107178Snjl union ccb *ccb; 939107178Snjl int ccb_len; 94039213Sgibbs 941107178Snjl ccb_len = targccblen(type); 942197332Smjacob ccb = malloc(ccb_len, M_TARG, M_NOWAIT); 943107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb)); 944197332Smjacob if (ccb == NULL) { 945197332Smjacob return (ccb); 946197332Smjacob } 947107178Snjl xpt_setup_ccb(&ccb->ccb_h, softc->path, priority); 948107178Snjl ccb->ccb_h.func_code = type; 949107178Snjl ccb->ccb_h.cbfcnp = targdone; 950107178Snjl ccb->ccb_h.targ_descr = targgetdescr(softc); 951197332Smjacob if (ccb->ccb_h.targ_descr == NULL) { 952197332Smjacob free (ccb, M_TARG); 953197332Smjacob ccb = NULL; 954197332Smjacob } 955107178Snjl return (ccb); 95639213Sgibbs} 95739213Sgibbs 95839213Sgibbsstatic void 959107178Snjltargfreeccb(struct targ_softc *softc, union ccb *ccb) 96039213Sgibbs{ 961107178Snjl CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("targfreeccb descr %p and\n", 962107178Snjl ccb->ccb_h.targ_descr)); 963184205Sdes free(ccb->ccb_h.targ_descr, M_TARG); 96439213Sgibbs 965107178Snjl switch (ccb->ccb_h.func_code) { 96639213Sgibbs case XPT_ACCEPT_TARGET_IO: 967107178Snjl case XPT_IMMED_NOTIFY: 968255120Smav case XPT_IMMEDIATE_NOTIFY: 969107178Snjl CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("freeing ccb %p\n", ccb)); 970184205Sdes free(ccb, M_TARG); 971107178Snjl break; 972107178Snjl default: 973107178Snjl /* Send back CCB if we got it from the periph */ 974107178Snjl if (XPT_FC_IS_QUEUED(ccb)) { 975107178Snjl CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, 976107178Snjl ("returning queued ccb %p\n", ccb)); 977107178Snjl xpt_release_ccb(ccb); 97856595Smjacob } else { 979107178Snjl CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, 980107178Snjl ("freeing ccb %p\n", ccb)); 981184205Sdes free(ccb, M_TARG); 98239213Sgibbs } 98339213Sgibbs break; 98439213Sgibbs } 985107178Snjl} 98639213Sgibbs 987107178Snjlstatic struct targ_cmd_descr * 988107178Snjltarggetdescr(struct targ_softc *softc) 989107178Snjl{ 990107178Snjl struct targ_cmd_descr *descr; 99139213Sgibbs 992184205Sdes descr = malloc(sizeof(*descr), M_TARG, 993197332Smjacob M_NOWAIT); 994197332Smjacob if (descr) { 995197332Smjacob descr->mapinfo.num_bufs_used = 0; 996197332Smjacob } 997107178Snjl return (descr); 998107178Snjl} 99939213Sgibbs 1000107178Snjlstatic void 1001107178Snjltarginit(void) 1002107178Snjl{ 1003228481Sed struct cdev *dev; 100456595Smjacob 1005228481Sed /* Add symbolic link to targ0 for compatibility. */ 1006228481Sed dev = make_dev(&targ_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "targ"); 1007228481Sed make_dev_alias(dev, "targ0"); 1008107178Snjl} 100956595Smjacob 1010107178Snjlstatic void 1011107178Snjltargasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 1012107178Snjl{ 1013107178Snjl /* All events are handled in usermode by INOTs */ 1014107178Snjl panic("targasync() called, should be an INOT instead"); 1015107178Snjl} 101680574Smjacob 1017107178Snjl/* Cancel all pending requests and CCBs awaiting work. */ 1018107178Snjlstatic void 1019107178Snjlabort_all_pending(struct targ_softc *softc) 1020107178Snjl{ 1021107178Snjl struct targ_cmd_descr *descr; 1022107178Snjl struct ccb_abort cab; 1023107178Snjl struct ccb_hdr *ccb_h; 102480574Smjacob 1025107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n")); 102639213Sgibbs 1027107178Snjl /* First abort the descriptors awaiting resources */ 1028107178Snjl while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) { 1029107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 1030107178Snjl ("Aborting descr from workq %p\n", descr)); 1031107178Snjl TAILQ_REMOVE(&softc->work_queue, descr, tqe); 1032107178Snjl TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe); 1033107178Snjl } 103439213Sgibbs 1035107178Snjl /* 1036107178Snjl * Then abort all pending CCBs. 1037107178Snjl * targdone() will return the aborted CCB via user_ccb_queue 1038107178Snjl */ 1039198382Smav xpt_setup_ccb(&cab.ccb_h, softc->path, CAM_PRIORITY_NORMAL); 1040107178Snjl cab.ccb_h.func_code = XPT_ABORT; 1041107178Snjl cab.ccb_h.status = CAM_REQ_CMP_ERR; 1042107178Snjl TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, periph_links.tqe) { 1043107178Snjl CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 1044107178Snjl ("Aborting pending CCB %p\n", ccb_h)); 1045107178Snjl cab.abort_ccb = (union ccb *)ccb_h; 1046107178Snjl xpt_action((union ccb *)&cab); 1047107178Snjl if (cab.ccb_h.status != CAM_REQ_CMP) { 1048164906Smjacob xpt_print(cab.ccb_h.path, 1049164906Smjacob "Unable to abort CCB, status %#x\n", 1050164906Smjacob cab.ccb_h.status); 105139213Sgibbs } 1052107178Snjl } 105339213Sgibbs 1054107178Snjl /* If we aborted at least one pending CCB ok, wait for it. */ 1055107178Snjl if (cab.ccb_h.status == CAM_REQ_CMP) { 1056260387Sscottl cam_periph_sleep(softc->periph, &softc->pending_ccb_queue, 1057107178Snjl PRIBIO | PCATCH, "tgabrt", 0); 105839213Sgibbs } 105949929Sgibbs 1060107178Snjl /* If we aborted anything from the work queue, wakeup user. */ 1061107178Snjl if (!TAILQ_EMPTY(&softc->user_ccb_queue) 1062197332Smjacob || !TAILQ_EMPTY(&softc->abort_queue)) { 1063197332Smjacob cam_periph_unlock(softc->periph); 1064107178Snjl notify_user(softc); 1065197332Smjacob cam_periph_lock(softc->periph); 1066197332Smjacob } 106739213Sgibbs} 106839213Sgibbs 1069107178Snjl/* Notify the user that data is ready */ 107039213Sgibbsstatic void 1071107178Snjlnotify_user(struct targ_softc *softc) 107239213Sgibbs{ 107339213Sgibbs /* 1074107178Snjl * Notify users sleeping via poll(), kqueue(), and 1075107178Snjl * blocking read(). 107639213Sgibbs */ 1077122352Stanimura selwakeuppri(&softc->read_select, PRIBIO); 1078158883Smjacob KNOTE_UNLOCKED(&softc->read_select.si_note, 0); 1079107178Snjl wakeup(&softc->user_ccb_queue); 108039213Sgibbs} 108139213Sgibbs 1082107178Snjl/* Convert CAM status to errno values */ 1083107178Snjlstatic int 1084107178Snjltargcamstatus(cam_status status) 108549929Sgibbs{ 1086107178Snjl switch (status & CAM_STATUS_MASK) { 1087107178Snjl case CAM_REQ_CMP: /* CCB request completed without error */ 1088107178Snjl return (0); 1089107178Snjl case CAM_REQ_INPROG: /* CCB request is in progress */ 1090107178Snjl return (EINPROGRESS); 1091107178Snjl case CAM_REQ_CMP_ERR: /* CCB request completed with an error */ 1092107178Snjl return (EIO); 1093107178Snjl case CAM_PROVIDE_FAIL: /* Unable to provide requested capability */ 1094107178Snjl return (ENOTTY); 1095107178Snjl case CAM_FUNC_NOTAVAIL: /* The requested function is not available */ 1096107178Snjl return (ENOTSUP); 1097107178Snjl case CAM_LUN_ALRDY_ENA: /* LUN is already enabled for target mode */ 1098107178Snjl return (EADDRINUSE); 1099107178Snjl case CAM_PATH_INVALID: /* Supplied Path ID is invalid */ 1100107178Snjl case CAM_DEV_NOT_THERE: /* SCSI Device Not Installed/there */ 1101107178Snjl return (ENOENT); 1102107178Snjl case CAM_REQ_ABORTED: /* CCB request aborted by the host */ 1103107178Snjl return (ECANCELED); 1104107178Snjl case CAM_CMD_TIMEOUT: /* Command timeout */ 1105107178Snjl return (ETIMEDOUT); 1106107178Snjl case CAM_REQUEUE_REQ: /* Requeue to preserve transaction ordering */ 1107107178Snjl return (EAGAIN); 1108107178Snjl case CAM_REQ_INVALID: /* CCB request was invalid */ 1109107178Snjl return (EINVAL); 1110107178Snjl case CAM_RESRC_UNAVAIL: /* Resource Unavailable */ 1111107178Snjl return (ENOMEM); 1112210779Sbcr case CAM_BUSY: /* CAM subsystem is busy */ 1113107178Snjl case CAM_UA_ABORT: /* Unable to abort CCB request */ 1114107178Snjl return (EBUSY); 111549929Sgibbs default: 1116107178Snjl return (ENXIO); 111749929Sgibbs } 111849929Sgibbs} 111949929Sgibbs 1120107178Snjlstatic size_t 1121107178Snjltargccblen(xpt_opcode func_code) 112239213Sgibbs{ 1123107178Snjl int len; 112449929Sgibbs 1125107178Snjl /* Codes we expect to see as a target */ 1126107178Snjl switch (func_code) { 1127107178Snjl case XPT_CONT_TARGET_IO: 1128107178Snjl case XPT_SCSI_IO: 1129107178Snjl len = sizeof(struct ccb_scsiio); 113049929Sgibbs break; 1131107178Snjl case XPT_ACCEPT_TARGET_IO: 1132107178Snjl len = sizeof(struct ccb_accept_tio); 113349929Sgibbs break; 1134107178Snjl case XPT_IMMED_NOTIFY: 1135107178Snjl len = sizeof(struct ccb_immed_notify); 113649929Sgibbs break; 1137255120Smav case XPT_IMMEDIATE_NOTIFY: 1138255120Smav len = sizeof(struct ccb_immediate_notify); 1139255120Smav break; 1140107178Snjl case XPT_REL_SIMQ: 1141107178Snjl len = sizeof(struct ccb_relsim); 114249929Sgibbs break; 1143107178Snjl case XPT_PATH_INQ: 1144107178Snjl len = sizeof(struct ccb_pathinq); 114549929Sgibbs break; 1146107178Snjl case XPT_DEBUG: 1147107178Snjl len = sizeof(struct ccb_debug); 114849929Sgibbs break; 1149107178Snjl case XPT_ABORT: 1150107178Snjl len = sizeof(struct ccb_abort); 115149929Sgibbs break; 1152107178Snjl case XPT_EN_LUN: 1153107178Snjl len = sizeof(struct ccb_en_lun); 1154107178Snjl break; 115549929Sgibbs default: 1156107178Snjl len = sizeof(union ccb); 1157107178Snjl break; 115849929Sgibbs } 115949929Sgibbs 1160107178Snjl return (len); 116139213Sgibbs} 1162