summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2002-11-22 22:55:51 +0000
committernjl <njl@FreeBSD.org>2002-11-22 22:55:51 +0000
commitaeab0b1a1869e24828db1a4a45df921e4d2673da (patch)
tree60367d753c053b106c51fbbc085b3a0433b196a5 /sys
parenta52def4e3fb09991ac89994427cc83679843d652 (diff)
downloadFreeBSD-src-aeab0b1a1869e24828db1a4a45df921e4d2673da.zip
FreeBSD-src-aeab0b1a1869e24828db1a4a45df921e4d2673da.tar.gz
New SCSI target emulator code
This code allows a user program to enable target mode on a SIM and then emulate any number of devices (disks, tape drives, etc.) All decisions about device behavior (UA, CA, inquiry response) are left to the usermode program and the kernel driver is merely a conduit for CCBs. This enables multiple concurrent target emulators, each using its own backing store and IO model. Also included is a user program that emulates a disk (RBC) using a file as a backing store. This provides functionality similar to md(4) at the CAM layer. Code has been tested on ahc(4) and should also work on isp(4) (and other SIMs that gain target mode support). It is a complete rewrite of /sys/cam/scsi_target* and /usr/share/examples/scsi_target. Design, comments from: gibbs Supported by: Cryptography Research Approved by: re
Diffstat (limited to 'sys')
-rw-r--r--sys/cam/scsi/scsi_target.c2915
-rw-r--r--sys/cam/scsi/scsi_targetio.h110
-rw-r--r--sys/modules/cam/Makefile2
3 files changed, 923 insertions, 2104 deletions
diff --git a/sys/cam/scsi/scsi_target.c b/sys/cam/scsi/scsi_target.c
index 2c8f32e..b775c43 100644
--- a/sys/cam/scsi/scsi_target.c
+++ b/sys/cam/scsi/scsi_target.c
@@ -1,7 +1,8 @@
/*
- * Implementation of a simple Target Mode SCSI Proccessor Target driver for CAM.
+ * Generic SCSI Target Kernel Mode Driver
*
- * Copyright (c) 1998, 1999, 2001 Justin T. Gibbs.
+ * Copyright (c) 2002 Nate Lawson.
+ * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,17 +30,17 @@
*/
#include <sys/param.h>
-#include <sys/queue.h>
#include <sys/systm.h>
#include <sys/kernel.h>
-#include <sys/types.h>
-#include <sys/bio.h>
#include <sys/conf.h>
-#include <sys/devicestat.h>
+#include <sys/event.h>
#include <sys/malloc.h>
#include <sys/poll.h>
#include <sys/selinfo.h>
#include <sys/uio.h>
+#include <sys/vnode.h>
+#include <sys/queue.h>
+#include <sys/devicestat.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@@ -47,131 +48,66 @@
#include <cam/cam_queue.h>
#include <cam/cam_xpt_periph.h>
#include <cam/cam_debug.h>
-
-#include <cam/scsi/scsi_all.h>
-#include <cam/scsi/scsi_pt.h>
#include <cam/scsi/scsi_targetio.h>
-#include <cam/scsi/scsi_message.h>
-
-typedef enum {
- TARG_STATE_NORMAL,
- TARG_STATE_EXCEPTION,
- TARG_STATE_TEARDOWN
-} targ_state;
-
-typedef enum {
- TARG_FLAG_NONE = 0x00,
- TARG_FLAG_SEND_EOF = 0x01,
- TARG_FLAG_RECEIVE_EOF = 0x02,
- TARG_FLAG_LUN_ENABLED = 0x04
-} targ_flags;
-
-typedef enum {
- TARG_CCB_NONE = 0x00,
- TARG_CCB_WAITING = 0x01,
- TARG_CCB_HELDQ = 0x02,
- TARG_CCB_ABORT_TO_HELDQ = 0x04
-} targ_ccb_flags;
-
-#define MAX_ACCEPT 16
-#define MAX_IMMEDIATE 16
-#define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */
-#define MAX_INITIATORS 256 /* includes widest fibre channel for now */
-
-#define MIN(a, b) ((a > b) ? b : a)
-#define TARG_CONTROL_UNIT 0xffff00ff
-#define TARG_IS_CONTROL_DEV(d) (minor((d)) == TARG_CONTROL_UNIT)
-
-#define TARG_TAG_WILDCARD ((u_int)~0)
+/* Transaction information attached to each CCB sent by the user */
+struct targ_cmd_descr {
+ struct cam_periph_map_info mapinfo;
+ TAILQ_ENTRY(targ_cmd_descr) tqe;
+ union ccb *user_ccb;
+ int priority;
+ int func_code;
+};
-/* Offsets into our private CCB area for storing accept information */
-#define ccb_flags ppriv_field0
-#define ccb_descr ppriv_ptr1
+/* Offset into the private CCB area for storing our descriptor */
+#define targ_descr periph_priv.entries[1].ptr
-/* We stick a pointer to the originating accept TIO in each continue I/O CCB */
-#define ccb_atio ppriv_ptr1
+TAILQ_HEAD(descr_queue, targ_cmd_descr);
-/*
- * When we're constructing a unit, we point to passed in user inquiry data here.
- */
-#define ccb_inq ppriv_ptr1
+typedef enum {
+ TARG_STATE_RESV = 0x00, /* Invalid state */
+ TARG_STATE_OPENED = 0x01, /* Device opened, softc initialized */
+ TARG_STATE_LUN_ENABLED = 0x02 /* Device enabled for a path */
+} targ_state;
+/* Per-instance device software context */
struct targ_softc {
- /* CTIOs pending on the controller */
- struct ccb_queue pending_queue;
-
- /* ATIOs awaiting CTIO resources from the XPT */
- struct ccb_queue work_queue;
-
- /*
- * ATIOs for SEND operations waiting for 'write'
- * buffer resources from our userland daemon.
- */
- struct ccb_queue snd_ccb_queue;
+ /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */
+ struct ccb_queue pending_ccb_queue;
- /*
- * ATIOs for RCV operations waiting for 'read'
- * buffer resources from our userland daemon.
- */
- struct ccb_queue rcv_ccb_queue;
+ /* Command descriptors awaiting CTIO resources from the XPT */
+ struct descr_queue work_queue;
- /*
- * ATIOs for commands unknown to the kernel driver.
- * These are queued for the userland daemon to
- * consume.
- */
- struct ccb_queue unknown_atio_queue;
+ /* Command descriptors that have been aborted back to the user. */
+ struct descr_queue abort_queue;
/*
- * Userland buffers for SEND commands waiting for
- * SEND ATIOs to be queued by an initiator.
+ * Queue of CCBs that have been copied out to userland, but our
+ * userland daemon has not yet seen.
*/
- struct bio_queue_head snd_bio_queue;
-
- /*
- * Userland buffers for RCV commands waiting for
- * RCV ATIOs to be queued by an initiator.
- */
- struct bio_queue_head rcv_bio_queue;
- struct devstat device_stats;
- dev_t targ_dev;
- struct selinfo snd_select;
- struct selinfo rcv_select;
- targ_state state;
- targ_flags flags;
- targ_exception exceptions;
- u_int init_level;
- u_int inq_data_len;
- struct scsi_inquiry_data *inq_data;
- struct ccb_accept_tio *accept_tio_list;
- struct ccb_hdr_slist immed_notify_slist;
- struct initiator_state istate[MAX_INITIATORS];
-};
-
-struct targ_cmd_desc {
- struct ccb_accept_tio* atio_link;
- u_int data_resid; /* How much left to transfer */
- u_int data_increment;/* Amount to send before next disconnect */
- void* data; /* The data. Can be from backing_store or not */
- void* backing_store;/* Backing store allocated for this descriptor*/
- struct bio *bp; /* Buffer for this transfer */
- u_int max_size; /* Size of backing_store */
- u_int32_t timeout;
- u_int32_t
- user_atio : 1, /* user ATIO (will define last CTIO) */
- status : 8; /* Status to return to initiator */
+ struct ccb_queue user_ccb_queue;
+
+ struct cam_periph *periph;
+ struct cam_path *path;
+ targ_state state;
+ struct selinfo read_select;
+ struct devstat device_stats;
+ struct mtx mtx;
};
-static d_open_t targopen;
-static d_close_t targclose;
-static d_read_t targread;
-static d_write_t targwrite;
-static d_ioctl_t targioctl;
-static d_poll_t targpoll;
-static d_strategy_t targstrategy;
-
-#define TARG_CDEV_MAJOR 65
+static d_open_t targopen;
+static d_close_t targclose;
+static d_read_t targread;
+static d_write_t targwrite;
+static d_ioctl_t targioctl;
+static d_poll_t targpoll;
+static d_kqfilter_t targkqfilter;
+static void targreadfiltdetach(struct knote *kn);
+static int targreadfilt(struct knote *kn, long hint);
+static struct filterops targread_filtops =
+ { 1, NULL, targreadfiltdetach, targreadfilt };
+
+#define TARG_CDEV_MAJOR 65
static struct cdevsw targ_cdevsw = {
/* open */ targopen,
/* close */ targclose,
@@ -180,805 +116,644 @@ static struct cdevsw targ_cdevsw = {
/* ioctl */ targioctl,
/* poll */ targpoll,
/* mmap */ nommap,
- /* strategy */ targstrategy,
+ /* strategy */ nostrategy,
/* name */ "targ",
/* maj */ TARG_CDEV_MAJOR,
/* dump */ nodump,
/* psize */ nopsize,
- /* flags */ 0,
+ /* flags */ D_KQFILTER,
+ /* kqfilter */ targkqfilter
};
-static int targsendccb(struct cam_periph *periph, union ccb *ccb,
- union ccb *inccb);
+static cam_status targendislun(struct cam_path *path, int enable,
+ int grp6_len, int grp7_len);
+static cam_status targenable(struct targ_softc *softc,
+ struct cam_path *path,
+ int grp6_len, int grp7_len);
+static cam_status targdisable(struct targ_softc *softc);
+static periph_ctor_t targctor;
+static periph_dtor_t targdtor;
+static periph_start_t targstart;
+static int targusermerge(struct targ_softc *softc,
+ struct targ_cmd_descr *descr,
+ union ccb *ccb);
+static int targsendccb(struct targ_softc *softc, union ccb *ccb,
+ struct targ_cmd_descr *descr);
+static void targdone(struct cam_periph *periph,
+ union ccb *done_ccb);
+static int targreturnccb(struct targ_softc *softc,
+ union ccb *ccb);
+static union ccb * targgetccb(struct targ_softc *softc, xpt_opcode type,
+ int priority);
+static void targfreeccb(struct targ_softc *softc, union ccb *ccb);
+static struct targ_cmd_descr *
+ targgetdescr(struct targ_softc *softc);
static periph_init_t targinit;
+static void targclone(void *arg, char *name, int namelen,
+ dev_t *dev);
static void targasync(void *callback_arg, u_int32_t code,
- struct cam_path *path, void *arg);
-static int targallocinstance(void *, u_long);
-static int targfreeinstance(struct ioc_alloc_unit *);
-static cam_status targenlun(struct cam_periph *periph);
-static cam_status targdislun(struct cam_periph *periph);
-static periph_ctor_t targctor;
-static periph_dtor_t targdtor;
-static void targrunqueue(struct cam_periph *periph,
- struct targ_softc *softc);
-static periph_start_t targstart;
-static void targdone(struct cam_periph *periph,
- union ccb *done_ccb);
-static void targfireexception(struct cam_periph *periph,
- struct targ_softc *softc);
-static void targinoterror(struct cam_periph *periph,
- struct targ_softc *softc,
- struct ccb_immed_notify *inot);
-static int targerror(union ccb *ccb, u_int32_t cam_flags,
- u_int32_t sense_flags);
-static struct targ_cmd_desc* allocdescr(void);
-static void freedescr(struct targ_cmd_desc *buf);
-static void fill_sense(struct targ_softc *softc,
- u_int initiator_id, u_int error_code,
- u_int sense_key, u_int asc, u_int ascq);
-static void copy_sense(struct targ_softc *softc,
- struct initiator_state *istate,
- u_int8_t *sense_buffer, size_t sense_len);
-static void set_unit_attention_cond(struct cam_periph *periph,
- u_int initiator_id, ua_types ua);
-static void set_ca_condition(struct cam_periph *periph,
- u_int initiator_id, ca_types ca);
-static void abort_pending_transactions(struct cam_periph *periph,
- u_int initiator_id, u_int tag_id,
- int errno, int to_held_queue);
-
+ struct cam_path *path, void *arg);
+static void abort_all_pending(struct targ_softc *softc);
+static void notify_user(struct targ_softc *softc);
+static int targcamstatus(cam_status status);
+static size_t targccblen(xpt_opcode func_code);
+
static struct periph_driver targdriver =
{
targinit, "targ",
TAILQ_HEAD_INITIALIZER(targdriver.units), /* generation */ 0
};
-
PERIPHDRIVER_DECLARE(targ, targdriver);
-static dev_t targ_ctl_dev;
+static struct mtx targ_mtx;
+#define TARG_LOCK(softc) mtx_lock(&(softc)->mtx)
+#define TARG_UNLOCK(softc) mtx_unlock(&(softc)->mtx)
-static void
-targinit(void)
-{
- targ_ctl_dev = make_dev(&targ_cdevsw, TARG_CONTROL_UNIT, UID_ROOT,
- GID_OPERATOR, 0600, "%s.ctl", "targ");
- if (targ_ctl_dev == (dev_t) 0) {
- printf("targ: failed to create control dev\n");
- }
-}
+static MALLOC_DEFINE(M_TARG, "TARG", "TARG data");
-static void
-targasync(void *callback_arg, u_int32_t code,
- struct cam_path *path, void *arg)
+/* Create softc and initialize it. Only one proc can open each targ device. */
+static int
+targopen(dev_t dev, int flags, int fmt, struct thread *td)
{
- struct cam_periph *periph;
struct targ_softc *softc;
- periph = (struct cam_periph *)callback_arg;
- softc = (struct targ_softc *)periph->softc;
- switch (code) {
- case AC_PATH_DEREGISTERED:
- {
- /* XXX Implement */
- break;
- }
- default:
- break;
+ mtx_lock(&targ_mtx);
+ if (dev->si_drv1 != 0) {
+ mtx_unlock(&targ_mtx);
+ return (EBUSY);
}
+
+ /* Mark device busy before any potentially blocking operations */
+ dev->si_drv1 = (void *)~0;
+ mtx_unlock(&targ_mtx);
+
+ /* Create the targ device, allocate its softc, initialize it */
+ if ((dev->si_flags & SI_NAMED) == 0) {
+ make_dev(&targ_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 0600,
+ "targ%d", dev2unit(dev));
+ }
+ MALLOC(softc, struct targ_softc *, sizeof(*softc), M_TARG,
+ M_WAITOK | M_ZERO);
+ dev->si_drv1 = softc;
+ softc->state = TARG_STATE_OPENED;
+ softc->periph = NULL;
+ softc->path = NULL;
+ mtx_init(&softc->mtx, devtoname(dev), "targ cdev", MTX_DEF);
+
+ TAILQ_INIT(&softc->pending_ccb_queue);
+ TAILQ_INIT(&softc->work_queue);
+ TAILQ_INIT(&softc->abort_queue);
+ TAILQ_INIT(&softc->user_ccb_queue);
+
+ return (0);
}
-/* Attempt to enable our lun */
-static cam_status
-targenlun(struct cam_periph *periph)
+/* Disable LUN if enabled and teardown softc */
+static int
+targclose(dev_t dev, int flag, int fmt, struct thread *td)
{
- union ccb immed_ccb;
- struct targ_softc *softc;
- cam_status status;
- int i;
-
- softc = (struct targ_softc *)periph->softc;
-
- if ((softc->flags & TARG_FLAG_LUN_ENABLED) != 0)
- return (CAM_REQ_CMP);
-
- xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1);
- immed_ccb.ccb_h.func_code = XPT_EN_LUN;
-
- /* Don't need support for any vendor specific commands */
- immed_ccb.cel.grp6_len = 0;
- immed_ccb.cel.grp7_len = 0;
- immed_ccb.cel.enable = 1;
- xpt_action(&immed_ccb);
- status = immed_ccb.ccb_h.status;
- if (status != CAM_REQ_CMP) {
- xpt_print_path(periph->path);
- printf("targenlun - Enable Lun Rejected with status 0x%x\n",
- status);
- return (status);
- }
-
- softc->flags |= TARG_FLAG_LUN_ENABLED;
-
- /*
- * Build up a buffer of accept target I/O
- * operations for incoming selections.
- */
- for (i = 0; i < MAX_ACCEPT; i++) {
- struct ccb_accept_tio *atio;
+ struct targ_softc *softc;
+ int error;
- atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF,
- M_NOWAIT);
- if (atio == NULL) {
- status = CAM_RESRC_UNAVAIL;
- break;
+ softc = (struct targ_softc *)dev->si_drv1;
+ TARG_LOCK(softc);
+ error = targdisable(softc);
+ if (error == 0) {
+ dev->si_drv1 = 0;
+ mtx_lock(&targ_mtx);
+ if (softc->periph != NULL) {
+ cam_periph_invalidate(softc->periph);
+ softc->periph = NULL;
}
+ mtx_unlock(&targ_mtx);
+ TARG_UNLOCK(softc);
+ mtx_destroy(&softc->mtx);
+ destroy_dev(dev);
+ FREE(softc, M_TARG);
+ } else {
+ TARG_UNLOCK(softc);
+ }
+ return (error);
+}
- atio->ccb_h.ccb_descr = allocdescr();
+/* Enable/disable LUNs, set debugging level */
+static int
+targioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
+{
+ struct targ_softc *softc;
+ cam_status status;
- if (atio->ccb_h.ccb_descr == NULL) {
- free(atio, M_DEVBUF);
- status = CAM_RESRC_UNAVAIL;
- break;
- }
+ softc = (struct targ_softc *)dev->si_drv1;
- xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1);
- atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
- atio->ccb_h.cbfcnp = targdone;
- atio->ccb_h.ccb_flags = TARG_CCB_NONE;
- xpt_action((union ccb *)atio);
- status = atio->ccb_h.status;
- if (status != CAM_REQ_INPROG) {
- xpt_print_path(periph->path);
- printf("Queue of atio failed\n");
- freedescr(atio->ccb_h.ccb_descr);
- free(atio, M_DEVBUF);
+ switch (cmd) {
+ case TARGIOCENABLE:
+ {
+ struct ioc_enable_lun *new_lun;
+ struct cam_path *path;
+
+ new_lun = (struct ioc_enable_lun *)addr;
+ status = xpt_create_path(&path, /*periph*/NULL,
+ new_lun->path_id,
+ new_lun->target_id,
+ new_lun->lun_id);
+ if (status != CAM_REQ_CMP) {
+ printf("Couldn't create path, status %#x\n", status);
break;
}
- ((struct targ_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
- softc->accept_tio_list;
- softc->accept_tio_list = atio;
- }
-
- if (i == 0) {
- xpt_print_path(periph->path);
- printf("targenlun - Could not allocate accept tio CCBs: "
- "status = 0x%x\n", status);
- targdislun(periph);
- return (CAM_REQ_CMP_ERR);
+ TARG_LOCK(softc);
+ status = targenable(softc, path, new_lun->grp6_len,
+ new_lun->grp7_len);
+ TARG_UNLOCK(softc);
+ xpt_free_path(path);
+ break;
}
+ case TARGIOCDISABLE:
+ TARG_LOCK(softc);
+ status = targdisable(softc);
+ TARG_UNLOCK(softc);
+ break;
+ case TARGIOCDEBUG:
+ {
+#ifdef CAMDEBUG
+ struct ccb_debug cdbg;
- /*
- * Build up a buffer of immediate notify CCBs
- * so the SIM can tell us of asynchronous target mode events.
- */
- for (i = 0; i < MAX_ACCEPT; i++) {
- struct ccb_immed_notify *inot;
-
- inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF,
- M_NOWAIT);
-
- if (inot == NULL) {
- status = CAM_RESRC_UNAVAIL;
+ bzero(&cdbg, sizeof cdbg);
+ if (*((int *)addr) != 0)
+ cdbg.flags = CAM_DEBUG_PERIPH;
+ else
+ cdbg.flags = CAM_DEBUG_NONE;
+ xpt_setup_ccb(&cdbg.ccb_h, softc->path, /*priority*/0);
+ cdbg.ccb_h.func_code = XPT_DEBUG;
+ cdbg.ccb_h.cbfcnp = targdone;
+
+ /* If no periph available, disallow debugging changes */
+ TARG_LOCK(softc);
+ if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
+ status = CAM_DEV_NOT_THERE;
+ TARG_UNLOCK(softc);
break;
}
-
- xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1);
- inot->ccb_h.func_code = XPT_IMMED_NOTIFY;
- inot->ccb_h.cbfcnp = targdone;
- SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
- periph_links.sle);
- xpt_action((union ccb *)inot);
+ xpt_action((union ccb *)&cdbg);
+ TARG_UNLOCK(softc);
+ status = cdbg.ccb_h.status & CAM_STATUS_MASK;
+#else
+ status = CAM_FUNC_NOTAVAIL;
+#endif
+ break;
}
-
- if (i == 0) {
- xpt_print_path(periph->path);
- printf("targenlun - Could not allocate immediate notify CCBs: "
- "status = 0x%x\n", status);
- targdislun(periph);
- return (CAM_REQ_CMP_ERR);
+ default:
+ status = CAM_PROVIDE_FAIL;
+ break;
}
- return (CAM_REQ_CMP);
+ return (targcamstatus(status));
}
-static cam_status
-targdislun(struct cam_periph *periph)
+/* Writes are always ready, reads wait for user_ccb_queue or abort_queue */
+static int
+targpoll(dev_t dev, int poll_events, struct thread *td)
{
- union ccb ccb;
struct targ_softc *softc;
- struct ccb_accept_tio* atio;
- struct ccb_hdr *ccb_h;
+ int revents;
- softc = (struct targ_softc *)periph->softc;
- if ((softc->flags & TARG_FLAG_LUN_ENABLED) == 0)
- return CAM_REQ_CMP;
+ softc = (struct targ_softc *)dev->si_drv1;
- /* XXX Block for Continue I/O completion */
-
- /* Kill off all ACCECPT and IMMEDIATE CCBs */
- while ((atio = softc->accept_tio_list) != NULL) {
-
- softc->accept_tio_list =
- ((struct targ_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
- xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
- ccb.cab.ccb_h.func_code = XPT_ABORT;
- ccb.cab.abort_ccb = (union ccb *)atio;
- xpt_action(&ccb);
- }
-
- while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
- SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
- xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
- ccb.cab.ccb_h.func_code = XPT_ABORT;
- ccb.cab.abort_ccb = (union ccb *)ccb_h;
- xpt_action(&ccb);
+ /* Poll for write() is always ok. */
+ revents = poll_events & (POLLOUT | POLLWRNORM);
+ if ((poll_events & (POLLIN | POLLRDNORM)) != 0) {
+ /* Poll for read() depends on user and abort queues. */
+ TARG_LOCK(softc);
+ if (!TAILQ_EMPTY(&softc->user_ccb_queue) ||
+ !TAILQ_EMPTY(&softc->abort_queue)) {
+ revents |= poll_events & (POLLIN | POLLRDNORM);
+ }
+ /* Only sleep if the user didn't poll for write. */
+ if (revents == 0)
+ selrecord(td, &softc->read_select);
+ TARG_UNLOCK(softc);
}
- /*
- * Dissable this lun.
- */
- xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1);
- ccb.cel.ccb_h.func_code = XPT_EN_LUN;
- ccb.cel.enable = 0;
- xpt_action(&ccb);
-
- if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
- printf("targdislun - Disabling lun on controller failed "
- "with status 0x%x\n", ccb.cel.ccb_h.status);
- else
- softc->flags &= ~TARG_FLAG_LUN_ENABLED;
- return (ccb.cel.ccb_h.status);
+ return (revents);
}
-static cam_status
-targctor(struct cam_periph *periph, void *arg)
+static int
+targkqfilter(dev_t dev, struct knote *kn)
{
- struct ccb_pathinq *cpi;
- struct targ_softc *softc;
- int i;
-
- cpi = (struct ccb_pathinq *)arg;
-
- /* Allocate our per-instance private storage */
- softc = (struct targ_softc *)malloc(sizeof(*softc), M_DEVBUF, M_NOWAIT);
- if (softc == NULL) {
- printf("targctor: unable to malloc softc\n");
- return (CAM_REQ_CMP_ERR);
- }
-
- bzero(softc, sizeof(*softc));
- TAILQ_INIT(&softc->pending_queue);
- TAILQ_INIT(&softc->work_queue);
- TAILQ_INIT(&softc->snd_ccb_queue);
- TAILQ_INIT(&softc->rcv_ccb_queue);
- TAILQ_INIT(&softc->unknown_atio_queue);
- bioq_init(&softc->snd_bio_queue);
- bioq_init(&softc->rcv_bio_queue);
- softc->accept_tio_list = NULL;
- SLIST_INIT(&softc->immed_notify_slist);
- softc->state = TARG_STATE_NORMAL;
- periph->softc = softc;
- softc->init_level++;
-
- /*
- * We start out life with a UA to indicate power-on/reset.
- */
- for (i = 0; i < MAX_INITIATORS; i++)
- softc->istate[i].pending_ua = UA_POWER_ON;
-
- /*
- * Allocate an inquiry data buffer.
- * We let the user to override this if desired.
- */
- softc->inq_data_len = sizeof(*softc->inq_data);
- softc->inq_data = malloc(softc->inq_data_len, M_DEVBUF, M_NOWAIT);
- if (softc->inq_data == NULL) {
- printf("targctor - Unable to malloc inquiry data\n");
- targdtor(periph);
- return (CAM_RESRC_UNAVAIL);
- }
- if (cpi->ccb_h.ccb_inq) {
- bcopy(cpi->ccb_h.ccb_inq, softc->inq_data, softc->inq_data_len);
- } else {
- bzero(softc->inq_data, softc->inq_data_len);
- softc->inq_data->device =
- T_PROCESSOR | (SID_QUAL_LU_CONNECTED << 5);
- softc->inq_data->version = 2;
- softc->inq_data->response_format = 2; /* SCSI2 Inquiry Format */
- softc->inq_data->additional_length = softc->inq_data_len - 4;
- strncpy(softc->inq_data->vendor, "FreeBSD ", SID_VENDOR_SIZE);
- strncpy(softc->inq_data->product,
- "TM-PT ", SID_PRODUCT_SIZE);
- strncpy(softc->inq_data->revision, "0.0 ", SID_REVISION_SIZE);
- }
-
- /*
- * Preserve the SIM's capabilities here. Don't let user applications
- * do something dumb.
- */
- if (softc->inq_data->version >= 2) {
- softc->inq_data->flags &=
- ~(PI_SDTR_ABLE|PI_WIDE_16|PI_WIDE_32|PI_TAG_ABLE);
- softc->inq_data->flags |= (cpi->hba_inquiry &
- (PI_SDTR_ABLE|PI_WIDE_16|PI_WIDE_32|PI_TAG_ABLE));
- }
- softc->targ_dev = make_dev(&targ_cdevsw, periph->unit_number, UID_ROOT,
- GID_OPERATOR, 0600, "%s%d",
- periph->periph_name, periph->unit_number);
- softc->targ_dev->si_drv1 = periph;
-
- softc->init_level++;
- return (CAM_REQ_CMP);
+ struct targ_softc *softc;
+
+ softc = (struct targ_softc *)dev->si_drv1;
+ kn->kn_hook = (caddr_t)softc;
+ kn->kn_fop = &targread_filtops;
+ TARG_LOCK(softc);
+ SLIST_INSERT_HEAD(&softc->read_select.si_note, kn, kn_selnext);
+ TARG_UNLOCK(softc);
+ return (0);
}
static void
-targdtor(struct cam_periph *periph)
+targreadfiltdetach(struct knote *kn)
{
- struct targ_softc *softc;
-
- softc = (struct targ_softc *)periph->softc;
+ struct targ_softc *softc;
- softc->state = TARG_STATE_TEARDOWN;
-
- targdislun(periph);
-
- switch (softc->init_level) {
- default:
- /* FALLTHROUGH */
- case 2:
- free(softc->inq_data, M_DEVBUF);
- destroy_dev(softc->targ_dev);
- /* FALLTHROUGH */
- case 1:
- free(softc, M_DEVBUF);
- break;
- case 0:
- panic("targdtor - impossible init level");;
- }
+ softc = (struct targ_softc *)kn->kn_hook;
+ TARG_LOCK(softc);
+ SLIST_REMOVE(&softc->read_select.si_note, kn, knote, kn_selnext);
+ TARG_UNLOCK(softc);
}
+/* Notify the user's kqueue when the user queue or abort queue gets a CCB */
static int
-targopen(dev_t dev, int flags, int fmt, struct thread *td)
+targreadfilt(struct knote *kn, long hint)
{
- struct cam_periph *periph;
- struct targ_softc *softc;
- cam_status status;
- int error;
- int s;
-
- /* An open of the control device always succeeds */
- if (TARG_IS_CONTROL_DEV(dev))
- return 0;
-
- s = splsoftcam();
- periph = (struct cam_periph *)dev->si_drv1;
- if (periph == NULL) {
- splx(s);
- return (ENXIO);
- }
- if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0) {
- splx(s);
- return (error);
- }
-
- softc = (struct targ_softc *)periph->softc;
- if ((softc->flags & TARG_FLAG_LUN_ENABLED) == 0) {
- if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
- splx(s);
- cam_periph_unlock(periph);
- return(ENXIO);
- }
- }
- splx(s);
-
- status = targenlun(periph);
- switch (status) {
- case CAM_REQ_CMP:
- error = 0;
- break;
- case CAM_RESRC_UNAVAIL:
- error = ENOMEM;
- break;
- case CAM_LUN_ALRDY_ENA:
- error = EADDRINUSE;
- break;
- default:
- error = ENXIO;
- break;
- }
- cam_periph_unlock(periph);
- if (error) {
- cam_periph_release(periph);
- }
- return (error);
+ struct targ_softc *softc;
+ int retval;
+
+ softc = (struct targ_softc *)kn->kn_hook;
+ TARG_LOCK(softc);
+ retval = !TAILQ_EMPTY(&softc->user_ccb_queue) ||
+ !TAILQ_EMPTY(&softc->abort_queue);
+ TARG_UNLOCK(softc);
+ return (retval);
}
-static int
-targclose(dev_t dev, int flag, int fmt, struct thread *td)
+/* Send the HBA the enable/disable message */
+static cam_status
+targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len)
{
- struct cam_periph *periph;
- struct targ_softc *softc;
- int s;
- int error;
-
- /* A close of the control device always succeeds */
- if (TARG_IS_CONTROL_DEV(dev))
- return 0;
-
- s = splsoftcam();
- periph = (struct cam_periph *)dev->si_drv1;
- if (periph == NULL) {
- splx(s);
- return (ENXIO);
- }
- if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
- return (error);
- softc = (struct targ_softc *)periph->softc;
- splx(s);
-
- targdislun(periph);
-
- cam_periph_unlock(periph);
- cam_periph_release(periph);
+ struct ccb_en_lun en_ccb;
+ cam_status status;
- return (0);
+ /* Tell the lun to begin answering selects */
+ xpt_setup_ccb(&en_ccb.ccb_h, path, /*priority*/1);
+ en_ccb.ccb_h.func_code = XPT_EN_LUN;
+ /* Don't need support for any vendor specific commands */
+ en_ccb.grp6_len = grp6_len;
+ en_ccb.grp7_len = grp7_len;
+ en_ccb.enable = enable ? 1 : 0;
+ xpt_action((union ccb *)&en_ccb);
+ status = en_ccb.ccb_h.status & CAM_STATUS_MASK;
+ if (status != CAM_REQ_CMP) {
+ xpt_print_path(path);
+ printf("%sable lun CCB rejected, status %#x\n",
+ enable ? "en" : "dis", status);
+ }
+ return (status);
}
-static int
-targallocinstance(void *arg, u_long cmd)
+/* Enable target mode on a LUN, given its path */
+static cam_status
+targenable(struct targ_softc *softc, struct cam_path *path, int grp6_len,
+ int grp7_len)
{
- struct ioc_alloc_unit *alloc_unit = arg;
- struct scsi_inquiry_data local;
- struct ccb_pathinq cpi;
- struct cam_path *path;
struct cam_periph *periph;
- cam_status status;
- int free_path_on_return;
- int error;
-
- free_path_on_return = 0;
- status = xpt_create_path(&path, /*periph*/NULL,
- alloc_unit->path_id,
- alloc_unit->target_id,
- alloc_unit->lun_id);
- if (status != CAM_REQ_CMP) {
- printf("Couldn't Allocate Path %x\n", status);
- goto fail;
- }
+ struct ccb_pathinq cpi;
+ cam_status status;
- free_path_on_return++;
+ if ((softc->state & TARG_STATE_LUN_ENABLED) != 0)
+ return (CAM_LUN_ALRDY_ENA);
+ /* Make sure SIM supports target mode */
xpt_setup_ccb(&cpi.ccb_h, path, /*priority*/1);
cpi.ccb_h.func_code = XPT_PATH_INQ;
xpt_action((union ccb *)&cpi);
- status = cpi.ccb_h.status;
-
+ status = cpi.ccb_h.status & CAM_STATUS_MASK;
if (status != CAM_REQ_CMP) {
- printf("Couldn't CPI %x\n", status);
- goto fail;
+ printf("pathinq failed, status %#x\n", status);
+ goto enable_fail;
}
-
- /* Can only alloc units on controllers that support target mode */
if ((cpi.target_sprt & PIT_PROCESSOR) == 0) {
- printf("Controller does not support target mode - status %x\n",
- status);
- status = CAM_PATH_INVALID;
- goto fail;
+ printf("controller does not support target mode\n");
+ status = CAM_FUNC_NOTAVAIL;
+ goto enable_fail;
}
- /* Ensure that we don't already have an instance for this unit. */
- if ((periph = cam_periph_find(path, "targ")) != NULL) {
- status = CAM_LUN_ALRDY_ENA;
- goto fail;
- }
+ /* Destroy any periph on our path if it is disabled */
+ mtx_lock(&targ_mtx);
+ periph = cam_periph_find(path, "targ");
+ if (periph != NULL) {
+ struct targ_softc *del_softc;
- if (cmd == TARGCTLIOALLOCUNIT) {
- status = copyin(alloc_unit->inquiry_data, &local, sizeof local);
- if (status)
- goto fail;
- cpi.ccb_h.ccb_inq = &local;
- } else {
- cpi.ccb_h.ccb_inq = NULL;
+ del_softc = (struct targ_softc *)periph->softc;
+ if ((del_softc->state & TARG_STATE_LUN_ENABLED) == 0) {
+ cam_periph_invalidate(del_softc->periph);
+ del_softc->periph = NULL;
+ } else {
+ printf("Requested path still in use by targ%d\n",
+ periph->unit_number);
+ mtx_unlock(&targ_mtx);
+ status = CAM_LUN_ALRDY_ENA;
+ goto enable_fail;
+ }
}
-
- /*
- * Allocate a peripheral instance for
- * this target instance.
- */
+ /* Create a periph instance attached to this path */
status = cam_periph_alloc(targctor, NULL, targdtor, targstart,
- "targ", CAM_PERIPH_BIO, path, targasync,
- 0, &cpi);
-
-fail:
- switch (status) {
- case CAM_REQ_CMP:
- {
- struct cam_periph *periph;
+ "targ", CAM_PERIPH_BIO, path, targasync, 0, softc);
+ mtx_unlock(&targ_mtx);
+ if (status != CAM_REQ_CMP) {
+ printf("cam_periph_alloc failed, status %#x\n", status);
+ goto enable_fail;
+ }
- if ((periph = cam_periph_find(path, "targ")) == NULL)
- panic("targallocinstance: Succeeded but no periph?");
- error = 0;
- alloc_unit->unit = periph->unit_number;
- break;
+ /* Ensure that the periph now exists. */
+ if (cam_periph_find(path, "targ") == NULL) {
+ panic("targenable: succeeded but no periph?");
+ /* NOTREACHED */
}
- case CAM_RESRC_UNAVAIL:
- error = ENOMEM;
- break;
- case CAM_LUN_ALRDY_ENA:
- error = EADDRINUSE;
- break;
- default:
- printf("targallocinstance: Unexpected CAM status %x\n", status);
- /* FALLTHROUGH */
- case CAM_PATH_INVALID:
- error = ENXIO;
- break;
- case CAM_PROVIDE_FAIL:
- error = ENODEV;
- break;
+
+ /* Send the enable lun message */
+ status = targendislun(path, /*enable*/1, grp6_len, grp7_len);
+ if (status != CAM_REQ_CMP) {
+ printf("enable lun failed, status %#x\n", status);
+ goto enable_fail;
}
+ softc->state |= TARG_STATE_LUN_ENABLED;
- if (free_path_on_return != 0)
- xpt_free_path(path);
+enable_fail:
+ return (status);
+}
- return (error);
+/* Disable this softc's target instance if enabled */
+static cam_status
+targdisable(struct targ_softc *softc)
+{
+ cam_status status;
+
+ if ((softc->state & TARG_STATE_LUN_ENABLED) == 0)
+ return (CAM_REQ_CMP);
+
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targdisable\n"));
+
+ /* Abort any ccbs pending on the controller */
+ abort_all_pending(softc);
+
+ /* Disable this lun */
+ status = targendislun(softc->path, /*enable*/0,
+ /*grp6_len*/0, /*grp7_len*/0);
+ if (status == CAM_REQ_CMP)
+ softc->state &= ~TARG_STATE_LUN_ENABLED;
+ else
+ printf("Disable lun failed, status %#x\n", status);
+
+ return (status);
}
-static int
-targfreeinstance(struct ioc_alloc_unit *alloc_unit)
+/* Initialize a periph (called from cam_periph_alloc) */
+static cam_status
+targctor(struct cam_periph *periph, void *arg)
{
- struct cam_path *path;
- struct cam_periph *periph;
struct targ_softc *softc;
- cam_status status;
- int free_path_on_return;
- int error;
-
- periph = NULL;
- free_path_on_return = 0;
- status = xpt_create_path(&path, /*periph*/NULL,
- alloc_unit->path_id,
- alloc_unit->target_id,
- alloc_unit->lun_id);
- free_path_on_return++;
-
- if (status != CAM_REQ_CMP)
- goto fail;
-
- /* Find our instance. */
- if ((periph = cam_periph_find(path, "targ")) == NULL) {
- xpt_print_path(path);
- printf("Invalid path specified for freeing target instance\n");
- status = CAM_PATH_INVALID;
- goto fail;
- }
- softc = (struct targ_softc *)periph->softc;
-
- if ((softc->flags & TARG_FLAG_LUN_ENABLED) != 0) {
- status = CAM_BUSY;
- goto fail;
- }
+ /* Store pointer to softc for periph-driven routines */
+ softc = (struct targ_softc *)arg;
+ periph->softc = softc;
+ softc->periph = periph;
+ softc->path = periph->path;
+ return (CAM_REQ_CMP);
+}
-fail:
- if (free_path_on_return != 0)
- xpt_free_path(path);
+static void
+targdtor(struct cam_periph *periph)
+{
+ struct targ_softc *softc;
+ struct ccb_hdr *ccb_h;
+ struct targ_cmd_descr *descr;
- switch (status) {
- case CAM_REQ_CMP:
- if (periph != NULL)
- cam_periph_invalidate(periph);
- error = 0;
- break;
- case CAM_RESRC_UNAVAIL:
- error = ENOMEM;
- break;
- case CAM_LUN_ALRDY_ENA:
- error = EADDRINUSE;
- break;
- default:
- printf("targfreeinstance: Unexpected CAM status %x\n", status);
- /* FALLTHROUGH */
- case CAM_PATH_INVALID:
- error = ENODEV;
- break;
+ softc = (struct targ_softc *)periph->softc;
+
+ /*
+ * targdisable() aborts CCBs back to the user and leaves them
+ * on user_ccb_queue and abort_queue in case the user is still
+ * interested in them. We free them now.
+ */
+ while ((ccb_h = TAILQ_FIRST(&softc->user_ccb_queue)) != NULL) {
+ TAILQ_REMOVE(&softc->user_ccb_queue, ccb_h, periph_links.tqe);
+ targfreeccb(softc, (union ccb *)ccb_h);
}
- return (error);
+ while ((descr = TAILQ_FIRST(&softc->abort_queue)) != NULL) {
+ TAILQ_REMOVE(&softc->abort_queue, descr, tqe);
+ FREE(descr, M_TARG);
+ }
+
+ softc->periph = NULL;
+ softc->path = NULL;
+ periph->softc = NULL;
}
+/* Receive CCBs from user mode proc and send them to the HBA */
static int
-targioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
+targwrite(dev_t dev, struct uio *uio, int ioflag)
{
- struct cam_periph *periph;
+ union ccb *user_ccb;
struct targ_softc *softc;
- int error;
+ struct targ_cmd_descr *descr;
+ int write_len, error;
+ int func_code, priority;
+
+ softc = (struct targ_softc *)dev->si_drv1;
+ write_len = error = 0;
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("write - uio_resid %d\n", uio->uio_resid));
+ while (uio->uio_resid >= sizeof(user_ccb) && error == 0) {
+ union ccb *ccb;
+ int error;
- error = 0;
- if (TARG_IS_CONTROL_DEV(dev)) {
- switch (cmd) {
- case OTARGCTLIOALLOCUNIT:
- case TARGCTLIOALLOCUNIT:
- error = targallocinstance(addr, cmd);
+ error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
+ if (error != 0) {
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("write - uiomove failed (%d)\n", error));
break;
- case OTARGCTLIOFREEUNIT:
- case TARGCTLIOFREEUNIT:
- /*
- * Old_ioc_alloc_unit and ioc_alloc_unit are the
- * same with respect to what we need from the structure
- * for this function.
- */
- error = targfreeinstance((struct ioc_alloc_unit*)addr);
+ }
+ priority = fuword(&user_ccb->ccb_h.pinfo.priority);
+ if (priority == -1) {
+ error = EINVAL;
+ break;
+ }
+ func_code = fuword(&user_ccb->ccb_h.func_code);
+ switch (func_code) {
+ case XPT_ACCEPT_TARGET_IO:
+ case XPT_IMMED_NOTIFY:
+ ccb = targgetccb(softc, func_code, priority);
+ descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
+ descr->user_ccb = user_ccb;
+ descr->func_code = func_code;
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("Sent ATIO/INOT (%p)\n", user_ccb));
+ xpt_action(ccb);
+ TARG_LOCK(softc);
+ TAILQ_INSERT_TAIL(&softc->pending_ccb_queue,
+ &ccb->ccb_h,
+ periph_links.tqe);
+ TARG_UNLOCK(softc);
break;
default:
- error = EINVAL;
+ if ((func_code & XPT_FC_QUEUED) != 0) {
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("Sending queued ccb %#x (%p)\n",
+ func_code, user_ccb));
+ descr = targgetdescr(softc);
+ descr->user_ccb = user_ccb;
+ descr->priority = priority;
+ descr->func_code = func_code;
+ TARG_LOCK(softc);
+ TAILQ_INSERT_TAIL(&softc->work_queue,
+ descr, tqe);
+ TARG_UNLOCK(softc);
+ xpt_schedule(softc->periph, priority);
+ } else {
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("Sending inline ccb %#x (%p)\n",
+ func_code, user_ccb));
+ ccb = targgetccb(softc, func_code, priority);
+ descr = (struct targ_cmd_descr *)
+ ccb->ccb_h.targ_descr;
+ descr->user_ccb = user_ccb;
+ descr->priority = priority;
+ descr->func_code = func_code;
+ if (targusermerge(softc, descr, ccb) != EFAULT)
+ targsendccb(softc, ccb, descr);
+ targreturnccb(softc, ccb);
+ }
break;
}
- return (error);
+ write_len += sizeof(user_ccb);
}
+
+ /*
+ * If we've successfully taken in some amount of
+ * data, return success for that data first. If
+ * an error is persistent, it will be reported
+ * on the next write.
+ */
+ if (error != 0 && write_len == 0)
+ return (error);
+ if (write_len == 0 && uio->uio_resid != 0)
+ return (ENOSPC);
+ return (0);
+}
+
+/* Process requests (descrs) via the periph-supplied CCBs */
+static void
+targstart(struct cam_periph *periph, union ccb *start_ccb)
+{
+ struct targ_softc *softc;
+ struct targ_cmd_descr *descr, *next_descr;
+ int error;
- periph = (struct cam_periph *)dev->si_drv1;
- if (periph == NULL)
- return (ENXIO);
softc = (struct targ_softc *)periph->softc;
- switch (cmd) {
- case TARGIOCFETCHEXCEPTION:
- *((targ_exception *)addr) = softc->exceptions;
- break;
- case TARGIOCCLEAREXCEPTION:
- {
- targ_exception clear_mask;
-
- clear_mask = *((targ_exception *)addr);
- if ((clear_mask & TARG_EXCEPT_UNKNOWN_ATIO) != 0) {
- struct ccb_hdr *ccbh;
-
- ccbh = TAILQ_FIRST(&softc->unknown_atio_queue);
- if (ccbh != NULL) {
- TAILQ_REMOVE(&softc->unknown_atio_queue,
- ccbh, periph_links.tqe);
- /* Requeue the ATIO back to the controller */
- ccbh->ccb_flags = TARG_CCB_NONE;
- xpt_action((union ccb *)ccbh);
- ccbh = TAILQ_FIRST(&softc->unknown_atio_queue);
- }
- if (ccbh != NULL)
- clear_mask &= ~TARG_EXCEPT_UNKNOWN_ATIO;
- }
- softc->exceptions &= ~clear_mask;
- if (softc->exceptions == TARG_EXCEPT_NONE
- && softc->state == TARG_STATE_EXCEPTION) {
- softc->state = TARG_STATE_NORMAL;
- targrunqueue(periph, softc);
- }
- break;
- }
- case TARGIOCFETCHATIO:
- {
- struct ccb_hdr *ccbh;
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb));
- ccbh = TAILQ_FIRST(&softc->unknown_atio_queue);
- if (ccbh != NULL) {
- bcopy(ccbh, addr, sizeof(struct ccb_accept_tio));
- } else {
- error = ENOENT;
+ TARG_LOCK(softc);
+ descr = TAILQ_FIRST(&softc->work_queue);
+ if (descr == NULL) {
+ TARG_UNLOCK(softc);
+ xpt_release_ccb(start_ccb);
+ } else {
+ TAILQ_REMOVE(&softc->work_queue, descr, tqe);
+ next_descr = TAILQ_FIRST(&softc->work_queue);
+ TARG_UNLOCK(softc);
+
+ /* Initiate a transaction using the descr and supplied CCB */
+ error = targusermerge(softc, descr, start_ccb);
+ if (error == 0)
+ error = targsendccb(softc, start_ccb, descr);
+ if (error != 0) {
+ xpt_print_path(periph->path);
+ printf("targsendccb failed, err %d\n", error);
+ xpt_release_ccb(start_ccb);
+ suword(&descr->user_ccb->ccb_h.status,
+ CAM_REQ_CMP_ERR);
+ TARG_LOCK(softc);
+ TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
+ TARG_UNLOCK(softc);
+ notify_user(softc);
}
- break;
- }
- case TARGIOCCOMMAND:
- {
- union ccb *inccb;
- union ccb *ccb;
- /*
- * XXX JGibbs
- * This code is lifted directly from the pass-thru driver.
- * Perhaps this should be moved to a library????
- */
- inccb = (union ccb *)addr;
- ccb = cam_periph_getccb(periph, inccb->ccb_h.pinfo.priority);
+ /* If we have more work to do, stay scheduled */
+ if (next_descr != NULL)
+ xpt_schedule(periph, next_descr->priority);
+ }
+}
- error = targsendccb(periph, ccb, inccb);
+static int
+targusermerge(struct targ_softc *softc, struct targ_cmd_descr *descr,
+ union ccb *ccb)
+{
+ struct ccb_hdr *u_ccbh, *k_ccbh;
+ size_t ccb_len;
+ int error;
- xpt_release_ccb(ccb);
+ u_ccbh = &descr->user_ccb->ccb_h;
+ k_ccbh = &ccb->ccb_h;
- break;
+ /*
+ * There are some fields in the CCB header that need to be
+ * preserved, the rest we get from the user ccb. (See xpt_merge_ccb)
+ */
+ xpt_setup_ccb(k_ccbh, softc->path, descr->priority);
+ k_ccbh->retry_count = fuword(&u_ccbh->retry_count);
+ k_ccbh->func_code = descr->func_code;
+ k_ccbh->flags = fuword(&u_ccbh->flags);
+ k_ccbh->timeout = fuword(&u_ccbh->timeout);
+ ccb_len = targccblen(k_ccbh->func_code) - sizeof(struct ccb_hdr);
+ error = copyin(u_ccbh + 1, k_ccbh + 1, ccb_len);
+ if (error != 0) {
+ k_ccbh->status = CAM_REQ_CMP_ERR;
+ return (error);
}
- case TARGIOCGETISTATE:
- case TARGIOCSETISTATE:
- {
- struct ioc_initiator_state *ioc_istate;
- ioc_istate = (struct ioc_initiator_state *)addr;
- if (ioc_istate->initiator_id > MAX_INITIATORS) {
- error = EINVAL;
- break;
- }
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("GET/SETISTATE for %d\n", ioc_istate->initiator_id));
- if (cmd == TARGIOCGETISTATE) {
- bcopy(&softc->istate[ioc_istate->initiator_id],
- &ioc_istate->istate, sizeof(ioc_istate->istate));
- } else {
- bcopy(&ioc_istate->istate,
- &softc->istate[ioc_istate->initiator_id],
- sizeof(ioc_istate->istate));
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("pending_ca now %x\n",
- softc->istate[ioc_istate->initiator_id].pending_ca));
- }
- break;
- }
- case TARGIODEBUG:
- {
-#ifdef CAMDEBUG
- union ccb ccb;
- bzero (&ccb, sizeof ccb);
- if (xpt_create_path(&ccb.ccb_h.path, periph,
- xpt_path_path_id(periph->path),
- xpt_path_target_id(periph->path),
- xpt_path_lun_id(periph->path)) != CAM_REQ_CMP) {
- error = EINVAL;
- break;
- }
- if (*((int *)addr)) {
- ccb.cdbg.flags = CAM_DEBUG_PERIPH;
- } else {
- ccb.cdbg.flags = CAM_DEBUG_NONE;
+ /* Translate usermode abort_ccb pointer to its kernel counterpart */
+ if (k_ccbh->func_code == XPT_ABORT) {
+ struct ccb_abort *cab;
+ struct ccb_hdr *ccb_h;
+
+ cab = (struct ccb_abort *)ccb;
+ TARG_LOCK(softc);
+ TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue,
+ periph_links.tqe) {
+ struct targ_cmd_descr *ab_descr;
+
+ ab_descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
+ if (ab_descr->user_ccb == cab->abort_ccb) {
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("Changing abort for %p to %p\n",
+ cab->abort_ccb, ccb_h));
+ cab->abort_ccb = (union ccb *)ccb_h;
+ break;
+ }
}
- xpt_setup_ccb(&ccb.ccb_h, ccb.ccb_h.path, 0);
- ccb.ccb_h.func_code = XPT_DEBUG;
- ccb.ccb_h.path_id = xpt_path_path_id(ccb.ccb_h.path);
- ccb.ccb_h.target_id = xpt_path_target_id(ccb.ccb_h.path);
- ccb.ccb_h.target_lun = xpt_path_lun_id(ccb.ccb_h.path);
- ccb.ccb_h.cbfcnp = targdone;
- xpt_action(&ccb);
- if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- error = EIO;
- } else {
- error = 0;
+ TARG_UNLOCK(softc);
+ /* CCB not found, set appropriate status */
+ if (ccb_h == NULL) {
+ k_ccbh->status = CAM_PATH_INVALID;
+ error = ESRCH;
}
- xpt_free_path(ccb.ccb_h.path);
-#else
- error = 0;
-#endif
- break;
- }
- default:
- error = ENOTTY;
- break;
}
+
return (error);
}
-/*
- * XXX JGibbs lifted from pass-thru driver.
- * Generally, "ccb" should be the CCB supplied by the kernel. "inccb"
- * should be the CCB that is copied in from the user.
- */
+/* Build and send a kernel CCB formed from descr->user_ccb */
static int
-targsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
+targsendccb(struct targ_softc *softc, union ccb *ccb,
+ struct targ_cmd_descr *descr)
{
- struct targ_softc *softc;
- struct cam_periph_map_info mapinfo;
- int error, need_unmap;
- int s;
-
- softc = (struct targ_softc *)periph->softc;
-
- need_unmap = 0;
+ struct cam_periph_map_info *mapinfo;
+ struct ccb_hdr *ccb_h;
+ int error;
- /*
- * There are some fields in the CCB header that need to be
- * preserved, the rest we get from the user.
- */
- xpt_merge_ccb(ccb, inccb);
+ ccb_h = &ccb->ccb_h;
+ mapinfo = &descr->mapinfo;
+ mapinfo->num_bufs_used = 0;
/*
* There's no way for the user to have a completion
* function, so we put our own completion function in here.
+ * We also stash in a reference to our descriptor so targreturnccb()
+ * can find our mapping info.
*/
- ccb->ccb_h.cbfcnp = targdone;
+ ccb_h->cbfcnp = targdone;
+ ccb_h->targ_descr = descr;
/*
* We only attempt to map the user memory into kernel space
@@ -991,1327 +766,435 @@ targsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
* without data are a reasonably common occurance (e.g. test unit
* ready), it will save a few cycles if we check for it here.
*/
- if (((ccb->ccb_h.flags & CAM_DATA_PHYS) == 0)
- && (((ccb->ccb_h.func_code == XPT_CONT_TARGET_IO)
- && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE))
- || (ccb->ccb_h.func_code == XPT_DEV_MATCH))) {
-
- bzero(&mapinfo, sizeof(mapinfo));
+ if (((ccb_h->flags & CAM_DATA_PHYS) == 0)
+ && (((ccb_h->func_code == XPT_CONT_TARGET_IO)
+ && ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE))
+ || (ccb_h->func_code == XPT_DEV_MATCH))) {
- error = cam_periph_mapmem(ccb, &mapinfo);
+ error = cam_periph_mapmem(ccb, mapinfo);
/*
* cam_periph_mapmem returned an error, we can't continue.
* Return the error to the user.
*/
- if (error)
- return(error);
-
- /*
- * We successfully mapped the memory in, so we need to
- * unmap it when the transaction is done.
- */
- need_unmap = 1;
+ if (error) {
+ ccb_h->status = CAM_REQ_CMP_ERR;
+ mapinfo->num_bufs_used = 0;
+ return (error);
+ }
}
/*
* Once queued on the pending CCB list, this CCB will be protected
- * by the error recovery handling used for 'buffer I/O' ccbs. Since
- * we are in a process context here, however, the software interrupt
- * for this driver may deliver an event invalidating this CCB just
- * before we queue it. Close this race condition by blocking
- * software interrupt delivery, checking for any pertinent queued
- * events, and only then queuing this CCB.
+ * by our error recovery handler.
*/
- s = splsoftcam();
- if (softc->exceptions == 0) {
- if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO)
- TAILQ_INSERT_TAIL(&softc->pending_queue, &ccb->ccb_h,
- periph_links.tqe);
-
- /*
- * If the user wants us to perform any error recovery,
- * then honor that request. Otherwise, it's up to the
- * user to perform any error recovery.
- */
- error = cam_periph_runccb(ccb, /* error handler */NULL,
- CAM_RETRY_SELTO, SF_RETRY_UA,
- &softc->device_stats);
-
- if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO)
- TAILQ_REMOVE(&softc->pending_queue, &ccb->ccb_h,
- periph_links.tqe);
- } else {
- ccb->ccb_h.status = CAM_UNACKED_EVENT;
- error = 0;
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb));
+ if (XPT_FC_IS_QUEUED(ccb)) {
+ TARG_LOCK(softc);
+ TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h,
+ periph_links.tqe);
+ TARG_UNLOCK(softc);
}
- splx(s);
+ xpt_action(ccb);
- if (need_unmap != 0)
- cam_periph_unmapmem(ccb, &mapinfo);
-
- ccb->ccb_h.cbfcnp = NULL;
- ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
- bcopy(ccb, inccb, sizeof(union ccb));
-
- return(error);
+ return (0);
}
-
-static int
-targpoll(dev_t dev, int poll_events, struct thread *td)
+/* Completion routine for CCBs (called at splsoftcam) */
+static void
+targdone(struct cam_periph *periph, union ccb *done_ccb)
{
- struct cam_periph *periph;
struct targ_softc *softc;
- int revents;
- int s;
-
- /* ioctl is the only supported operation of the control device */
- if (TARG_IS_CONTROL_DEV(dev))
- return EINVAL;
+ cam_status status;
- periph = (struct cam_periph *)dev->si_drv1;
- if (periph == NULL)
- return (ENXIO);
+ CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb));
softc = (struct targ_softc *)periph->softc;
-
- revents = 0;
- s = splcam();
- if ((poll_events & (POLLOUT | POLLWRNORM)) != 0) {
- if (TAILQ_FIRST(&softc->rcv_ccb_queue) != NULL
- && bioq_first(&softc->rcv_bio_queue) == NULL)
- revents |= poll_events & (POLLOUT | POLLWRNORM);
- }
- if ((poll_events & (POLLIN | POLLRDNORM)) != 0) {
- if (TAILQ_FIRST(&softc->snd_ccb_queue) != NULL
- && bioq_first(&softc->snd_bio_queue) == NULL)
- revents |= poll_events & (POLLIN | POLLRDNORM);
+ TARG_LOCK(softc);
+ TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h,
+ periph_links.tqe);
+ status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
+
+ /* If we're no longer enabled, throw away CCB */
+ if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) {
+ targfreeccb(softc, done_ccb);
+ return;
}
+ /* abort_all_pending() waits for pending queue to be empty */
+ if (TAILQ_EMPTY(&softc->pending_ccb_queue))
+ wakeup(&softc->pending_ccb_queue);
- if (softc->state != TARG_STATE_NORMAL)
- revents |= POLLERR;
-
- if (revents == 0) {
- if (poll_events & (POLLOUT | POLLWRNORM))
- selrecord(td, &softc->rcv_select);
- if (poll_events & (POLLIN | POLLRDNORM))
- selrecord(td, &softc->snd_select);
+ switch (done_ccb->ccb_h.func_code) {
+ /* All FC_*_QUEUED CCBs go back to userland */
+ case XPT_IMMED_NOTIFY:
+ case XPT_ACCEPT_TARGET_IO:
+ case XPT_CONT_TARGET_IO:
+ TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h,
+ periph_links.tqe);
+ notify_user(softc);
+ break;
+ default:
+ panic("targdone: impossible xpt opcode %#x",
+ done_ccb->ccb_h.func_code);
+ /* NOTREACHED */
}
- splx(s);
- return (revents);
+ TARG_UNLOCK(softc);
}
+/* Return CCBs to the user from the user queue and abort queue */
static int
targread(dev_t dev, struct uio *uio, int ioflag)
{
- /* ioctl is the only supported operation of the control device */
- if (TARG_IS_CONTROL_DEV(dev))
- return EINVAL;
-
- if (uio->uio_iovcnt == 0
- || uio->uio_iov->iov_len == 0) {
- /* EOF */
- struct cam_periph *periph;
- struct targ_softc *softc;
- int s;
-
- s = splcam();
- periph = (struct cam_periph *)dev->si_drv1;
- if (periph == NULL)
- return (ENXIO);
- softc = (struct targ_softc *)periph->softc;
- softc->flags |= TARG_FLAG_SEND_EOF;
- splx(s);
- targrunqueue(periph, softc);
- return (0);
- }
- return(physread(dev, uio, ioflag));
-}
+ struct descr_queue *abort_queue;
+ struct targ_cmd_descr *user_descr;
+ struct targ_softc *softc;
+ struct ccb_queue *user_queue;
+ struct ccb_hdr *ccb_h;
+ union ccb *user_ccb;
+ int read_len, error;
-static int
-targwrite(dev_t dev, struct uio *uio, int ioflag)
-{
- /* ioctl is the only supported operation of the control device */
- if (TARG_IS_CONTROL_DEV(dev))
- return EINVAL;
-
- if (uio->uio_iovcnt == 0
- || uio->uio_iov->iov_len == 0) {
- /* EOF */
- struct cam_periph *periph;
- struct targ_softc *softc;
- int s;
-
- s = splcam();
- periph = (struct cam_periph *)dev->si_drv1;
- if (periph == NULL)
- return (ENXIO);
- softc = (struct targ_softc *)periph->softc;
- softc->flags |= TARG_FLAG_RECEIVE_EOF;
- splx(s);
- targrunqueue(periph, softc);
- return (0);
- }
- return(physwrite(dev, uio, ioflag));
-}
-
-/*
- * Actually translate the requested transfer into one the physical driver
- * can understand. The transfer is described by a buf and will include
- * only one physical transfer.
- */
-static void
-targstrategy(struct bio *bp)
-{
- struct cam_periph *periph;
- struct targ_softc *softc;
- int s;
-
- bp->bio_resid = bp->bio_bcount;
-
- /* ioctl is the only supported operation of the control device */
- if (TARG_IS_CONTROL_DEV(bp->bio_dev)) {
- biofinish(bp, NULL, EINVAL);
- return;
+ error = 0;
+ read_len = 0;
+ softc = (struct targ_softc *)dev->si_drv1;
+ user_queue = &softc->user_ccb_queue;
+ abort_queue = &softc->abort_queue;
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n"));
+
+ /* If no data is available, wait or return immediately */
+ TARG_LOCK(softc);
+ ccb_h = TAILQ_FIRST(user_queue);
+ user_descr = TAILQ_FIRST(abort_queue);
+ while (ccb_h == NULL && user_descr == NULL) {
+ if ((ioflag & IO_NDELAY) == 0) {
+ error = msleep(user_queue, &softc->mtx,
+ PRIBIO | PCATCH, "targrd", 0);
+ ccb_h = TAILQ_FIRST(user_queue);
+ user_descr = TAILQ_FIRST(abort_queue);
+ if (error != 0) {
+ if (error == ERESTART) {
+ continue;
+ } else {
+ TARG_UNLOCK(softc);
+ goto read_fail;
+ }
+ }
+ } else {
+ TARG_UNLOCK(softc);
+ return (EAGAIN);
+ }
}
- periph = (struct cam_periph *)bp->bio_dev->si_drv1;
- if (periph == NULL) {
- biofinish(bp, NULL, ENXIO);
- return;
- }
- softc = (struct targ_softc *)periph->softc;
+ /* Data is available so fill the user's buffer */
+ while (ccb_h != NULL) {
+ struct targ_cmd_descr *descr;
- /*
- * Mask interrupts so that the device cannot be invalidated until
- * after we are in the queue. Otherwise, we might not properly
- * clean up one of the buffers.
- */
- s = splbio();
-
- /*
- * If there is an exception pending, error out
- */
- if (softc->state != TARG_STATE_NORMAL) {
- splx(s);
- if (softc->state == TARG_STATE_EXCEPTION
- && (softc->exceptions & TARG_EXCEPT_DEVICE_INVALID) == 0)
- s = EBUSY;
- else
- s = ENXIO;
- biofinish(bp, NULL, s);
- return;
- }
-
- /*
- * Place it in the queue of buffers available for either
- * SEND or RECEIVE commands.
- *
- */
- bp->bio_resid = bp->bio_bcount;
- if (bp->bio_cmd == BIO_READ) {
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Queued a SEND buffer\n"));
- bioq_insert_tail(&softc->snd_bio_queue, bp);
- } else {
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Queued a RECEIVE buffer\n"));
- bioq_insert_tail(&softc->rcv_bio_queue, bp);
- }
+ if (uio->uio_resid < sizeof(user_ccb))
+ break;
+ TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe);
+ TARG_UNLOCK(softc);
+ descr = (struct targ_cmd_descr *)ccb_h->targ_descr;
+ user_ccb = descr->user_ccb;
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("targread ccb %p (%p)\n", ccb_h, user_ccb));
+ error = targreturnccb(softc, (union ccb *)ccb_h);
+ if (error != 0)
+ goto read_fail;
+ error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
+ if (error != 0)
+ goto read_fail;
+ read_len += sizeof(user_ccb);
+
+ TARG_LOCK(softc);
+ ccb_h = TAILQ_FIRST(user_queue);
+ }
+
+ /* Flush out any aborted descriptors */
+ while (user_descr != NULL) {
+ if (uio->uio_resid < sizeof(user_ccb))
+ break;
+ TAILQ_REMOVE(abort_queue, user_descr, tqe);
+ TARG_UNLOCK(softc);
+ user_ccb = user_descr->user_ccb;
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("targread aborted descr %p (%p)\n",
+ user_descr, user_ccb));
+ suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED);
+ error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio);
+ if (error != 0)
+ goto read_fail;
+ read_len += sizeof(user_ccb);
+
+ TARG_LOCK(softc);
+ user_descr = TAILQ_FIRST(abort_queue);
+ }
+ TARG_UNLOCK(softc);
- splx(s);
-
/*
- * Attempt to use the new buffer to service any pending
- * target commands.
+ * If we've successfully read some amount of data, don't report an
+ * error. If the error is persistent, it will be reported on the
+ * next read().
*/
- targrunqueue(periph, softc);
+ if (read_len == 0 && uio->uio_resid != 0)
+ error = ENOSPC;
- return;
+read_fail:
+ return (error);
}
-static void
-targrunqueue(struct cam_periph *periph, struct targ_softc *softc)
+/* Copy completed ccb back to the user */
+static int
+targreturnccb(struct targ_softc *softc, union ccb *ccb)
{
- struct ccb_queue *pending_queue;
- struct ccb_accept_tio *atio;
- struct bio_queue_head *bioq;
- struct bio *bp;
- struct targ_cmd_desc *desc;
- struct ccb_hdr *ccbh;
- int s;
-
- s = splbio();
- pending_queue = NULL;
- bioq = NULL;
- ccbh = NULL;
- /* Only run one request at a time to maintain data ordering. */
- if (softc->state != TARG_STATE_NORMAL
- || TAILQ_FIRST(&softc->work_queue) != NULL
- || TAILQ_FIRST(&softc->pending_queue) != NULL) {
- splx(s);
- return;
- }
+ struct targ_cmd_descr *descr;
+ struct ccb_hdr *u_ccbh;
+ size_t ccb_len;
+ int error;
- if (((bp = bioq_first(&softc->snd_bio_queue)) != NULL
- || (softc->flags & TARG_FLAG_SEND_EOF) != 0)
- && (ccbh = TAILQ_FIRST(&softc->snd_ccb_queue)) != NULL) {
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targreturnccb %p\n", ccb));
+ descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descr;
+ u_ccbh = &descr->user_ccb->ccb_h;
- if (bp == NULL)
- softc->flags &= ~TARG_FLAG_SEND_EOF;
- else {
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("De-Queued a SEND buffer %ld\n",
- bp->bio_bcount));
- }
- bioq = &softc->snd_bio_queue;
- pending_queue = &softc->snd_ccb_queue;
- } else if (((bp = bioq_first(&softc->rcv_bio_queue)) != NULL
- || (softc->flags & TARG_FLAG_RECEIVE_EOF) != 0)
- && (ccbh = TAILQ_FIRST(&softc->rcv_ccb_queue)) != NULL) {
-
- if (bp == NULL)
- softc->flags &= ~TARG_FLAG_RECEIVE_EOF;
- else {
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("De-Queued a RECEIVE buffer %ld\n",
- bp->bio_bcount));
- }
- bioq = &softc->rcv_bio_queue;
- pending_queue = &softc->rcv_ccb_queue;
- }
+ /* Copy out the central portion of the ccb_hdr */
+ copyout(&ccb->ccb_h.retry_count, &u_ccbh->retry_count,
+ offsetof(struct ccb_hdr, periph_priv) -
+ offsetof(struct ccb_hdr, retry_count));
- if (pending_queue != NULL) {
- /* Process a request */
- atio = (struct ccb_accept_tio *)ccbh;
- TAILQ_REMOVE(pending_queue, ccbh, periph_links.tqe);
- desc = (struct targ_cmd_desc *)atio->ccb_h.ccb_descr;
- desc->bp = bp;
- if (bp == NULL) {
- /* EOF */
- desc->data = NULL;
- desc->data_increment = 0;
- desc->data_resid = 0;
- atio->ccb_h.flags &= ~CAM_DIR_MASK;
- atio->ccb_h.flags |= CAM_DIR_NONE;
- } else {
- bioq_remove(bioq, bp);
- desc->data = &bp->bio_data[bp->bio_bcount - bp->bio_resid];
- desc->data_increment =
- MIN(desc->data_resid, bp->bio_resid);
- }
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Buffer command: data %p: datacnt %d\n",
- desc->data, desc->data_increment));
- TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
- periph_links.tqe);
+ /* Copy out the rest of the ccb (after the ccb_hdr) */
+ ccb_len = targccblen(ccb->ccb_h.func_code) - sizeof(struct ccb_hdr);
+ if (descr->mapinfo.num_bufs_used != 0)
+ cam_periph_unmapmem(ccb, &descr->mapinfo);
+ error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len);
+ if (error != 0) {
+ xpt_print_path(softc->path);
+ printf("targreturnccb - CCB copyout failed (%d)\n",
+ error);
}
- atio = (struct ccb_accept_tio *)TAILQ_FIRST(&softc->work_queue);
- if (atio != NULL) {
- int priority;
-
- priority = (atio->ccb_h.flags & CAM_DIS_DISCONNECT) ? 0 : 1;
- splx(s);
- xpt_schedule(periph, priority);
- } else
- splx(s);
+ /* Free CCB or send back to devq. */
+ targfreeccb(softc, ccb);
+
+ return (error);
}
-static void
-targstart(struct cam_periph *periph, union ccb *start_ccb)
+static union ccb *
+targgetccb(struct targ_softc *softc, xpt_opcode type, int priority)
{
- struct targ_softc *softc;
- struct ccb_hdr *ccbh;
- struct ccb_accept_tio *atio;
- struct targ_cmd_desc *desc;
- struct ccb_scsiio *csio;
- targ_ccb_flags flags;
- int s;
+ union ccb *ccb;
+ int ccb_len;
- softc = (struct targ_softc *)periph->softc;
-
- s = splbio();
- ccbh = TAILQ_FIRST(&softc->work_queue);
- if (periph->immediate_priority <= periph->pinfo.priority) {
- start_ccb->ccb_h.ccb_flags = TARG_CCB_WAITING;
- SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
- periph_links.sle);
- periph->immediate_priority = CAM_PRIORITY_NONE;
- splx(s);
- wakeup(&periph->ccb_list);
- } else if (ccbh == NULL) {
- splx(s);
- xpt_release_ccb(start_ccb);
- } else {
- TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
- splx(s);
- atio = (struct ccb_accept_tio*)ccbh;
- desc = (struct targ_cmd_desc *)atio->ccb_h.ccb_descr;
-
- /* Is this a tagged request? */
- flags = atio->ccb_h.flags & (CAM_DIS_DISCONNECT |
- CAM_TAG_ACTION_VALID | CAM_DIR_MASK | CAM_SEND_STATUS);
-
- /*
- * If we are done with the transaction, tell the
- * controller to send status and perform a CMD_CMPLT.
- */
- if (desc->user_atio == 0 &&
- desc->data_resid == desc->data_increment) {
- flags |= CAM_SEND_STATUS;
- }
-
- csio = &start_ccb->csio;
- cam_fill_ctio(csio,
- /*retries*/2,
- targdone,
- flags,
- (flags & CAM_TAG_ACTION_VALID) ?
- MSG_SIMPLE_Q_TAG : 0,
- atio->tag_id,
- atio->init_id,
- desc->status,
- /*data_ptr*/desc->data_increment == 0
- ? NULL : desc->data,
- /*dxfer_len*/desc->data_increment,
- /*timeout*/desc->timeout);
-
- if ((flags & CAM_SEND_STATUS) != 0
- && (desc->status == SCSI_STATUS_CHECK_COND
- || desc->status == SCSI_STATUS_CMD_TERMINATED)) {
- struct initiator_state *istate;
-
- istate = &softc->istate[atio->init_id];
- csio->sense_len = istate->sense_data.extra_len
- + offsetof(struct scsi_sense_data,
- extra_len);
- bcopy(&istate->sense_data, &csio->sense_data,
- csio->sense_len);
- csio->ccb_h.flags |= CAM_SEND_SENSE;
- } else {
- csio->sense_len = 0;
- }
+ ccb_len = targccblen(type);
+ MALLOC(ccb, union ccb *, ccb_len, M_TARG, M_WAITOK);
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb));
- start_ccb->ccb_h.ccb_flags = TARG_CCB_NONE;
- start_ccb->ccb_h.ccb_atio = atio;
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Sending a CTIO (flags 0x%x)\n", csio->ccb_h.flags));
- TAILQ_INSERT_TAIL(&softc->pending_queue, &csio->ccb_h,
- periph_links.tqe);
- xpt_action(start_ccb);
- /*
- * If the queue was frozen waiting for the response
- * to this ATIO (for instance disconnection was disallowed),
- * then release it now that our response has been queued.
- */
- if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
- cam_release_devq(periph->path,
- /*relsim_flags*/0,
- /*reduction*/0,
- /*timeout*/0,
- /*getcount_only*/0);
- atio->ccb_h.status &= ~CAM_DEV_QFRZN;
- }
- s = splbio();
- ccbh = TAILQ_FIRST(&softc->work_queue);
- splx(s);
- }
- if (ccbh != NULL)
- targrunqueue(periph, softc);
+ xpt_setup_ccb(&ccb->ccb_h, softc->path, priority);
+ ccb->ccb_h.func_code = type;
+ ccb->ccb_h.cbfcnp = targdone;
+ ccb->ccb_h.targ_descr = targgetdescr(softc);
+ return (ccb);
}
static void
-targdone(struct cam_periph *periph, union ccb *done_ccb)
+targfreeccb(struct targ_softc *softc, union ccb *ccb)
{
- struct targ_softc *softc;
-
- softc = (struct targ_softc *)periph->softc;
-
- if (done_ccb->ccb_h.ccb_flags == TARG_CCB_WAITING) {
- /* Caller will release the CCB */
- wakeup(&done_ccb->ccb_h.cbfcnp);
- return;
- }
-
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("targdone %x\n", done_ccb->ccb_h.func_code));
+ CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("targfreeccb descr %p and\n",
+ ccb->ccb_h.targ_descr));
+ FREE(ccb->ccb_h.targ_descr, M_TARG);
- switch (done_ccb->ccb_h.func_code) {
+ switch (ccb->ccb_h.func_code) {
case XPT_ACCEPT_TARGET_IO:
- {
- struct ccb_accept_tio *atio;
- struct targ_cmd_desc *descr;
- struct initiator_state *istate;
- u_int8_t *cdb;
- int priority;
-
- atio = &done_ccb->atio;
- descr = (struct targ_cmd_desc*)atio->ccb_h.ccb_descr;
- istate = &softc->istate[atio->init_id];
- cdb = atio->cdb_io.cdb_bytes;
- if (softc->state == TARG_STATE_TEARDOWN
- || atio->ccb_h.status == CAM_REQ_ABORTED) {
- freedescr(descr);
- free(done_ccb, M_DEVBUF);
- return;
- }
- descr->data_resid = 0;
- descr->data_increment = 0;
- descr->user_atio = 0;
-
-#ifdef CAMDEBUG
- {
- int i;
- char dcb[128];
- for (dcb[0] = 0, i = 0; i < atio->cdb_len; i++) {
- snprintf(dcb, sizeof dcb,
- "%s %02x", dcb, cdb[i] & 0xff);
- }
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("flags %x cdb:%s\n", atio->ccb_h.flags, dcb));
- }
-#endif
- if (atio->sense_len != 0) {
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("ATIO with sense_len\n"));
-
- /*
- * We had an error in the reception of
- * this command. Immediately issue a CA.
- */
- atio->ccb_h.flags &= ~CAM_DIR_MASK;
- atio->ccb_h.flags |= CAM_DIR_NONE;
- descr->timeout = 5 * 1000;
- descr->status = SCSI_STATUS_CHECK_COND;
- copy_sense(softc, istate, (u_int8_t *)&atio->sense_data,
- atio->sense_len);
- set_ca_condition(periph, atio->init_id, CA_CMD_SENSE);
- } else if (istate->pending_ca == 0
- && istate->pending_ua != 0
- && cdb[0] != INQUIRY) {
-
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("pending_ca %d pending_ua %d\n",
- istate->pending_ca, istate->pending_ua));
-
- /* Pending UA, tell initiator */
- /* Direction is always relative to the initator */
- atio->ccb_h.flags &= ~CAM_DIR_MASK;
- atio->ccb_h.flags |= CAM_DIR_NONE;
- descr->timeout = 5 * 1000;
- descr->status = SCSI_STATUS_CHECK_COND;
- fill_sense(softc, atio->init_id,
- SSD_CURRENT_ERROR, SSD_KEY_UNIT_ATTENTION,
- 0x29,
- istate->pending_ua == UA_POWER_ON ? 1 : 2);
- set_ca_condition(periph, atio->init_id, CA_UNIT_ATTN);
- } else {
- /*
- * Save the current CA and UA status so
- * they can be used by this command.
- */
- ua_types pending_ua;
- ca_types pending_ca;
-
- pending_ua = istate->pending_ua;
- pending_ca = istate->pending_ca;
-
- /*
- * As per the SCSI2 spec, any command that occurs
- * after a CA is reported, clears the CA. We must
- * also clear the UA condition, if any, that caused
- * the CA to occur assuming the UA is not for a
- * persistant condition.
- */
- istate->pending_ca = CA_NONE;
- if (pending_ca == CA_UNIT_ATTN)
- istate->pending_ua = UA_NONE;
-
- /*
- * Determine the type of incoming command and
- * setup our buffer for a response.
- */
- switch (cdb[0]) {
- case INQUIRY:
- {
- struct scsi_inquiry *inq;
- struct scsi_sense_data *sense;
-
- inq = (struct scsi_inquiry *)cdb;
- sense = &istate->sense_data;
- descr->status = SCSI_STATUS_OK;
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Saw an inquiry!\n"));
- /*
- * Validate the command. We don't
- * support any VPD pages, so complain
- * if EVPD is set.
- */
- if ((inq->byte2 & SI_EVPD) != 0
- || inq->page_code != 0) {
- atio->ccb_h.flags &= ~CAM_DIR_MASK;
- atio->ccb_h.flags |= CAM_DIR_NONE;
- descr->timeout = 5 * 1000;
- descr->status = SCSI_STATUS_CHECK_COND;
- fill_sense(softc, atio->init_id,
- SSD_CURRENT_ERROR,
- SSD_KEY_ILLEGAL_REQUEST,
- /*asc*/0x24, /*ascq*/0x00);
- sense->extra_len =
- offsetof(struct scsi_sense_data,
- extra_bytes)
- - offsetof(struct scsi_sense_data,
- extra_len);
- set_ca_condition(periph, atio->init_id,
- CA_CMD_SENSE);
- }
-
- if ((inq->byte2 & SI_EVPD) != 0) {
- sense->sense_key_spec[0] =
- SSD_SCS_VALID|SSD_FIELDPTR_CMD
- |SSD_BITPTR_VALID| /*bit value*/1;
- sense->sense_key_spec[1] = 0;
- sense->sense_key_spec[2] =
- offsetof(struct scsi_inquiry,
- byte2);
- } else if (inq->page_code != 0) {
- sense->sense_key_spec[0] =
- SSD_SCS_VALID|SSD_FIELDPTR_CMD;
- sense->sense_key_spec[1] = 0;
- sense->sense_key_spec[2] =
- offsetof(struct scsi_inquiry,
- page_code);
- }
- if (descr->status == SCSI_STATUS_CHECK_COND)
- break;
-
- /*
- * Direction is always relative
- * to the initator.
- */
- atio->ccb_h.flags &= ~CAM_DIR_MASK;
- atio->ccb_h.flags |= CAM_DIR_IN;
- descr->data = softc->inq_data;
- descr->data_resid =
- MIN(softc->inq_data_len,
- SCSI_CDB6_LEN(inq->length));
- descr->data_increment = descr->data_resid;
- descr->timeout = 5 * 1000;
- break;
- }
- case TEST_UNIT_READY:
- atio->ccb_h.flags &= ~CAM_DIR_MASK;
- atio->ccb_h.flags |= CAM_DIR_NONE;
- descr->timeout = 5 * 1000;
- descr->status = SCSI_STATUS_OK;
- break;
- case REQUEST_SENSE:
- {
- struct scsi_request_sense *rsense;
- struct scsi_sense_data *sense;
-
- rsense = (struct scsi_request_sense *)cdb;
- sense = &istate->sense_data;
- if (pending_ca == 0) {
- fill_sense(softc, atio->init_id,
- SSD_CURRENT_ERROR,
- SSD_KEY_NO_SENSE, 0x00,
- 0x00);
- CAM_DEBUG(periph->path,
- CAM_DEBUG_PERIPH,
- ("No pending CA!\n"));
- }
- /*
- * Direction is always relative
- * to the initator.
- */
- atio->ccb_h.flags &= ~CAM_DIR_MASK;
- atio->ccb_h.flags |= CAM_DIR_IN;
- descr->data = sense;
- descr->data_resid =
- offsetof(struct scsi_sense_data,
- extra_len)
- + sense->extra_len;
- descr->data_resid =
- MIN(descr->data_resid,
- SCSI_CDB6_LEN(rsense->length));
- descr->data_increment = descr->data_resid;
- descr->timeout = 5 * 1000;
- descr->status = SCSI_STATUS_OK;
- break;
- }
- case RECEIVE:
- case SEND:
- if (SID_TYPE(softc->inq_data) == T_PROCESSOR) {
- struct scsi_send_receive *sr;
-
- sr = (struct scsi_send_receive *)cdb;
-
- /*
- * Direction is always relative
- * to the initator.
- */
- atio->ccb_h.flags &= ~CAM_DIR_MASK;
- descr->data_resid = scsi_3btoul(sr->xfer_len);
- descr->timeout = 5 * 1000;
- descr->status = SCSI_STATUS_OK;
- if (cdb[0] == SEND) {
- atio->ccb_h.flags |= CAM_DIR_OUT;
- CAM_DEBUG(periph->path,
- CAM_DEBUG_PERIPH,
- ("Saw a SEND!\n"));
- atio->ccb_h.flags |= CAM_DIR_OUT;
- TAILQ_INSERT_TAIL(&softc->snd_ccb_queue,
- &atio->ccb_h,
- periph_links.tqe);
- selwakeup(&softc->snd_select);
- } else {
- atio->ccb_h.flags |= CAM_DIR_IN;
- CAM_DEBUG(periph->path,
- CAM_DEBUG_PERIPH,
- ("Saw a RECEIVE!\n"));
- TAILQ_INSERT_TAIL(&softc->rcv_ccb_queue,
- &atio->ccb_h,
- periph_links.tqe);
- selwakeup(&softc->rcv_select);
- }
- /*
- * Attempt to satisfy this request with
- * a user buffer.
- */
- targrunqueue(periph, softc);
- return;
- }
- default:
- /*
- * Queue for consumption by our userland
- * counterpart and transition to the exception
- * state.
- */
- descr->data_resid = 0;
- descr->data_increment = 0;
- descr->user_atio = 1;
- TAILQ_INSERT_TAIL(&softc->unknown_atio_queue,
- &atio->ccb_h,
- periph_links.tqe);
- softc->exceptions |= TARG_EXCEPT_UNKNOWN_ATIO;
- targfireexception(periph, softc);
- return;
- }
- }
-
- /* Queue us up to receive a Continue Target I/O ccb. */
- if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
- TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
- periph_links.tqe);
- priority = 0;
- } else {
- TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
- periph_links.tqe);
- priority = 1;
- }
- xpt_schedule(periph, priority);
- break;
- }
- case XPT_CONT_TARGET_IO:
- {
- struct ccb_scsiio *csio;
- struct ccb_accept_tio *atio;
- struct targ_cmd_desc *desc;
- struct bio *bp;
- int error, lastctio;
-
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Received completed CTIO\n"));
- csio = &done_ccb->csio;
- atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
- desc = (struct targ_cmd_desc *)atio->ccb_h.ccb_descr;
-
- TAILQ_REMOVE(&softc->pending_queue, &done_ccb->ccb_h,
- periph_links.tqe);
-
- if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- printf("CCB with error %x\n", done_ccb->ccb_h.status);
- error = targerror(done_ccb, 0, 0);
- if (error == ERESTART)
- break;
- /*
- * Right now we don't need to do anything
- * prior to unfreezing the queue. This may
- * change if certain errors are reported while
- * we are in a connected state.
- */
- if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
- printf("Releasing Queue\n");
- cam_release_devq(done_ccb->ccb_h.path,
- /*relsim_flags*/0,
- /*reduction*/0,
- /*timeout*/0,
- /*getcount_only*/0);
- done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
- }
- } else
- error = 0;
-
- /*
- * If we shipped back sense data when completing
- * this command, clear the pending CA for it.
- */
- if (done_ccb->ccb_h.status & CAM_SENT_SENSE) {
- struct initiator_state *istate;
-
- istate = &softc->istate[csio->init_id];
- if (istate->pending_ca == CA_UNIT_ATTN)
- istate->pending_ua = UA_NONE;
- istate->pending_ca = CA_NONE;
- softc->istate[csio->init_id].pending_ca = CA_NONE;
- done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Sent Sense\n"));
- done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
- }
-
- if (done_ccb->ccb_h.status & CAM_AUTOSNS_VALID) {
- struct initiator_state *istate;
-
- istate = &softc->istate[csio->init_id];
- copy_sense(softc, istate, (u_int8_t *)&csio->sense_data,
- csio->sense_len);
- set_ca_condition(periph, csio->init_id, CA_CMD_SENSE);
- done_ccb->ccb_h.status &= ~CAM_AUTOSNS_VALID;
- }
- /*
- * Was this the last CTIO?
- */
- lastctio = done_ccb->ccb_h.status & CAM_SEND_STATUS;
-
- desc->data_increment -= csio->resid;
- desc->data_resid -= desc->data_increment;
- if ((bp = desc->bp) != NULL) {
-
- bp->bio_resid -= desc->data_increment;
- bp->bio_error = error;
-
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Buffer I/O Completed - Resid %ld:%d\n",
- bp->bio_resid, desc->data_resid));
- /*
- * Send the buffer back to the client if
- * either the command has completed or all
- * buffer space has been consumed.
- */
- if (desc->data_resid == 0
- || bp->bio_resid == 0
- || error != 0) {
- if (bp->bio_resid != 0)
- /* Short transfer */
- bp->bio_flags |= BIO_ERROR;
-
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Completing a buffer\n"));
- biodone(bp);
- desc->bp = NULL;
- }
- }
-
- if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
- atio->ccb_h.status |= CAM_DEV_QFRZN;
- xpt_release_ccb(done_ccb);
- if (softc->state != TARG_STATE_TEARDOWN) {
- if (lastctio) {
- /*
- * Send the original accept TIO back to the
- * controller to handle more work.
- */
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Returning ATIO to target SIM\n"));
- atio->ccb_h.ccb_flags = TARG_CCB_NONE;
- xpt_action((union ccb *)atio);
- break;
- }
-
- if (SID_TYPE(softc->inq_data) == T_PROCESSOR) {
- /* Queue us up for another buffer */
- if (atio->cdb_io.cdb_bytes[0] == SEND) {
- if (desc->bp != NULL)
- TAILQ_INSERT_HEAD(&softc->snd_bio_queue.queue,
- bp, bio_queue);
- TAILQ_INSERT_HEAD(&softc->snd_ccb_queue,
- &atio->ccb_h,
- periph_links.tqe);
- } else {
- if (desc->bp != NULL)
- TAILQ_INSERT_HEAD(&softc->rcv_bio_queue.queue,
- bp, bio_queue);
- TAILQ_INSERT_HEAD(&softc->rcv_ccb_queue,
- &atio->ccb_h,
- periph_links.tqe);
- }
- desc->bp = NULL;
- }
- targrunqueue(periph, softc);
- } else {
- if (desc->bp != NULL) {
- bp->bio_flags |= BIO_ERROR;
- bp->bio_error = ENXIO;
- biodone(bp);
- }
- freedescr(desc);
- free(atio, M_DEVBUF);
- }
- break;
- }
case XPT_IMMED_NOTIFY:
- {
- int frozen;
-
- frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
- if (softc->state == TARG_STATE_TEARDOWN) {
- SLIST_REMOVE(&softc->immed_notify_slist,
- &done_ccb->ccb_h, ccb_hdr,
- periph_links.sle);
- free(done_ccb, M_DEVBUF);
- } else if (done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
- free(done_ccb, M_DEVBUF);
- } else {
- printf("Saw event %x:%x\n", done_ccb->ccb_h.status,
- done_ccb->cin.message_args[0]);
- /* Process error condition. */
- targinoterror(periph, softc, &done_ccb->cin);
-
- /* Requeue for another immediate event */
- xpt_action(done_ccb);
- }
- if (frozen != 0)
- cam_release_devq(periph->path,
- /*relsim_flags*/0,
- /*opening reduction*/0,
- /*timeout*/0,
- /*getcount_only*/0);
- break;
- }
- case XPT_DEBUG:
- wakeup(&done_ccb->ccb_h.cbfcnp);
- break;
- default:
- panic("targdone: Impossible xpt opcode %x encountered.",
- done_ccb->ccb_h.func_code);
- /* NOTREACHED */
- break;
- }
-}
-
-/*
- * Transition to the exception state and notify our symbiotic
- * userland process of the change.
- */
-static void
-targfireexception(struct cam_periph *periph, struct targ_softc *softc)
-{
- /*
- * return all pending buffers with short read/write status so our
- * process unblocks, and do a selwakeup on any process queued
- * waiting for reads or writes. When the selwakeup is performed,
- * the waking process will wakeup, call our poll routine again,
- * and pick up the exception.
- */
- struct bio *bp;
-
- if (softc->state != TARG_STATE_NORMAL)
- /* Already either tearing down or in exception state */
- return;
-
- softc->state = TARG_STATE_EXCEPTION;
-
- while ((bp = bioq_first(&softc->snd_bio_queue)) != NULL) {
- bioq_remove(&softc->snd_bio_queue, bp);
- bp->bio_flags |= BIO_ERROR;
- biodone(bp);
- }
-
- while ((bp = bioq_first(&softc->rcv_bio_queue)) != NULL) {
- bioq_remove(&softc->snd_bio_queue, bp);
- bp->bio_flags |= BIO_ERROR;
- biodone(bp);
- }
-
- selwakeup(&softc->snd_select);
- selwakeup(&softc->rcv_select);
-}
-
-static void
-targinoterror(struct cam_periph *periph, struct targ_softc *softc,
- struct ccb_immed_notify *inot)
-{
- cam_status status;
- int sense;
-
- status = inot->ccb_h.status;
- sense = (status & CAM_AUTOSNS_VALID) != 0;
- status &= CAM_STATUS_MASK;
- switch (status) {
- case CAM_SCSI_BUS_RESET:
- set_unit_attention_cond(periph, /*init_id*/CAM_TARGET_WILDCARD,
- UA_BUS_RESET);
- abort_pending_transactions(periph,
- /*init_id*/CAM_TARGET_WILDCARD,
- TARG_TAG_WILDCARD, EINTR,
- /*to_held_queue*/FALSE);
- softc->exceptions |= TARG_EXCEPT_BUS_RESET_SEEN;
- targfireexception(periph, softc);
- break;
- case CAM_BDR_SENT:
- set_unit_attention_cond(periph, /*init_id*/CAM_TARGET_WILDCARD,
- UA_BDR);
- abort_pending_transactions(periph, CAM_TARGET_WILDCARD,
- TARG_TAG_WILDCARD, EINTR,
- /*to_held_queue*/FALSE);
- softc->exceptions |= TARG_EXCEPT_BDR_RECEIVED;
- targfireexception(periph, softc);
- break;
- case CAM_MESSAGE_RECV:
- switch (inot->message_args[0]) {
- case MSG_INITIATOR_DET_ERR:
- break;
- case MSG_ABORT:
- break;
- case MSG_BUS_DEV_RESET:
- break;
- case MSG_ABORT_TAG:
- break;
- case MSG_CLEAR_QUEUE:
- break;
- case MSG_TERM_IO_PROC:
- break;
- default:
- break;
- }
+ CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("freeing ccb %p\n", ccb));
+ FREE(ccb, M_TARG);
break;
default:
- break;
- }
-}
-
-static int
-targerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
-{
- struct cam_periph *periph;
- struct targ_softc *softc;
- struct ccb_scsiio *csio;
- struct initiator_state *istate;
- cam_status status;
- int frozen;
- int sense;
- int error;
- int on_held_queue;
-
- periph = xpt_path_periph(ccb->ccb_h.path);
- softc = (struct targ_softc *)periph->softc;
- status = ccb->ccb_h.status;
- sense = (status & CAM_AUTOSNS_VALID) != 0;
- frozen = (status & CAM_DEV_QFRZN) != 0;
- status &= CAM_STATUS_MASK;
- on_held_queue = FALSE;
- csio = &ccb->csio;
- istate = &softc->istate[csio->init_id];
- switch (status) {
- case CAM_REQ_ABORTED:
- if ((ccb->ccb_h.ccb_flags & TARG_CCB_ABORT_TO_HELDQ) != 0) {
-
- /*
- * Place this CCB into the initiators
- * 'held' queue until the pending CA is cleared.
- * If there is no CA pending, reissue immediately.
- */
- if (istate->pending_ca == 0) {
- ccb->ccb_h.ccb_flags = TARG_CCB_NONE;
- xpt_action(ccb);
- } else {
- ccb->ccb_h.ccb_flags = TARG_CCB_HELDQ;
- TAILQ_INSERT_TAIL(&softc->pending_queue,
- &ccb->ccb_h,
- periph_links.tqe);
- }
- /* The command will be retried at a later time. */
- on_held_queue = TRUE;
- error = ERESTART;
- break;
- }
- /* FALLTHROUGH */
- case CAM_SCSI_BUS_RESET:
- case CAM_BDR_SENT:
- case CAM_REQ_TERMIO:
- case CAM_CMD_TIMEOUT:
- /* Assume we did not send any data */
- csio->resid = csio->dxfer_len;
- error = EIO;
- break;
- case CAM_SEL_TIMEOUT:
- if (ccb->ccb_h.retry_count > 0) {
- ccb->ccb_h.retry_count--;
- error = ERESTART;
+ /* Send back CCB if we got it from the periph */
+ if (XPT_FC_IS_QUEUED(ccb)) {
+ CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
+ ("returning queued ccb %p\n", ccb));
+ xpt_release_ccb(ccb);
} else {
- /* "Select or reselect failure" */
- csio->resid = csio->dxfer_len;
- fill_sense(softc, csio->init_id, SSD_CURRENT_ERROR,
- SSD_KEY_HARDWARE_ERROR, 0x45, 0x00);
- set_ca_condition(periph, csio->init_id, CA_CMD_SENSE);
- error = EIO;
+ CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,
+ ("freeing ccb %p\n", ccb));
+ FREE(ccb, M_TARG);
}
break;
- case CAM_UNCOR_PARITY:
- /* "SCSI parity error" */
- fill_sense(softc, csio->init_id, SSD_CURRENT_ERROR,
- SSD_KEY_HARDWARE_ERROR, 0x47, 0x00);
- set_ca_condition(periph, csio->init_id, CA_CMD_SENSE);
- csio->resid = csio->dxfer_len;
- error = EIO;
- break;
- case CAM_NO_HBA:
- csio->resid = csio->dxfer_len;
- error = ENXIO;
- break;
- case CAM_SEQUENCE_FAIL:
- if (sense != 0) {
- copy_sense(softc, istate, (u_int8_t *)&csio->sense_data,
- csio->sense_len);
- set_ca_condition(periph, csio->init_id, CA_CMD_SENSE);
- }
- csio->resid = csio->dxfer_len;
- error = EIO;
- break;
- case CAM_IDE:
- /* "Initiator detected error message received" */
- fill_sense(softc, csio->init_id, SSD_CURRENT_ERROR,
- SSD_KEY_HARDWARE_ERROR, 0x48, 0x00);
- set_ca_condition(periph, csio->init_id, CA_CMD_SENSE);
- csio->resid = csio->dxfer_len;
- error = EIO;
- break;
- case CAM_REQUEUE_REQ:
- printf("Requeue Request!\n");
- error = ERESTART;
- break;
- default:
- csio->resid = csio->dxfer_len;
- error = EIO;
- panic("targerror: Unexpected status %x encounterd", status);
- /* NOTREACHED */
- }
-
- if (error == ERESTART || error == 0) {
- /* Clear the QFRZN flag as we will release the queue */
- if (frozen != 0)
- ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
-
- if (error == ERESTART && !on_held_queue)
- xpt_action(ccb);
-
- if (frozen != 0)
- cam_release_devq(ccb->ccb_h.path,
- /*relsim_flags*/0,
- /*opening reduction*/0,
- /*timeout*/0,
- /*getcount_only*/0);
}
- return (error);
}
-static struct targ_cmd_desc*
-allocdescr()
+static struct targ_cmd_descr *
+targgetdescr(struct targ_softc *softc)
{
- struct targ_cmd_desc* descr;
-
- /* Allocate the targ_descr structure */
- descr = (struct targ_cmd_desc *)
- malloc(sizeof(*descr), M_DEVBUF, M_NOWAIT);
- if (descr == NULL)
- return (NULL);
-
- bzero(descr, sizeof(*descr));
+ struct targ_cmd_descr *descr;
- /* Allocate buffer backing store */
- descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT);
- if (descr->backing_store == NULL) {
- free(descr, M_DEVBUF);
- return (NULL);
- }
- descr->max_size = MAX_BUF_SIZE;
+ MALLOC(descr, struct targ_cmd_descr *, sizeof(*descr), M_TARG,
+ M_WAITOK);
+ descr->mapinfo.num_bufs_used = 0;
return (descr);
}
static void
-freedescr(struct targ_cmd_desc *descr)
-{
- free(descr->backing_store, M_DEVBUF);
- free(descr, M_DEVBUF);
-}
-
-static void
-fill_sense(struct targ_softc *softc, u_int initiator_id, u_int error_code,
- u_int sense_key, u_int asc, u_int ascq)
-{
- struct initiator_state *istate;
- struct scsi_sense_data *sense;
-
- istate = &softc->istate[initiator_id];
- sense = &istate->sense_data;
- bzero(sense, sizeof(*sense));
- sense->error_code = error_code;
- sense->flags = sense_key;
- sense->add_sense_code = asc;
- sense->add_sense_code_qual = ascq;
-
- sense->extra_len = offsetof(struct scsi_sense_data, fru)
- - offsetof(struct scsi_sense_data, extra_len);
-}
-
-static void
-copy_sense(struct targ_softc *softc, struct initiator_state *istate,
- u_int8_t *sense_buffer, size_t sense_len)
+targinit(void)
{
- struct scsi_sense_data *sense;
- size_t copylen;
-
- sense = &istate->sense_data;
- copylen = sizeof(*sense);
- if (copylen > sense_len)
- copylen = sense_len;
- bcopy(sense_buffer, sense, copylen);
+ mtx_init(&targ_mtx, "targ global", NULL, MTX_DEF);
+ EVENTHANDLER_REGISTER(dev_clone, targclone, 0, 1000);
+ cdevsw_add(&targ_cdevsw);
}
static void
-set_unit_attention_cond(struct cam_periph *periph,
- u_int initiator_id, ua_types ua)
+targclone(void *arg, char *name, int namelen, dev_t *dev)
{
- int start;
- int end;
- struct targ_softc *softc;
+ int u;
- softc = (struct targ_softc *)periph->softc;
- if (initiator_id == CAM_TARGET_WILDCARD) {
- start = 0;
- end = MAX_INITIATORS - 1;
- } else
- start = end = initiator_id;
-
- while (start <= end) {
- softc->istate[start].pending_ua = ua;
- start++;
- }
+ if (*dev != NODEV)
+ return;
+ if (dev_stdclone(name, NULL, "targ", &u) != 1)
+ return;
+ *dev = make_dev(&targ_cdevsw, unit2minor(u), UID_ROOT, GID_WHEEL,
+ 0600, "targ%d", u);
+ (*dev)->si_flags |= SI_CHEAPCLONE;
}
static void
-set_ca_condition(struct cam_periph *periph, u_int initiator_id, ca_types ca)
+targasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
{
- struct targ_softc *softc;
-
- softc = (struct targ_softc *)periph->softc;
- softc->istate[initiator_id].pending_ca = ca;
- abort_pending_transactions(periph, initiator_id, TARG_TAG_WILDCARD,
- /*errno*/0, /*to_held_queue*/TRUE);
+ /* All events are handled in usermode by INOTs */
+ panic("targasync() called, should be an INOT instead");
}
+/* Cancel all pending requests and CCBs awaiting work. */
static void
-abort_pending_transactions(struct cam_periph *periph, u_int initiator_id,
- u_int tag_id, int errno, int to_held_queue)
+abort_all_pending(struct targ_softc *softc)
{
- struct ccb_abort cab;
- struct ccb_queue *atio_queues[3];
- struct targ_softc *softc;
- struct ccb_hdr *ccbh;
- u_int i;
-
- softc = (struct targ_softc *)periph->softc;
+ struct targ_cmd_descr *descr;
+ struct ccb_abort cab;
+ struct ccb_hdr *ccb_h;
- atio_queues[0] = &softc->work_queue;
- atio_queues[1] = &softc->snd_ccb_queue;
- atio_queues[2] = &softc->rcv_ccb_queue;
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n"));
- /* First address the ATIOs awaiting resources */
- for (i = 0; i < (sizeof(atio_queues) / sizeof(*atio_queues)); i++) {
- struct ccb_queue *atio_queue;
+ /* First abort the descriptors awaiting resources */
+ while ((descr = TAILQ_FIRST(&softc->work_queue)) != NULL) {
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("Aborting descr from workq %p\n", descr));
+ TAILQ_REMOVE(&softc->work_queue, descr, tqe);
+ TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe);
+ }
- if (to_held_queue) {
- /*
- * The device queue is frozen anyway, so there
- * is nothing for us to do.
- */
- continue;
- }
- atio_queue = atio_queues[i];
- ccbh = TAILQ_FIRST(atio_queue);
- while (ccbh != NULL) {
- struct ccb_accept_tio *atio;
- struct targ_cmd_desc *desc;
-
- atio = (struct ccb_accept_tio *)ccbh;
- desc = (struct targ_cmd_desc *)atio->ccb_h.ccb_descr;
- ccbh = TAILQ_NEXT(ccbh, periph_links.tqe);
-
- /* Only abort the CCBs that match */
- if ((atio->init_id != initiator_id
- && initiator_id != CAM_TARGET_WILDCARD)
- || (tag_id != TARG_TAG_WILDCARD
- && ((atio->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0
- || atio->tag_id != tag_id)))
- continue;
-
- TAILQ_REMOVE(atio_queue, &atio->ccb_h,
- periph_links.tqe);
-
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Aborting ATIO\n"));
- if (desc->bp != NULL) {
- desc->bp->bio_flags |= BIO_ERROR;
- if (softc->state != TARG_STATE_TEARDOWN)
- desc->bp->bio_error = errno;
- else
- desc->bp->bio_error = ENXIO;
- biodone(desc->bp);
- desc->bp = NULL;
- }
- if (softc->state == TARG_STATE_TEARDOWN) {
- freedescr(desc);
- free(atio, M_DEVBUF);
- } else {
- /* Return the ATIO back to the controller */
- atio->ccb_h.ccb_flags = TARG_CCB_NONE;
- xpt_action((union ccb *)atio);
- }
+ /*
+ * Then abort all pending CCBs.
+ * targdone() will return the aborted CCB via user_ccb_queue
+ */
+ xpt_setup_ccb(&cab.ccb_h, softc->path, /*priority*/0);
+ cab.ccb_h.func_code = XPT_ABORT;
+ cab.ccb_h.status = CAM_REQ_CMP_ERR;
+ TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, periph_links.tqe) {
+ CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,
+ ("Aborting pending CCB %p\n", ccb_h));
+ cab.abort_ccb = (union ccb *)ccb_h;
+ xpt_action((union ccb *)&cab);
+ if (cab.ccb_h.status != CAM_REQ_CMP) {
+ xpt_print_path(cab.ccb_h.path);
+ printf("Unable to abort CCB, status %#x\n",
+ cab.ccb_h.status);
}
}
- ccbh = TAILQ_FIRST(&softc->pending_queue);
- while (ccbh != NULL) {
- struct ccb_scsiio *csio;
+ /* If we aborted at least one pending CCB ok, wait for it. */
+ if (cab.ccb_h.status == CAM_REQ_CMP) {
+ msleep(&softc->pending_ccb_queue, &softc->mtx,
+ PRIBIO | PCATCH, "tgabrt", 0);
+ }
- csio = (struct ccb_scsiio *)ccbh;
- ccbh = TAILQ_NEXT(ccbh, periph_links.tqe);
+ /* If we aborted anything from the work queue, wakeup user. */
+ if (!TAILQ_EMPTY(&softc->user_ccb_queue)
+ || !TAILQ_EMPTY(&softc->abort_queue))
+ notify_user(softc);
+}
- /* Only abort the CCBs that match */
- if ((csio->init_id != initiator_id
- && initiator_id != CAM_TARGET_WILDCARD)
- || (tag_id != TARG_TAG_WILDCARD
- && ((csio->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0
- || csio->tag_id != tag_id)))
- continue;
+/* Notify the user that data is ready */
+static void
+notify_user(struct targ_softc *softc)
+{
+ /*
+ * Notify users sleeping via poll(), kqueue(), and
+ * blocking read().
+ */
+ selwakeup(&softc->read_select);
+ KNOTE(&softc->read_select.si_note, 0);
+ wakeup(&softc->user_ccb_queue);
+}
- CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH,
- ("Aborting CTIO\n"));
+/* Convert CAM status to errno values */
+static int
+targcamstatus(cam_status status)
+{
+ switch (status & CAM_STATUS_MASK) {
+ case CAM_REQ_CMP: /* CCB request completed without error */
+ return (0);
+ case CAM_REQ_INPROG: /* CCB request is in progress */
+ return (EINPROGRESS);
+ case CAM_REQ_CMP_ERR: /* CCB request completed with an error */
+ return (EIO);
+ case CAM_PROVIDE_FAIL: /* Unable to provide requested capability */
+ return (ENOTTY);
+ case CAM_FUNC_NOTAVAIL: /* The requested function is not available */
+ return (ENOTSUP);
+ case CAM_LUN_ALRDY_ENA: /* LUN is already enabled for target mode */
+ return (EADDRINUSE);
+ case CAM_PATH_INVALID: /* Supplied Path ID is invalid */
+ case CAM_DEV_NOT_THERE: /* SCSI Device Not Installed/there */
+ return (ENOENT);
+ case CAM_REQ_ABORTED: /* CCB request aborted by the host */
+ return (ECANCELED);
+ case CAM_CMD_TIMEOUT: /* Command timeout */
+ return (ETIMEDOUT);
+ case CAM_REQUEUE_REQ: /* Requeue to preserve transaction ordering */
+ return (EAGAIN);
+ case CAM_REQ_INVALID: /* CCB request was invalid */
+ return (EINVAL);
+ case CAM_RESRC_UNAVAIL: /* Resource Unavailable */
+ return (ENOMEM);
+ case CAM_BUSY: /* CAM subsytem is busy */
+ case CAM_UA_ABORT: /* Unable to abort CCB request */
+ return (EBUSY);
+ default:
+ return (ENXIO);
+ }
+}
- TAILQ_REMOVE(&softc->pending_queue, &csio->ccb_h,
- periph_links.tqe);
+static size_t
+targccblen(xpt_opcode func_code)
+{
+ int len;
- if (to_held_queue != 0)
- csio->ccb_h.ccb_flags |= TARG_CCB_ABORT_TO_HELDQ;
- xpt_setup_ccb(&cab.ccb_h, csio->ccb_h.path, /*priority*/1);
- cab.abort_ccb = (union ccb *)csio;
- xpt_action((union ccb *)&cab);
- if (cab.ccb_h.status != CAM_REQ_CMP) {
- xpt_print_path(cab.ccb_h.path);
- printf("Unable to abort CCB. Status %x\n",
- cab.ccb_h.status);
- }
+ /* Codes we expect to see as a target */
+ switch (func_code) {
+ case XPT_CONT_TARGET_IO:
+ case XPT_SCSI_IO:
+ len = sizeof(struct ccb_scsiio);
+ break;
+ case XPT_ACCEPT_TARGET_IO:
+ len = sizeof(struct ccb_accept_tio);
+ break;
+ case XPT_IMMED_NOTIFY:
+ len = sizeof(struct ccb_immed_notify);
+ break;
+ case XPT_REL_SIMQ:
+ len = sizeof(struct ccb_relsim);
+ break;
+ case XPT_PATH_INQ:
+ len = sizeof(struct ccb_pathinq);
+ break;
+ case XPT_DEBUG:
+ len = sizeof(struct ccb_debug);
+ break;
+ case XPT_ABORT:
+ len = sizeof(struct ccb_abort);
+ break;
+ case XPT_EN_LUN:
+ len = sizeof(struct ccb_en_lun);
+ break;
+ default:
+ len = sizeof(union ccb);
+ break;
}
+
+ return (len);
}
diff --git a/sys/cam/scsi/scsi_targetio.h b/sys/cam/scsi/scsi_targetio.h
index a67f78e..b6f57db 100644
--- a/sys/cam/scsi/scsi_targetio.h
+++ b/sys/cam/scsi/scsi_targetio.h
@@ -1,6 +1,7 @@
/*
- * Ioctl definitions for the Target Mode SCSI Proccessor Target driver for CAM.
+ * Ioctl definitions for the SCSI Target Driver
*
+ * Copyright (c) 2002 Nate Lawson.
* Copyright (c) 1998 Justin T. Gibbs.
* All rights reserved.
*
@@ -38,104 +39,39 @@
#include <cam/cam.h>
#include <cam/cam_ccb.h>
-TAILQ_HEAD(ccb_queue, ccb_hdr);
-
-/* Determine and clear exception state in the driver */
-typedef enum {
- TARG_EXCEPT_NONE = 0x00,
- TARG_EXCEPT_DEVICE_INVALID = 0x01,
- TARG_EXCEPT_BDR_RECEIVED = 0x02,
- TARG_EXCEPT_BUS_RESET_SEEN = 0x04,
- TARG_EXCEPT_ABORT_SEEN = 0x08,
- TARG_EXCEPT_ABORT_TAG_SEEN = 0x10,
- TARG_EXCEPT_UNKNOWN_ATIO = 0x80
-} targ_exception;
-
-#define TARGIOCFETCHEXCEPTION _IOR('C', 1, targ_exception)
-#define TARGIOCCLEAREXCEPTION _IOW('C', 2, targ_exception)
-
-/*
- * Retreive an Accept Target I/O CCB for a command that is not handled
- * directly by the kernel target driver.
- */
-#define TARGIOCFETCHATIO _IOR('C', 3, struct ccb_accept_tio)
-
/*
- * Used for responding to incoming ATIO requests. XPT_CONTINUE_TARG_IO
- * operations are the norm, but ccb types for manipulating the device
- * queue, etc. can also be used if error handling is to be performed by the
- * user land process.
+ * CCBs (ATIO, CTIO, INOT, REL_SIMQ) are sent to the kernel driver
+ * by writing one or more pointers. The user receives notification
+ * of CCB completion through poll/select/kqueue and then calls
+ * read(2) which outputs pointers to the completed CCBs.
*/
-#define TARGIOCCOMMAND _IOWR('C', 4, union ccb)
-
-
-typedef enum {
- UA_NONE = 0x00,
- UA_POWER_ON = 0x01,
- UA_BUS_RESET = 0x02,
- UA_BDR = 0x04
-} ua_types;
-
-typedef enum {
- CA_NONE = 0x00,
- CA_UNIT_ATTN = 0x01,
- CA_CMD_SENSE = 0x02
-} ca_types;
-
-struct initiator_state {
- ua_types pending_ua;
- ca_types pending_ca;
- struct scsi_sense_data sense_data;
- struct ccb_queue held_queue;
-};
-
-struct ioc_initiator_state {
- u_int initiator_id;
- struct initiator_state istate;
-};
/*
- * Get and Set Contingent Allegiance and Unit Attention state
- * presented by the target driver. This is usually used to
- * properly report and error condition in response to an incoming
- * ATIO request handled by the userland process.
- *
- * The initiator_id must be properly initialized in the ioc_initiator_state
- * structure before calling TARGIOCGETISTATE.
+ * Enable and disable a target mode instance. For enabling, the path_id,
+ * target_id, and lun_id fields must be set. The grp6/7_len fields
+ * specify the length of vendor-specific CDBs the target expects and
+ * should normally be set to 0. On successful completion
+ * of enable, the specified target instance will answer selection.
+ * Disable causes the target instance to abort any outstanding commands
+ * and stop accepting new ones. The aborted CCBs will be returned to
+ * the user via read(2) or discarded if the user closes the device.
+ * The user can then re-enable the device for a new path.
*/
-#define TARGIOCGETISTATE _IOWR('C', 6, struct ioc_initiator_state)
-#define TARGIOCSETISTATE _IOW('C', 5, struct ioc_initiator_state)
-
-struct old_ioc_alloc_unit {
+struct ioc_enable_lun {
path_id_t path_id;
target_id_t target_id;
lun_id_t lun_id;
- u_int unit;
+ int grp6_len;
+ int grp7_len;
};
-
-struct ioc_alloc_unit {
- path_id_t path_id;
- target_id_t target_id;
- lun_id_t lun_id;
- u_int unit;
- struct scsi_inquiry_data *inquiry_data;
-};
-
-/*
- * Allocate and Free a target mode instance. For allocation, the path_id,
- * target_id, and lun_id fields must be set. On successful completion
- * of the ioctl, the unit field will indicate the unit number of the
- * newly created instance. For de-allocation, all fields must match
- * an instance in the inactive (i.e. closed) state.
- */
-#define OTARGCTLIOALLOCUNIT _IOWR('C', 7, struct old_ioc_alloc_unit)
-#define OTARGCTLIOFREEUNIT _IOW('C', 8, struct old_ioc_alloc_unit)
-#define TARGCTLIOALLOCUNIT _IOWR('C', 7, struct ioc_alloc_unit)
-#define TARGCTLIOFREEUNIT _IOW('C', 8, struct ioc_alloc_unit)
+#define TARGIOCENABLE _IOW('C', 5, struct ioc_enable_lun)
+#define TARGIOCDISABLE _IO('C', 6)
/*
* Set/clear debugging for this target mode instance
*/
-#define TARGIODEBUG _IOW('C', 9, int)
+#define TARGIOCDEBUG _IOW('C', 7, int)
+
+TAILQ_HEAD(ccb_queue, ccb_hdr);
#endif /* _CAM_SCSI_SCSI_TARGETIO_H_ */
diff --git a/sys/modules/cam/Makefile b/sys/modules/cam/Makefile
index 633668d..0f0d238 100644
--- a/sys/modules/cam/Makefile
+++ b/sys/modules/cam/Makefile
@@ -15,7 +15,7 @@ SRCS+= opt_hw_wdog.h
SRCS+= opt_pt.h
SRCS+= opt_sa.h
SRCS+= opt_ses.h
-SRCS+= device_if.h bus_if.h
+SRCS+= device_if.h bus_if.h vnode_if.h
SRCS+= cam.c cam_periph.c cam_queue.c
SRCS+= cam_sim.c cam_xpt.c
SRCS+= scsi_all.c scsi_cd.c scsi_ch.c
OpenPOWER on IntegriCloud