PERFORCE change 160378 for review
Scott Long
scottl at FreeBSD.org
Wed Apr 8 07:13:12 PDT 2009
http://perforce.freebsd.org/chv.cgi?CH=160378
Change 160378 by scottl at scottl-deimos on 2009/04/08 14:13:08
Separate xpt_action into a transport-specific action, and bring some
helper functions over with it. Also create a async notification
vector.
Affected files ...
.. //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.c#83 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.h#15 edit
.. //depot/projects/scottl-camlock/src/sys/cam/scsi/scsi_xpt.c#9 edit
Differences ...
==== //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.c#83 (text+ko) ====
@@ -204,11 +204,6 @@
u_int32_t async_code,
struct cam_path *path,
void *async_arg);
-static void xpt_dev_async(u_int32_t async_code,
- struct cam_eb *bus,
- struct cam_et *target,
- struct cam_ed *device,
- void *async_arg);
static path_id_t xptnextfreepathid(void);
static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus);
static union ccb *xpt_get_ccb(struct cam_ed *device);
@@ -286,10 +281,6 @@
static xpt_busfunc_t xptsetasyncbusfunc;
static cam_status xptregister(struct cam_periph *periph,
void *arg);
-static void xpt_set_transfer_settings(struct ccb_trans_settings *cts,
- struct cam_ed *device,
- int async_update);
-static void xpt_toggle_tags(struct cam_path *path);
static void xpt_start_tags(struct cam_path *path);
static __inline int xpt_schedule_dev_allocq(struct cam_eb *bus,
struct cam_ed *dev);
@@ -2415,49 +2406,17 @@
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action\n"));
start_ccb->ccb_h.status = CAM_REQ_INPROG;
+ (*(start_ccb->ccb_h.path->bus->xport->xpt_action_func))(start_ccb);
+}
- switch (start_ccb->ccb_h.func_code) {
- case XPT_SCSI_IO:
- {
- struct cam_ed *device;
-#ifdef CAMDEBUG
- char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
- struct cam_path *path;
+void
+xpt_action_default(union ccb *start_ccb)
+{
- path = start_ccb->ccb_h.path;
-#endif
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("xpt_action_default\n"));
- /*
- * For the sake of compatibility with SCSI-1
- * devices that may not understand the identify
- * message, we include lun information in the
- * second byte of all commands. SCSI-1 specifies
- * that luns are a 3 bit value and reserves only 3
- * bits for lun information in the CDB. Later
- * revisions of the SCSI spec allow for more than 8
- * luns, but have deprecated lun information in the
- * CDB. So, if the lun won't fit, we must omit.
- *
- * Also be aware that during initial probing for devices,
- * the inquiry information is unknown but initialized to 0.
- * This means that this code will be exercised while probing
- * devices with an ANSI revision greater than 2.
- */
- device = start_ccb->ccb_h.path->device;
- if (device->protocol_version <= SCSI_REV_2
- && start_ccb->ccb_h.target_lun < 8
- && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) {
- start_ccb->csio.cdb_io.cdb_bytes[1] |=
- start_ccb->ccb_h.target_lun << 5;
- }
- start_ccb->csio.scsi_status = SCSI_STATUS_OK;
- CAM_DEBUG(path, CAM_DEBUG_CDB,("%s. CDB: %s\n",
- scsi_op_desc(start_ccb->csio.cdb_io.cdb_bytes[0],
- &path->device->inq_data),
- scsi_cdb_string(start_ccb->csio.cdb_io.cdb_bytes,
- cdb_str, sizeof(cdb_str))));
- }
+ switch (start_ccb->ccb_h.func_code) {
/* FALLTHROUGH */
case XPT_TARGET_IO:
case XPT_CONT_TARGET_IO:
@@ -2481,13 +2440,6 @@
xpt_run_dev_sendq(path->bus);
break;
}
- case XPT_SET_TRAN_SETTINGS:
- {
- xpt_set_transfer_settings(&start_ccb->cts,
- start_ccb->ccb_h.path->device,
- /*async_update*/FALSE);
- break;
- }
case XPT_CALC_GEOMETRY:
{
struct cam_sim *sim;
@@ -2573,7 +2525,6 @@
case XPT_EN_LUN:
case XPT_IMMED_NOTIFY:
case XPT_NOTIFY_ACK:
- case XPT_GET_TRAN_SETTINGS:
case XPT_RESET_BUS:
{
struct cam_sim *sim;
@@ -2938,14 +2889,6 @@
start_ccb->ccb_h.status = CAM_REQ_CMP;
break;
}
- case XPT_SCAN_BUS:
- xpt_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
- break;
- case XPT_SCAN_LUN:
- xpt_scan_lun(start_ccb->ccb_h.path->periph,
- start_ccb->ccb_h.path, start_ccb->crcn.flags,
- start_ccb);
- break;
case XPT_DEBUG: {
#ifdef CAMDEBUG
#ifdef CAM_DEBUG_DELAY
@@ -3947,8 +3890,9 @@
&& device->lun_id != CAM_LUN_WILDCARD)
continue;
- xpt_dev_async(async_code, bus, target,
- device, async_arg);
+ (*(bus->xport->xpt_dev_async_func))(async_code, bus,
+ target, device,
+ async_arg);
xpt_async_bcast(&device->asyncs, async_code,
path, async_arg);
@@ -3988,70 +3932,6 @@
}
}
-/*
- * Handle any per-device event notifications that require action by the XPT.
- */
-static void
-xpt_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
- struct cam_ed *device, void *async_arg)
-{
- cam_status status;
- struct cam_path newpath;
-
- /*
- * We only need to handle events for real devices.
- */
- if (target->target_id == CAM_TARGET_WILDCARD
- || device->lun_id == CAM_LUN_WILDCARD)
- return;
-
- /*
- * We need our own path with wildcards expanded to
- * handle certain types of events.
- */
- if ((async_code == AC_SENT_BDR)
- || (async_code == AC_BUS_RESET)
- || (async_code == AC_INQ_CHANGED))
- status = xpt_compile_path(&newpath, NULL,
- bus->path_id,
- target->target_id,
- device->lun_id);
- else
- status = CAM_REQ_CMP_ERR;
-
- if (status == CAM_REQ_CMP) {
-
- /*
- * Allow transfer negotiation to occur in a
- * tag free environment.
- */
- if (async_code == AC_SENT_BDR
- || async_code == AC_BUS_RESET)
- xpt_toggle_tags(&newpath);
-
- if (async_code == AC_INQ_CHANGED) {
- /*
- * We've sent a start unit command, or
- * something similar to a device that
- * may have caused its inquiry data to
- * change. So we re-scan the device to
- * refresh the inquiry data for it.
- */
- xpt_scan_lun(newpath.periph, &newpath,
- CAM_EXPECT_INQ_CHANGE, NULL);
- }
- xpt_release_path(&newpath);
- } else if (async_code == AC_LOST_DEVICE) {
- device->flags |= CAM_DEV_UNCONFIGURED;
- } else if (async_code == AC_TRANSFER_NEG) {
- struct ccb_trans_settings *settings;
-
- settings = (struct ccb_trans_settings *)async_arg;
- xpt_set_transfer_settings(settings, device,
- /*async_update*/TRUE);
- }
-}
-
u_int32_t
xpt_freeze_devq(struct cam_path *path, u_int count)
{
@@ -4526,326 +4406,6 @@
}
static void
-xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
- int async_update)
-{
- struct ccb_pathinq cpi;
- struct ccb_trans_settings cur_cts;
- struct ccb_trans_settings_scsi *scsi;
- struct ccb_trans_settings_scsi *cur_scsi;
- struct cam_sim *sim;
- struct scsi_inquiry_data *inq_data;
-
- if (device == NULL) {
- cts->ccb_h.status = CAM_PATH_INVALID;
- xpt_done((union ccb *)cts);
- return;
- }
-
- if (cts->protocol == PROTO_UNKNOWN
- || cts->protocol == PROTO_UNSPECIFIED) {
- cts->protocol = device->protocol;
- cts->protocol_version = device->protocol_version;
- }
-
- if (cts->protocol_version == PROTO_VERSION_UNKNOWN
- || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
- cts->protocol_version = device->protocol_version;
-
- if (cts->protocol != device->protocol) {
- xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n",
- cts->protocol, device->protocol);
- cts->protocol = device->protocol;
- }
-
- if (cts->protocol_version > device->protocol_version) {
- if (bootverbose) {
- xpt_print(cts->ccb_h.path, "Down reving Protocol "
- "Version from %d to %d?\n", cts->protocol_version,
- device->protocol_version);
- }
- cts->protocol_version = device->protocol_version;
- }
-
- if (cts->transport == XPORT_UNKNOWN
- || cts->transport == XPORT_UNSPECIFIED) {
- cts->transport = device->transport;
- cts->transport_version = device->transport_version;
- }
-
- if (cts->transport_version == XPORT_VERSION_UNKNOWN
- || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
- cts->transport_version = device->transport_version;
-
- if (cts->transport != device->transport) {
- xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n",
- cts->transport, device->transport);
- cts->transport = device->transport;
- }
-
- if (cts->transport_version > device->transport_version) {
- if (bootverbose) {
- xpt_print(cts->ccb_h.path, "Down reving Transport "
- "Version from %d to %d?\n", cts->transport_version,
- device->transport_version);
- }
- cts->transport_version = device->transport_version;
- }
-
- sim = cts->ccb_h.path->bus->sim;
-
- /*
- * Nothing more of interest to do unless
- * this is a device connected via the
- * SCSI protocol.
- */
- if (cts->protocol != PROTO_SCSI) {
- if (async_update == FALSE)
- (*(sim->sim_action))(sim, (union ccb *)cts);
- return;
- }
-
- inq_data = &device->inq_data;
- scsi = &cts->proto_specific.scsi;
- xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1);
- cpi.ccb_h.func_code = XPT_PATH_INQ;
- xpt_action((union ccb *)&cpi);
-
- /* SCSI specific sanity checking */
- if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
- || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
- || (device->queue_flags & SCP_QUEUE_DQUE) != 0
- || (device->mintags == 0)) {
- /*
- * Can't tag on hardware that doesn't support tags,
- * doesn't have it enabled, or has broken tag support.
- */
- scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
- }
-
- if (async_update == FALSE) {
- /*
- * Perform sanity checking against what the
- * controller and device can do.
- */
- xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1);
- cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
- cur_cts.type = cts->type;
- xpt_action((union ccb *)&cur_cts);
- if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- return;
- }
- cur_scsi = &cur_cts.proto_specific.scsi;
- if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
- scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
- scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB;
- }
- if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0)
- scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
- }
-
- /* SPI specific sanity checking */
- if (cts->transport == XPORT_SPI && async_update == FALSE) {
- u_int spi3caps;
- struct ccb_trans_settings_spi *spi;
- struct ccb_trans_settings_spi *cur_spi;
-
- spi = &cts->xport_specific.spi;
-
- cur_spi = &cur_cts.xport_specific.spi;
-
- /* Fill in any gaps in what the user gave us */
- if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
- spi->sync_period = cur_spi->sync_period;
- if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
- spi->sync_period = 0;
- if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
- spi->sync_offset = cur_spi->sync_offset;
- if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
- spi->sync_offset = 0;
- if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0)
- spi->ppr_options = cur_spi->ppr_options;
- if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0)
- spi->ppr_options = 0;
- if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0)
- spi->bus_width = cur_spi->bus_width;
- if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0)
- spi->bus_width = 0;
- if ((spi->valid & CTS_SPI_VALID_DISC) == 0) {
- spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
- spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB;
- }
- if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0)
- spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
- if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
- && (inq_data->flags & SID_Sync) == 0
- && cts->type == CTS_TYPE_CURRENT_SETTINGS)
- || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)) {
- /* Force async */
- spi->sync_period = 0;
- spi->sync_offset = 0;
- }
-
- switch (spi->bus_width) {
- case MSG_EXT_WDTR_BUS_32_BIT:
- if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
- || (inq_data->flags & SID_WBus32) != 0
- || cts->type == CTS_TYPE_USER_SETTINGS)
- && (cpi.hba_inquiry & PI_WIDE_32) != 0)
- break;
- /* Fall Through to 16-bit */
- case MSG_EXT_WDTR_BUS_16_BIT:
- if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
- || (inq_data->flags & SID_WBus16) != 0
- || cts->type == CTS_TYPE_USER_SETTINGS)
- && (cpi.hba_inquiry & PI_WIDE_16) != 0) {
- spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
- break;
- }
- /* Fall Through to 8-bit */
- default: /* New bus width?? */
- case MSG_EXT_WDTR_BUS_8_BIT:
- /* All targets can do this */
- spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- break;
- }
-
- spi3caps = cpi.xport_specific.spi.ppr_options;
- if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
- && cts->type == CTS_TYPE_CURRENT_SETTINGS)
- spi3caps &= inq_data->spi3data;
-
- if ((spi3caps & SID_SPI_CLOCK_DT) == 0)
- spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ;
-
- if ((spi3caps & SID_SPI_IUS) == 0)
- spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ;
-
- if ((spi3caps & SID_SPI_QAS) == 0)
- spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
-
- /* No SPI Transfer settings are allowed unless we are wide */
- if (spi->bus_width == 0)
- spi->ppr_options = 0;
-
- if ((spi->valid & CTS_SPI_VALID_DISC)
- && ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0)) {
- /*
- * Can't tag queue without disconnection.
- */
- scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
- scsi->valid |= CTS_SCSI_VALID_TQ;
- }
-
- /*
- * If we are currently performing tagged transactions to
- * this device and want to change its negotiation parameters,
- * go non-tagged for a bit to give the controller a chance to
- * negotiate unhampered by tag messages.
- */
- if (cts->type == CTS_TYPE_CURRENT_SETTINGS
- && (device->inq_flags & SID_CmdQue) != 0
- && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
- && (spi->flags & (CTS_SPI_VALID_SYNC_RATE|
- CTS_SPI_VALID_SYNC_OFFSET|
- CTS_SPI_VALID_BUS_WIDTH)) != 0)
- xpt_toggle_tags(cts->ccb_h.path);
- }
-
- if (cts->type == CTS_TYPE_CURRENT_SETTINGS
- && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
- int device_tagenb;
-
- /*
- * If we are transitioning from tags to no-tags or
- * vice-versa, we need to carefully freeze and restart
- * the queue so that we don't overlap tagged and non-tagged
- * commands. We also temporarily stop tags if there is
- * a change in transfer negotiation settings to allow
- * "tag-less" negotiation.
- */
- if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
- || (device->inq_flags & SID_CmdQue) != 0)
- device_tagenb = TRUE;
- else
- device_tagenb = FALSE;
-
- if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
- && device_tagenb == FALSE)
- || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0
- && device_tagenb == TRUE)) {
-
- if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
- /*
- * Delay change to use tags until after a
- * few commands have gone to this device so
- * the controller has time to perform transfer
- * negotiations without tagged messages getting
- * in the way.
- */
- device->tag_delay_count = CAM_TAG_DELAY_COUNT;
- device->flags |= CAM_DEV_TAG_AFTER_COUNT;
- } else {
- struct ccb_relsim crs;
-
- xpt_freeze_devq(cts->ccb_h.path, /*count*/1);
- device->inq_flags &= ~SID_CmdQue;
- xpt_dev_ccbq_resize(cts->ccb_h.path,
- sim->max_dev_openings);
- device->flags &= ~CAM_DEV_TAG_AFTER_COUNT;
- device->tag_delay_count = 0;
-
- xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path,
- /*priority*/1);
- crs.ccb_h.func_code = XPT_REL_SIMQ;
- crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY;
- crs.openings
- = crs.release_timeout
- = crs.qfrozen_cnt
- = 0;
- xpt_action((union ccb *)&crs);
- }
- }
- }
- if (async_update == FALSE)
- (*(sim->sim_action))(sim, (union ccb *)cts);
-}
-
-
-static void
-xpt_toggle_tags(struct cam_path *path)
-{
- struct cam_ed *dev;
-
- /*
- * Give controllers a chance to renegotiate
- * before starting tag operations. We
- * "toggle" tagged queuing off then on
- * which causes the tag enable command delay
- * counter to come into effect.
- */
- dev = path->device;
- if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
- || ((dev->inq_flags & SID_CmdQue) != 0
- && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) {
- struct ccb_trans_settings cts;
-
- xpt_setup_ccb(&cts.ccb_h, path, 1);
- cts.protocol = PROTO_SCSI;
- cts.protocol_version = PROTO_VERSION_UNSPECIFIED;
- cts.transport = XPORT_UNSPECIFIED;
- cts.transport_version = XPORT_VERSION_UNSPECIFIED;
- cts.proto_specific.scsi.flags = 0;
- cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
- xpt_set_transfer_settings(&cts, path->device,
- /*async_update*/TRUE);
- cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
- xpt_set_transfer_settings(&cts, path->device,
- /*async_update*/TRUE);
- }
-}
-
-static void
xpt_start_tags(struct cam_path *path)
{
struct ccb_relsim crs;
==== //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.h#15 (text+ko) ====
@@ -173,6 +173,7 @@
typedef struct cam_ed * (*xpt_alloc_device_func)(struct cam_eb *bus,
struct cam_et *target,
lun_id_t lun_id);
+typedef void (*xpt_action_func)(union ccb *start_ccb);
#if defined(CAM_DEBUG_FLAGS) && !defined(CAMDEBUG)
#error "You must have options CAMDEBUG to use options CAM_DEBUG_FLAGS"
@@ -199,6 +200,7 @@
MALLOC_DECLARE(M_CAMXPT);
void xpt_action(union ccb *new_ccb);
+void xpt_action_default(union ccb *new_ccb);
static struct cam_ed* xpt_alloc_device(struct cam_eb *bus,
struct cam_et *target,
lun_id_t lun_id);
==== //depot/projects/scottl-camlock/src/sys/cam/scsi/scsi_xpt.c#9 (text+ko) ====
@@ -540,6 +540,15 @@
scsi_alloc_device(struct cam_eb *bus, struct cam_et *target,
lun_id_t lun_id);
static void scsi_devise_transport(struct cam_path *path);
+static void xpt_set_transfer_settings(struct ccb_trans_settings *cts,
+ struct cam_ed *device,
+ int async_update);
+static void xpt_toggle_tags(struct cam_path *path);
+static void xpt_dev_async(u_int32_t async_code,
+ struct cam_eb *bus,
+ struct cam_et *target,
+ struct cam_ed *device,
+ void *async_arg);
static void
probe_periph_init()
@@ -1938,3 +1947,476 @@
xpt_action((union ccb *)&cts);
}
+static void
+scsi_action(union ccb *start_ccb)
+{
+
+ switch (start_ccb->ccb_h.func_code) {
+ case XPT_SCSI_IO:
+ {
+ struct cam_ed *device;
+#ifdef CAMDEBUG
+ char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
+ struct cam_path *path;
+
+ path = start_ccb->ccb_h.path;
+#endif
+
+ /*
+ * For the sake of compatibility with SCSI-1
+ * devices that may not understand the identify
+ * message, we include lun information in the
+ * second byte of all commands. SCSI-1 specifies
+ * that luns are a 3 bit value and reserves only 3
+ * bits for lun information in the CDB. Later
+ * revisions of the SCSI spec allow for more than 8
+ * luns, but have deprecated lun information in the
+ * CDB. So, if the lun won't fit, we must omit.
+ *
+ * Also be aware that during initial probing for devices,
+ * the inquiry information is unknown but initialized to 0.
+ * This means that this code will be exercised while probing
+ * devices with an ANSI revision greater than 2.
+ */
+ device = start_ccb->ccb_h.path->device;
+ if (device->protocol_version <= SCSI_REV_2
+ && start_ccb->ccb_h.target_lun < 8
+ && (start_ccb->ccb_h.flags & CAM_CDB_POINTER) == 0) {
+
+ start_ccb->csio.cdb_io.cdb_bytes[1] |=
+ start_ccb->ccb_h.target_lun << 5;
+ }
+ start_ccb->csio.scsi_status = SCSI_STATUS_OK;
+ CAM_DEBUG(path, CAM_DEBUG_CDB,("%s. CDB: %s\n",
+ scsi_op_desc(start_ccb->csio.cdb_io.cdb_bytes[0],
+ &path->device->inq_data),
+ scsi_cdb_string(start_ccb->csio.cdb_io.cdb_bytes,
+ cdb_str, sizeof(cdb_str))));
+ }
+ {
+ struct cam_path *path;
+ int runq;
+
+ path = start_ccb->ccb_h.path;
+
+ cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb);
+ if (path->device->qfrozen_cnt == 0)
+ runq = xpt_schedule_dev_sendq(path->bus, path->device);
+ else
+ runq = 0;
+ if (runq != 0)
+ xpt_run_dev_sendq(path->bus);
+ break;
+ }
+ case XPT_SET_TRAN_SETTINGS:
+ {
+ xpt_set_transfer_settings(&start_ccb->cts,
+ start_ccb->ccb_h.path->device,
+ /*async_update*/FALSE);
+ break;
+ }
+ case XPT_SCAN_BUS:
+ xpt_scan_bus(start_ccb->ccb_h.path->periph, start_ccb);
+ break;
+ case XPT_SCAN_LUN:
+ xpt_scan_lun(start_ccb->ccb_h.path->periph,
+ start_ccb->ccb_h.path, start_ccb->crcn.flags,
+ start_ccb);
+ break;
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct cam_sim *sim;
+
+ sim = start_ccb->ccb_h.path->bus->sim;
+ (*(sim->sim_action))(sim, start_ccb);
+ break;
+ }
+ default:
+ xpt_action_default(start_ccb);
+ break;
+ }
+}
+
+static void
+xpt_set_transfer_settings(struct ccb_trans_settings *cts, struct cam_ed *device,
+ int async_update)
+{
+ struct ccb_pathinq cpi;
+ struct ccb_trans_settings cur_cts;
+ struct ccb_trans_settings_scsi *scsi;
+ struct ccb_trans_settings_scsi *cur_scsi;
+ struct cam_sim *sim;
+ struct scsi_inquiry_data *inq_data;
+
+ if (device == NULL) {
+ cts->ccb_h.status = CAM_PATH_INVALID;
+ xpt_done((union ccb *)cts);
+ return;
+ }
+
+ if (cts->protocol == PROTO_UNKNOWN
+ || cts->protocol == PROTO_UNSPECIFIED) {
+ cts->protocol = device->protocol;
+ cts->protocol_version = device->protocol_version;
+ }
+
+ if (cts->protocol_version == PROTO_VERSION_UNKNOWN
+ || cts->protocol_version == PROTO_VERSION_UNSPECIFIED)
+ cts->protocol_version = device->protocol_version;
+
+ if (cts->protocol != device->protocol) {
+ xpt_print(cts->ccb_h.path, "Uninitialized Protocol %x:%x?\n",
+ cts->protocol, device->protocol);
+ cts->protocol = device->protocol;
+ }
+
+ if (cts->protocol_version > device->protocol_version) {
+ if (bootverbose) {
+ xpt_print(cts->ccb_h.path, "Down reving Protocol "
+ "Version from %d to %d?\n", cts->protocol_version,
+ device->protocol_version);
+ }
+ cts->protocol_version = device->protocol_version;
+ }
+
+ if (cts->transport == XPORT_UNKNOWN
+ || cts->transport == XPORT_UNSPECIFIED) {
+ cts->transport = device->transport;
+ cts->transport_version = device->transport_version;
+ }
+
+ if (cts->transport_version == XPORT_VERSION_UNKNOWN
+ || cts->transport_version == XPORT_VERSION_UNSPECIFIED)
+ cts->transport_version = device->transport_version;
+
+ if (cts->transport != device->transport) {
+ xpt_print(cts->ccb_h.path, "Uninitialized Transport %x:%x?\n",
+ cts->transport, device->transport);
+ cts->transport = device->transport;
+ }
+
+ if (cts->transport_version > device->transport_version) {
+ if (bootverbose) {
+ xpt_print(cts->ccb_h.path, "Down reving Transport "
+ "Version from %d to %d?\n", cts->transport_version,
+ device->transport_version);
+ }
+ cts->transport_version = device->transport_version;
+ }
+
+ sim = cts->ccb_h.path->bus->sim;
+
+ /*
+ * Nothing more of interest to do unless
+ * this is a device connected via the
+ * SCSI protocol.
+ */
+ if (cts->protocol != PROTO_SCSI) {
+ if (async_update == FALSE)
+ (*(sim->sim_action))(sim, (union ccb *)cts);
+ return;
+ }
+
+ inq_data = &device->inq_data;
+ scsi = &cts->proto_specific.scsi;
+ xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, /*priority*/1);
+ cpi.ccb_h.func_code = XPT_PATH_INQ;
+ xpt_action((union ccb *)&cpi);
+
+ /* SCSI specific sanity checking */
+ if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0
+ || (INQ_DATA_TQ_ENABLED(inq_data)) == 0
+ || (device->queue_flags & SCP_QUEUE_DQUE) != 0
+ || (device->mintags == 0)) {
+ /*
+ * Can't tag on hardware that doesn't support tags,
+ * doesn't have it enabled, or has broken tag support.
+ */
+ scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
+ }
+
+ if (async_update == FALSE) {
+ /*
+ * Perform sanity checking against what the
+ * controller and device can do.
+ */
+ xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, /*priority*/1);
+ cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
+ cur_cts.type = cts->type;
+ xpt_action((union ccb *)&cur_cts);
+ if ((cur_cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ return;
+ }
+ cur_scsi = &cur_cts.proto_specific.scsi;
+ if ((scsi->valid & CTS_SCSI_VALID_TQ) == 0) {
+ scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
+ scsi->flags |= cur_scsi->flags & CTS_SCSI_FLAGS_TAG_ENB;
+ }
+ if ((cur_scsi->valid & CTS_SCSI_VALID_TQ) == 0)
+ scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
+ }
+
+ /* SPI specific sanity checking */
+ if (cts->transport == XPORT_SPI && async_update == FALSE) {
+ u_int spi3caps;
+ struct ccb_trans_settings_spi *spi;
+ struct ccb_trans_settings_spi *cur_spi;
+
+ spi = &cts->xport_specific.spi;
+
+ cur_spi = &cur_cts.xport_specific.spi;
+
+ /* Fill in any gaps in what the user gave us */
+ if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
+ spi->sync_period = cur_spi->sync_period;
+ if ((cur_spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
+ spi->sync_period = 0;
+ if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
+ spi->sync_offset = cur_spi->sync_offset;
+ if ((cur_spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
+ spi->sync_offset = 0;
+ if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0)
+ spi->ppr_options = cur_spi->ppr_options;
+ if ((cur_spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0)
+ spi->ppr_options = 0;
+ if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0)
+ spi->bus_width = cur_spi->bus_width;
+ if ((cur_spi->valid & CTS_SPI_VALID_BUS_WIDTH) == 0)
+ spi->bus_width = 0;
+ if ((spi->valid & CTS_SPI_VALID_DISC) == 0) {
+ spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
+ spi->flags |= cur_spi->flags & CTS_SPI_FLAGS_DISC_ENB;
+ }
+ if ((cur_spi->valid & CTS_SPI_VALID_DISC) == 0)
+ spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
+ if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
+ && (inq_data->flags & SID_Sync) == 0
+ && cts->type == CTS_TYPE_CURRENT_SETTINGS)
+ || ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0)) {
+ /* Force async */
+ spi->sync_period = 0;
+ spi->sync_offset = 0;
+ }
+
+ switch (spi->bus_width) {
+ case MSG_EXT_WDTR_BUS_32_BIT:
+ if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
+ || (inq_data->flags & SID_WBus32) != 0
+ || cts->type == CTS_TYPE_USER_SETTINGS)
+ && (cpi.hba_inquiry & PI_WIDE_32) != 0)
+ break;
+ /* Fall Through to 16-bit */
+ case MSG_EXT_WDTR_BUS_16_BIT:
+ if (((device->flags & CAM_DEV_INQUIRY_DATA_VALID) == 0
+ || (inq_data->flags & SID_WBus16) != 0
+ || cts->type == CTS_TYPE_USER_SETTINGS)
+ && (cpi.hba_inquiry & PI_WIDE_16) != 0) {
+ spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+ break;
+ }
+ /* Fall Through to 8-bit */
+ default: /* New bus width?? */
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ /* All targets can do this */
+ spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ break;
+ }
+
+ spi3caps = cpi.xport_specific.spi.ppr_options;
+ if ((device->flags & CAM_DEV_INQUIRY_DATA_VALID) != 0
+ && cts->type == CTS_TYPE_CURRENT_SETTINGS)
+ spi3caps &= inq_data->spi3data;
+
+ if ((spi3caps & SID_SPI_CLOCK_DT) == 0)
+ spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+
+ if ((spi3caps & SID_SPI_IUS) == 0)
+ spi->ppr_options &= ~MSG_EXT_PPR_IU_REQ;
+
+ if ((spi3caps & SID_SPI_QAS) == 0)
+ spi->ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
+
+ /* No SPI Transfer settings are allowed unless we are wide */
+ if (spi->bus_width == 0)
+ spi->ppr_options = 0;
+
+ if ((spi->valid & CTS_SPI_VALID_DISC)
+ && ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) == 0)) {
+ /*
+ * Can't tag queue without disconnection.
+ */
+ scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
+ scsi->valid |= CTS_SCSI_VALID_TQ;
+ }
+
+ /*
+ * If we are currently performing tagged transactions to
+ * this device and want to change its negotiation parameters,
+ * go non-tagged for a bit to give the controller a chance to
+ * negotiate unhampered by tag messages.
+ */
+ if (cts->type == CTS_TYPE_CURRENT_SETTINGS
+ && (device->inq_flags & SID_CmdQue) != 0
+ && (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
+ && (spi->flags & (CTS_SPI_VALID_SYNC_RATE|
+ CTS_SPI_VALID_SYNC_OFFSET|
+ CTS_SPI_VALID_BUS_WIDTH)) != 0)
+ xpt_toggle_tags(cts->ccb_h.path);
+ }
+
+ if (cts->type == CTS_TYPE_CURRENT_SETTINGS
+ && (scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
+ int device_tagenb;
+
+ /*
+ * If we are transitioning from tags to no-tags or
+ * vice-versa, we need to carefully freeze and restart
+ * the queue so that we don't overlap tagged and non-tagged
+ * commands. We also temporarily stop tags if there is
+ * a change in transfer negotiation settings to allow
+ * "tag-less" negotiation.
+ */
+ if ((device->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
+ || (device->inq_flags & SID_CmdQue) != 0)
+ device_tagenb = TRUE;
+ else
+ device_tagenb = FALSE;
+
+ if (((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0
+ && device_tagenb == FALSE)
+ || ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) == 0
+ && device_tagenb == TRUE)) {
+
+ if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) {
+ /*
+ * Delay change to use tags until after a
+ * few commands have gone to this device so
+ * the controller has time to perform transfer
+ * negotiations without tagged messages getting
+ * in the way.
+ */
+ device->tag_delay_count = CAM_TAG_DELAY_COUNT;
+ device->flags |= CAM_DEV_TAG_AFTER_COUNT;
+ } else {
+ struct ccb_relsim crs;
+
+ xpt_freeze_devq(cts->ccb_h.path, /*count*/1);
+ device->inq_flags &= ~SID_CmdQue;
+ xpt_dev_ccbq_resize(cts->ccb_h.path,
+ sim->max_dev_openings);
+ device->flags &= ~CAM_DEV_TAG_AFTER_COUNT;
+ device->tag_delay_count = 0;
+
+ xpt_setup_ccb(&crs.ccb_h, cts->ccb_h.path,
+ /*priority*/1);
+ crs.ccb_h.func_code = XPT_REL_SIMQ;
+ crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY;
+ crs.openings
+ = crs.release_timeout
+ = crs.qfrozen_cnt
+ = 0;
+ xpt_action((union ccb *)&crs);
+ }
+ }
+ }
+ if (async_update == FALSE)
+ (*(sim->sim_action))(sim, (union ccb *)cts);
+}
+
+static void
+xpt_toggle_tags(struct cam_path *path)
+{
+ struct cam_ed *dev;
+
+ /*
+ * Give controllers a chance to renegotiate
+ * before starting tag operations. We
+ * "toggle" tagged queuing off then on
+ * which causes the tag enable command delay
+ * counter to come into effect.
+ */
+ dev = path->device;
+ if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0
+ || ((dev->inq_flags & SID_CmdQue) != 0
+ && (dev->inq_flags & (SID_Sync|SID_WBus16|SID_WBus32)) != 0)) {
+ struct ccb_trans_settings cts;
+
+ xpt_setup_ccb(&cts.ccb_h, path, 1);
+ cts.protocol = PROTO_SCSI;
+ cts.protocol_version = PROTO_VERSION_UNSPECIFIED;
+ cts.transport = XPORT_UNSPECIFIED;
+ cts.transport_version = XPORT_VERSION_UNSPECIFIED;
+ cts.proto_specific.scsi.flags = 0;
+ cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
+ xpt_set_transfer_settings(&cts, path->device,
+ /*async_update*/TRUE);
+ cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
+ xpt_set_transfer_settings(&cts, path->device,
+ /*async_update*/TRUE);
+ }
+}
+
+/*
+ * Handle any per-device event notifications that require action by the XPT.
+ */
+static void
+xpt_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
+ struct cam_ed *device, void *async_arg)
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list