summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/Makefile.files12
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3.c78
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3.h137
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_ciss.c445
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_ciss_performant.c320
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c194
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_commands.c203
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_ioctl.c16
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_isr.c158
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_mem.c147
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_mem.h41
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_q_mem.h103
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_scsi.c36
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_scsi.h43
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c865
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_transport.c435
-rw-r--r--usr/src/uts/common/io/cpqary3/cpqary3_util.c19
17 files changed, 1491 insertions, 1761 deletions
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 8139f2c022..ebb40152cc 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -2153,10 +2153,16 @@ DR_SAS_OBJS = dr_sas.o
# CPQARY3 module
#
# XXX disabled cpqary3_noe.o cpqary3_ioctl.o
-CPQARY3_OBJS = cpqary3.o cpqary3_talk2ctlr.o \
- cpqary3_isr.o cpqary3_transport.o cpqary3_mem.o \
+CPQARY3_OBJS = cpqary3.o \
+ cpqary3_transport.o cpqary3_mem.o \
cpqary3_scsi.o cpqary3_util.o \
- cpqary3_bd.o cpqary3_device.o cpqary3_interrupts.o
+ cpqary3_bd.o \
+ cpqary3_device.o \
+ cpqary3_interrupts.o \
+ cpqary3_commands.o \
+ cpqary3_ciss_simple.o \
+ cpqary3_ciss_performant.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 ea15d30b9a..5fae90f093 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3.c
@@ -300,8 +300,8 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
/*
* Allocate HBA transport structure
*/
- if ((cpq->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP)) ==
- NULL) {
+ 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);
@@ -322,7 +322,7 @@ cpqary3_attach(dev_info_t *dip, ddi_attach_cmd_t attach_cmd)
* Register the DMA attributes and the transport vectors
* of each instance of the HBA device.
*/
- if (scsi_hba_attach_setup(dip, &tmp_dma_attr, cpq->hba_tran,
+ 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);
@@ -474,14 +474,12 @@ cpqary3_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
* Return Values: None
*/
static void
-cpqary3_cleanup(cpqary3_t *cpqary3p)
+cpqary3_cleanup(cpqary3_t *cpq)
{
int8_t node_name[10];
clock_t cpqary3_lbolt;
uint32_t targ;
- ASSERT(cpqary3p != NULL);
-
/*
* Disable the NOE command
* Free the Command Memory Pool
@@ -498,76 +496,76 @@ cpqary3_cleanup(cpqary3_t *cpqary3p)
*/
if (status & CPQARY3_NOE_INIT_DONE) {
- if (CPQARY3_SUCCESS == cpqary3_disable_NOE_command(cpqary3p)) {
- mutex_enter(&cpqary3p->hw_mutex);
+ if (CPQARY3_SUCCESS == cpqary3_disable_NOE_command(cpq)) {
+ mutex_enter(&cpq->hw_mutex);
cpqary3_lbolt = ddi_get_lbolt();
if (DDI_FAILURE ==
- cv_timedwait_sig(&cpqary3p->cv_noe_wait,
- &cpqary3p->hw_mutex,
+ cv_timedwait_sig(&cpq->cv_noe_wait,
+ &cpq->hw_mutex,
cpqary3_lbolt + drv_usectohz(3000000))) {
cmn_err(CE_NOTE,
"CPQary3: Resume signal for disable NOE "
"command not received \n");
}
- mutex_exit(&cpqary3p->hw_mutex);
+ mutex_exit(&cpq->hw_mutex);
}
}
#endif
- cpqary3_interrupts_teardown(cpqary3p);
+ cpqary3_interrupts_teardown(cpq);
- if (cpqary3p->cpq_init_level & CPQARY3_INITLEVEL_PERIODIC) {
- ddi_periodic_delete(cpqary3p->cpq_periodic);
- cpqary3p->cpq_init_level &= ~CPQARY3_INITLEVEL_PERIODIC;
+ if (cpq->cpq_init_level & CPQARY3_INITLEVEL_PERIODIC) {
+ ddi_periodic_delete(cpq->cpq_periodic);
+ cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_PERIODIC;
}
- if (cpqary3p->cpq_init_level & CPQARY3_INITLEVEL_MINOR_NODE) {
+ if (cpq->cpq_init_level & CPQARY3_INITLEVEL_MINOR_NODE) {
(void) sprintf(node_name, "cpqary3%d",
- ddi_get_instance(cpqary3p->dip));
- ddi_remove_minor_node(cpqary3p->dip, node_name);
- cpqary3p->cpq_init_level &= ~CPQARY3_INITLEVEL_MINOR_NODE;
+ ddi_get_instance(cpq->dip));
+ ddi_remove_minor_node(cpq->dip, node_name);
+ cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_MINOR_NODE;
}
- if (cpqary3p->cpq_init_level & CPQARY3_INITLEVEL_HBA_ATTACH) {
- (void) scsi_hba_detach(cpqary3p->dip);
- cpqary3p->cpq_init_level &= ~CPQARY3_INITLEVEL_HBA_ATTACH;
+ if (cpq->cpq_init_level & CPQARY3_INITLEVEL_HBA_ATTACH) {
+ (void) scsi_hba_detach(cpq->dip);
+ cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_HBA_ATTACH;
}
- if (cpqary3p->cpq_init_level & CPQARY3_INITLEVEL_HBA_ALLOC) {
- scsi_hba_tran_free(cpqary3p->hba_tran);
- cpqary3p->cpq_init_level &= ~CPQARY3_INITLEVEL_HBA_ALLOC;
+ if (cpq->cpq_init_level & CPQARY3_INITLEVEL_HBA_ALLOC) {
+ scsi_hba_tran_free(cpq->cpq_hba_tran);
+ cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_HBA_ALLOC;
}
- if (cpqary3p->cpq_init_level & CPQARY3_INITLEVEL_BASIC) {
- mutex_enter(&cpqary3p->hw_mutex);
+ if (cpq->cpq_init_level & CPQARY3_INITLEVEL_BASIC) {
+ mutex_enter(&cpq->hw_mutex);
- cv_destroy(&cpqary3p->cv_abort_wait);
- cv_destroy(&cpqary3p->cv_flushcache_wait);
- cv_destroy(&cpqary3p->cv_noe_wait);
- cv_destroy(&cpqary3p->cv_immediate_wait);
- cv_destroy(&cpqary3p->cv_ioctl_wait);
+ cv_destroy(&cpq->cv_abort_wait);
+ cv_destroy(&cpq->cv_flushcache_wait);
+ cv_destroy(&cpq->cv_noe_wait);
+ cv_destroy(&cpq->cv_immediate_wait);
+ cv_destroy(&cpq->cv_ioctl_wait);
for (targ = 0; targ < CPQARY3_MAX_TGT; targ++) {
- if (cpqary3p->cpqary3_tgtp[targ] == NULL)
+ if (cpq->cpqary3_tgtp[targ] == NULL)
continue;
- kmem_free(cpqary3p->cpqary3_tgtp[targ],
+ kmem_free(cpq->cpqary3_tgtp[targ],
sizeof (cpqary3_tgt_t));
- cpqary3p->cpqary3_tgtp[targ] = NULL;
+ cpq->cpqary3_tgtp[targ] = NULL;
}
- mutex_exit(&cpqary3p->hw_mutex);
+ mutex_exit(&cpq->hw_mutex);
/*
* XXX avl_destroy, list_destroy, etc
*/
- cpqary3p->cpq_init_level &= ~CPQARY3_INITLEVEL_BASIC;
+ cpq->cpq_init_level &= ~CPQARY3_INITLEVEL_BASIC;
}
- cpqary3_device_teardown(cpqary3p);
+ cpqary3_device_teardown(cpq);
- VERIFY0(cpqary3p->cpq_init_level);
+ VERIFY0(cpq->cpq_init_level);
- ddi_soft_state_free(cpqary3_state, ddi_get_instance(cpqary3p->dip));
+ ddi_soft_state_free(cpqary3_state, ddi_get_instance(cpq->dip));
}
static int
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3.h b/usr/src/uts/common/io/cpqary3/cpqary3.h
index 3b902134f4..cc3535753f 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3.h
+++ b/usr/src/uts/common/io/cpqary3/cpqary3.h
@@ -28,6 +28,7 @@
#include <sys/cmn_err.h>
#include <sys/stat.h>
#include <sys/scsi/scsi.h>
+#include <sys/scsi/impl/spc3_types.h>
#include <sys/devops.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
@@ -43,45 +44,15 @@ extern "C" {
* Ioctl Commands
*/
#define CPQARY3_IOCTL_CMD ('c' << 4)
-#define CPQARY3_IOCTL_DRIVER_INFO CPQARY3_IOCTL_CMD | 0x01
-#define CPQARY3_IOCTL_CTLR_INFO CPQARY3_IOCTL_CMD | 0x02
#define CPQARY3_IOCTL_BMIC_PASS CPQARY3_IOCTL_CMD | 0x04
#define CPQARY3_IOCTL_SCSI_PASS CPQARY3_IOCTL_CMD | 0x08
-/* Driver Revision : Used in Ioctl */
-#define CPQARY3_MINOR_REV_NO 00
-#define CPQARY3_MAJOR_REV_NO 01
-#define CPQARY3_REV_DATE 05
-#define CPQARY3_REV_MONTH 04
-#define CPQARY3_REV_YEAR 2001
-
/* Some Useful definations */
#define CPQARY3_FAILURE 0
#define CPQARY3_SUCCESS 1
-#define CPQARY3_SENT 2
-#define CPQARY3_SUBMITTED 3
-#define CPQARY3_NO_SIG 4
-
-#define CPQARY3_TRUE 1
-#define CPQARY3_FALSE 0
#define CTLR_SCSI_ID 7
#define CPQARY3_LD_FAILED 1
-/*
- * Defines for cleanup in cpqary3_attach and cpqary3_detach.
- */
-#define CPQARY3_HBA_TRAN_ALLOC_DONE 0x0001
-#define CPQARY3_HBA_TRAN_ATTACH_DONE 0x0002
-#define CPQARY3_INTR_HDLR_SET 0x0008
-#define CPQARY3_CREATE_MINOR_NODE 0x0010
-#define CPQARY3_SOFTSTATE_ALLOC_DONE 0x0020
-#define CPQARY3_MUTEX_INIT_DONE 0x0040
-#define CPQARY3_TICK_TMOUT_REGD 0x0080
-#define CPQARY3_SW_INTR_HDLR_SET 0x0200
-#define CPQARY3_SW_MUTEX_INIT_DONE 0x0400
-#define CPQARY3_NOE_INIT_DONE 0x0800
-
-#define CPQARY3_CLEAN_ALL 0x0FFF
typedef enum cpqary3_init_level {
CPQARY3_INITLEVEL_BASIC = (0x1 << 0),
@@ -96,6 +67,14 @@ typedef enum cpqary3_init_level {
CPQARY3_INITLEVEL_HBA_ATTACH = (0x1 << 9),
} cpqary3_init_level_t;
+/*
+ * Commands issued to the controller carry a (generally 32-bit, though with two
+ * reserved signalling bits) identifying tag number. In order to avoid having
+ * the controller confuse us by double-reporting the completion of a particular
+ * tag, we try to reuse them as infrequently as possible. In practice, this
+ * means looping through a range of values. The minimum and maximum value are
+ * defined below.
+ */
#define CPQARY3_MIN_TAG_NUMBER 0x00000100
#define CPQARY3_MAX_TAG_NUMBER 0x0fffffff
@@ -119,7 +98,6 @@ typedef enum cpqary3_ctlr_mode {
/*
* Defines for Maximum and Default Settings.
*/
-
#define MAX_LOGDRV 64 /* Max supported Logical Drivers */
#define MAX_CTLRS 8 /* Max supported Controllers */
#define MAX_TAPE 28
@@ -127,11 +105,9 @@ typedef enum cpqary3_ctlr_mode {
* NOTE: When changing the below two entries, Max SG count in cpqary3_ciss.h
* should also be changed.
*/
-/* SG */
#define MAX_PERF_SG_CNT 64 /* Maximum S/G in performant mode */
#define CPQARY3_SG_CNT 30 /* minimum S/G in simple mode */
#define CPQARY3_PERF_SG_CNT 31 /* minimum S/G for performant mode */
-/* SG */
#define CPQARY3_MAX_TGT (MAX_LOGDRV + MAX_TAPE + 1)
@@ -180,11 +156,7 @@ typedef enum cpqary3_ctlr_mode {
((cpqary3_cmdpvt_t *)(CTLR2MEMLISTP(ctlr)->pool[tag]))
/* MACROS */
-#define CPQARY3_MIN(x, y) (x < y ? x : y)
#define CPQARY3_SWAP(val) ((val >> 8) | ((val & 0xff) << 8))
-#define RETURN_VOID_IF_NULL(x) if (NULL == x) return
-#define RETURN_NULL_IF_NULL(x) if (NULL == x) return (NULL)
-#define RETURN_FAILURE_IF_NULL(x) if (NULL == x) return (CPQARY3_FAILURE)
#define CPQARY3_SEC2HZ(x) drv_usectohz((x) * 1000000)
/*
@@ -202,10 +174,8 @@ typedef enum cpqary3_ctlr_mode {
ddi_get32((ctlr)->ct_handle, (uint32_t *)(regp))
#define DDI_PUT32(ctlr, regp, value) \
ddi_put32((ctlr)->ct_handle, (uint32_t *)(regp), (value))
- /* PERF */
#define DDI_PUT32_CP(ctlr, regp, value) \
ddi_put32((ctlr)->cp_handle, (uint32_t *)(regp), (value))
- /* PERF */
#define CPQARY3_BUFFER_ERROR_CLEAR 0x0 /* to be used with bioerror */
#define CPQARY3_DMA_NO_CALLBACK 0x0 /* to be used with DMA calls */
@@ -219,7 +189,7 @@ typedef enum cpqary3_ctlr_mode {
* Include the driver specific relevant header files here.
*/
#include "cpqary3_ciss.h"
-#include "cpqary3_q_mem.h"
+#include "cpqary3_mem.h"
#include "cpqary3_noe.h"
#include "cpqary3_scsi.h"
#include "cpqary3_ioctl.h"
@@ -227,10 +197,9 @@ typedef enum cpqary3_ctlr_mode {
/*
* Per Target Structure
*/
-
typedef struct cpqary3_target {
- uint32_t logical_id : 30; /* at most 64 : 63 drives + 1 CTLR */
- uint32_t type : 2; /* NONE, CTLR, LOGICAL DRIVE, TAPE */
+ uint32_t logical_id:30; /* at most 64 : 63 drives + 1 CTLR */
+ uint32_t type:2; /* CPQARY3_TARGET_* values */
PhysDevAddr_t PhysID;
union {
struct {
@@ -250,30 +219,17 @@ typedef struct cpqary3_target {
/*
- * Values for the type field in the Per Target Structure (above)
+ * Values for "type" on "cpqary3_tgt_t".
*/
#define CPQARY3_TARGET_NONE 0 /* No Device */
#define CPQARY3_TARGET_CTLR 1 /* Controller */
#define CPQARY3_TARGET_LOG_VOL 2 /* Logical Volume */
#define CPQARY3_TARGET_TAPE 3 /* SCSI Device - Tape */
+
/*
- * Index into PCI Configuration Registers for Base Address Registers(BAR)
- * Currently, only index for BAR 0 and BAR 1 are defined
+ * Interrupt status and mask values
*/
-#define INDEX_PCI_BASE0 1 /* offset 0x10 */
-#define INDEX_PCI_BASE1 2 /* offset 0x14 */
-
-/* Offset Values for IO interface from BAR 0 */
-#define INBOUND_DOORBELL 0x20
-#define OUTBOUND_LIST_STATUS 0x30
-#define OUTBOUND_INTERRUPT_MASK 0x34
-#define INBOUND_QUEUE 0x40
-#define OUTBOUND_QUEUE 0x44
-
-/* Offset Values for IO interface from BAR 1 */
-#define CONFIGURATION_TABLE 0x00
-
#define INTR_DISABLE_5300_MASK 0x00000008l
#define INTR_DISABLE_5I_MASK 0x00000004l
@@ -289,7 +245,6 @@ typedef struct cpqary3_target {
#define INTR_SIMPLE_MASK 0x00000008l
#define INTR_SIMPLE_LOCKUP_MASK 0x0000000cl
-
#define INTR_SIMPLE_5I_MASK 0x00000004l
#define INTR_SIMPLE_5I_LOCKUP_MASK 0x0000000cl
@@ -318,6 +273,7 @@ struct cpqary3 {
cpqary3_bd_t *cpq_board;
uint32_t cpq_host_support;
+ uint32_t cpq_bus_support;
uint32_t cpq_maxcmds;
uint32_t cpq_sg_cnt;
@@ -342,28 +298,16 @@ struct cpqary3 {
kcondvar_t cv_abort_wait;
kcondvar_t cv_ioctl_wait; /* Variable for ioctls */
- /*
- * CPQary3 driver related entities related to :
- * Hardware & Software Interrupts, Cookies & Mutex.
- * Timeout Handler
- * Driver Transport Layer/Structure
- * Database for the per-controller Command Memory Pool
- * Target List for the per-controller
- */
-
-
ddi_iblock_cookie_t cpq_int_hw_cookie;
ddi_iblock_cookie_t cpq_int_sw_cookie;
-
- kmutex_t hw_mutex; /* h/w mutex */
- kmutex_t sw_mutex; /* s/w mutex */
- ddi_softintr_t cpqary3_softintr_id; /* s/w intr identifier */
+ 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 *hba_tran; /* transport structure */
- cpqary3_cmdmemlist_t *cmdmemlistp; /* database - Memory Pool */
+ scsi_hba_tran_t *cpq_hba_tran;
cpqary3_tgt_t *cpqary3_tgtp[CPQARY3_MAX_TGT];
/*
@@ -399,8 +343,8 @@ struct cpqary3 {
ddi_acc_handle_t cpq_ct_handle;
uint32_t noe_support;
- uint8_t controller_lockup;
- uint8_t lockup_logged;
+ boolean_t controller_lockup;
+ boolean_t lockup_logged;
uint32_t poll_flag;
};
@@ -433,6 +377,8 @@ struct cpqary3_command {
boolean_t cpcm_free_on_complete;
boolean_t cpcm_used;
+ clock_t cpcm_time_submit;
+
cpqary3_synccmd_status_t cpcm_synccmd_status;
cpqary3_pkt_t *cpcm_private;
@@ -452,6 +398,12 @@ struct cpqary3_command {
uint32_t cpcm_pa_err; /* XXX wrong type */
};
+/*
+ * Commands issued internally to the driver (as opposed to by the HBA
+ * framework) generally require a buffer in which to assemble the command body,
+ * and for receiving the response from the controller. The following object
+ * tracks this (optional) extra buffer.
+ */
struct cpqary3_command_internal {
cpqary3_phyctg_t cpcmi_phyctg;
@@ -473,10 +425,7 @@ struct cpqary3_pkt {
struct scsi_pkt *scsi_cmd_pkt;
ddi_dma_win_t prev_winp;
ddi_dma_seg_t prev_segp;
- clock_t cmd_start_time;
- /* SG */
ddi_dma_cookie_t cmd_dmacookies[MAX_PERF_SG_CNT];
- /* SG */
uint32_t cmd_ncookies;
uint32_t cmd_cookie;
uint32_t cmd_cookiecnt;
@@ -526,19 +475,20 @@ void cpqary3_periodic(void *);
int cpqary3_flush_cache(cpqary3_t *);
void cpqary3_intr_onoff(cpqary3_t *, uint8_t);
void cpqary3_lockup_intr_onoff(cpqary3_t *, uint8_t);
+#if 0
uint8_t cpqary3_disable_NOE_command(cpqary3_t *);
uint8_t cpqary3_send_NOE_command(cpqary3_t *, cpqary3_cmdpvt_t *, uint8_t);
+void cpqary3_NOE_handler(cpqary3_cmdpvt_t *);
+void cpqary3_noe_complete(cpqary3_cmdpvt_t *cpqary3_cmdpvtp);
+#endif
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 *);
-void cpqary3_cmdlist_release(cpqary3_cmdpvt_t *, uint8_t);
int cpqary3_submit(cpqary3_t *, cpqary3_command_t *);
-cpqary3_cmdpvt_t *cpqary3_cmdlist_occupy(cpqary3_t *);
-void cpqary3_NOE_handler(cpqary3_cmdpvt_t *);
-int cpqary3_retrieve(cpqary3_t *);
+int cpqary3_retrieve(cpqary3_t *, uint32_t, boolean_t *);
void cpqary3_retrieve_simple(cpqary3_t *, uint32_t, boolean_t *);
void cpqary3_retrieve_performant(cpqary3_t *, uint32_t, boolean_t *);
int cpqary3_target_geometry(struct scsi_address *);
@@ -546,14 +496,17 @@ int8_t cpqary3_detect_target_geometry(cpqary3_t *);
uint8_t cpqary3_send_abortcmd(cpqary3_t *, uint16_t, CommandList_t *);
void cpqary3_memfini(cpqary3_t *, uint8_t);
int16_t cpqary3_meminit(cpqary3_t *);
-void cpqary3_noe_complete(cpqary3_cmdpvt_t *cpqary3_cmdpvtp);
-uint8_t cpqary3_poll_retrieve(cpqary3_t *cpqary3p, uint32_t poll_tag);
uint8_t cpqary3_build_cmdlist(cpqary3_command_t *cpqary3_cmdpvtp, uint32_t tid);
void cpqary3_lockup_check(cpqary3_t *);
+void cpqary3_oscmd_complete(cpqary3_command_t *);
/*
* Memory management.
*/
+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 *,
@@ -575,6 +528,7 @@ uint32_t cpqary3_isr_hw_simple(caddr_t);
uint32_t cpqary3_isr_sw_simple(caddr_t);
uint32_t cpqary3_isr_hw_performant(caddr_t);
uint32_t cpqary3_isr_sw_performant(caddr_t);
+void cpqary3_trigger_sw_isr(cpqary3_t *);
int cpqary3_interrupts_setup(cpqary3_t *);
void cpqary3_interrupts_teardown(cpqary3_t *);
@@ -583,14 +537,21 @@ void cpqary3_interrupts_teardown(cpqary3_t *);
*/
int cpqary3_ctlr_init(cpqary3_t *);
int cpqary3_ctlr_wait_for_state(cpqary3_t *, cpqary3_wait_state_t);
+int cpqary3_ctlr_init_simple(cpqary3_t *);
+int cpqary3_cfgtbl_flush(cpqary3_t *);
+int cpqary3_cfgtbl_transport_has_support(cpqary3_t *, int);
+void cpqary3_cfgtbl_transport_set(cpqary3_t *, int);
+int cpqary3_cfgtbl_transport_confirm(cpqary3_t *, int);
+uint32_t cpqary3_ctlr_get_cmdsoutmax(cpqary3_t *);
/*
* Command object management.
*/
-cpqary3_command_t *cpqary3_command_alloc(cpqary3_t *);
+cpqary3_command_t *cpqary3_command_alloc(cpqary3_t *, cpqary3_command_type_t);
cpqary3_command_internal_t *cpqary3_command_internal_alloc(cpqary3_t *, size_t);
void cpqary3_command_free(cpqary3_command_t *);
cpqary3_command_t *cpqary3_lookup_inflight(cpqary3_t *, uint32_t);
+void cpqary3_command_reuse(cpqary3_command_t *);
/*
* Device management routines.
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_ciss.c b/usr/src/uts/common/io/cpqary3/cpqary3_ciss.c
new file mode 100644
index 0000000000..1e21cd8858
--- /dev/null
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_ciss.c
@@ -0,0 +1,445 @@
+/*
+ * 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 (C) 2013 Hewlett-Packard Development Company, L.P.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * This module contains routines that program the controller. All
+ * operations viz., initialization of controller, submision &
+ * retrieval of commands, enabling & disabling of interrupts,
+ * checking interrupt status are performed here.
+ */
+
+#include <sys/sdt.h>
+#include "cpqary3.h"
+
+/*
+ * XXX
+ */
+int
+cpqary3_retrieve(cpqary3_t *cpq, uint32_t want_tag, boolean_t *found)
+{
+ VERIFY(MUTEX_HELD(&cpq->hw_mutex));
+ VERIFY(MUTEX_HELD(&cpq->sw_mutex));
+
+ switch (cpq->cpq_ctlr_mode) {
+ case CPQARY3_CTLR_MODE_SIMPLE:
+ cpqary3_retrieve_simple(cpq, want_tag, found);
+ return (DDI_SUCCESS);
+
+ case CPQARY3_CTLR_MODE_PERFORMANT:
+ cpqary3_retrieve_performant(cpq, want_tag, found);
+ return (DDI_SUCCESS);
+
+ case CPQARY3_CTLR_MODE_UNKNOWN:
+ break;
+ }
+
+ panic("unknown controller mode");
+}
+
+int
+cpqary3_submit(cpqary3_t *cpq, cpqary3_command_t *cpcm)
+{
+ VERIFY(MUTEX_HELD(&cpq->hw_mutex));
+
+ /*
+ * If a controller lockup has been detected, reject new command
+ * submissions.
+ */
+ if (cpq->controller_lockup) {
+ return (EIO);
+ }
+
+ /*
+ * 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;
+
+ /*
+ * Insert this command into the inflight AVL.
+ */
+ avl_index_t where;
+ if (avl_find(&cpq->cpq_inflight, cpcm, &where) != NULL) {
+ dev_err(cpq->dip, CE_PANIC, "duplicate submit tag %x",
+ cpcm->cpcm_tag);
+ }
+ avl_insert(&cpq->cpq_inflight, cpcm, where);
+
+ VERIFY(cpcm->cpcm_inflight == B_FALSE);
+ cpcm->cpcm_inflight = B_TRUE;
+ 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);
+ break;
+
+ case CPQARY3_CTLR_MODE_PERFORMANT:
+ /*
+ * XXX The driver always uses the 0th block fetch count always
+ *
+ * (NB: from spec, the 0x1 here sets "pull from host memory"
+ * mode, and the 0 represents "pull just one command record"
+ */
+ cpqary3_put32(cpq, CISS_I2O_INBOUND_POST_Q,
+ cpcm->cpcm_pa_cmd | 0 | 0x1);
+ break;
+
+ default:
+ panic("unknown controller mode");
+ }
+
+ return (0);
+}
+
+
+/*
+ * Function : cpqary3_intr_onoff
+ * Description : This routine enables/disables the HBA interrupt.
+ * Called By : cpqary3_attach(), ry3_handle_flag_nointr(),
+ * cpqary3_tick_hdlr(), cpqary3_init_ctlr_resource()
+ * Parameters : per-controller, flag stating enable/disable
+ * Calls : None
+ * Return Values: None
+ */
+void
+cpqary3_intr_onoff(cpqary3_t *cpq, uint8_t flag)
+{
+ /*
+ * Read the Interrupt Mask Register.
+ */
+ uint32_t imr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_MASK);
+
+ VERIFY(flag == CPQARY3_INTR_ENABLE || flag == CPQARY3_INTR_DISABLE);
+
+ switch (cpq->cpq_ctlr_mode) {
+ case CPQARY3_CTLR_MODE_SIMPLE:
+ if (flag == CPQARY3_INTR_ENABLE) {
+ imr &= ~INTR_SIMPLE_MASK;
+ } else {
+ imr |= INTR_SIMPLE_MASK;
+ }
+ break;
+
+ default:
+ if (flag == CPQARY3_INTR_ENABLE) {
+ imr &= ~cpq->cpq_board->bd_intrmask;
+ } else {
+ imr |= cpq->cpq_board->bd_intrmask;
+ }
+ break;
+ }
+
+ cpqary3_put32(cpq, CISS_I2O_INTERRUPT_MASK, imr);
+}
+
+/*
+ * Function : cpqary3_lockup_intr_onoff
+ * Description : This routine enables/disables the lockup interrupt.
+ * Called By : cpqary3_attach(), cpqary3_handle_flag_nointr(),
+ * cpqary3_tick_hdlr(), cpqary3_hw_isr,
+ * cpqary3_init_ctlr_resource()
+ * Parameters : per-controller, flag stating enable/disable
+ * Calls : None
+ * Return Values: None
+ */
+void
+cpqary3_lockup_intr_onoff(cpqary3_t *cpq, uint8_t flag)
+{
+ /*
+ * Read the Interrupt Mask Register.
+ */
+ uint32_t imr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_MASK);
+
+ /*
+ * Enable or disable firmware lockup interrupts from the controller
+ * based on the flag.
+ */
+ if (flag == CPQARY3_LOCKUP_INTR_ENABLE) {
+ imr &= ~cpq->cpq_board->bd_lockup_intrmask;
+ } else {
+ VERIFY(flag == CPQARY3_LOCKUP_INTR_DISABLE);
+
+ imr |= cpq->cpq_board->bd_lockup_intrmask;
+ }
+
+ 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
+ * number of seconds, acknowledge this by clearing the bit.
+ *
+ * If successful, return DDI_SUCCESS. If the controller takes too long to
+ * acknowledge, return DDI_FAILURE.
+ */
+int
+cpqary3_cfgtbl_flush(cpqary3_t *cpq)
+{
+ /*
+ * Read the current value of the Inbound Doorbell Register.
+ */
+ uint32_t idr = cpqary3_get32(cpq, CISS_I2O_INBOUND_DOORBELL);
+
+ /*
+ * Signal the Configuration Table change to the controller.
+ */
+ idr |= CISS_IDR_BIT_CFGTBL_CHANGE;
+ cpqary3_put32(cpq, CISS_I2O_INBOUND_DOORBELL, idr);
+
+ /*
+ * Wait for the controller to acknowledge the change.
+ */
+ for (unsigned i = 0; i < CISS_INIT_TIME; i++) {
+ idr = cpqary3_get32(cpq, CISS_I2O_INBOUND_DOORBELL);
+
+ if ((idr & CISS_IDR_BIT_CFGTBL_CHANGE) == 0) {
+ return (DDI_SUCCESS);
+ }
+
+ /*
+ * Wait for one second before trying again.
+ */
+ delay(drv_usectohz(1000000));
+ }
+
+ dev_err(cpq->dip, CE_WARN, "time out expired before controller "
+ "configuration completed");
+ return (DDI_FAILURE);
+}
+
+int
+cpqary3_cfgtbl_transport_has_support(cpqary3_t *cpq, int xport)
+{
+ VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE ||
+ xport == CISS_CFGTBL_XPORT_PERFORMANT);
+
+ /*
+ * Read the current value of the TransportSupport field in the
+ * Configuration Table.
+ */
+ uint32_t xport_active = ddi_get32(cpq->cpq_ct_handle,
+ &cpq->cpq_ct->TransportSupport);
+
+ /*
+ * Check that the desired transport method is supported by the
+ * controller:
+ */
+ if ((xport_active & xport) == 0) {
+ dev_err(cpq->dip, CE_WARN, "controller does not support "
+ "method \"%s\"", xport == CISS_CFGTBL_XPORT_SIMPLE ?
+ "simple" : "performant");
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+void
+cpqary3_cfgtbl_transport_set(cpqary3_t *cpq, int xport)
+{
+ VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE ||
+ xport == CISS_CFGTBL_XPORT_PERFORMANT);
+
+ ddi_put32(cpq->cpq_ct_handle,
+ &cpq->cpq_ct->HostWrite.TransportRequest, xport);
+}
+
+int
+cpqary3_cfgtbl_transport_confirm(cpqary3_t *cpq, int xport)
+{
+ VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE ||
+ xport == CISS_CFGTBL_XPORT_PERFORMANT);
+
+ /*
+ * Read the current value of the TransportActive field in the
+ * Configuration Table.
+ */
+ uint32_t xport_active = ddi_get32(cpq->cpq_ct_handle,
+ &cpq->cpq_ct->TransportActive);
+
+ /*
+ * Check that the desired transport method is now active:
+ */
+ if ((xport_active & xport) == 0) {
+ dev_err(cpq->dip, CE_WARN, "failed to enable transport "
+ "method \"%s\"", xport == CISS_CFGTBL_XPORT_SIMPLE ?
+ "simple" : "performant");
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * Ensure that the controller is now ready to accept commands.
+ */
+ if ((xport_active & CISS_CFGTBL_READY_FOR_COMMANDS) == 0) {
+ dev_err(cpq->dip, CE_WARN, "controller not ready to "
+ "accept commands");
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
+
+uint32_t
+cpqary3_ctlr_get_cmdsoutmax(cpqary3_t *cpq)
+{
+ uint32_t val;
+
+ if (cpq->cpq_ctlr_mode == CPQARY3_CTLR_MODE_PERFORMANT) {
+ if ((val = ddi_get32(cpq->cpq_ct_handle,
+ &cpq->cpq_ct->MaxPerfModeCmdsOutMax)) != 0) {
+ return (val);
+ }
+ }
+
+ return (ddi_get32(cpq->cpq_ct_handle, &cpq->cpq_ct->CmdsOutMax));
+}
+
+static uint32_t
+cpqary3_ctlr_get_hostdrvsup(cpqary3_t *cpq)
+{
+ if (!cpq->cpq_board->bd_is_e200 && !cpq->cpq_board->bd_is_ssll) {
+ uint32_t val = ddi_get32(cpq->cpq_ct_handle,
+ &cpq->cpq_ct->HostDrvrSupport);
+
+ /*
+ * XXX This is "bit 2" in the "Host Driver Specific Support"
+ * field of the Configuration Table. According to the CISS
+ * spec, this is "Interrupt Host upon Controller Lockup"
+ * Enable.
+ *
+ * It's not clear why we _set_ this bit, but then it's not yet
+ * clear how this table entry is even supposed to work.
+ */
+ val |= 0x04;
+
+ ddi_put32(cpq->cpq_ct_handle, &cpq->cpq_ct->HostDrvrSupport,
+ val);
+ }
+
+ return (ddi_get32(cpq->cpq_ct_handle, &cpq->cpq_ct->HostDrvrSupport));
+}
+
+int
+cpqary3_ctlr_init(cpqary3_t *cpq)
+{
+ uint8_t signature[4] = { 'C', 'I', 'S', 'S' };
+ CfgTable_t *ctp = cpq->cpq_ct;
+ int e;
+
+ if ((e = cpqary3_ctlr_wait_for_state(cpq,
+ CPQARY3_WAIT_STATE_READY) != DDI_SUCCESS)) {
+ return (e);
+ }
+
+ /*
+ * The configuration table contains an ASCII signature ("CISS") which
+ * should be checked as we initialise the controller.
+ * See: "9.1 Configuration Table" in CISS Specification.
+ */
+ for (unsigned i = 0; i < 4; i++) {
+ if (ddi_get8(cpq->cpq_ct_handle, &cpq->cpq_ct->Signature[i]) !=
+ signature[i]) {
+ dev_err(cpq->dip, CE_WARN, "invalid signature "
+ "detected");
+ return (DDI_FAILURE);
+ }
+ }
+
+ if ((e = cpqary3_ctlr_init_simple(cpq)) != 0) {
+ return (e);
+ }
+
+ /*
+ * Save some common feature support bitfields.
+ */
+ cpq->cpq_host_support = cpqary3_ctlr_get_hostdrvsup(cpq);
+ cpq->cpq_bus_support = ddi_get32(cpq->cpq_ct_handle,
+ &cpq->cpq_ct->BusTypes);
+
+ /*
+ * Read initial controller heartbeat value and mark the current
+ * reading time.
+ */
+ cpq->cpq_last_heartbeat = ddi_get32(cpq->cpq_ct_handle,
+ &cpq->cpq_ct->HeartBeat);
+ cpq->cpq_last_heartbeat_lbolt = ddi_get_lbolt();
+
+ return (0);
+}
+
+int
+cpqary3_ctlr_wait_for_state(cpqary3_t *cpq, cpqary3_wait_state_t state)
+{
+ VERIFY(state == CPQARY3_WAIT_STATE_READY ||
+ state == CPQARY3_WAIT_STATE_UNREADY);
+
+ /*
+ * Read from the Scratchpad Register until the expected ready signature
+ * is detected. This behaviour is not described in the CISS
+ * specification.
+ *
+ * If the device is not in the desired state immediately, sleep for a
+ * second and try again. If the device has not become ready in 300
+ * seconds, give up.
+ */
+ for (unsigned i = 0; i < CPQARY3_WAIT_DELAY_SECONDS; i++) {
+ uint32_t spr = cpqary3_get32(cpq, CISS_I2O_SCRATCHPAD);
+
+ switch (state) {
+ case CPQARY3_WAIT_STATE_READY:
+ if (spr == CISS_SCRATCHPAD_INITIALISED) {
+ return (DDI_SUCCESS);
+ }
+ break;
+
+ case CPQARY3_WAIT_STATE_UNREADY:
+ if (spr != CISS_SCRATCHPAD_INITIALISED) {
+ return (DDI_SUCCESS);
+ }
+ break;
+ }
+
+ /*
+ * Wait for a second and try again.
+ */
+ delay(drv_usectohz(1000000));
+ }
+
+ dev_err(cpq->dip, CE_WARN, "time out waiting for controller "
+ "to enter state \"%s\"", state == CPQARY3_WAIT_STATE_READY ?
+ "ready": "unready");
+ return (DDI_FAILURE);
+}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_ciss_performant.c b/usr/src/uts/common/io/cpqary3/cpqary3_ciss_performant.c
new file mode 100644
index 0000000000..d70dcb7696
--- /dev/null
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_ciss_performant.c
@@ -0,0 +1,320 @@
+/*
+ * 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"
+
+/*
+ * Function : cpqary3_check_perf_ctlr_intr
+ * Description : This routine determines if the
+ * controller did interrupt.
+ * Called By : cpqary3_hw_isr()
+ * Parameters : per-controller
+ * Calls : None
+ * Return Values: SUCCESS : This controller did interrupt.
+ * FAILURE : It did not.
+ */
+uint8_t
+cpqary3_check_perf_ctlr_intr(cpqary3_t *cpq)
+{
+ /*
+ * Read the Interrupt Status Register and
+ * if bit 3 is set, it indicates that we have completed commands
+ * in the controller
+ * XXX _which_ bit?
+ */
+ if ((cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS) & 0x1) != 0) {
+ return (CPQARY3_SUCCESS);
+ }
+
+ return (CPQARY3_FAILURE);
+}
+
+/*
+ * Function : cpqary3_check_perf_e200_intr
+ * Description : This routine determines if the controller
+ * did interrupt.
+ * Called By : cpqary3_hw_isr()
+ * Parameters : per-controller
+ * Calls : None
+ * Return Values: SUCCESS : This controller did interrupt.
+ * FAILURE : It did not.
+ */
+uint8_t
+cpqary3_check_perf_e200_intr(cpqary3_t *cpq)
+{
+ /*
+ * Read the Interrupt Status Register and
+ * if bit 3 is set, it indicates that we have completed commands
+ * in the controller
+ */
+ if ((cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS) & 0x4) != 0) {
+ return (CPQARY3_SUCCESS);
+ }
+
+ return (CPQARY3_FAILURE);
+}
+
+uint_t
+cpqary3_isr_hw_performant(caddr_t arg)
+{
+ cpqary3_t *cpq = (cpqary3_t *)arg;
+ uint32_t isr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS);
+
+ if (isr == 0) {
+ /*
+ * Check to see if the firmware has come to rest. If it has,
+ * this routine will panic the system.
+ */
+ cpqary3_lockup_check(cpq);
+
+ return (DDI_INTR_UNCLAIMED);
+ }
+
+ uint32_t odr = cpqary3_get32(cpq, CISS_I2O_OUTBOUND_DOORBELL_STATUS);
+ if ((odr & 0x1) != 0) {
+ uint32_t odr_cl = cpqary3_get32(cpq,
+ CISS_I2O_OUTBOUND_DOORBELL_CLEAR);
+
+ odr_cl |= 0x1;
+ cpqary3_put32(cpq, CISS_I2O_OUTBOUND_DOORBELL_CLEAR, odr_cl);
+
+ /*
+ * Read the status register again to ensure the write to clear
+ * is flushed to the controller.
+ */
+ (void) cpqary3_get32(cpq, CISS_I2O_OUTBOUND_DOORBELL_STATUS);
+ }
+
+ cpqary3_trigger_sw_isr(cpq);
+
+ return (DDI_INTR_CLAIMED);
+}
+
+uint_t
+cpqary3_isr_sw_performant(caddr_t arg)
+{
+ cpqary3_t *cpq = (cpqary3_t *)arg;
+
+ /*
+ * Confirm that the hardware interrupt routine scheduled this
+ * software interrupt.
+ */
+ 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_performant(cpq, 0, NULL);
+
+ cpq->cpq_swintr_flag = B_FALSE;
+ mutex_exit(&cpq->hw_mutex);
+ mutex_exit(&cpq->sw_mutex);
+ return (DDI_INTR_CLAIMED);
+}
+
+void
+cpqary3_retrieve_performant(cpqary3_t *cpq, uint32_t watchfor, boolean_t *found)
+{
+ cpqary3_replyq_t *cprq = &cpq->cpq_replyq;
+
+ for (;;) {
+ uint32_t ent = cprq->cprq_tags[2 * cprq->cprq_read_index];
+ uint32_t tag = ent >> 2; /* XXX */
+ cpqary3_command_t *cpcm;
+
+ if ((ent & 0x1) != cprq->cprq_cycle_indicator) {
+ break;
+ }
+
+ if ((cpcm = cpqary3_lookup_inflight(cpq, tag)) == NULL) {
+ dev_err(cpq->dip, CE_WARN, "spurious tag %x", tag);
+ continue;
+ }
+
+ avl_remove(&cpq->cpq_inflight, cpcm);
+ cpcm->cpcm_inflight = B_FALSE;
+ cpcm->cpcm_error = (ent & (0x1 << 1)) != 0;
+
+ if (found != NULL && cpcm->cpcm_tag == watchfor) {
+ *found = B_TRUE;
+ }
+
+ cpcm->cpcm_complete(cpcm);
+
+ if (++cprq->cprq_read_index >= cprq->cprq_ntags) {
+ cprq->cprq_read_index = 0;
+ if (cprq->cprq_cycle_indicator == 1) {
+ cprq->cprq_cycle_indicator = 0;
+ } else {
+ cprq->cprq_cycle_indicator = 1;
+ }
+ }
+ }
+}
+
+/*
+ * XXX
+ */
+#if 0
+static int
+cpqary3_ctlr_init_performant(cpqary3_t *cpq)
+{
+ cpqary3_replyq_t *cprq = &cpq->cpq_replyq;
+
+ VERIFY(cpq->cpq_ctlr_mode == CPQARY3_CTLR_MODE_UNKNOWN);
+
+ if (cpqary3_cfgtbl_transport_has_support(cpq,
+ CISS_CFGTBL_XPORT_PERFORMANT) != DDI_SUCCESS) {
+ return (ENOTTY);
+ }
+ cpq->cpq_ctlr_mode = CPQARY3_CTLR_MODE_PERFORMANT;
+
+ if ((cpq->ctlr_maxcmds = cpqary3_ctlr_get_cmdsoutmax(cpq)) == 0) {
+ dev_err(cpq->dip, CE_WARN, "maximum outstanding commands set "
+ "to zero");
+ return (EPROTO);
+ }
+
+ /*
+ * Initialize the Performant Method Transport Method Table.
+ *
+ * XXX "Number of 4-byte nodes in each reply queue. Same for all reply
+ * queues." Here we are passing the number of COMMANDS, which is the
+ * number of 8-byte nodes...
+ */
+ DDI_PUT32_CP(cpq, &cpq->cp->ReplyQSize, cpq->ctlr_maxcmds);
+ DDI_PUT32_CP(cpq, &cpq->cp->ReplyQCount, 1);
+ DDI_PUT32_CP(cpq, &cpq->cp->ReplyQCntrAddrLow32, 0);
+ DDI_PUT32_CP(cpq, &cpq->cp->ReplyQCntrAddrHigh32, 0);
+
+ /*
+ * Each slot in the Reply Queue consists of two 4 byte integer
+ * fields.
+ */
+ size_t qsize = cpq->ctlr_maxcmds * 2 * sizeof (uint32_t);
+
+ if ((cprq->cprq_tags = (void *)cpqary3_alloc_phyctgs_mem(cpq, qsize,
+ &cprq->cprq_tags_pa, &cprq->cprq_phyctg)) == NULL) {
+ dev_err(cpq->dip, CE_WARN, "could not allocate replyq");
+ return (ENOMEM);
+ }
+
+ bzero(cprq->cprq_tags, qsize);
+ cprq->cprq_ntags = cpq->ctlr_maxcmds;
+ cprq->cprq_cycle_indicator = 1;
+ cprq->cprq_read_index = 0;
+
+ DDI_PUT32_CP(cpq, &cpq->cp->ReplyQAddr0Low32, cprq->cprq_tags_pa);
+ DDI_PUT32_CP(cpq, &cpq->cp->ReplyQAddr0High32, 0);
+
+ max_blk_fetch_cnt = DDI_GET32(cpq, &ctp->MaxBlockFetchCount);
+
+ /*
+ * For non-proton FW controllers, max_blk_fetch_count is not
+ * implemented in the firmware
+ */
+
+ /*
+ * When blk fetch count is 0, FW auto fetches 564 bytes
+ * corresponding to an optimal S/G of 31
+ */
+ if (max_blk_fetch_cnt == 0) {
+ BlockFetchCnt[0] = 35;
+ } else {
+ /*
+ * With MAX_PERF_SG_CNT set to 64, block fetch count
+ * is got by:(sizeof (CommandList_t) + 15)/16
+ */
+ if (max_blk_fetch_cnt > 68)
+ BlockFetchCnt[0] = 68;
+ else
+ BlockFetchCnt[0] = max_blk_fetch_cnt;
+ }
+
+ DDI_PUT32_CP(cpq, &perf_cfg->BlockFetchCnt[0], BlockFetchCnt[0]);
+
+ /*
+ * Set the Transport Method and flush the changes to the
+ * Configuration Table.
+ */
+ cpqary3_cfgtbl_transport_set(cpq, CISS_CFGTBL_XPORT_PERFORMANT);
+ if (cpqary3_cfgtbl_flush(cpq) != DDI_SUCCESS) {
+ return (EPROTO);
+ }
+
+ if (cpqary3_cfgtbl_transport_confirm(cpq,
+ CISS_CFGTBL_XPORT_PERFORMANT) != DDI_SUCCESS) {
+ return (EPROTO);
+ }
+
+ /*
+ * XXX It's not clear why we check this a second time, but the original
+ * driver did.
+ */
+ uint32_t check_again = cpqary3_ctlr_get_cmdsoutmax(cpq);
+ if (check_again != cpq->ctlr_maxcmds) {
+ dev_err(cpq->dip, CE_WARN, "maximum outstanding commands "
+ "changed during initialisation (was %u, now %u)",
+ cpq->ctlr_maxcmds, check_again);
+ return (EPROTO);
+ }
+
+ /* SG */
+ max_sg_cnt = DDI_GET32(cpq, &ctp->MaxSGElements);
+ max_blk_fetch_cnt = DDI_GET32(cpq, &ctp->MaxBlockFetchCount);
+
+ /* 32 byte aligned - size_of_cmdlist */
+ size_of_cmdlist = ((sizeof (CommandList_t) + 31) / 32) * 32;
+ size_of_HRE = size_of_cmdlist -
+ (sizeof (SGDescriptor_t) * CISS_MAXSGENTRIES);
+
+ if ((max_blk_fetch_cnt == 0) || (max_sg_cnt == 0) ||
+ ((max_blk_fetch_cnt * 16) <= size_of_HRE)) {
+ cpq->sg_cnt = CPQARY3_PERF_SG_CNT;
+ } else {
+ /*
+ * Get the optimal_sg - no of the SG's that will fit
+ * into the max_blk_fetch_cnt
+ */
+
+ optimal_sg_size = (max_blk_fetch_cnt * 16) - size_of_HRE;
+
+ if (optimal_sg_size < sizeof (SGDescriptor_t)) {
+ optimal_sg = CPQARY3_PERF_SG_CNT;
+ } else {
+ optimal_sg = optimal_sg_size / sizeof (SGDescriptor_t);
+ }
+
+ cpq->sg_cnt = MIN(max_sg_cnt, optimal_sg);
+
+ if (cpq->sg_cnt > MAX_PERF_SG_CNT) {
+ cpq->sg_cnt = MAX_PERF_SG_CNT;
+ }
+ }
+
+ /* SG */
+
+ /*
+ * Zero the Upper 32 Address in the Controller
+ */
+
+ DDI_PUT32(cpq, &ctp->HostWrite.Upper32Addr, 0x00000000);
+
+ return (0);
+}
+#endif
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c b/usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c
new file mode 100644
index 0000000000..0667496912
--- /dev/null
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c
@@ -0,0 +1,194 @@
+/*
+ * 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"
+
+boolean_t
+cpqary3_check_simple_ctlr_intr(cpqary3_t *cpq)
+{
+ uint32_t intr_pending_mask = cpq->cpq_board->bd_intrpendmask;
+ uint32_t isr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS);
+
+ /*
+ * Read the Interrupt Status Register and
+ * if bit 3 is set, it indicates that we have completed commands
+ * in the controller
+ */
+ 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,
+ * this routine will panic the system.
+ */
+ cpqary3_lockup_check(cpq);
+
+ mutex_exit(&cpq->hw_mutex);
+ return (DDI_INTR_UNCLAIMED);
+ }
+
+ /*
+ * Disable interrupts until the soft interrupt handler has had a chance
+ * to read and process replies.
+ */
+ cpqary3_intr_onoff(cpq, CPQARY3_INTR_DISABLE);
+
+ 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;
+
+ /*
+ * Confirm that the hardware interrupt routine scheduled this
+ * software interrupt.
+ */
+ 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);
+
+ /*
+ * Unmask the controller inbound data interrupt.
+ */
+ if (!cpq->cpq_intr_off) {
+ cpqary3_intr_onoff(cpq, CPQARY3_INTR_ENABLE);
+ }
+
+ cpq->cpq_swintr_flag = B_FALSE;
+ mutex_exit(&cpq->hw_mutex);
+ mutex_exit(&cpq->sw_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)
+{
+ uint32_t opq;
+ uint32_t none = 0xffffffff;
+
+ VERIFY(MUTEX_HELD(&cpq->hw_mutex));
+ VERIFY(MUTEX_HELD(&cpq->sw_mutex));
+
+ while ((opq = cpqary3_get32(cpq, CISS_I2O_OUTBOUND_POST_Q)) != none) {
+ 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);
+ continue;
+ }
+
+ 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;
+ }
+
+ mutex_exit(&cpq->hw_mutex);
+ cpcm->cpcm_complete(cpcm);
+ mutex_enter(&cpq->hw_mutex);
+ }
+}
+
+int
+cpqary3_ctlr_init_simple(cpqary3_t *cpq)
+{
+ VERIFY(cpq->cpq_ctlr_mode == CPQARY3_CTLR_MODE_UNKNOWN);
+
+ if (cpqary3_cfgtbl_transport_has_support(cpq,
+ CISS_CFGTBL_XPORT_SIMPLE) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+ cpq->cpq_ctlr_mode = CPQARY3_CTLR_MODE_SIMPLE;
+
+ /*
+ * Disable device interrupts while we are setting up.
+ */
+ cpqary3_intr_onoff(cpq, CPQARY3_INTR_DISABLE);
+
+ if ((cpq->cpq_maxcmds = cpqary3_ctlr_get_cmdsoutmax(cpq)) == 0) {
+ dev_err(cpq->dip, CE_WARN, "maximum outstanding commands set "
+ "to zero");
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * XXX ?
+ */
+ cpq->cpq_sg_cnt = CPQARY3_SG_CNT;
+
+ /*
+ * Zero the upper 32 bits of the address in the Controller.
+ */
+ ddi_put32(cpq->cpq_ct_handle, &cpq->cpq_ct->HostWrite.Upper32Addr, 0);
+
+ /*
+ * Set the Transport Method and flush the changes to the
+ * Configuration Table.
+ */
+ cpqary3_cfgtbl_transport_set(cpq, CISS_CFGTBL_XPORT_SIMPLE);
+ if (cpqary3_cfgtbl_flush(cpq) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ if (cpqary3_cfgtbl_transport_confirm(cpq,
+ CISS_CFGTBL_XPORT_SIMPLE) != DDI_SUCCESS) {
+ return (DDI_FAILURE);
+ }
+
+ /*
+ * XXX It's not clear why we check this a second time, but the original
+ * driver did.
+ */
+ uint32_t check_again = cpqary3_ctlr_get_cmdsoutmax(cpq);
+ if (check_again != cpq->cpq_maxcmds) {
+ dev_err(cpq->dip, CE_WARN, "maximum outstanding commands "
+ "changed during initialisation (was %u, now %u)",
+ cpq->cpq_maxcmds, check_again);
+ return (DDI_FAILURE);
+ }
+
+ return (DDI_SUCCESS);
+}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_commands.c b/usr/src/uts/common/io/cpqary3/cpqary3_commands.c
new file mode 100644
index 0000000000..8c600383bc
--- /dev/null
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_commands.c
@@ -0,0 +1,203 @@
+/*
+ * 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 size_t
+cpqary3_round_up(size_t offset)
+{
+ size_t gran = 0x20;
+
+ return ((offset + (gran - 1)) & ~(gran - 1));
+}
+
+cpqary3_command_t *
+cpqary3_command_alloc(cpqary3_t *cpq, cpqary3_command_type_t type)
+{
+ cpqary3_command_t *cpcm;
+
+ if ((cpcm = kmem_zalloc(sizeof (*cpcm), KM_NOSLEEP)) == NULL) {
+ return (NULL);
+ }
+
+ cpcm->cpcm_ctlr = cpq;
+
+ 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);
+
+ size_t contig_size = 0;
+ size_t errorinfo_offset;
+
+ contig_size += cpqary3_round_up(sizeof (CommandList_t));
+
+ errorinfo_offset = contig_size;
+ contig_size += cpqary3_round_up(sizeof (ErrorInfo_t));
+
+ /*
+ * Allocate physmem for CommandList_t (cpcm_va_cmd), and ErrorInfo_t
+ * (cpcm_va_err).
+ * XXX
+ *
+ * - 0x20 aligned CommandList_t
+ * header
+ * request block
+ * error descriptor
+ * scatter/gather list
+ * - 0x20 aligned ErrorInfo_t
+ * - ...?
+ */
+
+ if ((cpcm->cpcm_va_cmd = (void *)cpqary3_alloc_phyctgs_mem(cpq,
+ contig_size, &cpcm->cpcm_pa_cmd, &cpcm->cpcm_phyctg)) == NULL) {
+ kmem_free(cpcm, sizeof (*cpcm));
+ return (NULL);
+ }
+ cpcm->cpcm_va_err = (void *)((caddr_t)cpcm->cpcm_va_cmd +
+ errorinfo_offset);
+ cpcm->cpcm_pa_err = cpcm->cpcm_pa_cmd + errorinfo_offset;
+
+ /*
+ * Ensure we asked for, and received, the correct physical alignment:
+ */
+ VERIFY0(cpcm->cpcm_pa_cmd & 0x1f);
+ VERIFY0(cpcm->cpcm_pa_err & 0x1f);
+
+ /*
+ * Populate Fields.
+ */
+ bzero(cpcm->cpcm_va_cmd, contig_size);
+ cpcm->cpcm_va_cmd->Header.Tag.tag_value = cpcm->cpcm_tag;
+ cpcm->cpcm_va_cmd->ErrDesc.Addr = cpcm->cpcm_pa_err;
+ cpcm->cpcm_va_cmd->ErrDesc.Len = sizeof (ErrorInfo_t);
+
+ /*
+ * Insert into the per-controller command list.
+ */
+ mutex_enter(&cpq->sw_mutex);
+ list_insert_tail(&cpq->cpq_commands, cpcm);
+ mutex_exit(&cpq->sw_mutex);
+
+ return (cpcm);
+}
+
+cpqary3_command_internal_t *
+cpqary3_command_internal_alloc(cpqary3_t *cpq, size_t len)
+{
+ cpqary3_command_internal_t *cpcmi;
+
+ if ((cpcmi = kmem_zalloc(sizeof (*cpcmi), KM_NOSLEEP)) == NULL) {
+ return (NULL);
+ }
+
+ if ((cpcmi->cpcmi_va = (void *)cpqary3_alloc_phyctgs_mem(cpq, len,
+ &cpcmi->cpcmi_pa, &cpcmi->cpcmi_phyctg)) == NULL) {
+ kmem_free(cpcmi, sizeof (*cpcmi));
+ return (NULL);
+ }
+
+ bzero(cpcmi->cpcmi_va, cpcmi->cpcmi_len);
+
+ return (cpcmi);
+}
+
+void
+cpqary3_command_reuse(cpqary3_command_t *cpcm)
+{
+ cpqary3_t *cpq = cpcm->cpcm_ctlr;
+
+ mutex_enter(&cpq->sw_mutex);
+
+ /*
+ * Make sure the command is not currently inflight.
+ */
+ VERIFY(!cpcm->cpcm_inflight);
+ if (!cpcm->cpcm_used) {
+ /*
+ * If the command has not yet been issued to the controller,
+ * this is a no-op.
+ */
+ mutex_exit(&cpq->sw_mutex);
+ return;
+ }
+ cpcm->cpcm_used = B_FALSE;
+
+ /*
+ * 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;
+ }
+
+ /*
+ * Populate fields.
+ */
+ cpcm->cpcm_va_cmd->Header.Tag.tag_value = cpcm->cpcm_tag;
+
+ mutex_exit(&cpq->sw_mutex);
+}
+
+void
+cpqary3_command_free(cpqary3_command_t *cpcm)
+{
+ cpqary3_t *cpq = cpcm->cpcm_ctlr;
+
+ /*
+ * Ensure the object we are about to free is not currently in the
+ * inflight AVL.
+ */
+ VERIFY(!cpcm->cpcm_inflight);
+
+ if (cpcm->cpcm_internal != NULL) {
+ cpqary3_command_internal_t *cpcmi = cpcm->cpcm_internal;
+
+ cpqary3_free_phyctgs_mem(&cpcmi->cpcmi_phyctg,
+ CPQARY3_FREE_PHYCTG_MEM);
+ kmem_free(cpcmi, sizeof (*cpcmi));
+ }
+
+ cpqary3_free_phyctgs_mem(&cpcm->cpcm_phyctg, CPQARY3_FREE_PHYCTG_MEM);
+
+ mutex_enter(&cpq->sw_mutex);
+ list_remove(&cpq->cpq_commands, cpcm);
+ mutex_exit(&cpq->sw_mutex);
+
+ kmem_free(cpcm, sizeof (*cpcm));
+}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_ioctl.c b/usr/src/uts/common/io/cpqary3/cpqary3_ioctl.c
index cf74044730..7bdee56599 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_ioctl.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_ioctl.c
@@ -285,14 +285,16 @@ cpqary3_ioctl_fil_bmic(CommandList_t *cmdlist,
break;
}
- cmdlist ->Request.CDB[0] =
- (bmic_pass->io_direction == CPQARY3_SCSI_IN) ? 0x26: 0x27;
+ if (bmic_pass->io_direction == CPQARY3_SCSI_IN) {
+ cmdlist->Request.CDB[0] = CISS_SCMD_ARRAY_READ;
+ } else {
+ cmdlist->Request.CDB[0] = CISS_SCMD_ARRAY_WRITE;
+ }
cmdlist ->Request.CDB[1] = bmic_pass->unit_number; /* Unit Number */
/*
* BMIC Detail - bytes 2[MSB] to 5[LSB]
*/
-
cmdlist->Request.CDB[2] = (bmic_pass->blk_number >> 24) & 0xff;
cmdlist->Request.CDB[3] = (bmic_pass->blk_number >> 16) & 0xff;
cmdlist->Request.CDB[4] = (bmic_pass->blk_number >> 8) & 0xff;
@@ -300,16 +302,16 @@ cpqary3_ioctl_fil_bmic(CommandList_t *cmdlist,
cmdlist->Request.CDB[6] = bmic_pass->cmd; /* BMIC Command */
- /* Transfer Length - bytes 7[MSB] to 8[LSB] */
-
+ /*
+ * Transfer Length - bytes 7[MSB] to 8[LSB]
+ */
cmdlist->Request.CDB[7] = (bmic_pass->buf_len >> 8) & 0xff;
cmdlist->Request.CDB[8] = bmic_pass->buf_len & 0xff;
cmdlist->Request.CDB[9] = 0x00; /* Reserved */
/*
- * Copy the Lun address from the request
+ * Copy the LUN address from the request
*/
-
bcopy(&bmic_pass->lun_addr[0], &(cmdlist->Header.LUN),
sizeof (LUNAddr_t));
cmdlist->SG[0].Len = bmic_pass->buf_len;
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_isr.c b/usr/src/uts/common/io/cpqary3/cpqary3_isr.c
deleted file mode 100644
index 0fdcb88083..0000000000
--- a/usr/src/uts/common/io/cpqary3/cpqary3_isr.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * 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 (C) 2013 Hewlett-Packard Development Company, L.P.
- * Copyright 2016 Joyent, Inc.
- */
-
-#include "cpqary3.h"
-
-
-static 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);
- }
-}
-
-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,
- * this routine will panic the system.
- */
- cpqary3_lockup_check(cpq);
-
- mutex_exit(&cpq->hw_mutex);
- return (DDI_INTR_UNCLAIMED);
- }
-
- /*
- * Disable interrupts until the soft interrupt handler has had a chance
- * to read and process replies.
- */
- cpqary3_intr_onoff(cpq, CPQARY3_INTR_DISABLE);
-
- cpqary3_trigger_sw_isr(cpq);
-
- mutex_exit(&cpq->hw_mutex);
- return (DDI_INTR_CLAIMED);
-}
-
-uint_t
-cpqary3_isr_hw_performant(caddr_t arg)
-{
- cpqary3_t *cpq = (cpqary3_t *)arg;
- uint32_t isr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS);
-
- if (isr == 0) {
- /*
- * Check to see if the firmware has come to rest. If it has,
- * this routine will panic the system.
- */
- cpqary3_lockup_check(cpq);
-
- return (DDI_INTR_UNCLAIMED);
- }
-
- uint32_t odr = cpqary3_get32(cpq, CISS_I2O_OUTBOUND_DOORBELL_STATUS);
- if ((odr & 0x1) != 0) {
- uint32_t odr_cl = cpqary3_get32(cpq,
- CISS_I2O_OUTBOUND_DOORBELL_CLEAR);
-
- odr_cl |= 0x1;
- cpqary3_put32(cpq, CISS_I2O_OUTBOUND_DOORBELL_CLEAR, odr_cl);
-
- /*
- * Read the status register again to ensure the write to clear
- * is flushed to the controller.
- */
- (void) cpqary3_get32(cpq, CISS_I2O_OUTBOUND_DOORBELL_STATUS);
- }
-
- cpqary3_trigger_sw_isr(cpq);
-
- return (DDI_INTR_CLAIMED);
-}
-
-uint_t
-cpqary3_isr_sw_simple(caddr_t arg)
-{
- cpqary3_t *cpq = (cpqary3_t *)arg;
-
- /*
- * Confirm that the hardware interrupt routine scheduled this
- * software interrupt.
- */
- 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);
-
- /*
- * Unmask the controller inbound data interrupt.
- */
- if (!cpq->cpq_intr_off) {
- cpqary3_intr_onoff(cpq, CPQARY3_INTR_ENABLE);
- }
-
- cpq->cpq_swintr_flag = B_FALSE;
- mutex_exit(&cpq->hw_mutex);
- mutex_exit(&cpq->sw_mutex);
- return (DDI_INTR_CLAIMED);
-}
-
-uint_t
-cpqary3_isr_sw_performant(caddr_t arg)
-{
- cpqary3_t *cpq = (cpqary3_t *)arg;
-
- /*
- * Confirm that the hardware interrupt routine scheduled this
- * software interrupt.
- */
- 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_performant(cpq, 0, NULL);
-
- cpq->cpq_swintr_flag = B_FALSE;
- mutex_exit(&cpq->hw_mutex);
- mutex_exit(&cpq->sw_mutex);
- return (DDI_INTR_CLAIMED);
-}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_mem.c b/usr/src/uts/common/io/cpqary3/cpqary3_mem.c
index de3e268f59..c3f3338fbb 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_mem.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_mem.c
@@ -16,15 +16,6 @@
#include <sys/sdt.h>
#include "cpqary3.h"
-static caddr_t cpqary3_alloc_phyctgs_mem(cpqary3_t *, size_t, uint32_t *,
- cpqary3_phyctg_t *);
-static void cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *, uint8_t);
-
-/*
- * Local Functions Definitions
- */
-uint8_t cleanstatus = 0;
-
/*
* The Driver DMA Limit structure.
*/
@@ -64,7 +55,7 @@ extern ddi_device_acc_attr_t cpqary3_dev_attributes;
* Virtual Memory Pointer to the allocated Memory(caddr_t),
* Physical Address of the allocated Memory(phyaddr)
*/
-static caddr_t
+caddr_t
cpqary3_alloc_phyctgs_mem(cpqary3_t *ctlr, size_t size_mempool,
uint32_t *phyaddr, cpqary3_phyctg_t *phyctgp)
{
@@ -187,7 +178,7 @@ cpqary3_alloc_phyctgs_mem(cpqary3_t *ctlr, size_t size_mempool,
* Parameters : per-physical, identifier(what all to free)
* Calls : None
*/
-static void
+void
cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *cpqary3_phyctgp, uint8_t cleanstat)
{
@@ -212,137 +203,3 @@ cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *cpqary3_phyctgp, uint8_t cleanstat)
ddi_dma_free_handle(&cpqary3_phyctgp->cpqary3_dmahandle);
}
}
-
-static size_t
-cpqary3_round_up(size_t offset)
-{
- size_t gran = 0x20;
-
- return ((offset + (gran - 1)) & ~(gran - 1));
-}
-
-cpqary3_command_t *
-cpqary3_command_alloc(cpqary3_t *cpq)
-{
- cpqary3_command_t *cpcm;
-
- if ((cpcm = kmem_zalloc(sizeof (*cpcm), KM_NOSLEEP)) == NULL) {
- return (NULL);
- }
-
- cpcm->cpcm_ctlr = cpq;
-
- /*
- * 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);
-
- size_t contig_size = 0;
- size_t errorinfo_offset;
-
- contig_size += cpqary3_round_up(sizeof (CommandList_t));
-
- errorinfo_offset = contig_size;
- contig_size += cpqary3_round_up(sizeof (ErrorInfo_t));
-
- /*
- * Allocate physmem for CommandList_t (cpcm_va_cmd), and ErrorInfo_t
- * (cpcm_va_err).
- * XXX
- *
- * - 0x20 aligned CommandList_t
- * header
- * request block
- * error descriptor
- * scatter/gather list
- * - 0x20 aligned ErrorInfo_t
- * - ...?
- */
-
- if ((cpcm->cpcm_va_cmd = (void *)cpqary3_alloc_phyctgs_mem(cpq,
- contig_size, &cpcm->cpcm_pa_cmd, &cpcm->cpcm_phyctg)) == NULL) {
- kmem_free(cpcm, sizeof (*cpcm));
- return (NULL);
- }
- cpcm->cpcm_va_err = (void *)((caddr_t)cpcm->cpcm_va_cmd +
- errorinfo_offset);
- cpcm->cpcm_pa_err = cpcm->cpcm_pa_cmd + errorinfo_offset;
-
- /*
- * Ensure we asked for, and received, the correct physical alignment:
- */
- VERIFY0(cpcm->cpcm_pa_cmd & 0x1f);
- VERIFY0(cpcm->cpcm_pa_err & 0x1f);
-
- /*
- * XXX Populate Fields.
- */
- bzero(cpcm->cpcm_va_cmd, contig_size);
- cpcm->cpcm_va_cmd->Header.Tag.tag_value = cpcm->cpcm_tag;
- cpcm->cpcm_va_cmd->ErrDesc.Addr = cpcm->cpcm_pa_err;
- cpcm->cpcm_va_cmd->ErrDesc.Len = sizeof (ErrorInfo_t);
-
- /*
- * Insert into the per-controller command list.
- */
- mutex_enter(&cpq->sw_mutex);
- list_insert_tail(&cpq->cpq_commands, cpcm);
- mutex_exit(&cpq->sw_mutex);
-
- return (cpcm);
-}
-
-cpqary3_command_internal_t *
-cpqary3_command_internal_alloc(cpqary3_t *cpq, size_t len)
-{
- cpqary3_command_internal_t *cpcmi;
-
- if ((cpcmi = kmem_zalloc(sizeof (*cpcmi), KM_NOSLEEP)) == NULL) {
- return (NULL);
- }
-
- if ((cpcmi->cpcmi_va = (void *)cpqary3_alloc_phyctgs_mem(cpq, len,
- &cpcmi->cpcmi_pa, &cpcmi->cpcmi_phyctg)) == NULL) {
- kmem_free(cpcmi, sizeof (*cpcmi));
- return (NULL);
- }
-
- bzero(cpcmi->cpcmi_va, cpcmi->cpcmi_len);
-
- return (cpcmi);
-}
-
-void
-cpqary3_command_free(cpqary3_command_t *cpcm)
-{
- cpqary3_t *cpq = cpcm->cpcm_ctlr;
-
- /*
- * Ensure the object we are about to free is not currently in the
- * inflight AVL.
- */
- VERIFY(!cpcm->cpcm_inflight);
-
- if (cpcm->cpcm_internal != NULL) {
- cpqary3_command_internal_t *cpcmi = cpcm->cpcm_internal;
-
- cpqary3_free_phyctgs_mem(&cpcmi->cpcmi_phyctg,
- CPQARY3_FREE_PHYCTG_MEM);
- kmem_free(cpcmi, sizeof (*cpcmi));
- }
-
- cpqary3_free_phyctgs_mem(&cpcm->cpcm_phyctg, CPQARY3_FREE_PHYCTG_MEM);
-
- mutex_enter(&cpq->sw_mutex);
- list_remove(&cpq->cpq_commands, cpcm);
- mutex_exit(&cpq->sw_mutex);
-
- kmem_free(cpcm, sizeof (*cpcm));
-}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_mem.h b/usr/src/uts/common/io/cpqary3/cpqary3_mem.h
new file mode 100644
index 0000000000..18162a444e
--- /dev/null
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_mem.h
@@ -0,0 +1,41 @@
+/*
+ * 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 (C) 2013 Hewlett-Packard Development Company, L.P.
+ */
+
+#ifndef _CPQARY3_Q_MEM_H
+#define _CPQARY3_Q_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This structure is meant to store the handle of the physically contiguous
+ * memory blcoks that will be allocated during the _meminit().
+ * The no. of blocks that will be allocated will be decide at run time
+ * depending upon the maximum outstanding commands supported by the controller.
+ * each block is physically contiguous & can hold 3 commands.
+ */
+typedef struct cpqary3_phyctg {
+ size_t real_size;
+ ddi_dma_handle_t cpqary3_dmahandle;
+ ddi_acc_handle_t cpqary3_acchandle;
+ ddi_dma_cookie_t cpqary3_dmacookie;
+} cpqary3_phyctg_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CPQARY3_Q_MEM_H */
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_q_mem.h b/usr/src/uts/common/io/cpqary3/cpqary3_q_mem.h
deleted file mode 100644
index ed3127230b..0000000000
--- a/usr/src/uts/common/io/cpqary3/cpqary3_q_mem.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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 (C) 2013 Hewlett-Packard Development Company, L.P.
- */
-
-#ifndef _CPQARY3_Q_MEM_H
-#define _CPQARY3_Q_MEM_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define CPQARY3_GET_MEM_TAG 4
-
-#define CPQARY3_FREE 0
-#define CPQARY3_OCCUPIED 1
-#define CPQARY3_SELF_OCCUPIED 2
-#define CPQARY3_POLL_OCCUPIED 3
-
-#define CPQARY3_PHYCTGS_DONE 0x01
-#define CPQARY3_CMDMEM_DONE 0x02
-#define CPQARY3_MEMLIST_DONE 0x04
-
-#define CPQARY3_SUBMITTED_Q 0x0100
-#define CPQARY3_APPEND_RETRIEVE 1
-#define CPQARY3_REMOVE_SUBMITTED 0
-
-#define CPQARY3_Q_UNMASK 0x0300
-
-/*
- * No. of Commands that would be accomodated in each Command Pool
- * Each command needs a physical contigous memory of 564 Bytes.
- * The number of blocks to be allocated would be decided at run time
- * depending upon the maximum outstanding commands supported by that controller.
- */
-#define NO_OF_CMDLIST_IN_A_BLK 3
-
-
-/*
- * This structure is meant to store the handle of the physically contiguous
- * memory blcoks that will be allocated during the _meminit().
- * The no. of blocks that will be allocated will be decide at run time
- * depending upon the maximum outstanding commands supported by the controller.
- * each block is physically contiguous & can hold 3 commands.
- */
-typedef struct cpqary3_phyctg {
- size_t real_size;
- ddi_dma_handle_t cpqary3_dmahandle;
- ddi_acc_handle_t cpqary3_acchandle;
- ddi_dma_cookie_t cpqary3_dmacookie;
-} cpqary3_phyctg_t;
-
-typedef struct cpqary3_command_private CMDLIST;
-
-/* Linked List Structure to hold Command List Details */
-typedef struct cpqary3_command_private {
- uint8_t occupied;
- uint8_t cmdpvt_flag;
- uint32_t cmdlist_phyaddr;
- uint32_t cmdlist_erraddr;
- cpqary3_tag_t tag;
- ErrorInfo_t *errorinfop;
- CommandList_t *cmdlist_memaddr;
- struct cpqary3_command_private *next; /* next Command Memory */
- struct cpqary3_command_private *prev; /* previous Command Memory */
- struct cpqary3_per_controller *ctlr; /* to its controller */
- struct cpqary3_pkt *pvt_pkt; /* Driver Private Packet */
- struct cpqary3_driver_private *driverdata; /* command private data */
- struct cpqary3_command_private *snext; /* to maintain Submitted Q & */
- struct cpqary3_command_private *sprev; /* Retrieved Q. */
- void (*complete)(CMDLIST *);
-} cpqary3_cmdpvt_t;
-
-/* structure to maintain a linked list of the memory blocks */
-typedef struct physical_handle_address {
- cpqary3_phyctg_t *blk_addr;
- struct physical_handle_address *next;
-} cpqary3_phys_hdl_addr_t;
-
-/* Structure to hold Memory Pool Details */
-typedef struct cpqary3_cmdmemlist {
- uint16_t max_memcnt;
- cpqary3_cmdpvt_t *pool;
- cpqary3_cmdpvt_t *head;
- cpqary3_cmdpvt_t *tail;
- cpqary3_phys_hdl_addr_t *cpqary3_phyctgp; /* list of memory blocks */
-} cpqary3_cmdmemlist_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _CPQARY3_Q_MEM_H */
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c b/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c
index 2122990649..64c0c98fe6 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_scsi.c
@@ -20,8 +20,6 @@
* Local Functions Definitions
*/
-uint8_t cpqary3_format_unit(cpqary3_cmdpvt_t *);
-
static uint8_t cpqary3_probe4LVs(cpqary3_t *);
static uint8_t cpqary3_probe4Tapes(cpqary3_t *);
@@ -239,31 +237,12 @@ cpqary3_send_abortcmd(cpqary3_t *cpqary3p, uint16_t target_id,
}
-
-/*
- * Function : cpqary3_fulsh_cache
- * Description : This routine flushes the controller cache.
- * Called By : cpqary3_detach(), cpqary3_additional_cmd()
- * Parameters : per controller
- * Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send()
- * cpqary3_synccmd_free()
- * Return Values: None
- */
int
cpqary3_flush_cache(cpqary3_t *cpqary3p)
{
cpqary3_command_t *cpcm;
CommandList_t *cmdlistp;
- /*
- * Occupy the Command List
- * Allocate Physically Contigous Memory for the FLUSH CACHE buffer
- * Update the Command List accordingly
- * Submit the command and wait for a signal
- */
-
- ASSERT(cpqary3p != NULL);
-
/* grab a command and allocate a dma buffer */
if ((cpcm = cpqary3_synccmd_alloc(cpqary3p,
sizeof (flushcache_buf_t))) == NULL) {
@@ -282,12 +261,10 @@ cpqary3_flush_cache(cpqary3_t *cpqary3p)
cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
cmdlistp->Request.Type.Direction = CISS_XFER_WRITE;
cmdlistp->Request.Timeout = CISS_NO_TIMEOUT;
- cmdlistp->Request.CDB[0] = ARRAY_WRITE;
- cmdlistp->Request.CDB[6] = CISS_FLUSH_CACHE; /* 0xC2 */
+ cmdlistp->Request.CDB[0] = CISS_SCMD_ARRAY_WRITE;
+ cmdlistp->Request.CDB[6] = BMIC_FLUSH_CACHE;
cmdlistp->Request.CDB[8] = 0x02;
- cpcm->cpcm_complete = cpqary3_synccmd_complete;
-
if (cpqary3_synccmd_send(cpqary3p, cpcm, 90000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
dev_err(cpqary3p->dip, CE_WARN, "flush cache failed: timeout");
@@ -543,8 +520,6 @@ cpqary3_probe4Tapes(cpqary3_t *cpqary3p)
DTRACE_PROBE2(tape_probe_cmd_send,
CommandList_t *, cmdlistp, cpqary3_command_t *, cpcm);
- cpcm->cpcm_complete = cpqary3_synccmd_complete;
-
if (cpqary3_synccmd_send(cpqary3p, cpcm, 90000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
cpqary3_synccmd_free(cpqary3p, cpcm);
@@ -662,13 +637,6 @@ cpqary3_synccmd_complete(cpqary3_command_t *cpcm)
case CPQARY3_SYNCCMD_STATUS_SUBMITTED:
cpcm->cpcm_synccmd_status = CPQARY3_SYNCCMD_STATUS_NONE;
-
- /*
- * Fix for Flush Cache Operation Timed out issue:
- * cv_signal() wakes up only one blocked thread.
- * We need to use cv_broadcast which unblocks
- * all the blocked threads()
- */
cv_broadcast(&cpq->cv_ioctl_wait);
return;
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_scsi.h b/usr/src/uts/common/io/cpqary3/cpqary3_scsi.h
index 515c568369..6df5d7cabe 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_scsi.h
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_scsi.h
@@ -25,26 +25,34 @@ extern "C" {
/* CISS LUN Addressing MODEs */
#define PERIPHERIAL_DEV_ADDR 0x0
-#define LOGICAL_VOL_ADDR 0x1
+#define LOGICAL_VOL_ADDR 0x1
#define MASK_PERIPHERIAL_DEV_ADDR 0x3
-#define CISS_PHYS_MODE 0x0
+#define CISS_PHYS_MODE 0x0
/*
* Definitions for compatibility with the old array BMIC interface
* CISS_OPCODE_RLL IS THE OPCODE FOR THE Report Logical Luns command
*/
-#define ARRAY_READ 0x26
-#define ARRAY_WRITE 0x27
+#define CISS_SCMD_ARRAY_READ 0x26
+#define CISS_SCMD_ARRAY_WRITE 0x27
+
#define CISS_NEW_READ 0xC0
#define CISS_NEW_WRITE 0xC1
#define CISS_OPCODE_RLL 0xC2
#define CISS_OPCODE_RPL 0xC3
-#define CISS_NO_TIMEOUT 0x0
+#define CISS_NO_TIMEOUT 0x00
/*
- * BMIC commands
+ * 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.
*/
-#define CISS_FLUSH_CACHE 0xC2
+#define BMIC_FLUSH_CACHE 0xC2
#define BMIC_IDENTIFY_LOGICAL_DRIVE 0x10
#define BMIC_SENSE_LOGICAL_DRIVE_STATUS 0x12
@@ -153,7 +161,6 @@ typedef struct rpl_data {
/*
* Format of the data returned for the IDENTIFY LOGICAL DRIVE Command
*/
-
typedef struct Identify_Logical_Drive {
uint16_t block_size_in_bytes;
uint32_t blocks_available;
@@ -171,7 +178,6 @@ typedef struct Identify_Logical_Drive {
uint8_t reserved3[418];
} IdLogDrive;
-/* FORMAT */
typedef struct Identify_Ld_Status {
uint8_t status; /* Logical Drive Status */
uint32_t failure_map; /* Drive Failure Map */
@@ -206,25 +212,6 @@ typedef struct Identify_Ld_Status {
uint8_t big_drive_rebuild; /* Drive Rebuilding - Drive # */
uint8_t reserved[36];
} SenseLdStatus;
-/* FORMAT */
-
-/*
- * SCSI Command Opcodes
- */
-#define SCSI_READ_6 0x08 /* READ - 6 byte command */
-#define SCSI_READ_10 0x28 /* READ - 10 byte command */
-#define SCSI_READ_12 0xA8 /* READ - 12 byte command */
-#define SCSI_WRITE_6 0x0A /* WRITE - 6 byte command */
-#define SCSI_WRITE_10 0x2A /* WRITE - 10 byte command */
-#define SCSI_WRITE_12 0xAA /* WRITE - 12 byte command */
-
-/*
- * SCSI Opcodes Not supported by FW
- *
- */
-#define SCSI_LOG_SENSE 0x4D /* LOG SENSE */
-#define SCSI_MODE_SELECT 0x15 /* LOG SENSE */
-#define SCSI_PERSISTENT_RESERVE_IN 0x5E /* PERSISTENT RESERVE IN */
#pragma pack()
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c b/usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c
deleted file mode 100644
index d72ffd2159..0000000000
--- a/usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c
+++ /dev/null
@@ -1,865 +0,0 @@
-/*
- * 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 (C) 2013 Hewlett-Packard Development Company, L.P.
- * Copyright 2016 Joyent, Inc.
- */
-
-/*
- * This module contains routines that program the controller. All
- * operations viz., initialization of controller, submision &
- * retrieval of commands, enabling & disabling of interrupts,
- * checking interrupt status are performed here.
- */
-
-#include <sys/sdt.h>
-#include "cpqary3.h"
-
-/*
- * Local Functions Definitions
- */
-uint8_t cpqary3_check_simple_ctlr_intr(cpqary3_t *cpqary3p);
-uint8_t cpqary3_check_perf_ctlr_intr(cpqary3_t *cpqary3p);
-uint8_t cpqary3_check_perf_e200_intr(cpqary3_t *cpqary3p);
-
-/*
- * Function : cpqary3_check_simple_ctlr_intr
- * Description : This routine determines if the controller did interrupt.
- * Called By : cpqary3_hw_isr()
- * Parameters : per-controller
- * Calls : None
- * Return Values: SUCCESS : This controller did interrupt.
- * FAILURE : It did not.
- */
-uint8_t
-cpqary3_check_simple_ctlr_intr(cpqary3_t *cpq)
-{
- uint32_t intr_pending_mask = cpq->cpq_board->bd_intrpendmask;
-
- /*
- * Read the Interrupt Status Register and
- * if bit 3 is set, it indicates that we have completed commands
- * in the controller
- */
- if (intr_pending_mask &
- cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS)) {
- return (CPQARY3_SUCCESS);
- }
-
- return (CPQARY3_FAILURE);
-}
-
-/*
- * Function : cpqary3_check_perf_ctlr_intr
- * Description : This routine determines if the
- * controller did interrupt.
- * Called By : cpqary3_hw_isr()
- * Parameters : per-controller
- * Calls : None
- * Return Values: SUCCESS : This controller did interrupt.
- * FAILURE : It did not.
- */
-uint8_t
-cpqary3_check_perf_ctlr_intr(cpqary3_t *cpq)
-{
- /*
- * Read the Interrupt Status Register and
- * if bit 3 is set, it indicates that we have completed commands
- * in the controller
- * XXX _which_ bit?
- */
- if (cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS) & 0x1) {
- return (CPQARY3_SUCCESS);
- }
-
- return (CPQARY3_FAILURE);
-}
-
-/*
- * Function : cpqary3_check_perf_e200_intr
- * Description : This routine determines if the controller
- * did interrupt.
- * Called By : cpqary3_hw_isr()
- * Parameters : per-controller
- * Calls : None
- * Return Values: SUCCESS : This controller did interrupt.
- * FAILURE : It did not.
- */
-uint8_t
-cpqary3_check_perf_e200_intr(cpqary3_t *cpq)
-{
- /*
- * Read the Interrupt Status Register and
- * if bit 3 is set, it indicates that we have completed commands
- * in the controller
- */
- if (cpqary3_get32(cpq, CISS_I2O_INTERRUPT_STATUS) & 0x4) {
- return (CPQARY3_SUCCESS);
- }
-
- return (CPQARY3_FAILURE);
-}
-
-/*
- * 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)
-{
- uint32_t opq;
- uint32_t none = 0xffffffff;
-
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
- VERIFY(MUTEX_HELD(&cpq->sw_mutex));
-
- while ((opq = cpqary3_get32(cpq, CISS_I2O_OUTBOUND_POST_Q)) != none) {
- 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);
- continue;
- }
-
- 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;
- }
-
- mutex_exit(&cpq->hw_mutex);
- cpcm->cpcm_complete(cpcm);
- mutex_enter(&cpq->hw_mutex);
- }
-}
-
-void
-cpqary3_retrieve_performant(cpqary3_t *cpq, uint32_t watchfor, boolean_t *found)
-{
- cpqary3_replyq_t *cprq = &cpq->cpq_replyq;
-
- for (;;) {
- uint32_t ent = cprq->cprq_tags[2 * cprq->cprq_read_index];
- uint32_t tag = ent >> 2; /* XXX */
- cpqary3_command_t *cpcm;
-
- if ((ent & 0x1) != cprq->cprq_cycle_indicator) {
- break;
- }
-
- if ((cpcm = cpqary3_lookup_inflight(cpq, tag)) == NULL) {
- dev_err(cpq->dip, CE_WARN, "spurious tag %x", tag);
- continue;
- }
-
- avl_remove(&cpq->cpq_inflight, cpcm);
- cpcm->cpcm_inflight = B_FALSE;
- cpcm->cpcm_error = (ent & (0x1 << 1)) != 0;
-
- if (found != NULL && cpcm->cpcm_tag == watchfor) {
- *found = B_TRUE;
- }
-
- cpcm->cpcm_complete(cpcm);
-
- if (++cprq->cprq_read_index >= cprq->cprq_ntags) {
- cprq->cprq_read_index = 0;
- if (cprq->cprq_cycle_indicator == 1) {
- cprq->cprq_cycle_indicator = 0;
- } else {
- cprq->cprq_cycle_indicator = 1;
- }
- }
- }
-}
-
-/*
- * XXX
- */
-int
-cpqary3_retrieve(cpqary3_t *cpq)
-{
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
- VERIFY(MUTEX_HELD(&cpq->sw_mutex));
-
- switch (cpq->cpq_ctlr_mode) {
- case CPQARY3_CTLR_MODE_SIMPLE:
- cpqary3_retrieve_simple(cpq, 0, NULL);
- return (DDI_SUCCESS);
-
- case CPQARY3_CTLR_MODE_PERFORMANT:
- cpqary3_retrieve_performant(cpq, 0, NULL);
- return (DDI_SUCCESS);
-
- case CPQARY3_CTLR_MODE_UNKNOWN:
- break;
- }
-
- panic("unknown controller mode");
-}
-
-/*
- * Function : cpqary3_poll_retrieve
- * Description : This routine retrieves the completed command from the
- * controller reply queue in poll mode.
- * and processes the completed commands.
- * Called By : cpqary3_poll
- * Parameters : per-controller
- * Calls : packet completion routines
- * Return Values: If the polled command is completed, send back a success.
- * If not return failure.
- */
-uint8_t
-cpqary3_poll_retrieve(cpqary3_t *cpq, uint32_t poll_tag)
-{
- boolean_t found = B_FALSE;
-
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
- VERIFY(MUTEX_HELD(&cpq->sw_mutex));
-
- switch (cpq->cpq_ctlr_mode) {
- case CPQARY3_CTLR_MODE_SIMPLE:
- cpqary3_retrieve_simple(cpq, poll_tag, &found);
- break;
-
- case CPQARY3_CTLR_MODE_PERFORMANT:
- cpqary3_retrieve_performant(cpq, poll_tag, &found);
- break;
-
- default:
- panic("unknown controller mode");
- }
-
- return (found ? DDI_SUCCESS : DDI_FAILURE);
-}
-
-/*
- * Function : cpqary3_submit
- * Description : This routine submits the command to the Inbound Post Q.
- * Called By : cpqary3_transport(), cpqary3_send_NOE_command(),
- * cpqary3_disable_NOE_command(),
- * cpqary3_handle_flag_nointr(),
- * cpqary3_tick_hdlr(), cpqary3_synccmd_send()
- * Parameters : per-controller, physical address
- * Calls : None
- * Return Values: None
- */
-int
-cpqary3_submit(cpqary3_t *cpq, cpqary3_command_t *cpcm)
-{
- VERIFY(MUTEX_HELD(&cpq->hw_mutex));
-
- /*
- * If a controller lockup has been detected, reject new command
- * submissions.
- */
- if (cpq->controller_lockup == CPQARY3_TRUE) {
- return (EIO);
- }
-
- /*
- * XXX
- * At present, we have no good way to "re-use" an allocated
- * command structure. Let's catch any places where this happens.
- */
- VERIFY(!cpcm->cpcm_used);
- cpcm->cpcm_used = B_TRUE;
-
- /*
- * Insert this command into the inflight AVL.
- */
- avl_index_t where;
- if (avl_find(&cpq->cpq_inflight, cpcm, &where) != NULL) {
- dev_err(cpq->dip, CE_PANIC, "duplicate submit tag %x",
- cpcm->cpcm_tag);
- }
- avl_insert(&cpq->cpq_inflight, cpcm, where);
-
- VERIFY(cpcm->cpcm_inflight == B_FALSE);
- cpcm->cpcm_inflight = B_TRUE;
-
- switch (cpq->cpq_ctlr_mode) {
- case CPQARY3_CTLR_MODE_SIMPLE:
- cpqary3_put32(cpq, CISS_I2O_INBOUND_POST_Q, cpcm->cpcm_pa_cmd);
- break;
-
- case CPQARY3_CTLR_MODE_PERFORMANT:
- /*
- * XXX The driver always uses the 0th block fetch count always
- *
- * (NB: from spec, the 0x1 here sets "pull from host memory"
- * mode, and the 0 represents "pull just one command record"
- */
- cpqary3_put32(cpq, CISS_I2O_INBOUND_POST_Q,
- cpcm->cpcm_pa_cmd | 0 | 0x1);
- break;
-
- default:
- panic("unknown controller mode");
- }
-
- return (0);
-}
-
-
-/*
- * Function : cpqary3_intr_onoff
- * Description : This routine enables/disables the HBA interrupt.
- * Called By : cpqary3_attach(), ry3_handle_flag_nointr(),
- * cpqary3_tick_hdlr(), cpqary3_init_ctlr_resource()
- * Parameters : per-controller, flag stating enable/disable
- * Calls : None
- * Return Values: None
- */
-void
-cpqary3_intr_onoff(cpqary3_t *cpq, uint8_t flag)
-{
- /*
- * Read the Interrupt Mask Register.
- */
- uint32_t imr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_MASK);
-
- VERIFY(flag == CPQARY3_INTR_ENABLE || flag == CPQARY3_INTR_DISABLE);
-
- switch (cpq->cpq_ctlr_mode) {
- case CPQARY3_CTLR_MODE_SIMPLE:
- if (flag == CPQARY3_INTR_ENABLE) {
- imr &= ~INTR_SIMPLE_MASK;
- } else {
- imr |= INTR_SIMPLE_MASK;
- }
- break;
-
- default:
- if (flag == CPQARY3_INTR_ENABLE) {
- imr &= ~cpq->cpq_board->bd_intrmask;
- } else {
- imr |= cpq->cpq_board->bd_intrmask;
- }
- break;
- }
-
- cpqary3_put32(cpq, CISS_I2O_INTERRUPT_MASK, imr);
-}
-
-/*
- * Function : cpqary3_lockup_intr_onoff
- * Description : This routine enables/disables the lockup interrupt.
- * Called By : cpqary3_attach(), cpqary3_handle_flag_nointr(),
- * cpqary3_tick_hdlr(), cpqary3_hw_isr,
- * cpqary3_init_ctlr_resource()
- * Parameters : per-controller, flag stating enable/disable
- * Calls : None
- * Return Values: None
- */
-void
-cpqary3_lockup_intr_onoff(cpqary3_t *cpq, uint8_t flag)
-{
- /*
- * Read the Interrupt Mask Register.
- */
- uint32_t imr = cpqary3_get32(cpq, CISS_I2O_INTERRUPT_MASK);
-
- /*
- * Enable or disable firmware lockup interrupts from the controller
- * based on the flag.
- */
- if (flag == CPQARY3_LOCKUP_INTR_ENABLE) {
- imr &= ~cpq->cpq_board->bd_lockup_intrmask;
- } else {
- VERIFY(flag == CPQARY3_LOCKUP_INTR_DISABLE);
-
- imr |= cpq->cpq_board->bd_lockup_intrmask;
- }
-
- cpqary3_put32(cpq, CISS_I2O_INTERRUPT_MASK, imr);
-}
-
-/*
- * Signal to the controller that we have updated the Configuration Table by
- * writing to the Inbound Doorbell Register. The controller will, after some
- * number of seconds, acknowledge this by clearing the bit.
- *
- * If successful, return DDI_SUCCESS. If the controller takes too long to
- * acknowledge, return DDI_FAILURE.
- */
-static int
-cpqary3_cfgtbl_flush(cpqary3_t *cpq)
-{
- /*
- * Read the current value of the Inbound Doorbell Register.
- */
- uint32_t idr = cpqary3_get32(cpq, CISS_I2O_INBOUND_DOORBELL);
-
- /*
- * Signal the Configuration Table change to the controller.
- */
- idr |= CISS_IDR_BIT_CFGTBL_CHANGE;
- cpqary3_put32(cpq, CISS_I2O_INBOUND_DOORBELL, idr);
-
- /*
- * Wait for the controller to acknowledge the change.
- */
- for (unsigned i = 0; i < CISS_INIT_TIME; i++) {
- idr = cpqary3_get32(cpq, CISS_I2O_INBOUND_DOORBELL);
-
- if ((idr & CISS_IDR_BIT_CFGTBL_CHANGE) == 0) {
- return (DDI_SUCCESS);
- }
-
- /*
- * Wait for one second before trying again.
- */
- delay(drv_usectohz(1000000));
- }
-
- dev_err(cpq->dip, CE_WARN, "time out expired before controller "
- "configuration completed");
- return (DDI_FAILURE);
-}
-
-static int
-cpqary3_cfgtbl_transport_has_support(cpqary3_t *cpq, int xport)
-{
- VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE ||
- xport == CISS_CFGTBL_XPORT_PERFORMANT);
-
- /*
- * Read the current value of the TransportSupport field in the
- * Configuration Table.
- */
- uint32_t xport_active = ddi_get32(cpq->cpq_ct_handle,
- &cpq->cpq_ct->TransportSupport);
-
- /*
- * Check that the desired transport method is supported by the
- * controller:
- */
- if ((xport_active & xport) == 0) {
- dev_err(cpq->dip, CE_WARN, "controller does not support "
- "method \"%s\"", xport == CISS_CFGTBL_XPORT_SIMPLE ?
- "simple" : "performant");
- return (DDI_FAILURE);
- }
-
- return (DDI_SUCCESS);
-}
-
-static void
-cpqary3_cfgtbl_transport_set(cpqary3_t *cpq, int xport)
-{
- VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE ||
- xport == CISS_CFGTBL_XPORT_PERFORMANT);
-
- ddi_put32(cpq->cpq_ct_handle,
- &cpq->cpq_ct->HostWrite.TransportRequest, xport);
-}
-
-static int
-cpqary3_cfgtbl_transport_confirm(cpqary3_t *cpq, int xport)
-{
- VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE ||
- xport == CISS_CFGTBL_XPORT_PERFORMANT);
-
- /*
- * Read the current value of the TransportActive field in the
- * Configuration Table.
- */
- uint32_t xport_active = ddi_get32(cpq->cpq_ct_handle,
- &cpq->cpq_ct->TransportActive);
-
- /*
- * Check that the desired transport method is now active:
- */
- if ((xport_active & xport) == 0) {
- dev_err(cpq->dip, CE_WARN, "failed to enable transport "
- "method \"%s\"", xport == CISS_CFGTBL_XPORT_SIMPLE ?
- "simple" : "performant");
- return (DDI_FAILURE);
- }
-
- /*
- * Ensure that the controller is now ready to accept commands.
- */
- if ((xport_active & CISS_CFGTBL_READY_FOR_COMMANDS) == 0) {
- dev_err(cpq->dip, CE_WARN, "controller not ready to "
- "accept commands");
- return (DDI_FAILURE);
- }
-
- return (DDI_SUCCESS);
-}
-
-static uint32_t
-cpqary3_ctlr_get_cmdsoutmax(cpqary3_t *cpq)
-{
- uint32_t val;
-
- if (cpq->cpq_ctlr_mode == CPQARY3_CTLR_MODE_PERFORMANT) {
- if ((val = ddi_get32(cpq->cpq_ct_handle,
- &cpq->cpq_ct->MaxPerfModeCmdsOutMax)) != 0) {
- return (val);
- }
- }
-
- return (ddi_get32(cpq->cpq_ct_handle, &cpq->cpq_ct->CmdsOutMax));
-}
-
-static uint32_t
-cpqary3_ctlr_get_hostdrvsup(cpqary3_t *cpq)
-{
- if (!cpq->cpq_board->bd_is_e200 && !cpq->cpq_board->bd_is_ssll) {
- uint32_t val = ddi_get32(cpq->cpq_ct_handle,
- &cpq->cpq_ct->HostDrvrSupport);
-
- /*
- * XXX This is "bit 2" in the "Host Driver Specific Support"
- * field of the Configuration Table. According to the CISS
- * spec, this is "Interrupt Host upon Controller Lockup"
- * Enable.
- *
- * It's not clear why we _set_ this bit, but then it's not yet
- * clear how this table entry is even supposed to work.
- */
- val |= 0x04;
-
- ddi_put32(cpq->cpq_ct_handle, &cpq->cpq_ct->HostDrvrSupport,
- val);
- }
-
- return (ddi_get32(cpq->cpq_ct_handle, &cpq->cpq_ct->HostDrvrSupport));
-}
-
-static int
-cpqary3_ctlr_init_simple(cpqary3_t *cpq)
-{
- VERIFY(cpq->cpq_ctlr_mode == CPQARY3_CTLR_MODE_UNKNOWN);
-
- if (cpqary3_cfgtbl_transport_has_support(cpq,
- CISS_CFGTBL_XPORT_SIMPLE) != DDI_SUCCESS) {
- return (DDI_FAILURE);
- }
- cpq->cpq_ctlr_mode = CPQARY3_CTLR_MODE_SIMPLE;
-
- /*
- * Disable device interrupts while we are setting up.
- */
- cpqary3_intr_onoff(cpq, CPQARY3_INTR_DISABLE);
-
- if ((cpq->cpq_maxcmds = cpqary3_ctlr_get_cmdsoutmax(cpq)) == 0) {
- dev_err(cpq->dip, CE_WARN, "maximum outstanding commands set "
- "to zero");
- return (DDI_FAILURE);
- }
-
- /*
- * XXX ?
- */
- cpq->cpq_sg_cnt = CPQARY3_SG_CNT;
-
- /*
- * Zero the upper 32 bits of the address in the Controller.
- */
- ddi_put32(cpq->cpq_ct_handle, &cpq->cpq_ct->HostWrite.Upper32Addr, 0);
-
- /*
- * Set the Transport Method and flush the changes to the
- * Configuration Table.
- */
- cpqary3_cfgtbl_transport_set(cpq, CISS_CFGTBL_XPORT_SIMPLE);
- if (cpqary3_cfgtbl_flush(cpq) != DDI_SUCCESS) {
- return (DDI_FAILURE);
- }
-
- if (cpqary3_cfgtbl_transport_confirm(cpq,
- CISS_CFGTBL_XPORT_SIMPLE) != DDI_SUCCESS) {
- return (DDI_FAILURE);
- }
-
- /*
- * XXX It's not clear why we check this a second time, but the original
- * driver did.
- */
- uint32_t check_again = cpqary3_ctlr_get_cmdsoutmax(cpq);
- if (check_again != cpq->cpq_maxcmds) {
- dev_err(cpq->dip, CE_WARN, "maximum outstanding commands "
- "changed during initialisation (was %u, now %u)",
- cpq->cpq_maxcmds, check_again);
- return (DDI_FAILURE);
- }
-
-#if 0
- /*
- * Set the controller interrupt check routine.
- */
- cpq->check_ctlr_intr = cpqary3_check_simple_ctlr_intr;
-#endif
-
- return (DDI_SUCCESS);
-}
-
-/*
- * XXX
- */
-#if 0
-static int
-cpqary3_ctlr_init_performant(cpqary3_t *cpq)
-{
- cpqary3_replyq_t *cprq = &cpq->cpq_replyq;
-
- VERIFY(cpq->cpq_ctlr_mode == CPQARY3_CTLR_MODE_UNKNOWN);
-
- if (cpqary3_cfgtbl_transport_has_support(cpq,
- CISS_CFGTBL_XPORT_PERFORMANT) != DDI_SUCCESS) {
- return (ENOTTY);
- }
- cpq->cpq_ctlr_mode = CPQARY3_CTLR_MODE_PERFORMANT;
-
- if ((cpq->ctlr_maxcmds = cpqary3_ctlr_get_cmdsoutmax(cpq)) == 0) {
- dev_err(cpq->dip, CE_WARN, "maximum outstanding commands set "
- "to zero");
- return (EPROTO);
- }
-
- /*
- * Initialize the Performant Method Transport Method Table.
- *
- * XXX "Number of 4-byte nodes in each reply queue. Same for all reply
- * queues." Here we are passing the number of COMMANDS, which is the
- * number of 8-byte nodes...
- */
- DDI_PUT32_CP(cpq, &cpq->cp->ReplyQSize, cpq->ctlr_maxcmds);
- DDI_PUT32_CP(cpq, &cpq->cp->ReplyQCount, 1);
- DDI_PUT32_CP(cpq, &cpq->cp->ReplyQCntrAddrLow32, 0);
- DDI_PUT32_CP(cpq, &cpq->cp->ReplyQCntrAddrHigh32, 0);
-
- /*
- * Each slot in the Reply Queue consists of two 4 byte integer
- * fields.
- */
- size_t qsize = cpq->ctlr_maxcmds * 2 * sizeof (uint32_t);
-
- if ((cprq->cprq_tags = (void *)cpqary3_alloc_phyctgs_mem(cpq, qsize,
- &cprq->cprq_tags_pa, &cprq->cprq_phyctg)) == NULL) {
- dev_err(cpq->dip, CE_WARN, "could not allocate replyq");
- return (ENOMEM);
- }
-
- bzero(cprq->cprq_tags, qsize);
- cprq->cprq_ntags = cpq->ctlr_maxcmds;
- cprq->cprq_cycle_indicator = 1;
- cprq->cprq_read_index = 0;
-
- DDI_PUT32_CP(cpq, &cpq->cp->ReplyQAddr0Low32, cprq->cprq_tags_pa);
- DDI_PUT32_CP(cpq, &cpq->cp->ReplyQAddr0High32, 0);
-
- max_blk_fetch_cnt = DDI_GET32(cpq, &ctp->MaxBlockFetchCount);
-
- /*
- * For non-proton FW controllers, max_blk_fetch_count is not
- * implemented in the firmware
- */
-
- /*
- * When blk fetch count is 0, FW auto fetches 564 bytes
- * corresponding to an optimal S/G of 31
- */
- if (max_blk_fetch_cnt == 0) {
- BlockFetchCnt[0] = 35;
- } else {
- /*
- * With MAX_PERF_SG_CNT set to 64, block fetch count
- * is got by:(sizeof (CommandList_t) + 15)/16
- */
- if (max_blk_fetch_cnt > 68)
- BlockFetchCnt[0] = 68;
- else
- BlockFetchCnt[0] = max_blk_fetch_cnt;
- }
-
- DDI_PUT32_CP(cpq, &perf_cfg->BlockFetchCnt[0], BlockFetchCnt[0]);
-
- /*
- * Set the Transport Method and flush the changes to the
- * Configuration Table.
- */
- cpqary3_cfgtbl_transport_set(cpq, CISS_CFGTBL_XPORT_PERFORMANT);
- if (cpqary3_cfgtbl_flush(cpq) != DDI_SUCCESS) {
- return (EPROTO);
- }
-
- if (cpqary3_cfgtbl_transport_confirm(cpq,
- CISS_CFGTBL_XPORT_PERFORMANT) != DDI_SUCCESS) {
- return (EPROTO);
- }
-
- /*
- * XXX It's not clear why we check this a second time, but the original
- * driver did.
- */
- uint32_t check_again = cpqary3_ctlr_get_cmdsoutmax(cpq);
- if (check_again != cpq->ctlr_maxcmds) {
- dev_err(cpq->dip, CE_WARN, "maximum outstanding commands "
- "changed during initialisation (was %u, now %u)",
- cpq->ctlr_maxcmds, check_again);
- return (EPROTO);
- }
-
- /* SG */
- max_sg_cnt = DDI_GET32(cpq, &ctp->MaxSGElements);
- max_blk_fetch_cnt = DDI_GET32(cpq, &ctp->MaxBlockFetchCount);
-
- /* 32 byte aligned - size_of_cmdlist */
- size_of_cmdlist = ((sizeof (CommandList_t) + 31) / 32) * 32;
- size_of_HRE = size_of_cmdlist -
- (sizeof (SGDescriptor_t) * CISS_MAXSGENTRIES);
-
- if ((max_blk_fetch_cnt == 0) || (max_sg_cnt == 0) ||
- ((max_blk_fetch_cnt * 16) <= size_of_HRE)) {
- cpq->sg_cnt = CPQARY3_PERF_SG_CNT;
- } else {
- /*
- * Get the optimal_sg - no of the SG's that will fit
- * into the max_blk_fetch_cnt
- */
-
- optimal_sg_size = (max_blk_fetch_cnt * 16) - size_of_HRE;
-
- if (optimal_sg_size < sizeof (SGDescriptor_t)) {
- optimal_sg = CPQARY3_PERF_SG_CNT;
- } else {
- optimal_sg = optimal_sg_size / sizeof (SGDescriptor_t);
- }
-
- cpq->sg_cnt = MIN(max_sg_cnt, optimal_sg);
-
- if (cpq->sg_cnt > MAX_PERF_SG_CNT) {
- cpq->sg_cnt = MAX_PERF_SG_CNT;
- }
- }
-
- /* SG */
-
- /*
- * Zero the Upper 32 Address in the Controller
- */
-
- DDI_PUT32(cpq, &ctp->HostWrite.Upper32Addr, 0x00000000);
-
- return (0);
-}
-#endif
-
-int
-cpqary3_ctlr_init(cpqary3_t *cpq)
-{
- uint8_t signature[4] = { 'C', 'I', 'S', 'S' };
- CfgTable_t *ctp = cpq->cpq_ct;
- int e;
-
- if ((e = cpqary3_ctlr_wait_for_state(cpq,
- CPQARY3_WAIT_STATE_READY) != DDI_SUCCESS)) {
- return (e);
- }
-
- /*
- * The configuration table contains an ASCII signature ("CISS") which
- * should be checked as we initialise the controller.
- * See: "9.1 Configuration Table" in CISS Specification.
- */
- for (unsigned i = 0; i < 4; i++) {
- if (ddi_get8(cpq->cpq_ct_handle, &cpq->cpq_ct->Signature[i]) !=
- signature[i]) {
- dev_err(cpq->dip, CE_WARN, "invalid signature "
- "detected");
- return (DDI_FAILURE);
- }
- }
-
-#if 0
- if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) {
- if ((e = cpqary3_ctlr_init_simple(cpqary3p)) != 0) {
- return (e);
- }
- } else {
- if ((e = cpqary3_ctlr_init_performant(cpqary3p)) != 0) {
- return (e);
- }
- }
-#else
- /*
- * XXX Let's just do Simple mode for now...
- */
- if ((e = cpqary3_ctlr_init_simple(cpq)) != 0) {
- return (e);
- }
-#endif
-
- cpq->cpq_host_support = cpqary3_ctlr_get_hostdrvsup(cpq);
-
- /*
- * Read initial controller heartbeat value and mark the current
- * reading time.
- */
- cpq->cpq_last_heartbeat = ddi_get32(cpq->cpq_ct_handle,
- &cpq->cpq_ct->HeartBeat);
- cpq->cpq_last_heartbeat_lbolt = ddi_get_lbolt();
-
- return (0);
-}
-
-int
-cpqary3_ctlr_wait_for_state(cpqary3_t *cpq, cpqary3_wait_state_t state)
-{
- VERIFY(state == CPQARY3_WAIT_STATE_READY ||
- state == CPQARY3_WAIT_STATE_UNREADY);
-
- /*
- * Read from the Scratchpad Register until the expected ready signature
- * is detected. This behaviour is not described in the CISS
- * specification.
- *
- * If the device is not in the desired state immediately, sleep for a
- * second and try again. If the device has not become ready in 300
- * seconds, give up.
- */
- for (unsigned i = 0; i < CPQARY3_WAIT_DELAY_SECONDS; i++) {
- uint32_t spr = cpqary3_get32(cpq, CISS_I2O_SCRATCHPAD);
-
- switch (state) {
- case CPQARY3_WAIT_STATE_READY:
- if (spr == CISS_SCRATCHPAD_INITIALISED) {
- return (DDI_SUCCESS);
- }
- break;
-
- case CPQARY3_WAIT_STATE_UNREADY:
- if (spr != CISS_SCRATCHPAD_INITIALISED) {
- return (DDI_SUCCESS);
- }
- break;
- }
-
- /*
- * Wait for a second and try again.
- */
- delay(drv_usectohz(1000000));
- }
-
- dev_err(cpq->dip, CE_WARN, "time out waiting for controller "
- "to enter state \"%s\"", state == CPQARY3_WAIT_STATE_READY ?
- "ready": "unready");
- return (DDI_FAILURE);
-}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_transport.c b/usr/src/uts/common/io/cpqary3/cpqary3_transport.c
index 15a751a2b0..bcb8365f15 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_transport.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_transport.c
@@ -24,7 +24,7 @@
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_transport(struct scsi_address *, struct scsi_pkt *);
+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_getcap(struct scsi_address *, char *, int);
@@ -41,8 +41,7 @@ static struct scsi_pkt *cpqary3_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 *);
-void cpqary3_oscmd_complete(cpqary3_command_t *);
-static uint8_t cpqary3_is_scsi_read_write(struct scsi_pkt *scsi_pktp);
+static boolean_t cpqary3_is_scsi_read_write(struct scsi_pkt *scsi_pktp);
/*
* External Variable Declarations
@@ -50,30 +49,21 @@ static uint8_t cpqary3_is_scsi_read_write(struct scsi_pkt *scsi_pktp);
extern ddi_dma_attr_t cpqary3_dma_attr;
-/*
- * Function : cpqary3_init_hbatran
- * Description : This routine initializes the transport vector in the
- * SCSA architecture for entry ponts in this driver.
- * Called By : cpqary3_attach()
- * Parameters : per_controller
- * Calls : None
- * Return Values: None
- */
void
-cpqary3_init_hbatran(cpqary3_t *ctlr)
+cpqary3_init_hbatran(cpqary3_t *cpq)
{
scsi_hba_tran_t *hba_tran;
ASSERT(ctlr != NULL);
- hba_tran = ctlr->hba_tran;
+ hba_tran = cpq->cpq_hba_tran;
/*
* Memory for the transport vector has been allocated by now.
* initialize all the entry points in this vector
*/
- hba_tran->tran_hba_private = (void *)ctlr;
+ hba_tran->tran_hba_private = cpq;
/* Target Driver Instance Initialization */
hba_tran->tran_tgt_init = cpqary3_tgt_init;
@@ -86,7 +76,7 @@ cpqary3_init_hbatran(cpqary3_t *ctlr)
hba_tran->tran_dmafree = cpqary3_dmafree;
/* Command Transport */
- hba_tran->tran_start = cpqary3_transport;
+ hba_tran->tran_start = cpqary3_tran_start;
/* Capability Management */
hba_tran->tran_getcap = cpqary3_getcap;
@@ -97,17 +87,6 @@ cpqary3_init_hbatran(cpqary3_t *ctlr)
hba_tran->tran_abort = cpqary3_abort;
}
-/*
- * Function : cpqary3_tgt_init ()
- * Description : This routine validates the target ID.
- * Called By : cpqary3_init_hbatran()
- * Parameters : HBA-instance, target instance, transport vector,
- * scsi-device structure
- * Calls : cpqary3_detect_target_geometry(),
- * cpqary3_probe4targets()
- * Return Values: DDI_SUCCESS : A Target exists at this ID.
- * DDI_FAILURE : No such target exists.
- */
/* ARGSUSED */
static int
cpqary3_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
@@ -164,14 +143,6 @@ cpqary3_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
return (DDI_SUCCESS);
}
-/*
- * Function : cpqary3_tgt_probe()
- * Description : This routine probes into the Target Details.
- * Called By : cpqary3_init_hbatran()
- * Parameters : scsi-device structure, calling function if any
- * Calls : None
- * Return Values: value returned by scsi_hba_probe()
- */
static int
cpqary3_tgt_probe(struct scsi_device *sd, int (*waitfunc)())
{
@@ -181,7 +152,6 @@ cpqary3_tgt_probe(struct scsi_device *sd, int (*waitfunc)())
* driver
*/
- /* HPQacucli Changes */
extern int8_t cpqary3_detect_target_geometry(cpqary3_t *);
struct scsi_hba_tran *hba_tran = sd->sd_address.a_hba_tran;
cpqary3_t *ctlr = hba_tran->tran_hba_private;
@@ -190,7 +160,6 @@ cpqary3_tgt_probe(struct scsi_device *sd, int (*waitfunc)())
(ctlr->cpq_ntargets > 0)) {
(void) cpqary3_detect_target_geometry(ctlr);
}
- /* HPQacucli Changes */
return (scsi_hba_probe(sd, waitfunc));
}
@@ -543,83 +512,127 @@ cpqary3_dma_move(struct scsi_pkt *scsi_pktp, struct buf *bp,
}
-/*
- * Function : cpqary3_transport()
- * Description : This routine services requests from the OS that are
- * directed towards the targets.(any SCSI command)
- * Called By : kernel
- * Parameters : SCSI address, SCSI packet, buffer
- * Calls : cpqary3_build_iop, cpqary3_add2submitted
- * Return Values: TRAN_ACCEPT : The driver accepts the command.
- * TRAN_BUSY : Required resources not available
- * at the moment.
- * TRAN_FATAL_ERROR: A target no longer exists.
- */
+static void
+cpqary3_set_arq_data(struct scsi_pkt *pkt, uchar_t key)
+{
+ struct scsi_arq_status *arqstat;
+
+ arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp);
+
+ arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */
+ arqstat->sts_rqpkt_reason = CMD_CMPLT;
+ arqstat->sts_rqpkt_resid = 0;
+ arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+ STATE_SENT_CMD | STATE_XFERRED_DATA;
+ arqstat->sts_rqpkt_statistics = 0;
+ 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
-cpqary3_transport(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
+cpqary3_tran_start(struct scsi_address *sa, struct scsi_pkt *scsi_pktp)
{
- cpqary3_t *ctlr;
- cpqary3_pkt_t *cpqary3_pktp;
- cpqary3_tgt_t *tgtp;
+ cpqary3_t *cpq = SA2CTLR(sa);
+ cpqary3_pkt_t *privp = PKT2PVTPKT(scsi_pktp);
+ cpqary3_tgt_t *tgtp;
cpqary3_command_t *cpcm;
int r;
+ boolean_t nointr = (scsi_pktp->pkt_flags & FLAG_NOINTR) != 0;
- ASSERT(sa != NULL);
- ctlr = SA2CTLR(sa);
- cpqary3_pktp = PKT2PVTPKT(scsi_pktp);
- tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)];
-
- if (!tgtp)
+ /*
+ * Determine the target to which this command is addressed.
+ */
+ if (SA2TGT(sa) >= CPQARY3_MAX_TGT ||
+ (tgtp = cpq->cpqary3_tgtp[SA2TGT(sa)]) == NULL ||
+ tgtp->type == CPQARY3_TARGET_NONE) {
+ /*
+ * This target does not exist.
+ */
return (TRAN_FATAL_ERROR);
+ }
- if (tgtp->type == CPQARY3_TARGET_NONE)
- return (TRAN_FATAL_ERROR);
+ /*
+ * Check to see if we need any special handling for this SCSI
+ * command.
+ */
+ switch (scsi_pktp->pkt_cdbp[0]) {
+ case SCMD_FORMAT:
+ case SCMD_LOG_SENSE_G1:
+ case SCMD_MODE_SELECT:
+ case SCMD_PERSISTENT_RESERVE_IN:
+ /*
+ * These SCSI commands are allegedly not supported by the
+ * controller firmware.
+ */
+ cpqary3_set_arq_data(scsi_pktp, KEY_ILLEGAL_REQUEST);
+ if (!nointr) {
+ (*scsi_pktp->pkt_comp)(scsi_pktp);
+ }
+ return (TRAN_ACCEPT);
- if (cpqary3_additional_cmd(scsi_pktp, ctlr))
+ case SCMD_SYNCHRONIZE_CACHE:
+ /*
+ * Emulate SYNCHRONIZE CACHE with the BMIC Flush Cache
+ * command.
+ */
+ 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;
+ } 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;
+ }
+ if (!nointr) {
+ (*scsi_pktp->pkt_comp)(scsi_pktp);
+ }
return (TRAN_ACCEPT);
+ }
/*
- * Attempt to occupy a free command memory block
- * If not successful, return TRAN_BUSY
- * Else, build the Command
- * Submit it to the controller
- * If NO_INTR flag is set, wait for the completion of the command and
- * when the command completes, update packet values appropriately and
- * return TRAN_ACCEPT.
- * Make an entry in the submitted Q
- * return TRAN_ACCEPT
+ * Allocate a command object for this transaction:
*/
-
- if ((cpcm = cpqary3_command_alloc(ctlr)) == NULL) {
+ if ((cpcm = cpqary3_command_alloc(cpq, CPQARY3_CMDTYPE_OS)) == NULL) {
+ /*
+ * Signal to the framework to back off.
+ */
return (TRAN_BUSY);
}
+ cpcm->cpcm_private = privp;
+ privp->cmd_command = cpcm;
- cpcm->cpcm_type = CPQARY3_CMDTYPE_OS;
- cpqary3_pktp->cmd_command = cpcm;
- cpcm->cpcm_private = cpqary3_pktp;
-
- if ((cpqary3_pktp->cmd_flags & DDI_DMA_CONSISTENT) &&
- cpqary3_pktp->cmd_dmahandle) {
- (void) ddi_dma_sync(cpqary3_pktp->cmd_dmahandle, 0, 0,
+ if ((privp->cmd_flags & DDI_DMA_CONSISTENT) && privp->cmd_dmahandle) {
+ (void) ddi_dma_sync(privp->cmd_dmahandle, 0, 0,
DDI_DMA_SYNC_FORDEV);
}
- VERIFY(cpqary3_pktp->cmd_cookiecnt <= ctlr->cpq_sg_cnt);
-
- cpcm->cpcm_complete = cpqary3_oscmd_complete;
+ VERIFY(privp->cmd_cookiecnt <= cpq->cpq_sg_cnt);
if (cpqary3_build_cmdlist(cpcm, SA2TGT(sa)) != CPQARY3_SUCCESS) {
goto fail;
}
- if ((scsi_pktp->pkt_flags & FLAG_NOINTR) != 0) {
+ if (nointr) {
+ /*
+ * This command was issued with the FLAG_NOINTR flag, so
+ * perform the necessary polling to collect the response
+ * synchronously.
+ */
return (cpqary3_handle_flag_nointr(cpcm, scsi_pktp));
}
- cpqary3_pktp->cmd_start_time = ddi_get_lbolt();
- mutex_enter(&ctlr->hw_mutex);
- r = cpqary3_submit(ctlr, cpcm);
- mutex_exit(&ctlr->hw_mutex);
+ mutex_enter(&cpq->hw_mutex);
+ r = cpqary3_submit(cpq, cpcm);
+ mutex_exit(&cpq->hw_mutex);
if (r != 0) {
goto fail;
}
@@ -917,218 +930,100 @@ cpqary3_setcap(struct scsi_address *sa, char *capstr, int value, int tgtonly)
}
}
-/*
- * Function : cpqary3_handle_flag_nointr
- * Description : This routine is called to handle submission and
- * subsequently poll for the completion of a command,
- * when its FLAG_NOINTR bit is set.
- * Called By : cpqary3_transport()
- * Parameters : command private structure, SCSI packet
- * Calls : cpqary3_intr_onoff, cpqary3_retrieve,
- * cpqary3_submit, cpqary3_poll
- * Return Values: TRAN_ACCEPT
- */
static int
cpqary3_handle_flag_nointr(cpqary3_command_t *cpcm, struct scsi_pkt *scsi_pktp)
{
- uint32_t tag = cpcm->cpcm_tag;
- uint32_t simple_tag;
- uint32_t i;
- cpqary3_t *ctlr = cpcm->cpcm_ctlr;
- cpqary3_cmdpvt_t *cpqary3_cmdpvtp;
- uint32_t CmdsOutMax;
- uint32_t no_cmds;
- int ret;
-
- /*
- * XXX this function is totally fucked with the mutexes and so on.
- * fix it.
- */
+ cpqary3_t *cpq = cpcm->cpcm_ctlr;
/*
* Before sumitting this command, ensure all commands pending
* with the controller are completed.
*/
- mutex_enter(&ctlr->sw_mutex);
- mutex_enter(&ctlr->hw_mutex);
- ctlr->cpq_intr_off = B_TRUE;
- cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE);
- if (ctlr->cpq_host_support & 0x4)
- cpqary3_lockup_intr_onoff(ctlr, CPQARY3_LOCKUP_INTR_DISABLE);
-
- while (avl_numnodes(&ctlr->cpq_inflight) > 0) {
- (void) cpqary3_retrieve(ctlr);
+ mutex_enter(&cpq->sw_mutex);
+ mutex_enter(&cpq->hw_mutex);
+ cpq->cpq_intr_off = B_TRUE;
+ cpqary3_intr_onoff(cpq, CPQARY3_INTR_DISABLE);
+ if (cpq->cpq_host_support & 0x4)
+ cpqary3_lockup_intr_onoff(cpq, CPQARY3_LOCKUP_INTR_DISABLE);
+
+ while (avl_numnodes(&cpq->cpq_inflight) > 0) {
+ (void) cpqary3_retrieve(cpq, 0, NULL);
drv_usecwait(1000);
}
- if (cpqary3_submit(ctlr, cpcm) != 0) {
- ctlr->cpq_intr_off = B_FALSE;
- cpqary3_intr_onoff(ctlr, CPQARY3_INTR_ENABLE);
- if (ctlr->cpq_host_support & 0x4) {
- cpqary3_lockup_intr_onoff(ctlr,
+ if (cpqary3_submit(cpq, cpcm) != 0) {
+ cpq->cpq_intr_off = B_FALSE;
+ cpqary3_intr_onoff(cpq, CPQARY3_INTR_ENABLE);
+ if (cpq->cpq_host_support & 0x4) {
+ cpqary3_lockup_intr_onoff(cpq,
CPQARY3_LOCKUP_INTR_ENABLE);
}
- mutex_exit(&ctlr->hw_mutex);
- mutex_exit(&ctlr->sw_mutex);
+ mutex_exit(&cpq->hw_mutex);
+ mutex_exit(&cpq->sw_mutex);
cpqary3_command_free(cpcm);
return (TRAN_FATAL_ERROR);
}
- if (cpqary3_poll(ctlr, tag) != CPQARY3_SUCCESS) {
+ 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;
- ctlr->cpq_intr_off = B_FALSE;
- cpqary3_intr_onoff(ctlr, CPQARY3_INTR_ENABLE);
- if (ctlr->cpq_host_support & 0x4) {
- cpqary3_lockup_intr_onoff(ctlr,
+ cpq->cpq_intr_off = B_FALSE;
+ cpqary3_intr_onoff(cpq, CPQARY3_INTR_ENABLE);
+ if (cpq->cpq_host_support & 0x4) {
+ cpqary3_lockup_intr_onoff(cpq,
CPQARY3_LOCKUP_INTR_ENABLE);
}
- mutex_exit(&ctlr->hw_mutex);
- mutex_exit(&ctlr->sw_mutex);
+ mutex_exit(&cpq->hw_mutex);
+ mutex_exit(&cpq->sw_mutex);
cpqary3_command_free(cpcm);
return (TRAN_ACCEPT);
}
- ctlr->cpq_intr_off = B_FALSE;
- cpqary3_intr_onoff(ctlr, CPQARY3_INTR_ENABLE);
- if (ctlr->cpq_host_support & 0x4) {
- cpqary3_lockup_intr_onoff(ctlr, CPQARY3_LOCKUP_INTR_ENABLE);
+ cpq->cpq_intr_off = B_FALSE;
+ cpqary3_intr_onoff(cpq, CPQARY3_INTR_ENABLE);
+ if (cpq->cpq_host_support & 0x4) {
+ cpqary3_lockup_intr_onoff(cpq, CPQARY3_LOCKUP_INTR_ENABLE);
}
- mutex_exit(&ctlr->hw_mutex);
- mutex_exit(&ctlr->sw_mutex);
+ mutex_exit(&cpq->hw_mutex);
+ mutex_exit(&cpq->sw_mutex);
return (TRAN_ACCEPT);
}
-/*
- * Function : cpqary3_poll
- * Description : This routine polls for the completion of a command.
- * Called By : cpqary3_handle_flag_nointr
- * Parameters : per controller, tag of the command to be polled
- * Calls : cpqary3_poll_retrieve
- * Return Values: TRAN_ACCEPT
- */
static int
cpqary3_poll(cpqary3_t *cpq, uint32_t tag)
{
- boolean_t found = B_FALSE;
- unsigned tries = 0;
-
VERIFY(MUTEX_HELD(&cpq->hw_mutex));
VERIFY(MUTEX_HELD(&cpq->sw_mutex));
/*
- * XXX
- * POLL for the completion of the said command
- * Since, we had ensured that controller is empty, we need not
- * check for the complete Retrieved Q.
- * However, we just check the Retrieved Q and complete all
- * commands in it, inclusive of the polled command.
- * if the polled command is completed, send back a success.
+ * 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;
-retry:
- switch (cpq->cpq_ctlr_mode) {
- case CPQARY3_CTLR_MODE_SIMPLE:
- cpqary3_retrieve_simple(cpq, tag, &found);
- break;
- case CPQARY3_CTLR_MODE_PERFORMANT:
- cpqary3_retrieve_performant(cpq, tag, &found);
- break;
- default:
- panic("unknown controller mode");
- }
-
- if (found) {
- return (CPQARY3_SUCCESS);
- }
-
- if (tries++ < 120000) {
- drv_usecwait(500);
- goto retry;
- }
-
- return (CPQARY3_FAILURE);
-}
-
-static int
-cpqary3_additional_cmd(struct scsi_pkt *scsi_pktp, cpqary3_t *ctlr)
-{
- struct scsi_arq_status *arqstat;
- /* LINTED: alignment */
- arqstat = (struct scsi_arq_status *)(scsi_pktp->pkt_scbp);
-
- switch (scsi_pktp->pkt_cdbp[0]) {
- case 0x35: /* Synchronize Cache */
-
- cpqary3_flush_cache(ctlr);
-
- 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;
+ (void) cpqary3_retrieve(cpq, tag, &found);
- if (scsi_pktp->pkt_comp) {
- (*scsi_pktp->pkt_comp)(scsi_pktp);
+ if (found) {
+ return (DDI_SUCCESS);
}
- return (1);
-
- case 0x04: /* Format Unit */
- cmn_err(CE_NOTE, "The FORMAT UNIT is not supported by this "
- "device If this option is selected from the format utility "
- "do not continue further. Please refer to cpqary3 driver "
- "man pages for details.");
-
- return (0);
- case SCSI_LOG_SENSE:
- case SCSI_MODE_SELECT:
- case SCSI_PERSISTENT_RESERVE_IN:
- arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */
- arqstat->sts_rqpkt_reason = CMD_CMPLT;
- arqstat->sts_rqpkt_resid = 0;
- arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
- STATE_SENT_CMD | STATE_XFERRED_DATA;
- arqstat->sts_rqpkt_statistics = 0;
- arqstat->sts_sensedata.es_valid = 1;
- arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
- arqstat->sts_sensedata.es_key = KEY_ILLEGAL_REQUEST;
- scsi_pktp->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
- STATE_SENT_CMD | STATE_XFERRED_DATA;
-
- if (scsi_pktp->pkt_comp) {
- (*scsi_pktp->pkt_comp)(scsi_pktp);
- }
- return (1);
+ drv_usecwait(500);
}
- return (0);
+ return (DDI_FAILURE);
}
-/* PERF */
-/*
- * Function : cpqary3_oscmd_complete
- * Description : This routine processes the
- * completed OS commands and
- * initiates any callback that is needed.
- * Called By : cpqary3_transport
- * Parameters : per-command
- * Calls : cpqary3_ioctl_send_bmiccmd,
- * cpqary3_ioctl_send_scsicmd,
- * cpqary3_send_abortcmd, cpqary3_flush_cache,
- * cpqary3_probe4LVs,
- * cpqary3_probe4Tapes, cpqary3_synccmd_complete,
- * cpqary3_detect_target_geometry,
- * cpqary3_detect_target_geometry
- * Return Values: None
- */
void
cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
{
@@ -1136,18 +1031,11 @@ cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
ErrorInfo_t *errorinfop = cpcm->cpcm_va_err;
CommandList_t *cmdlistp = cpcm->cpcm_va_cmd;
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(cpcm->cpcm_type == CPQARY3_CMDTYPE_OS);
- /*
- * XXX oops?
- */
- if (cpcm->cpcm_free_on_complete) {
- cpqary3_command_free(cpcm);
- return;
- }
-
if (cmdlistp->Header.Tag.error != 0) {
mutex_exit(&cpqary3p->sw_mutex);
@@ -1159,13 +1047,8 @@ cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
STATE_GOT_TARGET | STATE_SENT_CMD |
STATE_XFERRED_DATA | STATE_GOT_STATUS;
- /*
- * XXX this is suspect...
- */
if ((scsi_pktp->pkt_flags & FLAG_NOINTR) == 0) {
- if (scsi_pktp->pkt_comp != NULL) {
- (*scsi_pktp->pkt_comp)(scsi_pktp);
- }
+ (*scsi_pktp->pkt_comp)(scsi_pktp);
}
mutex_enter(&cpqary3p->sw_mutex);
@@ -1269,7 +1152,7 @@ cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
scsi_pktp->pkt_statistics;
bcopy((caddr_t)&errorinfop->SenseInfo[0],
(caddr_t)(&arq_statusp->sts_sensedata),
- CPQARY3_MIN(errorinfop->SenseLen,
+ MIN(errorinfop->SenseLen,
cpcm->cpcm_private->scb_len));
scsi_pktp->pkt_state |= STATE_ARQ_DONE;
}
@@ -1279,19 +1162,14 @@ cpqary3_oscmd_complete(cpqary3_command_t *cpcm)
cpqary3_command_free(cpcm);
- /*
- * XXX this is also suspicious.
- */
- if ((scsi_pktp->pkt_flags & FLAG_NOINTR) == 0) {
- if (scsi_pktp->pkt_comp != NULL) {
- (*scsi_pktp->pkt_comp)(scsi_pktp);
- }
+ if (!nointr) {
+ (*scsi_pktp->pkt_comp)(scsi_pktp);
}
mutex_enter(&cpqary3p->sw_mutex);
}
-static uint8_t
+static boolean_t
cpqary3_is_scsi_read_write(struct scsi_pkt *scsi_pktp)
{
/*
@@ -1299,17 +1177,16 @@ cpqary3_is_scsi_read_write(struct scsi_pkt *scsi_pktp)
* OpCode. We check to see if it is any one of the SCSI Read or Write
* opcodes.
*/
-
switch (scsi_pktp->pkt_cdbp[0]) {
- case SCSI_READ_6:
- case SCSI_READ_10:
- case SCSI_READ_12:
- case SCSI_WRITE_6:
- case SCSI_WRITE_10:
- case SCSI_WRITE_12:
- return (1);
+ case SPC3_CMD_READ6:
+ case SPC3_CMD_READ10:
+ case SPC3_CMD_READ12:
+ case SPC3_CMD_WRITE6:
+ case SPC3_CMD_WRITE10:
+ case SPC3_CMD_WRITE12:
+ return (B_TRUE);
default:
- return (0);
+ return (B_FALSE);
}
}
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_util.c b/usr/src/uts/common/io/cpqary3/cpqary3_util.c
index 88d3a6852f..66ec332dde 100644
--- a/usr/src/uts/common/io/cpqary3/cpqary3_util.c
+++ b/usr/src/uts/common/io/cpqary3/cpqary3_util.c
@@ -188,13 +188,11 @@ cpqary3_synccmd_alloc(cpqary3_t *cpq, size_t bufsz)
{
cpqary3_command_t *cpcm;
- if ((cpcm = cpqary3_command_alloc(cpq)) == NULL) {
+ if ((cpcm = cpqary3_command_alloc(cpq, CPQARY3_CMDTYPE_SYNCCMD)) ==
+ NULL) {
return (NULL);
}
- cpcm->cpcm_type = CPQARY3_CMDTYPE_SYNCCMD;
- cpcm->cpcm_complete = cpqary3_synccmd_complete;
-
if (bufsz == 0) {
return (cpcm);
}
@@ -407,15 +405,14 @@ cpqary3_detect_target_geometry(cpqary3_t *ctlr)
cmdlistp = cpcm->cpcm_va_cmd;
idlogdrive = cpcm->cpcm_internal->cpcmi_va;
- /* Cmd Reques */
cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16;
- cmdlistp->Request.CDB[0] = 0x26;
- cmdlistp->Request.CDB[6] = BMIC_IDENTIFY_LOGICAL_DRIVE;
- cmdlistp->Request.CDB[7] = (sizeof (IdLogDrive) >> 8) & 0xff;
- cmdlistp->Request.CDB[8] = sizeof (IdLogDrive) & 0xff;
cmdlistp->Request.Type.Type = CISS_TYPE_CMD;
cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE;
cmdlistp->Request.Type.Direction = CISS_XFER_READ;
+ cmdlistp->Request.CDB[0] = CISS_SCMD_ARRAY_READ;
+ cmdlistp->Request.CDB[6] = BMIC_IDENTIFY_LOGICAL_DRIVE;
+ cmdlistp->Request.CDB[7] = (sizeof (IdLogDrive) >> 8) & 0xff;
+ cmdlistp->Request.CDB[8] = sizeof (IdLogDrive) & 0xff;
/*
* For all the Targets that exist, issue an IDENTIFY LOGICAL DRIVE.
@@ -460,8 +457,6 @@ cpqary3_detect_target_geometry(cpqary3_t *ctlr)
(cmdlistp->Header.LUN.PhysDev.Bus > 0) ?
MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR;
- cpcm->cpcm_complete = cpqary3_synccmd_complete;
-
/*
* Submit the command
* Poll for its completion
@@ -471,6 +466,8 @@ cpqary3_detect_target_geometry(cpqary3_t *ctlr)
* faulty !!!)
*/
+ cpqary3_command_reuse(cpcm);
+
if (cpqary3_synccmd_send(ctlr, cpcm, 90000,
CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) {
/* Timed out */