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