diff options
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/uts/common/Makefile.files | 12 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3.c | 78 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3.h | 137 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_ciss.c | 445 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_ciss_performant.c | 320 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_ciss_simple.c | 194 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_commands.c | 203 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_ioctl.c | 16 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_isr.c | 158 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_mem.c | 147 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_mem.h | 41 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_q_mem.h | 103 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_scsi.c | 36 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_scsi.h | 43 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c | 865 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_transport.c | 435 | ||||
| -rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_util.c | 19 |
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 */ |
