summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua M. Clulow <jmc@joyent.com>2016-03-04 04:53:43 +0000
committerJoshua M. Clulow <jmc@joyent.com>2016-07-06 16:25:26 +0000
commit0e2422b4b98c00ad10ff1594813b9b07a1a3b88e (patch)
tree1148d229e3029ae46ae494d6938bfcd9d9ddba33
parent5a46843f22669876303102876598a411aedc3c94 (diff)
downloadillumos-joyent-0e2422b4b98c00ad10ff1594813b9b07a1a3b88e.tar.gz
XXX more extensive refactoring; into the SCSA HBA driver stuff
-rw-r--r--usr/src/uts/common/Makefile.files4
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3.c89
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3.h243
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_ciss.c227
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_ciss.h10
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c102
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_commands.c65
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_hba.c115
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_interrupts.c114
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_logvol.c259
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_scsi.c179
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_scsi.h66
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_transport.c476
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_util.c143
14 files changed, 1251 insertions, 841 deletions
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 938ab2b69f..7a135acb5e 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -2160,8 +2160,10 @@ CPQARY3_OBJS = cpqary3.o \
cpqary3_device.o \
cpqary3_interrupts.o \
cpqary3_commands.o \
+ cpqary3_logvol.o \
+ cpqary3_hba.o \
cpqary3_ciss_simple.o \
- cpqary3_ciss.o
+ cpqary3_ciss.o \
#
# ISCSI_INITIATOR module
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3.c b/usr/src/uts/common/io/cpqary3/cpqary3.c
index 83eaf65549..6df5d368ee 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3.c
@@ -246,16 +246,16 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
cpq->cpq_next_tag = CPQARY3_MIN_TAG_NUMBER;
list_create(&cpq->cpq_commands, sizeof (cpqary3_command_t),
offsetof(cpqary3_command_t, cpcm_link));
+ list_create(&cpq->cpq_finishq, sizeof (cpqary3_command_t),
+ offsetof(cpqary3_command_t, cpcm_link_finish));
avl_create(&cpq->cpq_inflight, cpqary3_command_comparator,
sizeof (cpqary3_command_t), offsetof(cpqary3_command_t,
cpcm_node));
- cv_init(&cpq->cv_immediate_wait, NULL, CV_DRIVER, NULL);
- cv_init(&cpq->cv_flushcache_wait, NULL, CV_DRIVER, NULL);
- cv_init(&cpq->cv_abort_wait, NULL, CV_DRIVER, NULL);
- cv_init(&cpq->cv_ioctl_wait, NULL, CV_DRIVER, NULL);
- cpq->cpqary3_tgtp[CTLR_SCSI_ID] = kmem_zalloc(sizeof (cpqary3_tgt_t),
+ mutex_init(&cpq->cpq_mutex, NULL, MUTEX_DRIVER, NULL);
+ cv_init(&cpq->cpq_cv_finishq, NULL, CV_DRIVER, NULL);
+ cpq->cpq_targets[CTLR_SCSI_ID] = kmem_zalloc(sizeof (cpqary3_tgt_t),
KM_SLEEP);
- cpq->cpqary3_tgtp[CTLR_SCSI_ID]->type = CPQARY3_TARGET_CTLR;
+ cpq->cpq_targets[CTLR_SCSI_ID]->type = CPQARY3_TARGET_CTLR;
cpq->cpq_init_level |= CPQARY3_INITLEVEL_BASIC;
@@ -265,8 +265,7 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
*/
if (cpqary3_device_setup(cpq) != DDI_SUCCESS) {
dev_err(dip, CE_WARN, "device setup failed");
- cpqary3_cleanup(cpq);
- return (DDI_FAILURE);
+ goto fail;
}
/*
@@ -276,8 +275,7 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
*/
if (cpqary3_ctlr_init(cpq) != DDI_SUCCESS) {
dev_err(dip, CE_WARN, "controller initialisation failed");
- cpqary3_cleanup(cpq);
- return (DDI_FAILURE);
+ goto fail;
}
/*
@@ -286,8 +284,7 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
*/
if (cpqary3_interrupts_setup(cpq) != DDI_SUCCESS) {
dev_err(dip, CE_WARN, "interrupt handler setup failed");
- cpqary3_cleanup(cpq);
- return (DDI_FAILURE);
+ goto fail;
}
/*
@@ -296,8 +293,7 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
if ((cpq->cpq_hba_tran = scsi_hba_tran_alloc(dip,
SCSI_HBA_CANSLEEP)) == NULL) {
dev_err(dip, CE_WARN, "scsi_hba_tran_alloc failed");
- cpqary3_cleanup(cpq);
- return (DDI_FAILURE);
+ goto fail;
}
cpq->cpq_init_level |= CPQARY3_INITLEVEL_HBA_ALLOC;
@@ -318,29 +314,10 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
if (scsi_hba_attach_setup(dip, &tmp_dma_attr, cpq->cpq_hba_tran,
SCSI_HBA_TRAN_CLONE) == DDI_FAILURE) {
dev_err(dip, CE_WARN, "scsi_hba_attach_setup failed");
- cpqary3_cleanup(cpq);
- return (DDI_FAILURE);
+ goto fail;
}
cpq->cpq_init_level |= CPQARY3_INITLEVEL_HBA_ATTACH;
- /*
- * Create a minor node for Ioctl interface.
- * The nomenclature used will be "cpqary3" immediately followed by
- * the current driver instance in the system.
- * for e.g.: for 0th instance : cpqary3,0
- * for 1st instance : cpqary3,1
- */
- (void) sprintf(minor_node_name, "cpqary3,%d", instance);
-
- if (ddi_create_minor_node(dip, minor_node_name, S_IFCHR,
- CPQARY3_INST2CPQARY3(instance), DDI_NT_SCSI_NEXUS, 0) !=
- DDI_SUCCESS) {
- cmn_err(CE_NOTE, "CPQary3 : Failed to create minor node");
- cpqary3_cleanup(cpq);
- return (DDI_FAILURE);
- }
- cpq->cpq_init_level |= CPQARY3_INITLEVEL_MINOR_NODE;
-
/* Enable the Controller Interrupt */
cpqary3_intr_set(cpq, B_TRUE);
if (cpq->cpq_host_support & 0x4) {
@@ -357,9 +334,17 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
/* Report that an Instance of the Driver is Attached Successfully */
ddi_report_dev(dip);
+ if (cpqary3_discover_logical_volumes(cpq, 30) != 0) {
+ dev_err(dip, CE_WARN, "could not discover logical volumes");
+ goto fail;
+ }
+
return (DDI_SUCCESS);
-}
+fail:
+ cpqary3_cleanup(cpq);
+ return (DDI_FAILURE);
+}
static int
cpqary3_detach(dev_info_t *dip, ddi_detach_cmd_t detach_cmd)
@@ -425,10 +410,6 @@ cpqary3_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
static void
cpqary3_cleanup(cpqary3_t *cpq)
{
- int8_t node_name[10];
- clock_t cpqary3_lbolt;
- uint32_t targ;
-
cpqary3_interrupts_teardown(cpq);
if (cpq->cpq_init_level & CPQARY3_INITLEVEL_PERIODIC) {
@@ -436,13 +417,6 @@ cpqary3_cleanup(cpqary3_t *cpq)
cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_PERIODIC;
}
- if (cpq->cpq_init_level & CPQARY3_INITLEVEL_MINOR_NODE) {
- (void) sprintf(node_name, "cpqary3%d",
- ddi_get_instance(cpq->dip));
- ddi_remove_minor_node(cpq->dip, node_name);
- cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_MINOR_NODE;
- }
-
if (cpq->cpq_init_level & CPQARY3_INITLEVEL_HBA_ATTACH) {
(void) scsi_hba_detach(cpq->dip);
cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_HBA_ATTACH;
@@ -454,23 +428,20 @@ cpqary3_cleanup(cpqary3_t *cpq)
}
if (cpq->cpq_init_level & CPQARY3_INITLEVEL_BASIC) {
- mutex_enter(&cpq->hw_mutex);
+ mutex_destroy(&cpq->cpq_mutex);
- cv_destroy(&cpq->cv_abort_wait);
- cv_destroy(&cpq->cv_flushcache_wait);
- cv_destroy(&cpq->cv_immediate_wait);
- cv_destroy(&cpq->cv_ioctl_wait);
+ cv_destroy(&cpq->cpq_cv_finishq);
- for (targ = 0; targ < CPQARY3_MAX_TGT; targ++) {
- if (cpq->cpqary3_tgtp[targ] == NULL)
+ for (int targ = 0; targ < CPQARY3_MAX_TGT; targ++) {
+ if (cpq->cpq_targets[targ] == NULL) {
continue;
- kmem_free(cpq->cpqary3_tgtp[targ],
+ }
+
+ kmem_free(cpq->cpq_targets[targ],
sizeof (cpqary3_tgt_t));
- cpq->cpqary3_tgtp[targ] = NULL;
+ cpq->cpq_targets[targ] = NULL;
}
- mutex_exit(&cpq->hw_mutex);
-
/*
* XXX avl_destroy, list_destroy, etc
*/
@@ -484,6 +455,10 @@ cpqary3_cleanup(cpqary3_t *cpq)
ddi_soft_state_free(cpqary3_state, ddi_get_instance(cpq->dip));
}
+/*
+ * Comparator for the "cpq_inflight" AVL tree in a "cpqary3_t". This AVL tree
+ * allows a tag ID to be mapped back to the relevant "cpqary_command_t".
+ */
static int
cpqary3_command_comparator(const void *lp, const void *rp)
{
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3.h b/usr/src/uts/common/io/cpqary3/cpqary3.h
index b5c194a343..b815380225 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3.h
+++ b/usr/src/uts/common/io/cpqary3/cpqary3.h
@@ -59,12 +59,11 @@ typedef enum cpqary3_init_level {
CPQARY3_INITLEVEL_I2O_MAPPED = (0x1 << 1),
CPQARY3_INITLEVEL_CFGTBL_MAPPED = (0x1 << 2),
CPQARY3_INITLEVEL_PERIODIC = (0x1 << 3),
- CPQARY3_INITLEVEL_INT_HW_HANDLER = (0x1 << 4),
- CPQARY3_INITLEVEL_INT_SW_HANDLER = (0x1 << 5),
- CPQARY3_INITLEVEL_MUTEX = (0x1 << 6),
- CPQARY3_INITLEVEL_MINOR_NODE = (0x1 << 7),
- CPQARY3_INITLEVEL_HBA_ALLOC = (0x1 << 8),
- CPQARY3_INITLEVEL_HBA_ATTACH = (0x1 << 9),
+ CPQARY3_INITLEVEL_INT_ALLOC = (0x1 << 4),
+ CPQARY3_INITLEVEL_INT_ADDED = (0x1 << 5),
+ CPQARY3_INITLEVEL_INT_ENABLED = (0x1 << 6),
+ CPQARY3_INITLEVEL_HBA_ALLOC = (0x1 << 7),
+ CPQARY3_INITLEVEL_HBA_ATTACH = (0x1 << 8),
} cpqary3_init_level_t;
/*
@@ -192,9 +191,60 @@ typedef enum cpqary3_ctlr_mode {
#include "cpqary3_scsi.h"
/*
- * Per Target Structure
+ * Logical Volume Structure
+ */
+typedef enum cpqary3_volume_flags {
+ CPQARY3_VOL_FLAG_WWN = (0x1 << 0),
+} cpqary3_volume_flags_t;
+typedef struct cpqary3_volume {
+ LogDevAddr_t cplv_addr;
+ cpqary3_volume_flags_t cplv_flags;
+
+ uint8_t cplv_wwn[16];
+
+ cpqary3_t *cplv_ctlr;
+ list_node_t cplv_link;
+
+ /*
+ * List of SCSA targets currently attached to this Logical Volume:
+ */
+ list_t cplv_targets;
+} cpqary3_volume_t;
+
+/*
+ * Per-Target Structure
*/
typedef struct cpqary3_target {
+ struct scsi_device *cptg_scsi_dev;
+
+ /*
+ * Linkage back to the Logical Volume that this target represents:
+ */
+ cpqary3_volume_t *cptg_volume;
+ list_node_t cptg_link_volume;
+} cpqary3_target_t;
+
+#if 0
+/*
+ * Per Target Structure
+ */
+typedef enum cpqary3_target_type {
+ CPQARY3_TARGET_TYPE_CONTROLLER = 1,
+ CPQARY3_TARGET_TYPE_VOLUME
+} cpqary3_target_type_t;
+typedef struct cpqary3_target cpqary3_target_t;
+struct cpqary3_target {
+ /*
+ * Controller-side logical unit number. The OS-side target number can
+ * be calculated by XXX
+ */
+ unsigned cpqt_logical_id;
+ cpqary3_target_type_t cpqt_type;
+ dev_info_t *cpqt_dip;
+};
+
+typedef struct cpqary3_target cpqary3_tgt_t;
+struct cpqary3_target {
uint32_t logical_id:30; /* at most 64 : 63 drives + 1 CTLR */
uint32_t type:2; /* CPQARY3_TARGET_* values */
PhysDevAddr_t PhysID;
@@ -212,7 +262,7 @@ typedef struct cpqary3_target {
uint32_t ctlr_flags;
dev_info_t *tgt_dip;
ddi_dma_attr_t dma_attrs;
-} cpqary3_tgt_t;
+};
/*
@@ -222,6 +272,7 @@ typedef struct cpqary3_target {
#define CPQARY3_TARGET_CTLR 1 /* Controller */
#define CPQARY3_TARGET_LOG_VOL 2 /* Logical Volume */
#define CPQARY3_TARGET_TAPE 3 /* SCSI Device - Tape */
+#endif
/*
@@ -245,15 +296,6 @@ typedef struct cpqary3_target {
#define INTR_SIMPLE_5I_MASK 0x00000004l
#define INTR_SIMPLE_5I_LOCKUP_MASK 0x0000000cl
-typedef struct cpqary3_replyq {
- unsigned cprq_cycle_indicator;
- size_t cprq_ntags;
- uint32_t *cprq_tags;
- size_t cprq_read_index;
- uint32_t cprq_tags_pa; /* XXX wrong type */
- cpqary3_phyctg_t cprq_phyctg;
-} cpqary3_replyq_t;
-
/*
* Per Controller Structure
*/
@@ -262,49 +304,73 @@ struct cpqary3 {
dev_info_t *dip;
int cpq_instance;
- cpqary3_init_level_t cpq_init_level;
-
- cpqary3_ctlr_mode_t cpq_ctlr_mode;
- unsigned cpq_ntargets;
+ /*
+ * Controller model-specific data.
+ */
uint32_t cpq_board_id;
cpqary3_bd_t *cpq_board;
+ /*
+ * Controller configuration discovered during initialisation.
+ */
uint32_t cpq_host_support;
uint32_t cpq_bus_support;
uint32_t cpq_maxcmds;
uint32_t cpq_sg_cnt;
/*
+ * The transport mode of the controller.
+ */
+ cpqary3_ctlr_mode_t cpq_ctlr_mode;
+
+ /*
+ * The current initialisation level of the driver. Bits in this field
+ * are set during initialisation and unset during cleanup of the
+ * allocated resources.
+ */
+ cpqary3_init_level_t cpq_init_level;
+
+ /*
+ * Essentially everything is protected by "cpq_mutex". When the
+ * completion queue is updated, threads sleeping on "cpq_cv_finishq"
+ * are awoken.
+ */
+ kmutex_t cpq_mutex;
+ kcondvar_t cpq_cv_finishq;
+
+ /*
+ * Controller target tracking. Note that "cpq_ntargets" refers to the
+ * current number of visible LUNs, as reported by the controller. The
+ * "cpq_targets" array is a sparse mapping from target ID number to
+ * the relevant target object.
+ */
+ cpqary3_tgt_t *cpq_targets[CPQARY3_MAX_TGT];
+ unsigned cpq_ntargets;
+
+ /*
* Controller Heartbeat Tracking
*/
uint32_t cpq_last_heartbeat;
clock_t cpq_last_heartbeat_lbolt;
+ /*
+ * Command object tracking. These lists, and all commands within the
+ * lists, are protected by "cpq_mutex".
+ */
uint32_t cpq_next_tag;
-
- boolean_t cpq_intr_off;
-
- cpqary3_replyq_t cpq_replyq;
avl_tree_t cpq_inflight;
list_t cpq_commands; /* List of all commands. */
+ list_t cpq_finishq; /* List of completed commands. */
- /* Condition Variables used */
- kcondvar_t cv_immediate_wait;
- kcondvar_t cv_flushcache_wait;
- kcondvar_t cv_abort_wait;
- kcondvar_t cv_ioctl_wait; /* Variable for ioctls */
-
- ddi_iblock_cookie_t cpq_int_hw_cookie;
- ddi_iblock_cookie_t cpq_int_sw_cookie;
+ /*
+ * Controller interrupt handler registration.
+ */
+ ddi_intr_handle_t cpq_interrupts[1];
+ int cpq_ninterrupts;
- kmutex_t hw_mutex;
- kmutex_t sw_mutex;
- ddi_softintr_t cpqary3_softintr_id;
- boolean_t cpq_swintr_flag;
ddi_periodic_t cpq_periodic;
- uint8_t cpqary3_tick_hdlr;
+
scsi_hba_tran_t *cpq_hba_tran;
- cpqary3_tgt_t *cpqary3_tgtp[CPQARY3_MAX_TGT];
/*
* Access to the I2O Registers:
@@ -326,11 +392,17 @@ typedef struct cpqary3_command cpqary3_command_t;
typedef struct cpqary3_command_internal cpqary3_command_internal_t;
typedef struct cpqary3_pkt cpqary3_pkt_t;
-typedef enum cpqary3_synccmd_status {
- CPQARY3_SYNCCMD_STATUS_NONE = 0,
- CPQARY3_SYNCCMD_STATUS_SUBMITTED,
- CPQARY3_SYNCCMD_STATUS_TIMEOUT
-} cpqary3_synccmd_status_t;
+typedef enum cpqary3_command_status {
+ CPQARY3_CMD_STATUS_USED = (0x1 << 0),
+ CPQARY3_CMD_STATUS_INFLIGHT = (0x1 << 1),
+ CPQARY3_CMD_STATUS_TIMEOUT = (0x1 << 2),
+ CPQARY3_CMD_STATUS_ERROR = (0x1 << 3),
+ CPQARY3_CMD_STATUS_ABANDONED = (0x1 << 4),
+ CPQARY3_CMD_STATUS_COMPLETE = (0x1 << 5),
+ CPQARY3_CMD_STATUS_POLLED = (0x1 << 6),
+ CPQARY3_CMD_STATUS_POLL_COMPLETE = (0x1 << 7),
+ CPQARY3_CMD_STATUS_ABORT_SENT = (0x1 << 8),
+} cpqary3_command_status_t;
typedef enum cpqary3_command_type {
CPQARY3_CMDTYPE_NONE = 0,
@@ -345,21 +417,17 @@ struct cpqary3_command {
cpqary3_t *cpcm_ctlr;
list_node_t cpcm_link; /* Linkage for allocated list. */
+ list_node_t cpcm_link_finish; /* Linkage for completion list. */
avl_node_t cpcm_node; /* Inflight AVL membership. */
- boolean_t cpcm_inflight;
- boolean_t cpcm_error;
- boolean_t cpcm_free_on_complete;
- boolean_t cpcm_used;
clock_t cpcm_time_submit;
+ clock_t cpcm_time_abort;
- cpqary3_synccmd_status_t cpcm_synccmd_status;
+ cpqary3_command_status_t cpcm_status;
cpqary3_pkt_t *cpcm_private;
cpqary3_command_internal_t *cpcm_internal;
- void (*cpcm_complete)(cpqary3_command_t *);
-
/*
* Physical allocation tracking:
*/
@@ -417,54 +485,29 @@ struct cpqary3_pkt {
cpqary3_command_t *cmd_command;
};
-#pragma pack(1)
-
-typedef struct cpqary3_ioctlresp {
- /* Driver Revision */
- struct cpqary3_revision {
- uint8_t minor; /* Version */
- uint8_t major;
- uint8_t mm; /* Revision Date */
- uint8_t dd;
- uint16_t yyyy;
- } cpqary3_drvrev;
-
- /* HBA Info */
- struct cpqary3_ctlr {
- uint8_t num_of_tgts; /* No of Logical Drive */
- uint8_t *name;
- } cpqary3_ctlr;
-} cpqary3_ioctlresp_t;
-
-typedef struct cpqary3_ioctlreq {
- cpqary3_ioctlresp_t *cpqary3_ioctlrespp;
-} cpqary3_ioctlreq_t;
-
-#pragma pack()
-
/* Driver function definitions */
void cpqary3_init_hbatran(cpqary3_t *);
void cpqary3_periodic(void *);
int cpqary3_flush_cache(cpqary3_t *);
uint16_t cpqary3_init_ctlr_resource(cpqary3_t *);
-int32_t cpqary3_ioctl_driver_info(uintptr_t, int);
-int32_t cpqary3_ioctl_ctlr_info(uintptr_t, cpqary3_t *, int);
-int32_t cpqary3_ioctl_bmic_pass(uintptr_t, cpqary3_t *, int);
-int32_t cpqary3_ioctl_scsi_pass(uintptr_t, cpqary3_t *, int);
uint8_t cpqary3_probe4targets(cpqary3_t *);
int cpqary3_submit(cpqary3_t *, cpqary3_command_t *);
-int cpqary3_retrieve(cpqary3_t *, uint32_t, boolean_t *);
-void cpqary3_retrieve_simple(cpqary3_t *, uint32_t, boolean_t *);
+void cpqary3_submit_simple(cpqary3_t *, cpqary3_command_t *);
+int cpqary3_retrieve(cpqary3_t *);
+void cpqary3_retrieve_simple(cpqary3_t *);
int cpqary3_target_geometry(struct scsi_address *);
int8_t cpqary3_detect_target_geometry(cpqary3_t *);
-uint8_t cpqary3_send_abortcmd(cpqary3_t *, uint16_t, CommandList_t *);
+uint8_t cpqary3_send_abortcmd(cpqary3_t *, cpqary3_tgt_t *, cpqary3_command_t *);
void cpqary3_memfini(cpqary3_t *, uint8_t);
int16_t cpqary3_meminit(cpqary3_t *);
-uint8_t cpqary3_build_cmdlist(cpqary3_command_t *cpqary3_cmdpvtp, uint32_t tid);
+void cpqary3_build_cmdlist(cpqary3_command_t *cpqary3_cmdpvtp,
+ cpqary3_tgt_t *);
void cpqary3_lockup_check(cpqary3_t *);
void cpqary3_oscmd_complete(cpqary3_command_t *);
+void cpqary3_poll_for(cpqary3_t *, cpqary3_command_t *);
+
/*
* Memory management.
*/
@@ -472,28 +515,23 @@ caddr_t cpqary3_alloc_phyctgs_mem(cpqary3_t *, size_t, uint32_t *,
cpqary3_phyctg_t *);
void cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *, uint8_t);
-#if 0
-void cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *, uint8_t);
-caddr_t cpqary3_alloc_phyctgs_mem(cpqary3_t *, size_t, uint32_t *,
- cpqary3_phyctg_t *);
-#endif
-
/*
* Synchronous command routines.
*/
cpqary3_command_t *cpqary3_synccmd_alloc(cpqary3_t *, size_t);
void cpqary3_synccmd_free(cpqary3_t *, cpqary3_command_t *);
int cpqary3_synccmd_send(cpqary3_t *, cpqary3_command_t *, clock_t, int);
-void cpqary3_synccmd_complete(cpqary3_command_t *);
/*
* Interrupt service routines.
*/
-uint32_t cpqary3_isr_hw_simple(caddr_t);
-uint32_t cpqary3_isr_sw_simple(caddr_t);
-void cpqary3_trigger_sw_isr(cpqary3_t *);
int cpqary3_interrupts_setup(cpqary3_t *);
void cpqary3_interrupts_teardown(cpqary3_t *);
+uint32_t cpqary3_isr_hw_simple(caddr_t, caddr_t);
+
+/*
+ * Interrupt enable/disable routines.
+ */
void cpqary3_intr_set(cpqary3_t *, boolean_t);
void cpqary3_lockup_intr_set(cpqary3_t *, boolean_t);
@@ -510,6 +548,19 @@ int cpqary3_cfgtbl_transport_confirm(cpqary3_t *, int);
uint32_t cpqary3_ctlr_get_cmdsoutmax(cpqary3_t *);
/*
+ * Device enumeration routines.
+ */
+int cpqary3_discover_logical_volumes(cpqary3_t *, int);
+cpqary3_volume_t *cpqary3_lookup_volume_by_id(cpqary3_t *, unsigned);
+cpqary3_volume_t *cpqary3_lookup_volume_by_addr(cpqary3_t *,
+ struct scsi_address *);
+
+cpqary3_tgt_t *cpqary3_target_from_id(cpqary3_t *, unsigned);
+cpqary3_tgt_t *cpqary3_target_from_addr(cpqary3_t *, struct scsi_address *);
+
+void cpqary3_process_finishq(cpqary3_t *);
+
+/*
* Command object management.
*/
cpqary3_command_t *cpqary3_command_alloc(cpqary3_t *, cpqary3_command_type_t);
@@ -521,10 +572,10 @@ void cpqary3_command_reuse(cpqary3_command_t *);
/*
* Device management routines.
*/
-uint32_t cpqary3_get32(cpqary3_t *, offset_t);
-void cpqary3_put32(cpqary3_t *, offset_t, uint32_t);
int cpqary3_device_setup(cpqary3_t *);
void cpqary3_device_teardown(cpqary3_t *);
+uint32_t cpqary3_get32(cpqary3_t *, offset_t);
+void cpqary3_put32(cpqary3_t *, offset_t, uint32_t);
#ifdef __cplusplus
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_ciss.c b/usr/src/uts/common/io/cpqary3/cpqary3_ciss.c
index b8fc52acb1..539558d296 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_ciss.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_ciss.c
@@ -15,15 +15,103 @@
#include "cpqary3.h"
+/*
+ * This routine is executed every 15 seconds via ddi_periodic_add(9F). It
+ * checks the health of the controller and looks for submitted commands that
+ * have timed out.
+ */
+void
+cpqary3_periodic(void *arg)
+{
+ cpqary3_t *cpq = arg;
+ clock_t now;
+ cpqary3_command_t *cpcm, *cpcm_next;
+
+ mutex_enter(&cpq->cpq_mutex);
+
+ /*
+ * Check on the health of the controller firmware. Note that if the
+ * controller has locked up, this routine will panic the system.
+ */
+ cpqary3_lockup_check(cpq);
+
+ /*
+ * Run the retrieval routine, in case the controller has become
+ * stuck or we have somehow missed an interrupt.
+ */
+ (void) cpqary3_retrieve(cpq);
+
+ /*
+ * Check inflight commands to see if they have timed out.
+ */
+ now = ddi_get_lbolt();
+ for (cpcm = avl_first(&cpq->cpq_inflight); cpcm != NULL;
+ cpcm = cpcm_next) {
+ cpqary3_pkt_t *privp;
+ struct scsi_pkt *pkt;
+ clock_t exp;
+
+ /*
+ * Save the next entry now, in case we need to remove this one
+ * from the AVL tree.
+ */
+ cpcm_next = AVL_NEXT(&cpq->cpq_inflight, cpcm);
+
+ /*
+ * We only need to process command timeout for commands
+ * issued on behalf of SCSA.
+ */
+ if (cpcm->cpcm_type != CPQARY3_CMDTYPE_OS ||
+ (privp = cpcm->cpcm_private) == NULL ||
+ (pkt = privp->scsi_cmd_pkt) == NULL) {
+ continue;
+ }
+
+ if (pkt->pkt_time == 0) {
+ /*
+ * This SCSI command has no timeout.
+ */
+ continue;
+ }
+
+ if (cpcm->cpcm_status & CPQARY3_CMD_STATUS_POLLED) {
+ /*
+ * Polled commands are timed out by the polling
+ * routine.
+ */
+ continue;
+ }
+
+ exp = CPQARY3_SEC2HZ(pkt->pkt_time) + cpcm->cpcm_time_submit;
+ if (exp < now) {
+ /*
+ * This command has timed out. Set the appropriate
+ * status bit and push it onto the completion
+ * queue.
+ */
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_TIMEOUT;
+ cpcm->cpcm_status &= ~CPQARY3_CMD_STATUS_INFLIGHT;
+ avl_remove(&cpq->cpq_inflight, cpcm);
+ list_insert_tail(&cpq->cpq_finishq, cpcm);
+ }
+ }
+
+ /*
+ * Process the completion queue.
+ */
+ (void) cpqary3_process_finishq(cpq);
+
+ mutex_exit(&cpq->cpq_mutex);
+}
+
int
-cpqary3_retrieve(cpqary3_t *cpq, uint32_t want_tag, boolean_t *found)
+cpqary3_retrieve(cpqary3_t *cpq)
{
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
- VERIFY(MUTEX_HELD(&cpq->sw_mutex));
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
switch (cpq->cpq_ctlr_mode) {
case CPQARY3_CTLR_MODE_SIMPLE:
- cpqary3_retrieve_simple(cpq, want_tag, found);
+ cpqary3_retrieve_simple(cpq);
return (DDI_SUCCESS);
case CPQARY3_CTLR_MODE_UNKNOWN:
@@ -33,25 +121,28 @@ cpqary3_retrieve(cpqary3_t *cpq, uint32_t want_tag, boolean_t *found)
panic("unknown controller mode");
}
+/*
+ * Submit a command to the controller.
+ */
int
cpqary3_submit(cpqary3_t *cpq, cpqary3_command_t *cpcm)
{
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
/*
- * If a controller lockup has been detected, reject new command
- * submissions.
+ * Do not allow submission of more concurrent commands than the
+ * controller supports.
*/
- if (cpq->controller_lockup) {
- return (EIO);
+ if (avl_numnodes(&cpq->cpq_inflight) >= cpq->cpq_maxcmds) {
+ return (EAGAIN);
}
/*
* Ensure that this command is not re-used without issuing a new
* tag number and performing any appropriate cleanup.
*/
- VERIFY(!cpcm->cpcm_used);
- cpcm->cpcm_used = B_TRUE;
+ VERIFY(!(cpcm->cpcm_status & ~CPQARY3_CMD_STATUS_USED));
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_USED;
/*
* Insert this command into the inflight AVL.
@@ -63,13 +154,14 @@ cpqary3_submit(cpqary3_t *cpq, cpqary3_command_t *cpcm)
}
avl_insert(&cpq->cpq_inflight, cpcm, where);
- VERIFY(cpcm->cpcm_inflight == B_FALSE);
- cpcm->cpcm_inflight = B_TRUE;
+ VERIFY(!(cpcm->cpcm_status & CPQARY3_CMD_STATUS_INFLIGHT));
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_INFLIGHT;
+
cpcm->cpcm_time_submit = ddi_get_lbolt();
switch (cpq->cpq_ctlr_mode) {
case CPQARY3_CTLR_MODE_SIMPLE:
- cpqary3_put32(cpq, CISS_I2O_INBOUND_POST_Q, cpcm->cpcm_pa_cmd);
+ cpqary3_submit_simple(cpq, cpcm);
break;
default:
@@ -79,6 +171,96 @@ cpqary3_submit(cpqary3_t *cpq, cpqary3_command_t *cpcm)
return (0);
}
+static void
+cpqary3_process_finishq_one(cpqary3_command_t *cpcm)
+{
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_COMPLETE;
+
+ switch (cpcm->cpcm_type) {
+ case CPQARY3_CMDTYPE_SYNCCMD:
+ cv_broadcast(&cpcm->cpcm_ctlr->cpq_cv_finishq);
+ return;
+
+ case CPQARY3_CMDTYPE_OS:
+ cpqary3_oscmd_complete(cpcm);
+ return;
+
+ default:
+ break;
+ }
+
+ panic("unknown command type");
+}
+
+void
+cpqary3_process_finishq(cpqary3_t *cpq)
+{
+ cpqary3_command_t *cpcm;
+
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
+
+ while ((cpcm = list_remove_head(&cpq->cpq_finishq)) != NULL) {
+ /*
+ * Check if this command has been abandoned by the original
+ * submitter. If it has, free it now to avoid a leak.
+ */
+ if (cpcm->cpcm_status & CPQARY3_CMD_STATUS_ABANDONED) {
+ mutex_exit(&cpq->cpq_mutex);
+ cpqary3_command_free(cpcm);
+ mutex_enter(&cpq->cpq_mutex);
+ continue;
+ }
+
+ if (cpcm->cpcm_status & CPQARY3_CMD_STATUS_POLLED) {
+ /*
+ * This command will be picked up and processed
+ * by "cpqary3_poll_for()" once the CV is triggered
+ * at the end of processing.
+ */
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_POLL_COMPLETE;
+ continue;
+ }
+
+ cpqary3_process_finishq_one(cpcm);
+ }
+
+ cv_broadcast(&cpq->cpq_cv_finishq);
+}
+
+void
+cpqary3_poll_for(cpqary3_t *cpq, cpqary3_command_t *cpcm)
+{
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
+ VERIFY(cpcm->cpcm_status & CPQARY3_CMD_STATUS_POLLED);
+
+ while (!(cpcm->cpcm_status & CPQARY3_CMD_STATUS_POLL_COMPLETE)) {
+ cv_wait(&cpq->cpq_cv_finishq, &cpq->cpq_mutex);
+ }
+
+#if 0
+ /*
+ * Ensure this command is no longer in the inflight AVL.
+ */
+ if (cpcm->cpcm_status & CPQARY3_CMD_STATUS_INFLIGHT) {
+ cpcm->cpcp_status &= ~CPQARY3_CMD_STATUS_INFLIGHT;
+ avl_remove(&cpq->cpq_inflight, cpcm);
+
+ /*
+ * Mark it timed out.
+ */
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_TIMEOUT |
+ CPQARY3_CMD_STATUS_COMPLETE;
+ }
+#endif
+
+ /*
+ * Fire the completion callback for this command. The callback
+ * is responsible for freeing the command, so it may not be
+ * referenced again once this call returns.
+ */
+ cpqary3_process_finishq_one(cpcm);
+}
+
void
cpqary3_intr_set(cpqary3_t *cpq, boolean_t enabled)
{
@@ -129,23 +311,6 @@ cpqary3_lockup_intr_set(cpqary3_t *cpq, boolean_t enabled)
cpqary3_put32(cpq, CISS_I2O_INTERRUPT_MASK, imr);
}
-void
-cpqary3_trigger_sw_isr(cpqary3_t *cpq)
-{
- boolean_t trigger = B_FALSE;
-
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
-
- if (!cpq->cpq_swintr_flag) {
- trigger = B_TRUE;
- cpq->cpq_swintr_flag = B_TRUE;
- }
-
- if (trigger) {
- ddi_trigger_softintr(cpq->cpqary3_softintr_id);
- }
-}
-
/*
* Signal to the controller that we have updated the Configuration Table by
* writing to the Inbound Doorbell Register. The controller will, after some
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_ciss.h b/usr/src/uts/common/io/cpqary3/cpqary3_ciss.h
index 0202380aa5..26e68d7de6 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_ciss.h
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_ciss.h
@@ -148,6 +148,16 @@ extern "C" {
#define CISS_CFGTBL_XPORT_MEMQ (1UL << 4)
/*
+ * In the Simple Transport Method, the Outbound Post Queue register is
+ * repeatedly read for notifications of the completion of commands previously
+ * submitted to the controller. These macros help break up the read value into
+ * its component fields: the tag number, and whether or not the command
+ * completed in error.
+ */
+#define CISS_OPQ_READ_TAG(x) ((x) >> 2)
+#define CISS_OPQ_READ_ERROR(x) ((x) & (1UL << 0))
+
+/*
* STRUCTURES
* Command List Structure
*/
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c b/usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c
index 07c09818c8..d16b2530cb 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c
@@ -15,31 +15,17 @@
#include "cpqary3.h"
-boolean_t
-cpqary3_check_simple_ctlr_intr(cpqary3_t *cpq)
+uint_t
+cpqary3_isr_hw_simple(caddr_t arg1, caddr_t arg2)
{
- uint32_t intr_pending_mask = cpq->cpq_board->bd_intrpendmask;
+ cpqary3_t *cpq = (cpqary3_t *)arg1;
uint32_t isr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS);
+ mutex_enter(&cpq->cpq_mutex);
+
/*
- * Read the Interrupt Status Register and
- * if bit 3 is set, it indicates that we have completed commands
- * in the controller
+ * Check to see if this interrupt came from the device:
*/
- if ((isr & intr_pending_mask) != 0) {
- return (CPQARY3_SUCCESS);
- }
-
- return (CPQARY3_FAILURE);
-}
-
-uint_t
-cpqary3_isr_hw_simple(caddr_t arg)
-{
- cpqary3_t *cpq = (cpqary3_t *)arg;
- uint32_t isr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS);
-
- mutex_enter(&cpq->hw_mutex);
if ((isr & cpq->cpq_board->bd_intrpendmask) == 0) {
/*
* Check to see if the firmware has come to rest. If it has,
@@ -47,71 +33,40 @@ cpqary3_isr_hw_simple(caddr_t arg)
*/
cpqary3_lockup_check(cpq);
- mutex_exit(&cpq->hw_mutex);
+ mutex_exit(&cpq->cpq_mutex);
return (DDI_INTR_UNCLAIMED);
}
/*
- * Disable interrupts until the soft interrupt handler has had a chance
- * to read and process replies.
+ * The interrupt was from our controller, so collect any pending
+ * command completions.
*/
- cpqary3_intr_set(cpq, B_FALSE);
-
- cpqary3_trigger_sw_isr(cpq);
-
- mutex_exit(&cpq->hw_mutex);
- return (DDI_INTR_CLAIMED);
-}
-
-uint_t
-cpqary3_isr_sw_simple(caddr_t arg)
-{
- cpqary3_t *cpq = (cpqary3_t *)arg;
+ cpqary3_retrieve_simple(cpq);
/*
- * Confirm that the hardware interrupt routine scheduled this
- * software interrupt.
+ * Process any commands in the completion queue.
*/
- mutex_enter(&cpq->sw_mutex);
- mutex_enter(&cpq->hw_mutex);
- if (!cpq->cpq_swintr_flag) {
- mutex_exit(&cpq->hw_mutex);
- mutex_exit(&cpq->sw_mutex);
- return (DDI_INTR_UNCLAIMED);
- }
-
- cpqary3_retrieve_simple(cpq, 0, NULL);
+ cpqary3_process_finishq(cpq);
- /*
- * Unmask the controller inbound data interrupt.
- */
- if (!cpq->cpq_intr_off) {
- cpqary3_intr_set(cpq, B_TRUE);
- }
-
- cpq->cpq_swintr_flag = B_FALSE;
- mutex_exit(&cpq->hw_mutex);
- mutex_exit(&cpq->sw_mutex);
+ mutex_exit(&cpq->cpq_mutex);
return (DDI_INTR_CLAIMED);
}
-
/*
* Read tags and process completion of the associated command until the supply
* of tags is exhausted.
*/
void
-cpqary3_retrieve_simple(cpqary3_t *cpq, uint32_t watchfor, boolean_t *found)
+cpqary3_retrieve_simple(cpqary3_t *cpq)
{
uint32_t opq;
uint32_t none = 0xffffffff;
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
- VERIFY(MUTEX_HELD(&cpq->sw_mutex));
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
while ((opq = cpqary3_get32(cpq, CISS_I2O_OUTBOUND_POST_Q)) != none) {
+ uint32_t tag = CISS_OPQ_READ_TAG(opq);
cpqary3_command_t *cpcm;
- uint32_t tag = opq >> 2; /* XXX */
if ((cpcm = cpqary3_lookup_inflight(cpq, tag)) == NULL) {
dev_err(cpq->dip, CE_WARN, "spurious tag %x", tag);
@@ -119,19 +74,28 @@ cpqary3_retrieve_simple(cpqary3_t *cpq, uint32_t watchfor, boolean_t *found)
}
avl_remove(&cpq->cpq_inflight, cpcm);
- cpcm->cpcm_inflight = B_FALSE;
- cpcm->cpcm_error = (opq & (0x1 << 1)) != 0;
-
- if (found != NULL && cpcm->cpcm_tag == watchfor) {
- *found = B_TRUE;
+ cpcm->cpcm_status &= ~CPQARY3_CMD_STATUS_INFLIGHT;
+ if (CISS_OPQ_READ_ERROR(opq) != 0) {
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_ERROR;
}
- mutex_exit(&cpq->hw_mutex);
- cpcm->cpcm_complete(cpcm);
- mutex_enter(&cpq->hw_mutex);
+ /*
+ * Push this command onto the completion queue.
+ */
+ list_insert_tail(&cpq->cpq_finishq, cpcm);
}
}
+/*
+ * Submit a command to the controller by posting it to the Inbound Post Queue
+ * Register.
+ */
+void
+cpqary3_submit_simple(cpqary3_t *cpq, cpqary3_command_t *cpcm)
+{
+ cpqary3_put32(cpq, CISS_I2O_INBOUND_POST_Q, cpcm->cpcm_pa_cmd);
+}
+
int
cpqary3_ctlr_init_simple(cpqary3_t *cpq)
{
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_commands.c b/usr/src/uts/common/io/cpqary3/cpqary3_commands.c
index 8c600383bc..a8f5390f9e 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_commands.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_commands.c
@@ -23,6 +23,20 @@ cpqary3_round_up(size_t offset)
return ((offset + (gran - 1)) & ~(gran - 1));
}
+static void
+cpqary3_set_new_tag(cpqary3_t *cpq, cpqary3_command_t *cpcm)
+{
+ /*
+ * Grab a new tag number for this command. We aim to avoid reusing tag
+ * numbers as much as possible, so as to avoid spurious double
+ * completion from the controller.
+ */
+ cpcm->cpcm_tag = cpq->cpq_next_tag;
+ if (++cpq->cpq_next_tag > CPQARY3_MAX_TAG_NUMBER) {
+ cpq->cpq_next_tag = CPQARY3_MIN_TAG_NUMBER;
+ }
+}
+
cpqary3_command_t *
cpqary3_command_alloc(cpqary3_t *cpq, cpqary3_command_type_t type)
{
@@ -36,29 +50,16 @@ cpqary3_command_alloc(cpqary3_t *cpq, cpqary3_command_type_t type)
switch (type) {
case CPQARY3_CMDTYPE_OS:
- cpcm->cpcm_complete = cpqary3_oscmd_complete;
- break;
-
case CPQARY3_CMDTYPE_SYNCCMD:
- cpcm->cpcm_complete = cpqary3_synccmd_complete;
break;
-
default:
panic("unexpected type");
}
cpcm->cpcm_type = type;
- /*
- * Grab a new tag number for this command. We aim to avoid reusing tag
- * numbers as much as possible, so as to avoid spurious double
- * completion from the controller.
- */
- mutex_enter(&cpq->sw_mutex);
- cpcm->cpcm_tag = cpq->cpq_next_tag;
- if (++cpq->cpq_next_tag > 0xfffff) {
- cpq->cpq_next_tag = 0x54321;
- }
- mutex_exit(&cpq->sw_mutex);
+ mutex_enter(&cpq->cpq_mutex);
+ cpqary3_set_new_tag(cpq, cpcm);
+ mutex_exit(&cpq->cpq_mutex);
size_t contig_size = 0;
size_t errorinfo_offset;
@@ -108,9 +109,9 @@ cpqary3_command_alloc(cpqary3_t *cpq, cpqary3_command_type_t type)
/*
* Insert into the per-controller command list.
*/
- mutex_enter(&cpq->sw_mutex);
+ mutex_enter(&cpq->cpq_mutex);
list_insert_tail(&cpq->cpq_commands, cpcm);
- mutex_exit(&cpq->sw_mutex);
+ mutex_exit(&cpq->cpq_mutex);
return (cpcm);
}
@@ -140,38 +141,30 @@ cpqary3_command_reuse(cpqary3_command_t *cpcm)
{
cpqary3_t *cpq = cpcm->cpcm_ctlr;
- mutex_enter(&cpq->sw_mutex);
+ mutex_enter(&cpq->cpq_mutex);
/*
* Make sure the command is not currently inflight.
*/
- VERIFY(!cpcm->cpcm_inflight);
- if (!cpcm->cpcm_used) {
+ VERIFY(!(cpcm->cpcm_status & CPQARY3_CMD_STATUS_INFLIGHT));
+ if (!(cpcm->cpcm_status & CPQARY3_CMD_STATUS_USED)) {
/*
* If the command has not yet been issued to the controller,
* this is a no-op.
*/
- mutex_exit(&cpq->sw_mutex);
+ mutex_exit(&cpq->cpq_mutex);
return;
}
- cpcm->cpcm_used = B_FALSE;
+ cpcm->cpcm_status &= ~CPQARY3_CMD_STATUS_USED;
- /*
- * Grab a new tag number for this command. We aim to avoid reusing tag
- * numbers as much as possible, so as to avoid spurious double
- * completion from the controller.
- */
- cpcm->cpcm_tag = cpq->cpq_next_tag;
- if (++cpq->cpq_next_tag > 0xfffff) {
- cpq->cpq_next_tag = 0x54321;
- }
+ cpqary3_set_new_tag(cpq, cpcm);
/*
* Populate fields.
*/
cpcm->cpcm_va_cmd->Header.Tag.tag_value = cpcm->cpcm_tag;
- mutex_exit(&cpq->sw_mutex);
+ mutex_exit(&cpq->cpq_mutex);
}
void
@@ -183,7 +176,7 @@ cpqary3_command_free(cpqary3_command_t *cpcm)
* Ensure the object we are about to free is not currently in the
* inflight AVL.
*/
- VERIFY(!cpcm->cpcm_inflight);
+ VERIFY(!(cpcm->cpcm_status & CPQARY3_CMD_STATUS_INFLIGHT));
if (cpcm->cpcm_internal != NULL) {
cpqary3_command_internal_t *cpcmi = cpcm->cpcm_internal;
@@ -195,9 +188,9 @@ cpqary3_command_free(cpqary3_command_t *cpcm)
cpqary3_free_phyctgs_mem(&cpcm->cpcm_phyctg, CPQARY3_FREE_PHYCTG_MEM);
- mutex_enter(&cpq->sw_mutex);
+ mutex_enter(&cpq->cpq_mutex);
list_remove(&cpq->cpq_commands, cpcm);
- mutex_exit(&cpq->sw_mutex);
+ mutex_exit(&cpq->cpq_mutex);
kmem_free(cpcm, sizeof (*cpcm));
}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_hba.c b/usr/src/uts/common/io/cpqary3/cpqary3_hba.c
new file mode 100644
index 0000000000..ad3e5b6054
--- /dev/null
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_hba.c
@@ -0,0 +1,115 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include "cpqary3.h"
+
+static int
+cpqary3_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+ scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+ cpqary3_t *cpq = (cpqary3_t *)hba_tran->tran_hba_private;
+ cpqary3_volume_t *cplv;
+ cpqary3_target_t *cptg;
+
+ /*
+ * XXX Check to see if new logical volumes are available.
+ */
+ if (cpqary3_discover_logical_volumes(cpq, 15) != 0) {
+ dev_err(cpq->dip, CE_WARN, "discover logical volumes failure");
+ return (DDI_FAILURE);
+ }
+
+ if ((cptg = kmem_zalloc(sizeof (*cptg), KM_NOSLEEP)) == NULL) {
+ dev_err(cpq->dip, CE_WARN, "could not allocate target object "
+ "due to memory exhaustion");
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Look for a logical volume for the SCSI address of this target.
+ */
+ mutex_enter(&cpq->cpq_mutex);
+ if ((cplv = cpqary3_lookup_volume_by_addr(cpq, sd)) == NULL) {
+ mutex_exit(&cpq_mutex);
+ kmem_free(cptg, sizeof (*cptg));
+ return (DDI_FAILURE);
+ }
+
+ cptg->cptg_scsi_dev = sd;
+ VERIFY(sd->sd_dev == tgt_dip); /* XXX */
+
+ cptg->cptg_volume = cplv;
+ list_insert_tail(&cplv->cplv_targets, cptg);
+
+ /*
+ * We passed SCSI_HBA_TRAN_CLONE to scsi_hba_attach(9F), so
+ * we can stash our target-specific data structure on the
+ * (cloned) "hba_tran" without affecting the HBA-level
+ * private data pointer.
+ */
+ hba_tran->tran_tgt_private = cptg;
+
+ mutex_exit(&cpq_mutex);
+ return (DDI_SUCCESS);
+}
+
+static void
+cpqary3_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+ scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+ cpqary3_target_t *cptg = (cpqary3_target_t *)hba_tran->tran_tgt_private;
+ cpqary3_volume_t *cplv = cptg->cptg_volume;
+
+ /*
+ * XXX Make sure that there are no outstanding commands for this
+ * target.
+ */
+
+ mutex_enter(&cpq->cpq_mutex);
+ list_insert_remove(&cplv->cplv_targets, cptg);
+ mutex_exit(&cpq_mutex);
+
+ kmem_free(cptg, sizeof (*cptg));
+}
+
+void
+cpqary3_hba_setup(cpqary3_t *cpq)
+{
+ scsi_hba_tran_t *tran = cpq->cpq_hba_tran;
+
+ tran->tran_hba_private = cpq;
+
+ tran->tran_tgt_init = cpqary3_tran_tgt_init;
+ tran->tran_tgt_probe = scsi_hba_probe;
+ tran->tran_tgt_free = cpqary3_tran_tgt_free;
+
+ tran->tran_start = XXX;
+ tran->tran_reset = XXX;
+ tran->tran_abort = XXX;
+
+ tran->tran_getcap = XXX;
+ tran->tran_setcap = XXX;
+
+ tran->tran_init_pkt = XXX;
+ tran->tran_destroy_pkt = XXX;
+ tran->tran_dmafree = XXX;
+ tran->tran_sync_pkt = XXX;
+
+ /*
+ * XXX We should set "tran_interconnect_type" appropriately.
+ * e.g. to INTERCONNECT_SAS for SAS controllers. How to tell?
+ * Who knows.
+ */
+}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_interrupts.c b/usr/src/uts/common/io/cpqary3/cpqary3_interrupts.c
index 031ff7284c..3ce89b1431 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_interrupts.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_interrupts.c
@@ -18,26 +18,10 @@
int
cpqary3_interrupts_setup(cpqary3_t *cpq)
{
- uint_t (*hw_isr)(caddr_t);
- uint_t (*sw_isr)(caddr_t);
-
- if (ddi_get_soft_iblock_cookie(cpq->dip, DDI_SOFTINT_HIGH,
- &cpq->cpq_int_sw_cookie) != DDI_SUCCESS) {
- dev_err(cpq->dip, CE_WARN, "ddi_get_soft_iblock_cookie failed");
- goto fail;
- }
-
- if (ddi_get_iblock_cookie(cpq->dip, 0, &cpq->cpq_int_hw_cookie) !=
- DDI_SUCCESS) {
- dev_err(cpq->dip, CE_WARN, "ddi_get_iblock_cookie (hw) failed");
- goto fail;
- }
-
- mutex_init(&cpq->sw_mutex, NULL, MUTEX_DRIVER,
- (void *)cpq->cpq_int_sw_cookie);
- mutex_init(&cpq->hw_mutex, NULL, MUTEX_DRIVER,
- (void *)cpq->cpq_int_hw_cookie);
- cpq->cpq_init_level |= CPQARY3_INITLEVEL_MUTEX;
+ int types;
+ int nintrs = 0, navail = 0;
+ unsigned ipri;
+ uint_t (*hw_isr)(caddr_t, caddr_t);
/*
* Select the correct hardware interrupt service routine for the
@@ -46,26 +30,75 @@ cpqary3_interrupts_setup(cpqary3_t *cpq)
switch (cpq->cpq_ctlr_mode) {
case CPQARY3_CTLR_MODE_SIMPLE:
hw_isr = cpqary3_isr_hw_simple;
- sw_isr = cpqary3_isr_sw_simple;
break;
default:
panic("unknown controller mode");
}
- if (ddi_add_softintr(cpq->dip, DDI_SOFTINT_HIGH,
- &cpq->cpqary3_softintr_id, &cpq->cpq_int_sw_cookie, NULL, sw_isr,
- (caddr_t)cpq) != DDI_SUCCESS) {
- dev_err(cpq->dip, CE_WARN, "ddi_add_softintr failed");
+ /*
+ * Ensure that at least one fixed interrupt is available to us.
+ */
+ if (ddi_intr_get_supported_types(cpq->dip, &types) != DDI_SUCCESS) {
+ dev_err(cpq->dip, CE_WARN, "could not get support interrupts");
+ goto fail;
+ }
+ if (!(types & DDI_INTR_TYPE_FIXED)) {
+ dev_err(cpq->dip, CE_WARN, "DDI_INTR_TYPE_FIXED not supported");
+ goto fail;
+ }
+ if (ddi_intr_get_nintrs(cpq->dip, DDI_INTR_TYPE_FIXED, &nintrs) !=
+ DDI_SUCCESS) {
+ dev_err(cpq->dip, CE_WARN, "could not count fixed interrupts");
+ goto fail;
+ }
+ if (ddi_intr_get_navail(cpq->dip, DDI_INTR_TYPE_FIXED, &navail) !=
+ DDI_SUCCESS || navail < 1) {
+ dev_err(cpq->dip, CE_WARN, "no fixed interrupts available");
+ goto fail;
+ }
+
+ /*
+ * Set the flag first, as we are still expected to call ddi_intr_free()
+ * for a partial, but failed, allocation of interrupts.
+ */
+ cpq->cpq_init_level |= CPQARY3_INITLEVEL_INT_ALLOC;
+ if (ddi_intr_alloc(cpq->dip, cpq->cpq_interrupts,
+ DDI_INTR_TYPE_FIXED, 0, 1, &cpq->cpq_ninterrupts,
+ DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) {
+ dev_err(cpq->dip, CE_WARN, "interrupt allocation failed");
goto fail;
}
- cpq->cpq_init_level |= CPQARY3_INITLEVEL_INT_SW_HANDLER;
- if (ddi_add_intr(cpq->dip, 0, &cpq->cpq_int_hw_cookie, NULL, hw_isr,
- (caddr_t)cpq) != DDI_SUCCESS) {
- dev_err(cpq->dip, CE_WARN, "ddi_add_intr (hw) failed");
+ /*
+ * Ensure that we have not been given a high-level interrupt, as our
+ * interrupt handlers do not support them.
+ */
+ if (ddi_intr_get_pri(cpq->cpq_interrupts[0], &ipri) != DDI_SUCCESS) {
+ dev_err(cpq->dip, CE_WARN, "could not determine interrupt "
+ "priority");
+ goto fail;
+ }
+ if (ipri >= ddi_intr_get_hilevel_pri()) {
+ dev_err(cpq->dip, CE_WARN, "high level interrupts not "
+ "supported");
+ goto fail;
+ }
+
+ if (ddi_intr_add_handler(cpq->cpq_interrupts[0], hw_isr,
+ (caddr_t)cpq, NULL) != DDI_SUCCESS) {
+ dev_err(cpq->dip, CE_WARN, "adding interrupt failed");
+ goto fail;
+ }
+ cpq->cpq_init_level |= CPQARY3_INITLEVEL_INT_ADDED;
+
+ /*
+ * Enable the interrupt handler.
+ */
+ if (ddi_intr_enable(cpq->cpq_interrupts[0]) != DDI_SUCCESS) {
+ dev_err(cpq->dip, CE_WARN, "enable interrupt failed");
goto fail;
}
- cpq->cpq_init_level |= CPQARY3_INITLEVEL_INT_HW_HANDLER;
+ cpq->cpq_init_level |= CPQARY3_INITLEVEL_INT_ENABLED;
return (DDI_SUCCESS);
@@ -77,22 +110,23 @@ fail:
void
cpqary3_interrupts_teardown(cpqary3_t *cpq)
{
- if (cpq->cpq_init_level & CPQARY3_INITLEVEL_INT_HW_HANDLER) {
- ddi_remove_intr(cpq->dip, 0, cpq->cpq_int_hw_cookie);
+ if (cpq->cpq_init_level & CPQARY3_INITLEVEL_INT_ENABLED) {
+ (void) ddi_intr_disable(cpq->cpq_interrupts[0]);
- cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_INT_HW_HANDLER;
+ cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_INT_ENABLED;
}
- if (cpq->cpq_init_level & CPQARY3_INITLEVEL_INT_SW_HANDLER) {
- ddi_remove_softintr(cpq->cpqary3_softintr_id);
+ if (cpq->cpq_init_level & CPQARY3_INITLEVEL_INT_ADDED) {
+ (void) ddi_intr_remove_handler(cpq->cpq_interrupts[0]);
- cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_INT_SW_HANDLER;
+ cpq->cpq_init_level &= CPQARY3_INITLEVEL_INT_ADDED;
}
- if (cpq->cpq_init_level & CPQARY3_INITLEVEL_MUTEX) {
- mutex_destroy(&cpq->sw_mutex);
- mutex_destroy(&cpq->hw_mutex);
+ if (cpq->cpq_init_level & CPQARY3_INITLEVEL_INT_ALLOC) {
+ for (int i = 0; i < cpq->cpq_ninterrupts; i++) {
+ (void) ddi_intr_free(cpq->cpq_interrupts[i]);
+ }
- cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_MUTEX;
+ cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_INT_ALLOC;
}
}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_logvol.c b/usr/src/uts/common/io/cpqary3/cpqary3_logvol.c
new file mode 100644
index 0000000000..54418df81e
--- /dev/null
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_logvol.c
@@ -0,0 +1,259 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#include "cpqary3.h"
+
+cpqary3_volume_t *
+cpqary3_lookup_volume_by_id(cpqary3_t *cpq, unsigned id)
+{
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
+
+ for (cpqary3_volume_t *cplv = list_head(&cpq->cpq_volumes);
+ cplv != NULL; cplv = list_next(&cpq->cpq_volumes, cplv)) {
+ if (cplv->cplv_addr.VolId == id) {
+ return (cplv);
+ }
+ }
+
+ return (NULL);
+}
+
+cpqary3_volume_t *
+cpqary3_lookup_volume_by_addr(cpqary3_t *cpq, struct scsi_address *sa)
+{
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
+
+ if (sa->sa_lun != 0) {
+ return (NULL);
+ }
+
+ return (cpqary3_lookup_volume_by_id(cpq, sa->sa_target));
+}
+
+static void
+cpqary3_write_lun_addr_phys(LUNAddr_t *lun, boolean_t masked, unsigned bus,
+ unsigned target)
+{
+ lun->PhysDev.Mode = masked ? MASK_PERIPHERIAL_DEV_ADDR :
+ PERIPHERIAL_DEV_ADDR;
+
+ lun->PhysDev.TargetId = target;
+ lun->PhysDev.Bus = bus;
+
+ bzero(&lun->PhysDev.Target, sizeof (lun->PhysDev.Target));
+}
+
+static int
+cpqary3_read_logvols(cpqary3_t *cpq, cpqary3_report_logical_lun_t *cprll)
+{
+ cpqary3_report_logical_lun_extent_t *ents =
+ cprll->cprll_data.ents;
+ uint32_t count = ntohl(cprll->cprll_datasize) /
+ sizeof (cpqary3_report_logical_lun_ent_t);
+
+ if (count > MAX_LOGDRV) {
+ count = MAX_LOGDRV;
+ }
+
+ for (unsigned i = 0; i < count; i++) {
+ cpqary3_volume_t *cplv;
+
+ if ((cplv = cpqary3_lookup_volume_by_id(cpq,
+ ents[i]->cprle_addr.VolId)) != NULL) {
+ continue;
+ }
+
+ dev_err(cpq->dip, CE_WARN, "NEW LOGVOL[%u]: mode %x "
+ "volid %x attr %x", i,
+ ents[i]->cprle_addr.Mode,
+ ents[i]->cprle_addr.VolId,
+ *((uint32_t *)ents[i]->cprle_addr.reserved));
+
+ /*
+ * This is a new Logical Volume, so add it the the list.
+ */
+ if ((cplv = kmem_zalloc(sizeof (*cplv), KM_NOSLEEP)) ==
+ NULL) {
+ return (ENOMEM);
+
+ cplv->cplv_addr = ents[i]->cprle_addr;
+
+ list_create(&cplv->cplv_targets,
+ sizeof (cpqary3_target_t),
+ offsetof(cpqary3_target_t, cptg_link_volume));
+
+ cplv->cplv_ctrl = cpq;
+ list_insert_tail(&cpq->cpq_volumes, cplv);
+ }
+ }
+
+ return (0);
+}
+
+static int
+cpqary3_read_logvols_ext(cpqary3_t *cpq, cpqary3_report_logical_lun_t *cprll)
+{
+ cpqary3_report_logical_lun_extent_t *extents =
+ cprll->cprll_data.extents;
+ uint32_t count = ntohl(cprll->cprll_datasize) /
+ sizeof (cpqary3_report_logical_lun_extent_t);
+
+ if (count > MAX_LOGDRV) {
+ count = MAX_LOGDRV;
+ }
+
+ for (unsigned i = 0; i < count; i++) {
+ cpqary3_volume_t *cplv;
+
+ if ((cplv = cpqary3_lookup_volume_by_id(cpq,
+ ents[i]->cprle_addr.VolId)) != NULL) {
+ /*
+ * XXX compare previous WWN with current WWN...
+ */
+ continue;
+ }
+
+ dev_err(cpq->dip, CE_WARN, "NEW EXT LOGVOL[%u]: mode %x "
+ "volid %x attr %x", i,
+ extents[i]->cprle_addr.Mode,
+ extents[i]->cprle_addr.VolId,
+ *((uint32_t *)extents[i]->cprle_addr.reserved));
+ dev_err(cpq->dip, CE_WARN, "-- id %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x",
+ (uint32_t)extents[i]->cprle_wwn[0],
+ (uint32_t)extents[i]->cprle_wwn[1],
+ (uint32_t)extents[i]->cprle_wwn[2],
+ (uint32_t)extents[i]->cprle_wwn[3],
+ (uint32_t)extents[i]->cprle_wwn[4],
+ (uint32_t)extents[i]->cprle_wwn[5],
+ (uint32_t)extents[i]->cprle_wwn[6],
+ (uint32_t)extents[i]->cprle_wwn[7],
+ (uint32_t)extents[i]->cprle_wwn[8],
+ (uint32_t)extents[i]->cprle_wwn[9],
+ (uint32_t)extents[i]->cprle_wwn[10],
+ (uint32_t)extents[i]->cprle_wwn[11],
+ (uint32_t)extents[i]->cprle_wwn[12],
+ (uint32_t)extents[i]->cprle_wwn[13],
+ (uint32_t)extents[i]->cprle_wwn[14],
+ (uint32_t)extents[i]->cprle_wwn[15]);
+
+ /*
+ * This is a new Logical Volume, so add it the the list.
+ */
+ if ((cplv = kmem_zalloc(sizeof (*cplv), KM_NOSLEEP)) ==
+ NULL) {
+ return (ENOMEM);
+
+ cplv->cplv_addr = ents[i]->cprle_addr;
+
+ bcopy(extents[i]->cprle_wwn, cplv->cplv_addr, 16);
+ cplv->cplv_flags |= CPQARY3_VOL_FLAG_WWN;
+
+ list_create(&cplv->cplv_targets,
+ sizeof (cpqary3_target_t),
+ offsetof(cpqary3_target_t, cptg_link_volume));
+
+ cplv->cplv_ctrl = cpq;
+ list_insert_tail(&cpq->cpq_volumes, cplv);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Discover the currently visible set of Logical Volumes exposed by the
+ * controller.
+ */
+int
+cpqary3_discover_logical_volumes(cpqary3_t *cpq, int timeout)
+{
+ cpqary3_command_t *cpcm;
+ cpqary3_report_logical_lun_t *cprll;
+ CommandList_t *cl;
+ cpqary3_report_logical_lun_req_t cprllr = { 0 };
+ int r;
+
+ /*
+ * Allocate the command to send to the device, including buffer space
+ * for the returned list of Logical Volumes.
+ */
+ if ((cpcm = cpqary3_synccmd_alloc(cpq,
+ sizeof (cpqary3_report_logical_lun_t))) == NULL) {
+ return (ENOMEM);
+ }
+ cprll = cpcm->cpcm_internal->cpcmi_va;
+ cl = cpcm->cpcm_va_cmd;
+
+ /*
+ * According to the CISS Specification, the Report Logical LUNs
+ * command is sent to the controller itself. The Masked Peripheral
+ * Device addressing mode is used, with LUN of 0.
+ */
+ cpqary3_write_lun_addr_phys(&cl->Header.LUN, B_TRUE, 0, 0);
+
+ cl->Request.CDBLen = 12;
+ cl->Request.Timeout = 0;
+ cl->Request.Type.Type = CISS_TYPE_CMD;
+ cl->Request.Type.Attribute = CISS_ATTR_ORDERED;
+ cl->Request.Type.Direction = CISS_XFER_READ;
+
+ /*
+ * The Report Logical LUNs command is essentially a vendor-specific
+ * SCSI command, which we assemble into the CDB region of the command
+ * block.
+ */
+ cprllr.cprllr_opcode = CISS_SCMD_REPORT_LOGICAL_LUNS;
+ cprllr.cprllr_extflag = 1;
+ cprllr.cprllr_datasize = htonl(sizeof (cpqary3_report_logical_lun_t));
+ bcopy(&cprllr, cl->Request.CDB, 16);
+
+ dev_err(cpq->dip, CE_WARN, "send: REPORT LOGICAL LUNs");
+ if (cpqary3_synccmd_send(cpq, cpcm, timeout * 1000,
+ CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
+ cpqary3_synccmd_free(cpq, cpcm);
+ return (EIO);
+ }
+
+ if (cpcm->cpcm_status & CPQARY3_CMD_STATUS_ERROR) {
+ ErrorInfo_t *ei = cpcm->cpcm_va_err;
+
+ dev_err(cpq->dip, CE_WARN, "RLL ERROR: %x", ei->CommandStatus);
+ if (ei->CommandStatus != CISS_CMD_DATA_UNDERRUN) {
+ /*
+ * XXX This is fatal, then...
+ */
+ cpqary3_synccmd_free(cpq, cpcm);
+ return (EIO);
+ }
+ }
+
+ mutex_enter(&cpq->cpq_mutex);
+ if ((cprll->cprll_extflag & 0x1) != 0) {
+ dev_err(cpq->dip, CE_WARN, "LOG LUNS: EXT RESPONSE!");
+
+ r = cpqary3_read_logvols_ext(cpq, cprll);
+ } else {
+ dev_err(cpq->dip, CE_WARN, "LOG LUNS: NORMAL RESPONSE!");
+
+ r = cpqary3_read_logvols(cpq, cprll);
+ }
+ mutex_exit(&cpq->cpq_mutex);
+
+ cpqary3_synccmd_free(cpq, cpcm);
+
+ return (r);
+}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c b/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c
index 4e31107c09..3f7d7509db 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c
@@ -62,22 +62,15 @@ cpqary3_probe4targets(cpqary3_t *cpqary3p)
* Return Values: SUCCESS : Build is successful
* FAILURE : Build has Failed
*/
-uint8_t
-cpqary3_build_cmdlist(cpqary3_command_t *cpcm, uint32_t tid)
+void
+cpqary3_build_cmdlist(cpqary3_command_t *cpcm, cpqary3_tgt_t *tgtp)
{
int cntr;
cpqary3_t *cpq = cpcm->cpcm_ctlr;
- cpqary3_tgt_t *tgtp;
- CommandList_t *cmdlistp;
+ CommandList_t *cmdlistp = cpcm->cpcm_va_cmd;
cpqary3_pkt_t *pkt = cpcm->cpcm_private;
struct buf *bfp = pkt->bf;
- if ((tgtp = cpq->cpqary3_tgtp[tid]) == NULL) {
- return (CPQARY3_FAILURE);
- }
-
- cmdlistp = cpcm->cpcm_va_cmd;
-
/* Update Cmd Header */
cmdlistp->Header.SGList = pkt->cmd_cookiecnt;
cmdlistp->Header.SGTotal = pkt->cmd_cookiecnt;
@@ -94,6 +87,9 @@ cpqary3_build_cmdlist(cpqary3_command_t *cpcm, uint32_t tid)
sizeof (PhysDevAddr_t));
DTRACE_PROBE1(build_cmdlist_tape, CommandList_t *, cmdlistp);
+ } else {
+ dev_err(cpq->dip, CE_PANIC, "unexpected target type: %x",
+ tgtp->type);
}
/* Cmd Request */
@@ -142,8 +138,6 @@ cpqary3_build_cmdlist(cpqary3_command_t *cpcm, uint32_t tid)
cmdlistp->SG[cntr].Len = (uint32_t)
pkt->cmd_dmacookies[cntr].dmac_size;
}
-
- return (CPQARY3_SUCCESS);
}
@@ -159,20 +153,22 @@ cpqary3_build_cmdlist(cpqary3_command_t *cpcm, uint32_t tid)
* FAILURE - Could not submit the abort cmd.
*/
uint8_t
-cpqary3_send_abortcmd(cpqary3_t *cpqary3p, uint16_t target_id,
- CommandList_t *cmdlist2abortp)
+cpqary3_send_abortcmd(cpqary3_t *cpq, cpqary3_tgt_t *tgtp,
+ cpqary3_command_t *abort_cpcm)
{
- CommandList_t *cmdlistp;
- cpqary3_tgt_t *cpqtgtp;
- cpqary3_tag_t *cpqary3_tagp;
- cpqary3_command_t *cpcm;
+ CommandList_t *cmdlistp;
+ cpqary3_tag_t *cpqary3_tagp;
+ cpqary3_command_t *cpcm;
- if (target_id == CTLR_SCSI_ID) {
- return (CPQARY3_FAILURE);
- }
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
- if ((cpqtgtp = cpqary3p->cpqary3_tgtp[target_id]) == NULL) {
- return (CPQARY3_FAILURE);
+ switch (tgtp->type) {
+ case CPQARY3_TARGET_TAPE:
+ case CPQARY3_TARGET_LOG_VOL:
+ break;
+
+ default:
+ return (EINVAL);
}
/*
@@ -180,10 +176,8 @@ cpqary3_send_abortcmd(cpqary3_t *cpqary3p, uint16_t target_id,
* Update the Command List accordingly
* Submit the command and wait for a signal
*/
-
- /* BGB: CVFIX -> Introduced the call to cpqary3_synccmd_alloc */
- if ((cpcm = cpqary3_synccmd_alloc(cpqary3p, 0)) == NULL) {
- return (CPQARY3_FAILURE);
+ if ((cpcm = cpqary3_synccmd_alloc(cpq, 0)) == NULL) {
+ return (ENOMEM);
}
cmdlistp = cpcm->cpcm_va_cmd;
@@ -199,43 +193,59 @@ cpqary3_send_abortcmd(cpqary3_t *cpqary3p, uint16_t target_id,
cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
cmdlistp->Request.CDB[0] = CISS_MSG_ABORT;
- if (cmdlist2abortp != NULL) { /* Abort this Particular Task */
+ if (abort_cpcm != NULL) {
+ /*
+ * Abort the specified task.
+ */
cmdlistp->Request.CDB[1] = CISS_ABORT_TASK;
+
cpqary3_tagp = (cpqary3_tag_t *)&cmdlistp->Request.CDB[4];
- cpqary3_tagp->tag_value = cmdlist2abortp->Header.Tag.tag_value;
- } else { /* Abort all tasks for this Target */
+ cpqary3_tagp->tag_value = abort_cpcm->cpcm_tag;
+
+ if (abort_cpcm->cpcm_time_abort != 0) {
+ abort_cpcm->cpcm_time_abort = ddi_get_lbolt();
+ }
+ abort_cpcm->cpcm_status |= CPQARY3_CMD_STATUS_ABORT_SENT;
+
+ } else {
+ /*
+ * Abort all tasks for the controller.
+ * XXX Does this cause the controller to fire completion
+ * of all inflight tasks, but marked aborted?
+ */
cmdlistp->Request.CDB[1] = CISS_ABORT_TASKSET;
- switch (cpqtgtp->type) {
+ switch (tgtp->type) {
case CPQARY3_TARGET_LOG_VOL:
cmdlistp->Header.LUN.LogDev.Mode = LOGICAL_VOL_ADDR;
- cmdlistp->Header.LUN.LogDev.VolId = cpqtgtp->logical_id;
+ cmdlistp->Header.LUN.LogDev.VolId = tgtp->logical_id;
break;
+
case CPQARY3_TARGET_TAPE:
- bcopy(&(cpqtgtp->PhysID),
- &(cmdlistp->Header.LUN.PhysDev),
+ bcopy(&(tgtp->PhysID), &(cmdlistp->Header.LUN.PhysDev),
sizeof (PhysDevAddr_t));
+ break;
+
+ default:
+ panic("unexpected target type");
+ break;
}
}
- cpcm->cpcm_complete = cpqary3_synccmd_complete;
-
- /* BGB: CVFIX -> Introduced a call to cpqary3_synccmd_send */
- if (cpqary3_synccmd_send(cpqary3p, cpcm, 30000,
+ if (cpqary3_synccmd_send(cpq, cpcm, 30000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
- cpqary3_synccmd_free(cpqary3p, cpcm);
+ cpqary3_synccmd_free(cpq, cpcm);
return (CPQARY3_FAILURE);
}
- if (cmdlistp->Header.Tag.error != 0) {
- cpqary3_synccmd_free(cpqary3p, cpcm);
+ if (cpcm->cpcm_status & CPQARY3_CMD_STATUS_ERROR) {
+ cpqary3_synccmd_free(cpq, cpcm);
return (CPQARY3_FAILURE);
}
- cpqary3_synccmd_free(cpqary3p, cpcm);
+ cpqary3_synccmd_free(cpq, cpcm);
return (CPQARY3_SUCCESS);
-
}
int
@@ -323,7 +333,7 @@ cpqary3_probe4LVs(cpqary3_t *cpqary3p)
cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED;
cmdlistp->Request.Type.Direction = CISS_XFER_READ;
- cmdlistp->Request.CDB[0] = CISS_OPCODE_RLL;
+ cmdlistp->Request.CDB[0] = CISS_SCMD_REPORT_LOGICAL_LUNS;
data_addr_len = sizeof (rll_data_t);
@@ -341,7 +351,7 @@ cpqary3_probe4LVs(cpqary3_t *cpqary3p)
return (CPQARY3_FAILURE);
}
- if ((cmdlistp->Header.Tag.error != 0) &&
+ if ((cpcm->cpcm_status & CPQARY3_CMD_STATUS_ERROR) &&
(cpcm->cpcm_va_err->CommandStatus != CISS_CMD_DATA_UNDERRUN)) {
dev_err(cpqary3p->dip, CE_WARN, "probe for logical targets "
"failed");
@@ -394,11 +404,11 @@ cpqary3_probe4LVs(cpqary3_t *cpqary3p)
* Fix for QXCR1000446657: Logical drives are re numbered after
* deleting a Logical drive.
* We are using new indexing mechanism to fill the
- * cpqary3_tgtp[],
- * Check given during memory allocation of cpqary3_tgtp
+ * cpq_targets[],
+ * Check given during memory allocation of cpq_targets
* elements, so that memory is not re-allocated each time the
* cpqary3_probe4LVs() is called.
- * Check given while freeing the memory of the cpqary3_tgtp[]
+ * Check given while freeing the memory of the cpq_targets[]
* elements, when a hole is found in the Logical Drives
* configured.
*/
@@ -410,14 +420,14 @@ cpqary3_probe4LVs(cpqary3_t *cpqary3p)
cntr : cntr + CPQARY3_TGT_ALIGNMENT);
lun_id = (rllp->ll_data[ld_count].logical_id & 0xFFFF);
if (cntr != lun_id) {
- if (cpqary3p->cpqary3_tgtp[i]) {
- kmem_free(cpqary3p->cpqary3_tgtp[i],
+ if (cpqary3p->cpq_targets[i]) {
+ kmem_free(cpqary3p->cpq_targets[i],
sizeof (cpqary3_tgt_t));
- cpqary3p->cpqary3_tgtp[i] = NULL;
+ cpqary3p->cpq_targets[i] = NULL;
}
} else {
- if (cpqary3p->cpqary3_tgtp[i] == NULL &&
- !(cpqary3p->cpqary3_tgtp[i] =
+ if (cpqary3p->cpq_targets[i] == NULL &&
+ !(cpqary3p->cpq_targets[i] =
(cpqary3_tgt_t *)kmem_zalloc(
sizeof (cpqary3_tgt_t), KM_NOSLEEP))) {
cmn_err(CE_WARN,
@@ -429,9 +439,9 @@ cpqary3_probe4LVs(cpqary3_t *cpqary3p)
/* Sync Changes */
return (CPQARY3_FAILURE);
}
- cpqary3p->cpqary3_tgtp[i]->logical_id =
+ cpqary3p->cpq_targets[i]->logical_id =
rllp->ll_data[ld_count].logical_id;
- cpqary3p->cpqary3_tgtp[i]->type =
+ cpqary3p->cpq_targets[i]->type =
CPQARY3_TARGET_LOG_VOL;
/*
@@ -449,8 +459,8 @@ cpqary3_probe4LVs(cpqary3_t *cpqary3p)
cpqary3_tgt_t *t;
i = ((cntr < CTLR_SCSI_ID) ?
cntr : cntr + CPQARY3_TGT_ALIGNMENT);
- t = cpqary3p->cpqary3_tgtp[i];
- cpqary3p->cpqary3_tgtp[i] = NULL;
+ t = cpqary3p->cpq_targets[i];
+ cpqary3p->cpq_targets[i] = NULL;
if (t != NULL) {
kmem_free(t, sizeof (*t));
}
@@ -509,7 +519,7 @@ cpqary3_probe4Tapes(cpqary3_t *cpqary3p)
cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED;
cmdlistp->Request.Type.Direction = CISS_XFER_READ;
- cmdlistp->Request.CDB[0] = CISS_OPCODE_RPL;
+ cmdlistp->Request.CDB[0] = CISS_SCMD_REPORT_PHYSICAL_LUNS;
data_addr_len = sizeof (rpl_data_t);
@@ -527,7 +537,7 @@ cpqary3_probe4Tapes(cpqary3_t *cpqary3p)
return (CPQARY3_FAILURE);
}
- if ((cmdlistp->Header.Tag.error != 0) &&
+ if ((cpcm->cpcm_status & CPQARY3_CMD_STATUS_ERROR) &&
(cpcm->cpcm_va_err->CommandStatus != CISS_CMD_DATA_UNDERRUN)) {
cmn_err(CE_WARN, "CPQary3 : Probe for physical targets "
"returned ERROR !");
@@ -568,8 +578,8 @@ cpqary3_probe4Tapes(cpqary3_t *cpqary3p)
for (cntr = 0; cntr < phy_lun_no; cntr++) {
if (rplp->pl_data[cntr].Mode == CISS_PHYS_MODE) {
- if (cpqary3p->cpqary3_tgtp[ii] == NULL &&
- !(cpqary3p->cpqary3_tgtp[ii] =
+ if (cpqary3p->cpq_targets[ii] == NULL &&
+ !(cpqary3p->cpq_targets[ii] =
(cpqary3_tgt_t *)
kmem_zalloc(sizeof (cpqary3_tgt_t), KM_NOSLEEP))) {
cmn_err(CE_WARN, "CPQary3 : Failed to Detect "
@@ -579,13 +589,13 @@ cpqary3_probe4Tapes(cpqary3_t *cpqary3p)
}
bcopy(&(rplp->pl_data[cntr]),
- &(cpqary3p->cpqary3_tgtp[ii]->PhysID),
+ &(cpqary3p->cpq_targets[ii]->PhysID),
sizeof (PhysDevAddr_t));
- cpqary3p->cpqary3_tgtp[ii]->type = CPQARY3_TARGET_TAPE;
+ cpqary3p->cpq_targets[ii]->type = CPQARY3_TARGET_TAPE;
DTRACE_PROBE1(tape_discovered,
- cpqary3_tgt_t *, cpqary3p->cpqary3_tgtp[ii]);
+ cpqary3_tgt_t *, cpqary3p->cpq_targets[ii]);
ii++;
}
@@ -596,44 +606,3 @@ cpqary3_probe4Tapes(cpqary3_t *cpqary3p)
return (CPQARY3_SUCCESS);
}
-
-/*
- * Function : cpqary3_synccmd_complete
- * Description : This routine processes the completed commands
- * using the sync interface and
- * initiates any callback that is needed.
- * Called By : cpqary3_transport
- * Parameters : per-command
- * Calls : cpqary3_cmdlist_release, cpqary3_synccmd_cleanup
- * Return Values: None
- */
-void
-cpqary3_synccmd_complete(cpqary3_command_t *cpcm)
-{
- cpqary3_t *cpq = cpcm->cpcm_ctlr;
-
- VERIFY(MUTEX_HELD(&cpq->sw_mutex));
-
- switch (cpcm->cpcm_synccmd_status) {
- case CPQARY3_SYNCCMD_STATUS_TIMEOUT:
- /*
- * The submitter has abandoned this command, so we
- * have to free the resources here.
- */
- mutex_exit(&cpq->sw_mutex);
- cpqary3_command_free(cpcm);
- mutex_enter(&cpq->sw_mutex);
- return;
-
- case CPQARY3_SYNCCMD_STATUS_SUBMITTED:
- cpcm->cpcm_synccmd_status = CPQARY3_SYNCCMD_STATUS_NONE;
- cv_broadcast(&cpq->cv_ioctl_wait);
- return;
-
- case CPQARY3_SYNCCMD_STATUS_NONE:
- panic("synccmd completed but status is NONE");
- break;
- }
-
- panic("unknown synccmd status");
-}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_scsi.h b/usr/src/uts/common/io/cpqary3/cpqary3_scsi.h
index a91373555e..b7d33348fd 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_scsi.h
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_scsi.h
@@ -38,19 +38,27 @@ extern "C" {
#define CISS_NEW_READ 0xC0
#define CISS_NEW_WRITE 0xC1
-#define CISS_OPCODE_RLL 0xC2
-#define CISS_OPCODE_RPL 0xC3
#define CISS_NO_TIMEOUT 0x00
/*
+ * Vendor-specific SCSI Commands
+ *
+ * These command opcodes are for use in the first byte of the CDB in a
+ * CISS_TYPE_CMD XXX message. These are essentially SCSI commands, but using
+ * the vendor-specific part of the opcode space; i.e., 0xC0 through 0xFF.
+ */
+#define CISS_SCMD_REPORT_LOGICAL_LUNS 0xC2
+#define CISS_SCMD_REPORT_PHYSICAL_LUNS 0xC3
+
+/*
* BMIC Commands
*
* These commands are generally not documented in the OpenCISS specification,
* but _do_ appear in "Compaq Host-Based PCI Array Controller Firmware
* Specification" (March 1999).
*
- * These commands are generally sent to the controller LUN via
- * CISS_SCMD_ARRAY_WRITE in a command CDB.
+ * These commands are sent to the controller LUN via CISS_SCMD_ARRAY_WRITE
+ * and (CISS_SCMD_ARRAY_READ? XXX) in a command CDB.
*/
#define BMIC_FLUSH_CACHE 0xC2
#define BMIC_IDENTIFY_LOGICAL_DRIVE 0x10
@@ -76,25 +84,10 @@ extern "C" {
* 7 - (Controller)
* 8 - 32 7 - 31
*/
-
#define CPQARY3_TGT_ALIGNMENT 0x1
-#define CPQARY3_LEN_TAGINUSE 0x4
-
-#define CPQARY3_CDBLEN_12 12
-#define CPQARY3_CDBLEN_16 16
-
-/*
- * possible values to fill in the cmdpvt_flag member
- * in the cpqary3_cmdpvt_t structure
- */
-#define CPQARY3_TIMEOUT 1
-#define CPQARY3_CV_TIMEOUT 2
-#define CPQARY3_RESET 4
-#define CPQARY3_SYNC_SUBMITTED 8
-#define CPQARY3_SYNC_TIMEOUT 16
-#define CPQARY3_COALESCE_DELAY 0x0
-#define CPQARY3_COALESCE_COUNT 0x00000001l
+#define CPQARY3_CDBLEN_12 12
+#define CPQARY3_CDBLEN_16 16
/* Fatal SCSI Status */
#define SCSI_CHECK_CONDITION 0x2
@@ -102,6 +95,37 @@ extern "C" {
#pragma pack(1)
+typedef struct cpqary3_report_logical_lun_ent {
+ LogDevAddr_t cprle_addr;
+} cpqary3_report_logical_lun_ent_t;
+
+typedef struct cpqary3_report_logical_lun_extent {
+ LogDevAddr_t cprle_addr;
+ uint8_t cprle_wwn[16];
+} cpqary3_report_logical_lun_extent_t;
+
+typedef struct cpqary3_report_logical_lun {
+ uint32_t cprll_datasize; /* Big Endian */
+ uint8_t cprll_extflag;
+ uint8_t cprll_reserved1[3];
+ union {
+ cpqary3_report_logical_lun_ent_t ents[MAX_LOGDRV];
+ cpqary3_report_logical_lun_extent_t extents[MAX_LOGDRV];
+ } cprll_data;
+} cpqary3_report_logical_lun_t;
+
+typedef struct cpqary3_report_logical_lun_req {
+ uint8_t cprllr_opcode;
+ uint8_t cprllr_extflag;
+ uint8_t cprllr_reserved1[4];
+ uint32_t cprllr_datasize; /* Big Endian */
+ uint8_t cprllr_reserved2;
+ uint8_t cprllr_control;
+} cpqary3_report_logical_lun_req_t;
+
+
+
+
typedef struct flushcache {
uint16_t disable_flag;
uint8_t reserved[510];
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_transport.c b/usr/src/uts/common/io/cpqary3/cpqary3_transport.c
index f829a7f018..1e3865acc4 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_transport.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_transport.c
@@ -25,19 +25,19 @@ static int cpqary3_tgt_init(dev_info_t *, dev_info_t *, scsi_hba_tran_t *,
struct scsi_device *);
static int cpqary3_tgt_probe(struct scsi_device *, int (*)());
static int cpqary3_tran_start(struct scsi_address *, struct scsi_pkt *);
-static int cpqary3_reset(struct scsi_address *, int);
-static int cpqary3_abort(struct scsi_address *, struct scsi_pkt *);
+static int cpqary3_tran_reset(struct scsi_address *, int);
+static int cpqary3_tran_abort(struct scsi_address *, struct scsi_pkt *);
static int cpqary3_getcap(struct scsi_address *, char *, int);
static int cpqary3_setcap(struct scsi_address *, char *, int, int);
static int cpqary3_dma_alloc(cpqary3_t *, struct scsi_pkt *,
struct buf *, int, int (*)());
static int cpqary3_dma_move(struct scsi_pkt *, struct buf *, cpqary3_t *);
static int cpqary3_handle_flag_nointr(cpqary3_command_t *, struct scsi_pkt *);
-static int cpqary3_poll(cpqary3_t *, uint32_t);
static void cpqary3_dmafree(struct scsi_address *, struct scsi_pkt *);
static void cpqary3_dma_sync(struct scsi_address *, struct scsi_pkt *);
-static void cpqary3_destroy_pkt(struct scsi_address *, struct scsi_pkt *);
-static struct scsi_pkt *cpqary3_init_pkt(struct scsi_address *,
+static void cpqary3_tran_destroy_pkt(struct scsi_address *,
+ struct scsi_pkt *);
+static struct scsi_pkt *cpqary3_tran_init_pkt(struct scsi_address *,
struct scsi_pkt *, struct buf *, int, int, int, int, int (*callback)(),
caddr_t);
static int cpqary3_additional_cmd(struct scsi_pkt *scsi_pktp, cpqary3_t *);
@@ -52,11 +52,7 @@ extern ddi_dma_attr_t cpqary3_dma_attr;
void
cpqary3_init_hbatran(cpqary3_t *cpq)
{
- scsi_hba_tran_t *hba_tran;
-
- ASSERT(ctlr != NULL);
-
- hba_tran = cpq->cpq_hba_tran;
+ scsi_hba_tran_t *hba_tran = cpq->cpq_hba_tran;
/*
* Memory for the transport vector has been allocated by now.
@@ -70,8 +66,8 @@ cpqary3_init_hbatran(cpqary3_t *cpq)
hba_tran->tran_tgt_probe = cpqary3_tgt_probe;
/* Resource Allocation */
- hba_tran->tran_init_pkt = cpqary3_init_pkt;
- hba_tran->tran_destroy_pkt = cpqary3_destroy_pkt;
+ hba_tran->tran_init_pkt = cpqary3_tran_init_pkt;
+ hba_tran->tran_destroy_pkt = cpqary3_tran_destroy_pkt;
hba_tran->tran_sync_pkt = cpqary3_dma_sync;
hba_tran->tran_dmafree = cpqary3_dmafree;
@@ -83,8 +79,8 @@ cpqary3_init_hbatran(cpqary3_t *cpq)
hba_tran->tran_setcap = cpqary3_setcap;
/* Abort and Reset */
- hba_tran->tran_reset = cpqary3_reset;
- hba_tran->tran_abort = cpqary3_abort;
+ hba_tran->tran_reset = cpqary3_tran_reset;
+ hba_tran->tran_abort = cpqary3_tran_abort;
}
/* ARGSUSED */
@@ -95,10 +91,10 @@ cpqary3_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
uint32_t tid = SD2TGT(sd);
uint32_t lun = SD2LUN(sd);
cpqary3_t *ctlr;
+ cpqary3_tgt_t *tgtp;
ctlr = (cpqary3_t *)hba_tran->tran_hba_private;
- extern int8_t cpqary3_detect_target_geometry(cpqary3_t *);
if ((CPQARY3_SUCCESS == cpqary3_probe4targets(ctlr)) &&
(ctlr->cpq_ntargets > 0)) {
(void) cpqary3_detect_target_geometry(ctlr);
@@ -124,25 +120,38 @@ cpqary3_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
* is target does not exist, return FAILURE
*/
- mutex_enter(&ctlr->sw_mutex);
+ mutex_enter(&ctlr->cpq_mutex);
- if (!(ctlr->cpqary3_tgtp[tid])) {
- mutex_exit(&ctlr->sw_mutex);
+ if ((tgtp = cpqary3_target_from_id(ctlr, tid)) == NULL) {
+ mutex_exit(&ctlr->cpq_mutex);
return (DDI_FAILURE);
}
- ctlr->cpqary3_tgtp[tid]->tgt_dip = tgt_dip;
- ctlr->cpqary3_tgtp[tid]->ctlr_flags = CPQARY3_CAP_DISCON_ENABLED |
+ tgtp->tgt_dip = tgt_dip;
+ tgtp->ctlr_flags = CPQARY3_CAP_DISCON_ENABLED |
CPQARY3_CAP_SYNC_ENABLED | CPQARY3_CAP_WIDE_XFER_ENABLED |
CPQARY3_CAP_ARQ_ENABLED;
- mutex_exit(&ctlr->sw_mutex);
+ mutex_exit(&ctlr->cpq_mutex);
DTRACE_PROBE1(tgt_init_done, uint32_t, tid);
return (DDI_SUCCESS);
}
+void
+cpqary3_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip,
+ scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
+{
+ cpqary3_t *cpq = (cpqary3_t *)hba_tran->tran_hba_private;
+
+ mutex_enter(&cpq->cpq_mutex);
+ /*
+ * XXX
+ */
+ mutex_exit(&cpq->cpq_mutex);
+}
+
static int
cpqary3_tgt_probe(struct scsi_device *sd, int (*waitfunc)())
{
@@ -164,104 +173,77 @@ cpqary3_tgt_probe(struct scsi_device *sd, int (*waitfunc)())
return (scsi_hba_probe(sd, waitfunc));
}
-/*
- * Function : cpqary3_init_pkt
- * Description : This routine allocates resources for a SCSI packet.
- * Called By : cpqary3_init_pkt()
- * Parameters : SCSI address, SCSI packet, buffer, CDB length,
- * SCB length, driver private length, flags modifier,
- * callback function, arguement for the callback function
- * Calls : cpqary3_dma_alloc(), cpqary3_dma_move()
- * Return Values: allocated SCSI packet / NULL
- */
/* ARGSUSED */
static struct scsi_pkt *
-cpqary3_init_pkt(struct scsi_address *sa, struct scsi_pkt *scsi_pktp,
+cpqary3_tran_init_pkt(struct scsi_address *sa, struct scsi_pkt *scsi_pktp,
struct buf *bp, int cmdlen, int statuslen, int tgtlen,
int flags, int (*callback)(), caddr_t arg)
{
- cpqary3_t *cpqary3p;
- dev_info_t *dip;
- cpqary3_pkt_t *cpqary3_pktp;
+ cpqary3_t *cpq = SA2CTLR(sa);
+ boolean_t allocated_packet = B_FALSE;
+
+ cpqary3_pkt_t *privp;
struct scsi_pkt *new_scsi_pktp;
ASSERT(callback == NULL_FUNC || callback == SLEEP_FUNC);
- cpqary3p = SA2CTLR(sa);
- dip = cpqary3p->dip;
-
- /*
- * If the SCSI packet is NULL, allocate frresh resources to it.
- * Else, get the next available resources for the same
- */
-
if (scsi_pktp == NULL) {
- scsi_pktp = scsi_hba_pkt_alloc(dip, sa, cmdlen, statuslen,
- tgtlen, sizeof (cpqary3_pkt_t), callback, NULL);
- if (!scsi_pktp)
+ /*
+ * The framework requires we allocate a new packet
+ * structure via scsi_hba_pkt_alloc(9F).
+ */
+ if ((scsi_pktp = scsi_hba_pkt_alloc(cpq->dip, sa, cmdlen,
+ statuslen, tgtlen, sizeof (cpqary3_pkt_t), callback,
+ NULL)) == NULL) {
return (NULL);
+ }
+ allocated_packet = B_TRUE;
+ }
- cpqary3_pktp = (cpqary3_pkt_t *)scsi_pktp->pkt_ha_private;
- bzero(cpqary3_pktp, sizeof (cpqary3_pkt_t));
-
- cpqary3_pktp->scsi_cmd_pkt = scsi_pktp;
+ privp = (cpqary3_pkt_t *)scsi_pktp->pkt_ha_private;
+ if (allocated_packet) {
/*
- * Store the CDB length and sense data length in the
- * pkt private
+ * Our private SCSI packet object was just allocated by
+ * scsi_hba_pkt_alloc(9F). Initialise it:
*/
- cpqary3_pktp->cdb_len = cmdlen;
- cpqary3_pktp->scb_len = statuslen;
- cpqary3_pktp->cmd_dmahandle = NULL;
- cpqary3_pktp->cmd_command = NULL;
+ bzero(privp, sizeof (*privp));
/*
- * Initialize to NULL all the fields of scsi_pktp, except
- * pkt_scbp, pkt_cdbp, pkt_ha_private and pkt_private members.
+ * Link our private point back to the SCSI framework
+ * packet object, and include the CDB/SCB lengths we
+ * have been passed.
*/
- scsi_pktp->pkt_address = *sa;
- scsi_pktp->pkt_comp = (void (*) ())NULL;
- scsi_pktp->pkt_flags = 0;
- scsi_pktp->pkt_time = 0;
- scsi_pktp->pkt_resid = 0;
- scsi_pktp->pkt_statistics = 0;
- scsi_pktp->pkt_state = 0;
- scsi_pktp->pkt_reason = 0;
-
- if (flags & PKT_CONSISTENT)
- cpqary3_pktp->cmd_flags |= DDI_DMA_CONSISTENT;
-
- if (flags & PKT_DMA_PARTIAL)
- cpqary3_pktp->cmd_flags |= DDI_DMA_PARTIAL;
+ privp->scsi_cmd_pkt = scsi_pktp;
+ privp->cdb_len = cmdlen;
+ privp->scb_len = statuslen;
- new_scsi_pktp = scsi_pktp;
- } else {
- new_scsi_pktp = NULL;
- cpqary3_pktp = (cpqary3_pkt_t *)scsi_pktp->pkt_ha_private;
+ if (flags & PKT_DMA_PARTIAL) {
+ privp->cmd_flags |= DDI_DMA_PARTIAL;
+ }
}
- cpqary3_pktp->bf = bp;
-
- /*
- * If any I/O is desired, Allocate/Move DMA resources for the SCSI
- * packet
- * If first time allocation for this SCSI packet, allocate fresh DMA
- * Else, move the already allocated DMA resources
- */
- if (bp && bp->b_bcount != 0) { /* I/O is desired */
- if (!cpqary3_pktp->cmd_dmahandle) { /* First time allocation */
- if (cpqary3_dma_alloc(cpqary3p, scsi_pktp,
- bp, flags, callback) == CPQARY3_FAILURE) {
- if (new_scsi_pktp)
- scsi_hba_pkt_free(sa, new_scsi_pktp);
- return ((struct scsi_pkt *)NULL);
- }
- } else {
- ASSERT(new_scsi_pktp == NULL);
- if (CPQARY3_FAILURE ==
- cpqary3_dma_move(scsi_pktp, bp, cpqary3p)) {
- return ((struct scsi_pkt *)NULL);
- }
+ if (bp != NULL && allocated_packet) {
+ /*
+ * This is a new packet with an associated buffer. The
+ * framework requires us to allocate appropriate DMA
+ * resources.
+ */
+ privp->bf = bp;
+ if (cpqary3_dma_alloc(cpq, scsi_pktp, bp, flags,
+ callback) != DDI_SUCCESS) {
+ scsi_hba_pkt_free(sa, scsi_pktp);
+ return (NULL);
+ }
+ } else if (bp != NULL && !allocated_packet &&
+ (flags & PKT_DMA_PARTIAL) != 0) {
+ /*
+ * This is not a new packet, but a buffer was passed in and we
+ * had previously allocated DMA resources. This is a request
+ * from the framework to move the DMA resources.
+ */
+ if (cpqary3_dma_move(scsi_pktp, bp, cpq) != DDI_SUCCESS) {
+ return (NULL);
}
}
@@ -528,9 +510,6 @@ cpqary3_set_arq_data(struct scsi_pkt *pkt, uchar_t key)
arqstat->sts_sensedata.es_valid = 1;
arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
arqstat->sts_sensedata.es_key = key;
-
- pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
- STATE_SENT_CMD | STATE_XFERRED_DATA;
}
static int
@@ -546,8 +525,7 @@ cpqary3_tran_start(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
/*
* Determine the target to which this command is addressed.
*/
- if (SA2TGT(sa) >= CPQARY3_MAX_TGT ||
- (tgtp = cpq->cpqary3_tgtp[SA2TGT(sa)]) == NULL ||
+ if ((tgtp = cpqary3_target_from_addr(cpq, sa)) == NULL ||
tgtp->type == CPQARY3_TARGET_NONE) {
/*
* This target does not exist.
@@ -556,6 +534,16 @@ cpqary3_tran_start(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
}
/*
+ * Initialise the SCSI packet as described in tran_start(9E). We will
+ * progressively update these fields as the command moves through the
+ * submission and completion states.
+ */
+ scsi_pktp->pkt_resid = 0;
+ scsi_pktp->pkt_reason = CMD_CMPLT;
+ scsi_pktp->pkt_statistics = 0;
+ scsi_pktp->pkt_state = 0;
+
+ /*
* Check to see if we need any special handling for this SCSI
* command.
*/
@@ -569,7 +557,10 @@ cpqary3_tran_start(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
* controller firmware.
*/
cpqary3_set_arq_data(scsi_pktp, KEY_ILLEGAL_REQUEST);
- if (!nointr) {
+ scsi_pktp->pkt_reason = CMD_BADMSG;
+ scsi_pktp->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
+ STATE_SENT_CMD | STATE_XFERRED_DATA;
+ if (!nointr && scsi_pktp->pkt_comp != NULL) {
(*scsi_pktp->pkt_comp)(scsi_pktp);
}
return (TRAN_ACCEPT);
@@ -579,20 +570,18 @@ cpqary3_tran_start(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
* Emulate SYNCHRONIZE CACHE with the BMIC Flush Cache
* command.
*/
+ scsi_pktp->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
+ STATE_SENT_CMD;
if ((r = cpqary3_flush_cache(cpq)) == ENOMEM) {
return (TRAN_BUSY);
} else if (r != 0) {
scsi_pktp->pkt_reason = CMD_TIMEOUT;
- scsi_pktp->pkt_statistics = STAT_TIMEOUT;
- scsi_pktp->pkt_state = 0;
+ scsi_pktp->pkt_statistics |= STAT_TIMEOUT;
} else {
- scsi_pktp->pkt_reason = CMD_CMPLT;
- scsi_pktp->pkt_statistics = 0;
- scsi_pktp->pkt_state = STATE_GOT_BUS |
- STATE_GOT_TARGET | STATE_SENT_CMD |
- STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ scsi_pktp->pkt_state |= STATE_XFERRED_DATA |
+ STATE_GOT_STATUS;
}
- if (!nointr) {
+ if (!nointr && scsi_pktp->pkt_comp != NULL) {
(*scsi_pktp->pkt_comp)(scsi_pktp);
}
return (TRAN_ACCEPT);
@@ -609,39 +598,63 @@ cpqary3_tran_start(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
}
cpcm->cpcm_private = privp;
privp->cmd_command = cpcm;
+ if (nointr) {
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_POLLED;
+ }
- if ((privp->cmd_flags & DDI_DMA_CONSISTENT) && privp->cmd_dmahandle) {
+ if ((privp->cmd_flags & CFLAG_CMDIOPB) && privp->cmd_dmahandle) {
(void) ddi_dma_sync(privp->cmd_dmahandle, 0, 0,
DDI_DMA_SYNC_FORDEV);
}
+ /*
+ * Build the command to send to the controller based on the SCSI
+ * packet passed in by the framework.
+ */
VERIFY(privp->cmd_cookiecnt <= cpq->cpq_sg_cnt);
+ cpqary3_build_cmdlist(cpcm, tgtp);
- if (cpqary3_build_cmdlist(cpcm, SA2TGT(sa)) != CPQARY3_SUCCESS) {
- goto fail;
- }
+ mutex_enter(&cpq->cpq_mutex);
+ if ((r = cpqary3_submit(cpq, cpcm)) != 0) {
+ mutex_exit(&cpq->cpq_mutex);
+
+ /*
+ * The command could not be submitted, so free it now.
+ */
+ cpqary3_command_free(cpcm);
- if (nointr) {
/*
- * This command was issued with the FLAG_NOINTR flag, so
- * perform the necessary polling to collect the response
- * synchronously.
+ * Inform the SCSI framework that we could not submit
+ * the command.
*/
- return (cpqary3_handle_flag_nointr(cpcm, scsi_pktp));
+ return (r == EAGAIN ? TRAN_BUSY : TRAN_FATAL_ERROR);
}
- mutex_enter(&cpq->hw_mutex);
- r = cpqary3_submit(cpq, cpcm);
- mutex_exit(&cpq->hw_mutex);
- if (r != 0) {
- goto fail;
+ /*
+ * Update the SCSI packet to reflect submission of the command.
+ */
+ scsi_pktp->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
+ STATE_SENT_CMD;
+
+ if (!nointr) {
+ /*
+ * This is a regular command submission, so we return
+ * without polling for completion.
+ */
+ mutex_exit(&cpq->cpq_mutex);
+ return (TRAN_ACCEPT);
}
+ /*
+ * Poll the controller for completion of the command we submitted.
+ * Once this routine has returned, the completion callback will have
+ * been fired with either an active response (success or error) or a
+ * timeout. The command is freed by the completion callback, so it
+ * may not be referenced again after this call returns.
+ */
+ cpqary3_poll_for(cpq, cpcm);
+ mutex_exit(&cpq->cpq_mutex);
return (TRAN_ACCEPT);
-
-fail:
- cpqary3_command_free(cpcm);
- return (TRAN_FATAL_ERROR);
}
/*
@@ -719,7 +732,7 @@ cpqary3_dma_sync(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
* Return Values: None
*/
static void
-cpqary3_destroy_pkt(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
+cpqary3_tran_destroy_pkt(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
{
cpqary3_pkt_t *cpqary3_pktp;
@@ -748,22 +761,20 @@ cpqary3_destroy_pkt(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
}
/*
- * Function : cpqary3_reset
- * Description : This routine resets a SCSI bus/target.
- * Called By : kernel
- * Parameters : SCSI address, reset level required
- * Calls : None
- * Return Values: SUCCESS
+ * The tran_reset(9E) entry point is called when the SCSI framework wishes us
+ * to reset the SCSI bus (RESET_ALL), a particular target (RESET_TARGET), or a
+ * particular logical unit (RESET_LUN).
+ *
+ * On success, return 1; on failure, return 0.
*/
-/* ARGSUSED */
static int
-cpqary3_reset(struct scsi_address *sa, int level)
+cpqary3_tran_reset(struct scsi_address *sa, int level)
{
/*
- * Fix for Crash seen during RAID 0 Drive removal -
- * just return CPQARY3_SUCCESS on reset request
+ * We currently have no support for resetting the controller.
+ * Signal universal failure to the SCSI framework.
*/
- return (CPQARY3_SUCCESS);
+ return (0);
}
/*
@@ -778,11 +789,18 @@ cpqary3_reset(struct scsi_address *sa, int level)
* a failure. ]
*/
static int
-cpqary3_abort(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
+cpqary3_tran_abort(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
{
- uint32_t tid = SA2TGT(sa);
cpqary3_t *cpq = SA2CTLR(sa);
- CommandList_t *clp = NULL;
+ cpqary3_command_t *cpcm = NULL;
+ cpqary3_tgt_t *tgtp;
+ int r;
+
+ mutex_enter(&cpq->cpq_mutex);
+
+ if ((tgtp = cpqary3_target_from_addr(cpq, sa)) == NULL) {
+ return (0);
+ }
/*
* If SCSI packet exists, abort that particular command.
@@ -794,10 +812,13 @@ cpqary3_abort(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
cpqary3_pkt_t *pktp = (cpqary3_pkt_t *)scsi_pktp->
pkt_ha_private;
- clp = pktp->cmd_command->cpcm_va_cmd;
+ cpcm = pktp->cmd_command;
}
- return (cpqary3_send_abortcmd(cpq, tid, clp));
+ r = cpqary3_send_abortcmd(cpq, tgtp, cpcm);
+
+ mutex_exit(&cpq->cpq_mutex);
+ return (r == 0 ? 1 : 0);
}
/*
@@ -812,15 +833,16 @@ cpqary3_abort(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
static int
cpqary3_getcap(struct scsi_address *sa, char *capstr, int tgtonly)
{
- int index;
- cpqary3_t *ctlr = SA2CTLR(sa);
- cpqary3_tgt_t *tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
+ int index;
+ cpqary3_t *cpq = SA2CTLR(sa);
+ cpqary3_tgt_t *tgtp = cpqary3_target_from_addr(cpq, sa);
/*
* If requested Capability is not supported, return -1.
*/
- if (DDI_FAILURE == (index = scsi_hba_lookup_capstr(capstr)))
+ if ((index = scsi_hba_lookup_capstr(capstr)) == DDI_FAILURE) {
return (CAP_NOT_DEFINED);
+ }
/*
* Getting capability for a particulat target is supported
@@ -930,99 +952,6 @@ cpqary3_setcap(struct scsi_address *sa, char *capstr, int value, int tgtonly)
}
}
-static int
-cpqary3_handle_flag_nointr(cpqary3_command_t *cpcm, struct scsi_pkt *scsi_pktp)
-{
- cpqary3_t *cpq = cpcm->cpcm_ctlr;
-
- /*
- * Before sumitting this command, ensure all commands pending
- * with the controller are completed.
- */
- mutex_enter(&cpq->sw_mutex);
- mutex_enter(&cpq->hw_mutex);
- cpq->cpq_intr_off = B_TRUE;
- cpqary3_intr_set(cpq, B_FALSE);
- if (cpq->cpq_host_support & 0x4) {
- cpqary3_lockup_intr_set(cpq, B_FALSE);
- }
-
- while (avl_numnodes(&cpq->cpq_inflight) > 0) {
- (void) cpqary3_retrieve(cpq, 0, NULL);
- drv_usecwait(1000);
- }
-
- if (cpqary3_submit(cpq, cpcm) != 0) {
- cpq->cpq_intr_off = B_FALSE;
- cpqary3_intr_set(cpq, B_TRUE);
- if (cpq->cpq_host_support & 0x4) {
- cpqary3_lockup_intr_set(cpq, B_TRUE);
- }
-
- mutex_exit(&cpq->hw_mutex);
- mutex_exit(&cpq->sw_mutex);
-
- cpqary3_command_free(cpcm);
- return (TRAN_FATAL_ERROR);
- }
-
- if (cpqary3_poll(cpq, cpcm->cpcm_tag) != DDI_SUCCESS) {
- scsi_pktp->pkt_reason = CMD_TIMEOUT;
- scsi_pktp->pkt_statistics = STAT_TIMEOUT;
- scsi_pktp->pkt_state = 0;
-
- cpq->cpq_intr_off = B_FALSE;
- cpqary3_intr_set(cpq, B_TRUE);
- if (cpq->cpq_host_support & 0x4) {
- cpqary3_lockup_intr_set(cpq, B_TRUE);
- }
-
- mutex_exit(&cpq->hw_mutex);
- mutex_exit(&cpq->sw_mutex);
-
- cpqary3_command_free(cpcm);
- return (TRAN_ACCEPT);
- }
-
- cpq->cpq_intr_off = B_FALSE;
- cpqary3_intr_set(cpq, B_TRUE);
- if (cpq->cpq_host_support & 0x4) {
- cpqary3_lockup_intr_set(cpq, B_TRUE);
- }
-
- mutex_exit(&cpq->hw_mutex);
- mutex_exit(&cpq->sw_mutex);
-
- return (TRAN_ACCEPT);
-}
-
-static int
-cpqary3_poll(cpqary3_t *cpq, uint32_t tag)
-{
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
- VERIFY(MUTEX_HELD(&cpq->sw_mutex));
-
- /*
- * Poll the controller for command completions, stopping if we receive
- * a completion for the watched tag. Note that, although we are
- * looking for a specific completion, any other commands that complete
- * in the interim will have their callbacks fired.
- */
- for (unsigned tries = 0; tries < 120000; tries++) {
- boolean_t found = B_FALSE;
-
- (void) cpqary3_retrieve(cpq, tag, &found);
-
- if (found) {
- return (DDI_SUCCESS);
- }
-
- drv_usecwait(500);
- }
-
- return (DDI_FAILURE);
-}
-
void
cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
{
@@ -1032,60 +961,48 @@ cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
struct scsi_pkt *scsi_pktp = cpcm->cpcm_private->scsi_cmd_pkt;
boolean_t nointr = (scsi_pktp->pkt_flags & FLAG_NOINTR) != 0;
- VERIFY(MUTEX_HELD(&cpqary3p->sw_mutex));
+ VERIFY(MUTEX_HELD(&cpqary3p->cpq_mutex));
VERIFY(cpcm->cpcm_type == CPQARY3_CMDTYPE_OS);
- if (cmdlistp->Header.Tag.error != 0) {
- mutex_exit(&cpqary3p->sw_mutex);
-
- cpqary3_command_free(cpcm);
-
- scsi_pktp->pkt_reason = CMD_CMPLT;
- scsi_pktp->pkt_statistics = 0;
- scsi_pktp->pkt_state = STATE_GOT_BUS |
- STATE_GOT_TARGET | STATE_SENT_CMD |
- STATE_XFERRED_DATA | STATE_GOT_STATUS;
-
- if ((scsi_pktp->pkt_flags & FLAG_NOINTR) == 0) {
- (*scsi_pktp->pkt_comp)(scsi_pktp);
- }
+ if (cpcm->cpcm_status & CPQARY3_CMD_STATUS_TIMEOUT) {
+ scsi_pktp->pkt_reason = CMD_TIMEOUT;
+ scsi_pktp->pkt_statistics |= STAT_TIMEOUT;
+ goto finish;
+ }
- mutex_enter(&cpqary3p->sw_mutex);
- return;
+ if (!(cpcm->cpcm_status & CPQARY3_CMD_STATUS_ERROR)) {
+ scsi_pktp->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ goto finish;
}
switch (errorinfop->CommandStatus) {
- case CISS_CMD_DATA_OVERRUN :
+ case CISS_CMD_DATA_OVERRUN:
scsi_pktp->pkt_reason = CMD_DATA_OVR;
- scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
- STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ scsi_pktp->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
break;
- case CISS_CMD_INVALID :
+ case CISS_CMD_INVALID:
DTRACE_PROBE1(invalid_cmd, struct scsi_pkt *, scsi_pktp);
scsi_pktp->pkt_reason = CMD_BADMSG;
- scsi_pktp->pkt_state = STATE_GOT_BUS |STATE_GOT_TARGET |
- STATE_SENT_CMD | STATE_GOT_STATUS;
+ scsi_pktp->pkt_state |= STATE_GOT_STATUS;
break;
case CISS_CMD_PROTOCOL_ERR :
scsi_pktp->pkt_reason = CMD_BADMSG;
- scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
- STATE_SENT_CMD | STATE_GOT_STATUS;
+ scsi_pktp->pkt_state |= STATE_GOT_STATUS;
break;
case CISS_CMD_HARDWARE_ERR:
case CISS_CMD_CONNECTION_LOST:
scsi_pktp->pkt_reason = CMD_INCOMPLETE;
- scsi_pktp->pkt_state = 0;
+ scsi_pktp->pkt_state = 0; /* XXX ? */
break;
case CISS_CMD_ABORTED:
case CISS_CMD_UNSOLICITED_ABORT:
scsi_pktp->pkt_reason = CMD_ABORTED;
- scsi_pktp->pkt_statistics = STAT_ABORTED;
- scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
- STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
+ scsi_pktp->pkt_statistics |= STAT_ABORTED;
+ scsi_pktp->pkt_state = STATE_XFERRED_DATA | STATE_GOT_STATUS;
break;
case CISS_CMD_ABORT_FAILED:
@@ -1093,8 +1010,7 @@ cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
case CISS_CMD_TIMEOUT:
scsi_pktp->pkt_reason = CMD_TIMEOUT;
- scsi_pktp->pkt_statistics = STAT_TIMEOUT;
- scsi_pktp->pkt_state = 0;
+ scsi_pktp->pkt_statistics |= STAT_TIMEOUT;
break;
case CISS_CMD_DATA_UNDERRUN: /* Significant ONLY for Read & Write */
@@ -1157,15 +1073,13 @@ cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
}
}
- mutex_exit(&cpqary3p->sw_mutex);
-
+finish:
+ mutex_exit(&cpqary3p->cpq_mutex);
cpqary3_command_free(cpcm);
-
- if (!nointr) {
+ if (!nointr && scsi_pktp->pkt_comp != NULL) {
(*scsi_pktp->pkt_comp)(scsi_pktp);
}
-
- mutex_enter(&cpqary3p->sw_mutex);
+ mutex_enter(&cpqary3p->cpq_mutex);
}
static boolean_t
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_util.c b/usr/src/uts/common/io/cpqary3/cpqary3_util.c
index 66ec332dde..7b6f4f9fad 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_util.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_util.c
@@ -26,6 +26,8 @@ cpqary3_lockup_check(cpqary3_t *cpq)
uint32_t heartbeat = ddi_get32(cpq->cpq_ct_handle,
&cpq->cpq_ct->HeartBeat);
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
+
/*
* Check to see if the value is the same as last time we looked:
*/
@@ -62,91 +64,36 @@ cpqary3_lockup_check(cpqary3_t *cpq)
}
}
-/*
- * Function : cpqary3_periodic
- * Description : This routine is called once in 15 seconds to detect any
- * command that is pending with the controller and has
- * timed out.
- * Called By : kernel
- * Parameters : per_controller
- * Calls : None
- * Return Values: None
- */
-void
-cpqary3_periodic(void *arg)
+cpqary3_command_t *
+cpqary3_lookup_inflight(cpqary3_t *cpq, uint32_t tag)
{
- cpqary3_t *cpq = arg;
- uint32_t no_cmds;
-
- cpqary3_lockup_check(cpq);
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
- mutex_enter(&cpq->hw_mutex);
- mutex_exit(&cpq->hw_mutex);
+ cpqary3_command_t srch;
- /*
- * XXX This should be re-tooled to use "cpq_inflight".
- */
-#if 0
- mutex_enter(&cpq->sw_mutex);
- no_cmds = (uint32_t)((cpq->ctlr_maxcmds / 3) * NO_OF_CMDLIST_IN_A_BLK);
- for (uint32_t i = 0; i < no_cmds; i++) {
- cpqary3_cmdpvt_t *local = &cpq->cmdmemlistp->pool[i];
- cpqary3_pkt_t *pktp;
- struct scsi_pkt *scsi_pktp;
- clock_t cpqary3_lbolt;
-
- ASSERT(local != NULL);
- if ((pktp = MEM2PVTPKT(local)) == NULL) {
- continue;
- }
+ srch.cpcm_tag = tag;
- if ((local->cmdpvt_flag == CPQARY3_TIMEOUT) ||
- (local->cmdpvt_flag == CPQARY3_RESET)) {
- continue;
- }
+ return (avl_find(&cpq->cpq_inflight, &srch, NULL));
+}
- if (local->occupied != CPQARY3_OCCUPIED) {
- continue;
- }
+cpqary3_tgt_t *
+cpqary3_target_from_id(cpqary3_t *cpq, unsigned id)
+{
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
- scsi_pktp = pktp->scsi_cmd_pkt;
- cpqary3_lbolt = ddi_get_lbolt();
- if ((scsi_pktp) && (scsi_pktp->pkt_time)) {
- clock_t cpqary3_ticks = cpqary3_lbolt -
- pktp->cmd_start_time;
-
- if ((drv_hztousec(cpqary3_ticks) / 1000000) >
- scsi_pktp->pkt_time) {
- scsi_pktp->pkt_reason = CMD_TIMEOUT;
- scsi_pktp->pkt_statistics = STAT_TIMEOUT;
- scsi_pktp->pkt_state = STATE_GOT_BUS |
- STATE_GOT_TARGET | STATE_SENT_CMD;
- local->cmdpvt_flag = CPQARY3_TIMEOUT;
-
- /* This should always be the case */
- if (scsi_pktp->pkt_comp != NULL) {
- mutex_exit(&cpq->sw_mutex);
- (*scsi_pktp->pkt_comp)(scsi_pktp);
- mutex_enter(&cpq->sw_mutex);
- continue;
- }
- }
- }
+ if (id >= CPQARY3_MAX_TGT) {
+ return (NULL);
}
- mutex_exit(&cpq->sw_mutex);
-#endif
+
+ return (cpq->cpq_targets[id]);
}
-cpqary3_command_t *
-cpqary3_lookup_inflight(cpqary3_t *cpq, uint32_t tag)
+cpqary3_tgt_t *
+cpqary3_target_from_addr(cpqary3_t *cpq, struct scsi_address *sa)
{
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
+ VERIFY(MUTEX_HELD(&cpq->cpq_mutex));
- cpqary3_command_t srch;
-
- srch.cpcm_tag = tag;
-
- return (avl_find(&cpq->cpq_inflight, &srch, NULL));
+ return (cpqary3_target_from_id(cpq, sa->a_target));
}
/*
@@ -161,7 +108,7 @@ int
cpqary3_target_geometry(struct scsi_address *sa)
{
cpqary3_t *ctlr = SA2CTLR(sa);
- cpqary3_tgt_t *tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
+ cpqary3_tgt_t *tgtp = ctlr->cpq_targets[SA2TGT(sa)];
/*
* The target CHS are stored in the per-target structure
@@ -252,19 +199,13 @@ cpqary3_synccmd_free(cpqary3_t *cpq, cpqary3_command_t *cpcm)
* cpqary3_process_pkt() clean it up instead.
*/
- mutex_enter(&cpq->sw_mutex);
- if (cpcm->cpcm_synccmd_status == CPQARY3_SYNCCMD_STATUS_SUBMITTED) {
- /*
- * command is still pending (case #3 above).
- * mark the command as abandoned and let
- * cpqary3_process_pkt() clean it up.
- */
- cpcm->cpcm_synccmd_status = CPQARY3_SYNCCMD_STATUS_TIMEOUT;
- mutex_exit(&cpq->sw_mutex);
+ mutex_enter(&cpq->cpq_mutex);
+ if (cpcm->cpcm_status & CPQARY3_CMD_STATUS_INFLIGHT) {
+ cpcm->cpcm_status |= CPQARY3_CMD_STATUS_ABANDONED;
+ mutex_exit(&cpq->cpq_mutex);
return;
}
- cpcm->cpcm_synccmd_status = CPQARY3_SYNCCMD_STATUS_NONE;
- mutex_exit(&cpq->sw_mutex);
+ mutex_exit(&cpq->cpq_mutex);
/*
* command was either never submitted or has completed
@@ -307,23 +248,17 @@ cpqary3_synccmd_send(cpqary3_t *cpqary3p, cpqary3_command_t *cpcm,
}
/* acquire the sw mutex for our wait */
- mutex_enter(&cpqary3p->sw_mutex);
- mutex_enter(&cpqary3p->hw_mutex);
-
- VERIFY(cpcm->cpcm_synccmd_status == CPQARY3_SYNCCMD_STATUS_NONE);
- cpcm->cpcm_synccmd_status = CPQARY3_SYNCCMD_STATUS_SUBMITTED;
+ mutex_enter(&cpqary3p->cpq_mutex);
if (cpqary3_submit(cpqary3p, cpcm) != 0) {
- mutex_exit(&cpqary3p->hw_mutex);
- mutex_exit(&cpqary3p->sw_mutex);
+ mutex_exit(&cpqary3p->cpq_mutex);
return (-1);
}
- mutex_exit(&cpqary3p->hw_mutex);
/* wait for command completion, timeout, or signal */
- while (cpcm->cpcm_synccmd_status == CPQARY3_SYNCCMD_STATUS_SUBMITTED) {
- kmutex_t *mt = &cpqary3p->sw_mutex;
- kcondvar_t *cv = &cpqary3p->cv_ioctl_wait;
+ while (!(cpcm->cpcm_status & CPQARY3_CMD_STATUS_COMPLETE)) {
+ kmutex_t *mt = &cpqary3p->cpq_mutex;
+ kcondvar_t *cv = &cpqary3p->cpq_cv_finishq;
/* wait with the request behavior */
if (absto) {
@@ -361,7 +296,7 @@ cpqary3_synccmd_send(cpqary3_t *cpqary3p, cpqary3_command_t *cpcm,
}
}
- mutex_exit(&cpqary3p->sw_mutex);
+ mutex_exit(&cpqary3p->cpq_mutex);
return (rc);
}
@@ -434,13 +369,13 @@ cpqary3_detect_target_geometry(cpqary3_t *ctlr)
*/
for (i = 0; ld_count < ctlr->cpq_ntargets; i++) {
- if (i == CTLR_SCSI_ID || ctlr->cpqary3_tgtp[i] == NULL) {
+ if (i == CTLR_SCSI_ID || ctlr->cpq_targets[i] == NULL) {
/* Go to the Next logical target */
continue;
}
bzero(idlogdrive, sizeof (IdLogDrive));
- cmdlistp->Request.CDB[1] = ctlr->cpqary3_tgtp[i]->logical_id;
+ cmdlistp->Request.CDB[1] = ctlr->cpq_targets[i]->logical_id;
/* Always zero */
cmdlistp->Header.LUN.PhysDev.TargetId = 0;
/*
@@ -452,7 +387,7 @@ cpqary3_detect_target_geometry(cpqary3_t *ctlr)
* connected to MSA20 / MSA500
*/
cmdlistp->Header.LUN.PhysDev.Bus =
- (ctlr->cpqary3_tgtp[i]->logical_id) >> 16;
+ (ctlr->cpq_targets[i]->logical_id) >> 16;
cmdlistp->Header.LUN.PhysDev.Mode =
(cmdlistp->Header.LUN.PhysDev.Bus > 0) ?
MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR;
@@ -475,7 +410,7 @@ cpqary3_detect_target_geometry(cpqary3_t *ctlr)
return (CPQARY3_FAILURE);
}
- if (cmdlistp->Header.Tag.error != 0 &&
+ if ((cpcm->cpcm_status & CPQARY3_CMD_STATUS_ERROR) &&
cpcm->cpcm_va_err->CommandStatus != 2) {
DTRACE_PROBE1(id_logdrv_fail,
ErrorInfo_t *, cpcm->cpcm_va_err);
@@ -483,9 +418,9 @@ cpqary3_detect_target_geometry(cpqary3_t *ctlr)
return (CPQARY3_FAILURE);
}
- ctlr->cpqary3_tgtp[i]->properties.drive.heads =
+ ctlr->cpq_targets[i]->properties.drive.heads =
idlogdrive->heads;
- ctlr->cpqary3_tgtp[i]->properties.drive.sectors =
+ ctlr->cpq_targets[i]->properties.drive.sectors =
idlogdrive->sectors;
DTRACE_PROBE2(tgt_geometry_detect,