scsi_target.c revision 111579
1257251Skib/* 2257251Skib * Generic SCSI Target Kernel Mode Driver 3257251Skib * 4257251Skib * Copyright (c) 2002 Nate Lawson. 5257251Skib * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs. 6257251Skib * All rights reserved. 7257251Skib * 8257251Skib * Redistribution and use in source and binary forms, with or without 9257251Skib * modification, are permitted provided that the following conditions 10257251Skib * are met: 11257251Skib * 1. Redistributions of source code must retain the above copyright 12257251Skib * notice, this list of conditions, and the following disclaimer, 13257251Skib * without modification, immediately at the beginning of the file. 14257251Skib * 2. The name of the author may not be used to endorse or promote products 15257251Skib * derived from this software without specific prior written permission. 16257251Skib * 17257251Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18257251Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19257251Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20257251Skib * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21257251Skib * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22257251Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23257251Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24257251Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25257251Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26257251Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27257251Skib * SUCH DAMAGE. 28257251Skib * 29257251Skib * $FreeBSD: head/sys/cam/scsi/scsi_target.c 111571 2003-02-26 20:53:28Z phk $ 30257251Skib */ 31257251Skib 32257251Skib#include <sys/param.h> 33257251Skib#include <sys/systm.h> 34257251Skib#include <sys/kernel.h> 35257251Skib#include <sys/conf.h> 36257251Skib#include <sys/malloc.h> 37257251Skib#include <sys/poll.h> 38257251Skib#include <sys/vnode.h> 39257251Skib#include <sys/lock.h> 40257251Skib#include <sys/mutex.h> 41257251Skib#include <sys/devicestat.h> 42257251Skib 43257251Skib#include <cam/cam.h> 44257251Skib#include <cam/cam_ccb.h> 45257251Skib#include <cam/cam_periph.h> 46257251Skib#include <cam/cam_xpt_periph.h> 47257251Skib#include <cam/scsi/scsi_targetio.h> 48257251Skib 49257251Skib/* Transaction information attached to each CCB sent by the user */ 50257251Skibstruct targ_cmd_descr { 51257251Skib struct cam_periph_map_info mapinfo; 52280260Skib TAILQ_ENTRY(targ_cmd_descr) tqe; 53257251Skib union ccb *user_ccb; 54257251Skib int priority; 55257251Skib int func_code; 56257251Skib}; 57257251Skib 58257251Skib/* Offset into the private CCB area for storing our descriptor */ 59257251Skib#define targ_descr periph_priv.entries[1].ptr 60257251Skib 61257251SkibTAILQ_HEAD(descr_queue, targ_cmd_descr); 62257251Skib 63257251Skibtypedef enum { 64257251Skib TARG_STATE_RESV = 0x00, /* Invalid state */ 65257251Skib TARG_STATE_OPENED = 0x01, /* Device opened, softc initialized */ 66257251Skib TARG_STATE_LUN_ENABLED = 0x02 /* Device enabled for a path */ 67257251Skib} targ_state; 68257251Skib 69257251Skib/* Per-instance device software context */ 70257251Skibstruct targ_softc { 71257251Skib /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */ 72257251Skib struct ccb_queue pending_ccb_queue; 73257251Skib 74257251Skib /* Command descriptors awaiting CTIO resources from the XPT */ 75257251Skib struct descr_queue work_queue; 76257251Skib 77257251Skib /* Command descriptors that have been aborted back to the user. */ 78257251Skib struct descr_queue abort_queue; 79257251Skib 80257251Skib /* 81257251Skib * Queue of CCBs that have been copied out to userland, but our 82329942Smarkj * userland daemon has not yet seen. 83257251Skib */ 84257251Skib struct ccb_queue user_ccb_queue; 85257251Skib 86257251Skib struct cam_periph *periph; 87284869Skib struct cam_path *path; 88257251Skib targ_state state; 89257251Skib struct selinfo read_select; 90257251Skib struct devstat device_stats; 91257251Skib struct mtx mtx; 92257251Skib}; 93257251Skib 94257251Skibstatic d_open_t targopen; 95257251Skibstatic d_close_t targclose; 96257512Skibstatic d_read_t targread; 97284869Skibstatic d_write_t targwrite; 98284869Skibstatic d_ioctl_t targioctl; 99257512Skibstatic d_poll_t targpoll; 100257251Skibstatic d_kqfilter_t targkqfilter; 101257251Skibstatic void targreadfiltdetach(struct knote *kn); 102257251Skibstatic int targreadfilt(struct knote *kn, long hint); 103257251Skibstatic struct filterops targread_filtops = 104284869Skib { 1, NULL, targreadfiltdetach, targreadfilt }; 105257251Skib 106257251Skib#define TARG_CDEV_MAJOR 65 107284869Skibstatic struct cdevsw targ_cdevsw = { 108284869Skib /* open */ targopen, 109284869Skib /* close */ targclose, 110284869Skib /* read */ targread, 111257251Skib /* write */ targwrite, 112257251Skib /* ioctl */ targioctl, 113257251Skib /* poll */ targpoll, 114257251Skib /* mmap */ nommap, 115257251Skib /* strategy */ nostrategy, 116257251Skib /* name */ "targ", 117257251Skib /* maj */ TARG_CDEV_MAJOR, 118257251Skib /* dump */ nodump, 119257251Skib /* psize */ nopsize, 120257251Skib /* flags */ D_KQFILTER, 121257251Skib /* kqfilter */ targkqfilter 122257251Skib}; 123257251Skib 124257251Skibstatic cam_status targendislun(struct cam_path *path, int enable, 125257251Skib int grp6_len, int grp7_len); 126257251Skibstatic cam_status targenable(struct targ_softc *softc, 127257251Skib struct cam_path *path, 128257251Skib int grp6_len, int grp7_len); 129257251Skibstatic cam_status targdisable(struct targ_softc *softc); 130257251Skibstatic periph_ctor_t targctor; 131257251Skibstatic periph_dtor_t targdtor; 132257251Skibstatic periph_start_t targstart; 133257251Skibstatic int targusermerge(struct targ_softc *softc, 134257251Skib struct targ_cmd_descr *descr, 135257251Skib union ccb *ccb); 136257251Skibstatic int targsendccb(struct targ_softc *softc, union ccb *ccb, 137257251Skib struct targ_cmd_descr *descr); 138257251Skibstatic void targdone(struct cam_periph *periph, 139257251Skib union ccb *done_ccb); 140257251Skibstatic int targreturnccb(struct targ_softc *softc, 141257251Skib union ccb *ccb); 142257251Skibstatic union ccb * targgetccb(struct targ_softc *softc, xpt_opcode type, 143257251Skib int priority); 144257251Skibstatic void targfreeccb(struct targ_softc *softc, union ccb *ccb); 145257251Skibstatic struct targ_cmd_descr * 146257251Skib targgetdescr(struct targ_softc *softc); 147257251Skibstatic periph_init_t targinit; 148257251Skibstatic void targclone(void *arg, char *name, int namelen, 149257251Skib dev_t *dev); 150257251Skibstatic void targasync(void *callback_arg, u_int32_t code, 151257251Skib struct cam_path *path, void *arg); 152257251Skibstatic void abort_all_pending(struct targ_softc *softc); 153257251Skibstatic void notify_user(struct targ_softc *softc); 154257251Skibstatic int targcamstatus(cam_status status); 155257251Skibstatic size_t targccblen(xpt_opcode func_code); 156257251Skib 157257251Skibstatic struct periph_driver targdriver = 158257251Skib{ 159257251Skib targinit, "targ", 160257251Skib TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0 161284869Skib}; 162257251SkibPERIPHDRIVER_DECLARE(targ, targdriver); 163257251Skib 164257251Skibstatic struct mtx targ_mtx; 165284869Skib#define TARG_LOCK(softc) mtx_lock(&(softc)->mtx) 166284869Skib#define TARG_UNLOCK(softc) mtx_unlock(&(softc)->mtx) 167257251Skib 168257251Skibstatic MALLOC_DEFINE(M_TARG, "TARG", "TARG data"); 169257251Skib 170257251Skib/* Create softc and initialize it. Only one proc can open each targ device. */ 171257251Skibstatic int 172257251Skibtargopen(dev_t dev, int flags, int fmt, struct thread *td) 173284869Skib{ 174257251Skib struct targ_softc *softc; 175257251Skib 176257251Skib mtx_lock(&targ_mtx); 177257251Skib if (dev->si_drv1 != 0) { 178284869Skib mtx_unlock(&targ_mtx); 179284869Skib return (EBUSY); 180284869Skib } 181284869Skib 182284869Skib /* Mark device busy before any potentially blocking operations */ 183257251Skib dev->si_drv1 = (void *)~0; 184284869Skib mtx_unlock(&targ_mtx); 185257251Skib 186257251Skib /* Create the targ device, allocate its softc, initialize it */ 187257251Skib if ((dev->si_flags & SI_NAMED) == 0) { 188257251Skib make_dev(&targ_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 0600, 189257251Skib "targ%d", dev2unit(dev)); 190257251Skib } 191257251Skib MALLOC(softc, struct targ_softc *, sizeof(*softc), M_TARG, 192257251Skib M_WAITOK | M_ZERO); 193257251Skib dev->si_drv1 = softc; 194257251Skib softc->state = TARG_STATE_OPENED; 195257251Skib softc->periph = NULL; 196257251Skib softc->path = NULL; 197257251Skib mtx_init(&softc->mtx, devtoname(dev), "targ cdev", MTX_DEF); 198257251Skib 199257251Skib TAILQ_INIT(&softc->pending_ccb_queue); 200257251Skib TAILQ_INIT(&softc->work_queue); 201317248Skib TAILQ_INIT(&softc->abort_queue); 202257251Skib TAILQ_INIT(&softc->user_ccb_queue); 203257251Skib 204257251Skib return (0); 205257251Skib} 206257251Skib 207257251Skib/* Disable LUN if enabled and teardown softc */ 208257251Skibstatic int 209284869Skibtargclose(dev_t dev, int flag, int fmt, struct thread *td) 210257251Skib{ 211257251Skib struct targ_softc *softc; 212257251Skib int error; 213284869Skib 214284869Skib softc = (struct targ_softc *)dev->si_drv1; 215284869Skib TARG_LOCK(softc); 216257251Skib error = targdisable(softc); 217284869Skib if (error == CAM_REQ_CMP) { 218257251Skib dev->si_drv1 = 0; 219257251Skib mtx_lock(&targ_mtx); 220257251Skib if (softc->periph != NULL) { 221257251Skib cam_periph_invalidate(softc->periph); 222284869Skib softc->periph = NULL; 223257251Skib } 224257251Skib mtx_unlock(&targ_mtx); 225257251Skib TARG_UNLOCK(softc); 226284869Skib mtx_destroy(&softc->mtx); 227284869Skib destroy_dev(dev); 228257251Skib FREE(softc, M_TARG); 229284869Skib } else { 230257251Skib TARG_UNLOCK(softc); 231257251Skib } 232257251Skib return (error); 233284869Skib} 234257251Skib 235257251Skib/* Enable/disable LUNs, set debugging level */ 236257251Skibstatic int 237284869Skibtargioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 238284869Skib{ 239257251Skib struct targ_softc *softc; 240284869Skib cam_status status; 241284869Skib 242284869Skib softc = (struct targ_softc *)dev->si_drv1; 243257251Skib 244257251Skib switch (cmd) { 245257251Skib case TARGIOCENABLE: 246284869Skib { 247257251Skib struct ioc_enable_lun *new_lun; 248284869Skib struct cam_path *path; 249257251Skib 250284869Skib new_lun = (struct ioc_enable_lun *)addr; 251284869Skib status = xpt_create_path(&path, /*periph*/NULL, 252257251Skib new_lun->path_id, 253257251Skib new_lun->target_id, 254284869Skib new_lun->lun_id); 255257251Skib if (status != CAM_REQ_CMP) { 256284869Skib printf("Couldn't create path, status %#x\n", status); 257284869Skib break; 258284869Skib } 259284869Skib TARG_LOCK(softc); 260257251Skib status = targenable(softc, path, new_lun->grp6_len, 261257251Skib new_lun->grp7_len); 262257251Skib TARG_UNLOCK(softc); 263284869Skib xpt_free_path(path); 264257251Skib break; 265257251Skib } 266257251Skib case TARGIOCDISABLE: 267284869Skib TARG_LOCK(softc); 268284869Skib status = targdisable(softc); 269257251Skib TARG_UNLOCK(softc); 270284869Skib break; 271284869Skib case TARGIOCDEBUG: 272284869Skib { 273257251Skib#ifdef CAMDEBUG 274284869Skib struct ccb_debug cdbg; 275284869Skib 276284869Skib bzero(&cdbg, sizeof cdbg); 277257251Skib if (*((int *)addr) != 0) 278284869Skib cdbg.flags = CAM_DEBUG_PERIPH; 279284869Skib else 280284869Skib cdbg.flags = CAM_DEBUG_NONE; 281284869Skib xpt_setup_ccb(&cdbg.ccb_h, softc->path, /*priority*/0); 282257251Skib cdbg.ccb_h.func_code = XPT_DEBUG; 283284869Skib cdbg.ccb_h.cbfcnp = targdone; 284284869Skib 285284869Skib /* If no periph available, disallow debugging changes */ 286257251Skib TARG_LOCK(softc); 287284869Skib if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { 288284869Skib status = CAM_DEV_NOT_THERE; 289257251Skib TARG_UNLOCK(softc); 290284869Skib break; 291284869Skib } 292284869Skib xpt_action((union ccb *)&cdbg); 293257251Skib TARG_UNLOCK(softc); 294257251Skib status = cdbg.ccb_h.status & CAM_STATUS_MASK; 295257251Skib#else 296257251Skib status = CAM_FUNC_NOTAVAIL; 297284869Skib#endif 298257251Skib break; 299281254Skib } 300257251Skib default: 301257251Skib status = CAM_PROVIDE_FAIL; 302257251Skib break; 303257251Skib } 304257251Skib 305257251Skib return (targcamstatus(status)); 306257251Skib} 307257251Skib 308257251Skib/* Writes are always ready, reads wait for user_ccb_queue or abort_queue */ 309257251Skibstatic int 310257251Skibtargpoll(dev_t dev, int poll_events, struct thread *td) 311257251Skib{ 312257251Skib struct targ_softc *softc; 313257251Skib int revents; 314257251Skib 315257251Skib softc = (struct targ_softc *)dev->si_drv1; 316281254Skib 317281254Skib /* Poll for write() is always ok. */ 318257251Skib revents = poll_events & (POLLOUT | POLLWRNORM); 319257251Skib if ((poll_events & (POLLIN | POLLRDNORM)) != 0) { 320257251Skib /* Poll for read() depends on user and abort queues. */ 321281254Skib TARG_LOCK(softc); 322281254Skib if (!TAILQ_EMPTY(&softc->user_ccb_queue) || 323257251Skib !TAILQ_EMPTY(&softc->abort_queue)) { 324257251Skib revents |= poll_events & (POLLIN | POLLRDNORM); 325257251Skib } 326281254Skib /* Only sleep if the user didn't poll for write. */ 327281254Skib if (revents == 0) 328281254Skib selrecord(td, &softc->read_select); 329257251Skib TARG_UNLOCK(softc); 330298433Spfg } 331298433Spfg 332257251Skib return (revents); 333257251Skib} 334281254Skib 335281254Skibstatic int 336281254Skibtargkqfilter(dev_t dev, struct knote *kn) 337281254Skib{ 338280196Skib struct targ_softc *softc; 339257251Skib 340257251Skib softc = (struct targ_softc *)dev->si_drv1; 341257251Skib kn->kn_hook = (caddr_t)softc; 342257251Skib kn->kn_fop = &targread_filtops; 343257251Skib TARG_LOCK(softc); 344280196Skib SLIST_INSERT_HEAD(&softc->read_select.si_note, kn, kn_selnext); 345280196Skib TARG_UNLOCK(softc); 346257251Skib return (0); 347257251Skib} 348257251Skib 349257251Skibstatic void 350257251Skibtargreadfiltdetach(struct knote *kn) 351257251Skib{ 352257251Skib struct targ_softc *softc; 353257251Skib 354257251Skib softc = (struct targ_softc *)kn->kn_hook; 355257251Skib TARG_LOCK(softc); 356257251Skib SLIST_REMOVE(&softc->read_select.si_note, kn, knote, kn_selnext); 357257251Skib TARG_UNLOCK(softc); 358257251Skib} 359257251Skib 360257251Skib/* Notify the user's kqueue when the user queue or abort queue gets a CCB */ 361257251Skibstatic int 362257251Skibtargreadfilt(struct knote *kn, long hint) 363257251Skib{ 364257251Skib struct targ_softc *softc; 365257251Skib int retval; 366257251Skib 367257251Skib softc = (struct targ_softc *)kn->kn_hook; 368257251Skib TARG_LOCK(softc); 369257251Skib retval = !TAILQ_EMPTY(&softc->user_ccb_queue) || 370257251Skib !TAILQ_EMPTY(&softc->abort_queue); 371257251Skib TARG_UNLOCK(softc); 372257251Skib return (retval); 373257251Skib} 374257251Skib 375257251Skib/* Send the HBA the enable/disable message */ 376284869Skibstatic cam_status 377257251Skibtargendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len) 378280195Skib{ 379280195Skib struct ccb_en_lun en_ccb; 380257251Skib cam_status status; 381284869Skib 382257251Skib /* Tell the lun to begin answering selects */ 383257251Skib xpt_setup_ccb(&en_ccb.ccb_h, path, /*priority*/1); 384257251Skib en_ccb.ccb_h.func_code = XPT_EN_LUN; 385257251Skib /* Don't need support for any vendor specific commands */ 386257251Skib en_ccb.grp6_len = grp6_len; 387257251Skib en_ccb.grp7_len = grp7_len; 388257251Skib en_ccb.enable = enable ? 1 : 0; 389257251Skib xpt_action((union ccb *)&en_ccb); 390284869Skib status = en_ccb.ccb_h.status & CAM_STATUS_MASK; 391257251Skib if (status != CAM_REQ_CMP) { 392284869Skib xpt_print_path(path); 393257251Skib printf("%sable lun CCB rejected, status %#x\n", 394257251Skib enable ? "en" : "dis", status); 395284869Skib } 396257251Skib return (status); 397257251Skib} 398284869Skib 399284869Skib/* Enable target mode on a LUN, given its path */ 400257251Skibstatic cam_status 401257251Skibtargenable(struct targ_softc *softc, struct cam_path *path, int grp6_len, 402284869Skib int grp7_len) 403257251Skib{ 404257251Skib struct cam_periph *periph; 405257251Skib struct ccb_pathinq cpi; 406257251Skib cam_status status; 407257251Skib 408257251Skib if ((softc->state & TARG_STATE_LUN_ENABLED) != 0) 409257251Skib return (CAM_LUN_ALRDY_ENA); 410257251Skib 411257251Skib /* Make sure SIM supports target mode */ 412257251Skib xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1); 413257251Skib cpi.ccb_h.func_code = XPT_PATH_INQ; 414257251Skib xpt_action((union ccb *)&cpi); 415257251Skib status = cpi.ccb_h.status & CAM_STATUS_MASK; 416257251Skib if (status != CAM_REQ_CMP) { 417257251Skib printf("pathinq failed, status %#x\n", status); 418257251Skib goto enable_fail; 419281254Skib } 420257251Skib if ((cpi.target_sprt & PIT_PROCESSOR) == 0) { 421257251Skib printf("controller does not support target mode\n"); 422257251Skib status = CAM_FUNC_NOTAVAIL; 423257251Skib goto enable_fail; 424257251Skib } 425257251Skib 426257251Skib /* Destroy any periph on our path if it is disabled */ 427257251Skib mtx_lock(&targ_mtx); 428257251Skib periph = cam_periph_find(path, "targ"); 429257251Skib if (periph != NULL) { 430257251Skib struct targ_softc *del_softc; 431257251Skib 432257251Skib del_softc = (struct targ_softc *)periph->softc; 433257251Skib if ((del_softc->state & TARG_STATE_LUN_ENABLED) == 0) { 434257251Skib cam_periph_invalidate(del_softc->periph); 435257251Skib del_softc->periph = NULL; 436257251Skib } else { 437257251Skib printf("Requested path still in use by targ%d\n", 438257251Skib periph->unit_number); 439284869Skib mtx_unlock(&targ_mtx); 440284869Skib status = CAM_LUN_ALRDY_ENA; 441257251Skib goto enable_fail; 442257251Skib } 443284869Skib } 444284869Skib 445257251Skib /* Create a periph instance attached to this path */ 446257251Skib status = cam_periph_alloc(targctor, NULL, targdtor, targstart, 447257251Skib "targ", CAM_PERIPH_BIO, path, targasync, 0, softc); 448257251Skib mtx_unlock(&targ_mtx); 449257251Skib if (status != CAM_REQ_CMP) { 450257251Skib printf("cam_periph_alloc failed, status %#x\n", status); 451257251Skib goto enable_fail; 452284869Skib } 453257251Skib 454257251Skib /* Ensure that the periph now exists. */ 455257251Skib if (cam_periph_find(path, "targ") == NULL) { 456257251Skib panic("targenable: succeeded but no periph?"); 457257251Skib /* NOTREACHED */ 458257251Skib } 459257251Skib 460257251Skib /* Send the enable lun message */ 461257251Skib status = targendislun(path, /*enable*/1, grp6_len, grp7_len); 462257251Skib if (status != CAM_REQ_CMP) { 463257251Skib printf("enable lun failed, status %#x\n", status); 464257251Skib goto enable_fail; 465284869Skib } 466284869Skib softc->state |= TARG_STATE_LUN_ENABLED; 467284869Skib 468257251Skibenable_fail: 469284869Skib return (status); 470257251Skib} 471257251Skib 472257251Skib/* Disable this softc's target instance if enabled */ 473257251Skibstatic cam_status 474257251Skibtargdisable(struct targ_softc *softc) 475284869Skib{ 476257251Skib cam_status status; 477281254Skib 478257251Skib if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) 479257251Skib return (CAM_REQ_CMP); 480257251Skib 481257251Skib CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targdisable\n")); 482284869Skib 483284869Skib /* Abort any ccbs pending on the controller */ 484257251Skib abort_all_pending(softc); 485257251Skib 486284869Skib /* Disable this lun */ 487257251Skib status = targendislun(softc->path, /*enable*/0, 488281254Skib /*grp6_len*/0, /*grp7_len*/0); 489257251Skib if (status == CAM_REQ_CMP) 490257251Skib softc->state &= ~TARG_STATE_LUN_ENABLED; 491257251Skib else 492257251Skib printf("Disable lun failed, status %#x\n", status); 493257251Skib 494257251Skib return (status); 495284869Skib} 496257251Skib 497257251Skib/* Initialize a periph (called from cam_periph_alloc) */ 498257251Skibstatic cam_status 499257251Skibtargctor(struct cam_periph *periph, void *arg) 500257251Skib{ 501257251Skib struct targ_softc *softc; 502284869Skib 503257251Skib /* Store pointer to softc for periph-driven routines */ 504257251Skib softc = (struct targ_softc *)arg; 505257251Skib periph->softc = softc; 506257251Skib softc->periph = periph; 507257251Skib softc->path = periph->path; 508257251Skib return (CAM_REQ_CMP); 509257251Skib} 510257251Skib 511284869Skibstatic void 512257251Skibtargdtor(struct cam_periph *periph) 513257251Skib{ 514257251Skib struct targ_softc *softc; 515257251Skib struct ccb_hdr *ccb_h; 516257251Skib struct targ_cmd_descr *descr; 517284869Skib 518257251Skib softc = (struct targ_softc *)periph->softc; 519257251Skib 520257251Skib /* 521257251Skib * targdisable() aborts CCBs back to the user and leaves them 522257251Skib * on user_ccb_queue and abort_queue in case the user is still 523257251Skib * interested in them. We free them now. 524284869Skib */ 525257251Skib while ((ccb_h = TAILQ_FIRST(&softc->user_ccb_queue)) != NULL) { 526257251Skib TAILQ_REMOVE(&softc->user_ccb_queue, ccb_h, periph_links.tqe); 527284869Skib targfreeccb(softc, (union ccb *)ccb_h); 528284869Skib } 529257251Skib while ((descr = TAILQ_FIRST(&softc->abort_queue)) != NULL) { 530284869Skib TAILQ_REMOVE(&softc->abort_queue, descr, tqe); 531257251Skib FREE(descr, M_TARG); 532257251Skib } 533257251Skib 534257251Skib softc->periph = NULL; 535257251Skib softc->path = NULL; 536257251Skib periph->softc = NULL; 537257251Skib} 538257251Skib 539257251Skib/* Receive CCBs from user mode proc and send them to the HBA */ 540257251Skibstatic int 541257251Skibtargwrite(dev_t dev, struct uio *uio, int ioflag) 542257251Skib{ 543257251Skib union ccb *user_ccb; 544257251Skib struct targ_softc *softc; 545257251Skib struct targ_cmd_descr *descr; 546257251Skib int write_len, error; 547257251Skib int func_code, priority; 548257251Skib 549257251Skib softc = (struct targ_softc *)dev->si_drv1; 550257251Skib write_len = error = 0; 551257251Skib CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 552257251Skib ("write - uio_resid %d\n", uio->uio_resid)); 553257251Skib while (uio->uio_resid >= sizeof(user_ccb) && error == 0) { 554257251Skib union ccb *ccb; 555257251Skib int error; 556257251Skib 557257251Skib error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); 558284869Skib if (error != 0) { 559257251Skib CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 560257251Skib ("write - uiomove failed (%d)\n", error)); 561257251Skib break; 562284869Skib } 563257251Skib priority = fuword(&user_ccb->ccb_h.pinfo.priority); 564257251Skib if (priority == -1) { 565257251Skib error = EINVAL; 566284869Skib break; 567257251Skib } 568284869Skib func_code = fuword(&user_ccb->ccb_h.func_code); 569257251Skib switch (func_code) { 570257251Skib case XPT_ACCEPT_TARGET_IO: 571257251Skib case XPT_IMMED_NOTIFY: 572257251Skib ccb = targgetccb(softc, func_code, priority); 573284869Skib descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr; 574284869Skib descr->user_ccb = user_ccb; 575257251Skib descr->func_code = func_code; 576257251Skib CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 577257251Skib ("Sent ATIO/INOT (%p)\n", user_ccb)); 578257251Skib xpt_action(ccb); 579257251Skib TARG_LOCK(softc); 580257251Skib TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, 581257251Skib &ccb->ccb_h, 582257251Skib periph_links.tqe); 583257251Skib TARG_UNLOCK(softc); 584257251Skib break; 585257251Skib default: 586257251Skib if ((func_code & XPT_FC_QUEUED) != 0) { 587257251Skib CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 588257251Skib ("Sending queued ccb %#x (%p)\n", 589257251Skib func_code, user_ccb)); 590257251Skib descr = targgetdescr(softc); 591284869Skib descr->user_ccb = user_ccb; 592257251Skib descr->priority = priority; 593257251Skib descr->func_code = func_code; 594284869Skib TARG_LOCK(softc); 595257251Skib TAILQ_INSERT_TAIL(&softc->work_queue, 596257251Skib descr, tqe); 597284869Skib TARG_UNLOCK(softc); 598257251Skib xpt_schedule(softc->periph, priority); 599284869Skib } else { 600257251Skib CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 601257251Skib ("Sending inline ccb %#x (%p)\n", 602257251Skib func_code, user_ccb)); 603284869Skib ccb = targgetccb(softc, func_code, priority); 604257251Skib descr = (struct targ_cmd_descr *) 605257251Skib ccb->ccb_h.targ_descr; 606257251Skib descr->user_ccb = user_ccb; 607257512Skib descr->priority = priority; 608284869Skib descr->func_code = func_code; 609257251Skib if (targusermerge(softc, descr, ccb) != EFAULT) 610257251Skib targsendccb(softc, ccb, descr); 611257251Skib targreturnccb(softc, ccb); 612284869Skib } 613257251Skib break; 614257251Skib } 615284869Skib write_len += sizeof(user_ccb); 616257251Skib } 617284869Skib 618284869Skib /* 619284869Skib * If we've successfully taken in some amount of 620257251Skib * data, return success for that data first. If 621257251Skib * an error is persistent, it will be reported 622257251Skib * on the next write. 623284869Skib */ 624257251Skib if (error != 0 && write_len == 0) 625284869Skib return (error); 626257251Skib if (write_len == 0 && uio->uio_resid != 0) 627257251Skib return (ENOSPC); 628257251Skib return (0); 629284869Skib} 630284869Skib 631284869Skib/* Process requests (descrs) via the periph-supplied CCBs */ 632257251Skibstatic void 633257251Skibtargstart(struct cam_periph *periph, union ccb *start_ccb) 634257251Skib{ 635257251Skib struct targ_softc *softc; 636257251Skib struct targ_cmd_descr *descr, *next_descr; 637257251Skib int error; 638257251Skib 639284869Skib softc = (struct targ_softc *)periph->softc; 640257251Skib CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb)); 641257251Skib 642257251Skib TARG_LOCK(softc); 643284869Skib descr = TAILQ_FIRST(&softc->work_queue); 644284869Skib if (descr == NULL) { 645284869Skib TARG_UNLOCK(softc); 646257251Skib xpt_release_ccb(start_ccb); 647284869Skib } else { 648284869Skib TAILQ_REMOVE(&softc->work_queue, descr, tqe); 649257251Skib next_descr = TAILQ_FIRST(&softc->work_queue); 650257251Skib TARG_UNLOCK(softc); 651257251Skib 652257251Skib /* Initiate a transaction using the descr and supplied CCB */ 653284869Skib error = targusermerge(softc, descr, start_ccb); 654257251Skib if (error == 0) 655257251Skib error = targsendccb(softc, start_ccb, descr); 656257251Skib if (error != 0) { 657284869Skib xpt_print_path(periph->path); 658284869Skib printf("targsendccb failed, err %d\n", error); 659257251Skib xpt_release_ccb(start_ccb); 660284869Skib suword(&descr->user_ccb->ccb_h.status, 661257251Skib CAM_REQ_CMP_ERR); 662284869Skib TARG_LOCK(softc); 663284869Skib TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe); 664257251Skib TARG_UNLOCK(softc); 665257251Skib notify_user(softc); 666257251Skib } 667257251Skib 668257251Skib /* If we have more work to do, stay scheduled */ 669257251Skib if (next_descr != NULL) 670284869Skib xpt_schedule(periph, next_descr->priority); 671257251Skib } 672257251Skib} 673257251Skib 674284869Skibstatic int 675257251Skibtargusermerge(struct targ_softc *softc, struct targ_cmd_descr *descr, 676257251Skib union ccb *ccb) 677257251Skib{ 678257251Skib struct ccb_hdr *u_ccbh, *k_ccbh; 679257251Skib size_t ccb_len; 680257251Skib int error; 681284869Skib 682257251Skib u_ccbh = &descr->user_ccb->ccb_h; 683257251Skib k_ccbh = &ccb->ccb_h; 684257251Skib 685257251Skib /* 686257251Skib * There are some fields in the CCB header that need to be 687284869Skib * preserved, the rest we get from the user ccb. (See xpt_merge_ccb) 688257251Skib */ 689257251Skib xpt_setup_ccb(k_ccbh, softc->path, descr->priority); 690257251Skib k_ccbh->retry_count = fuword(&u_ccbh->retry_count); 691257251Skib k_ccbh->func_code = descr->func_code; 692257251Skib k_ccbh->flags = fuword(&u_ccbh->flags); 693284869Skib k_ccbh->timeout = fuword(&u_ccbh->timeout); 694284869Skib ccb_len = targccblen(k_ccbh->func_code) - sizeof(struct ccb_hdr); 695257251Skib error = copyin(u_ccbh + 1, k_ccbh + 1, ccb_len); 696284869Skib if (error != 0) { 697257251Skib k_ccbh->status = CAM_REQ_CMP_ERR; 698257251Skib return (error); 699257251Skib } 700284869Skib 701257251Skib /* Translate usermode abort_ccb pointer to its kernel counterpart */ 702257251Skib if (k_ccbh->func_code == XPT_ABORT) { 703257251Skib struct ccb_abort *cab; 704284869Skib struct ccb_hdr *ccb_h; 705257251Skib 706257251Skib cab = (struct ccb_abort *)ccb; 707257251Skib TARG_LOCK(softc); 708257251Skib TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, 709257251Skib periph_links.tqe) { 710257251Skib struct targ_cmd_descr *ab_descr; 711257251Skib 712284869Skib ab_descr = (struct targ_cmd_descr *)ccb_h->targ_descr; 713257251Skib if (ab_descr->user_ccb == cab->abort_ccb) { 714257251Skib CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 715257251Skib ("Changing abort for %p to %p\n", 716284869Skib cab->abort_ccb, ccb_h)); 717257251Skib cab->abort_ccb = (union ccb *)ccb_h; 718257251Skib break; 719257251Skib } 720257251Skib } 721257251Skib TARG_UNLOCK(softc); 722284869Skib /* CCB not found, set appropriate status */ 723257251Skib if (ccb_h == NULL) { 724257251Skib k_ccbh->status = CAM_PATH_INVALID; 725257251Skib error = ESRCH; 726257251Skib } 727257251Skib } 728284869Skib 729257251Skib return (error); 730257251Skib} 731284869Skib 732284869Skib/* Build and send a kernel CCB formed from descr->user_ccb */ 733257251Skibstatic int 734257251Skibtargsendccb(struct targ_softc *softc, union ccb *ccb, 735284869Skib struct targ_cmd_descr *descr) 736257251Skib{ 737284869Skib struct cam_periph_map_info *mapinfo; 738257251Skib struct ccb_hdr *ccb_h; 739257251Skib int error; 740 741 ccb_h = &ccb->ccb_h; 742 mapinfo = &descr->mapinfo; 743 mapinfo->num_bufs_used = 0; 744 745 /* 746 * There's no way for the user to have a completion 747 * function, so we put our own completion function in here. 748 * We also stash in a reference to our descriptor so targreturnccb() 749 * can find our mapping info. 750 */ 751 ccb_h->cbfcnp = targdone; 752 ccb_h->targ_descr = descr; 753 754 /* 755 * We only attempt to map the user memory into kernel space 756 * if they haven't passed in a physical memory pointer, 757 * and if there is actually an I/O operation to perform. 758 * Right now cam_periph_mapmem() only supports SCSI and device 759 * match CCBs. For the SCSI CCBs, we only pass the CCB in if 760 * there's actually data to map. cam_periph_mapmem() will do the 761 * right thing, even if there isn't data to map, but since CCBs 762 * without data are a reasonably common occurance (e.g. test unit 763 * ready), it will save a few cycles if we check for it here. 764 */ 765 if (((ccb_h->flags & CAM_DATA_PHYS) == 0) 766 && (((ccb_h->func_code == XPT_CONT_TARGET_IO) 767 && ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE)) 768 || (ccb_h->func_code == XPT_DEV_MATCH))) { 769 770 error = cam_periph_mapmem(ccb, mapinfo); 771 772 /* 773 * cam_periph_mapmem returned an error, we can't continue. 774 * Return the error to the user. 775 */ 776 if (error) { 777 ccb_h->status = CAM_REQ_CMP_ERR; 778 mapinfo->num_bufs_used = 0; 779 return (error); 780 } 781 } 782 783 /* 784 * Once queued on the pending CCB list, this CCB will be protected 785 * by our error recovery handler. 786 */ 787 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb)); 788 if (XPT_FC_IS_QUEUED(ccb)) { 789 TARG_LOCK(softc); 790 TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h, 791 periph_links.tqe); 792 TARG_UNLOCK(softc); 793 } 794 xpt_action(ccb); 795 796 return (0); 797} 798 799/* Completion routine for CCBs (called at splsoftcam) */ 800static void 801targdone(struct cam_periph *periph, union ccb *done_ccb) 802{ 803 struct targ_softc *softc; 804 cam_status status; 805 806 CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb)); 807 softc = (struct targ_softc *)periph->softc; 808 TARG_LOCK(softc); 809 TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h, 810 periph_links.tqe); 811 status = done_ccb->ccb_h.status & CAM_STATUS_MASK; 812 813 /* If we're no longer enabled, throw away CCB */ 814 if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { 815 targfreeccb(softc, done_ccb); 816 return; 817 } 818 /* abort_all_pending() waits for pending queue to be empty */ 819 if (TAILQ_EMPTY(&softc->pending_ccb_queue)) 820 wakeup(&softc->pending_ccb_queue); 821 822 switch (done_ccb->ccb_h.func_code) { 823 /* All FC_*_QUEUED CCBs go back to userland */ 824 case XPT_IMMED_NOTIFY: 825 case XPT_ACCEPT_TARGET_IO: 826 case XPT_CONT_TARGET_IO: 827 TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h, 828 periph_links.tqe); 829 notify_user(softc); 830 break; 831 default: 832 panic("targdone: impossible xpt opcode %#x", 833 done_ccb->ccb_h.func_code); 834 /* NOTREACHED */ 835 } 836 TARG_UNLOCK(softc); 837} 838 839/* Return CCBs to the user from the user queue and abort queue */ 840static int 841targread(dev_t dev, struct uio *uio, int ioflag) 842{ 843 struct descr_queue *abort_queue; 844 struct targ_cmd_descr *user_descr; 845 struct targ_softc *softc; 846 struct ccb_queue *user_queue; 847 struct ccb_hdr *ccb_h; 848 union ccb *user_ccb; 849 int read_len, error; 850 851 error = 0; 852 read_len = 0; 853 softc = (struct targ_softc *)dev->si_drv1; 854 user_queue = &softc->user_ccb_queue; 855 abort_queue = &softc->abort_queue; 856 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n")); 857 858 /* If no data is available, wait or return immediately */ 859 TARG_LOCK(softc); 860 ccb_h = TAILQ_FIRST(user_queue); 861 user_descr = TAILQ_FIRST(abort_queue); 862 while (ccb_h == NULL && user_descr == NULL) { 863 if ((ioflag & IO_NDELAY) == 0) { 864 error = msleep(user_queue, &softc->mtx, 865 PRIBIO | PCATCH, "targrd", 0); 866 ccb_h = TAILQ_FIRST(user_queue); 867 user_descr = TAILQ_FIRST(abort_queue); 868 if (error != 0) { 869 if (error == ERESTART) { 870 continue; 871 } else { 872 TARG_UNLOCK(softc); 873 goto read_fail; 874 } 875 } 876 } else { 877 TARG_UNLOCK(softc); 878 return (EAGAIN); 879 } 880 } 881 882 /* Data is available so fill the user's buffer */ 883 while (ccb_h != NULL) { 884 struct targ_cmd_descr *descr; 885 886 if (uio->uio_resid < sizeof(user_ccb)) 887 break; 888 TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe); 889 TARG_UNLOCK(softc); 890 descr = (struct targ_cmd_descr *)ccb_h->targ_descr; 891 user_ccb = descr->user_ccb; 892 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 893 ("targread ccb %p (%p)\n", ccb_h, user_ccb)); 894 error = targreturnccb(softc, (union ccb *)ccb_h); 895 if (error != 0) 896 goto read_fail; 897 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); 898 if (error != 0) 899 goto read_fail; 900 read_len += sizeof(user_ccb); 901 902 TARG_LOCK(softc); 903 ccb_h = TAILQ_FIRST(user_queue); 904 } 905 906 /* Flush out any aborted descriptors */ 907 while (user_descr != NULL) { 908 if (uio->uio_resid < sizeof(user_ccb)) 909 break; 910 TAILQ_REMOVE(abort_queue, user_descr, tqe); 911 TARG_UNLOCK(softc); 912 user_ccb = user_descr->user_ccb; 913 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 914 ("targread aborted descr %p (%p)\n", 915 user_descr, user_ccb)); 916 suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED); 917 error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); 918 if (error != 0) 919 goto read_fail; 920 read_len += sizeof(user_ccb); 921 922 TARG_LOCK(softc); 923 user_descr = TAILQ_FIRST(abort_queue); 924 } 925 TARG_UNLOCK(softc); 926 927 /* 928 * If we've successfully read some amount of data, don't report an 929 * error. If the error is persistent, it will be reported on the 930 * next read(). 931 */ 932 if (read_len == 0 && uio->uio_resid != 0) 933 error = ENOSPC; 934 935read_fail: 936 return (error); 937} 938 939/* Copy completed ccb back to the user */ 940static int 941targreturnccb(struct targ_softc *softc, union ccb *ccb) 942{ 943 struct targ_cmd_descr *descr; 944 struct ccb_hdr *u_ccbh; 945 size_t ccb_len; 946 int error; 947 948 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targreturnccb %p\n", ccb)); 949 descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr; 950 u_ccbh = &descr->user_ccb->ccb_h; 951 952 /* Copy out the central portion of the ccb_hdr */ 953 copyout(&ccb->ccb_h.retry_count, &u_ccbh->retry_count, 954 offsetof(struct ccb_hdr, periph_priv) - 955 offsetof(struct ccb_hdr, retry_count)); 956 957 /* Copy out the rest of the ccb (after the ccb_hdr) */ 958 ccb_len = targccblen(ccb->ccb_h.func_code) - sizeof(struct ccb_hdr); 959 if (descr->mapinfo.num_bufs_used != 0) 960 cam_periph_unmapmem(ccb, &descr->mapinfo); 961 error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len); 962 if (error != 0) { 963 xpt_print_path(softc->path); 964 printf("targreturnccb - CCB copyout failed (%d)\n", 965 error); 966 } 967 /* Free CCB or send back to devq. */ 968 targfreeccb(softc, ccb); 969 970 return (error); 971} 972 973static union ccb * 974targgetccb(struct targ_softc *softc, xpt_opcode type, int priority) 975{ 976 union ccb *ccb; 977 int ccb_len; 978 979 ccb_len = targccblen(type); 980 MALLOC(ccb, union ccb *, ccb_len, M_TARG, M_WAITOK); 981 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb)); 982 983 xpt_setup_ccb(&ccb->ccb_h, softc->path, priority); 984 ccb->ccb_h.func_code = type; 985 ccb->ccb_h.cbfcnp = targdone; 986 ccb->ccb_h.targ_descr = targgetdescr(softc); 987 return (ccb); 988} 989 990static void 991targfreeccb(struct targ_softc *softc, union ccb *ccb) 992{ 993 CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("targfreeccb descr %p and\n", 994 ccb->ccb_h.targ_descr)); 995 FREE(ccb->ccb_h.targ_descr, M_TARG); 996 997 switch (ccb->ccb_h.func_code) { 998 case XPT_ACCEPT_TARGET_IO: 999 case XPT_IMMED_NOTIFY: 1000 CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("freeing ccb %p\n", ccb)); 1001 FREE(ccb, M_TARG); 1002 break; 1003 default: 1004 /* Send back CCB if we got it from the periph */ 1005 if (XPT_FC_IS_QUEUED(ccb)) { 1006 CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, 1007 ("returning queued ccb %p\n", ccb)); 1008 xpt_release_ccb(ccb); 1009 } else { 1010 CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, 1011 ("freeing ccb %p\n", ccb)); 1012 FREE(ccb, M_TARG); 1013 } 1014 break; 1015 } 1016} 1017 1018static struct targ_cmd_descr * 1019targgetdescr(struct targ_softc *softc) 1020{ 1021 struct targ_cmd_descr *descr; 1022 1023 MALLOC(descr, struct targ_cmd_descr *, sizeof(*descr), M_TARG, 1024 M_WAITOK); 1025 descr->mapinfo.num_bufs_used = 0; 1026 return (descr); 1027} 1028 1029static void 1030targinit(void) 1031{ 1032 mtx_init(&targ_mtx, "targ global", NULL, MTX_DEF); 1033 EVENTHANDLER_REGISTER(dev_clone, targclone, 0, 1000); 1034} 1035 1036static void 1037targclone(void *arg, char *name, int namelen, dev_t *dev) 1038{ 1039 int u; 1040 1041 if (*dev != NODEV) 1042 return; 1043 if (dev_stdclone(name, NULL, "targ", &u) != 1) 1044 return; 1045 *dev = make_dev(&targ_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL, 1046 0600, "targ%d", u); 1047 (*dev)->si_flags |= SI_CHEAPCLONE; 1048} 1049 1050static void 1051targasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 1052{ 1053 /* All events are handled in usermode by INOTs */ 1054 panic("targasync() called, should be an INOT instead"); 1055} 1056 1057/* Cancel all pending requests and CCBs awaiting work. */ 1058static void 1059abort_all_pending(struct targ_softc *softc) 1060{ 1061 struct targ_cmd_descr *descr; 1062 struct ccb_abort cab; 1063 struct ccb_hdr *ccb_h; 1064 1065 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n")); 1066 1067 /* First abort the descriptors awaiting resources */ 1068 while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) { 1069 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 1070 ("Aborting descr from workq %p\n", descr)); 1071 TAILQ_REMOVE(&softc->work_queue, descr, tqe); 1072 TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe); 1073 } 1074 1075 /* 1076 * Then abort all pending CCBs. 1077 * targdone() will return the aborted CCB via user_ccb_queue 1078 */ 1079 xpt_setup_ccb(&cab.ccb_h, softc->path, /*priority*/0); 1080 cab.ccb_h.func_code = XPT_ABORT; 1081 cab.ccb_h.status = CAM_REQ_CMP_ERR; 1082 TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, periph_links.tqe) { 1083 CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, 1084 ("Aborting pending CCB %p\n", ccb_h)); 1085 cab.abort_ccb = (union ccb *)ccb_h; 1086 xpt_action((union ccb *)&cab); 1087 if (cab.ccb_h.status != CAM_REQ_CMP) { 1088 xpt_print_path(cab.ccb_h.path); 1089 printf("Unable to abort CCB, status %#x\n", 1090 cab.ccb_h.status); 1091 } 1092 } 1093 1094 /* If we aborted at least one pending CCB ok, wait for it. */ 1095 if (cab.ccb_h.status == CAM_REQ_CMP) { 1096 msleep(&softc->pending_ccb_queue, &softc->mtx, 1097 PRIBIO | PCATCH, "tgabrt", 0); 1098 } 1099 1100 /* If we aborted anything from the work queue, wakeup user. */ 1101 if (!TAILQ_EMPTY(&softc->user_ccb_queue) 1102 || !TAILQ_EMPTY(&softc->abort_queue)) 1103 notify_user(softc); 1104} 1105 1106/* Notify the user that data is ready */ 1107static void 1108notify_user(struct targ_softc *softc) 1109{ 1110 /* 1111 * Notify users sleeping via poll(), kqueue(), and 1112 * blocking read(). 1113 */ 1114 selwakeup(&softc->read_select); 1115 KNOTE(&softc->read_select.si_note, 0); 1116 wakeup(&softc->user_ccb_queue); 1117} 1118 1119/* Convert CAM status to errno values */ 1120static int 1121targcamstatus(cam_status status) 1122{ 1123 switch (status & CAM_STATUS_MASK) { 1124 case CAM_REQ_CMP: /* CCB request completed without error */ 1125 return (0); 1126 case CAM_REQ_INPROG: /* CCB request is in progress */ 1127 return (EINPROGRESS); 1128 case CAM_REQ_CMP_ERR: /* CCB request completed with an error */ 1129 return (EIO); 1130 case CAM_PROVIDE_FAIL: /* Unable to provide requested capability */ 1131 return (ENOTTY); 1132 case CAM_FUNC_NOTAVAIL: /* The requested function is not available */ 1133 return (ENOTSUP); 1134 case CAM_LUN_ALRDY_ENA: /* LUN is already enabled for target mode */ 1135 return (EADDRINUSE); 1136 case CAM_PATH_INVALID: /* Supplied Path ID is invalid */ 1137 case CAM_DEV_NOT_THERE: /* SCSI Device Not Installed/there */ 1138 return (ENOENT); 1139 case CAM_REQ_ABORTED: /* CCB request aborted by the host */ 1140 return (ECANCELED); 1141 case CAM_CMD_TIMEOUT: /* Command timeout */ 1142 return (ETIMEDOUT); 1143 case CAM_REQUEUE_REQ: /* Requeue to preserve transaction ordering */ 1144 return (EAGAIN); 1145 case CAM_REQ_INVALID: /* CCB request was invalid */ 1146 return (EINVAL); 1147 case CAM_RESRC_UNAVAIL: /* Resource Unavailable */ 1148 return (ENOMEM); 1149 case CAM_BUSY: /* CAM subsytem is busy */ 1150 case CAM_UA_ABORT: /* Unable to abort CCB request */ 1151 return (EBUSY); 1152 default: 1153 return (ENXIO); 1154 } 1155} 1156 1157static size_t 1158targccblen(xpt_opcode func_code) 1159{ 1160 int len; 1161 1162 /* Codes we expect to see as a target */ 1163 switch (func_code) { 1164 case XPT_CONT_TARGET_IO: 1165 case XPT_SCSI_IO: 1166 len = sizeof(struct ccb_scsiio); 1167 break; 1168 case XPT_ACCEPT_TARGET_IO: 1169 len = sizeof(struct ccb_accept_tio); 1170 break; 1171 case XPT_IMMED_NOTIFY: 1172 len = sizeof(struct ccb_immed_notify); 1173 break; 1174 case XPT_REL_SIMQ: 1175 len = sizeof(struct ccb_relsim); 1176 break; 1177 case XPT_PATH_INQ: 1178 len = sizeof(struct ccb_pathinq); 1179 break; 1180 case XPT_DEBUG: 1181 len = sizeof(struct ccb_debug); 1182 break; 1183 case XPT_ABORT: 1184 len = sizeof(struct ccb_abort); 1185 break; 1186 case XPT_EN_LUN: 1187 len = sizeof(struct ccb_en_lun); 1188 break; 1189 default: 1190 len = sizeof(union ccb); 1191 break; 1192 } 1193 1194 return (len); 1195} 1196