Print this page
Code reconciliation with other base.
hg changesets 607a5b46a793..b706c96317c3
Fix ncpus for early boot config
Purge the ack to the interrupt before exiting mptsas_intr()
Changes from code review
Optimise slot alocation through rotor and the use
of per target mutex in start path.
Update tx waitq's code.
Create 2 threads, divide the workflow and deliver
to the hardware from the threads.
Optimise mutex's and code paths.
Split out offline target code.
Test timeouts code
Add support for more than 8 MSI-X interrupts.
Tidy up interrupt assignement and card ID messages.
Enable Fast Path for capable devices.
Merge fixes for Illumos issue 4819, fix mpt_sas command timeout handling.
Tweeks debug flags.
Default to process done commands all in threads if only 1 interrupt.
Lint and cstyle fixes.
Fix problem with running against 64bit msgaddr attributes for DMA.
Default is now to run like this.
Don't take tx_waiq_mutex if draining isn't set.
Fixes for Illumos issue 4682.
Fix hang bug to do with tx_wq.
Re-arrange mptsas_poll() to disable interrupts before issuing the
command.
Improve the tx_waitq code path.
Major rework of mutexes.
During normal operation do not grab m_mutex during interrupt.
Use reply post queues instead.
Make a few variable non static so you can change in /etc/system.
Fixes to some address arithmetic using 32bit values.
Distribute command done processing around the threads.
Improved auto-request sense memory usage.
Fix for Nexenta commit 36c74113a21
OS-91 mptsas does inquiry without setting pkt_time
Add comment about testing.
Test firmware version of 2008 controllers for MSI-X Compatibility.
Re-arrange mptsas_intr() to reduce number of spurious interrupts.
Fix bug in mptsas_free_post_queue().
Change mptsas_doneq_mv() to not loop.
Should not need m_in_callback flag. It prevents concurrent
command completion processing.
Added code to support using MSI-X interrupts across multiple
reply queues. Not tested with anything other than 3008 yet.
Change output "mptsas%d" -> "mptsas3%d".
Add SAS3 specific messages (12.0Gb).
Allow over-ride for interrupt type.
Restrict pre MPI2.5 to MSI interrupts.
Allow watchdog timout to work for mptsas_smhba_setup() in attach().
Merge fixes for "4403 mpt_sas panic when pulling a drive", commit f7d0d869a9ae78d
Use MSI-X interrupts, just one for now.
Pre-allocate array for request sense buffers, similar to command frames.
No more messing about with scsi_alloc_consistent_buf().
Add rolling buffer for *all* debug messages.
Improve mdb module and seperate out into mpt_sas3.
Initial modifications using the code changes present between
the LSI source code for FreeBSD drivers. Specifically the changes
between from mpslsi-source-17.00.00.00 -> mpslsi-source-03.00.00.00.
This mainly involves using a different scatter/gather element in
frame setup.
Change some obvious references sas -> sas3.
Changes to enable driver to compile.
Header paths, object lists, etc.

*** 19,30 **** * CDDL HEADER END */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ /* * Copyright (c) 2000 to 2010, LSI Corporation. * All rights reserved. --- 19,32 ---- * CDDL HEADER END */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. + * Copyright (c) 2014, Tegile Systems Inc. All rights reserved. + * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved. */ /* * Copyright (c) 2000 to 2010, LSI Corporation. * All rights reserved.
*** 51,61 **** * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ /* ! * mptsas - This is a driver based on LSI Logic's MPT2.0 interface. * */ #if defined(lint) || defined(DEBUG) #define MPTSAS_DEBUG --- 53,63 ---- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ /* ! * mptsas3 - This is a driver based on LSI Logic's MPT2.0/2.5 interface. * */ #if defined(lint) || defined(DEBUG) #define MPTSAS_DEBUG
*** 76,104 **** #include <sys/sata/sata_defs.h> #include <sys/scsi/generic/sas.h> #include <sys/scsi/impl/scsi_sas.h> #pragma pack(1) ! #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h> ! #include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h> ! #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h> ! #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h> ! #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h> ! #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h> ! #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h> ! #include <sys/scsi/adapters/mpt_sas/mpi/mpi2_raid.h> #pragma pack() /* * private header files. * */ #include <sys/scsi/impl/scsi_reset_notify.h> ! #include <sys/scsi/adapters/mpt_sas/mptsas_var.h> ! #include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h> ! #include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h> ! #include <sys/scsi/adapters/mpt_sas/mptsas_hash.h> #include <sys/raidioctl.h> #include <sys/fs/dv_node.h> /* devfs_clean */ /* --- 78,106 ---- #include <sys/sata/sata_defs.h> #include <sys/scsi/generic/sas.h> #include <sys/scsi/impl/scsi_sas.h> #pragma pack(1) ! #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_type.h> ! #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2.h> ! #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_cnfg.h> ! #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_init.h> ! #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_ioc.h> ! #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_sas.h> ! #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_tool.h> ! #include <sys/scsi/adapters/mpt_sas3/mpi/mpi2_raid.h> #pragma pack() /* * private header files. * */ #include <sys/scsi/impl/scsi_reset_notify.h> ! #include <sys/scsi/adapters/mpt_sas3/mptsas3_var.h> ! #include <sys/scsi/adapters/mpt_sas3/mptsas3_ioctl.h> ! #include <sys/scsi/adapters/mpt_sas3/mptsas3_smhba.h> ! #include <sys/scsi/adapters/mpt_sas3/mptsas3_hash.h> #include <sys/raidioctl.h> #include <sys/fs/dv_node.h> /* devfs_clean */ /*
*** 142,154 **** --- 144,158 ---- static int mptsas_smp_setup(mptsas_t *mpt); static void mptsas_smp_teardown(mptsas_t *mpt); static int mptsas_cache_create(mptsas_t *mpt); static void mptsas_cache_destroy(mptsas_t *mpt); static int mptsas_alloc_request_frames(mptsas_t *mpt); + static int mptsas_alloc_sense_bufs(mptsas_t *mpt); static int mptsas_alloc_reply_frames(mptsas_t *mpt); static int mptsas_alloc_free_queue(mptsas_t *mpt); static int mptsas_alloc_post_queue(mptsas_t *mpt); + static void mptsas_free_post_queue(mptsas_t *mpt); static void mptsas_alloc_reply_args(mptsas_t *mpt); static int mptsas_alloc_extra_sgl_frame(mptsas_t *mpt, mptsas_cmd_t *cmd); static void mptsas_free_extra_sgl_frame(mptsas_t *mpt, mptsas_cmd_t *cmd); static int mptsas_init_chip(mptsas_t *mpt, int first_time);
*** 199,211 **** static void mptsas_free_handshake_msg(mptsas_t *mpt); static void mptsas_ncmds_checkdrain(void *arg); static int mptsas_prepare_pkt(mptsas_cmd_t *cmd); ! static int mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *sp); ! static int mptsas_accept_txwq_and_pkt(mptsas_t *mpt, mptsas_cmd_t *sp); ! static void mptsas_accept_tx_waitq(mptsas_t *mpt); static int mptsas_do_detach(dev_info_t *dev); static int mptsas_do_scsi_reset(mptsas_t *mpt, uint16_t devhdl); static int mptsas_do_scsi_abort(mptsas_t *mpt, int target, int lun, struct scsi_pkt *pkt); --- 203,220 ---- static void mptsas_free_handshake_msg(mptsas_t *mpt); static void mptsas_ncmds_checkdrain(void *arg); static int mptsas_prepare_pkt(mptsas_cmd_t *cmd); ! static void mptsas_retry_pkt(mptsas_t *mpt, mptsas_cmd_t *sp); ! static int mptsas_save_cmd_to_slot(mptsas_t *mpt, mptsas_cmd_t *cmd); ! static int mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *sp, ! int *tran_rval); ! static void mptsas_accept_tx_waitqs(mptsas_t *mpt); ! static void mptsas_unblock_tx_waitqs(mptsas_t *mpt); ! static void mptsas_drain_tx_waitq(mptsas_t *mpt, mptsas_tx_waitqueue_t *txwq); ! static int mptsas_check_targ_intxtion(mptsas_target_t *ptgt, int cmd_pkt_flags); static int mptsas_do_detach(dev_info_t *dev); static int mptsas_do_scsi_reset(mptsas_t *mpt, uint16_t devhdl); static int mptsas_do_scsi_abort(mptsas_t *mpt, int target, int lun, struct scsi_pkt *pkt);
*** 225,252 **** uint8_t tasktype); static void mptsas_set_pkt_reason(mptsas_t *mpt, mptsas_cmd_t *cmd, uchar_t reason, uint_t stat); static uint_t mptsas_intr(caddr_t arg1, caddr_t arg2); ! static void mptsas_process_intr(mptsas_t *mpt, pMpi2ReplyDescriptorsUnion_t reply_desc_union); static void mptsas_handle_scsi_io_success(mptsas_t *mpt, ! pMpi2ReplyDescriptorsUnion_t reply_desc); static void mptsas_handle_address_reply(mptsas_t *mpt, pMpi2ReplyDescriptorsUnion_t reply_desc); static int mptsas_wait_intr(mptsas_t *mpt, int polltime); static void mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control, pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl); static void mptsas_watch(void *arg); static void mptsas_watchsubr(mptsas_t *mpt); ! static void mptsas_cmd_timeout(mptsas_t *mpt, uint16_t devhdl); static void mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd); static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply, uint8_t *data, uint32_t request_size, uint32_t reply_size, ! uint32_t data_size, uint32_t direction, uint8_t *dataout, uint32_t dataout_size, short timeout, int mode); static int mptsas_free_devhdl(mptsas_t *mpt, uint16_t devhdl); static uint8_t mptsas_get_fw_diag_buffer_number(mptsas_t *mpt, uint32_t unique_id); --- 234,261 ---- uint8_t tasktype); static void mptsas_set_pkt_reason(mptsas_t *mpt, mptsas_cmd_t *cmd, uchar_t reason, uint_t stat); static uint_t mptsas_intr(caddr_t arg1, caddr_t arg2); ! static void mptsas_process_intr(mptsas_t *mpt, mptsas_reply_pqueue_t *rpqp, pMpi2ReplyDescriptorsUnion_t reply_desc_union); static void mptsas_handle_scsi_io_success(mptsas_t *mpt, ! mptsas_reply_pqueue_t *rpqp, pMpi2ReplyDescriptorsUnion_t reply_desc); static void mptsas_handle_address_reply(mptsas_t *mpt, pMpi2ReplyDescriptorsUnion_t reply_desc); static int mptsas_wait_intr(mptsas_t *mpt, int polltime); static void mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control, pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl); static void mptsas_watch(void *arg); static void mptsas_watchsubr(mptsas_t *mpt); ! static void mptsas_cmd_timeout(mptsas_t *mpt, mptsas_target_t *ptgt); static void mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd); static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply, uint8_t *data, uint32_t request_size, uint32_t reply_size, ! uint32_t data_size, uint8_t direction, uint8_t *dataout, uint32_t dataout_size, short timeout, int mode); static int mptsas_free_devhdl(mptsas_t *mpt, uint16_t devhdl); static uint8_t mptsas_get_fw_diag_buffer_number(mptsas_t *mpt, uint32_t unique_id);
*** 297,324 **** static int mptsas_start_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd); static void mptsas_restart_hba(mptsas_t *mpt); static void mptsas_restart_waitq(mptsas_t *mpt); ! static void mptsas_deliver_doneq_thread(mptsas_t *mpt); static void mptsas_doneq_add(mptsas_t *mpt, mptsas_cmd_t *cmd); ! static void mptsas_doneq_mv(mptsas_t *mpt, uint64_t t); static mptsas_cmd_t *mptsas_doneq_thread_rm(mptsas_t *mpt, uint64_t t); static void mptsas_doneq_empty(mptsas_t *mpt); ! static void mptsas_doneq_thread(mptsas_doneq_thread_arg_t *arg); static mptsas_cmd_t *mptsas_waitq_rm(mptsas_t *mpt); static void mptsas_waitq_delete(mptsas_t *mpt, mptsas_cmd_t *cmd); - static mptsas_cmd_t *mptsas_tx_waitq_rm(mptsas_t *mpt); - static void mptsas_tx_waitq_delete(mptsas_t *mpt, mptsas_cmd_t *cmd); - static void mptsas_start_watch_reset_delay(); static void mptsas_setup_bus_reset_delay(mptsas_t *mpt); static void mptsas_watch_reset_delay(void *arg); static int mptsas_watch_reset_delay_subr(mptsas_t *mpt); /* * helper functions */ static void mptsas_dump_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd); --- 306,341 ---- static int mptsas_start_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd); static void mptsas_restart_hba(mptsas_t *mpt); static void mptsas_restart_waitq(mptsas_t *mpt); ! static void mptsas_deliver_doneq_thread(mptsas_t *mpt, ! mptsas_done_list_t *dlist); static void mptsas_doneq_add(mptsas_t *mpt, mptsas_cmd_t *cmd); ! static void mptsas_rpdoneq_add(mptsas_t *mpt, mptsas_reply_pqueue_t *rpqp, ! mptsas_cmd_t *cmd); ! static void mptsas_doneq_mv(mptsas_done_list_t *from, ! mptsas_doneq_thread_list_t *item); static mptsas_cmd_t *mptsas_doneq_thread_rm(mptsas_t *mpt, uint64_t t); static void mptsas_doneq_empty(mptsas_t *mpt); ! static void mptsas_rpdoneq_empty(mptsas_reply_pqueue_t *rpqp); ! static void mptsas_doneq_thread(mptsas_thread_arg_t *arg); ! static void mptsas_tx_waitq_thread(mptsas_thread_arg_t *arg); static mptsas_cmd_t *mptsas_waitq_rm(mptsas_t *mpt); static void mptsas_waitq_delete(mptsas_t *mpt, mptsas_cmd_t *cmd); static void mptsas_start_watch_reset_delay(); static void mptsas_setup_bus_reset_delay(mptsas_t *mpt); static void mptsas_watch_reset_delay(void *arg); static int mptsas_watch_reset_delay_subr(mptsas_t *mpt); + static void mptsas_set_throttle(struct mptsas *mpt, mptsas_target_t *ptgt, + int what); + static void mptsas_set_throttle_mtx(struct mptsas *mpt, mptsas_target_t *ptgt, + int what); + static void mptsas_remove_cmd_nomtx(mptsas_t *mpt, mptsas_cmd_t *cmd); /* * helper functions */ static void mptsas_dump_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd);
*** 367,377 **** dev_info_t **lundip); static int mptsas_config_one_phy(dev_info_t *pdip, uint8_t phy, int lun, dev_info_t **lundip); static int mptsas_config_target(dev_info_t *pdip, mptsas_target_t *ptgt); ! static int mptsas_offline_target(dev_info_t *pdip, char *name); static int mptsas_config_raid(dev_info_t *pdip, uint16_t target, dev_info_t **dip); static int mptsas_config_luns(dev_info_t *pdip, mptsas_target_t *ptgt); --- 384,396 ---- dev_info_t **lundip); static int mptsas_config_one_phy(dev_info_t *pdip, uint8_t phy, int lun, dev_info_t **lundip); static int mptsas_config_target(dev_info_t *pdip, mptsas_target_t *ptgt); ! static int mptsas_offline_targetdev(dev_info_t *pdip, char *name); ! static void mptsas_offline_target(mptsas_t *mpt, mptsas_target_t *ptgt, ! uint8_t topo_flags, dev_info_t *parent); static int mptsas_config_raid(dev_info_t *pdip, uint16_t target, dev_info_t **dip); static int mptsas_config_luns(dev_info_t *pdip, mptsas_target_t *ptgt);
*** 423,434 **** --- 442,459 ---- * MPT MSI tunable: * * By default MSI is enabled on all supported platforms. */ boolean_t mptsas_enable_msi = B_TRUE; + boolean_t mptsas_enable_msix = B_TRUE; boolean_t mptsas_physical_bind_failed_page_83 = B_FALSE; + /* + * Global switch for use of MPI2.5 FAST PATH. + */ + boolean_t mptsas3_use_fastpath = B_TRUE; + static int mptsas_register_intrs(mptsas_t *); static void mptsas_unregister_intrs(mptsas_t *); static int mptsas_add_intrs(mptsas_t *, int); static void mptsas_rem_intrs(mptsas_t *);
*** 438,447 **** --- 463,480 ---- static void mptsas_fm_init(mptsas_t *mpt); static void mptsas_fm_fini(mptsas_t *mpt); static int mptsas_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *); extern pri_t minclsyspri, maxclsyspri; + /* + * NCPUS is used to determine some optimal configurations for number + * of threads created to perform specific jobs. If we are invoked because + * a disk is part of the root file system ncpus may still be 1 so check + * boot_ncpus as well. + */ + extern int ncpus, boot_ncpus; + #define NCPUS max(ncpus, boot_ncpus) /* * This device is created by the SCSI pseudo nexus driver (SCSI vHCI). It is * under this device that the paths to a physical device are created when * MPxIO is used.
*** 453,462 **** --- 486,502 ---- * By default the value is 30 seconds. */ int mptsas_inq83_retry_timeout = 30; /* + * Tunable for default SCSI pkt timeout. Defaults to 5 seconds, which should + * be plenty for INQUIRY and REPORT_LUNS, which are the only commands currently + * issued by mptsas directly. + */ + int mptsas_scsi_pkt_time = 5; + + /* * This is used to allocate memory for message frame storage, not for * data I/O DMA. All message frames must be stored in the first 4G of * physical memory. */ ddi_dma_attr_t mptsas_dma_attrs = {
*** 488,498 **** 1, /* minxfer - gran. of DMA engine */ 0x00ffffffull, /* maxxfer - gran. of DMA engine */ 0xffffffffull, /* max segment size (DMA boundary) */ MPTSAS_MAX_DMA_SEGS, /* scatter/gather list length */ 512, /* granularity - device transfer size */ ! DDI_DMA_RELAXED_ORDERING /* flags, enable relaxed ordering */ }; ddi_device_acc_attr_t mptsas_dev_attr = { DDI_DEVICE_ATTR_V1, DDI_STRUCTURE_LE_ACC, --- 528,538 ---- 1, /* minxfer - gran. of DMA engine */ 0x00ffffffull, /* maxxfer - gran. of DMA engine */ 0xffffffffull, /* max segment size (DMA boundary) */ MPTSAS_MAX_DMA_SEGS, /* scatter/gather list length */ 512, /* granularity - device transfer size */ ! 0 /* flags, set to 0 */ }; ddi_device_acc_attr_t mptsas_dev_attr = { DDI_DEVICE_ATTR_V1, DDI_STRUCTURE_LE_ACC,
*** 543,553 **** mptsas_quiesce /* quiesce */ #endif /* __sparc */ }; ! #define MPTSAS_MOD_STRING "MPTSAS HBA Driver 00.00.00.24" static struct modldrv modldrv = { &mod_driverops, /* Type of module. This one is a driver */ MPTSAS_MOD_STRING, /* Name of the module. */ &mptsas_ops, /* driver ops */ --- 583,593 ---- mptsas_quiesce /* quiesce */ #endif /* __sparc */ }; ! #define MPTSAS_MOD_STRING "MPTSAS3 HBA Driver 00.00.01" static struct modldrv modldrv = { &mod_driverops, /* Type of module. This one is a driver */ MPTSAS_MOD_STRING, /* Name of the module. */ &mptsas_ops, /* driver ops */
*** 566,581 **** /* * Local static data */ #if defined(MPTSAS_DEBUG) ! uint32_t mptsas_debug_flags = 0; #endif /* defined(MPTSAS_DEBUG) */ uint32_t mptsas_debug_resets = 0; static kmutex_t mptsas_global_mutex; ! static void *mptsas_state; /* soft state ptr */ static krwlock_t mptsas_global_rwlock; static kmutex_t mptsas_log_mutex; static char mptsas_log_buf[256]; _NOTE(MUTEX_PROTECTS_DATA(mptsas_log_mutex, mptsas_log_buf)) --- 606,628 ---- /* * Local static data */ #if defined(MPTSAS_DEBUG) ! uint32_t mptsas_debug_flags = 0x0; ! /* ! * Flags to ignore these messages in local debug ring buffer. ! * Default is to ignore the watchsubr() output which normally happens ! * every second. ! */ ! uint32_t mptsas_dbglog_imask = 0x40000000; ! uint32_t mptsas_test_timeout = 0; #endif /* defined(MPTSAS_DEBUG) */ uint32_t mptsas_debug_resets = 0; static kmutex_t mptsas_global_mutex; ! static void *mptsas3_state; /* soft state ptr */ static krwlock_t mptsas_global_rwlock; static kmutex_t mptsas_log_mutex; static char mptsas_log_buf[256]; _NOTE(MUTEX_PROTECTS_DATA(mptsas_log_mutex, mptsas_log_buf))
*** 584,593 **** --- 631,669 ---- static clock_t mptsas_scsi_watchdog_tick; static clock_t mptsas_tick; static timeout_id_t mptsas_reset_watch; static timeout_id_t mptsas_timeout_id; static int mptsas_timeouts_enabled = 0; + + /* + * Maximum number of MSI-X interrupts any instance of mptsas3 can use. + * Note that if you want to increase this you may have to also bump the + * value of ddi_msix_alloc_limit which defaults to 8. + * Set to zero to fall back to other interrupt types. + */ + int mptsas3_max_msix_intrs = 8; + + /* + * Default length for extended auto request sense buffers. + * All sense buffers need to be under the same alloc because there + * is only one common top 32bits (of 64bits) address register. + * Most requests only require 32 bytes, but some request >256. + * We use rmalloc()/rmfree() on this additional memory to manage the + * "extended" requests. + */ + int mptsas_extreq_sense_bufsize = 256*64; + + /* + * Believe that all software resrictions of having to run with DMA + * attributes to limit allocation to the first 4G are removed. + * However, this flag remains to enable quick switchback should suspicious + * problems emerge. + * Note that scsi_alloc_consistent_buf() does still adhering to allocating + * 32 bit addressable memory, but we can cope if that is changed now. + */ + int mptsas_use_64bit_msgaddr = 1; + /* * warlock directives */ _NOTE(SCHEME_PROTECTS_DATA("unique per pkt", scsi_pkt \ mptsas_cmd NcrTableIndirect buf scsi_cdb scsi_status))
*** 617,634 **** /* CONSTCOND */ ASSERT(NO_COMPETING_THREADS); NDBG0(("_init")); ! status = ddi_soft_state_init(&mptsas_state, MPTSAS_SIZE, MPTSAS_INITIAL_SOFT_SPACE); if (status != 0) { return (status); } if ((status = scsi_hba_init(&modlinkage)) != 0) { ! ddi_soft_state_fini(&mptsas_state); return (status); } mutex_init(&mptsas_global_mutex, NULL, MUTEX_DRIVER, NULL); rw_init(&mptsas_global_rwlock, NULL, RW_DRIVER, NULL); --- 693,710 ---- /* CONSTCOND */ ASSERT(NO_COMPETING_THREADS); NDBG0(("_init")); ! status = ddi_soft_state_init(&mptsas3_state, MPTSAS_SIZE, MPTSAS_INITIAL_SOFT_SPACE); if (status != 0) { return (status); } if ((status = scsi_hba_init(&modlinkage)) != 0) { ! ddi_soft_state_fini(&mptsas3_state); return (status); } mutex_init(&mptsas_global_mutex, NULL, MUTEX_DRIVER, NULL); rw_init(&mptsas_global_rwlock, NULL, RW_DRIVER, NULL);
*** 636,646 **** if ((status = mod_install(&modlinkage)) != 0) { mutex_destroy(&mptsas_log_mutex); rw_destroy(&mptsas_global_rwlock); mutex_destroy(&mptsas_global_mutex); ! ddi_soft_state_fini(&mptsas_state); scsi_hba_fini(&modlinkage); } return (status); } --- 712,722 ---- if ((status = mod_install(&modlinkage)) != 0) { mutex_destroy(&mptsas_log_mutex); rw_destroy(&mptsas_global_rwlock); mutex_destroy(&mptsas_global_mutex); ! ddi_soft_state_fini(&mptsas3_state); scsi_hba_fini(&modlinkage); } return (status); }
*** 657,667 **** ASSERT(NO_COMPETING_THREADS); NDBG0(("_fini")); if ((status = mod_remove(&modlinkage)) == 0) { ! ddi_soft_state_fini(&mptsas_state); scsi_hba_fini(&modlinkage); mutex_destroy(&mptsas_global_mutex); rw_destroy(&mptsas_global_rwlock); mutex_destroy(&mptsas_log_mutex); } --- 733,743 ---- ASSERT(NO_COMPETING_THREADS); NDBG0(("_fini")); if ((status = mod_remove(&modlinkage)) == 0) { ! ddi_soft_state_fini(&mptsas3_state); scsi_hba_fini(&modlinkage); mutex_destroy(&mptsas_global_mutex); rw_destroy(&mptsas_global_rwlock); mutex_destroy(&mptsas_log_mutex); }
*** 763,772 **** --- 839,849 ---- mptsas_target_t *tp; mptsas_smp_t *sp; for (tp = refhash_first(mpt->m_targets); tp != NULL; tp = refhash_next(mpt->m_targets, tp)) { + mutex_destroy(&tp->m_t_mutex); refhash_remove(mpt->m_targets, tp); } for (sp = refhash_first(mpt->m_smp_targets); sp != NULL; sp = refhash_next(mpt->m_smp_targets, sp)) { refhash_remove(mpt->m_smp_targets, sp);
*** 797,807 **** uint16_t attached_devhdl = 0; uint32_t dev_info; uint64_t attached_sas_wwn; uint16_t dev_hdl; uint16_t pdev_hdl; ! uint16_t bay_num, enclosure; char attached_wwnstr[MPTSAS_WWN_STRLEN]; /* CONSTCOND */ ASSERT(NO_COMPETING_THREADS); --- 874,884 ---- uint16_t attached_devhdl = 0; uint32_t dev_info; uint64_t attached_sas_wwn; uint16_t dev_hdl; uint16_t pdev_hdl; ! uint16_t bay_num, enclosure, io_flags; char attached_wwnstr[MPTSAS_WWN_STRLEN]; /* CONSTCOND */ ASSERT(NO_COMPETING_THREADS);
*** 959,969 **** mutex_enter(&mpt->m_mutex); page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)attached_devhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &attached_sas_wwn, &dev_info, &phy_port, &phy_id, ! &pdev_hdl, &bay_num, &enclosure); if (rval != DDI_SUCCESS) { mptsas_log(mpt, CE_WARN, "Failed to get device page0 for handle:%d", attached_devhdl); mutex_exit(&mpt->m_mutex); --- 1036,1046 ---- mutex_enter(&mpt->m_mutex); page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)attached_devhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &attached_sas_wwn, &dev_info, &phy_port, &phy_id, ! &pdev_hdl, &bay_num, &enclosure, &io_flags); if (rval != DDI_SUCCESS) { mptsas_log(mpt, CE_WARN, "Failed to get device page0 for handle:%d", attached_devhdl); mutex_exit(&mpt->m_mutex);
*** 1016,1035 **** static int mptsas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { mptsas_t *mpt = NULL; int instance, i, j; ! int doneq_thread_num; ! char intr_added = 0; char map_setup = 0; char config_setup = 0; char hba_attach_setup = 0; char smp_attach_setup = 0; char mutex_init_done = 0; char event_taskq_create = 0; char dr_taskq_create = 0; char doneq_thread_create = 0; scsi_hba_tran_t *hba_tran; uint_t mem_bar = MEM_SPACE; int rval = DDI_FAILURE; /* CONSTCOND */ --- 1093,1113 ---- static int mptsas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { mptsas_t *mpt = NULL; int instance, i, j; ! int q_thread_num; char map_setup = 0; char config_setup = 0; char hba_attach_setup = 0; char smp_attach_setup = 0; char mutex_init_done = 0; char event_taskq_create = 0; char dr_taskq_create = 0; char doneq_thread_create = 0; + char txwq_thread_create = 0; + char added_watchdog = 0; scsi_hba_tran_t *hba_tran; uint_t mem_bar = MEM_SPACE; int rval = DDI_FAILURE; /* CONSTCOND */
*** 1140,1156 **** instance = ddi_get_instance(dip); /* * Allocate softc information. */ ! if (ddi_soft_state_zalloc(mptsas_state, instance) != DDI_SUCCESS) { mptsas_log(NULL, CE_WARN, "mptsas%d: cannot allocate soft state", instance); goto fail; } ! mpt = ddi_get_soft_state(mptsas_state, instance); if (mpt == NULL) { mptsas_log(NULL, CE_WARN, "mptsas%d: cannot get soft state", instance); goto fail; --- 1218,1234 ---- instance = ddi_get_instance(dip); /* * Allocate softc information. */ ! if (ddi_soft_state_zalloc(mptsas3_state, instance) != DDI_SUCCESS) { mptsas_log(NULL, CE_WARN, "mptsas%d: cannot allocate soft state", instance); goto fail; } ! mpt = ddi_get_soft_state(mptsas3_state, instance); if (mpt == NULL) { mptsas_log(NULL, CE_WARN, "mptsas%d: cannot get soft state", instance); goto fail;
*** 1162,1176 **** --- 1240,1263 ---- mpt->m_dip = dip; mpt->m_instance = instance; /* Make a per-instance copy of the structures */ mpt->m_io_dma_attr = mptsas_dma_attrs64; + if (mptsas_use_64bit_msgaddr) { + mpt->m_msg_dma_attr = mptsas_dma_attrs64; + } else { mpt->m_msg_dma_attr = mptsas_dma_attrs; + } mpt->m_reg_acc_attr = mptsas_dev_attr; mpt->m_dev_acc_attr = mptsas_dev_attr; /* + * Round down the arq sense buffer size to nearest 16 bytes. + */ + mpt->m_req_sense_size = EXTCMDS_STATUS_SIZE; + + /* * Initialize FMA */ mpt->m_fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, mpt->m_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable", DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
*** 1220,1241 **** "failed"); goto fail; } dr_taskq_create++; mpt->m_doneq_thread_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "mptsas_doneq_thread_threshold_prop", 10); mpt->m_doneq_length_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "mptsas_doneq_length_threshold_prop", 8); mpt->m_doneq_thread_n = ddi_prop_get_int(DDI_DEV_T_ANY, dip, ! 0, "mptsas_doneq_thread_n_prop", 8); if (mpt->m_doneq_thread_n) { ! cv_init(&mpt->m_doneq_thread_cv, NULL, CV_DRIVER, NULL); ! mutex_init(&mpt->m_doneq_mutex, NULL, MUTEX_DRIVER, NULL); ! ! mutex_enter(&mpt->m_doneq_mutex); mpt->m_doneq_thread_id = kmem_zalloc(sizeof (mptsas_doneq_thread_list_t) * mpt->m_doneq_thread_n, KM_SLEEP); for (j = 0; j < mpt->m_doneq_thread_n; j++) { --- 1307,1373 ---- "failed"); goto fail; } dr_taskq_create++; + cv_init(&mpt->m_qthread_cv, NULL, CV_DRIVER, NULL); + mutex_init(&mpt->m_qthread_mutex, NULL, MUTEX_DRIVER, NULL); + + i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + 0, "mptsas_enable_txwq_prop", NCPUS > 1); + if (i) { + mpt->m_txwq_thread_n = NUM_TX_WAITQ; + mpt->m_txwq_enabled = FALSE; + if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, + 0, "mptsas_allow_txwq_jumping", 0)) { + mpt->m_txwq_allow_q_jumping = TRUE; + } + i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, + 0, "mptsas_txwq_threashold_prop", 80000); + mpt->m_txwq_thread_threshold = (uint16_t)i; + } else { + mpt->m_txwq_thread_n = 0; + mpt->m_txwq_enabled = FALSE; + } + + if (mpt->m_txwq_thread_n) { + mutex_enter(&mpt->m_qthread_mutex); + for (j = 0; j < NUM_TX_WAITQ; j++) { + mutex_init(&mpt->m_tx_waitq[j].txwq_mutex, NULL, + MUTEX_DRIVER, + NULL); + cv_init(&mpt->m_tx_waitq[j].txwq_cv, NULL, CV_DRIVER, + NULL); + cv_init(&mpt->m_tx_waitq[j].txwq_drain_cv, NULL, + CV_DRIVER, NULL); + mpt->m_tx_waitq[j].txwq_active = TRUE; + mpt->m_tx_waitq[j].txwq_draining = FALSE; + mpt->m_tx_waitq[j].txwq_cmdq = NULL; + mpt->m_tx_waitq[j].txwq_qtail = + &mpt->m_tx_waitq[j].txwq_cmdq; + mutex_enter(&mpt->m_tx_waitq[j].txwq_mutex); + mpt->m_tx_waitq[j].arg.mpt = mpt; + mpt->m_tx_waitq[j].arg.t = j; + mpt->m_tx_waitq[j].txwq_threadp = + thread_create(NULL, 0, mptsas_tx_waitq_thread, + &mpt->m_tx_waitq[j].arg, + 0, &p0, TS_RUN, maxclsyspri - 10); + mutex_exit(&mpt->m_tx_waitq[j].txwq_mutex); + } + mutex_exit(&mpt->m_qthread_mutex); + txwq_thread_create++; + } + mpt->m_doneq_thread_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "mptsas_doneq_thread_threshold_prop", 10); mpt->m_doneq_length_threshold = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "mptsas_doneq_length_threshold_prop", 8); mpt->m_doneq_thread_n = ddi_prop_get_int(DDI_DEV_T_ANY, dip, ! 0, "mptsas_doneq_thread_n_prop", min(NCPUS, 8)); if (mpt->m_doneq_thread_n) { ! mutex_enter(&mpt->m_qthread_mutex); mpt->m_doneq_thread_id = kmem_zalloc(sizeof (mptsas_doneq_thread_list_t) * mpt->m_doneq_thread_n, KM_SLEEP); for (j = 0; j < mpt->m_doneq_thread_n; j++) {
*** 1249,1295 **** mpt->m_doneq_thread_id[j].arg.mpt = mpt; mpt->m_doneq_thread_id[j].arg.t = j; mpt->m_doneq_thread_id[j].threadp = thread_create(NULL, 0, mptsas_doneq_thread, &mpt->m_doneq_thread_id[j].arg, ! 0, &p0, TS_RUN, minclsyspri); ! mpt->m_doneq_thread_id[j].donetail = ! &mpt->m_doneq_thread_id[j].doneq; mutex_exit(&mpt->m_doneq_thread_id[j].mutex); } ! mutex_exit(&mpt->m_doneq_mutex); doneq_thread_create++; } ! /* Initialize mutex used in interrupt handler */ ! mutex_init(&mpt->m_mutex, NULL, MUTEX_DRIVER, ! DDI_INTR_PRI(mpt->m_intr_pri)); mutex_init(&mpt->m_passthru_mutex, NULL, MUTEX_DRIVER, NULL); - mutex_init(&mpt->m_tx_waitq_mutex, NULL, MUTEX_DRIVER, - DDI_INTR_PRI(mpt->m_intr_pri)); for (i = 0; i < MPTSAS_MAX_PHYS; i++) { mutex_init(&mpt->m_phy_info[i].smhba_info.phy_mutex, ! NULL, MUTEX_DRIVER, ! DDI_INTR_PRI(mpt->m_intr_pri)); } cv_init(&mpt->m_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_passthru_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_fw_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_config_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_fw_diag_cv, NULL, CV_DRIVER, NULL); mutex_init_done++; - /* - * Disable hardware interrupt since we're not ready to - * handle it yet. - */ - MPTSAS_DISABLE_INTR(mpt); - if (mptsas_register_intrs(mpt) == FALSE) - goto fail; - intr_added++; - mutex_enter(&mpt->m_mutex); /* * Initialize power management component */ if (mpt->m_options & MPTSAS_OPT_PM) { --- 1381,1427 ---- mpt->m_doneq_thread_id[j].arg.mpt = mpt; mpt->m_doneq_thread_id[j].arg.t = j; mpt->m_doneq_thread_id[j].threadp = thread_create(NULL, 0, mptsas_doneq_thread, &mpt->m_doneq_thread_id[j].arg, ! 0, &p0, TS_RUN, maxclsyspri - 10); ! mpt->m_doneq_thread_id[j].dlist.dl_tail = ! &mpt->m_doneq_thread_id[j].dlist.dl_q; mutex_exit(&mpt->m_doneq_thread_id[j].mutex); } ! mutex_exit(&mpt->m_qthread_mutex); doneq_thread_create++; } ! /* ! * Disable hardware interrupt since we're not ready to ! * handle it yet. ! */ ! MPTSAS_DISABLE_INTR(mpt); ! ! /* ! * Initialize mutex used in interrupt handler. ! * We don't support hi-level so the mutex's are all adaptive ! * and we don't want to register the interrupts until we get ! * the chip type information from _init_chip() below. ! * Otherwise we would use DDI_INTR_PRI(mpt->m_intr_pri) ! * rather than NULL in the mutex_init() calls. ! */ ! mutex_init(&mpt->m_mutex, NULL, MUTEX_DRIVER, NULL); mutex_init(&mpt->m_passthru_mutex, NULL, MUTEX_DRIVER, NULL); for (i = 0; i < MPTSAS_MAX_PHYS; i++) { mutex_init(&mpt->m_phy_info[i].smhba_info.phy_mutex, ! NULL, MUTEX_DRIVER, NULL); } cv_init(&mpt->m_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_passthru_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_fw_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_config_cv, NULL, CV_DRIVER, NULL); cv_init(&mpt->m_fw_diag_cv, NULL, CV_DRIVER, NULL); mutex_init_done++; mutex_enter(&mpt->m_mutex); /* * Initialize power management component */ if (mpt->m_options & MPTSAS_OPT_PM) {
*** 1330,1339 **** --- 1462,1484 ---- mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 failed!"); goto fail; } + /* + * If we only have one interrupt the default for doneq_thread_threshold + * should be 0 so that all completion processing goes to the threads. + * Only change it if it wasn't set from .conf file. + */ + if (mpt->m_doneq_thread_n != 0 && + ddi_prop_exists(DDI_DEV_T_ANY, dip, + 0, "mptsas_doneq_length_threshold_prop") == 0 && + mpt->m_intr_cnt == 1) { + mpt->m_doneq_length_threshold = 0; + } + + mutex_exit(&mpt->m_mutex); /* * Register the iport for multiple port HBA */
*** 1363,1376 **** } /* * Initialize the wait and done FIFO queue */ ! mpt->m_donetail = &mpt->m_doneq; mpt->m_waitqtail = &mpt->m_waitq; - mpt->m_tx_waitqtail = &mpt->m_tx_waitq; - mpt->m_tx_draining = 0; /* * ioc cmd queue initialize */ mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq; --- 1508,1519 ---- } /* * Initialize the wait and done FIFO queue */ ! mpt->m_dlist.dl_tail = &mpt->m_dlist.dl_q; mpt->m_waitqtail = &mpt->m_waitq; /* * ioc cmd queue initialize */ mpt->m_ioc_event_cmdtail = &mpt->m_ioc_event_cmdq;
*** 1387,1407 **** goto fail; } mutex_exit(&mpt->m_mutex); /* ! * Initialize PHY info for smhba */ if (mptsas_smhba_setup(mpt)) { mptsas_log(mpt, CE_WARN, "mptsas phy initialization " "failed"); goto fail; } /* Check all dma handles allocated in attach */ if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_reply_frame_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_free_queue_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_post_queue_hdl) --- 1530,1573 ---- goto fail; } mutex_exit(&mpt->m_mutex); /* ! * used for mptsas_watch ! */ ! mptsas_list_add(mpt); ! ! mutex_enter(&mptsas_global_mutex); ! if (mptsas_timeouts_enabled == 0) { ! mptsas_scsi_watchdog_tick = ddi_prop_get_int(DDI_DEV_T_ANY, ! dip, 0, "scsi-watchdog-tick", DEFAULT_WD_TICK); ! ! mptsas_tick = mptsas_scsi_watchdog_tick * ! drv_usectohz((clock_t)1000000); ! ! mptsas_timeout_id = timeout(mptsas_watch, NULL, mptsas_tick); ! mptsas_timeouts_enabled = 1; ! } ! mutex_exit(&mptsas_global_mutex); ! added_watchdog++; ! ! /* ! * Initialize PHY info for smhba. ! * This requires watchdog to be enabled otherwise if interrupts ! * don't work the system will hang. */ if (mptsas_smhba_setup(mpt)) { mptsas_log(mpt, CE_WARN, "mptsas phy initialization " "failed"); goto fail; } /* Check all dma handles allocated in attach */ if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) != DDI_SUCCESS) || + (mptsas_check_dma_handle(mpt->m_dma_req_sense_hdl) + != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_reply_frame_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_free_queue_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_post_queue_hdl)
*** 1413,1422 **** --- 1579,1590 ---- /* Check all acc handles allocated in attach */ if ((mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) != DDI_SUCCESS) || + (mptsas_check_acc_handle(mpt->m_acc_req_sense_hdl) + != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_reply_frame_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_free_queue_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_post_queue_hdl)
*** 1429,1455 **** } /* * After this point, we are not going to fail the attach. */ - /* - * used for mptsas_watch - */ - mptsas_list_add(mpt); - - mutex_enter(&mptsas_global_mutex); - if (mptsas_timeouts_enabled == 0) { - mptsas_scsi_watchdog_tick = ddi_prop_get_int(DDI_DEV_T_ANY, - dip, 0, "scsi-watchdog-tick", DEFAULT_WD_TICK); - - mptsas_tick = mptsas_scsi_watchdog_tick * - drv_usectohz((clock_t)1000000); - - mptsas_timeout_id = timeout(mptsas_watch, NULL, mptsas_tick); - mptsas_timeouts_enabled = 1; - } - mutex_exit(&mptsas_global_mutex); /* Print message of HBA present */ ddi_report_dev(dip); /* report idle status to pm framework */ --- 1597,1606 ----
*** 1462,1471 **** --- 1613,1625 ---- fail: mptsas_log(mpt, CE_WARN, "attach failed"); mptsas_fm_ereport(mpt, DDI_FM_DEVICE_NO_RESPONSE); ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_LOST); if (mpt) { + /* deallocate in reverse order */ + if (added_watchdog) { + mptsas_list_del(mpt); mutex_enter(&mptsas_global_mutex); if (mptsas_timeout_id && (mptsas_head == NULL)) { timeout_id_t tid = mptsas_timeout_id; mptsas_timeouts_enabled = 0;
*** 1473,1483 **** mutex_exit(&mptsas_global_mutex); (void) untimeout(tid); mutex_enter(&mptsas_global_mutex); } mutex_exit(&mptsas_global_mutex); ! /* deallocate in reverse order */ mptsas_cache_destroy(mpt); if (smp_attach_setup) { mptsas_smp_teardown(mpt); } --- 1627,1638 ---- mutex_exit(&mptsas_global_mutex); (void) untimeout(tid); mutex_enter(&mptsas_global_mutex); } mutex_exit(&mptsas_global_mutex); ! } ! mptsas_cache_destroy(mpt); if (smp_attach_setup) { mptsas_smp_teardown(mpt); }
*** 1491,1543 **** refhash_destroy(mpt->m_smp_targets); if (mpt->m_active) { mptsas_free_active_slots(mpt); } ! if (intr_added) { mptsas_unregister_intrs(mpt); } if (doneq_thread_create) { ! mutex_enter(&mpt->m_doneq_mutex); ! doneq_thread_num = mpt->m_doneq_thread_n; ! for (j = 0; j < mpt->m_doneq_thread_n; j++) { mutex_enter(&mpt->m_doneq_thread_id[j].mutex); mpt->m_doneq_thread_id[j].flag &= (~MPTSAS_DONEQ_THREAD_ACTIVE); cv_signal(&mpt->m_doneq_thread_id[j].cv); mutex_exit(&mpt->m_doneq_thread_id[j].mutex); } while (mpt->m_doneq_thread_n) { ! cv_wait(&mpt->m_doneq_thread_cv, ! &mpt->m_doneq_mutex); } ! for (j = 0; j < doneq_thread_num; j++) { cv_destroy(&mpt->m_doneq_thread_id[j].cv); mutex_destroy(&mpt->m_doneq_thread_id[j].mutex); } kmem_free(mpt->m_doneq_thread_id, sizeof (mptsas_doneq_thread_list_t) ! * doneq_thread_num); ! mutex_exit(&mpt->m_doneq_mutex); ! cv_destroy(&mpt->m_doneq_thread_cv); ! mutex_destroy(&mpt->m_doneq_mutex); } if (event_taskq_create) { ddi_taskq_destroy(mpt->m_event_taskq); } if (dr_taskq_create) { ddi_taskq_destroy(mpt->m_dr_taskq); } if (mutex_init_done) { ! mutex_destroy(&mpt->m_tx_waitq_mutex); mutex_destroy(&mpt->m_passthru_mutex); mutex_destroy(&mpt->m_mutex); for (i = 0; i < MPTSAS_MAX_PHYS; i++) { mutex_destroy( &mpt->m_phy_info[i].smhba_info.phy_mutex); } cv_destroy(&mpt->m_cv); cv_destroy(&mpt->m_passthru_cv); cv_destroy(&mpt->m_fw_cv); cv_destroy(&mpt->m_config_cv); cv_destroy(&mpt->m_fw_diag_cv); --- 1646,1716 ---- refhash_destroy(mpt->m_smp_targets); if (mpt->m_active) { mptsas_free_active_slots(mpt); } ! if (mpt->m_intr_cnt) { mptsas_unregister_intrs(mpt); } if (doneq_thread_create) { ! mutex_enter(&mpt->m_qthread_mutex); ! q_thread_num = mpt->m_doneq_thread_n; ! for (j = 0; j < q_thread_num; j++) { mutex_enter(&mpt->m_doneq_thread_id[j].mutex); mpt->m_doneq_thread_id[j].flag &= (~MPTSAS_DONEQ_THREAD_ACTIVE); cv_signal(&mpt->m_doneq_thread_id[j].cv); mutex_exit(&mpt->m_doneq_thread_id[j].mutex); } while (mpt->m_doneq_thread_n) { ! cv_wait(&mpt->m_qthread_cv, ! &mpt->m_qthread_mutex); } ! for (j = 0; j < q_thread_num; j++) { cv_destroy(&mpt->m_doneq_thread_id[j].cv); mutex_destroy(&mpt->m_doneq_thread_id[j].mutex); } kmem_free(mpt->m_doneq_thread_id, sizeof (mptsas_doneq_thread_list_t) ! * q_thread_num); ! mutex_exit(&mpt->m_qthread_mutex); ! } ! if (txwq_thread_create) { ! mutex_enter(&mpt->m_qthread_mutex); ! q_thread_num = mpt->m_txwq_thread_n; ! for (j = 0; j < q_thread_num; j++) { ! mutex_enter(&mpt->m_tx_waitq[j].txwq_mutex); ! mpt->m_tx_waitq[j].txwq_active = FALSE; ! cv_signal(&mpt->m_tx_waitq[j].txwq_cv); ! mutex_exit(&mpt->m_tx_waitq[j].txwq_mutex); ! } ! while (mpt->m_txwq_thread_n) { ! cv_wait(&mpt->m_qthread_cv, ! &mpt->m_qthread_mutex); ! } ! for (j = 0; j < q_thread_num; j++) { ! cv_destroy(&mpt->m_tx_waitq[j].txwq_cv); ! cv_destroy(&mpt->m_tx_waitq[j].txwq_drain_cv); ! mutex_destroy(&mpt->m_tx_waitq[j].txwq_mutex); ! } } if (event_taskq_create) { ddi_taskq_destroy(mpt->m_event_taskq); } if (dr_taskq_create) { ddi_taskq_destroy(mpt->m_dr_taskq); } if (mutex_init_done) { ! mutex_destroy(&mpt->m_qthread_mutex); mutex_destroy(&mpt->m_passthru_mutex); mutex_destroy(&mpt->m_mutex); for (i = 0; i < MPTSAS_MAX_PHYS; i++) { mutex_destroy( &mpt->m_phy_info[i].smhba_info.phy_mutex); } + cv_destroy(&mpt->m_qthread_cv); cv_destroy(&mpt->m_cv); cv_destroy(&mpt->m_passthru_cv); cv_destroy(&mpt->m_fw_cv); cv_destroy(&mpt->m_config_cv); cv_destroy(&mpt->m_fw_diag_cv);
*** 1551,1561 **** } mptsas_free_handshake_msg(mpt); mptsas_hba_fini(mpt); mptsas_fm_fini(mpt); ! ddi_soft_state_free(mptsas_state, instance); ddi_prop_remove_all(dip); } return (DDI_FAILURE); } --- 1724,1734 ---- } mptsas_free_handshake_msg(mpt); mptsas_hba_fini(mpt); mptsas_fm_fini(mpt); ! ddi_soft_state_free(mptsas3_state, instance); ddi_prop_remove_all(dip); } return (DDI_FAILURE); }
*** 1765,1775 **** scsi_hba_tran_t *tran; int circ = 0; int circ1 = 0; mdi_pathinfo_t *pip = NULL; int i; ! int doneq_thread_num = 0; NDBG0(("mptsas_do_detach: dip=0x%p", (void *)dip)); if ((tran = ndi_flavorv_get(dip, SCSA_FLAVOR_SCSI_DEVICE)) == NULL) return (DDI_FAILURE); --- 1938,1948 ---- scsi_hba_tran_t *tran; int circ = 0; int circ1 = 0; mdi_pathinfo_t *pip = NULL; int i; ! int q_thread_num = 0; NDBG0(("mptsas_do_detach: dip=0x%p", (void *)dip)); if ((tran = ndi_flavorv_get(dip, SCSA_FLAVOR_SCSI_DEVICE)) == NULL) return (DDI_FAILURE);
*** 1813,1823 **** (void) pm_busy_component(dip, 0); if (mpt->m_power_level != PM_LEVEL_D0) { if (pm_raise_power(dip, 0, PM_LEVEL_D0) != DDI_SUCCESS) { mptsas_log(mpt, CE_WARN, ! "mptsas%d: Raise power request failed.", mpt->m_instance); (void) pm_idle_component(dip, 0); return (DDI_FAILURE); } } --- 1986,1996 ---- (void) pm_busy_component(dip, 0); if (mpt->m_power_level != PM_LEVEL_D0) { if (pm_raise_power(dip, 0, PM_LEVEL_D0) != DDI_SUCCESS) { mptsas_log(mpt, CE_WARN, ! "mptsas3%d: Raise power request failed.", mpt->m_instance); (void) pm_idle_component(dip, 0); return (DDI_FAILURE); } }
*** 1837,1869 **** mptsas_rem_intrs(mpt); ddi_taskq_destroy(mpt->m_event_taskq); ddi_taskq_destroy(mpt->m_dr_taskq); if (mpt->m_doneq_thread_n) { ! mutex_enter(&mpt->m_doneq_mutex); ! doneq_thread_num = mpt->m_doneq_thread_n; for (i = 0; i < mpt->m_doneq_thread_n; i++) { mutex_enter(&mpt->m_doneq_thread_id[i].mutex); mpt->m_doneq_thread_id[i].flag &= (~MPTSAS_DONEQ_THREAD_ACTIVE); cv_signal(&mpt->m_doneq_thread_id[i].cv); mutex_exit(&mpt->m_doneq_thread_id[i].mutex); } while (mpt->m_doneq_thread_n) { ! cv_wait(&mpt->m_doneq_thread_cv, ! &mpt->m_doneq_mutex); } ! for (i = 0; i < doneq_thread_num; i++) { cv_destroy(&mpt->m_doneq_thread_id[i].cv); mutex_destroy(&mpt->m_doneq_thread_id[i].mutex); } kmem_free(mpt->m_doneq_thread_id, sizeof (mptsas_doneq_thread_list_t) ! * doneq_thread_num); ! mutex_exit(&mpt->m_doneq_mutex); ! cv_destroy(&mpt->m_doneq_thread_cv); ! mutex_destroy(&mpt->m_doneq_mutex); } scsi_hba_reset_notify_tear_down(mpt->m_reset_notify_listf); mptsas_list_del(mpt); --- 2010,2059 ---- mptsas_rem_intrs(mpt); ddi_taskq_destroy(mpt->m_event_taskq); ddi_taskq_destroy(mpt->m_dr_taskq); if (mpt->m_doneq_thread_n) { ! mutex_enter(&mpt->m_qthread_mutex); ! q_thread_num = mpt->m_doneq_thread_n; for (i = 0; i < mpt->m_doneq_thread_n; i++) { mutex_enter(&mpt->m_doneq_thread_id[i].mutex); mpt->m_doneq_thread_id[i].flag &= (~MPTSAS_DONEQ_THREAD_ACTIVE); cv_signal(&mpt->m_doneq_thread_id[i].cv); mutex_exit(&mpt->m_doneq_thread_id[i].mutex); } while (mpt->m_doneq_thread_n) { ! cv_wait(&mpt->m_qthread_cv, ! &mpt->m_qthread_mutex); } ! for (i = 0; i < q_thread_num; i++) { cv_destroy(&mpt->m_doneq_thread_id[i].cv); mutex_destroy(&mpt->m_doneq_thread_id[i].mutex); } kmem_free(mpt->m_doneq_thread_id, sizeof (mptsas_doneq_thread_list_t) ! * q_thread_num); ! mutex_exit(&mpt->m_qthread_mutex); ! } ! if (mpt->m_txwq_thread_n) { ! mutex_enter(&mpt->m_qthread_mutex); ! q_thread_num = mpt->m_txwq_thread_n; ! for (i = 0; i < q_thread_num; i++) { ! mutex_enter(&mpt->m_tx_waitq[i].txwq_mutex); ! mpt->m_tx_waitq[i].txwq_active = FALSE; ! cv_signal(&mpt->m_tx_waitq[i].txwq_cv); ! mutex_exit(&mpt->m_tx_waitq[i].txwq_mutex); ! } ! while (mpt->m_txwq_thread_n) { ! cv_wait(&mpt->m_qthread_cv, ! &mpt->m_qthread_mutex); ! } ! for (i = 0; i < q_thread_num; i++) { ! cv_destroy(&mpt->m_tx_waitq[i].txwq_cv); ! cv_destroy(&mpt->m_tx_waitq[i].txwq_drain_cv); ! mutex_destroy(&mpt->m_tx_waitq[i].txwq_mutex); ! } } scsi_hba_reset_notify_tear_down(mpt->m_reset_notify_listf); mptsas_list_del(mpt);
*** 1940,1960 **** /* Lower the power informing PM Framework */ if (mpt->m_options & MPTSAS_OPT_PM) { if (pm_lower_power(dip, 0, PM_LEVEL_D3) != DDI_SUCCESS) mptsas_log(mpt, CE_WARN, ! "!mptsas%d: Lower power request failed " "during detach, ignoring.", mpt->m_instance); } ! mutex_destroy(&mpt->m_tx_waitq_mutex); mutex_destroy(&mpt->m_passthru_mutex); mutex_destroy(&mpt->m_mutex); for (i = 0; i < MPTSAS_MAX_PHYS; i++) { mutex_destroy(&mpt->m_phy_info[i].smhba_info.phy_mutex); } cv_destroy(&mpt->m_cv); cv_destroy(&mpt->m_passthru_cv); cv_destroy(&mpt->m_fw_cv); cv_destroy(&mpt->m_config_cv); cv_destroy(&mpt->m_fw_diag_cv); --- 2130,2151 ---- /* Lower the power informing PM Framework */ if (mpt->m_options & MPTSAS_OPT_PM) { if (pm_lower_power(dip, 0, PM_LEVEL_D3) != DDI_SUCCESS) mptsas_log(mpt, CE_WARN, ! "!mptsas3%d: Lower power request failed " "during detach, ignoring.", mpt->m_instance); } ! mutex_destroy(&mpt->m_qthread_mutex); mutex_destroy(&mpt->m_passthru_mutex); mutex_destroy(&mpt->m_mutex); for (i = 0; i < MPTSAS_MAX_PHYS; i++) { mutex_destroy(&mpt->m_phy_info[i].smhba_info.phy_mutex); } + cv_destroy(&mpt->m_qthread_cv); cv_destroy(&mpt->m_cv); cv_destroy(&mpt->m_passthru_cv); cv_destroy(&mpt->m_fw_cv); cv_destroy(&mpt->m_config_cv); cv_destroy(&mpt->m_fw_diag_cv);
*** 1966,1976 **** mptsas_config_space_fini(mpt); mptsas_free_handshake_msg(mpt); mptsas_fm_fini(mpt); ! ddi_soft_state_free(mptsas_state, ddi_get_instance(dip)); ddi_prop_remove_all(dip); return (DDI_SUCCESS); } --- 2157,2167 ---- mptsas_config_space_fini(mpt); mptsas_free_handshake_msg(mpt); mptsas_fm_fini(mpt); ! ddi_soft_state_free(mptsas3_state, ddi_get_instance(dip)); ddi_prop_remove_all(dip); return (DDI_SUCCESS); }
*** 2019,2028 **** --- 2210,2220 ---- static int mptsas_alloc_handshake_msg(mptsas_t *mpt, size_t alloc_size) { ddi_dma_attr_t task_dma_attrs; + mpt->m_hshk_dma_size = 0; task_dma_attrs = mpt->m_msg_dma_attr; task_dma_attrs.dma_attr_sgllen = 1; task_dma_attrs.dma_attr_granular = (uint32_t)(alloc_size); /* allocate Task Management ddi_dma resources */
*** 2037,2046 **** --- 2229,2240 ---- } static void mptsas_free_handshake_msg(mptsas_t *mpt) { + if (mpt->m_hshk_dma_size == 0) + return; mptsas_dma_addr_destroy(&mpt->m_hshk_dma_hdl, &mpt->m_hshk_acc_hdl); mpt->m_hshk_dma_size = 0; } static int
*** 2214,2226 **** char buf[64]; /* * create kmem cache for packets */ ! (void) sprintf(buf, "mptsas%d_cache", instance); mpt->m_kmem_cache = kmem_cache_create(buf, ! sizeof (struct mptsas_cmd) + scsi_pkt_size(), 8, mptsas_kmem_cache_constructor, mptsas_kmem_cache_destructor, NULL, (void *)mpt, NULL, 0); if (mpt->m_kmem_cache == NULL) { mptsas_log(mpt, CE_WARN, "creating kmem cache failed"); --- 2408,2420 ---- char buf[64]; /* * create kmem cache for packets */ ! (void) sprintf(buf, "mptsas3%d_cache", instance); mpt->m_kmem_cache = kmem_cache_create(buf, ! sizeof (struct mptsas_cmd) + scsi_pkt_size(), 16, mptsas_kmem_cache_constructor, mptsas_kmem_cache_destructor, NULL, (void *)mpt, NULL, 0); if (mpt->m_kmem_cache == NULL) { mptsas_log(mpt, CE_WARN, "creating kmem cache failed");
*** 2229,2241 **** /* * create kmem cache for extra SGL frames if SGL cannot * be accomodated into main request frame. */ ! (void) sprintf(buf, "mptsas%d_cache_frames", instance); mpt->m_cache_frames = kmem_cache_create(buf, ! sizeof (mptsas_cache_frames_t), 8, mptsas_cache_frames_constructor, mptsas_cache_frames_destructor, NULL, (void *)mpt, NULL, 0); if (mpt->m_cache_frames == NULL) { mptsas_log(mpt, CE_WARN, "creating cache for frames failed"); --- 2423,2435 ---- /* * create kmem cache for extra SGL frames if SGL cannot * be accomodated into main request frame. */ ! (void) sprintf(buf, "mptsas3%d_cache_frames", instance); mpt->m_cache_frames = kmem_cache_create(buf, ! sizeof (mptsas_cache_frames_t), 16, mptsas_cache_frames_constructor, mptsas_cache_frames_destructor, NULL, (void *)mpt, NULL, 0); if (mpt->m_cache_frames == NULL) { mptsas_log(mpt, CE_WARN, "creating cache for frames failed");
*** 2271,2281 **** uint32_t ioc_status; if (scsi_hba_iport_unit_address(dip) != 0) return (DDI_SUCCESS); ! mpt = ddi_get_soft_state(mptsas_state, ddi_get_instance(dip)); if (mpt == NULL) { return (DDI_FAILURE); } mutex_enter(&mpt->m_mutex); --- 2465,2475 ---- uint32_t ioc_status; if (scsi_hba_iport_unit_address(dip) != 0) return (DDI_SUCCESS); ! mpt = ddi_get_soft_state(mptsas3_state, ddi_get_instance(dip)); if (mpt == NULL) { return (DDI_FAILURE); } mutex_enter(&mpt->m_mutex);
*** 2287,2297 **** mutex_exit(&mpt->m_mutex); return (DDI_FAILURE); } switch (level) { case PM_LEVEL_D0: ! NDBG11(("mptsas%d: turning power ON.", mpt->m_instance)); MPTSAS_POWER_ON(mpt); /* * Wait up to 30 seconds for IOC to come out of reset. */ while (((ioc_status = ddi_get32(mpt->m_datap, --- 2481,2491 ---- mutex_exit(&mpt->m_mutex); return (DDI_FAILURE); } switch (level) { case PM_LEVEL_D0: ! NDBG11(("mptsas3%d: turning power ON.", mpt->m_instance)); MPTSAS_POWER_ON(mpt); /* * Wait up to 30 seconds for IOC to come out of reset. */ while (((ioc_status = ddi_get32(mpt->m_datap,
*** 2316,2330 **** } } mpt->m_power_level = PM_LEVEL_D0; break; case PM_LEVEL_D3: ! NDBG11(("mptsas%d: turning power OFF.", mpt->m_instance)); MPTSAS_POWER_OFF(mpt); break; default: ! mptsas_log(mpt, CE_WARN, "mptsas%d: unknown power level <%x>.", mpt->m_instance, level); rval = DDI_FAILURE; break; } mutex_exit(&mpt->m_mutex); --- 2510,2524 ---- } } mpt->m_power_level = PM_LEVEL_D0; break; case PM_LEVEL_D3: ! NDBG11(("mptsas3%d: turning power OFF.", mpt->m_instance)); MPTSAS_POWER_OFF(mpt); break; default: ! mptsas_log(mpt, CE_WARN, "mptsas3%d: unknown power level <%x>.", mpt->m_instance, level); rval = DDI_FAILURE; break; } mutex_exit(&mpt->m_mutex);
*** 2498,2509 **** --- 2692,2706 ---- size_t mem_size; /* * re-alloc when it has already alloced */ + if (mpt->m_dma_flags & MPTSAS_REQ_FRAME) { mptsas_dma_addr_destroy(&mpt->m_dma_req_frame_hdl, &mpt->m_acc_req_frame_hdl); + mpt->m_dma_flags &= ~MPTSAS_REQ_FRAME; + } /* * The size of the request frame pool is: * Number of Request Frames * Request Frame Size */
*** 2537,2546 **** --- 2734,2818 ---- /* * Clear the request frame pool. */ bzero(mpt->m_req_frame, mem_size); + mpt->m_dma_flags |= MPTSAS_REQ_FRAME; + return (DDI_SUCCESS); + } + + static int + mptsas_alloc_sense_bufs(mptsas_t *mpt) + { + ddi_dma_attr_t sense_dma_attrs; + caddr_t memp; + ddi_dma_cookie_t cookie; + size_t mem_size; + int num_extrqsense_bufs; + + /* + * re-alloc when it has already alloced + */ + if (mpt->m_dma_flags & MPTSAS_REQ_SENSE) { + rmfreemap(mpt->m_erqsense_map); + mptsas_dma_addr_destroy(&mpt->m_dma_req_sense_hdl, + &mpt->m_acc_req_sense_hdl); + mpt->m_dma_flags &= ~MPTSAS_REQ_SENSE; + } + + /* + * The size of the request sense pool is: + * (Number of Request Frames - 2 ) * Request Sense Size + + * extra memory for extended sense requests. + */ + mem_size = ((mpt->m_max_requests - 2) * mpt->m_req_sense_size) + + mptsas_extreq_sense_bufsize; + + /* + * set the DMA attributes. ARQ buffers + * aligned on a 16-byte boundry. + */ + sense_dma_attrs = mpt->m_msg_dma_attr; + sense_dma_attrs.dma_attr_align = 16; + sense_dma_attrs.dma_attr_sgllen = 1; + + /* + * allocate the request sense buffer pool. + */ + if (mptsas_dma_addr_create(mpt, sense_dma_attrs, + &mpt->m_dma_req_sense_hdl, &mpt->m_acc_req_sense_hdl, &memp, + mem_size, &cookie) == FALSE) { + return (DDI_FAILURE); + } + + /* + * Store the request sense base memory address. This chip uses this + * address to dma the request sense data. The second + * address is the address mpt uses to access the data. + * The third is the base for the extended rqsense buffers. + */ + mpt->m_req_sense_dma_addr = cookie.dmac_laddress; + mpt->m_req_sense = memp; + memp += (mpt->m_max_requests - 2) * mpt->m_req_sense_size; + mpt->m_extreq_sense = memp; + + /* + * The extra memory is divided up into multiples of the base + * buffer size in order to allocate via rmalloc(). + * Note that the rmallocmap cannot start at zero! + */ + num_extrqsense_bufs = mptsas_extreq_sense_bufsize / + mpt->m_req_sense_size; + mpt->m_erqsense_map = rmallocmap_wait(num_extrqsense_bufs); + rmfree(mpt->m_erqsense_map, num_extrqsense_bufs, 1); + + /* + * Clear the pool. + */ + bzero(mpt->m_req_sense, mem_size); + + mpt->m_dma_flags |= MPTSAS_REQ_SENSE; return (DDI_SUCCESS); } static int mptsas_alloc_reply_frames(mptsas_t *mpt)
*** 2551,2562 **** --- 2823,2837 ---- size_t mem_size; /* * re-alloc when it has already alloced */ + if (mpt->m_dma_flags & MPTSAS_REPLY_FRAME) { mptsas_dma_addr_destroy(&mpt->m_dma_reply_frame_hdl, &mpt->m_acc_reply_frame_hdl); + mpt->m_dma_flags &= ~MPTSAS_REPLY_FRAME; + } /* * The size of the reply frame pool is: * Number of Reply Frames * Reply Frame Size */
*** 2589,2598 **** --- 2864,2874 ---- /* * Clear the reply frame pool. */ bzero(mpt->m_reply_frame, mem_size); + mpt->m_dma_flags |= MPTSAS_REPLY_FRAME; return (DDI_SUCCESS); } static int mptsas_alloc_free_queue(mptsas_t *mpt)
*** 2603,2614 **** --- 2879,2893 ---- size_t mem_size; /* * re-alloc when it has already alloced */ + if (mpt->m_dma_flags & MPTSAS_FREE_QUEUE) { mptsas_dma_addr_destroy(&mpt->m_dma_free_queue_hdl, &mpt->m_acc_free_queue_hdl); + mpt->m_dma_flags &= ~MPTSAS_FREE_QUEUE; + } /* * The reply free queue size is: * Reply Free Queue Depth * 4 * The "4" is the size of one 32 bit address (low part of 64-bit
*** 2644,2687 **** /* * Clear the reply free queue memory. */ bzero(mpt->m_free_queue, mem_size); return (DDI_SUCCESS); } static int mptsas_alloc_post_queue(mptsas_t *mpt) { ddi_dma_attr_t frame_dma_attrs; caddr_t memp; ddi_dma_cookie_t cookie; size_t mem_size; /* * re-alloc when it has already alloced */ ! mptsas_dma_addr_destroy(&mpt->m_dma_post_queue_hdl, ! &mpt->m_acc_post_queue_hdl); /* * The reply descriptor post queue size is: * Reply Descriptor Post Queue Depth * 8 * The "8" is the size of each descriptor (8 bytes or 64 bits). */ ! mem_size = mpt->m_post_queue_depth * 8; /* * set the DMA attributes. The Reply Descriptor Post Queue must be * aligned on a 16-byte boundry. */ frame_dma_attrs = mpt->m_msg_dma_attr; frame_dma_attrs.dma_attr_align = 16; frame_dma_attrs.dma_attr_sgllen = 1; /* ! * allocate the reply post queue */ if (mptsas_dma_addr_create(mpt, frame_dma_attrs, &mpt->m_dma_post_queue_hdl, &mpt->m_acc_post_queue_hdl, &memp, mem_size, &cookie) == FALSE) { return (DDI_FAILURE); --- 2923,2995 ---- /* * Clear the reply free queue memory. */ bzero(mpt->m_free_queue, mem_size); + mpt->m_dma_flags |= MPTSAS_FREE_QUEUE; return (DDI_SUCCESS); } + static void + mptsas_free_post_queue(mptsas_t *mpt) + { + mptsas_reply_pqueue_t *rpqp; + int i; + + if (mpt->m_dma_flags & MPTSAS_POST_QUEUE) { + mptsas_dma_addr_destroy(&mpt->m_dma_post_queue_hdl, + &mpt->m_acc_post_queue_hdl); + rpqp = mpt->m_rep_post_queues; + for (i = 0; i < mpt->m_post_reply_qcount; i++) { + mutex_destroy(&rpqp->rpq_mutex); + rpqp++; + } + kmem_free(mpt->m_rep_post_queues, + sizeof (mptsas_reply_pqueue_t) * + mpt->m_post_reply_qcount); + mpt->m_dma_flags &= ~MPTSAS_POST_QUEUE; + } + } + static int mptsas_alloc_post_queue(mptsas_t *mpt) { ddi_dma_attr_t frame_dma_attrs; caddr_t memp; ddi_dma_cookie_t cookie; size_t mem_size; + mptsas_reply_pqueue_t *rpqp; + int i; /* * re-alloc when it has already alloced */ ! mptsas_free_post_queue(mpt); /* * The reply descriptor post queue size is: * Reply Descriptor Post Queue Depth * 8 * The "8" is the size of each descriptor (8 bytes or 64 bits). */ ! mpt->m_post_reply_qcount = mpt->m_intr_cnt; ! mem_size = mpt->m_post_queue_depth * 8 * mpt->m_post_reply_qcount; /* * set the DMA attributes. The Reply Descriptor Post Queue must be * aligned on a 16-byte boundry. */ frame_dma_attrs = mpt->m_msg_dma_attr; frame_dma_attrs.dma_attr_align = 16; frame_dma_attrs.dma_attr_sgllen = 1; /* ! * Allocate the reply post queue(s). ! * MPI2.5 introduces a method to allocate multiple queues ! * using a redirect table. For now stick to one contiguous ! * chunck. This can get as big as 1Mbyte for 16 queues. ! * The spec gives no indication that the queue size can be ! * reduced if you have many of them. */ if (mptsas_dma_addr_create(mpt, frame_dma_attrs, &mpt->m_dma_post_queue_hdl, &mpt->m_acc_post_queue_hdl, &memp, mem_size, &cookie) == FALSE) { return (DDI_FAILURE);
*** 2693,2716 **** --- 3001,3040 ---- * second address is the address mpt uses to manage the queue. */ mpt->m_post_queue_dma_addr = cookie.dmac_laddress; mpt->m_post_queue = memp; + mpt->m_rep_post_queues = kmem_zalloc(sizeof (mptsas_reply_pqueue_t) * + mpt->m_post_reply_qcount, KM_SLEEP); + rpqp = mpt->m_rep_post_queues; + for (i = 0; i < mpt->m_post_reply_qcount; i++) { + rpqp->rpq_queue = memp; + mutex_init(&rpqp->rpq_mutex, NULL, MUTEX_DRIVER, NULL); + rpqp->rpq_dlist.dl_tail = &rpqp->rpq_dlist.dl_q; + rpqp->rpq_num = (uint8_t)i; + memp += (mpt->m_post_queue_depth * 8); + rpqp++; + } + /* * Clear the reply post queue memory. */ bzero(mpt->m_post_queue, mem_size); + mpt->m_dma_flags |= MPTSAS_POST_QUEUE; return (DDI_SUCCESS); } static void mptsas_alloc_reply_args(mptsas_t *mpt) { if (mpt->m_replyh_args == NULL) { mpt->m_replyh_args = kmem_zalloc(sizeof (m_replyh_arg_t) * mpt->m_max_replies, KM_SLEEP); + } else { + bzero(mpt->m_replyh_args, sizeof (m_replyh_arg_t) * + mpt->m_max_replies); } } static int mptsas_alloc_extra_sgl_frame(mptsas_t *mpt, mptsas_cmd_t *cmd)
*** 2749,2769 **** NDBG0(("mptsas_hba_fini")); /* * Free up any allocated memory */ mptsas_dma_addr_destroy(&mpt->m_dma_req_frame_hdl, &mpt->m_acc_req_frame_hdl); mptsas_dma_addr_destroy(&mpt->m_dma_reply_frame_hdl, &mpt->m_acc_reply_frame_hdl); mptsas_dma_addr_destroy(&mpt->m_dma_free_queue_hdl, &mpt->m_acc_free_queue_hdl); ! mptsas_dma_addr_destroy(&mpt->m_dma_post_queue_hdl, ! &mpt->m_acc_post_queue_hdl); if (mpt->m_replyh_args != NULL) { kmem_free(mpt->m_replyh_args, sizeof (m_replyh_arg_t) * mpt->m_max_replies); } --- 3073,3104 ---- NDBG0(("mptsas_hba_fini")); /* * Free up any allocated memory */ + if (mpt->m_dma_flags & MPTSAS_REQ_FRAME) { mptsas_dma_addr_destroy(&mpt->m_dma_req_frame_hdl, &mpt->m_acc_req_frame_hdl); + } + + if (mpt->m_dma_flags & MPTSAS_REQ_SENSE) { + rmfreemap(mpt->m_erqsense_map); + mptsas_dma_addr_destroy(&mpt->m_dma_req_sense_hdl, + &mpt->m_acc_req_sense_hdl); + } + if (mpt->m_dma_flags & MPTSAS_REPLY_FRAME) { mptsas_dma_addr_destroy(&mpt->m_dma_reply_frame_hdl, &mpt->m_acc_reply_frame_hdl); + } + if (mpt->m_dma_flags & MPTSAS_FREE_QUEUE) { mptsas_dma_addr_destroy(&mpt->m_dma_free_queue_hdl, &mpt->m_acc_free_queue_hdl); + } ! mptsas_free_post_queue(mpt); if (mpt->m_replyh_args != NULL) { kmem_free(mpt->m_replyh_args, sizeof (m_replyh_arg_t) * mpt->m_max_replies); }
*** 3038,3049 **** #ifndef __lock_lint _NOTE(ARGUNUSED(ap)) #endif mptsas_t *mpt = PKT2MPT(pkt); mptsas_cmd_t *cmd = PKT2CMD(pkt); ! int rval; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; NDBG1(("mptsas_scsi_start: pkt=0x%p", (void *)pkt)); ASSERT(ptgt); if (ptgt == NULL) return (TRAN_FATAL_ERROR); --- 3373,3386 ---- #ifndef __lock_lint _NOTE(ARGUNUSED(ap)) #endif mptsas_t *mpt = PKT2MPT(pkt); mptsas_cmd_t *cmd = PKT2CMD(pkt); ! int rval, start; ! uint8_t pref; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; + mptsas_tx_waitqueue_t *txwq; NDBG1(("mptsas_scsi_start: pkt=0x%p", (void *)pkt)); ASSERT(ptgt); if (ptgt == NULL) return (TRAN_FATAL_ERROR);
*** 3088,3205 **** * the last cmd in a burst be processed. * * we enable this feature only when the helper threads are enabled, * at which we think the loads are heavy. * ! * per instance mutex m_tx_waitq_mutex is introduced to protect the ! * m_tx_waitqtail, m_tx_waitq, m_tx_draining. */ ! if (mpt->m_doneq_thread_n) { ! if (mutex_tryenter(&mpt->m_mutex) != 0) { ! rval = mptsas_accept_txwq_and_pkt(mpt, cmd); ! mutex_exit(&mpt->m_mutex); ! } else if (cmd->cmd_pkt_flags & FLAG_NOINTR) { mutex_enter(&mpt->m_mutex); ! rval = mptsas_accept_txwq_and_pkt(mpt, cmd); ! mutex_exit(&mpt->m_mutex); } else { ! mutex_enter(&mpt->m_tx_waitq_mutex); ! /* ! * ptgt->m_dr_flag is protected by m_mutex or ! * m_tx_waitq_mutex. In this case, m_tx_waitq_mutex ! * is acquired. ! */ ! if (ptgt->m_dr_flag == MPTSAS_DR_INTRANSITION) { ! if (cmd->cmd_pkt_flags & FLAG_NOQUEUE) { ! /* ! * The command should be allowed to ! * retry by returning TRAN_BUSY to ! * to stall the I/O's which come from ! * scsi_vhci since the device/path is ! * in unstable state now. ! */ ! mutex_exit(&mpt->m_tx_waitq_mutex); ! return (TRAN_BUSY); } else { ! /* ! * The device is offline, just fail the ! * command by returning ! * TRAN_FATAL_ERROR. ! */ ! mutex_exit(&mpt->m_tx_waitq_mutex); ! return (TRAN_FATAL_ERROR); } } ! if (mpt->m_tx_draining) { ! cmd->cmd_flags |= CFLAG_TXQ; ! *mpt->m_tx_waitqtail = cmd; ! mpt->m_tx_waitqtail = &cmd->cmd_linkp; ! mutex_exit(&mpt->m_tx_waitq_mutex); ! } else { /* drain the queue */ ! mpt->m_tx_draining = 1; ! mutex_exit(&mpt->m_tx_waitq_mutex); ! mutex_enter(&mpt->m_mutex); ! rval = mptsas_accept_txwq_and_pkt(mpt, cmd); ! mutex_exit(&mpt->m_mutex); } } } else { mutex_enter(&mpt->m_mutex); - /* - * ptgt->m_dr_flag is protected by m_mutex or m_tx_waitq_mutex - * in this case, m_mutex is acquired. - */ - if (ptgt->m_dr_flag == MPTSAS_DR_INTRANSITION) { - if (cmd->cmd_pkt_flags & FLAG_NOQUEUE) { - /* - * commands should be allowed to retry by - * returning TRAN_BUSY to stall the I/O's - * which come from scsi_vhci since the device/ - * path is in unstable state now. - */ - mutex_exit(&mpt->m_mutex); - return (TRAN_BUSY); - } else { - /* - * The device is offline, just fail the - * command by returning TRAN_FATAL_ERROR. - */ - mutex_exit(&mpt->m_mutex); - return (TRAN_FATAL_ERROR); } } ! rval = mptsas_accept_pkt(mpt, cmd); mutex_exit(&mpt->m_mutex); } return (rval); } - /* - * Accept all the queued cmds(if any) before accept the current one. - */ static int ! mptsas_accept_txwq_and_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd) { - int rval; - mptsas_target_t *ptgt = cmd->cmd_tgt_addr; - - ASSERT(mutex_owned(&mpt->m_mutex)); /* ! * The call to mptsas_accept_tx_waitq() must always be performed ! * because that is where mpt->m_tx_draining is cleared. ! */ ! mutex_enter(&mpt->m_tx_waitq_mutex); ! mptsas_accept_tx_waitq(mpt); ! mutex_exit(&mpt->m_tx_waitq_mutex); ! /* ! * ptgt->m_dr_flag is protected by m_mutex or m_tx_waitq_mutex ! * in this case, m_mutex is acquired. */ if (ptgt->m_dr_flag == MPTSAS_DR_INTRANSITION) { ! if (cmd->cmd_pkt_flags & FLAG_NOQUEUE) { /* * The command should be allowed to retry by returning * TRAN_BUSY to stall the I/O's which come from * scsi_vhci since the device/path is in unstable state * now. --- 3425,3510 ---- * the last cmd in a burst be processed. * * we enable this feature only when the helper threads are enabled, * at which we think the loads are heavy. * ! * per instance, per queue mutex m_tx_waitq[i].txwq_mutex is ! * introduced to protect the txwq_qtail, txwq_cmdq, txwq_len */ ! if (mpt->m_txwq_enabled == TRUE) { ! int gotmtx = 0; ! ! if (mpt->m_txwq_allow_q_jumping) { ! gotmtx = mutex_tryenter(&mpt->m_mutex); ! } ! if (gotmtx == 0) { ! /* We didn't get the mutex or didn't try */ ! if (cmd->cmd_pkt_flags & FLAG_NOINTR) { mutex_enter(&mpt->m_mutex); ! /* Polled commands queue jump */ ! mptsas_accept_tx_waitqs(mpt); } else { ! rval = mptsas_check_targ_intxtion( ! cmd->cmd_tgt_addr, ! cmd->cmd_pkt_flags); ! if (rval != TRAN_ACCEPT) { ! return (rval); ! } ! ! cmd->cmd_flags |= CFLAG_TXQ; ! pref = mpt->m_pref_tx_waitq; ! txwq = &mpt->m_tx_waitq[pref]; ! ! if (mutex_tryenter(&txwq->txwq_mutex) == 0) { ! txwq = &mpt->m_tx_waitq[pref^1]; ! mutex_enter(&txwq->txwq_mutex); } else { ! pref ^= 1; ! mpt->m_pref_tx_waitq = pref; } + + *txwq->txwq_qtail = cmd; + txwq->txwq_qtail = &cmd->cmd_linkp; + txwq->txwq_len++; + if (!txwq->txwq_draining) { + cv_signal(&txwq->txwq_cv); } ! mutex_exit(&txwq->txwq_mutex); ! return (rval); } } } else { mutex_enter(&mpt->m_mutex); } + rval = mptsas_check_targ_intxtion(cmd->cmd_tgt_addr, + cmd->cmd_pkt_flags); + if (rval != TRAN_ACCEPT) { + mutex_exit(&mpt->m_mutex); + return (rval); } ! ! start = mptsas_accept_pkt(mpt, cmd, &rval); mutex_exit(&mpt->m_mutex); + if (start) { + (void) mptsas_start_cmd(mpt, cmd); } return (rval); } static int ! mptsas_check_targ_intxtion(mptsas_target_t *ptgt, int cmd_pkt_flags) { /* ! * ptgt->m_dr_flag is a variable that is only ever changed by ! * direct write under the main m_mutex. ! * It doesn't need a mutex hold to protect this read. */ + if (ptgt->m_dr_flag == MPTSAS_DR_INTRANSITION) { ! if (cmd_pkt_flags & FLAG_NOQUEUE) { /* * The command should be allowed to retry by returning * TRAN_BUSY to stall the I/O's which come from * scsi_vhci since the device/path is in unstable state * now.
*** 3211,3227 **** * return TRAN_FATAL_ERROR. */ return (TRAN_FATAL_ERROR); } } ! rval = mptsas_accept_pkt(mpt, cmd); ! return (rval); } static int ! mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd) { int rval = TRAN_ACCEPT; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; NDBG1(("mptsas_accept_pkt: cmd=0x%p", (void *)cmd)); --- 3516,3567 ---- * return TRAN_FATAL_ERROR. */ return (TRAN_FATAL_ERROR); } } ! return (TRAN_ACCEPT); ! } ! /* ! * Note that this function has a side effect of releasing the ! * per target mutex. ! */ ! static void ! mptsas_offline_target_direct(mptsas_t *mpt, mptsas_target_t *ptgt) ! { ! char phy_mask_name[MPTSAS_MAX_PHYS]; ! mptsas_phymask_t phymask = ptgt->m_addr.mta_phymask; ! dev_info_t *parent; ! ! ASSERT(mutex_owned(&mpt->m_mutex)); ! ! ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION; ! bzero(phy_mask_name, MPTSAS_MAX_PHYS); ! (void) sprintf(phy_mask_name, "%x", phymask); ! parent = scsi_hba_iport_find(mpt->m_dip, phy_mask_name); ! ! if (parent != NULL) { ! mptsas_offline_target(mpt, ptgt, ! ptgt->m_deviceinfo & DEVINFO_DIRECT_ATTACHED ? ! MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE : ! MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE, ! parent); ! } else { ! mptsas_log(mpt, CE_WARN, "Failed to find an " ! "iport for \"%s\", should not happen!", ! phy_mask_name); ! } } + /* + * In order to be efficient with the m_mutex (which can be dropped before + * calling mptsas_start_cmd()) indicate if start_cmd should be called via the + * returned value (FALSE or TRUE). Caller is then responsible for doing the + * right thing with the m_mutex. + */ static int ! mptsas_accept_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd, int *tran_rval) { int rval = TRAN_ACCEPT; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; NDBG1(("mptsas_accept_pkt: cmd=0x%p", (void *)cmd));
*** 3230,3253 **** if ((cmd->cmd_flags & CFLAG_PREPARED) == 0) { rval = mptsas_prepare_pkt(cmd); if (rval != TRAN_ACCEPT) { cmd->cmd_flags &= ~CFLAG_TRANFLAG; ! return (rval); } } /* ! * reset the throttle if we were draining */ ! if ((ptgt->m_t_ncmds == 0) && ! (ptgt->m_t_throttle == DRAIN_THROTTLE)) { ! NDBG23(("reset throttle")); ! ASSERT(ptgt->m_reset_delay == 0); ! mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } - /* * If HBA is being reset, the DevHandles are being re-initialized, * which means that they could be invalid even if the target is still * attached. Check if being reset and if DevHandle is being * re-initialized. If this is the case, return BUSY so the I/O can be --- 3570,3599 ---- if ((cmd->cmd_flags & CFLAG_PREPARED) == 0) { rval = mptsas_prepare_pkt(cmd); if (rval != TRAN_ACCEPT) { cmd->cmd_flags &= ~CFLAG_TRANFLAG; ! goto set_tranrval; } } /* ! * If the command came from the tx wait q it may have slipped ! * by the check for dr_flag before being added to the queue. ! * Fail here with abort status. */ ! if (cmd->cmd_flags & CFLAG_TXQ) { ! rval = mptsas_check_targ_intxtion(cmd->cmd_tgt_addr, ! cmd->cmd_pkt_flags); ! if (rval != TRAN_ACCEPT) { ! mptsas_set_pkt_reason(mpt, cmd, CMD_ABORTED, ! STAT_ABORTED); ! mptsas_doneq_add(mpt, cmd); ! mptsas_doneq_empty(mpt); ! goto set_tranrval; ! } } /* * If HBA is being reset, the DevHandles are being re-initialized, * which means that they could be invalid even if the target is still * attached. Check if being reset and if DevHandle is being * re-initialized. If this is the case, return BUSY so the I/O can be
*** 3256,3308 **** if ((ptgt->m_devhdl == MPTSAS_INVALID_DEVHDL) && mpt->m_in_reset) { mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET); if (cmd->cmd_flags & CFLAG_TXQ) { mptsas_doneq_add(mpt, cmd); mptsas_doneq_empty(mpt); - return (rval); } else { ! return (TRAN_BUSY); } } /* * If device handle has already been invalidated, just ! * fail the command. In theory, command from scsi_vhci ! * client is impossible send down command with invalid * devhdl since devhdl is set after path offline, target ! * driver is not suppose to select a offlined path. */ if (ptgt->m_devhdl == MPTSAS_INVALID_DEVHDL) { ! NDBG20(("rejecting command, it might because invalid devhdl " "request.")); mptsas_set_pkt_reason(mpt, cmd, CMD_DEV_GONE, STAT_TERMINATED); if (cmd->cmd_flags & CFLAG_TXQ) { mptsas_doneq_add(mpt, cmd); mptsas_doneq_empty(mpt); - return (rval); } else { ! return (TRAN_FATAL_ERROR); } } /* * The first case is the normal case. mpt gets a command from the * target driver and starts it. * Since SMID 0 is reserved and the TM slot is reserved, the actual max * commands is m_max_requests - 2. */ if ((mpt->m_ncmds <= (mpt->m_max_requests - 2)) && (ptgt->m_t_throttle > HOLD_THROTTLE) && (ptgt->m_t_ncmds < ptgt->m_t_throttle) && ! (ptgt->m_reset_delay == 0) && (ptgt->m_t_nwait == 0) && ((cmd->cmd_pkt_flags & FLAG_NOINTR) == 0)) { ! if (mptsas_save_cmd(mpt, cmd) == TRUE) { ! (void) mptsas_start_cmd(mpt, cmd); } else { mptsas_waitq_add(mpt, cmd); } } else { /* * Add this pkt to the work queue */ mptsas_waitq_add(mpt, cmd); --- 3602,3673 ---- if ((ptgt->m_devhdl == MPTSAS_INVALID_DEVHDL) && mpt->m_in_reset) { mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET); if (cmd->cmd_flags & CFLAG_TXQ) { mptsas_doneq_add(mpt, cmd); mptsas_doneq_empty(mpt); } else { ! rval = TRAN_BUSY; } + goto set_tranrval; + } + + mutex_enter(&ptgt->m_t_mutex); + /* + * reset the throttle if we were draining + */ + if ((ptgt->m_t_ncmds == 0) && + (ptgt->m_t_throttle == DRAIN_THROTTLE)) { + NDBG23(("reset throttle")); + ASSERT(ptgt->m_reset_delay == 0); + mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } /* * If device handle has already been invalidated, just ! * fail the command. In theory, for a command from scsi_vhci ! * client it's impossible to receive a command with an invalid * devhdl since devhdl is set after path offline, target ! * driver is not supposed to select an offlined path. */ if (ptgt->m_devhdl == MPTSAS_INVALID_DEVHDL) { ! NDBG3(("rejecting command, it might because invalid devhdl " "request.")); + mutex_exit(&ptgt->m_t_mutex); mptsas_set_pkt_reason(mpt, cmd, CMD_DEV_GONE, STAT_TERMINATED); if (cmd->cmd_flags & CFLAG_TXQ) { mptsas_doneq_add(mpt, cmd); mptsas_doneq_empty(mpt); } else { ! rval = TRAN_FATAL_ERROR; } + goto set_tranrval; } /* * The first case is the normal case. mpt gets a command from the * target driver and starts it. * Since SMID 0 is reserved and the TM slot is reserved, the actual max * commands is m_max_requests - 2. */ if ((mpt->m_ncmds <= (mpt->m_max_requests - 2)) && (ptgt->m_t_throttle > HOLD_THROTTLE) && (ptgt->m_t_ncmds < ptgt->m_t_throttle) && ! (ptgt->m_reset_delay == 0) && (mpt->m_polled_intr == 0) && (ptgt->m_t_nwait == 0) && ((cmd->cmd_pkt_flags & FLAG_NOINTR) == 0)) { ! ASSERT((cmd->cmd_flags & CFLAG_CMDIOC) == 0); ! if (mptsas_save_cmd_to_slot(mpt, cmd) == TRUE) { ! ptgt->m_t_ncmds++; ! mutex_exit(&ptgt->m_t_mutex); ! cmd->cmd_active_expiration = 0; ! *tran_rval = rval; ! return (TRUE); } else { + mutex_exit(&ptgt->m_t_mutex); mptsas_waitq_add(mpt, cmd); } } else { + mutex_exit(&ptgt->m_t_mutex); /* * Add this pkt to the work queue */ mptsas_waitq_add(mpt, cmd);
*** 3317,3337 **** if ((cmd->cmd_flags & CFLAG_TM_CMD) == 0) { mptsas_doneq_empty(mpt); } } } ! return (rval); } ! int ! mptsas_save_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd) { ! mptsas_slots_t *slots = mpt->m_active; ! uint_t slot, start_rotor; ! mptsas_target_t *ptgt = cmd->cmd_tgt_addr; ! ASSERT(MUTEX_HELD(&mpt->m_mutex)); /* * Account for reserved TM request slot and reserved SMID of 0. */ ASSERT(slots->m_n_normal == (mpt->m_max_requests - 2)); --- 3682,3721 ---- if ((cmd->cmd_flags & CFLAG_TM_CMD) == 0) { mptsas_doneq_empty(mpt); } } } ! set_tranrval: ! *tran_rval = rval; ! return (FALSE); } ! static void ! mptsas_retry_pkt(mptsas_t *mpt, mptsas_cmd_t *cmd) { ! int rval; ! cmd->cmd_pkt_flags |= FLAG_HEAD; ! cmd->cmd_flags |= CFLAG_RETRY; ! cmd->cmd_flags &= ~CFLAG_TXQ; ! if (mptsas_accept_pkt(mpt, cmd, &rval)) { ! (void) mptsas_start_cmd(mpt, cmd); ! } ! ! /* ! * If there was a problem clear the retry flag so that the ! * command will be completed with error rather than get lost! ! */ ! if (rval != TRAN_ACCEPT) ! cmd->cmd_flags &= ~CFLAG_RETRY; ! } ! ! static int ! mptsas_save_cmd_to_slot(mptsas_t *mpt, mptsas_cmd_t *cmd) ! { ! mptsas_slots_t *slots = mpt->m_active; ! uint_t slot, start_rotor, rotor, n_normal; /* * Account for reserved TM request slot and reserved SMID of 0. */ ASSERT(slots->m_n_normal == (mpt->m_max_requests - 2));
*** 3342,3387 **** * considers only the normal slots, not the reserved slot 0 nor the * task management slot m_n_normal + 1. The rotor is left to point to * the normal slot after the one we select, unless we select the last * normal slot in which case it returns to slot 1. */ ! start_rotor = slots->m_rotor; do { ! slot = slots->m_rotor++; ! if (slots->m_rotor > slots->m_n_normal) ! slots->m_rotor = 1; ! if (slots->m_rotor == start_rotor) break; } while (slots->m_slot[slot] != NULL); if (slots->m_slot[slot] != NULL) return (FALSE); ASSERT(slot != 0 && slot <= slots->m_n_normal); cmd->cmd_slot = slot; slots->m_slot[slot] = cmd; ! mpt->m_ncmds++; /* * only increment per target ncmds if this is not a * command that has no target associated with it (i.e. a ! * event acknoledgment) */ if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) { ptgt->m_t_ncmds++; ! } ! cmd->cmd_active_timeout = cmd->cmd_pkt->pkt_time; ! /* ! * If initial timout is less than or equal to one tick, bump ! * the timeout by a tick so that command doesn't timeout before ! * its allotted time. */ ! if (cmd->cmd_active_timeout <= mptsas_scsi_watchdog_tick) { ! cmd->cmd_active_timeout += mptsas_scsi_watchdog_tick; } return (TRUE); } /* --- 3726,3799 ---- * considers only the normal slots, not the reserved slot 0 nor the * task management slot m_n_normal + 1. The rotor is left to point to * the normal slot after the one we select, unless we select the last * normal slot in which case it returns to slot 1. */ ! start_rotor = rotor = slots->m_rotor; ! n_normal = slots->m_n_normal; do { ! slot = rotor++; ! if (rotor > n_normal) ! rotor = 1; ! if (rotor == start_rotor) break; } while (slots->m_slot[slot] != NULL); + slots->m_rotor = rotor; if (slots->m_slot[slot] != NULL) return (FALSE); ASSERT(slot != 0 && slot <= slots->m_n_normal); cmd->cmd_slot = slot; slots->m_slot[slot] = cmd; ! atomic_inc_32(&mpt->m_ncmds); ! ! /* ! * Distribute the commands amongst the reply queues (Interrupt vectors). ! * Stick to 0 for polled. ! */ ! if (!(cmd->cmd_pkt_flags & FLAG_NOINTR) && ! !(cmd->cmd_flags & (CFLAG_PASSTHRU|CFLAG_CONFIG|CFLAG_FW_DIAG)) && ! (mpt->m_post_reply_qcount > 1)) { ! cmd->cmd_rpqidx = slot % mpt->m_post_reply_qcount; ! } ! atomic_inc_32(&mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds); ! return (TRUE); ! } ! ! int ! mptsas_save_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd) ! { ! mptsas_target_t *ptgt = cmd->cmd_tgt_addr; ! ! ASSERT(MUTEX_HELD(&mpt->m_mutex)); ! ! if (!mptsas_save_cmd_to_slot(mpt, cmd)) { ! return (FALSE); ! } /* * only increment per target ncmds if this is not a * command that has no target associated with it (i.e. a ! * event acknoledgement) */ if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) { + /* + * Expiration time is set in mptsas_start_cmd + */ + mutex_enter(&ptgt->m_t_mutex); ptgt->m_t_ncmds++; ! mutex_exit(&ptgt->m_t_mutex); ! cmd->cmd_active_expiration = 0; ! } else { /* ! * Initialize expiration time for passthrough commands, */ ! cmd->cmd_active_expiration = gethrtime() + ! (hrtime_t)cmd->cmd_pkt->pkt_time * NANOSEC; } return (TRUE); } /*
*** 3482,3507 **** /* * Allocate the new packet. */ if (pkt == NULL) { ddi_dma_handle_t save_dma_handle; - ddi_dma_handle_t save_arq_dma_handle; - struct buf *save_arq_bp; - ddi_dma_cookie_t save_arqcookie; cmd = kmem_cache_alloc(mpt->m_kmem_cache, kf); if (cmd) { save_dma_handle = cmd->cmd_dmahandle; - save_arq_dma_handle = cmd->cmd_arqhandle; - save_arq_bp = cmd->cmd_arq_buf; - save_arqcookie = cmd->cmd_arqcookie; bzero(cmd, sizeof (*cmd) + scsi_pkt_size()); cmd->cmd_dmahandle = save_dma_handle; - cmd->cmd_arqhandle = save_arq_dma_handle; - cmd->cmd_arq_buf = save_arq_bp; - cmd->cmd_arqcookie = save_arqcookie; pkt = (void *)((uchar_t *)cmd + sizeof (struct mptsas_cmd)); pkt->pkt_ha_private = (opaque_t)cmd; pkt->pkt_address = *ap; --- 3894,3910 ----
*** 3777,3787 **** * If this was partially allocated we set the resid * the amount of data NOT transferred in this window * If there is only one window, the resid will be 0 */ pkt->pkt_resid = (bp->b_bcount - cmd->cmd_totaldmacount); ! NDBG16(("mptsas_dmaget: cmd_dmacount=%d.", cmd->cmd_dmacount)); } return (pkt); } /* --- 4180,4191 ---- * If this was partially allocated we set the resid * the amount of data NOT transferred in this window * If there is only one window, the resid will be 0 */ pkt->pkt_resid = (bp->b_bcount - cmd->cmd_totaldmacount); ! NDBG3(("mptsas_scsi_init_pkt: cmd_dmacount=%d.", ! cmd->cmd_dmacount)); } return (pkt); } /*
*** 3830,3895 **** static int mptsas_kmem_cache_constructor(void *buf, void *cdrarg, int kmflags) { mptsas_cmd_t *cmd = buf; mptsas_t *mpt = cdrarg; - struct scsi_address ap; - uint_t cookiec; - ddi_dma_attr_t arq_dma_attr; int (*callback)(caddr_t); callback = (kmflags == KM_SLEEP)? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT; NDBG4(("mptsas_kmem_cache_constructor")); - ap.a_hba_tran = mpt->m_tran; - ap.a_target = 0; - ap.a_lun = 0; - /* * allocate a dma handle */ if ((ddi_dma_alloc_handle(mpt->m_dip, &mpt->m_io_dma_attr, callback, NULL, &cmd->cmd_dmahandle)) != DDI_SUCCESS) { cmd->cmd_dmahandle = NULL; return (-1); } - - cmd->cmd_arq_buf = scsi_alloc_consistent_buf(&ap, (struct buf *)NULL, - SENSE_LENGTH, B_READ, callback, NULL); - if (cmd->cmd_arq_buf == NULL) { - ddi_dma_free_handle(&cmd->cmd_dmahandle); - cmd->cmd_dmahandle = NULL; - return (-1); - } - - /* - * allocate a arq handle - */ - arq_dma_attr = mpt->m_msg_dma_attr; - arq_dma_attr.dma_attr_sgllen = 1; - if ((ddi_dma_alloc_handle(mpt->m_dip, &arq_dma_attr, callback, - NULL, &cmd->cmd_arqhandle)) != DDI_SUCCESS) { - ddi_dma_free_handle(&cmd->cmd_dmahandle); - scsi_free_consistent_buf(cmd->cmd_arq_buf); - cmd->cmd_dmahandle = NULL; - cmd->cmd_arqhandle = NULL; - return (-1); - } - - if (ddi_dma_buf_bind_handle(cmd->cmd_arqhandle, - cmd->cmd_arq_buf, (DDI_DMA_READ | DDI_DMA_CONSISTENT), - callback, NULL, &cmd->cmd_arqcookie, &cookiec) != DDI_SUCCESS) { - ddi_dma_free_handle(&cmd->cmd_dmahandle); - ddi_dma_free_handle(&cmd->cmd_arqhandle); - scsi_free_consistent_buf(cmd->cmd_arq_buf); - cmd->cmd_dmahandle = NULL; - cmd->cmd_arqhandle = NULL; - cmd->cmd_arq_buf = NULL; - return (-1); - } - return (0); } static void mptsas_kmem_cache_destructor(void *buf, void *cdrarg) --- 4234,4257 ----
*** 3899,3917 **** #endif mptsas_cmd_t *cmd = buf; NDBG4(("mptsas_kmem_cache_destructor")); - if (cmd->cmd_arqhandle) { - (void) ddi_dma_unbind_handle(cmd->cmd_arqhandle); - ddi_dma_free_handle(&cmd->cmd_arqhandle); - cmd->cmd_arqhandle = NULL; - } - if (cmd->cmd_arq_buf) { - scsi_free_consistent_buf(cmd->cmd_arq_buf); - cmd->cmd_arq_buf = NULL; - } if (cmd->cmd_dmahandle) { ddi_dma_free_handle(&cmd->cmd_dmahandle); cmd->cmd_dmahandle = NULL; } } --- 4261,4270 ----
*** 3965,3975 **** /* * Store the SGL memory address. This chip uses this * address to dma to and from the driver. The second * address is the address mpt uses to fill in the SGL. */ ! p->m_phys_addr = cookie.dmac_address; return (DDI_SUCCESS); } static void --- 4318,4328 ---- /* * Store the SGL memory address. This chip uses this * address to dma to and from the driver. The second * address is the address mpt uses to fill in the SGL. */ ! p->m_phys_addr = cookie.dmac_laddress; return (DDI_SUCCESS); } static void
*** 4000,4015 **** static int mptsas_pkt_alloc_extern(mptsas_t *mpt, mptsas_cmd_t *cmd, int cmdlen, int tgtlen, int statuslen, int kf) { caddr_t cdbp, scbp, tgt; - int (*callback)(caddr_t) = (kf == KM_SLEEP) ? - DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; - struct scsi_address ap; size_t senselength; - ddi_dma_attr_t ext_arq_dma_attr; - uint_t cookiec; NDBG3(("mptsas_pkt_alloc_extern: " "cmd=0x%p cmdlen=%d tgtlen=%d statuslen=%d kf=%x", (void *)cmd, cmdlen, tgtlen, statuslen, kf)); --- 4353,4363 ----
*** 4040,4081 **** /* allocate sense data buf for DMA */ senselength = statuslen - MPTSAS_GET_ITEM_OFF( struct scsi_arq_status, sts_sensedata); cmd->cmd_rqslen = (uchar_t)senselength; - - ap.a_hba_tran = mpt->m_tran; - ap.a_target = 0; - ap.a_lun = 0; - - cmd->cmd_ext_arq_buf = scsi_alloc_consistent_buf(&ap, - (struct buf *)NULL, senselength, B_READ, - callback, NULL); - - if (cmd->cmd_ext_arq_buf == NULL) { - goto fail; - } - /* - * allocate a extern arq handle and bind the buf - */ - ext_arq_dma_attr = mpt->m_msg_dma_attr; - ext_arq_dma_attr.dma_attr_sgllen = 1; - if ((ddi_dma_alloc_handle(mpt->m_dip, - &ext_arq_dma_attr, callback, - NULL, &cmd->cmd_ext_arqhandle)) != DDI_SUCCESS) { - goto fail; - } - - if (ddi_dma_buf_bind_handle(cmd->cmd_ext_arqhandle, - cmd->cmd_ext_arq_buf, (DDI_DMA_READ | DDI_DMA_CONSISTENT), - callback, NULL, &cmd->cmd_ext_arqcookie, - &cookiec) - != DDI_SUCCESS) { - goto fail; } - cmd->cmd_flags |= CFLAG_EXTARQBUFVALID; } return (0); fail: mptsas_pkt_destroy_extern(mpt, cmd); return (1); --- 4388,4411 ---- /* allocate sense data buf for DMA */ senselength = statuslen - MPTSAS_GET_ITEM_OFF( struct scsi_arq_status, sts_sensedata); + if (senselength > mpt->m_req_sense_size) { + unsigned long i; + cmd->cmd_extrqslen = (uint16_t)senselength; + cmd->cmd_extrqschunks = (senselength + + (mpt->m_req_sense_size - 1))/mpt->m_req_sense_size; + i = rmalloc_wait(mpt->m_erqsense_map, + cmd->cmd_extrqschunks); + ASSERT(i != 0); + cmd->cmd_extrqsidx = i - 1; + cmd->cmd_arq_buf = mpt->m_extreq_sense + + (cmd->cmd_extrqsidx * mpt->m_req_sense_size); + } else { cmd->cmd_rqslen = (uchar_t)senselength; } } return (0); fail: mptsas_pkt_destroy_extern(mpt, cmd); return (1);
*** 4093,4116 **** mptsas_log(mpt, CE_PANIC, "mptsas_pkt_destroy_extern: freeing free packet"); _NOTE(NOT_REACHED) /* NOTREACHED */ } if (cmd->cmd_flags & CFLAG_CDBEXTERN) { kmem_free(cmd->cmd_pkt->pkt_cdbp, (size_t)cmd->cmd_cdblen); } if (cmd->cmd_flags & CFLAG_SCBEXTERN) { kmem_free(cmd->cmd_pkt->pkt_scbp, (size_t)cmd->cmd_scblen); - if (cmd->cmd_flags & CFLAG_EXTARQBUFVALID) { - (void) ddi_dma_unbind_handle(cmd->cmd_ext_arqhandle); - } - if (cmd->cmd_ext_arqhandle) { - ddi_dma_free_handle(&cmd->cmd_ext_arqhandle); - cmd->cmd_ext_arqhandle = NULL; - } - if (cmd->cmd_ext_arq_buf) - scsi_free_consistent_buf(cmd->cmd_ext_arq_buf); } if (cmd->cmd_flags & CFLAG_PRIVEXTERN) { kmem_free(cmd->cmd_pkt->pkt_private, (size_t)cmd->cmd_privlen); } cmd->cmd_flags = CFLAG_FREE; --- 4423,4441 ---- mptsas_log(mpt, CE_PANIC, "mptsas_pkt_destroy_extern: freeing free packet"); _NOTE(NOT_REACHED) /* NOTREACHED */ } + if (cmd->cmd_extrqslen != 0) { + rmfree(mpt->m_erqsense_map, cmd->cmd_extrqschunks, + cmd->cmd_extrqsidx + 1); + } if (cmd->cmd_flags & CFLAG_CDBEXTERN) { kmem_free(cmd->cmd_pkt->pkt_cdbp, (size_t)cmd->cmd_cdblen); } if (cmd->cmd_flags & CFLAG_SCBEXTERN) { kmem_free(cmd->cmd_pkt->pkt_scbp, (size_t)cmd->cmd_scblen); } if (cmd->cmd_flags & CFLAG_PRIVEXTERN) { kmem_free(cmd->cmd_pkt->pkt_private, (size_t)cmd->cmd_privlen); } cmd->cmd_flags = CFLAG_FREE;
*** 4152,4166 **** if (cmd->cmd_flags & CFLAG_DMAVALID) { (void) ddi_dma_unbind_handle(cmd->cmd_dmahandle); cmd->cmd_flags &= ~CFLAG_DMAVALID; } - if (cmd->cmd_flags & CFLAG_EXTARQBUFVALID) { - (void) ddi_dma_unbind_handle(cmd->cmd_ext_arqhandle); - cmd->cmd_flags &= ~CFLAG_EXTARQBUFVALID; - } - mptsas_free_extra_sgl_frame(mpt, cmd); } static void mptsas_pkt_comp(struct scsi_pkt *pkt, mptsas_cmd_t *cmd) --- 4477,4486 ----
*** 4172,4229 **** } (*pkt->pkt_comp)(pkt); } static void ! mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control, ! pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl) { ! uint_t cookiec; mptti_t *dmap; uint32_t flags; - pMpi2SGESimple64_t sge; - pMpi2SGEChain64_t sgechain; - ASSERT(cmd->cmd_flags & CFLAG_DMAVALID); - - /* - * Save the number of entries in the DMA - * Scatter/Gather list - */ - cookiec = cmd->cmd_cookiec; - - NDBG1(("mptsas_sge_setup: cookiec=%d", cookiec)); - - /* - * Set read/write bit in control. - */ - if (cmd->cmd_flags & CFLAG_DMASEND) { - *control |= MPI2_SCSIIO_CONTROL_WRITE; - } else { - *control |= MPI2_SCSIIO_CONTROL_READ; - } - - ddi_put32(acc_hdl, &frame->DataLength, cmd->cmd_dmacount); - /* - * We have 2 cases here. First where we can fit all the - * SG elements into the main frame, and the case - * where we can't. - * If we have more cookies than we can attach to a frame - * we will need to use a chain element to point - * a location of memory where the rest of the S/G - * elements reside. - */ - if (cookiec <= MPTSAS_MAX_FRAME_SGES64(mpt)) { dmap = cmd->cmd_sg; sge = (pMpi2SGESimple64_t)(&frame->SGL); while (cookiec--) { ! ddi_put32(acc_hdl, ! &sge->Address.Low, dmap->addr.address64.Low); ! ddi_put32(acc_hdl, ! &sge->Address.High, dmap->addr.address64.High); ! ddi_put32(acc_hdl, &sge->FlagsLength, ! dmap->count); flags = ddi_get32(acc_hdl, &sge->FlagsLength); flags |= ((uint32_t) (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << --- 4492,4518 ---- } (*pkt->pkt_comp)(pkt); } static void ! mptsas_sge_mainframe(mptsas_cmd_t *cmd, pMpi2SCSIIORequest_t frame, ! ddi_acc_handle_t acc_hdl, uint_t cookiec, ! uint32_t end_flags) { ! pMpi2SGESimple64_t sge; mptti_t *dmap; uint32_t flags; dmap = cmd->cmd_sg; + sge = (pMpi2SGESimple64_t)(&frame->SGL); while (cookiec--) { ! ddi_put32(acc_hdl, &sge->Address.Low, ! dmap->addr.address64.Low); ! ddi_put32(acc_hdl, &sge->Address.High, ! dmap->addr.address64.High); ! ddi_put32(acc_hdl, &sge->FlagsLength, dmap->count); flags = ddi_get32(acc_hdl, &sge->FlagsLength); flags |= ((uint32_t) (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
*** 4232,4246 **** /* * If this is the last cookie, we set the flags * to indicate so */ if (cookiec == 0) { ! flags |= ! ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT ! | MPI2_SGE_FLAGS_END_OF_BUFFER ! | MPI2_SGE_FLAGS_END_OF_LIST) << ! MPI2_SGE_FLAGS_SHIFT); } if (cmd->cmd_flags & CFLAG_DMASEND) { flags |= (MPI2_SGE_FLAGS_HOST_TO_IOC << MPI2_SGE_FLAGS_SHIFT); } else { --- 4521,4531 ---- /* * If this is the last cookie, we set the flags * to indicate so */ if (cookiec == 0) { ! flags |= end_flags; } if (cmd->cmd_flags & CFLAG_DMASEND) { flags |= (MPI2_SGE_FLAGS_HOST_TO_IOC << MPI2_SGE_FLAGS_SHIFT); } else {
*** 4249,4259 **** } ddi_put32(acc_hdl, &sge->FlagsLength, flags); dmap++; sge++; } ! } else { /* * Hereby we start to deal with multiple frames. * The process is as follows: * 1. Determine how many frames are needed for SGL element * storage; Note that all frames are stored in contiguous --- 4534,4563 ---- } ddi_put32(acc_hdl, &sge->FlagsLength, flags); dmap++; sge++; } ! } ! ! static void ! mptsas_sge_chain(mptsas_t *mpt, mptsas_cmd_t *cmd, ! pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl) ! { ! pMpi2SGESimple64_t sge; ! pMpi2SGEChain64_t sgechain; ! uint64_t nframe_phys_addr; ! uint_t cookiec; ! mptti_t *dmap; ! uint32_t flags; ! int i, j, k, l, frames, sgemax; ! int temp, maxframe_sges; ! uint8_t chainflags; ! uint16_t chainlength; ! mptsas_cache_frames_t *p; ! ! cookiec = cmd->cmd_cookiec; ! /* * Hereby we start to deal with multiple frames. * The process is as follows: * 1. Determine how many frames are needed for SGL element * storage; Note that all frames are stored in contiguous
*** 4280,4355 **** * hold SGL elements with the last 1 or 2 double-words * (4 or 8 bytes) un-used. On these controllers, we should * recognize that there's not enough room for another SGL * element and move the sge pointer to the next frame. */ - int i, j, k, l, frames, sgemax; - int temp; - uint8_t chainflags; - uint16_t chainlength; - mptsas_cache_frames_t *p; /* * Sgemax is the number of SGE's that will fit * each extra frame and frames is total * number of frames we'll need. 1 sge entry per * frame is reseverd for the chain element thus the -1 below. */ ! sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_SGE_SIMPLE64)) ! - 1); ! temp = (cookiec - (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) / sgemax; /* * A little check to see if we need to round up the number * of frames we need */ ! if ((cookiec - (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) - (temp * ! sgemax) > 1) { frames = (temp + 1); } else { frames = temp; } dmap = cmd->cmd_sg; sge = (pMpi2SGESimple64_t)(&frame->SGL); /* * First fill in the main frame */ ! for (j = 1; j < MPTSAS_MAX_FRAME_SGES64(mpt); j++) { ! ddi_put32(acc_hdl, &sge->Address.Low, ! dmap->addr.address64.Low); ! ddi_put32(acc_hdl, &sge->Address.High, ! dmap->addr.address64.High); ! ddi_put32(acc_hdl, &sge->FlagsLength, dmap->count); ! flags = ddi_get32(acc_hdl, &sge->FlagsLength); ! flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | ! MPI2_SGE_FLAGS_SYSTEM_ADDRESS | ! MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << ! MPI2_SGE_FLAGS_SHIFT); ! ! /* ! * If this is the last SGE of this frame ! * we set the end of list flag ! */ ! if (j == (MPTSAS_MAX_FRAME_SGES64(mpt) - 1)) { ! flags |= ((uint32_t) ! (MPI2_SGE_FLAGS_LAST_ELEMENT) << ! MPI2_SGE_FLAGS_SHIFT); ! } ! if (cmd->cmd_flags & CFLAG_DMASEND) { ! flags |= ! (MPI2_SGE_FLAGS_HOST_TO_IOC << ! MPI2_SGE_FLAGS_SHIFT); ! } else { ! flags |= ! (MPI2_SGE_FLAGS_IOC_TO_HOST << ! MPI2_SGE_FLAGS_SHIFT); ! } ! ddi_put32(acc_hdl, &sge->FlagsLength, flags); ! dmap++; ! sge++; ! } /* * Fill in the chain element in the main frame. * About calculation on ChainOffset: * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes) --- 4584,4626 ---- * hold SGL elements with the last 1 or 2 double-words * (4 or 8 bytes) un-used. On these controllers, we should * recognize that there's not enough room for another SGL * element and move the sge pointer to the next frame. */ /* * Sgemax is the number of SGE's that will fit * each extra frame and frames is total * number of frames we'll need. 1 sge entry per * frame is reseverd for the chain element thus the -1 below. */ ! sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_SGE_SIMPLE64)) - 1); ! maxframe_sges = MPTSAS_MAX_FRAME_SGES64(mpt); ! temp = (cookiec - (maxframe_sges - 1)) / sgemax; /* * A little check to see if we need to round up the number * of frames we need */ ! if ((cookiec - (maxframe_sges - 1)) - (temp * sgemax) > 1) { frames = (temp + 1); } else { frames = temp; } dmap = cmd->cmd_sg; sge = (pMpi2SGESimple64_t)(&frame->SGL); /* * First fill in the main frame */ ! j = maxframe_sges - 1; ! mptsas_sge_mainframe(cmd, frame, acc_hdl, j, ! ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT) << ! MPI2_SGE_FLAGS_SHIFT)); ! dmap += j; ! sge += j; ! j++; /* * Fill in the chain element in the main frame. * About calculation on ChainOffset: * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes)
*** 4390,4402 **** p = cmd->cmd_extra_frames; ddi_put16(acc_hdl, &sgechain->Length, chainlength); ddi_put32(acc_hdl, &sgechain->Address.Low, ! p->m_phys_addr); ! /* SGL is allocated in the first 4G mem range */ ! ddi_put32(acc_hdl, &sgechain->Address.High, 0); /* * If there are more than 2 frames left we have to * fill in the next chain offset to the location of * the chain element in the next frame. --- 4661,4672 ---- p = cmd->cmd_extra_frames; ddi_put16(acc_hdl, &sgechain->Length, chainlength); ddi_put32(acc_hdl, &sgechain->Address.Low, ! (p->m_phys_addr&0xffffffffull)); ! ddi_put32(acc_hdl, &sgechain->Address.High, p->m_phys_addr>>32); /* * If there are more than 2 frames left we have to * fill in the next chain offset to the location of * the chain element in the next frame.
*** 4450,4465 **** * k is the frame counter and (k + 1) * is the number of the next frame. * Note that frames are in contiguous * memory space. */ ddi_put32(p->m_acc_hdl, &sgechain->Address.Low, ! (p->m_phys_addr + ! (mpt->m_req_frame_size * k))); ddi_put32(p->m_acc_hdl, ! &sgechain->Address.High, 0); /* * If there are more than 2 frames left * we have to next chain offset to * the location of the chain element --- 4720,4737 ---- * k is the frame counter and (k + 1) * is the number of the next frame. * Note that frames are in contiguous * memory space. */ + nframe_phys_addr = p->m_phys_addr + + (mpt->m_req_frame_size * k); ddi_put32(p->m_acc_hdl, &sgechain->Address.Low, ! nframe_phys_addr&0xffffffffull); ddi_put32(p->m_acc_hdl, ! &sgechain->Address.High, ! nframe_phys_addr>>32); /* * If there are more than 2 frames left * we have to next chain offset to * the location of the chain element
*** 4558,4666 **** /* * Sync DMA with the chain buffers that were just created */ (void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); - } } ! /* ! * Interrupt handling ! * Utility routine. Poll for status of a command sent to HBA ! * without interrupts (a FLAG_NOINTR command). ! */ ! int ! mptsas_poll(mptsas_t *mpt, mptsas_cmd_t *poll_cmd, int polltime) { ! int rval = TRUE; ! NDBG5(("mptsas_poll: cmd=0x%p", (void *)poll_cmd)); ! if ((poll_cmd->cmd_flags & CFLAG_TM_CMD) == 0) { ! mptsas_restart_hba(mpt); ! } /* ! * Wait, using drv_usecwait(), long enough for the command to ! * reasonably return from the target if the target isn't ! * "dead". A polled command may well be sent from scsi_poll, and ! * there are retries built in to scsi_poll if the transport ! * accepted the packet (TRAN_ACCEPT). scsi_poll waits 1 second ! * and retries the transport up to scsi_poll_busycnt times ! * (currently 60) if ! * 1. pkt_reason is CMD_INCOMPLETE and pkt_state is 0, or ! * 2. pkt_reason is CMD_CMPLT and *pkt_scbp has STATUS_BUSY ! * ! * limit the waiting to avoid a hang in the event that the ! * cmd never gets started but we are still receiving interrupts */ ! while (!(poll_cmd->cmd_flags & CFLAG_FINISHED)) { ! if (mptsas_wait_intr(mpt, polltime) == FALSE) { ! NDBG5(("mptsas_poll: command incomplete")); ! rval = FALSE; ! break; ! } } - if (rval == FALSE) { - /* ! * this isn't supposed to happen, the hba must be wedged ! * Mark this cmd as a timeout. */ ! mptsas_set_pkt_reason(mpt, poll_cmd, CMD_TIMEOUT, ! (STAT_TIMEOUT|STAT_ABORTED)); ! ! if (poll_cmd->cmd_queued == FALSE) { ! ! NDBG5(("mptsas_poll: not on waitq")); ! poll_cmd->cmd_pkt->pkt_state |= (STATE_GOT_BUS|STATE_GOT_TARGET|STATE_SENT_CMD); } else { /* find and remove it from the waitq */ NDBG5(("mptsas_poll: delete from waitq")); mptsas_waitq_delete(mpt, poll_cmd); } } mptsas_fma_check(mpt, poll_cmd); NDBG5(("mptsas_poll: done")); return (rval); } /* * Used for polling cmds and TM function */ static int mptsas_wait_intr(mptsas_t *mpt, int polltime) { ! int cnt; pMpi2ReplyDescriptorsUnion_t reply_desc_union; ! uint32_t int_mask; NDBG5(("mptsas_wait_intr")); ! ! mpt->m_polled_intr = 1; /* ! * Get the current interrupt mask and disable interrupts. When ! * re-enabling ints, set mask to saved value. */ ! int_mask = ddi_get32(mpt->m_datap, &mpt->m_reg->HostInterruptMask); ! MPTSAS_DISABLE_INTR(mpt); /* ! * Keep polling for at least (polltime * 1000) seconds */ for (cnt = 0; cnt < polltime; cnt++) { (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply_desc_union = (pMpi2ReplyDescriptorsUnion_t) ! MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index); if (ddi_get32(mpt->m_acc_post_queue_hdl, &reply_desc_union->Words.Low) == 0xFFFFFFFF || ddi_get32(mpt->m_acc_post_queue_hdl, &reply_desc_union->Words.High) == 0xFFFFFFFF) { --- 4830,5333 ---- /* * Sync DMA with the chain buffers that were just created */ (void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); } ! static void ! mptsas_ieee_sge_mainframe(mptsas_cmd_t *cmd, pMpi2SCSIIORequest_t frame, ! ddi_acc_handle_t acc_hdl, uint_t cookiec, ! uint8_t end_flag) { ! pMpi2IeeeSgeSimple64_t ieeesge; ! mptti_t *dmap; ! uint8_t flags; ! dmap = cmd->cmd_sg; ! NDBG1(("mptsas_ieee_sge_mainframe: cookiec=%d, %s", cookiec, ! cmd->cmd_flags & CFLAG_DMASEND?"Out":"In")); ! ! ieeesge = (pMpi2IeeeSgeSimple64_t)(&frame->SGL); ! while (cookiec--) { ! ddi_put32(acc_hdl, &ieeesge->Address.Low, ! dmap->addr.address64.Low); ! ddi_put32(acc_hdl, &ieeesge->Address.High, ! dmap->addr.address64.High); ! ddi_put32(acc_hdl, &ieeesge->Length, dmap->count); ! NDBG1(("mptsas_ieee_sge_mainframe: len=%d, high=0x%x", ! dmap->count, dmap->addr.address64.High)); ! flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | ! MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); /* ! * If this is the last cookie, we set the flags ! * to indicate so */ ! if (cookiec == 0) { ! flags |= end_flag; } /* ! * XXX: Hmmm, what about the direction based on ! * cmd->cmd_flags & CFLAG_DMASEND? */ ! ddi_put8(acc_hdl, &ieeesge->Flags, flags); ! dmap++; ! ieeesge++; ! } ! } ! static void ! mptsas_ieee_sge_chain(mptsas_t *mpt, mptsas_cmd_t *cmd, ! pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl) ! { ! pMpi2IeeeSgeSimple64_t ieeesge; ! pMpi25IeeeSgeChain64_t ieeesgechain; ! uint64_t nframe_phys_addr; ! uint_t cookiec; ! mptti_t *dmap; ! uint8_t flags; ! int i, j, k, l, frames, sgemax; ! int temp, maxframe_sges; ! uint8_t chainflags; ! uint32_t chainlength; ! mptsas_cache_frames_t *p; ! ! cookiec = cmd->cmd_cookiec; ! ! NDBG1(("mptsas_ieee_sge_chain: cookiec=%d", cookiec)); ! ! /* ! * Hereby we start to deal with multiple frames. ! * The process is as follows: ! * 1. Determine how many frames are needed for SGL element ! * storage; Note that all frames are stored in contiguous ! * memory space and in 64-bit DMA mode each element is ! * 4 double-words (16 bytes) long. ! * 2. Fill up the main frame. We need to do this separately ! * since it contains the SCSI IO request header and needs ! * dedicated processing. Note that the last 4 double-words ! * of the SCSI IO header is for SGL element storage ! * (MPI2_SGE_IO_UNION). ! * 3. Fill the chain element in the main frame, so the DMA ! * engine can use the following frames. ! * 4. Enter a loop to fill the remaining frames. Note that the ! * last frame contains no chain element. The remaining ! * frames go into the mpt SGL buffer allocated on the fly, ! * not immediately following the main message frame, as in ! * Gen1. ! * Some restrictions: ! * 1. For 64-bit DMA, the simple element and chain element ! * are both of 4 double-words (16 bytes) in size, even ! * though all frames are stored in the first 4G of mem ! * range and the higher 32-bits of the address are always 0. ! * 2. On some controllers (like the 1064/1068), a frame can ! * hold SGL elements with the last 1 or 2 double-words ! * (4 or 8 bytes) un-used. On these controllers, we should ! * recognize that there's not enough room for another SGL ! * element and move the sge pointer to the next frame. ! */ ! ! /* ! * Sgemax is the number of SGE's that will fit ! * each extra frame and frames is total ! * number of frames we'll need. 1 sge entry per ! * frame is reseverd for the chain element thus the -1 below. ! */ ! sgemax = ((mpt->m_req_frame_size / sizeof (MPI2_IEEE_SGE_SIMPLE64)) ! - 1); ! maxframe_sges = MPTSAS_MAX_FRAME_SGES64(mpt); ! temp = (cookiec - (maxframe_sges - 1)) / sgemax; ! ! /* ! * A little check to see if we need to round up the number ! * of frames we need ! */ ! if ((cookiec - (maxframe_sges - 1)) - (temp * sgemax) > 1) { ! frames = (temp + 1); ! } else { ! frames = temp; ! } ! NDBG1(("mptsas_ieee_sge_chain: temp=%d, frames=%d", temp, frames)); ! dmap = cmd->cmd_sg; ! ieeesge = (pMpi2IeeeSgeSimple64_t)(&frame->SGL); ! ! /* ! * First fill in the main frame ! */ ! j = maxframe_sges - 1; ! mptsas_ieee_sge_mainframe(cmd, frame, acc_hdl, j, 0); ! dmap += j; ! ieeesge += j; ! j++; ! ! /* ! * Fill in the chain element in the main frame. ! * About calculation on ChainOffset: ! * 1. Struct msg_scsi_io_request has 4 double-words (16 bytes) ! * in the end reserved for SGL element storage ! * (MPI2_SGE_IO_UNION); we should count it in our ! * calculation. See its definition in the header file. ! * 2. Constant j is the counter of the current SGL element ! * that will be processed, and (j - 1) is the number of ! * SGL elements that have been processed (stored in the ! * main frame). ! * 3. ChainOffset value should be in units of quad-words (16 ! * bytes) so the last value should be divided by 16. ! */ ! ddi_put8(acc_hdl, &frame->ChainOffset, ! (sizeof (MPI2_SCSI_IO_REQUEST) - ! sizeof (MPI2_SGE_IO_UNION) + ! (j - 1) * sizeof (MPI2_IEEE_SGE_SIMPLE64)) >> 4); ! ieeesgechain = (pMpi25IeeeSgeChain64_t)ieeesge; ! chainflags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | ! MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); ! ddi_put8(acc_hdl, &ieeesgechain->Flags, chainflags); ! ! /* ! * The size of the next frame is the accurate size of space ! * (in bytes) used to store the SGL elements. j is the counter ! * of SGL elements. (j - 1) is the number of SGL elements that ! * have been processed (stored in frames). ! */ ! if (frames >= 2) { ! chainlength = mpt->m_req_frame_size / ! sizeof (MPI2_IEEE_SGE_SIMPLE64) * ! sizeof (MPI2_IEEE_SGE_SIMPLE64); ! } else { ! chainlength = ((cookiec - (j - 1)) * ! sizeof (MPI2_IEEE_SGE_SIMPLE64)); ! } ! ! p = cmd->cmd_extra_frames; ! ! ddi_put32(acc_hdl, &ieeesgechain->Length, chainlength); ! ddi_put32(acc_hdl, &ieeesgechain->Address.Low, ! p->m_phys_addr&0xffffffffull); ! ddi_put32(acc_hdl, &ieeesgechain->Address.High, p->m_phys_addr>>32); ! ! /* ! * If there are more than 2 frames left we have to ! * fill in the next chain offset to the location of ! * the chain element in the next frame. ! * sgemax is the number of simple elements in an extra ! * frame. Note that the value NextChainOffset should be ! * in double-words (4 bytes). ! */ ! if (frames >= 2) { ! ddi_put8(acc_hdl, &ieeesgechain->NextChainOffset, ! (sgemax * sizeof (MPI2_IEEE_SGE_SIMPLE64)) >> 4); ! } else { ! ddi_put8(acc_hdl, &ieeesgechain->NextChainOffset, 0); ! } ! ! /* ! * Jump to next frame; ! * Starting here, chain buffers go into the per command SGL. ! * This buffer is allocated when chain buffers are needed. ! */ ! ieeesge = (pMpi2IeeeSgeSimple64_t)p->m_frames_addr; ! i = cookiec; ! ! /* ! * Start filling in frames with SGE's. If we ! * reach the end of frame and still have SGE's ! * to fill we need to add a chain element and ! * use another frame. j will be our counter ! * for what cookie we are at and i will be ! * the total cookiec. k is the current frame ! */ ! for (k = 1; k <= frames; k++) { ! for (l = 1; (l <= (sgemax + 1)) && (j <= i); j++, l++) { ! ! /* ! * If we have reached the end of frame ! * and we have more SGE's to fill in ! * we have to fill the final entry ! * with a chain element and then ! * continue to the next frame ! */ ! if ((l == (sgemax + 1)) && (k != frames)) { ! ieeesgechain = (pMpi25IeeeSgeChain64_t)ieeesge; ! j--; ! chainflags = ! MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT | ! MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR; ! ddi_put8(p->m_acc_hdl, ! &ieeesgechain->Flags, chainflags); ! /* ! * k is the frame counter and (k + 1) ! * is the number of the next frame. ! * Note that frames are in contiguous ! * memory space. ! */ ! nframe_phys_addr = p->m_phys_addr + ! (mpt->m_req_frame_size * k); ! ddi_put32(p->m_acc_hdl, ! &ieeesgechain->Address.Low, ! nframe_phys_addr&0xffffffffull); ! ddi_put32(p->m_acc_hdl, ! &ieeesgechain->Address.High, ! nframe_phys_addr>>32); ! ! /* ! * If there are more than 2 frames left ! * we have to next chain offset to ! * the location of the chain element ! * in the next frame and fill in the ! * length of the next chain ! */ ! if ((frames - k) >= 2) { ! ddi_put8(p->m_acc_hdl, ! &ieeesgechain->NextChainOffset, ! (sgemax * ! sizeof (MPI2_IEEE_SGE_SIMPLE64)) ! >> 4); ! ddi_put32(p->m_acc_hdl, ! &ieeesgechain->Length, ! mpt->m_req_frame_size / ! sizeof (MPI2_IEEE_SGE_SIMPLE64) * ! sizeof (MPI2_IEEE_SGE_SIMPLE64)); ! } else { ! /* ! * This is the last frame. Set ! * the NextChainOffset to 0 and ! * Length is the total size of ! * all remaining simple elements ! */ ! ddi_put8(p->m_acc_hdl, ! &ieeesgechain->NextChainOffset, ! 0); ! ddi_put32(p->m_acc_hdl, ! &ieeesgechain->Length, ! (cookiec - j) * ! sizeof (MPI2_IEEE_SGE_SIMPLE64)); ! } ! ! /* Jump to the next frame */ ! ieeesge = (pMpi2IeeeSgeSimple64_t) ! ((char *)p->m_frames_addr + ! (int)mpt->m_req_frame_size * k); ! ! continue; ! } ! ! ddi_put32(p->m_acc_hdl, ! &ieeesge->Address.Low, ! dmap->addr.address64.Low); ! ddi_put32(p->m_acc_hdl, ! &ieeesge->Address.High, ! dmap->addr.address64.High); ! ddi_put32(p->m_acc_hdl, ! &ieeesge->Length, dmap->count); ! flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | ! MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); ! ! /* ! * If we are at the end of the frame and ! * there is another frame to fill in ! * do we need to do anything? ! * if ((l == sgemax) && (k != frames)) { ! * } ! */ ! ! /* ! * If this is the final cookie set end of list. ! */ ! if (j == i) { ! flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST; ! } ! ! ddi_put8(p->m_acc_hdl, &ieeesge->Flags, flags); ! dmap++; ! ieeesge++; ! } ! } ! ! /* ! * Sync DMA with the chain buffers that were just created ! */ ! (void) ddi_dma_sync(p->m_dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); ! } ! ! static void ! mptsas_sge_setup(mptsas_t *mpt, mptsas_cmd_t *cmd, uint32_t *control, ! pMpi2SCSIIORequest_t frame, ddi_acc_handle_t acc_hdl) ! { ! ASSERT(cmd->cmd_flags & CFLAG_DMAVALID); ! ! NDBG1(("mptsas_sge_setup: cookiec=%d", cmd->cmd_cookiec)); ! ! /* ! * Set read/write bit in control. ! */ ! if (cmd->cmd_flags & CFLAG_DMASEND) { ! *control |= MPI2_SCSIIO_CONTROL_WRITE; ! } else { ! *control |= MPI2_SCSIIO_CONTROL_READ; ! } ! ! ddi_put32(acc_hdl, &frame->DataLength, cmd->cmd_dmacount); ! ! /* ! * We have 4 cases here. First where we can fit all the ! * SG elements into the main frame, and the case ! * where we can't. The SG element is also different when using ! * MPI2.5 interface. ! * If we have more cookies than we can attach to a frame ! * we will need to use a chain element to point ! * a location of memory where the rest of the S/G ! * elements reside. ! */ ! if (cmd->cmd_cookiec <= MPTSAS_MAX_FRAME_SGES64(mpt)) { ! if (mpt->m_MPI25) { ! mptsas_ieee_sge_mainframe(cmd, frame, acc_hdl, ! cmd->cmd_cookiec, ! MPI25_IEEE_SGE_FLAGS_END_OF_LIST); ! } else { ! mptsas_sge_mainframe(cmd, frame, acc_hdl, ! cmd->cmd_cookiec, ! ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT ! | MPI2_SGE_FLAGS_END_OF_BUFFER ! | MPI2_SGE_FLAGS_END_OF_LIST) << ! MPI2_SGE_FLAGS_SHIFT)); ! } ! } else { ! if (mpt->m_MPI25) { ! mptsas_ieee_sge_chain(mpt, cmd, frame, acc_hdl); ! } else { ! mptsas_sge_chain(mpt, cmd, frame, acc_hdl); ! } ! } ! } ! ! /* ! * Interrupt handling ! * Utility routine. Poll for status of a command sent to HBA ! * without interrupts (a FLAG_NOINTR command). ! */ ! int ! mptsas_poll(mptsas_t *mpt, mptsas_cmd_t *poll_cmd, int polltime) ! { ! int rval = TRUE; ! uint32_t int_mask; ! ! NDBG5(("mptsas_poll: cmd=0x%p, flags 0x%x", (void *)poll_cmd, ! poll_cmd->cmd_flags)); ! ! /* ! * Get the current interrupt mask and disable interrupts. When ! * re-enabling ints, set mask to saved value. ! */ ! int_mask = ddi_get32(mpt->m_datap, &mpt->m_reg->HostInterruptMask); ! MPTSAS_DISABLE_INTR(mpt); ! ! mpt->m_polled_intr = 1; ! ! if ((poll_cmd->cmd_flags & CFLAG_TM_CMD) == 0) { ! mptsas_restart_hba(mpt); ! } ! ! /* ! * Wait, using drv_usecwait(), long enough for the command to ! * reasonably return from the target if the target isn't ! * "dead". A polled command may well be sent from scsi_poll, and ! * there are retries built in to scsi_poll if the transport ! * accepted the packet (TRAN_ACCEPT). scsi_poll waits 1 second ! * and retries the transport up to scsi_poll_busycnt times ! * (currently 60) if ! * 1. pkt_reason is CMD_INCOMPLETE and pkt_state is 0, or ! * 2. pkt_reason is CMD_CMPLT and *pkt_scbp has STATUS_BUSY ! * ! * limit the waiting to avoid a hang in the event that the ! * cmd never gets started but we are still receiving interrupts ! */ ! while (!(poll_cmd->cmd_flags & CFLAG_FINISHED)) { ! if (mptsas_wait_intr(mpt, polltime) == FALSE) { ! NDBG5(("mptsas_poll: command incomplete")); ! rval = FALSE; ! break; ! } ! } ! ! if (rval == FALSE) { ! ! /* ! * this isn't supposed to happen, the hba must be wedged ! * Mark this cmd as a timeout. ! */ ! mptsas_set_pkt_reason(mpt, poll_cmd, CMD_TIMEOUT, ! (STAT_TIMEOUT|STAT_ABORTED)); ! ! if (poll_cmd->cmd_queued == FALSE) { ! ! NDBG5(("mptsas_poll: not on waitq")); ! ! poll_cmd->cmd_pkt->pkt_state |= (STATE_GOT_BUS|STATE_GOT_TARGET|STATE_SENT_CMD); } else { /* find and remove it from the waitq */ NDBG5(("mptsas_poll: delete from waitq")); mptsas_waitq_delete(mpt, poll_cmd); } } mptsas_fma_check(mpt, poll_cmd); + + /* + * Clear polling flag, re-enable interrupts. + */ + mpt->m_polled_intr = 0; + ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptMask, int_mask); + + /* + * If there are queued cmd, start them now. + */ + if (mpt->m_waitq != NULL) { + mptsas_restart_waitq(mpt); + } + NDBG5(("mptsas_poll: done")); return (rval); } /* * Used for polling cmds and TM function */ static int mptsas_wait_intr(mptsas_t *mpt, int polltime) { ! int cnt, rval = FALSE; pMpi2ReplyDescriptorsUnion_t reply_desc_union; ! mptsas_reply_pqueue_t *rpqp; NDBG5(("mptsas_wait_intr")); ! ASSERT(mutex_owned(&mpt->m_mutex)); /* ! * Keep polling for at least (polltime * 1000) seconds */ ! rpqp = mpt->m_rep_post_queues; /* ! * Drop the main mutex and grab the mutex for reply queue 0 */ + mutex_exit(&mpt->m_mutex); + mutex_enter(&rpqp->rpq_mutex); for (cnt = 0; cnt < polltime; cnt++) { (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); + /* + * Polled requests should only come back through + * the first interrupt. + */ reply_desc_union = (pMpi2ReplyDescriptorsUnion_t) ! MPTSAS_GET_NEXT_REPLY(rpqp, rpqp->rpq_index); if (ddi_get32(mpt->m_acc_post_queue_hdl, &reply_desc_union->Words.Low) == 0xFFFFFFFF || ddi_get32(mpt->m_acc_post_queue_hdl, &reply_desc_union->Words.High) == 0xFFFFFFFF) {
*** 4670,4721 **** /* * The reply is valid, process it according to its * type. */ ! mptsas_process_intr(mpt, reply_desc_union); ! ! if (++mpt->m_post_index == mpt->m_post_queue_depth) { ! mpt->m_post_index = 0; ! } ! ! /* ! * Update the global reply index ! */ ! ddi_put32(mpt->m_datap, ! &mpt->m_reg->ReplyPostHostIndex, mpt->m_post_index); ! mpt->m_polled_intr = 0; /* ! * Re-enable interrupts and quit. */ ! ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptMask, ! int_mask); ! return (TRUE); } /* ! * Clear polling flag, re-enable interrupts and quit. */ ! mpt->m_polled_intr = 0; ! ddi_put32(mpt->m_datap, &mpt->m_reg->HostInterruptMask, int_mask); ! return (FALSE); } static void mptsas_handle_scsi_io_success(mptsas_t *mpt, pMpi2ReplyDescriptorsUnion_t reply_desc) { pMpi2SCSIIOSuccessReplyDescriptor_t scsi_io_success; uint16_t SMID; mptsas_slots_t *slots = mpt->m_active; mptsas_cmd_t *cmd = NULL; struct scsi_pkt *pkt; - ASSERT(mutex_owned(&mpt->m_mutex)); - scsi_io_success = (pMpi2SCSIIOSuccessReplyDescriptor_t)reply_desc; SMID = ddi_get16(mpt->m_acc_post_queue_hdl, &scsi_io_success->SMID); /* * This is a success reply so just complete the IO. First, do a sanity --- 5337,5387 ---- /* * The reply is valid, process it according to its * type. */ ! mptsas_process_intr(mpt, rpqp, reply_desc_union); /* ! * Clear the reply descriptor for re-use. */ ! ddi_put64(mpt->m_acc_post_queue_hdl, ! &((uint64_t *)(void *)rpqp->rpq_queue)[rpqp->rpq_index], ! 0xFFFFFFFFFFFFFFFF); ! (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0, ! DDI_DMA_SYNC_FORDEV); + if (++rpqp->rpq_index == mpt->m_post_queue_depth) { + rpqp->rpq_index = 0; } /* ! * Update the reply index */ ! ddi_put32(mpt->m_datap, ! &mpt->m_reg->ReplyPostHostIndex, rpqp->rpq_index); ! rval = TRUE; ! break; ! } ! ! mutex_exit(&rpqp->rpq_mutex); ! mutex_enter(&mpt->m_mutex); ! ! return (rval); } static void mptsas_handle_scsi_io_success(mptsas_t *mpt, + mptsas_reply_pqueue_t *rpqp, pMpi2ReplyDescriptorsUnion_t reply_desc) { pMpi2SCSIIOSuccessReplyDescriptor_t scsi_io_success; uint16_t SMID; mptsas_slots_t *slots = mpt->m_active; mptsas_cmd_t *cmd = NULL; struct scsi_pkt *pkt; scsi_io_success = (pMpi2SCSIIOSuccessReplyDescriptor_t)reply_desc; SMID = ddi_get16(mpt->m_acc_post_queue_hdl, &scsi_io_success->SMID); /* * This is a success reply so just complete the IO. First, do a sanity
*** 4737,4746 **** --- 5403,5413 ---- if (cmd == NULL) { mptsas_log(mpt, CE_WARN, "?NULL command for successful SCSI IO " "in slot %d", SMID); return; } + ASSERT(cmd->cmd_rpqidx == rpqp->rpq_num); pkt = CMD2PKT(cmd); pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD | STATE_GOT_STATUS); if (cmd->cmd_flags & CFLAG_DMAVALID) {
*** 4750,4761 **** if (cmd->cmd_flags & CFLAG_PASSTHRU) { cmd->cmd_flags |= CFLAG_FINISHED; cv_broadcast(&mpt->m_passthru_cv); return; ! } else { mptsas_remove_cmd(mpt, cmd); } if (cmd->cmd_flags & CFLAG_RETRY) { /* * The target returned QFULL or busy, do not add tihs --- 5417,5450 ---- if (cmd->cmd_flags & CFLAG_PASSTHRU) { cmd->cmd_flags |= CFLAG_FINISHED; cv_broadcast(&mpt->m_passthru_cv); return; ! } ! if (!(cmd->cmd_flags & CFLAG_TM_CMD)) { ! if (cmd->cmd_flags & CFLAG_CMDIOC) { ! mutex_enter(&mpt->m_mutex); mptsas_remove_cmd(mpt, cmd); + mutex_exit(&mpt->m_mutex); + } else { + #ifdef MPTSAS_DEBUG + /* + * In order to test timeout for a command set + * mptsas_test_timeout via mdb to avoid completion + * processing here. + */ + if (mptsas_test_timeout) { + mptsas_test_timeout = 0; + return; + } + #endif + /* + * This is the normal path, avoid grabbing + * the m_mutex. + */ + mptsas_remove_cmd_nomtx(mpt, cmd); + } } if (cmd->cmd_flags & CFLAG_RETRY) { /* * The target returned QFULL or busy, do not add tihs
*** 4766,4787 **** * mptsas_handle_qfull() or in mptsas_check_scsi_io_error(). * Remove this cmd_flag here. */ cmd->cmd_flags &= ~CFLAG_RETRY; } else { ! mptsas_doneq_add(mpt, cmd); } } static void mptsas_handle_address_reply(mptsas_t *mpt, pMpi2ReplyDescriptorsUnion_t reply_desc) { pMpi2AddressReplyDescriptor_t address_reply; pMPI2DefaultReply_t reply; mptsas_fw_diagnostic_buffer_t *pBuffer; ! uint32_t reply_addr; uint16_t SMID, iocstatus; mptsas_slots_t *slots = mpt->m_active; mptsas_cmd_t *cmd = NULL; uint8_t function, buffer_type; m_replyh_arg_t *args; --- 5455,5476 ---- * mptsas_handle_qfull() or in mptsas_check_scsi_io_error(). * Remove this cmd_flag here. */ cmd->cmd_flags &= ~CFLAG_RETRY; } else { ! mptsas_rpdoneq_add(mpt, rpqp, cmd); } } static void mptsas_handle_address_reply(mptsas_t *mpt, pMpi2ReplyDescriptorsUnion_t reply_desc) { pMpi2AddressReplyDescriptor_t address_reply; pMPI2DefaultReply_t reply; mptsas_fw_diagnostic_buffer_t *pBuffer; ! uint32_t reply_addr, reply_frame_dma_baseaddr; uint16_t SMID, iocstatus; mptsas_slots_t *slots = mpt->m_active; mptsas_cmd_t *cmd = NULL; uint8_t function, buffer_type; m_replyh_arg_t *args;
*** 4796,4822 **** /* * If reply frame is not in the proper range we should ignore this * message and exit the interrupt handler. */ ! if ((reply_addr < mpt->m_reply_frame_dma_addr) || ! (reply_addr >= (mpt->m_reply_frame_dma_addr + (mpt->m_reply_frame_size * mpt->m_max_replies))) || ! ((reply_addr - mpt->m_reply_frame_dma_addr) % mpt->m_reply_frame_size != 0)) { mptsas_log(mpt, CE_WARN, "?Received invalid reply frame " "address 0x%x\n", reply_addr); ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); return; } (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply = (pMPI2DefaultReply_t)(mpt->m_reply_frame + (reply_addr - ! mpt->m_reply_frame_dma_addr)); function = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->Function); /* * don't get slot information and command for events since these values * don't exist */ if ((function != MPI2_FUNCTION_EVENT_NOTIFICATION) && --- 5485,5515 ---- /* * If reply frame is not in the proper range we should ignore this * message and exit the interrupt handler. */ ! reply_frame_dma_baseaddr = mpt->m_reply_frame_dma_addr & 0xfffffffful; ! if ((reply_addr < reply_frame_dma_baseaddr) || ! (reply_addr >= (reply_frame_dma_baseaddr + (mpt->m_reply_frame_size * mpt->m_max_replies))) || ! ((reply_addr - reply_frame_dma_baseaddr) % mpt->m_reply_frame_size != 0)) { mptsas_log(mpt, CE_WARN, "?Received invalid reply frame " "address 0x%x\n", reply_addr); ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); return; } (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply = (pMPI2DefaultReply_t)(mpt->m_reply_frame + (reply_addr - ! reply_frame_dma_baseaddr)); function = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->Function); + NDBG31(("mptsas_handle_address_reply: function 0x%x, reply_addr=0x%x", + function, reply_addr)); + /* * don't get slot information and command for events since these values * don't exist */ if ((function != MPI2_FUNCTION_EVENT_NOTIFICATION) &&
*** 4841,4853 **** if (cmd == NULL) { mptsas_log(mpt, CE_WARN, "?NULL command for address " "reply in slot %d", SMID); return; } ! if ((cmd->cmd_flags & CFLAG_PASSTHRU) || ! (cmd->cmd_flags & CFLAG_CONFIG) || ! (cmd->cmd_flags & CFLAG_FW_DIAG)) { cmd->cmd_rfm = reply_addr; cmd->cmd_flags |= CFLAG_FINISHED; cv_broadcast(&mpt->m_passthru_cv); cv_broadcast(&mpt->m_config_cv); cv_broadcast(&mpt->m_fw_diag_cv); --- 5534,5545 ---- if (cmd == NULL) { mptsas_log(mpt, CE_WARN, "?NULL command for address " "reply in slot %d", SMID); return; } ! if ((cmd->cmd_flags & ! (CFLAG_PASSTHRU | CFLAG_CONFIG | CFLAG_FW_DIAG))) { cmd->cmd_rfm = reply_addr; cmd->cmd_flags |= CFLAG_FINISHED; cv_broadcast(&mpt->m_passthru_cv); cv_broadcast(&mpt->m_config_cv); cv_broadcast(&mpt->m_fw_diag_cv);
*** 4873,4883 **** case MPI2_FUNCTION_FW_DOWNLOAD: cmd->cmd_flags |= CFLAG_FINISHED; cv_signal(&mpt->m_fw_cv); break; case MPI2_FUNCTION_EVENT_NOTIFICATION: ! reply_frame_no = (reply_addr - mpt->m_reply_frame_dma_addr) / mpt->m_reply_frame_size; args = &mpt->m_replyh_args[reply_frame_no]; args->mpt = (void *)mpt; args->rfm = reply_addr; --- 5565,5575 ---- case MPI2_FUNCTION_FW_DOWNLOAD: cmd->cmd_flags |= CFLAG_FINISHED; cv_signal(&mpt->m_fw_cv); break; case MPI2_FUNCTION_EVENT_NOTIFICATION: ! reply_frame_no = (reply_addr - reply_frame_dma_baseaddr) / mpt->m_reply_frame_size; args = &mpt->m_replyh_args[reply_frame_no]; args->mpt = (void *)mpt; args->rfm = reply_addr;
*** 4984,4994 **** if (cmd->cmd_flags & CFLAG_FW_CMD) return; if (cmd->cmd_flags & CFLAG_RETRY) { /* ! * The target returned QFULL or busy, do not add tihs * pkt to the doneq since the hba will retry * this cmd. * * The pkt has already been resubmitted in * mptsas_handle_qfull() or in mptsas_check_scsi_io_error(). --- 5676,5686 ---- if (cmd->cmd_flags & CFLAG_FW_CMD) return; if (cmd->cmd_flags & CFLAG_RETRY) { /* ! * The target returned QFULL or busy, do not add this * pkt to the doneq since the hba will retry * this cmd. * * The pkt has already been resubmitted in * mptsas_handle_qfull() or in mptsas_check_scsi_io_error().
*** 4998,5042 **** } else { mptsas_doneq_add(mpt, cmd); } } static void mptsas_check_scsi_io_error(mptsas_t *mpt, pMpi2SCSIIOReply_t reply, mptsas_cmd_t *cmd) { uint8_t scsi_status, scsi_state; ! uint16_t ioc_status; uint32_t xferred, sensecount, responsedata, loginfo = 0; struct scsi_pkt *pkt; struct scsi_arq_status *arqstat; - struct buf *bp; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; uint8_t *sensedata = NULL; ! ! if ((cmd->cmd_flags & (CFLAG_SCBEXTERN | CFLAG_EXTARQBUFVALID)) == ! (CFLAG_SCBEXTERN | CFLAG_EXTARQBUFVALID)) { ! bp = cmd->cmd_ext_arq_buf; ! } else { ! bp = cmd->cmd_arq_buf; ! } scsi_status = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->SCSIStatus); ioc_status = ddi_get16(mpt->m_acc_reply_frame_hdl, &reply->IOCStatus); scsi_state = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->SCSIState); xferred = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->TransferCount); sensecount = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->SenseCount); responsedata = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->ResponseInfo); if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { loginfo = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->IOCLogInfo); mptsas_log(mpt, CE_NOTE, ! "?Log info 0x%x received for target %d.\n" "\tscsi_status=0x%x, ioc_status=0x%x, scsi_state=0x%x", ! loginfo, Tgt(cmd), scsi_status, ioc_status, scsi_state); } NDBG31(("\t\tscsi_status=0x%x, ioc_status=0x%x, scsi_state=0x%x", scsi_status, ioc_status, scsi_state)); --- 5690,5740 ---- } else { mptsas_doneq_add(mpt, cmd); } } + #ifdef MPTSAS_DEBUG + static uint8_t mptsas_last_sense[256]; + #endif + static void mptsas_check_scsi_io_error(mptsas_t *mpt, pMpi2SCSIIOReply_t reply, mptsas_cmd_t *cmd) { uint8_t scsi_status, scsi_state; ! uint16_t ioc_status, cmd_rqs_len; uint32_t xferred, sensecount, responsedata, loginfo = 0; struct scsi_pkt *pkt; struct scsi_arq_status *arqstat; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; uint8_t *sensedata = NULL; ! uint64_t sas_wwn; ! uint8_t phy; ! char wwn_str[MPTSAS_WWN_STRLEN]; scsi_status = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->SCSIStatus); ioc_status = ddi_get16(mpt->m_acc_reply_frame_hdl, &reply->IOCStatus); scsi_state = ddi_get8(mpt->m_acc_reply_frame_hdl, &reply->SCSIState); xferred = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->TransferCount); sensecount = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->SenseCount); responsedata = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->ResponseInfo); if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { + sas_wwn = ptgt->m_addr.mta_wwn; + phy = ptgt->m_phynum; + if (sas_wwn == 0) { + (void) sprintf(wwn_str, "p%x", phy); + } else { + (void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn); + } loginfo = ddi_get32(mpt->m_acc_reply_frame_hdl, &reply->IOCLogInfo); mptsas_log(mpt, CE_NOTE, ! "?Log info 0x%x received for target %d %s.\n" "\tscsi_status=0x%x, ioc_status=0x%x, scsi_state=0x%x", ! loginfo, Tgt(cmd), wwn_str, scsi_status, ioc_status, scsi_state); } NDBG31(("\t\tscsi_status=0x%x, ioc_status=0x%x, scsi_state=0x%x", scsi_status, ioc_status, scsi_state));
*** 5057,5070 **** --- 5755,5770 ---- if ((scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) && ((ioc_status & MPI2_IOCSTATUS_MASK) == MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE)) { pkt->pkt_reason = CMD_INCOMPLETE; pkt->pkt_state |= STATE_GOT_BUS; + mutex_enter(&ptgt->m_t_mutex); if (ptgt->m_reset_delay == 0) { mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE); } + mutex_exit(&ptgt->m_t_mutex); return; } if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { responsedata &= 0x000000FF;
*** 5076,5085 **** --- 5776,5787 ---- } switch (scsi_status) { case MPI2_SCSI_STATUS_CHECK_CONDITION: + (void) ddi_dma_sync(mpt->m_dma_req_sense_hdl, 0, 0, + DDI_DMA_SYNC_FORCPU); pkt->pkt_resid = (cmd->cmd_dmacount - xferred); arqstat = (void*)(pkt->pkt_scbp); arqstat->sts_rqpkt_status = *((struct scsi_status *) (pkt->pkt_scbp)); pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
*** 5093,5107 **** arqstat->sts_rqpkt_reason = pkt->pkt_reason; arqstat->sts_rqpkt_state = pkt->pkt_state; arqstat->sts_rqpkt_state |= STATE_XFERRED_DATA; arqstat->sts_rqpkt_statistics = pkt->pkt_statistics; sensedata = (uint8_t *)&arqstat->sts_sensedata; ! ! bcopy((uchar_t *)bp->b_un.b_addr, sensedata, ((cmd->cmd_rqslen >= sensecount) ? sensecount : ! cmd->cmd_rqslen)); ! arqstat->sts_rqpkt_resid = (cmd->cmd_rqslen - sensecount); cmd->cmd_flags |= CFLAG_CMDARQ; /* * Set proper status for pkt if autosense was valid */ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { --- 5795,5817 ---- arqstat->sts_rqpkt_reason = pkt->pkt_reason; arqstat->sts_rqpkt_state = pkt->pkt_state; arqstat->sts_rqpkt_state |= STATE_XFERRED_DATA; arqstat->sts_rqpkt_statistics = pkt->pkt_statistics; sensedata = (uint8_t *)&arqstat->sts_sensedata; ! #ifdef MPTSAS_DEBUG ! bcopy((uchar_t *)cmd->cmd_arq_buf, mptsas_last_sense, ! cmd->cmd_rqslen); ! #endif ! if (cmd->cmd_extrqslen != 0) { ! cmd_rqs_len = cmd->cmd_extrqslen; ! } else { ! cmd_rqs_len = cmd->cmd_rqslen; ! } ! bcopy((uchar_t *)cmd->cmd_arq_buf, sensedata, ((cmd->cmd_rqslen >= sensecount) ? sensecount : ! cmd_rqs_len)); ! arqstat->sts_rqpkt_resid = (cmd_rqs_len - sensecount); cmd->cmd_flags |= CFLAG_CMDARQ; /* * Set proper status for pkt if autosense was valid */ if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
*** 5149,5158 **** --- 5859,5870 ---- if ((ddi_taskq_dispatch(mpt->m_dr_taskq, mptsas_handle_dr, (void *)topo_node, DDI_NOSLEEP)) != DDI_SUCCESS) { + kmem_free(topo_node, + sizeof (mptsas_topo_change_list_t)); mptsas_log(mpt, CE_NOTE, "mptsas start taskq" "for handle SAS dynamic reconfigure" "failed. \n"); } }
*** 5160,5172 **** --- 5872,5886 ---- case MPI2_SCSI_STATUS_GOOD: switch (ioc_status & MPI2_IOCSTATUS_MASK) { case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: pkt->pkt_reason = CMD_DEV_GONE; pkt->pkt_state |= STATE_GOT_BUS; + mutex_enter(&ptgt->m_t_mutex); if (ptgt->m_reset_delay == 0) { mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE); } + mutex_exit(&ptgt->m_t_mutex); NDBG31(("lost disk for target%d, command:%x", Tgt(cmd), pkt->pkt_cdbp[0])); break; case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: NDBG31(("data overrun: xferred=%d", xferred));
*** 5187,5198 **** if (pkt->pkt_resid != cmd->cmd_dmacount) { pkt->pkt_state |= STATE_XFERRED_DATA; } break; case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: ! mptsas_set_pkt_reason(mpt, ! cmd, CMD_RESET, STAT_BUS_RESET); break; case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_DEV_RESET); --- 5901,5922 ---- if (pkt->pkt_resid != cmd->cmd_dmacount) { pkt->pkt_state |= STATE_XFERRED_DATA; } break; case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: ! if (cmd->cmd_active_expiration <= gethrtime()) { ! /* ! * When timeout requested, propagate ! * proper reason and statistics to ! * target drivers. ! */ ! mptsas_set_pkt_reason(mpt, cmd, CMD_TIMEOUT, ! STAT_BUS_RESET | STAT_TIMEOUT); ! } else { ! mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, ! STAT_BUS_RESET); ! } break; case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_DEV_RESET);
*** 5208,5227 **** /* * set throttles to drain */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE); } /* * retry command */ ! cmd->cmd_flags |= CFLAG_RETRY; ! cmd->cmd_pkt_flags |= FLAG_HEAD; ! ! (void) mptsas_accept_pkt(mpt, cmd); break; default: mptsas_log(mpt, CE_WARN, "unknown ioc_status = %x\n", ioc_status); mptsas_log(mpt, CE_CONT, "scsi_state = %x, transfer " --- 5932,5949 ---- /* * set throttles to drain */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle_mtx(mpt, ptgt, ! DRAIN_THROTTLE); } /* * retry command */ ! mptsas_retry_pkt(mpt, cmd); break; default: mptsas_log(mpt, CE_WARN, "unknown ioc_status = %x\n", ioc_status); mptsas_log(mpt, CE_CONT, "scsi_state = %x, transfer "
*** 5301,5321 **** break; } } static void ! mptsas_doneq_thread(mptsas_doneq_thread_arg_t *arg) { mptsas_t *mpt = arg->mpt; ! uint64_t t = arg->t; mptsas_cmd_t *cmd; struct scsi_pkt *pkt; mptsas_doneq_thread_list_t *item = &mpt->m_doneq_thread_id[t]; mutex_enter(&item->mutex); while (item->flag & MPTSAS_DONEQ_THREAD_ACTIVE) { ! if (!item->doneq) { cv_wait(&item->cv, &item->mutex); } pkt = NULL; if ((cmd = mptsas_doneq_thread_rm(mpt, t)) != NULL) { cmd->cmd_flags |= CFLAG_COMPLETED; --- 6023,6043 ---- break; } } static void ! mptsas_doneq_thread(mptsas_thread_arg_t *arg) { mptsas_t *mpt = arg->mpt; ! uint32_t t = arg->t; mptsas_cmd_t *cmd; struct scsi_pkt *pkt; mptsas_doneq_thread_list_t *item = &mpt->m_doneq_thread_id[t]; mutex_enter(&item->mutex); while (item->flag & MPTSAS_DONEQ_THREAD_ACTIVE) { ! if (!item->dlist.dl_q) { cv_wait(&item->cv, &item->mutex); } pkt = NULL; if ((cmd = mptsas_doneq_thread_rm(mpt, t)) != NULL) { cmd->cmd_flags |= CFLAG_COMPLETED;
*** 5326,5503 **** mptsas_pkt_comp(pkt, cmd); } mutex_enter(&item->mutex); } mutex_exit(&item->mutex); ! mutex_enter(&mpt->m_doneq_mutex); mpt->m_doneq_thread_n--; ! cv_broadcast(&mpt->m_doneq_thread_cv); ! mutex_exit(&mpt->m_doneq_mutex); } /* * mpt interrupt handler. */ static uint_t mptsas_intr(caddr_t arg1, caddr_t arg2) { mptsas_t *mpt = (void *)arg1; pMpi2ReplyDescriptorsUnion_t reply_desc_union; ! uchar_t did_reply = FALSE; ! NDBG1(("mptsas_intr: arg1 0x%p arg2 0x%p", (void *)arg1, (void *)arg2)); ! mutex_enter(&mpt->m_mutex); /* * If interrupts are shared by two channels then check whether this * interrupt is genuinely for this channel by making sure first the * chip is in high power state. */ if ((mpt->m_options & MPTSAS_OPT_PM) && (mpt->m_power_level != PM_LEVEL_D0)) { ! mutex_exit(&mpt->m_mutex); return (DDI_INTR_UNCLAIMED); } /* * If polling, interrupt was triggered by some shared interrupt because * IOC interrupts are disabled during polling, so polling routine will * handle any replies. Considering this, if polling is happening, * return with interrupt unclaimed. */ if (mpt->m_polled_intr) { ! mutex_exit(&mpt->m_mutex); ! mptsas_log(mpt, CE_WARN, "mpt_sas: Unclaimed interrupt"); return (DDI_INTR_UNCLAIMED); } /* ! * Read the istat register. */ ! if ((INTPENDING(mpt)) != 0) { /* ! * read fifo until empty. */ #ifndef __lock_lint _NOTE(CONSTCOND) #endif while (TRUE) { - (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0, - DDI_DMA_SYNC_FORCPU); reply_desc_union = (pMpi2ReplyDescriptorsUnion_t) ! MPTSAS_GET_NEXT_REPLY(mpt, mpt->m_post_index); if (ddi_get32(mpt->m_acc_post_queue_hdl, &reply_desc_union->Words.Low) == 0xFFFFFFFF || ddi_get32(mpt->m_acc_post_queue_hdl, &reply_desc_union->Words.High) == 0xFFFFFFFF) { break; } /* ! * The reply is valid, process it according to its ! * type. Also, set a flag for updating the reply index ! * after they've all been processed. */ ! did_reply = TRUE; ! mptsas_process_intr(mpt, reply_desc_union); /* * Increment post index and roll over if needed. */ ! if (++mpt->m_post_index == mpt->m_post_queue_depth) { ! mpt->m_post_index = 0; } } /* ! * Update the global reply index if at least one reply was ! * processed. */ ! if (did_reply) { ddi_put32(mpt->m_datap, ! &mpt->m_reg->ReplyPostHostIndex, mpt->m_post_index); ! } } else { ! mutex_exit(&mpt->m_mutex); ! return (DDI_INTR_UNCLAIMED); } - NDBG1(("mptsas_intr complete")); /* * If no helper threads are created, process the doneq in ISR. If * helpers are created, use the doneq length as a metric to measure the * load on the interrupt CPU. If it is long enough, which indicates the * load is heavy, then we deliver the IO completions to the helpers. * This measurement has some limitations, although it is simple and * straightforward and works well for most of the cases at present. */ if (!mpt->m_doneq_thread_n || ! (mpt->m_doneq_len <= mpt->m_doneq_length_threshold)) { mptsas_doneq_empty(mpt); } else { ! mptsas_deliver_doneq_thread(mpt); } /* * If there are queued cmd, start them now. */ if (mpt->m_waitq != NULL) { mptsas_restart_waitq(mpt); } - mutex_exit(&mpt->m_mutex); return (DDI_INTR_CLAIMED); } static void ! mptsas_process_intr(mptsas_t *mpt, pMpi2ReplyDescriptorsUnion_t reply_desc_union) { uint8_t reply_type; ! ASSERT(mutex_owned(&mpt->m_mutex)); /* * The reply is valid, process it according to its * type. Also, set a flag for updated the reply index * after they've all been processed. */ reply_type = ddi_get8(mpt->m_acc_post_queue_hdl, &reply_desc_union->Default.ReplyFlags); reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; ! if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { ! mptsas_handle_scsi_io_success(mpt, reply_desc_union); } else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { mptsas_handle_address_reply(mpt, reply_desc_union); } else { mptsas_log(mpt, CE_WARN, "?Bad reply type %x", reply_type); ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); } - - /* - * Clear the reply descriptor for re-use and increment - * index. - */ - ddi_put64(mpt->m_acc_post_queue_hdl, - &((uint64_t *)(void *)mpt->m_post_queue)[mpt->m_post_index], - 0xFFFFFFFFFFFFFFFF); - (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0, - DDI_DMA_SYNC_FORDEV); } /* * handle qfull condition */ static void mptsas_handle_qfull(mptsas_t *mpt, mptsas_cmd_t *cmd) { mptsas_target_t *ptgt = cmd->cmd_tgt_addr; if ((++cmd->cmd_qfull_retries > ptgt->m_qfull_retries) || (ptgt->m_qfull_retries == 0)) { /* * We have exhausted the retries on QFULL, or, * the target driver has indicated that it --- 6048,6324 ---- mptsas_pkt_comp(pkt, cmd); } mutex_enter(&item->mutex); } mutex_exit(&item->mutex); ! mutex_enter(&mpt->m_qthread_mutex); mpt->m_doneq_thread_n--; ! cv_broadcast(&mpt->m_qthread_cv); ! mutex_exit(&mpt->m_qthread_mutex); } /* * mpt interrupt handler. */ static uint_t mptsas_intr(caddr_t arg1, caddr_t arg2) { mptsas_t *mpt = (void *)arg1; + mptsas_reply_pqueue_t *rpqp; + int reply_q = (int)(uintptr_t)arg2; pMpi2ReplyDescriptorsUnion_t reply_desc_union; ! int found = 0, i, rpqidx; ! size_t dma_sync_len; ! off_t dma_sync_offset; ! uint32_t istat; ! NDBG18(("mptsas_intr: arg1 0x%p reply_q 0x%d", (void *)arg1, reply_q)); ! rpqp = &mpt->m_rep_post_queues[reply_q]; /* * If interrupts are shared by two channels then check whether this * interrupt is genuinely for this channel by making sure first the * chip is in high power state. */ if ((mpt->m_options & MPTSAS_OPT_PM) && (mpt->m_power_level != PM_LEVEL_D0)) { ! mpt->m_unclaimed_pm_interrupt_count++; return (DDI_INTR_UNCLAIMED); } + istat = MPTSAS_GET_ISTAT(mpt); + if (!(istat & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT)) { + NDBG18(("Interrupt bit not set, istat 0x%x", istat)); + mpt->m_unclaimed_no_interrupt_count++; + /* + * Really need a good definition of when this is valid. + * It appears not to be if you have multiple reply post + * queues, there may be a better way - need LSI info. + * For now just count them. + */ + #if 0 + return (DDI_INTR_UNCLAIMED); + #endif + } + /* * If polling, interrupt was triggered by some shared interrupt because * IOC interrupts are disabled during polling, so polling routine will * handle any replies. Considering this, if polling is happening, * return with interrupt unclaimed. */ if (mpt->m_polled_intr) { ! mptsas_log(mpt, CE_WARN, ! "Unclaimed interrupt, rpq %d (Polling), istat 0x%x", ! reply_q, istat); ! mpt->m_unclaimed_polled_interrupt_count++; return (DDI_INTR_UNCLAIMED); } /* ! * At the moment this is the only place the mutex is grabbed. ! * So it should never fail! */ ! if (mutex_tryenter(&rpqp->rpq_mutex) == 0) { ! mutex_enter(&rpqp->rpq_mutex); ! rpqp->rpq_intr_mutexbusy++; ! } ! ! dma_sync_len = mpt->m_post_queue_depth * 8; ! dma_sync_offset = dma_sync_len * reply_q; ! (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, ! dma_sync_offset, dma_sync_len, DDI_DMA_SYNC_FORCPU); ! /* ! * Go around the reply queue and process each descriptor until ! * we get to the next unused one. ! * It seems to be an occupational hazard that we get interrupts ! * with nothing to do. These are counted below. */ + rpqidx = rpqp->rpq_index; #ifndef __lock_lint _NOTE(CONSTCOND) #endif while (TRUE) { reply_desc_union = (pMpi2ReplyDescriptorsUnion_t) ! MPTSAS_GET_NEXT_REPLY(rpqp, rpqidx); if (ddi_get32(mpt->m_acc_post_queue_hdl, &reply_desc_union->Words.Low) == 0xFFFFFFFF || ddi_get32(mpt->m_acc_post_queue_hdl, &reply_desc_union->Words.High) == 0xFFFFFFFF) { break; } + found++; + + ASSERT(ddi_get8(mpt->m_acc_post_queue_hdl, + &reply_desc_union->Default.MSIxIndex) == reply_q); + /* ! * Process it according to its type. */ ! mptsas_process_intr(mpt, rpqp, reply_desc_union); ! /* ! * Clear the reply descriptor for re-use. ! */ ! ddi_put64(mpt->m_acc_post_queue_hdl, ! &((uint64_t *)(void *)rpqp->rpq_queue)[rpqidx], ! 0xFFFFFFFFFFFFFFFF); /* * Increment post index and roll over if needed. */ ! if (++rpqidx == mpt->m_post_queue_depth) { ! rpqidx = 0; ! } } + + if (found == 0) { + rpqp->rpq_intr_unclaimed++; + mutex_exit(&rpqp->rpq_mutex); + mpt->m_unclaimed_nocmd_interrupt_count++; + return (DDI_INTR_UNCLAIMED); } + rpqp->rpq_index = rpqidx; + rpqp->rpq_intr_count++; + NDBG18(("mptsas_intr complete(%d), did %d loops", reply_q, found)); + + (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, + dma_sync_offset, dma_sync_len, DDI_DMA_SYNC_FORDEV); + + mpt->m_interrupt_count++; + + /* + * Update the reply index if at least one reply was processed. + * For more than 8 reply queues on SAS3 controllers we have to do + * things a little different. See Chapter 20 in the MPI 2.5 spec. + */ + if (mpt->m_post_reply_qcount > 8) { /* ! * The offsets from the base are multiples of 0x10. ! * We are indexing into 32 bit quantities so calculate ! * the index for that. */ ! i = (reply_q&~0x7) >> 1; ddi_put32(mpt->m_datap, ! &mpt->m_reg->SuppReplyPostHostIndex[i], ! rpqp->rpq_index | ! ((reply_q&0x7)<<MPI2_RPHI_MSIX_INDEX_SHIFT)); ! (void) ddi_get32(mpt->m_datap, ! &mpt->m_reg->SuppReplyPostHostIndex[i]); } else { ! ddi_put32(mpt->m_datap, ! &mpt->m_reg->ReplyPostHostIndex, ! rpqp->rpq_index | (reply_q<<MPI2_RPHI_MSIX_INDEX_SHIFT)); ! (void) ddi_get32(mpt->m_datap, ! &mpt->m_reg->ReplyPostHostIndex); } /* * If no helper threads are created, process the doneq in ISR. If * helpers are created, use the doneq length as a metric to measure the * load on the interrupt CPU. If it is long enough, which indicates the * load is heavy, then we deliver the IO completions to the helpers. * This measurement has some limitations, although it is simple and * straightforward and works well for most of the cases at present. + * To always use the threads set mptsas_doneq_length_threshold_prop + * to zero in the mpt_sas3.conf file. + * + * Check the current reply queue done queue. + */ + if (rpqp->rpq_dlist.dl_len) { + if (!mpt->m_doneq_thread_n || + (rpqp->rpq_dlist.dl_len <= mpt->m_doneq_length_threshold)) { + mptsas_rpdoneq_empty(rpqp); + } else { + mptsas_deliver_doneq_thread(mpt, &rpqp->rpq_dlist); + } + } + + mutex_exit(&rpqp->rpq_mutex); + + /* + * Check the main done queue. If we find something + * grab the mutex and check again before processing. */ + if (mpt->m_dlist.dl_len) { + mutex_enter(&mpt->m_mutex); + if (mpt->m_dlist.dl_len) { if (!mpt->m_doneq_thread_n || ! (mpt->m_dlist.dl_len <= ! mpt->m_doneq_length_threshold)) { mptsas_doneq_empty(mpt); } else { ! mptsas_deliver_doneq_thread(mpt, &mpt->m_dlist); ! } ! } ! mutex_exit(&mpt->m_mutex); } /* * If there are queued cmd, start them now. */ if (mpt->m_waitq != NULL) { + mutex_enter(&mpt->m_mutex); + if (mpt->m_waitq != NULL && mpt->m_polled_intr == 0) { mptsas_restart_waitq(mpt); } mutex_exit(&mpt->m_mutex); + } return (DDI_INTR_CLAIMED); } static void ! mptsas_process_intr(mptsas_t *mpt, mptsas_reply_pqueue_t *rpqp, pMpi2ReplyDescriptorsUnion_t reply_desc_union) { uint8_t reply_type; ! /* ! * Should get here with the reply queue mutex held, but not ! * the main mpt mutex. Want to avoid grabbing that during ! * normal operations if possible. ! */ ! ASSERT(mutex_owned(&rpqp->rpq_mutex)); /* * The reply is valid, process it according to its * type. Also, set a flag for updated the reply index * after they've all been processed. */ reply_type = ddi_get8(mpt->m_acc_post_queue_hdl, &reply_desc_union->Default.ReplyFlags); + NDBG18(("mptsas_process_intr(rpq %d) reply_type 0x%x", rpqp->rpq_num, + reply_type)); reply_type &= MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; ! if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS || ! reply_type == MPI25_RPY_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO_SUCCESS) { ! mptsas_handle_scsi_io_success(mpt, rpqp, reply_desc_union); } else if (reply_type == MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { + mutex_enter(&mpt->m_mutex); mptsas_handle_address_reply(mpt, reply_desc_union); + mutex_exit(&mpt->m_mutex); } else { mptsas_log(mpt, CE_WARN, "?Bad reply type %x", reply_type); ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); } } /* * handle qfull condition */ static void mptsas_handle_qfull(mptsas_t *mpt, mptsas_cmd_t *cmd) { mptsas_target_t *ptgt = cmd->cmd_tgt_addr; + mutex_enter(&ptgt->m_t_mutex); if ((++cmd->cmd_qfull_retries > ptgt->m_qfull_retries) || (ptgt->m_qfull_retries == 0)) { /* * We have exhausted the retries on QFULL, or, * the target driver has indicated that it
*** 5511,5527 **** } else { if (ptgt->m_reset_delay == 0) { ptgt->m_t_throttle = max((ptgt->m_t_ncmds - 2), 0); } - cmd->cmd_pkt_flags |= FLAG_HEAD; cmd->cmd_flags &= ~(CFLAG_TRANFLAG); - cmd->cmd_flags |= CFLAG_RETRY; ! (void) mptsas_accept_pkt(mpt, cmd); /* * when target gives queue full status with no commands * outstanding (m_t_ncmds == 0), throttle is set to 0 * (HOLD_THROTTLE), and the queue full handling start * (see psarc/1994/313); if there are commands outstanding, --- 6332,6348 ---- } else { if (ptgt->m_reset_delay == 0) { ptgt->m_t_throttle = max((ptgt->m_t_ncmds - 2), 0); } + mutex_exit(&ptgt->m_t_mutex); cmd->cmd_flags &= ~(CFLAG_TRANFLAG); ! mptsas_retry_pkt(mpt, cmd); + mutex_enter(&ptgt->m_t_mutex); /* * when target gives queue full status with no commands * outstanding (m_t_ncmds == 0), throttle is set to 0 * (HOLD_THROTTLE), and the queue full handling start * (see psarc/1994/313); if there are commands outstanding,
*** 5540,5558 **** timeout(mptsas_restart_cmd, mpt, ptgt->m_qfull_retry_interval); } } } } mptsas_phymask_t mptsas_physport_to_phymask(mptsas_t *mpt, uint8_t physport) { mptsas_phymask_t phy_mask = 0; uint8_t i = 0; ! NDBG20(("mptsas%d physport_to_phymask enter", mpt->m_instance)); ASSERT(mutex_owned(&mpt->m_mutex)); /* * If physport is 0xFF, this is a RAID volume. Use phymask of 0. --- 6361,6380 ---- timeout(mptsas_restart_cmd, mpt, ptgt->m_qfull_retry_interval); } } } + mutex_exit(&ptgt->m_t_mutex); } mptsas_phymask_t mptsas_physport_to_phymask(mptsas_t *mpt, uint8_t physport) { mptsas_phymask_t phy_mask = 0; uint8_t i = 0; ! NDBG20(("mptsas3%d physport_to_phymask enter", mpt->m_instance)); ASSERT(mutex_owned(&mpt->m_mutex)); /* * If physport is 0xFF, this is a RAID volume. Use phymask of 0.
*** 5567,5577 **** (mpt->m_phy_info[i].port_num == physport)) { phy_mask = mpt->m_phy_info[i].phy_mask; break; } } ! NDBG20(("mptsas%d physport_to_phymask:physport :%x phymask :%x, ", mpt->m_instance, physport, phy_mask)); return (phy_mask); } /* --- 6389,6399 ---- (mpt->m_phy_info[i].port_num == physport)) { phy_mask = mpt->m_phy_info[i].phy_mask; break; } } ! NDBG20(("mptsas3%d physport_to_phymask:physport :%x phymask :%x, ", mpt->m_instance, physport, phy_mask)); return (phy_mask); } /*
*** 5621,5631 **** mptsas_phymask_t mask = 0, phy_mask; char *phy_mask_name; uint8_t current_port; int i, j; ! NDBG20(("mptsas%d update phymask ", mpt->m_instance)); ASSERT(mutex_owned(&mpt->m_mutex)); (void) mptsas_get_sas_io_unit_page(mpt); --- 6443,6453 ---- mptsas_phymask_t mask = 0, phy_mask; char *phy_mask_name; uint8_t current_port; int i, j; ! NDBG20(("mptsas3%d update phymask ", mpt->m_instance)); ASSERT(mutex_owned(&mpt->m_mutex)); (void) mptsas_get_sas_io_unit_page(mpt);
*** 5667,5677 **** */ (void) scsi_hba_iport_register(mpt->m_dip, phy_mask_name); mutex_enter(&mpt->m_mutex); } kmem_free(phy_mask_name, MPTSAS_MAX_PHYS); ! NDBG20(("mptsas%d update phymask return", mpt->m_instance)); } /* * mptsas_handle_dr is a task handler for DR, the DR action includes: * 1. Directly attched Device Added/Removed. --- 6489,6499 ---- */ (void) scsi_hba_iport_register(mpt->m_dip, phy_mask_name); mutex_enter(&mpt->m_mutex); } kmem_free(phy_mask_name, MPTSAS_MAX_PHYS); ! NDBG20(("mptsas3%d update phymask return", mpt->m_instance)); } /* * mptsas_handle_dr is a task handler for DR, the DR action includes: * 1. Directly attched Device Added/Removed.
*** 5687,5710 **** mptsas_topo_change_list_t *topo_node = NULL; mptsas_topo_change_list_t *save_node = NULL; mptsas_t *mpt; dev_info_t *parent = NULL; mptsas_phymask_t phymask = 0; ! char *phy_mask_name; uint8_t flags = 0, physport = 0xff; uint8_t port_update = 0; uint_t event; topo_node = (mptsas_topo_change_list_t *)args; mpt = topo_node->mpt; event = topo_node->event; flags = topo_node->flags; ! phy_mask_name = kmem_zalloc(MPTSAS_MAX_PHYS, KM_SLEEP); ! ! NDBG20(("mptsas%d handle_dr enter", mpt->m_instance)); switch (event) { case MPTSAS_DR_EVENT_RECONFIG_TARGET: if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) || (flags == MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE) || --- 6509,6530 ---- mptsas_topo_change_list_t *topo_node = NULL; mptsas_topo_change_list_t *save_node = NULL; mptsas_t *mpt; dev_info_t *parent = NULL; mptsas_phymask_t phymask = 0; ! char phy_mask_name[MPTSAS_MAX_PHYS]; uint8_t flags = 0, physport = 0xff; uint8_t port_update = 0; uint_t event; topo_node = (mptsas_topo_change_list_t *)args; mpt = topo_node->mpt; event = topo_node->event; flags = topo_node->flags; ! NDBG20(("mptsas3%d handle_dr enter", mpt->m_instance)); switch (event) { case MPTSAS_DR_EVENT_RECONFIG_TARGET: if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) || (flags == MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE) ||
*** 5742,5784 **** (void) mptsas_update_phymask(mpt); mpt->m_port_chng = 0; } mutex_exit(&mpt->m_mutex); while (topo_node) { phymask = 0; if (parent == NULL) { physport = topo_node->un.physport; - event = topo_node->event; - flags = topo_node->flags; if (event & (MPTSAS_DR_EVENT_OFFLINE_TARGET | MPTSAS_DR_EVENT_OFFLINE_SMP)) { /* * For all offline events, phymask is known */ phymask = topo_node->un.phymask; goto find_parent; } - if (event & MPTSAS_TOPO_FLAG_REMOVE_HANDLE) { - goto handle_topo_change; - } if (flags & MPTSAS_TOPO_FLAG_LUN_ASSOCIATED) { phymask = topo_node->un.phymask; goto find_parent; } - if ((flags == - MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED) && - (event == MPTSAS_DR_EVENT_RECONFIG_TARGET)) { - /* - * There is no any field in IR_CONFIG_CHANGE - * event indicate physport/phynum, let's get - * parent after SAS Device Page0 request. - */ - goto handle_topo_change; - } - mutex_enter(&mpt->m_mutex); if (flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) { /* * If the direct attached device added or a * phys disk is being unhidden, argument --- 6562,6604 ---- (void) mptsas_update_phymask(mpt); mpt->m_port_chng = 0; } mutex_exit(&mpt->m_mutex); + while (topo_node) { phymask = 0; + flags = topo_node->flags; + event = topo_node->event; + if (event == MPTSAS_DR_EVENT_REMOVE_HANDLE) { + goto handle_topo_change; + } + if ((event == MPTSAS_DR_EVENT_RECONFIG_TARGET) && + (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED)) { + /* + * There is no any field in IR_CONFIG_CHANGE + * event indicate physport/phynum, let's get + * parent after SAS Device Page0 request. + */ + goto handle_topo_change; + } + if (parent == NULL) { physport = topo_node->un.physport; if (event & (MPTSAS_DR_EVENT_OFFLINE_TARGET | MPTSAS_DR_EVENT_OFFLINE_SMP)) { /* * For all offline events, phymask is known */ phymask = topo_node->un.phymask; goto find_parent; } if (flags & MPTSAS_TOPO_FLAG_LUN_ASSOCIATED) { phymask = topo_node->un.phymask; goto find_parent; } mutex_enter(&mpt->m_mutex); if (flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) { /* * If the direct attached device added or a * phys disk is being unhidden, argument
*** 5790,5801 **** /* * Translate physport to phymask so that we can search * parent dip. */ ! phymask = mptsas_physport_to_phymask(mpt, ! physport); mutex_exit(&mpt->m_mutex); find_parent: bzero(phy_mask_name, MPTSAS_MAX_PHYS); /* --- 6610,6620 ---- /* * Translate physport to phymask so that we can search * parent dip. */ ! phymask = mptsas_physport_to_phymask(mpt, physport); mutex_exit(&mpt->m_mutex); find_parent: bzero(phy_mask_name, MPTSAS_MAX_PHYS); /*
*** 5804,5838 **** */ if (flags & MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) { (void) sprintf(phy_mask_name, "v0"); } else { /* ! * phymask can bo 0 if the drive has been * pulled by the time an add event is * processed. If phymask is 0, just skip this * event and continue. */ if (phymask == 0) { - mutex_enter(&mpt->m_mutex); save_node = topo_node; topo_node = topo_node->next; ASSERT(save_node); kmem_free(save_node, sizeof (mptsas_topo_change_list_t)); - mutex_exit(&mpt->m_mutex); - parent = NULL; continue; } (void) sprintf(phy_mask_name, "%x", phymask); } parent = scsi_hba_iport_find(mpt->m_dip, phy_mask_name); if (parent == NULL) { mptsas_log(mpt, CE_WARN, "Failed to find an " ! "iport, should not happen!"); ! goto out; } } ASSERT(parent); handle_topo_change: --- 6623,6660 ---- */ if (flags & MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) { (void) sprintf(phy_mask_name, "v0"); } else { /* ! * phymask can be 0 if the drive has been * pulled by the time an add event is * processed. If phymask is 0, just skip this * event and continue. */ if (phymask == 0) { save_node = topo_node; topo_node = topo_node->next; ASSERT(save_node); kmem_free(save_node, sizeof (mptsas_topo_change_list_t)); parent = NULL; continue; } (void) sprintf(phy_mask_name, "%x", phymask); } parent = scsi_hba_iport_find(mpt->m_dip, phy_mask_name); if (parent == NULL) { mptsas_log(mpt, CE_WARN, "Failed to find an " ! "iport for \"%s\", should not happen!", ! phy_mask_name); ! save_node = topo_node; ! topo_node = topo_node->next; ! ASSERT(save_node); ! kmem_free(save_node, ! sizeof (mptsas_topo_change_list_t)); ! continue; } } ASSERT(parent); handle_topo_change:
*** 5844,5858 **** */ if (!mpt->m_in_reset) mptsas_handle_topo_change(topo_node, parent); else NDBG20(("skipping topo change received during reset")); save_node = topo_node; topo_node = topo_node->next; ASSERT(save_node); kmem_free(save_node, sizeof (mptsas_topo_change_list_t)); - mutex_exit(&mpt->m_mutex); if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) || (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED) || (flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED)) { /* --- 6666,6680 ---- */ if (!mpt->m_in_reset) mptsas_handle_topo_change(topo_node, parent); else NDBG20(("skipping topo change received during reset")); + mutex_exit(&mpt->m_mutex); save_node = topo_node; topo_node = topo_node->next; ASSERT(save_node); kmem_free(save_node, sizeof (mptsas_topo_change_list_t)); if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) || (flags == MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED) || (flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED)) { /*
*** 5862,5873 **** * parent. Also, reset parent if this is for RAID. */ parent = NULL; } } ! out: ! kmem_free(phy_mask_name, MPTSAS_MAX_PHYS); } static void mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node, dev_info_t *parent) --- 6684,6783 ---- * parent. Also, reset parent if this is for RAID. */ parent = NULL; } } ! } ! ! static void ! mptsas_offline_target(mptsas_t *mpt, mptsas_target_t *ptgt, ! uint8_t topo_flags, dev_info_t *parent) ! { ! uint64_t sas_wwn = 0; ! uint8_t phy; ! char wwn_str[MPTSAS_WWN_STRLEN]; ! uint16_t devhdl; ! int circ = 0, circ1 = 0; ! int rval = 0; ! ! sas_wwn = ptgt->m_addr.mta_wwn; ! phy = ptgt->m_phynum; ! devhdl = ptgt->m_devhdl; ! ! if (sas_wwn) { ! (void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn); ! } else { ! (void) sprintf(wwn_str, "p%x", phy); ! } ! ! /* ! * Abort all outstanding command on the device ! */ ! rval = mptsas_do_scsi_reset(mpt, devhdl); ! if (rval) { ! NDBG20(("mptsas3%d: mptsas_offline_target: reset target " ! "before offline devhdl:%x, phymask:%x, rval:%x", ! mpt->m_instance, ptgt->m_devhdl, ! ptgt->m_addr.mta_phymask, rval)); ! } ! ! mutex_exit(&mpt->m_mutex); ! ! ndi_devi_enter(scsi_vhci_dip, &circ); ! ndi_devi_enter(parent, &circ1); ! rval = mptsas_offline_targetdev(parent, wwn_str); ! ndi_devi_exit(parent, circ1); ! ndi_devi_exit(scsi_vhci_dip, circ); ! NDBG20(("mptsas3%d: mptsas_offline_target %s devhdl:%x, " ! "phymask:%x, rval:%x", mpt->m_instance, wwn_str, ! ptgt->m_devhdl, ptgt->m_addr.mta_phymask, rval)); ! ! /* ! * Clear parent's props for SMHBA support ! */ ! if (topo_flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) { ! if (ddi_prop_update_string(DDI_DEV_T_NONE, parent, ! SCSI_ADDR_PROP_ATTACHED_PORT, "") != ! DDI_PROP_SUCCESS) { ! (void) ddi_prop_remove(DDI_DEV_T_NONE, parent, ! SCSI_ADDR_PROP_ATTACHED_PORT); ! mptsas_log(mpt, CE_WARN, "mptsas attached port " ! "prop update failed"); ! } ! if (ddi_prop_update_int(DDI_DEV_T_NONE, parent, ! MPTSAS_NUM_PHYS, 0) != DDI_PROP_SUCCESS) { ! (void) ddi_prop_remove(DDI_DEV_T_NONE, parent, ! MPTSAS_NUM_PHYS); ! mptsas_log(mpt, CE_WARN, "mptsas num phys " ! "prop update failed"); ! } ! if (ddi_prop_update_int(DDI_DEV_T_NONE, parent, ! MPTSAS_VIRTUAL_PORT, 1) != DDI_PROP_SUCCESS) { ! (void) ddi_prop_remove(DDI_DEV_T_NONE, parent, ! MPTSAS_VIRTUAL_PORT); ! mptsas_log(mpt, CE_WARN, "mptsas virtual port " ! "prop update failed"); ! } ! } ! ! mutex_enter(&mpt->m_mutex); ! ptgt->m_led_status = 0; ! (void) mptsas_flush_led_status(mpt, ptgt); ! if (rval == DDI_SUCCESS) { ! mutex_destroy(&ptgt->m_t_mutex); ! refhash_remove(mpt->m_targets, ptgt); ! ptgt = NULL; ! } else { ! /* ! * clean DR_INTRANSITION flag to allow I/O down to ! * PHCI driver since failover finished. ! * Invalidate the devhdl ! */ ! ptgt->m_devhdl = MPTSAS_INVALID_DEVHDL; ! ptgt->m_tgt_unconfigured = 0; ! ptgt->m_dr_flag = MPTSAS_DR_INACTIVE; ! } } static void mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node, dev_info_t *parent)
*** 5875,5894 **** mptsas_target_t *ptgt = NULL; mptsas_smp_t *psmp = NULL; mptsas_t *mpt = (void *)topo_node->mpt; uint16_t devhdl; uint16_t attached_devhdl; - uint64_t sas_wwn = 0; int rval = 0; uint32_t page_address; ! uint8_t phy, flags; ! char *addr = NULL; dev_info_t *lundip; int circ = 0, circ1 = 0; char attached_wwnstr[MPTSAS_WWN_STRLEN]; ! NDBG20(("mptsas%d handle_topo_change enter", mpt->m_instance)); ASSERT(mutex_owned(&mpt->m_mutex)); switch (topo_node->event) { case MPTSAS_DR_EVENT_RECONFIG_TARGET: --- 6785,6804 ---- mptsas_target_t *ptgt = NULL; mptsas_smp_t *psmp = NULL; mptsas_t *mpt = (void *)topo_node->mpt; uint16_t devhdl; uint16_t attached_devhdl; int rval = 0; uint32_t page_address; ! uint8_t flags; dev_info_t *lundip; int circ = 0, circ1 = 0; char attached_wwnstr[MPTSAS_WWN_STRLEN]; ! NDBG20(("mptsas3%d handle_topo_change enter, devhdl 0x%x," ! "event 0x%x, flags 0x%x", mpt->m_instance, topo_node->devhdl, ! topo_node->event, topo_node->flags)); ASSERT(mutex_owned(&mpt->m_mutex)); switch (topo_node->event) { case MPTSAS_DR_EVENT_RECONFIG_TARGET:
*** 6043,6199 **** return; } } } mutex_enter(&mpt->m_mutex); ! ! NDBG20(("mptsas%d handle_topo_change to online devhdl:%x, " ! "phymask:%x.", mpt->m_instance, ptgt->m_devhdl, ! ptgt->m_addr.mta_phymask)); ! break; ! } ! case MPTSAS_DR_EVENT_OFFLINE_TARGET: ! { ! devhdl = topo_node->devhdl; ! ptgt = refhash_linear_search(mpt->m_targets, ! mptsas_target_eval_devhdl, &devhdl); ! if (ptgt == NULL) ! break; ! ! sas_wwn = ptgt->m_addr.mta_wwn; ! phy = ptgt->m_phynum; ! ! addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP); ! ! if (sas_wwn) { ! (void) sprintf(addr, "w%016"PRIx64, sas_wwn); ! } else { ! (void) sprintf(addr, "p%x", phy); ! } ! ASSERT(ptgt->m_devhdl == devhdl); ! ! if ((topo_node->flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) || ! (topo_node->flags == ! MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED)) { ! /* ! * Get latest RAID info if RAID volume status changes ! * or Phys Disk status changes ! */ ! (void) mptsas_get_raid_info(mpt); ! } ! /* ! * Abort all outstanding command on the device ! */ ! rval = mptsas_do_scsi_reset(mpt, devhdl); ! if (rval) { ! NDBG20(("mptsas%d handle_topo_change to reset target " ! "before offline devhdl:%x, phymask:%x, rval:%x", ! mpt->m_instance, ptgt->m_devhdl, ! ptgt->m_addr.mta_phymask, rval)); ! } ! ! mutex_exit(&mpt->m_mutex); ! ! ndi_devi_enter(scsi_vhci_dip, &circ); ! ndi_devi_enter(parent, &circ1); ! rval = mptsas_offline_target(parent, addr); ! ndi_devi_exit(parent, circ1); ! ndi_devi_exit(scsi_vhci_dip, circ); ! NDBG20(("mptsas%d handle_topo_change to offline devhdl:%x, " ! "phymask:%x, rval:%x", mpt->m_instance, ! ptgt->m_devhdl, ptgt->m_addr.mta_phymask, rval)); ! ! kmem_free(addr, SCSI_MAXNAMELEN); ! ! /* ! * Clear parent's props for SMHBA support ! */ ! flags = topo_node->flags; ! if (flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) { ! bzero(attached_wwnstr, sizeof (attached_wwnstr)); ! if (ddi_prop_update_string(DDI_DEV_T_NONE, parent, ! SCSI_ADDR_PROP_ATTACHED_PORT, attached_wwnstr) != ! DDI_PROP_SUCCESS) { ! (void) ddi_prop_remove(DDI_DEV_T_NONE, parent, ! SCSI_ADDR_PROP_ATTACHED_PORT); ! mptsas_log(mpt, CE_WARN, "mptsas attached port " ! "prop update failed"); ! break; ! } ! if (ddi_prop_update_int(DDI_DEV_T_NONE, parent, ! MPTSAS_NUM_PHYS, 0) != ! DDI_PROP_SUCCESS) { ! (void) ddi_prop_remove(DDI_DEV_T_NONE, parent, ! MPTSAS_NUM_PHYS); ! mptsas_log(mpt, CE_WARN, "mptsas num phys " ! "prop update failed"); ! break; ! } ! if (ddi_prop_update_int(DDI_DEV_T_NONE, parent, ! MPTSAS_VIRTUAL_PORT, 1) != ! DDI_PROP_SUCCESS) { ! (void) ddi_prop_remove(DDI_DEV_T_NONE, parent, ! MPTSAS_VIRTUAL_PORT); ! mptsas_log(mpt, CE_WARN, "mptsas virtual port " ! "prop update failed"); ! break; ! } ! } ! ! mutex_enter(&mpt->m_mutex); ! ptgt->m_led_status = 0; ! (void) mptsas_flush_led_status(mpt, ptgt); ! if (rval == DDI_SUCCESS) { ! refhash_remove(mpt->m_targets, ptgt); ! ptgt = NULL; ! } else { /* ! * clean DR_INTRANSITION flag to allow I/O down to ! * PHCI driver since failover finished. ! * Invalidate the devhdl */ ! ptgt->m_devhdl = MPTSAS_INVALID_DEVHDL; ! ptgt->m_tgt_unconfigured = 0; ! mutex_enter(&mpt->m_tx_waitq_mutex); ! ptgt->m_dr_flag = MPTSAS_DR_INACTIVE; ! mutex_exit(&mpt->m_tx_waitq_mutex); } /* * Send SAS IO Unit Control to free the dev handle */ if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) || (flags == MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE)) { rval = mptsas_free_devhdl(mpt, devhdl); ! NDBG20(("mptsas%d handle_topo_change to remove " "devhdl:%x, rval:%x", mpt->m_instance, devhdl, rval)); } break; } ! case MPTSAS_TOPO_FLAG_REMOVE_HANDLE: { devhdl = topo_node->devhdl; /* ! * If this is the remove handle event, do a reset first. */ - if (topo_node->event == MPTSAS_TOPO_FLAG_REMOVE_HANDLE) { rval = mptsas_do_scsi_reset(mpt, devhdl); - if (rval) { NDBG20(("mpt%d reset target before remove " ! "devhdl:%x, rval:%x", mpt->m_instance, ! devhdl, rval)); ! } ! } /* * Send SAS IO Unit Control to free the dev handle */ rval = mptsas_free_devhdl(mpt, devhdl); ! NDBG20(("mptsas%d handle_topo_change to remove " "devhdl:%x, rval:%x", mpt->m_instance, devhdl, rval)); break; } case MPTSAS_DR_EVENT_RECONFIG_SMP: --- 6953,7020 ---- return; } } } mutex_enter(&mpt->m_mutex); ! ! NDBG20(("mptsas3%d handle_topo_change to online devhdl:%x, " ! "phymask:%x.", mpt->m_instance, ptgt->m_devhdl, ! ptgt->m_addr.mta_phymask)); ! break; ! } ! case MPTSAS_DR_EVENT_OFFLINE_TARGET: ! { ! devhdl = topo_node->devhdl; ! ptgt = refhash_linear_search(mpt->m_targets, ! mptsas_target_eval_devhdl, &devhdl); ! if (ptgt == NULL) ! break; ! ! ASSERT(ptgt->m_devhdl == devhdl); ! ! if ((topo_node->flags == MPTSAS_TOPO_FLAG_RAID_ASSOCIATED) || ! (topo_node->flags == ! MPTSAS_TOPO_FLAG_RAID_PHYSDRV_ASSOCIATED)) { /* ! * Get latest RAID info if RAID volume status changes ! * or Phys Disk status changes */ ! (void) mptsas_get_raid_info(mpt); } + mptsas_offline_target(mpt, ptgt, topo_node->flags, parent); + /* * Send SAS IO Unit Control to free the dev handle */ if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) || (flags == MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE)) { rval = mptsas_free_devhdl(mpt, devhdl); ! NDBG20(("mptsas3%d handle_topo_change to remove " "devhdl:%x, rval:%x", mpt->m_instance, devhdl, rval)); } break; } ! case MPTSAS_DR_EVENT_REMOVE_HANDLE: { devhdl = topo_node->devhdl; + /* ! * Do a reset first. */ rval = mptsas_do_scsi_reset(mpt, devhdl); NDBG20(("mpt%d reset target before remove " ! "devhdl:%x, rval:%x", mpt->m_instance, devhdl, rval)); /* * Send SAS IO Unit Control to free the dev handle */ rval = mptsas_free_devhdl(mpt, devhdl); ! NDBG20(("mptsas3%d handle_topo_change to remove " "devhdl:%x, rval:%x", mpt->m_instance, devhdl, rval)); break; } case MPTSAS_DR_EVENT_RECONFIG_SMP:
*** 6282,6292 **** return; } } mutex_enter(&mpt->m_mutex); ! NDBG20(("mptsas%d handle_topo_change to remove devhdl:%x, " "rval:%x", mpt->m_instance, psmp->m_devhdl, rval)); if (rval == DDI_SUCCESS) { refhash_remove(mpt->m_smp_targets, psmp); } else { psmp->m_devhdl = MPTSAS_INVALID_DEVHDL; --- 7103,7113 ---- return; } } mutex_enter(&mpt->m_mutex); ! NDBG20(("mptsas3%d handle_topo_change to remove devhdl:%x, " "rval:%x", mpt->m_instance, psmp->m_devhdl, rval)); if (rval == DDI_SUCCESS) { refhash_remove(mpt->m_smp_targets, psmp); } else { psmp->m_devhdl = MPTSAS_INVALID_DEVHDL;
*** 6318,6328 **** replyh_arg = (m_replyh_arg_t *)args; rfm = replyh_arg->rfm; mpt = replyh_arg->mpt; eventreply = (pMpi2EventNotificationReply_t) ! (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr)); event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event); /* * Generate a system event to let anyone who cares know that a --- 7139,7150 ---- replyh_arg = (m_replyh_arg_t *)args; rfm = replyh_arg->rfm; mpt = replyh_arg->mpt; eventreply = (pMpi2EventNotificationReply_t) ! (mpt->m_reply_frame + (rfm - ! (mpt->m_reply_frame_dma_addr&0xfffffffful))); event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event); /* * Generate a system event to let anyone who cares know that a
*** 6406,6430 **** mpt = replyh_arg->mpt; ASSERT(mutex_owned(&mpt->m_mutex)); eventreply = (pMpi2EventNotificationReply_t) ! (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr)); event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event); if (iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->IOCStatus)) { if (iocstatus == MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { mptsas_log(mpt, CE_WARN, ! "!mptsas_handle_event_sync: IOCStatus=0x%x, " ! "IOCLogInfo=0x%x", iocstatus, ddi_get32(mpt->m_acc_reply_frame_hdl, &eventreply->IOCLogInfo)); } else { mptsas_log(mpt, CE_WARN, ! "mptsas_handle_event_sync: IOCStatus=0x%x, " ! "IOCLogInfo=0x%x", iocstatus, ddi_get32(mpt->m_acc_reply_frame_hdl, &eventreply->IOCLogInfo)); } } --- 7228,7255 ---- mpt = replyh_arg->mpt; ASSERT(mutex_owned(&mpt->m_mutex)); eventreply = (pMpi2EventNotificationReply_t) ! (mpt->m_reply_frame + (rfm - ! (mpt->m_reply_frame_dma_addr&0xfffffffful))); event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event); if (iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->IOCStatus)) { if (iocstatus == MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { mptsas_log(mpt, CE_WARN, ! "!mptsas_handle_event_sync: event 0x%x, " ! "IOCStatus=0x%x, " ! "IOCLogInfo=0x%x", event, iocstatus, ddi_get32(mpt->m_acc_reply_frame_hdl, &eventreply->IOCLogInfo)); } else { mptsas_log(mpt, CE_WARN, ! "mptsas_handle_event_sync: event 0x%x, " ! "IOCStatus=0x%x, " ! "(IOCLogInfo=0x%x)", event, iocstatus, ddi_get32(mpt->m_acc_reply_frame_hdl, &eventreply->IOCLogInfo)); } }
*** 6555,6565 **** prev[0] = 0; string[0] = 0; switch (reason_code) { case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: { ! NDBG20(("mptsas%d phy %d physical_port %d " "dev_handle %d added", mpt->m_instance, phy, physport, dev_handle)); link_rate = ddi_get8(mpt->m_acc_reply_frame_hdl, &sas_topo_change_list->PHY[i].LinkRate); state = (link_rate & --- 7380,7390 ---- prev[0] = 0; string[0] = 0; switch (reason_code) { case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: { ! NDBG20(("mptsas3%d phy %d physical_port %d " "dev_handle %d added", mpt->m_instance, phy, physport, dev_handle)); link_rate = ddi_get8(mpt->m_acc_reply_frame_hdl, &sas_topo_change_list->PHY[i].LinkRate); state = (link_rate &
*** 6591,6600 **** --- 7416,7429 ---- break; case MPI2_EVENT_SAS_TOPO_LR_RATE_6_0: (void) sprintf(curr, "is online at 6.0 " "Gbps"); break; + case MPI25_EVENT_SAS_TOPO_LR_RATE_12_0: + (void) sprintf(curr, + "is online at 12.0 Gbps"); + break; default: (void) sprintf(curr, "state is " "unknown"); break; }
*** 6637,6647 **** } break; } case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: { ! NDBG20(("mptsas%d phy %d physical_port %d " "dev_handle %d removed", mpt->m_instance, phy, physport, dev_handle)); /* * Set association flag according to if an * expander is used or not. --- 7466,7476 ---- } break; } case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: { ! NDBG20(("mptsas3%d phy %d physical_port %d " "dev_handle %d removed", mpt->m_instance, phy, physport, dev_handle)); /* * Set association flag according to if an * expander is used or not.
*** 6668,6687 **** * the hash table because the add event will * have an invalid phymask. BUT, this does not * mean that the DevHandle is invalid. The * controller will still have a valid DevHandle * that must be removed. To do this, use the ! * MPTSAS_TOPO_FLAG_REMOVE_HANDLE event. */ if (ptgt == NULL) { topo_node = kmem_zalloc( sizeof (mptsas_topo_change_list_t), KM_SLEEP); topo_node->mpt = mpt; topo_node->un.phymask = 0; topo_node->event = ! MPTSAS_TOPO_FLAG_REMOVE_HANDLE; topo_node->devhdl = dev_handle; topo_node->flags = flags; topo_node->object = NULL; if (topo_head == NULL) { topo_head = topo_tail = --- 7497,7516 ---- * the hash table because the add event will * have an invalid phymask. BUT, this does not * mean that the DevHandle is invalid. The * controller will still have a valid DevHandle * that must be removed. To do this, use the ! * MPTSAS_DR_EVENT_REMOVE_HANDLE event. */ if (ptgt == NULL) { topo_node = kmem_zalloc( sizeof (mptsas_topo_change_list_t), KM_SLEEP); topo_node->mpt = mpt; topo_node->un.phymask = 0; topo_node->event = ! MPTSAS_DR_EVENT_REMOVE_HANDLE; topo_node->devhdl = dev_handle; topo_node->flags = flags; topo_node->object = NULL; if (topo_head == NULL) { topo_head = topo_tail =
*** 6693,6712 **** break; } /* * Update DR flag immediately avoid I/O failure ! * before failover finish. Pay attention to the ! * mutex protect, we need grab m_tx_waitq_mutex ! * during set m_dr_flag because we won't add ! * the following command into waitq, instead, * we need return TRAN_BUSY in the tran_start * context. */ - mutex_enter(&mpt->m_tx_waitq_mutex); ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION; - mutex_exit(&mpt->m_tx_waitq_mutex); topo_node = kmem_zalloc( sizeof (mptsas_topo_change_list_t), KM_SLEEP); topo_node->mpt = mpt; --- 7522,7537 ---- break; } /* * Update DR flag immediately avoid I/O failure ! * before failover finish. We won't add ! * any following commands into waitq, instead, * we need return TRAN_BUSY in the tran_start * context. */ ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION; topo_node = kmem_zalloc( sizeof (mptsas_topo_change_list_t), KM_SLEEP); topo_node->mpt = mpt;
*** 6794,6803 **** --- 7619,7640 ---- mptsas_smhba_log_sysevent(mpt, ESC_SAS_PHY_EVENT, SAS_PHY_ONLINE, &mpt->m_phy_info[i].smhba_info); break; + case MPI25_EVENT_SAS_TOPO_LR_RATE_12_0: + (void) sprintf(curr, "is online at " + "12.0 Gbps"); + if ((expd_handle == 0) && + (enc_handle == 1)) { + mpt->m_port_chng = 1; + } + mptsas_smhba_log_sysevent(mpt, + ESC_SAS_PHY_EVENT, + SAS_PHY_ONLINE, + &mpt->m_phy_info[i].smhba_info); + break; default: (void) sprintf(curr, "state is " "unknown"); break; }
*** 6831,6840 **** --- 7668,7681 ---- break; case MPI2_EVENT_SAS_TOPO_LR_RATE_6_0: (void) sprintf(prev, ", was online at " "6.0 Gbps"); break; + case MPI25_EVENT_SAS_TOPO_LR_RATE_12_0: + (void) sprintf(prev, ", was online at " + "12.0 Gbps"); + break; default: break; } (void) sprintf(&string[strlen(string)], "link " "changed, ");
*** 6845,6865 **** (void) sprintf(&string[strlen(string)], "target not responding, delaying " "removal"); break; } ! NDBG20(("mptsas%d phy %d DevHandle %x, %s%s%s\n", mpt->m_instance, phy, dev_handle, string, curr, prev)); } if (topo_head != NULL) { /* * Launch DR taskq to handle topology change */ if ((ddi_taskq_dispatch(mpt->m_dr_taskq, mptsas_handle_dr, (void *)topo_head, DDI_NOSLEEP)) != DDI_SUCCESS) { mptsas_log(mpt, CE_NOTE, "mptsas start taskq " "for handle SAS DR event failed. \n"); } } break; --- 7686,7712 ---- (void) sprintf(&string[strlen(string)], "target not responding, delaying " "removal"); break; } ! NDBG20(("mptsas3%d phy %d DevHandle %x, %s%s%s\n", mpt->m_instance, phy, dev_handle, string, curr, prev)); } if (topo_head != NULL) { /* * Launch DR taskq to handle topology change */ if ((ddi_taskq_dispatch(mpt->m_dr_taskq, mptsas_handle_dr, (void *)topo_head, DDI_NOSLEEP)) != DDI_SUCCESS) { + while (topo_head != NULL) { + topo_node = topo_head; + topo_head = topo_head->next; + kmem_free(topo_node, + sizeof (mptsas_topo_change_list_t)); + } mptsas_log(mpt, CE_NOTE, "mptsas start taskq " "for handle SAS DR event failed. \n"); } } break;
*** 6877,6887 **** irChangeList = (pMpi2EventDataIrConfigChangeList_t) eventreply->EventData; num_entries = ddi_get8(mpt->m_acc_reply_frame_hdl, &irChangeList->NumElements); ! NDBG20(("mptsas%d IR_CONFIGURATION_CHANGE_LIST event received", mpt->m_instance)); for (i = 0; i < num_entries; i++) { reason = ddi_get8(mpt->m_acc_reply_frame_hdl, &irChangeList->ConfigElement[i].ReasonCode); --- 7724,7734 ---- irChangeList = (pMpi2EventDataIrConfigChangeList_t) eventreply->EventData; num_entries = ddi_get8(mpt->m_acc_reply_frame_hdl, &irChangeList->NumElements); ! NDBG20(("mptsas3%d IR_CONFIGURATION_CHANGE_LIST event received", mpt->m_instance)); for (i = 0; i < num_entries; i++) { reason = ddi_get8(mpt->m_acc_reply_frame_hdl, &irChangeList->ConfigElement[i].ReasonCode);
*** 6933,6945 **** (void) mptsas_delete_volume(mpt, volhandle); /* * Update DR flag immediately avoid I/O failure */ - mutex_enter(&mpt->m_tx_waitq_mutex); ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION; - mutex_exit(&mpt->m_tx_waitq_mutex); topo_node = kmem_zalloc( sizeof (mptsas_topo_change_list_t), KM_SLEEP); topo_node->mpt = mpt; --- 7780,7790 ----
*** 6968,6980 **** break; /* * Update DR flag immediately avoid I/O failure */ - mutex_enter(&mpt->m_tx_waitq_mutex); ptgt->m_dr_flag = MPTSAS_DR_INTRANSITION; - mutex_exit(&mpt->m_tx_waitq_mutex); topo_node = kmem_zalloc( sizeof (mptsas_topo_change_list_t), KM_SLEEP); topo_node->mpt = mpt; --- 7813,7823 ----
*** 7034,7043 **** --- 7877,7892 ---- * Launch DR taskq to handle topology change */ if ((ddi_taskq_dispatch(mpt->m_dr_taskq, mptsas_handle_dr, (void *)topo_head, DDI_NOSLEEP)) != DDI_SUCCESS) { + while (topo_head != NULL) { + topo_node = topo_head; + topo_head = topo_head->next; + kmem_free(topo_node, + sizeof (mptsas_topo_change_list_t)); + } mptsas_log(mpt, CE_NOTE, "mptsas start taskq " "for handle SAS DR event failed. \n"); } } break;
*** 7076,7086 **** mutex_exit(&mpt->m_mutex); return; } eventreply = (pMpi2EventNotificationReply_t) ! (mpt->m_reply_frame + (rfm - mpt->m_reply_frame_dma_addr)); event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event); if (iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->IOCStatus)) { if (iocstatus == MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { --- 7925,7936 ---- mutex_exit(&mpt->m_mutex); return; } eventreply = (pMpi2EventNotificationReply_t) ! (mpt->m_reply_frame + (rfm - ! (mpt->m_reply_frame_dma_addr&0xfffffffful))); event = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->Event); if (iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl, &eventreply->IOCStatus)) { if (iocstatus == MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
*** 7109,7122 **** &eventreply->IOCLogInfo); NDBG20(("mptsas %d log info %x received.\n", mpt->m_instance, iocloginfo)); break; case MPI2_EVENT_STATE_CHANGE: ! NDBG20(("mptsas%d state change.", mpt->m_instance)); break; case MPI2_EVENT_HARD_RESET_RECEIVED: ! NDBG20(("mptsas%d event change.", mpt->m_instance)); break; case MPI2_EVENT_SAS_DISCOVERY: { MPI2_EVENT_DATA_SAS_DISCOVERY *sasdiscovery; char string[80]; --- 7959,7972 ---- &eventreply->IOCLogInfo); NDBG20(("mptsas %d log info %x received.\n", mpt->m_instance, iocloginfo)); break; case MPI2_EVENT_STATE_CHANGE: ! NDBG20(("mptsas3%d state change.", mpt->m_instance)); break; case MPI2_EVENT_HARD_RESET_RECEIVED: ! NDBG20(("mptsas3%d event change.", mpt->m_instance)); break; case MPI2_EVENT_SAS_DISCOVERY: { MPI2_EVENT_DATA_SAS_DISCOVERY *sasdiscovery; char string[80];
*** 7149,7167 **** port, status)); break; } case MPI2_EVENT_EVENT_CHANGE: ! NDBG20(("mptsas%d event change.", mpt->m_instance)); break; case MPI2_EVENT_TASK_SET_FULL: { pMpi2EventDataTaskSetFull_t taskfull; taskfull = (pMpi2EventDataTaskSetFull_t)eventreply->EventData; ! NDBG20(("TASK_SET_FULL received for mptsas%d, depth %d\n", mpt->m_instance, ddi_get16(mpt->m_acc_reply_frame_hdl, &taskfull->CurrentDepth))); break; } case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: --- 7999,8017 ---- port, status)); break; } case MPI2_EVENT_EVENT_CHANGE: ! NDBG20(("mptsas3%d event change.", mpt->m_instance)); break; case MPI2_EVENT_TASK_SET_FULL: { pMpi2EventDataTaskSetFull_t taskfull; taskfull = (pMpi2EventDataTaskSetFull_t)eventreply->EventData; ! NDBG20(("TASK_SET_FULL received for mptsas3%d, depth %d\n", mpt->m_instance, ddi_get16(mpt->m_acc_reply_frame_hdl, &taskfull->CurrentDepth))); break; } case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
*** 7191,7202 **** (void) sprintf(string, ", not responding"); break; default: break; } ! NDBG20(("mptsas%d ENCLOSURE STATUS CHANGE for enclosure %x%s\n", ! mpt->m_instance, ddi_get16(mpt->m_acc_reply_frame_hdl, &encstatus->EnclosureHandle), string)); break; } /* --- 8041,8053 ---- (void) sprintf(string, ", not responding"); break; default: break; } ! NDBG20(("mptsas3%d ENCLOSURE STATUS CHANGE for enclosure " ! "%x%s\n", mpt->m_instance, ! ddi_get16(mpt->m_acc_reply_frame_hdl, &encstatus->EnclosureHandle), string)); break; } /*
*** 7317,7327 **** default: (void) sprintf(reason_str, "unknown reason %x", rc); } ! NDBG20(("mptsas%d raid operational status: (%s)" "\thandle(0x%04x), percent complete(%d)\n", mpt->m_instance, reason_str, handle, percent)); break; } case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: --- 8168,8178 ---- default: (void) sprintf(reason_str, "unknown reason %x", rc); } ! NDBG20(("mptsas3%d raid operational status: (%s)" "\thandle(0x%04x), percent complete(%d)\n", mpt->m_instance, reason_str, handle, percent)); break; } case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
*** 7386,7401 **** ESC_SAS_HBA_PORT_BROADCAST, SAS_PORT_BROADCAST_D27_4, &mpt->m_phy_info[phy_num].smhba_info); break; default: ! NDBG20(("mptsas%d: unknown BROADCAST PRIMITIVE" " %x received", mpt->m_instance, primitive)); break; } ! NDBG20(("mptsas%d sas broadcast primitive: " "\tprimitive(0x%04x), phy(%d) complete\n", mpt->m_instance, primitive, phy_num)); break; } case MPI2_EVENT_IR_VOLUME: --- 8237,8252 ---- ESC_SAS_HBA_PORT_BROADCAST, SAS_PORT_BROADCAST_D27_4, &mpt->m_phy_info[phy_num].smhba_info); break; default: ! NDBG16(("mptsas3%d: unknown BROADCAST PRIMITIVE" " %x received", mpt->m_instance, primitive)); break; } ! NDBG16(("mptsas3%d sas broadcast primitive: " "\tprimitive(0x%04x), phy(%d) complete\n", mpt->m_instance, primitive, phy_num)); break; } case MPI2_EVENT_IR_VOLUME:
*** 7597,7607 **** break; } break; } default: ! NDBG20(("mptsas%d: unknown event %x received", mpt->m_instance, event)); break; } /* --- 8448,8458 ---- break; } break; } default: ! NDBG20(("mptsas3%d: unknown event %x received", mpt->m_instance, event)); break; } /*
*** 7632,7658 **** mpt->m_restart_cmd_timeid = 0; for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { if (ptgt->m_reset_delay == 0) { if (ptgt->m_t_throttle == QFULL_THROTTLE) { mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } } } mptsas_restart_hba(mpt); mutex_exit(&mpt->m_mutex); } void mptsas_remove_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd) { int slot; mptsas_slots_t *slots = mpt->m_active; - int t; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; ASSERT(cmd != NULL); ASSERT(cmd->cmd_queued == FALSE); --- 8483,8571 ---- mpt->m_restart_cmd_timeid = 0; for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { + mutex_enter(&ptgt->m_t_mutex); if (ptgt->m_reset_delay == 0) { if (ptgt->m_t_throttle == QFULL_THROTTLE) { mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } } + mutex_exit(&ptgt->m_t_mutex); } mptsas_restart_hba(mpt); mutex_exit(&mpt->m_mutex); } + /* + * Assume some checks have been done prior to calling this + * function so we don't need to consider taking the m_mutex. + */ + static void + mptsas_remove_cmd_nomtx(mptsas_t *mpt, mptsas_cmd_t *cmd) + { + int slot; + mptsas_slots_t *slots = mpt->m_active; + mptsas_target_t *ptgt = cmd->cmd_tgt_addr; + + ASSERT(cmd != NULL); + ASSERT(cmd->cmd_queued == FALSE); + ASSERT((cmd->cmd_flags & CFLAG_CMDIOC) == 0); + + slot = cmd->cmd_slot; + + /* + * remove the cmd. + */ + if (cmd == slots->m_slot[slot]) { + NDBG31(("mptsas_remove_cmd_nomtx: removing cmd=0x%p, flags " + "0x%x", (void *)cmd, cmd->cmd_flags)); + slots->m_slot[slot] = NULL; + ASSERT(mpt->m_ncmds != 0); + atomic_dec_32(&mpt->m_ncmds); + ASSERT(mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds != 0); + atomic_dec_32( + &mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds); + + /* + * Decrement per target ncmds, we know this is not an + * IOC cmd and it therefore has a target associated with it. + */ + mutex_enter(&ptgt->m_t_mutex); + ASSERT(ptgt->m_t_ncmds != 0); + ptgt->m_t_ncmds--; + + /* + * reset throttle if we just ran an untagged command + * to a tagged target + */ + if ((ptgt->m_t_ncmds == 0) && + ((cmd->cmd_pkt_flags & FLAG_TAGMASK) == 0)) { + mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); + } + + /* + * Remove this command from the active queue. + */ + if (cmd->cmd_active_expiration != 0) { + TAILQ_REMOVE(&ptgt->m_active_cmdq, cmd, + cmd_active_link); + cmd->cmd_active_expiration = 0; + } + mutex_exit(&ptgt->m_t_mutex); + } + + ASSERT(cmd != slots->m_slot[cmd->cmd_slot]); + } + void mptsas_remove_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd) { int slot; mptsas_slots_t *slots = mpt->m_active; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; ASSERT(cmd != NULL); ASSERT(cmd->cmd_queued == FALSE);
*** 7662,7696 **** */ if (cmd->cmd_flags & CFLAG_TM_CMD) { return; } - t = Tgt(cmd); slot = cmd->cmd_slot; /* * remove the cmd. */ if (cmd == slots->m_slot[slot]) { ! NDBG31(("mptsas_remove_cmd: removing cmd=0x%p", (void *)cmd)); slots->m_slot[slot] = NULL; ! mpt->m_ncmds--; /* * only decrement per target ncmds if command * has a target associated with it. */ if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) { ptgt->m_t_ncmds--; /* * reset throttle if we just ran an untagged command * to a tagged target */ if ((ptgt->m_t_ncmds == 0) && ((cmd->cmd_pkt_flags & FLAG_TAGMASK) == 0)) { mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } } } /* --- 8575,8626 ---- */ if (cmd->cmd_flags & CFLAG_TM_CMD) { return; } slot = cmd->cmd_slot; /* * remove the cmd. */ if (cmd == slots->m_slot[slot]) { ! NDBG31(("mptsas_remove_cmd: removing cmd=0x%p, flags 0x%x", ! (void *)cmd, cmd->cmd_flags)); slots->m_slot[slot] = NULL; ! ASSERT(mpt->m_ncmds != 0); ! atomic_dec_32(&mpt->m_ncmds); ! ASSERT(mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds != 0); ! atomic_dec_32( ! &mpt->m_rep_post_queues[cmd->cmd_rpqidx].rpq_ncmds); /* * only decrement per target ncmds if command * has a target associated with it. */ if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) { + mutex_enter(&ptgt->m_t_mutex); + ASSERT(ptgt->m_t_ncmds != 0); ptgt->m_t_ncmds--; + /* * reset throttle if we just ran an untagged command * to a tagged target */ if ((ptgt->m_t_ncmds == 0) && ((cmd->cmd_pkt_flags & FLAG_TAGMASK) == 0)) { mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } + + /* + * Remove this command from the active queue. + */ + if (cmd->cmd_active_expiration != 0) { + TAILQ_REMOVE(&ptgt->m_active_cmdq, cmd, + cmd_active_link); + cmd->cmd_active_expiration = 0; + } + mutex_exit(&ptgt->m_t_mutex); } } /*
*** 7699,7752 **** if (cmd->cmd_flags & CFLAG_CMDIOC) { mptsas_return_to_pool(mpt, cmd); return; } - /* - * Figure out what to set tag Q timeout for... - * - * Optimize: If we have duplicate's of same timeout - * we're using, then we'll use it again until we run - * out of duplicates. This should be the normal case - * for block and raw I/O. - * If no duplicates, we have to scan through tag que and - * find the longest timeout value and use it. This is - * going to take a while... - * Add 1 to m_n_normal to account for TM request. - */ - if (cmd->cmd_pkt->pkt_time == ptgt->m_timebase) { - if (--(ptgt->m_dups) == 0) { - if (ptgt->m_t_ncmds) { - mptsas_cmd_t *ssp; - uint_t n = 0; - ushort_t nslots = (slots->m_n_normal + 1); - ushort_t i; - /* - * This crude check assumes we don't do - * this too often which seems reasonable - * for block and raw I/O. - */ - for (i = 0; i < nslots; i++) { - ssp = slots->m_slot[i]; - if (ssp && (Tgt(ssp) == t) && - (ssp->cmd_pkt->pkt_time > n)) { - n = ssp->cmd_pkt->pkt_time; - ptgt->m_dups = 1; - } else if (ssp && (Tgt(ssp) == t) && - (ssp->cmd_pkt->pkt_time == n)) { - ptgt->m_dups++; - } - } - ptgt->m_timebase = n; - } else { - ptgt->m_dups = 0; - ptgt->m_timebase = 0; - } - } - } - ptgt->m_timeout = ptgt->m_timebase; - ASSERT(cmd != slots->m_slot[cmd->cmd_slot]); } /* * accept all cmds on the tx_waitq if any and then --- 8629,8638 ----
*** 7760,7774 **** static void mptsas_restart_hba(mptsas_t *mpt) { ASSERT(mutex_owned(&mpt->m_mutex)); ! mutex_enter(&mpt->m_tx_waitq_mutex); ! if (mpt->m_tx_waitq) { ! mptsas_accept_tx_waitq(mpt); ! } ! mutex_exit(&mpt->m_tx_waitq_mutex); mptsas_restart_waitq(mpt); } /* * start a fresh request from the top of the device queue --- 8646,8656 ---- static void mptsas_restart_hba(mptsas_t *mpt) { ASSERT(mutex_owned(&mpt->m_mutex)); ! mptsas_accept_tx_waitqs(mpt); mptsas_restart_waitq(mpt); } /* * start a fresh request from the top of the device queue
*** 7832,7894 **** cmd = next_cmd; continue; } ptgt = cmd->cmd_tgt_addr; ! if (ptgt && (ptgt->m_t_throttle == DRAIN_THROTTLE) && (ptgt->m_t_ncmds == 0)) { mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } if ((mpt->m_ncmds <= (mpt->m_max_requests - 2)) && ! (ptgt && (ptgt->m_reset_delay == 0)) && ! (ptgt && (ptgt->m_t_ncmds < ! ptgt->m_t_throttle))) { if (mptsas_save_cmd(mpt, cmd) == TRUE) { mptsas_waitq_delete(mpt, cmd); (void) mptsas_start_cmd(mpt, cmd); } } cmd = next_cmd; } } /* ! * Cmds are queued if tran_start() doesn't get the m_mutexlock(no wait). ! * Accept all those queued cmds before new cmd is accept so that the ! * cmds are sent in order. */ static void ! mptsas_accept_tx_waitq(mptsas_t *mpt) { ! mptsas_cmd_t *cmd; ASSERT(mutex_owned(&mpt->m_mutex)); ! ASSERT(mutex_owned(&mpt->m_tx_waitq_mutex)); /* ! * A Bus Reset could occur at any time and flush the tx_waitq, ! * so we cannot count on the tx_waitq to contain even one cmd. ! * And when the m_tx_waitq_mutex is released and run ! * mptsas_accept_pkt(), the tx_waitq may be flushed. */ ! cmd = mpt->m_tx_waitq; ! for (;;) { ! if ((cmd = mpt->m_tx_waitq) == NULL) { ! mpt->m_tx_draining = 0; ! break; } ! if ((mpt->m_tx_waitq = cmd->cmd_linkp) == NULL) { ! mpt->m_tx_waitqtail = &mpt->m_tx_waitq; } - cmd->cmd_linkp = NULL; - mutex_exit(&mpt->m_tx_waitq_mutex); - if (mptsas_accept_pkt(mpt, cmd) != TRAN_ACCEPT) - cmn_err(CE_WARN, "mpt: mptsas_accept_tx_waitq: failed " - "to accept cmd on queue\n"); - mutex_enter(&mpt->m_tx_waitq_mutex); } } /* * mpt tag type lookup */ static char mptsas_tag_lookup[] = --- 8714,8932 ---- cmd = next_cmd; continue; } ptgt = cmd->cmd_tgt_addr; ! if (ptgt) { ! mutex_enter(&ptgt->m_t_mutex); ! if ((ptgt->m_t_throttle == DRAIN_THROTTLE) && (ptgt->m_t_ncmds == 0)) { mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } if ((mpt->m_ncmds <= (mpt->m_max_requests - 2)) && ! (ptgt->m_reset_delay == 0) && ! (ptgt->m_t_ncmds < ptgt->m_t_throttle)) { ! mutex_exit(&ptgt->m_t_mutex); ! if (mptsas_save_cmd(mpt, cmd) == TRUE) { mptsas_waitq_delete(mpt, cmd); + mutex_exit(&mpt->m_mutex); (void) mptsas_start_cmd(mpt, cmd); + mutex_enter(&mpt->m_mutex); + cmd = mpt->m_waitq; + continue; + } + } else { + mutex_exit(&ptgt->m_t_mutex); } } cmd = next_cmd; } } + /* ! * Cmds are queued if scsi_start() doesn't get the m_mutex lock(no wait) ! * or if the decision has been made to always do that. Setting ! * mptsas_allow_txq_jumping to zero will allow higher performance on ! * a heavily loaded system as there is less disruption to the flow here. ! * There are 2 threads that handle one queue each. The idea is that ! * they take it in turn to grab the m_mutex to run the mptsas_accept_pkt() ! * function and then drop it while the cmd is started in mptsas_start_cmd(). */ static void ! mptsas_tx_waitq_thread(mptsas_thread_arg_t *arg) { ! mptsas_t *mpt = arg->mpt; ! mptsas_tx_waitqueue_t *txwq = &mpt->m_tx_waitq[arg->t]; ! ! mutex_enter(&txwq->txwq_mutex); ! while (txwq->txwq_active) { ! mptsas_drain_tx_waitq(mpt, txwq); ! if (txwq->txwq_wdrain) { ! cv_signal(&txwq->txwq_drain_cv); ! } ! cv_wait(&txwq->txwq_cv, &txwq->txwq_mutex); ! } ! mutex_exit(&txwq->txwq_mutex); ! mutex_enter(&mpt->m_qthread_mutex); ! mpt->m_txwq_thread_n--; ! cv_broadcast(&mpt->m_qthread_cv); ! mutex_exit(&mpt->m_qthread_mutex); ! } ! ! /* ! * Set the draining flag, disconnect the list and process one at a time ! * so that the cmds are sent in order. ! */ ! static void ! mptsas_drain_tx_waitq(mptsas_t *mpt, mptsas_tx_waitqueue_t *txwq) ! { ! mptsas_cmd_t *cmd, *ncmd; ! int rval, start; ! #ifdef MPTSAS_DEBUG ! uint32_t qlen; ! #endif ! ! txwq->txwq_draining = TRUE; ! #ifndef __lock_lint ! _NOTE(CONSTCOND) ! #endif ! while (TRUE) { ! ! /* ! * A Bus Reset could occur at any time but it will have to ! * wait for the main mutex before flushing the tx_waitq. ! * Pull all commands at once, then follow the list in order to ! * reduce txwq_mutex hold time. If there is a Bus Reset at ! * some point the commands will get to the waitq and then be ! * flushed. ! */ ! cmd = txwq->txwq_cmdq; ! ! if (cmd == NULL) { ! txwq->txwq_draining = FALSE; ! return; ! } ! txwq->txwq_cmdq = NULL; ! txwq->txwq_qtail = &txwq->txwq_cmdq; ! #ifdef MPTSAS_DEBUG ! qlen = txwq->txwq_len; ! #endif ! txwq->txwq_len = 0; ! mutex_exit(&txwq->txwq_mutex); ! ! while (cmd) { ! ncmd = cmd->cmd_linkp; ! cmd->cmd_linkp = NULL; ! mutex_enter(&mpt->m_mutex); ! start = mptsas_accept_pkt(mpt, cmd, &rval); ! mutex_exit(&mpt->m_mutex); ! if (start) { ! (void) mptsas_start_cmd(mpt, cmd); ! } ! if (rval != TRAN_ACCEPT) ! cmn_err(CE_WARN, ! "mpt: mptsas_drain_tx_waitq: failed " ! "(rval=0x%x) to accept cmd 0x%p on queue\n", ! rval, (void *)cmd); ! cmd = ncmd; ! #ifdef MPTSAS_DEBUG ! qlen--; ! #endif ! } ! ASSERT(qlen == 0); ! mutex_enter(&txwq->txwq_mutex); ! } ! } ! ! /* ! * Stop the drain threads from picking up a new list. ! * Optionally wait for the current list being processed to drain through. ! * Add to and processing the tx waitq is now on hold until unblock is called. ! */ ! static void ! mptsas_block_tx_waitqs(mptsas_t *mpt, int wait) ! { ! int i; ! uint8_t wdrain = 0; ! mptsas_tx_waitqueue_t *txwq; ASSERT(mutex_owned(&mpt->m_mutex)); ! ! if (mpt->m_txwq_thread_n == 0) { ! return; ! } /* ! * Turn off the use of the tx wait queues by scsi_start(). ! * This is just a dynamic flag no need for a mutex. */ ! mpt->m_txwq_enabled = BLOCKED; ! ! for (i = 0; i < NUM_TX_WAITQ; i++) { ! txwq = &mpt->m_tx_waitq[i]; ! mutex_enter(&txwq->txwq_mutex); ! txwq->txwq_wdrain = TRUE; ! if (txwq->txwq_draining && wait) ! wdrain |= (1<<i); ! mutex_exit(&txwq->txwq_mutex); ! } ! ! if (wdrain) { ! /* ! * Because the threads disconnect the entire queue each time ! * round in order to drain to completely drain we have to ! * drop the main mutex otherwise the drain threads get stuck. ! */ ! mutex_exit(&mpt->m_mutex); ! for (i = 0; i < NUM_TX_WAITQ; i++) { ! if (wdrain & (1<<i)) { ! txwq = &mpt->m_tx_waitq[i]; ! mutex_enter(&txwq->txwq_mutex); ! while (txwq->txwq_draining) { ! cv_wait(&txwq->txwq_drain_cv, ! &txwq->txwq_mutex); } ! mutex_exit(&txwq->txwq_mutex); } } + mutex_enter(&mpt->m_mutex); + } + } + + static void + mptsas_unblock_tx_waitqs(mptsas_t *mpt) + { + int i; + mptsas_tx_waitqueue_t *txwq; + + if (mpt->m_txwq_thread_n == 0) { + return; + } + + for (i = 0; i < NUM_TX_WAITQ; i++) { + txwq = &mpt->m_tx_waitq[i]; + mutex_enter(&txwq->txwq_mutex); + txwq->txwq_wdrain = FALSE; + cv_signal(&txwq->txwq_cv); + mutex_exit(&txwq->txwq_mutex); + } + + mpt->m_txwq_enabled = FALSE; } + static void + mptsas_accept_tx_waitqs(mptsas_t *mpt) + { + /* + * Block with drain and unblock will leave us in a state where + * we have the main mutex, there is nothing on the tx wait queues + * and they are not in use until watch notices high activity again. + */ + mptsas_block_tx_waitqs(mpt, 1); + mptsas_unblock_tx_waitqs(mpt); + } /* * mpt tag type lookup */ static char mptsas_tag_lookup[] =
*** 7897,7922 **** static int mptsas_start_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd) { struct scsi_pkt *pkt = CMD2PKT(cmd); uint32_t control = 0; ! int n; ! caddr_t mem; pMpi2SCSIIORequest_t io_request; ddi_dma_handle_t dma_hdl = mpt->m_dma_req_frame_hdl; ddi_acc_handle_t acc_hdl = mpt->m_acc_req_frame_hdl; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; ! uint16_t SMID, io_flags = 0; ! uint32_t request_desc_low, request_desc_high; ! NDBG1(("mptsas_start_cmd: cmd=0x%p", (void *)cmd)); /* * Set SMID and increment index. Rollover to 1 instead of 0 if index * is at the max. 0 is an invalid SMID, so we call the first index 1. */ SMID = cmd->cmd_slot; /* * It is possible for back to back device reset to * happen before the reset delay has expired. That's * ok, just let the device reset go out on the bus. --- 8935,8964 ---- static int mptsas_start_cmd(mptsas_t *mpt, mptsas_cmd_t *cmd) { struct scsi_pkt *pkt = CMD2PKT(cmd); uint32_t control = 0; ! caddr_t mem, arsbuf; pMpi2SCSIIORequest_t io_request; ddi_dma_handle_t dma_hdl = mpt->m_dma_req_frame_hdl; ddi_acc_handle_t acc_hdl = mpt->m_acc_req_frame_hdl; mptsas_target_t *ptgt = cmd->cmd_tgt_addr; ! uint16_t SMID, io_flags = 0, ars_size; ! uint8_t MSIidx; ! uint64_t request_desc; ! uint32_t ars_dmaaddrlow; ! mptsas_cmd_t *c; ! NDBG1(("mptsas_start_cmd: cmd=0x%p, flags 0x%x", (void *)cmd, ! cmd->cmd_flags)); /* * Set SMID and increment index. Rollover to 1 instead of 0 if index * is at the max. 0 is an invalid SMID, so we call the first index 1. */ SMID = cmd->cmd_slot; + MSIidx = cmd->cmd_rpqidx; /* * It is possible for back to back device reset to * happen before the reset delay has expired. That's * ok, just let the device reset go out on the bus.
*** 7928,7937 **** --- 8970,8980 ---- /* * if a non-tagged cmd is submitted to an active tagged target * then drain before submitting this cmd; SCSI-2 allows RQSENSE * to be untagged */ + mutex_enter(&ptgt->m_t_mutex); if (((cmd->cmd_pkt_flags & FLAG_TAGMASK) == 0) && (ptgt->m_t_ncmds > 1) && ((cmd->cmd_flags & CFLAG_TM_CMD) == 0) && (*(cmd->cmd_pkt->pkt_cdbp) != SCMD_REQUEST_SENSE)) { if ((cmd->cmd_pkt_flags & FLAG_NOINTR) == 0) {
*** 7939,7952 **** --- 8982,9000 ---- ptgt->m_devhdl)); if (ptgt->m_reset_delay == 0) { mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE); } + mutex_exit(&ptgt->m_t_mutex); + mutex_enter(&mpt->m_mutex); mptsas_remove_cmd(mpt, cmd); cmd->cmd_pkt_flags |= FLAG_HEAD; mptsas_waitq_add(mpt, cmd); + mutex_exit(&mpt->m_mutex); + } else { + mutex_exit(&ptgt->m_t_mutex); } return (DDI_FAILURE); } /*
*** 7973,7999 **** ptgt->m_t_throttle = 1; } control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; } if (cmd->cmd_pkt_flags & FLAG_TLR) { control |= MPI2_SCSIIO_CONTROL_TLR_ON; } mem = mpt->m_req_frame + (mpt->m_req_frame_size * SMID); io_request = (pMpi2SCSIIORequest_t)mem; ! bzero(io_request, sizeof (Mpi2SCSIIORequest_t)); ddi_put8(acc_hdl, &io_request->SGLOffset0, offsetof (MPI2_SCSI_IO_REQUEST, SGL) / 4); mptsas_init_std_hdr(acc_hdl, io_request, ptgt->m_devhdl, Lun(cmd), 0, MPI2_FUNCTION_SCSI_IO_REQUEST); (void) ddi_rep_put8(acc_hdl, (uint8_t *)pkt->pkt_cdbp, io_request->CDB.CDB32, cmd->cmd_cdblen, DDI_DEV_AUTOINCR); io_flags = cmd->cmd_cdblen; ddi_put16(acc_hdl, &io_request->IoFlags, io_flags); /* * setup the Scatter/Gather DMA list for this request */ if (cmd->cmd_cookiec > 0) { --- 9021,9111 ---- ptgt->m_t_throttle = 1; } control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; } + /* + * Set timeout. + */ + cmd->cmd_active_expiration = + gethrtime() + (hrtime_t)pkt->pkt_time * NANOSEC; + + c = TAILQ_FIRST(&ptgt->m_active_cmdq); + if (c == NULL || + c->cmd_active_expiration < cmd->cmd_active_expiration) { + /* + * Common case is that this is the last pending expiration + * (or queue is empty). Insert at head of the queue. + */ + TAILQ_INSERT_HEAD(&ptgt->m_active_cmdq, cmd, cmd_active_link); + } else { + /* + * Queue is not empty and first element expires later than + * this command. Search for element expiring sooner. + */ + while ((c = TAILQ_NEXT(c, cmd_active_link)) != NULL) { + if (c->cmd_active_expiration < + cmd->cmd_active_expiration) { + TAILQ_INSERT_BEFORE(c, cmd, cmd_active_link); + break; + } + } + if (c == NULL) { + /* + * No element found expiring sooner, append to + * non-empty queue. + */ + TAILQ_INSERT_TAIL(&ptgt->m_active_cmdq, cmd, + cmd_active_link); + } + } + + mutex_exit(&ptgt->m_t_mutex); + if (cmd->cmd_pkt_flags & FLAG_TLR) { control |= MPI2_SCSIIO_CONTROL_TLR_ON; } mem = mpt->m_req_frame + (mpt->m_req_frame_size * SMID); io_request = (pMpi2SCSIIORequest_t)mem; ! if (cmd->cmd_extrqslen != 0) { ! /* ! * Mapping of the buffer was done in mptsas_pkt_alloc_extern(). ! * Calculate the DMA address with the same offset. ! */ ! arsbuf = cmd->cmd_arq_buf; ! ars_size = cmd->cmd_extrqslen; ! ars_dmaaddrlow = (mpt->m_req_sense_dma_addr + ! ((uintptr_t)arsbuf - (uintptr_t)mpt->m_req_sense)) & ! 0xffffffffull; ! } else { ! arsbuf = mpt->m_req_sense + (mpt->m_req_sense_size * (SMID-1)); ! cmd->cmd_arq_buf = arsbuf; ! ars_size = mpt->m_req_sense_size; ! ars_dmaaddrlow = (mpt->m_req_sense_dma_addr + ! (mpt->m_req_sense_size * (SMID-1))) & ! 0xffffffffull; ! } bzero(io_request, sizeof (Mpi2SCSIIORequest_t)); + bzero(arsbuf, ars_size); + ddi_put8(acc_hdl, &io_request->SGLOffset0, offsetof (MPI2_SCSI_IO_REQUEST, SGL) / 4); mptsas_init_std_hdr(acc_hdl, io_request, ptgt->m_devhdl, Lun(cmd), 0, MPI2_FUNCTION_SCSI_IO_REQUEST); (void) ddi_rep_put8(acc_hdl, (uint8_t *)pkt->pkt_cdbp, io_request->CDB.CDB32, cmd->cmd_cdblen, DDI_DEV_AUTOINCR); io_flags = cmd->cmd_cdblen; + if (mptsas3_use_fastpath && + ptgt->m_io_flags & MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) { + io_flags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH; + request_desc = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; + } else { + request_desc = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; + } ddi_put16(acc_hdl, &io_request->IoFlags, io_flags); /* * setup the Scatter/Gather DMA list for this request */ if (cmd->cmd_cookiec > 0) {
*** 8008,8138 **** /* * save ARQ information */ ddi_put8(acc_hdl, &io_request->SenseBufferLength, cmd->cmd_rqslen); ! if ((cmd->cmd_flags & (CFLAG_SCBEXTERN | CFLAG_EXTARQBUFVALID)) == ! (CFLAG_SCBEXTERN | CFLAG_EXTARQBUFVALID)) { ! ddi_put32(acc_hdl, &io_request->SenseBufferLowAddress, ! cmd->cmd_ext_arqcookie.dmac_address); ! } else { ! ddi_put32(acc_hdl, &io_request->SenseBufferLowAddress, ! cmd->cmd_arqcookie.dmac_address); ! } ddi_put32(acc_hdl, &io_request->Control, control); ! NDBG31(("starting message=0x%p, with cmd=0x%p", ! (void *)(uintptr_t)mpt->m_req_frame_dma_addr, (void *)cmd)); (void) ddi_dma_sync(dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); /* * Build request descriptor and write it to the request desc post reg. */ ! request_desc_low = (SMID << 16) + MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; ! request_desc_high = ptgt->m_devhdl << 16; ! MPTSAS_START_CMD(mpt, request_desc_low, request_desc_high); ! ! /* ! * Start timeout. ! */ ! #ifdef MPTSAS_TEST ! /* ! * Temporarily set timebase = 0; needed for ! * timeout torture test. ! */ ! if (mptsas_test_timeouts) { ! ptgt->m_timebase = 0; ! } ! #endif ! n = pkt->pkt_time - ptgt->m_timebase; ! ! if (n == 0) { ! (ptgt->m_dups)++; ! ptgt->m_timeout = ptgt->m_timebase; ! } else if (n > 0) { ! ptgt->m_timeout = ! ptgt->m_timebase = pkt->pkt_time; ! ptgt->m_dups = 1; ! } else if (n < 0) { ! ptgt->m_timeout = ptgt->m_timebase; ! } ! #ifdef MPTSAS_TEST ! /* ! * Set back to a number higher than ! * mptsas_scsi_watchdog_tick ! * so timeouts will happen in mptsas_watchsubr ! */ ! if (mptsas_test_timeouts) { ! ptgt->m_timebase = 60; ! } ! #endif if ((mptsas_check_dma_handle(dma_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(acc_hdl) != DDI_SUCCESS)) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); return (DDI_FAILURE); } return (DDI_SUCCESS); } /* ! * Select a helper thread to handle current doneq */ static void ! mptsas_deliver_doneq_thread(mptsas_t *mpt) { ! uint64_t t, i; uint32_t min = 0xffffffff; mptsas_doneq_thread_list_t *item; for (i = 0; i < mpt->m_doneq_thread_n; i++) { ! item = &mpt->m_doneq_thread_id[i]; /* * If the completed command on help thread[i] less than ! * doneq_thread_threshold, then pick the thread[i]. Otherwise * pick a thread which has least completed command. */ ! ! mutex_enter(&item->mutex); ! if (item->len < mpt->m_doneq_thread_threshold) { ! t = i; ! mutex_exit(&item->mutex); break; } ! if (item->len < min) { ! min = item->len; ! t = i; } mutex_exit(&item->mutex); } ! mutex_enter(&mpt->m_doneq_thread_id[t].mutex); ! mptsas_doneq_mv(mpt, t); ! cv_signal(&mpt->m_doneq_thread_id[t].cv); ! mutex_exit(&mpt->m_doneq_thread_id[t].mutex); } /* ! * move the current global doneq to the doneq of thead[t] */ static void ! mptsas_doneq_mv(mptsas_t *mpt, uint64_t t) { mptsas_cmd_t *cmd; - mptsas_doneq_thread_list_t *item = &mpt->m_doneq_thread_id[t]; ! ASSERT(mutex_owned(&item->mutex)); ! while ((cmd = mpt->m_doneq) != NULL) { ! if ((mpt->m_doneq = cmd->cmd_linkp) == NULL) { ! mpt->m_donetail = &mpt->m_doneq; ! } ! cmd->cmd_linkp = NULL; ! *item->donetail = cmd; ! item->donetail = &cmd->cmd_linkp; ! mpt->m_doneq_len--; ! item->len++; } } void mptsas_fma_check(mptsas_t *mpt, mptsas_cmd_t *cmd) --- 9120,9230 ---- /* * save ARQ information */ ddi_put8(acc_hdl, &io_request->SenseBufferLength, cmd->cmd_rqslen); ! ddi_put32(acc_hdl, &io_request->SenseBufferLowAddress, ars_dmaaddrlow); ddi_put32(acc_hdl, &io_request->Control, control); ! NDBG31(("starting message=%d(0x%p), with cmd=0x%p", ! SMID, (void *)io_request, (void *)cmd)); (void) ddi_dma_sync(dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); /* * Build request descriptor and write it to the request desc post reg. */ ! request_desc |= (SMID << 16) + (MSIidx << 8); ! request_desc |= ((uint64_t)ptgt->m_devhdl << 48); ! MPTSAS_START_CMD(mpt, request_desc); + #if 0 + /* Is this of any benefit here, what is it going to catch? */ if ((mptsas_check_dma_handle(dma_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(acc_hdl) != DDI_SUCCESS)) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); return (DDI_FAILURE); } + #endif return (DDI_SUCCESS); } /* ! * Select a helper thread to handle given doneq. ! * Note that we don't require to have the main m_mutex here, but worst case ! * is that we wont follow the thread rotation to the letter. ! * However must ensure we have the mutex that covers the source dlist when ! * we actually hand off. */ static void ! mptsas_deliver_doneq_thread(mptsas_t *mpt, mptsas_done_list_t *dlist) { ! uint32_t t, i, j = mpt->m_doneq_next_thread; uint32_t min = 0xffffffff; mptsas_doneq_thread_list_t *item; + /* + * No need to take indivudual list mutex's during the loop. + * We are only reading values and the worst that will happen is that + * we pick the wrong thread. + */ for (i = 0; i < mpt->m_doneq_thread_n; i++) { ! item = &mpt->m_doneq_thread_id[j]; ! /* * If the completed command on help thread[i] less than ! * doneq_thread_threshold, then pick the thread[j]. Otherwise * pick a thread which has least completed command. */ ! if (item->dlist.dl_len < mpt->m_doneq_thread_threshold) { ! t = j; break; } ! if (item->dlist.dl_len < min) { ! min = item->dlist.dl_len; ! t = j; ! } ! if (++j == mpt->m_doneq_thread_n) { ! j = 0; ! } } + item = &mpt->m_doneq_thread_id[t]; + mutex_enter(&item->mutex); + mptsas_doneq_mv(dlist, item); + cv_signal(&item->cv); mutex_exit(&item->mutex); + + /* + * Next time start at the next thread. + * This will minimize the potential of grabing a lock + * for a thread that is busy, either on a very busy systems + * or on one that is configured to do all command completion + * processing through threads. + */ + if (++t == mpt->m_doneq_thread_n) { + t = 0; } ! mpt->m_doneq_next_thread = (uint16_t)t; } /* ! * move one doneq to another. */ static void ! mptsas_doneq_mv(mptsas_done_list_t *from, mptsas_doneq_thread_list_t *item) { + mptsas_done_list_t *to = &item->dlist; mptsas_cmd_t *cmd; ! if ((cmd = from->dl_q) != NULL) { ! *to->dl_tail = cmd; ! to->dl_tail = from->dl_tail; ! to->dl_len += from->dl_len; ! from->dl_q = NULL; ! from->dl_tail = &from->dl_q; ! from->dl_len = 0; } } void mptsas_fma_check(mptsas_t *mpt, mptsas_cmd_t *cmd)
*** 8142,8151 **** --- 9234,9245 ---- /* Check all acc and dma handles */ if ((mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) != DDI_SUCCESS) || + (mptsas_check_acc_handle(mpt->m_acc_req_sense_hdl) != + DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_reply_frame_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_free_queue_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_post_queue_hdl) !=
*** 8161,8170 **** --- 9255,9266 ---- pkt->pkt_reason = CMD_TRAN_ERR; pkt->pkt_statistics = 0; } if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) != DDI_SUCCESS) || + (mptsas_check_dma_handle(mpt->m_dma_req_sense_hdl) != + DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_reply_frame_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_free_queue_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_post_queue_hdl) !=
*** 8189,8210 **** DDI_SUCCESS)))) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); pkt->pkt_reason = CMD_TRAN_ERR; pkt->pkt_statistics = 0; } - if (cmd->cmd_arqhandle && - (mptsas_check_dma_handle(cmd->cmd_arqhandle) != DDI_SUCCESS)) { - ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); - pkt->pkt_reason = CMD_TRAN_ERR; - pkt->pkt_statistics = 0; - } - if (cmd->cmd_ext_arqhandle && - (mptsas_check_dma_handle(cmd->cmd_ext_arqhandle) != DDI_SUCCESS)) { - ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); - pkt->pkt_reason = CMD_TRAN_ERR; - pkt->pkt_statistics = 0; - } } /* * These routines manipulate the queue of commands that * are waiting for their completion routines to be called. --- 9285,9294 ----
*** 8231,8277 **** /* * only add scsi pkts that have completion routines to * the doneq. no intr cmds do not have callbacks. */ if (pkt && (pkt->pkt_comp)) { ! *mpt->m_donetail = cmd; ! mpt->m_donetail = &cmd->cmd_linkp; ! mpt->m_doneq_len++; } } static mptsas_cmd_t * mptsas_doneq_thread_rm(mptsas_t *mpt, uint64_t t) { mptsas_cmd_t *cmd; mptsas_doneq_thread_list_t *item = &mpt->m_doneq_thread_id[t]; /* pop one off the done queue */ ! if ((cmd = item->doneq) != NULL) { /* if the queue is now empty fix the tail pointer */ NDBG31(("mptsas_doneq_thread_rm: cmd=0x%p", (void *)cmd)); ! if ((item->doneq = cmd->cmd_linkp) == NULL) { ! item->donetail = &item->doneq; } cmd->cmd_linkp = NULL; ! item->len--; } return (cmd); } static void mptsas_doneq_empty(mptsas_t *mpt) { ! if (mpt->m_doneq && !mpt->m_in_callback) { mptsas_cmd_t *cmd, *next; struct scsi_pkt *pkt; ! mpt->m_in_callback = 1; ! cmd = mpt->m_doneq; ! mpt->m_doneq = NULL; ! mpt->m_donetail = &mpt->m_doneq; ! mpt->m_doneq_len = 0; mutex_exit(&mpt->m_mutex); /* * run the completion routines of all the * completed commands --- 9315,9386 ---- /* * only add scsi pkts that have completion routines to * the doneq. no intr cmds do not have callbacks. */ if (pkt && (pkt->pkt_comp)) { ! *mpt->m_dlist.dl_tail = cmd; ! mpt->m_dlist.dl_tail = &cmd->cmd_linkp; ! mpt->m_dlist.dl_len++; ! } ! } ! ! static void ! mptsas_rpdoneq_add(mptsas_t *mpt, mptsas_reply_pqueue_t *rpqp, ! mptsas_cmd_t *cmd) ! { ! struct scsi_pkt *pkt = CMD2PKT(cmd); ! ! NDBG31(("mptsas_rpdoneq_add: cmd=0x%p", (void *)cmd)); ! ! ASSERT((cmd->cmd_flags & CFLAG_COMPLETED) == 0); ! cmd->cmd_linkp = NULL; ! cmd->cmd_flags |= CFLAG_FINISHED; ! cmd->cmd_flags &= ~CFLAG_IN_TRANSPORT; ! ! mptsas_fma_check(mpt, cmd); ! ! /* ! * only add scsi pkts that have completion routines to ! * the doneq. no intr cmds do not have callbacks. ! */ ! if (pkt && (pkt->pkt_comp)) { ! *rpqp->rpq_dlist.dl_tail = cmd; ! rpqp->rpq_dlist.dl_tail = &cmd->cmd_linkp; ! rpqp->rpq_dlist.dl_len++; } } static mptsas_cmd_t * mptsas_doneq_thread_rm(mptsas_t *mpt, uint64_t t) { mptsas_cmd_t *cmd; mptsas_doneq_thread_list_t *item = &mpt->m_doneq_thread_id[t]; /* pop one off the done queue */ ! if ((cmd = item->dlist.dl_q) != NULL) { /* if the queue is now empty fix the tail pointer */ NDBG31(("mptsas_doneq_thread_rm: cmd=0x%p", (void *)cmd)); ! if ((item->dlist.dl_q = cmd->cmd_linkp) == NULL) { ! item->dlist.dl_tail = &item->dlist.dl_q; } cmd->cmd_linkp = NULL; ! item->dlist.dl_len--; } return (cmd); } static void mptsas_doneq_empty(mptsas_t *mpt) { ! if (mpt->m_dlist.dl_q) { mptsas_cmd_t *cmd, *next; struct scsi_pkt *pkt; ! cmd = mpt->m_dlist.dl_q; ! mpt->m_dlist.dl_q = NULL; ! mpt->m_dlist.dl_tail = &mpt->m_dlist.dl_q; ! mpt->m_dlist.dl_len = 0; mutex_exit(&mpt->m_mutex); /* * run the completion routines of all the * completed commands
*** 8284,8294 **** pkt = CMD2PKT(cmd); mptsas_pkt_comp(pkt, cmd); cmd = next; } mutex_enter(&mpt->m_mutex); ! mpt->m_in_callback = 0; } } /* * These routines manipulate the target's queue of pending requests --- 9393,9432 ---- pkt = CMD2PKT(cmd); mptsas_pkt_comp(pkt, cmd); cmd = next; } mutex_enter(&mpt->m_mutex); ! } ! } ! ! static void ! mptsas_rpdoneq_empty(mptsas_reply_pqueue_t *rpqp) ! { ! if (rpqp->rpq_dlist.dl_q) { ! mptsas_cmd_t *cmd, *next; ! struct scsi_pkt *pkt; ! ! cmd = rpqp->rpq_dlist.dl_q; ! rpqp->rpq_dlist.dl_q = NULL; ! rpqp->rpq_dlist.dl_tail = &rpqp->rpq_dlist.dl_q; ! rpqp->rpq_dlist.dl_len = 0; ! ! mutex_exit(&rpqp->rpq_mutex); ! /* ! * run the completion routines of all the ! * completed commands ! */ ! while (cmd != NULL) { ! next = cmd->cmd_linkp; ! cmd->cmd_linkp = NULL; ! /* run this command's completion routine */ ! cmd->cmd_flags |= CFLAG_COMPLETED; ! pkt = CMD2PKT(cmd); ! mptsas_pkt_comp(pkt, cmd); ! cmd = next; ! } ! mutex_enter(&rpqp->rpq_mutex); } } /* * These routines manipulate the target's queue of pending requests
*** 8374,8434 **** prevp = prevp->cmd_linkp; } cmn_err(CE_PANIC, "mpt: mptsas_waitq_delete: queue botch"); } - static mptsas_cmd_t * - mptsas_tx_waitq_rm(mptsas_t *mpt) - { - mptsas_cmd_t *cmd; - NDBG7(("mptsas_tx_waitq_rm")); - - MPTSAS_TX_WAITQ_RM(mpt, cmd); - - NDBG7(("mptsas_tx_waitq_rm: cmd=0x%p", (void *)cmd)); - - return (cmd); - } - - /* - * remove specified cmd from the middle of the tx_waitq. - */ - static void - mptsas_tx_waitq_delete(mptsas_t *mpt, mptsas_cmd_t *cmd) - { - mptsas_cmd_t *prevp = mpt->m_tx_waitq; - - NDBG7(("mptsas_tx_waitq_delete: mpt=0x%p cmd=0x%p", - (void *)mpt, (void *)cmd)); - - if (prevp == cmd) { - if ((mpt->m_tx_waitq = cmd->cmd_linkp) == NULL) - mpt->m_tx_waitqtail = &mpt->m_tx_waitq; - - cmd->cmd_linkp = NULL; - cmd->cmd_queued = FALSE; - NDBG7(("mptsas_tx_waitq_delete: mpt=0x%p cmd=0x%p", - (void *)mpt, (void *)cmd)); - return; - } - - while (prevp != NULL) { - if (prevp->cmd_linkp == cmd) { - if ((prevp->cmd_linkp = cmd->cmd_linkp) == NULL) - mpt->m_tx_waitqtail = &prevp->cmd_linkp; - - cmd->cmd_linkp = NULL; - cmd->cmd_queued = FALSE; - NDBG7(("mptsas_tx_waitq_delete: mpt=0x%p cmd=0x%p", - (void *)mpt, (void *)cmd)); - return; - } - prevp = prevp->cmd_linkp; - } - cmn_err(CE_PANIC, "mpt: mptsas_tx_waitq_delete: queue botch"); - } - /* * device and bus reset handling * * Notes: * - RESET_ALL: reset the controller --- 9512,9521 ----
*** 8540,8550 **** mptsas_get_bus_addr(struct scsi_device *sd, char *name, int len) { return (mptsas_get_name(sd, name, len)); } ! void mptsas_set_throttle(mptsas_t *mpt, mptsas_target_t *ptgt, int what) { NDBG25(("mptsas_set_throttle: throttle=%x", what)); --- 9627,9637 ---- mptsas_get_bus_addr(struct scsi_device *sd, char *name, int len) { return (mptsas_get_name(sd, name, len)); } ! static void mptsas_set_throttle(mptsas_t *mpt, mptsas_target_t *ptgt, int what) { NDBG25(("mptsas_set_throttle: throttle=%x", what));
*** 8564,8573 **** --- 9651,9710 ---- } else if (ptgt->m_reset_delay == 0) { ptgt->m_t_throttle = what; } } + static void + mptsas_set_throttle_mtx(mptsas_t *mpt, mptsas_target_t *ptgt, int what) + { + if (mpt->m_softstate & (MPTSAS_SS_QUIESCED | MPTSAS_SS_DRAINING)) { + return; + } + + mutex_enter(&ptgt->m_t_mutex); + mptsas_set_throttle(mpt, ptgt, what); + mutex_exit(&ptgt->m_t_mutex); + } + + /* + * Find all commands in the tx_waitq's for target and lun (if lun not -1), + * remove them from the queues and return the linked list. + */ + static mptsas_cmd_t * + mptsas_strip_targetlun_from_txwqs(mptsas_t *mpt, ushort_t target, int lun) + { + mptsas_cmd_t *cmd, *clist, **tailp, **prev_tailp; + mptsas_tx_waitqueue_t *txwq; + int i; + + clist = NULL; + tailp = &clist; + + for (i = 0; i < NUM_TX_WAITQ; i++) { + txwq = &mpt->m_tx_waitq[i]; + mutex_enter(&txwq->txwq_mutex); + prev_tailp = &txwq->txwq_cmdq; + cmd = txwq->txwq_cmdq; + while (cmd != NULL) { + if (Tgt(cmd) == target && + (lun == -1 || (Lun(cmd) == lun))) { + *prev_tailp = cmd->cmd_linkp; + *tailp = cmd; + tailp = &cmd->cmd_linkp; + cmd = cmd->cmd_linkp; + *tailp = NULL; + } else { + prev_tailp = &cmd->cmd_linkp; + cmd = cmd->cmd_linkp; + } + } + txwq->txwq_qtail = prev_tailp; + mutex_exit(&txwq->txwq_mutex); + } + return (clist); + } + /* * Clean up from a device reset. * For the case of target reset, this function clears the waitq of all * commands for a particular target. For the case of abort task set, this * function clears the waitq of all commonds for a particular target/lun.
*** 8578,8590 **** --- 9715,9730 ---- mptsas_slots_t *slots = mpt->m_active; mptsas_cmd_t *cmd, *next_cmd; int slot; uchar_t reason; uint_t stat; + hrtime_t timestamp; NDBG25(("mptsas_flush_target: target=%d lun=%d", target, lun)); + timestamp = gethrtime(); + /* * Make sure the I/O Controller has flushed all cmds * that are associated with this target for a target reset * and target/lun for abort task set. * Account for TM requests, which use the last SMID.
*** 8595,8604 **** --- 9735,9753 ---- reason = CMD_RESET; stat = STAT_DEV_RESET; switch (tasktype) { case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: if (Tgt(cmd) == target) { + if (cmd->cmd_active_expiration <= timestamp) { + /* + * When timeout requested, propagate + * proper reason and statistics to + * target drivers. + */ + reason = CMD_TIMEOUT; + stat |= STAT_TIMEOUT; + } NDBG25(("mptsas_flush_target discovered non-" "NULL cmd in slot %d, tasktype 0x%x", slot, tasktype)); mptsas_dump_cmd(mpt, cmd); mptsas_remove_cmd(mpt, cmd);
*** 8610,8627 **** reason = CMD_ABORTED; stat = STAT_ABORTED; /*FALLTHROUGH*/ case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: if ((Tgt(cmd) == target) && (Lun(cmd) == lun)) { NDBG25(("mptsas_flush_target discovered non-" "NULL cmd in slot %d, tasktype 0x%x", slot, tasktype)); mptsas_dump_cmd(mpt, cmd); mptsas_remove_cmd(mpt, cmd); ! mptsas_set_pkt_reason(mpt, cmd, reason, ! stat); mptsas_doneq_add(mpt, cmd); } break; default: break; --- 9759,9778 ---- reason = CMD_ABORTED; stat = STAT_ABORTED; /*FALLTHROUGH*/ case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: if ((Tgt(cmd) == target) && (Lun(cmd) == lun)) { + if (cmd->cmd_active_expiration <= timestamp) { + stat |= STAT_TIMEOUT; + } NDBG25(("mptsas_flush_target discovered non-" "NULL cmd in slot %d, tasktype 0x%x", slot, tasktype)); mptsas_dump_cmd(mpt, cmd); mptsas_remove_cmd(mpt, cmd); ! mptsas_set_pkt_reason(mpt, cmd, reason, stat); mptsas_doneq_add(mpt, cmd); } break; default: break;
*** 8646,8670 **** reason, stat); mptsas_doneq_add(mpt, cmd); } cmd = next_cmd; } ! mutex_enter(&mpt->m_tx_waitq_mutex); ! cmd = mpt->m_tx_waitq; while (cmd != NULL) { next_cmd = cmd->cmd_linkp; ! if (Tgt(cmd) == target) { ! mptsas_tx_waitq_delete(mpt, cmd); ! mutex_exit(&mpt->m_tx_waitq_mutex); ! mptsas_set_pkt_reason(mpt, cmd, ! reason, stat); mptsas_doneq_add(mpt, cmd); - mutex_enter(&mpt->m_tx_waitq_mutex); - } cmd = next_cmd; } - mutex_exit(&mpt->m_tx_waitq_mutex); break; case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: reason = CMD_ABORTED; stat = STAT_ABORTED; /*FALLTHROUGH*/ --- 9797,9813 ---- reason, stat); mptsas_doneq_add(mpt, cmd); } cmd = next_cmd; } ! cmd = mptsas_strip_targetlun_from_txwqs(mpt, target, -1); while (cmd != NULL) { next_cmd = cmd->cmd_linkp; ! mptsas_set_pkt_reason(mpt, cmd, reason, stat); mptsas_doneq_add(mpt, cmd); cmd = next_cmd; } break; case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: reason = CMD_ABORTED; stat = STAT_ABORTED; /*FALLTHROUGH*/
*** 8677,8701 **** reason, stat); mptsas_doneq_add(mpt, cmd); } cmd = next_cmd; } ! mutex_enter(&mpt->m_tx_waitq_mutex); ! cmd = mpt->m_tx_waitq; while (cmd != NULL) { next_cmd = cmd->cmd_linkp; ! if ((Tgt(cmd) == target) && (Lun(cmd) == lun)) { ! mptsas_tx_waitq_delete(mpt, cmd); ! mutex_exit(&mpt->m_tx_waitq_mutex); ! mptsas_set_pkt_reason(mpt, cmd, ! reason, stat); mptsas_doneq_add(mpt, cmd); - mutex_enter(&mpt->m_tx_waitq_mutex); - } cmd = next_cmd; } - mutex_exit(&mpt->m_tx_waitq_mutex); break; default: mptsas_log(mpt, CE_WARN, "Unknown task management type %d.", tasktype); break; --- 9820,9836 ---- reason, stat); mptsas_doneq_add(mpt, cmd); } cmd = next_cmd; } ! cmd = mptsas_strip_targetlun_from_txwqs(mpt, target, lun); while (cmd != NULL) { next_cmd = cmd->cmd_linkp; ! mptsas_set_pkt_reason(mpt, cmd, reason, stat); mptsas_doneq_add(mpt, cmd); cmd = next_cmd; } break; default: mptsas_log(mpt, CE_WARN, "Unknown task management type %d.", tasktype); break;
*** 8708,8719 **** */ static void mptsas_flush_hba(mptsas_t *mpt) { mptsas_slots_t *slots = mpt->m_active; ! mptsas_cmd_t *cmd; ! int slot; NDBG25(("mptsas_flush_hba")); /* * The I/O Controller should have already sent back --- 9843,9854 ---- */ static void mptsas_flush_hba(mptsas_t *mpt) { mptsas_slots_t *slots = mpt->m_active; ! mptsas_cmd_t *cmd, *ncmd; ! int slot, i; NDBG25(("mptsas_flush_hba")); /* * The I/O Controller should have already sent back
*** 8734,8746 **** * so there will be nothing to check against a time out. * Instead, mark the command as failed due to reset. */ mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET); ! if ((cmd->cmd_flags & CFLAG_PASSTHRU) || ! (cmd->cmd_flags & CFLAG_CONFIG) || ! (cmd->cmd_flags & CFLAG_FW_DIAG)) { cmd->cmd_flags |= CFLAG_FINISHED; cv_broadcast(&mpt->m_passthru_cv); cv_broadcast(&mpt->m_config_cv); cv_broadcast(&mpt->m_fw_diag_cv); } --- 9869,9880 ---- * so there will be nothing to check against a time out. * Instead, mark the command as failed due to reset. */ mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET); ! if ((cmd->cmd_flags & ! (CFLAG_PASSTHRU | CFLAG_CONFIG | CFLAG_FW_DIAG))) { cmd->cmd_flags |= CFLAG_FINISHED; cv_broadcast(&mpt->m_passthru_cv); cv_broadcast(&mpt->m_config_cv); cv_broadcast(&mpt->m_fw_diag_cv); }
*** 8772,8791 **** mptsas_doneq_add(mpt, cmd); } } /* ! * Flush the tx_waitq */ ! mutex_enter(&mpt->m_tx_waitq_mutex); ! while ((cmd = mptsas_tx_waitq_rm(mpt)) != NULL) { ! mutex_exit(&mpt->m_tx_waitq_mutex); ! mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, STAT_BUS_RESET); mptsas_doneq_add(mpt, cmd); ! mutex_enter(&mpt->m_tx_waitq_mutex); } - mutex_exit(&mpt->m_tx_waitq_mutex); /* * Drain the taskqs prior to reallocating resources. */ mutex_exit(&mpt->m_mutex); --- 9906,9931 ---- mptsas_doneq_add(mpt, cmd); } } /* ! * Flush the tx_waitqs */ ! for (i = 0; i < NUM_TX_WAITQ; i++) { ! mutex_enter(&mpt->m_tx_waitq[i].txwq_mutex); ! cmd = mpt->m_tx_waitq[i].txwq_cmdq; ! mpt->m_tx_waitq[i].txwq_cmdq = NULL; ! mpt->m_tx_waitq[i].txwq_qtail = &mpt->m_tx_waitq[i].txwq_cmdq; ! mutex_exit(&mpt->m_tx_waitq[i].txwq_mutex); ! while (cmd != NULL) { ! ncmd = cmd->cmd_linkp; ! mptsas_set_pkt_reason(mpt, cmd, CMD_RESET, ! STAT_BUS_RESET); mptsas_doneq_add(mpt, cmd); ! cmd = ncmd; ! } } /* * Drain the taskqs prior to reallocating resources. */ mutex_exit(&mpt->m_mutex);
*** 8839,8850 **** --- 9979,9992 ---- ASSERT(MUTEX_HELD(&mpt->m_mutex)); NDBG22(("mptsas_setup_bus_reset_delay")); for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { + mutex_enter(&ptgt->m_t_mutex); mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE); ptgt->m_reset_delay = mpt->m_scsi_reset_delay; + mutex_exit(&ptgt->m_t_mutex); } mptsas_start_watch_reset_delay(); }
*** 8894,8903 **** --- 10036,10046 ---- ASSERT(mutex_owned(&mpt->m_mutex)); for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { + mutex_enter(&ptgt->m_t_mutex); if (ptgt->m_reset_delay != 0) { ptgt->m_reset_delay -= MPTSAS_WATCH_RESET_DELAY_TICK; if (ptgt->m_reset_delay <= 0) { ptgt->m_reset_delay = 0;
*** 8906,8915 **** --- 10049,10059 ---- restart++; } else { done = -1; } } + mutex_exit(&ptgt->m_t_mutex); } if (restart > 0) { mptsas_restart_hba(mpt); }
*** 9122,9131 **** --- 10266,10276 ---- */ static int mptsas_scsi_setcap(struct scsi_address *ap, char *cap, int value, int tgtonly) { mptsas_t *mpt = ADDR2MPT(ap); + mptsas_target_t *ptgt; int ckey; int rval = FALSE; NDBG24(("mptsas_scsi_setcap: target=%d, cap=%s value=%x tgtonly=%x", ap->a_target, cap, value, tgtonly));
*** 9163,9175 **** } else { rval = FALSE; } break; case SCSI_CAP_TAGGED_QING: ! mptsas_set_throttle(mpt, ((mptsas_tgt_private_t *) ! (ap->a_hba_tran->tran_tgt_private))->t_private, ! MAX_THROTTLE); rval = TRUE; break; case SCSI_CAP_QFULL_RETRIES: ((mptsas_tgt_private_t *)(ap->a_hba_tran->tran_tgt_private))-> t_private->m_qfull_retries = (uchar_t)value; --- 10308,10320 ---- } else { rval = FALSE; } break; case SCSI_CAP_TAGGED_QING: ! ptgt = ((mptsas_tgt_private_t *) ! (ap->a_hba_tran->tran_tgt_private))->t_private; ! mptsas_set_throttle_mtx(mpt, ptgt, MAX_THROTTLE); rval = TRUE; break; case SCSI_CAP_QFULL_RETRIES: ((mptsas_tgt_private_t *)(ap->a_hba_tran->tran_tgt_private))-> t_private->m_qfull_retries = (uchar_t)value;
*** 9253,9263 **** } /* * Error logging, printing, and debug print routines. */ ! static char *mptsas_label = "mpt_sas"; /*PRINTFLIKE3*/ void mptsas_log(mptsas_t *mpt, int level, char *fmt, ...) { --- 10398,10408 ---- } /* * Error logging, printing, and debug print routines. */ ! static char *mptsas_label = "mpt_sas3"; /*PRINTFLIKE3*/ void mptsas_log(mptsas_t *mpt, int level, char *fmt, ...) {
*** 9284,9293 **** --- 10429,10464 ---- mutex_exit(&mptsas_log_mutex); } #ifdef MPTSAS_DEBUG + /* + * Use a circular buffer to log messages to private memory. + * No mutexes, so there is the opportunity for this to miss lines. + * But it's fast and does not hold up the proceedings too much. + */ + static char mptsas_dbglog_bufs[32][256]; + static uint32_t mptsas_dbglog_idx = 1; + + /*PRINTFLIKE1*/ + void + mptsas_debug_log(char *fmt, ...) + { + va_list ap; + uint32_t idx; + + if (!mptsas_dbglog_idx) { + return; + } + idx = (mptsas_dbglog_idx++) & 0x1f; + + va_start(ap, fmt); + (void) vsnprintf(mptsas_dbglog_bufs[idx], + sizeof (mptsas_dbglog_bufs[0]), fmt, ap); + va_end(ap); + } + /*PRINTFLIKE1*/ void mptsas_printf(char *fmt, ...) { dev_info_t *dev = 0;
*** 9300,9310 **** va_end(ap); #ifdef PROM_PRINTF prom_printf("%s:\t%s\n", mptsas_label, mptsas_log_buf); #else ! scsi_log(dev, mptsas_label, SCSI_DEBUG, "%s\n", mptsas_log_buf); #endif mutex_exit(&mptsas_log_mutex); } #endif --- 10471,10481 ---- va_end(ap); #ifdef PROM_PRINTF prom_printf("%s:\t%s\n", mptsas_label, mptsas_log_buf); #else ! scsi_log(dev, mptsas_label, CE_CONT, "!%s\n", mptsas_log_buf); #endif mutex_exit(&mptsas_log_mutex); } #endif
*** 9372,9423 **** if (mptsas_timeouts_enabled) mptsas_timeout_id = timeout(mptsas_watch, NULL, mptsas_tick); mutex_exit(&mptsas_global_mutex); } static void mptsas_watchsubr(mptsas_t *mpt) { int i; mptsas_cmd_t *cmd; mptsas_target_t *ptgt = NULL; ASSERT(MUTEX_HELD(&mpt->m_mutex)); ! NDBG30(("mptsas_watchsubr: mpt=0x%p", (void *)mpt)); ! #ifdef MPTSAS_TEST ! if (mptsas_enable_untagged) { ! mptsas_test_untagged++; } ! #endif /* * Check for commands stuck in active slot * Account for TM requests, which use the last SMID. */ for (i = 0; i <= mpt->m_active->m_n_normal; i++) { if ((cmd = mpt->m_active->m_slot[i]) != NULL) { if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) { - cmd->cmd_active_timeout -= - mptsas_scsi_watchdog_tick; - if (cmd->cmd_active_timeout <= 0) { /* * There seems to be a command stuck * in the active slot. Drain throttle. */ ! mptsas_set_throttle(mpt, ! cmd->cmd_tgt_addr, DRAIN_THROTTLE); ! } ! } ! if ((cmd->cmd_flags & CFLAG_PASSTHRU) || ! (cmd->cmd_flags & CFLAG_CONFIG) || ! (cmd->cmd_flags & CFLAG_FW_DIAG)) { ! cmd->cmd_active_timeout -= ! mptsas_scsi_watchdog_tick; ! if (cmd->cmd_active_timeout <= 0) { /* * passthrough command timeout */ cmd->cmd_flags |= (CFLAG_FINISHED | CFLAG_TIMEOUT); --- 10543,10597 ---- if (mptsas_timeouts_enabled) mptsas_timeout_id = timeout(mptsas_watch, NULL, mptsas_tick); mutex_exit(&mptsas_global_mutex); } + int mptsas_monitor_for_txwqs = 1; static void mptsas_watchsubr(mptsas_t *mpt) { int i; mptsas_cmd_t *cmd; mptsas_target_t *ptgt = NULL; + hrtime_t timestamp = gethrtime(); + boolean_t restart_hba = B_FALSE; ASSERT(MUTEX_HELD(&mpt->m_mutex)); ! NDBG30(("mptsas_watchsubr: mpt=0x%p, ncmds %d, nstarted %d", ! (void *)mpt, mpt->m_ncmds, mpt->m_ncstarted)); ! mpt->m_lncstarted = mpt->m_ncstarted; ! if (mpt->m_txwq_thread_n != 0 && mpt->m_txwq_enabled != BLOCKED && ! mptsas_monitor_for_txwqs) { ! i = mpt->m_ncstarted/mptsas_scsi_watchdog_tick; ! if (i > mpt->m_txwq_thread_threshold) { ! mpt->m_txwq_enabled = TRUE; ! } else if (i < (mpt->m_txwq_thread_threshold>>1)) { ! mpt->m_txwq_enabled = FALSE; } ! } ! mpt->m_ncstarted = 0; /* * Check for commands stuck in active slot * Account for TM requests, which use the last SMID. */ for (i = 0; i <= mpt->m_active->m_n_normal; i++) { if ((cmd = mpt->m_active->m_slot[i]) != NULL) { + if (cmd->cmd_active_expiration <= timestamp) { if ((cmd->cmd_flags & CFLAG_CMDIOC) == 0) { /* * There seems to be a command stuck * in the active slot. Drain throttle. */ ! ptgt = cmd->cmd_tgt_addr; ! mptsas_set_throttle_mtx(mpt, ptgt, DRAIN_THROTTLE); ! } else if (cmd->cmd_flags & ! (CFLAG_PASSTHRU | CFLAG_CONFIG | ! CFLAG_FW_DIAG)) { /* * passthrough command timeout */ cmd->cmd_flags |= (CFLAG_FINISHED | CFLAG_TIMEOUT);
*** 9429,9490 **** } } for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { /* * If we were draining due to a qfull condition, * go back to full throttle. */ if ((ptgt->m_t_throttle < MAX_THROTTLE) && (ptgt->m_t_throttle > HOLD_THROTTLE) && (ptgt->m_t_ncmds < ptgt->m_t_throttle)) { mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); ! mptsas_restart_hba(mpt); } ! if ((ptgt->m_t_ncmds > 0) && ! (ptgt->m_timebase)) { ! if (ptgt->m_timebase <= ! mptsas_scsi_watchdog_tick) { ! ptgt->m_timebase += ! mptsas_scsi_watchdog_tick; ! continue; ! } ! ptgt->m_timeout -= mptsas_scsi_watchdog_tick; ! if (ptgt->m_timeout < 0) { ! mptsas_cmd_timeout(mpt, ptgt->m_devhdl); continue; } ! ! if ((ptgt->m_timeout) <= ! mptsas_scsi_watchdog_tick) { NDBG23(("pending timeout")); ! mptsas_set_throttle(mpt, ptgt, ! DRAIN_THROTTLE); } } } } /* * timeout recovery */ static void ! mptsas_cmd_timeout(mptsas_t *mpt, uint16_t devhdl) { NDBG29(("mptsas_cmd_timeout: target=%d", devhdl)); mptsas_log(mpt, CE_WARN, "Disconnected command timeout for " ! "Target %d", devhdl); /* ! * If the current target is not the target passed in, ! * try to reset that target. */ NDBG29(("mptsas_cmd_timeout: device reset")); if (mptsas_do_scsi_reset(mpt, devhdl) != TRUE) { mptsas_log(mpt, CE_WARN, "Target %d reset for command timeout " "recovery failed!", devhdl); --- 10603,10701 ---- } } for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { + mutex_enter(&ptgt->m_t_mutex); /* * If we were draining due to a qfull condition, * go back to full throttle. */ if ((ptgt->m_t_throttle < MAX_THROTTLE) && (ptgt->m_t_throttle > HOLD_THROTTLE) && (ptgt->m_t_ncmds < ptgt->m_t_throttle)) { mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); ! restart_hba = B_TRUE; } ! cmd = TAILQ_LAST(&ptgt->m_active_cmdq, mptsas_active_cmdq); ! if (cmd != NULL) { ! if (cmd->cmd_active_expiration <= timestamp) { ! /* ! * Earliest command timeout expired. ! * Drain throttle. ! */ ! mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE); ! /* ! * Check for remaining commands. ! */ ! cmd = TAILQ_FIRST(&ptgt->m_active_cmdq); ! if (cmd->cmd_active_expiration > timestamp) { ! /* ! * Wait for remaining commands to ! * complete or time out. ! */ ! NDBG23(("command timed out, " ! "pending drain")); ! } else { ! mutex_exit(&ptgt->m_t_mutex); ! /* ! * All command timeouts expired. ! */ ! mptsas_log(mpt, CE_NOTE, ! "Timeout of %d seconds " ! "expired with %d commands on " ! "target %d lun %d.", ! cmd->cmd_pkt->pkt_time, ! ptgt->m_t_ncmds, ! ptgt->m_devhdl, Lun(cmd)); ! mptsas_cmd_timeout(mpt, ptgt); continue; } ! } else if (cmd->cmd_active_expiration <= timestamp + ! (hrtime_t)mptsas_scsi_watchdog_tick * NANOSEC) { NDBG23(("pending timeout")); ! mptsas_set_throttle(mpt, ptgt, DRAIN_THROTTLE); ! } } + mutex_exit(&ptgt->m_t_mutex); } + if (restart_hba == B_TRUE) { + mptsas_restart_hba(mpt); } } /* * timeout recovery */ static void ! mptsas_cmd_timeout(mptsas_t *mpt, mptsas_target_t *ptgt) { + uint16_t devhdl; + uint64_t sas_wwn; + uint8_t phy; + char wwn_str[MPTSAS_WWN_STRLEN]; + + devhdl = ptgt->m_devhdl; + sas_wwn = ptgt->m_addr.mta_wwn; + phy = ptgt->m_phynum; + if (sas_wwn == 0) { + (void) sprintf(wwn_str, "p%x", phy); + } else { + (void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn); + } NDBG29(("mptsas_cmd_timeout: target=%d", devhdl)); mptsas_log(mpt, CE_WARN, "Disconnected command timeout for " ! "target %d %s, enclosure %u .", devhdl, wwn_str, ! ptgt->m_enclosure); /* ! * Abort all outstanding commands on the device. */ NDBG29(("mptsas_cmd_timeout: device reset")); if (mptsas_do_scsi_reset(mpt, devhdl) != TRUE) { mptsas_log(mpt, CE_WARN, "Target %d reset for command timeout " "recovery failed!", devhdl);
*** 9529,9539 **** mutex_enter(&mpt->m_mutex); /* Set all the throttles to zero */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE); } /* If there are any outstanding commands in the queue */ if (mpt->m_ncmds) { mpt->m_softstate |= MPTSAS_SS_DRAINING; --- 10740,10750 ---- mutex_enter(&mpt->m_mutex); /* Set all the throttles to zero */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle_mtx(mpt, ptgt, HOLD_THROTTLE); } /* If there are any outstanding commands in the queue */ if (mpt->m_ncmds) { mpt->m_softstate |= MPTSAS_SS_DRAINING;
*** 9544,9554 **** * Quiesce has been interrupted */ mpt->m_softstate &= ~MPTSAS_SS_DRAINING; for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } mptsas_restart_hba(mpt); if (mpt->m_quiesce_timeid != 0) { timeout_id_t tid = mpt->m_quiesce_timeid; mpt->m_quiesce_timeid = 0; --- 10755,10766 ---- * Quiesce has been interrupted */ mpt->m_softstate &= ~MPTSAS_SS_DRAINING; for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle_mtx(mpt, ptgt, ! MAX_THROTTLE); } mptsas_restart_hba(mpt); if (mpt->m_quiesce_timeid != 0) { timeout_id_t tid = mpt->m_quiesce_timeid; mpt->m_quiesce_timeid = 0;
*** 9581,9591 **** NDBG28(("mptsas_unquiesce_bus")); mutex_enter(&mpt->m_mutex); mpt->m_softstate &= ~MPTSAS_SS_QUIESCED; for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } mptsas_restart_hba(mpt); mutex_exit(&mpt->m_mutex); return (0); } --- 10793,10803 ---- NDBG28(("mptsas_unquiesce_bus")); mutex_enter(&mpt->m_mutex); mpt->m_softstate &= ~MPTSAS_SS_QUIESCED; for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle_mtx(mpt, ptgt, MAX_THROTTLE); } mptsas_restart_hba(mpt); mutex_exit(&mpt->m_mutex); return (0); }
*** 9607,9617 **** * The throttle may have been reset because * of a SCSI bus reset */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE); } mpt->m_quiesce_timeid = timeout(mptsas_ncmds_checkdrain, mpt, (MPTSAS_QUIESCE_TIMEOUT * drv_usectohz(1000000))); --- 10819,10830 ---- * The throttle may have been reset because * of a SCSI bus reset */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle_mtx(mpt, ptgt, ! HOLD_THROTTLE); } mpt->m_quiesce_timeid = timeout(mptsas_ncmds_checkdrain, mpt, (MPTSAS_QUIESCE_TIMEOUT * drv_usectohz(1000000)));
*** 9643,9742 **** NDBG25(("?pkt_scbp=0x%x cmd_flags=0x%x\n", cmd->cmd_pkt->pkt_scbp ? *(cmd->cmd_pkt->pkt_scbp) : 0, cmd->cmd_flags)); } static void mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd) { caddr_t memp; pMPI2RequestHeader_t request_hdrp; struct scsi_pkt *pkt = cmd->cmd_pkt; mptsas_pt_request_t *pt = pkt->pkt_ha_private; ! uint32_t request_size, data_size, dataout_size; ! uint32_t direction; ! ddi_dma_cookie_t data_cookie; ! ddi_dma_cookie_t dataout_cookie; ! uint32_t request_desc_low, request_desc_high = 0; ! uint32_t i, sense_bufp; uint8_t desc_type; uint8_t *request, function; ddi_dma_handle_t dma_hdl = mpt->m_dma_req_frame_hdl; ddi_acc_handle_t acc_hdl = mpt->m_acc_req_frame_hdl; desc_type = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; request = pt->request; - direction = pt->direction; request_size = pt->request_size; - data_size = pt->data_size; - dataout_size = pt->dataout_size; - data_cookie = pt->data_cookie; - dataout_cookie = pt->dataout_cookie; /* * Store the passthrough message in memory location * corresponding to our slot number */ memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot); request_hdrp = (pMPI2RequestHeader_t)memp; bzero(memp, mpt->m_req_frame_size); ! for (i = 0; i < request_size; i++) { ! bcopy(request + i, memp + i, 1); ! } ! ! if (data_size || dataout_size) { ! pMpi2SGESimple64_t sgep; ! uint32_t sge_flags; ! sgep = (pMpi2SGESimple64_t)((uint8_t *)request_hdrp + ! request_size); ! if (dataout_size) { ! sge_flags = dataout_size | ! ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | ! MPI2_SGE_FLAGS_END_OF_BUFFER | ! MPI2_SGE_FLAGS_HOST_TO_IOC | ! MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << ! MPI2_SGE_FLAGS_SHIFT); ! ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags); ! ddi_put32(acc_hdl, &sgep->Address.Low, ! (uint32_t)(dataout_cookie.dmac_laddress & ! 0xffffffffull)); ! ddi_put32(acc_hdl, &sgep->Address.High, ! (uint32_t)(dataout_cookie.dmac_laddress ! >> 32)); ! sgep++; ! } ! sge_flags = data_size; ! sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | ! MPI2_SGE_FLAGS_LAST_ELEMENT | ! MPI2_SGE_FLAGS_END_OF_BUFFER | ! MPI2_SGE_FLAGS_END_OF_LIST | ! MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << ! MPI2_SGE_FLAGS_SHIFT); ! if (direction == MPTSAS_PASS_THRU_DIRECTION_WRITE) { ! sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << ! MPI2_SGE_FLAGS_SHIFT); } else { ! sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << ! MPI2_SGE_FLAGS_SHIFT); ! } ! ddi_put32(acc_hdl, &sgep->FlagsLength, ! sge_flags); ! ddi_put32(acc_hdl, &sgep->Address.Low, ! (uint32_t)(data_cookie.dmac_laddress & ! 0xffffffffull)); ! ddi_put32(acc_hdl, &sgep->Address.High, ! (uint32_t)(data_cookie.dmac_laddress >> 32)); } function = request_hdrp->Function; if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { pMpi2SCSIIORequest_t scsi_io_req; scsi_io_req = (pMpi2SCSIIORequest_t)request_hdrp; /* * Put SGE for data and data_out buffer at the end of * scsi_io_request message header.(64 bytes in total) * Following above SGEs, the residual space will be --- 10856,11002 ---- NDBG25(("?pkt_scbp=0x%x cmd_flags=0x%x\n", cmd->cmd_pkt->pkt_scbp ? *(cmd->cmd_pkt->pkt_scbp) : 0, cmd->cmd_flags)); } static void + mptsas_passthru_sge(ddi_acc_handle_t acc_hdl, mptsas_pt_request_t *pt, + pMpi2SGESimple64_t sgep) + { + uint32_t sge_flags; + uint32_t data_size, dataout_size; + ddi_dma_cookie_t data_cookie; + ddi_dma_cookie_t dataout_cookie; + + data_size = pt->data_size; + dataout_size = pt->dataout_size; + data_cookie = pt->data_cookie; + dataout_cookie = pt->dataout_cookie; + + if (dataout_size) { + sge_flags = dataout_size | + ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_HOST_TO_IOC | + MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << + MPI2_SGE_FLAGS_SHIFT); + ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags); + ddi_put32(acc_hdl, &sgep->Address.Low, + (uint32_t)(dataout_cookie.dmac_laddress & 0xffffffffull)); + ddi_put32(acc_hdl, &sgep->Address.High, + (uint32_t)(dataout_cookie.dmac_laddress >> 32)); + sgep++; + } + sge_flags = data_size; + sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST | + MPI2_SGE_FLAGS_64_BIT_ADDRESSING) << + MPI2_SGE_FLAGS_SHIFT); + if (pt->direction == MPTSAS_PASS_THRU_DIRECTION_WRITE) { + sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) << + MPI2_SGE_FLAGS_SHIFT); + } else { + sge_flags |= ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) << + MPI2_SGE_FLAGS_SHIFT); + } + ddi_put32(acc_hdl, &sgep->FlagsLength, sge_flags); + ddi_put32(acc_hdl, &sgep->Address.Low, + (uint32_t)(data_cookie.dmac_laddress & 0xffffffffull)); + ddi_put32(acc_hdl, &sgep->Address.High, + (uint32_t)(data_cookie.dmac_laddress >> 32)); + } + + static void + mptsas_passthru_ieee_sge(ddi_acc_handle_t acc_hdl, mptsas_pt_request_t *pt, + pMpi2IeeeSgeSimple64_t ieeesgep) + { + uint8_t sge_flags; + uint32_t data_size, dataout_size; + ddi_dma_cookie_t data_cookie; + ddi_dma_cookie_t dataout_cookie; + + data_size = pt->data_size; + dataout_size = pt->dataout_size; + data_cookie = pt->data_cookie; + dataout_cookie = pt->dataout_cookie; + + sge_flags = (MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR); + if (dataout_size) { + ddi_put32(acc_hdl, &ieeesgep->Length, dataout_size); + ddi_put32(acc_hdl, &ieeesgep->Address.Low, + (uint32_t)(dataout_cookie.dmac_laddress & + 0xffffffffull)); + ddi_put32(acc_hdl, &ieeesgep->Address.High, + (uint32_t)(dataout_cookie.dmac_laddress >> 32)); + ddi_put8(acc_hdl, &ieeesgep->Flags, sge_flags); + ieeesgep++; + } + sge_flags |= MPI25_IEEE_SGE_FLAGS_END_OF_LIST; + ddi_put32(acc_hdl, &ieeesgep->Length, data_size); + ddi_put32(acc_hdl, &ieeesgep->Address.Low, + (uint32_t)(data_cookie.dmac_laddress & 0xffffffffull)); + ddi_put32(acc_hdl, &ieeesgep->Address.High, + (uint32_t)(data_cookie.dmac_laddress >> 32)); + ddi_put8(acc_hdl, &ieeesgep->Flags, sge_flags); + } + + static void mptsas_start_passthru(mptsas_t *mpt, mptsas_cmd_t *cmd) { caddr_t memp; pMPI2RequestHeader_t request_hdrp; struct scsi_pkt *pkt = cmd->cmd_pkt; mptsas_pt_request_t *pt = pkt->pkt_ha_private; ! uint32_t request_size; ! uint64_t request_desc = 0; ! uint64_t sense_bufp; uint8_t desc_type; uint8_t *request, function; ddi_dma_handle_t dma_hdl = mpt->m_dma_req_frame_hdl; ddi_acc_handle_t acc_hdl = mpt->m_acc_req_frame_hdl; desc_type = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; request = pt->request; request_size = pt->request_size; /* * Store the passthrough message in memory location * corresponding to our slot number */ memp = mpt->m_req_frame + (mpt->m_req_frame_size * cmd->cmd_slot); request_hdrp = (pMPI2RequestHeader_t)memp; bzero(memp, mpt->m_req_frame_size); ! bcopy(request, memp, request_size); ! NDBG15(("mptsas_start_passthru: Func 0x%x, MsgFlags 0x%x, " ! "size=%d, in %d, out %d", request_hdrp->Function, ! request_hdrp->MsgFlags, request_size, ! pt->data_size, pt->dataout_size)); ! /* ! * Add an SGE, even if the length is zero. ! */ ! if (mpt->m_MPI25 && pt->simple == 0) { ! mptsas_passthru_ieee_sge(acc_hdl, pt, ! (pMpi2IeeeSgeSimple64_t) ! ((uint8_t *)request_hdrp + pt->sgl_offset)); } else { ! mptsas_passthru_sge(acc_hdl, pt, ! (pMpi2SGESimple64_t) ! ((uint8_t *)request_hdrp + pt->sgl_offset)); } function = request_hdrp->Function; if ((function == MPI2_FUNCTION_SCSI_IO_REQUEST) || (function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { pMpi2SCSIIORequest_t scsi_io_req; + NDBG15(("mptsas_start_passthru: Is SCSI IO Req")); scsi_io_req = (pMpi2SCSIIORequest_t)request_hdrp; /* * Put SGE for data and data_out buffer at the end of * scsi_io_request message header.(64 bytes in total) * Following above SGEs, the residual space will be
*** 9744,9755 **** */ ddi_put8(acc_hdl, &scsi_io_req->SenseBufferLength, (uint8_t)(request_size - 64)); ! sense_bufp = mpt->m_req_frame_dma_addr + ! (mpt->m_req_frame_size * cmd->cmd_slot); sense_bufp += 64; ddi_put32(acc_hdl, &scsi_io_req->SenseBufferLowAddress, sense_bufp); /* --- 11004,11015 ---- */ ddi_put8(acc_hdl, &scsi_io_req->SenseBufferLength, (uint8_t)(request_size - 64)); ! sense_bufp = (uint32_t)(mpt->m_req_frame_dma_addr + ! (mpt->m_req_frame_size * cmd->cmd_slot) & 0xffffffffull); sense_bufp += 64; ddi_put32(acc_hdl, &scsi_io_req->SenseBufferLowAddress, sense_bufp); /*
*** 9763,9798 **** * default request descriptor which is already set, so if this * is a SCSI IO request, change the descriptor to SCSI IO. */ if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) { desc_type = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; ! request_desc_high = (ddi_get16(acc_hdl, ! &scsi_io_req->DevHandle) << 16); } } /* * We must wait till the message has been completed before * beginning the next message so we wait for this one to * finish. */ (void) ddi_dma_sync(dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); ! request_desc_low = (cmd->cmd_slot << 16) + desc_type; cmd->cmd_rfm = NULL; ! MPTSAS_START_CMD(mpt, request_desc_low, request_desc_high); if ((mptsas_check_dma_handle(dma_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(acc_hdl) != DDI_SUCCESS)) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); } } static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply, uint8_t *data, uint32_t request_size, uint32_t reply_size, ! uint32_t data_size, uint32_t direction, uint8_t *dataout, uint32_t dataout_size, short timeout, int mode) { mptsas_pt_request_t pt; mptsas_dma_alloc_state_t data_dma_state; mptsas_dma_alloc_state_t dataout_dma_state; --- 11023,11419 ---- * default request descriptor which is already set, so if this * is a SCSI IO request, change the descriptor to SCSI IO. */ if (function == MPI2_FUNCTION_SCSI_IO_REQUEST) { desc_type = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; ! request_desc = (((uint64_t)ddi_get16(acc_hdl, ! &scsi_io_req->DevHandle)) << 48); } } /* * We must wait till the message has been completed before * beginning the next message so we wait for this one to * finish. */ (void) ddi_dma_sync(dma_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); ! request_desc |= ((cmd->cmd_slot << 16) | desc_type); cmd->cmd_rfm = NULL; ! MPTSAS_START_CMD(mpt, request_desc); if ((mptsas_check_dma_handle(dma_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(acc_hdl) != DDI_SUCCESS)) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); } } + typedef void (mps_pre_f)(mptsas_t *, mptsas_pt_request_t *); + static mps_pre_f mpi_pre_ioc_facts; + static mps_pre_f mpi_pre_port_facts; + static mps_pre_f mpi_pre_fw_download; + static mps_pre_f mpi_pre_fw_25_download; + static mps_pre_f mpi_pre_fw_upload; + static mps_pre_f mpi_pre_fw_25_upload; + static mps_pre_f mpi_pre_sata_passthrough; + static mps_pre_f mpi_pre_smp_passthrough; + static mps_pre_f mpi_pre_config; + static mps_pre_f mpi_pre_sas_io_unit_control; + static mps_pre_f mpi_pre_scsi_io_req; + + /* + * Prepare the pt for a SAS2 FW_DOWNLOAD request. + */ + static void + mpi_pre_fw_download(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMpi2FWDownloadTCSGE_t tcsge; + pMpi2FWDownloadRequest req; + + /* + * If SAS3, call separate function. + */ + if (mpt->m_MPI25) { + mpi_pre_fw_25_download(mpt, pt); + return; + } + + /* + * User requests should come in with the Transaction + * context element where the SGL will go. Putting the + * SGL after that seems to work, but don't really know + * why. Other drivers tend to create an extra SGL and + * refer to the TCE through that. + */ + req = (pMpi2FWDownloadRequest)pt->request; + tcsge = (pMpi2FWDownloadTCSGE_t)&req->SGL; + if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 || + tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) { + mptsas_log(mpt, CE_WARN, "FW Download tce invalid!"); + } + + pt->sgl_offset = offsetof(MPI2_FW_DOWNLOAD_REQUEST, SGL) + + sizeof (*tcsge); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_fw_download(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + (int)pt->request_size, (int)pt->sgl_offset, + (int)pt->dataout_size)); + if (pt->data_size < sizeof (MPI2_FW_DOWNLOAD_REPLY)) + NDBG15(("mpi_pre_fw_download(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_FW_DOWNLOAD_REPLY))); + } + + /* + * Prepare the pt for a SAS3 FW_DOWNLOAD request. + */ + static void + mpi_pre_fw_25_download(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMpi2FWDownloadTCSGE_t tcsge; + pMpi2FWDownloadRequest req2; + pMpi25FWDownloadRequest req25; + + /* + * User requests should come in with the Transaction + * context element where the SGL will go. The new firmware + * Doesn't use TCE and has space in the main request for + * this information. So move to the right place. + */ + req2 = (pMpi2FWDownloadRequest)pt->request; + req25 = (pMpi25FWDownloadRequest)pt->request; + tcsge = (pMpi2FWDownloadTCSGE_t)&req2->SGL; + if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 || + tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) { + mptsas_log(mpt, CE_WARN, "FW Download tce invalid!"); + } + req25->ImageOffset = tcsge->ImageOffset; + req25->ImageSize = tcsge->ImageSize; + + pt->sgl_offset = offsetof(MPI25_FW_DOWNLOAD_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_fw_25_download(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size < sizeof (MPI2_FW_DOWNLOAD_REPLY)) + NDBG15(("mpi_pre_fw_25_download(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_FW_UPLOAD_REPLY))); + } + + /* + * Prepare the pt for a SAS2 FW_UPLOAD request. + */ + static void + mpi_pre_fw_upload(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMpi2FWUploadTCSGE_t tcsge; + pMpi2FWUploadRequest_t req; + + /* + * If SAS3, call separate function. + */ + if (mpt->m_MPI25) { + mpi_pre_fw_25_upload(mpt, pt); + return; + } + + /* + * User requests should come in with the Transaction + * context element where the SGL will go. Putting the + * SGL after that seems to work, but don't really know + * why. Other drivers tend to create an extra SGL and + * refer to the TCE through that. + */ + req = (pMpi2FWUploadRequest_t)pt->request; + tcsge = (pMpi2FWUploadTCSGE_t)&req->SGL; + if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 || + tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) { + mptsas_log(mpt, CE_WARN, "FW Upload tce invalid!"); + } + + pt->sgl_offset = offsetof(MPI2_FW_UPLOAD_REQUEST, SGL) + + sizeof (*tcsge); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_fw_upload(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size < sizeof (MPI2_FW_UPLOAD_REPLY)) + NDBG15(("mpi_pre_fw_upload(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_FW_UPLOAD_REPLY))); + } + + /* + * Prepare the pt a SAS3 FW_UPLOAD request. + */ + static void + mpi_pre_fw_25_upload(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMpi2FWUploadTCSGE_t tcsge; + pMpi2FWUploadRequest_t req2; + pMpi25FWUploadRequest_t req25; + + /* + * User requests should come in with the Transaction + * context element where the SGL will go. The new firmware + * Doesn't use TCE and has space in the main request for + * this information. So move to the right place. + */ + req2 = (pMpi2FWUploadRequest_t)pt->request; + req25 = (pMpi25FWUploadRequest_t)pt->request; + tcsge = (pMpi2FWUploadTCSGE_t)&req2->SGL; + if (tcsge->ContextSize != 0 || tcsge->DetailsLength != 12 || + tcsge->Flags != MPI2_SGE_FLAGS_TRANSACTION_ELEMENT) { + mptsas_log(mpt, CE_WARN, "FW Upload tce invalid!"); + } + req25->ImageOffset = tcsge->ImageOffset; + req25->ImageSize = tcsge->ImageSize; + + pt->sgl_offset = offsetof(MPI25_FW_UPLOAD_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_fw_25_upload(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size < sizeof (MPI2_FW_UPLOAD_REPLY)) + NDBG15(("mpi_pre_fw_25_upload(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_FW_UPLOAD_REPLY))); + } + + /* + * Prepare the pt for an IOC_FACTS request. + */ + static void + mpi_pre_ioc_facts(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + if (pt->request_size != sizeof (MPI2_IOC_FACTS_REQUEST)) + NDBG15(("mpi_pre_ioc_facts(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, + (int)sizeof (MPI2_IOC_FACTS_REQUEST), + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_IOC_FACTS_REPLY)) + NDBG15(("mpi_pre_ioc_facts(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_IOC_FACTS_REPLY))); + pt->sgl_offset = (uint16_t)pt->request_size; + } + + /* + * Prepare the pt for a PORT_FACTS request. + */ + static void + mpi_pre_port_facts(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + if (pt->request_size != sizeof (MPI2_PORT_FACTS_REQUEST)) + NDBG15(("mpi_pre_port_facts(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, + (int)sizeof (MPI2_PORT_FACTS_REQUEST), + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_PORT_FACTS_REPLY)) + NDBG15(("mpi_pre_port_facts(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_PORT_FACTS_REPLY))); + pt->sgl_offset = (uint16_t)pt->request_size; + } + + /* + * Prepare pt for a SATA_PASSTHROUGH request. + */ + static void + mpi_pre_sata_passthrough(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = offsetof(MPI2_SATA_PASSTHROUGH_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_sata_passthrough(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_SATA_PASSTHROUGH_REPLY)) + NDBG15(("mpi_pre_sata_passthrough(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_SATA_PASSTHROUGH_REPLY))); + } + + static void + mpi_pre_smp_passthrough(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = offsetof(MPI2_SMP_PASSTHROUGH_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_smp_passthrough(): Incorrect req size, " + "0x%x, should be 0x%x, dataoutsz 0x%x", + pt->request_size, pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_SMP_PASSTHROUGH_REPLY)) + NDBG15(("mpi_pre_smp_passthrough(): Incorrect rep size, " + "0x%x, should be 0x%x", pt->data_size, + (int)sizeof (MPI2_SMP_PASSTHROUGH_REPLY))); + } + + /* + * Prepare pt for a CONFIG request. + */ + static void + mpi_pre_config(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = offsetof(MPI2_CONFIG_REQUEST, PageBufferSGE); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_config(): Incorrect req size, 0x%x, " + "should be 0x%x, dataoutsz 0x%x", pt->request_size, + pt->sgl_offset, pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_CONFIG_REPLY)) + NDBG15(("mpi_pre_config(): Incorrect rep size, 0x%x, " + "should be 0x%x", pt->data_size, + (int)sizeof (MPI2_CONFIG_REPLY))); + pt->simple = 1; + } + + /* + * Prepare pt for a SCSI_IO_REQ request. + */ + static void + mpi_pre_scsi_io_req(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = offsetof(MPI2_SCSI_IO_REQUEST, SGL); + if (pt->request_size != pt->sgl_offset) + NDBG15(("mpi_pre_config(): Incorrect req size, 0x%x, " + "should be 0x%x, dataoutsz 0x%x", pt->request_size, + pt->sgl_offset, + pt->dataout_size)); + if (pt->data_size != sizeof (MPI2_SCSI_IO_REPLY)) + NDBG15(("mpi_pre_config(): Incorrect rep size, 0x%x, " + "should be 0x%x", pt->data_size, + (int)sizeof (MPI2_SCSI_IO_REPLY))); + } + + /* + * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request. + */ + static void + mpi_pre_sas_io_unit_control(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + #ifndef __lock_lint + _NOTE(ARGUNUSED(mpt)) + #endif + pt->sgl_offset = (uint16_t)pt->request_size; + } + + /* + * A set of functions to prepare an mps_command for the various + * supported requests. + */ + struct mps_func { + U8 Function; + char *Name; + mps_pre_f *f_pre; + } mps_func_list[] = { + { MPI2_FUNCTION_IOC_FACTS, "IOC_FACTS", mpi_pre_ioc_facts }, + { MPI2_FUNCTION_PORT_FACTS, "PORT_FACTS", mpi_pre_port_facts }, + { MPI2_FUNCTION_FW_DOWNLOAD, "FW_DOWNLOAD", mpi_pre_fw_download }, + { MPI2_FUNCTION_FW_UPLOAD, "FW_UPLOAD", mpi_pre_fw_upload }, + { MPI2_FUNCTION_SATA_PASSTHROUGH, "SATA_PASSTHROUGH", + mpi_pre_sata_passthrough }, + { MPI2_FUNCTION_SMP_PASSTHROUGH, "SMP_PASSTHROUGH", + mpi_pre_smp_passthrough}, + { MPI2_FUNCTION_SCSI_IO_REQUEST, "SCSI_IO_REQUEST", + mpi_pre_scsi_io_req}, + { MPI2_FUNCTION_CONFIG, "CONFIG", mpi_pre_config}, + { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, "SAS_IO_UNIT_CONTROL", + mpi_pre_sas_io_unit_control }, + { 0xFF, NULL, NULL } /* list end */ + }; + + static void + mptsas_prep_sgl_offset(mptsas_t *mpt, mptsas_pt_request_t *pt) + { + pMPI2RequestHeader_t hdr; + struct mps_func *f; + + hdr = (pMPI2RequestHeader_t)pt->request; + + for (f = mps_func_list; f->f_pre != NULL; f++) { + if (hdr->Function == f->Function) { + f->f_pre(mpt, pt); + NDBG15(("mptsas_prep_sgl_offset: Function %s," + " sgl_offset 0x%x", f->Name, + pt->sgl_offset)); + return; + } + } + NDBG15(("mptsas_prep_sgl_offset: Unknown Function 0x%02x," + " returning req_size 0x%x for sgl_offset", + hdr->Function, pt->request_size)); + pt->sgl_offset = (uint16_t)pt->request_size; + } static int mptsas_do_passthru(mptsas_t *mpt, uint8_t *request, uint8_t *reply, uint8_t *data, uint32_t request_size, uint32_t reply_size, ! uint32_t data_size, uint8_t direction, uint8_t *dataout, uint32_t dataout_size, short timeout, int mode) { mptsas_pt_request_t pt; mptsas_dma_alloc_state_t data_dma_state; mptsas_dma_alloc_state_t dataout_dma_state;
*** 9865,9874 **** --- 11486,11497 ---- } } mutex_enter(&mpt->m_mutex); } } + else + bzero(&data_dma_state, sizeof (data_dma_state)); if (dataout_size != 0) { dataout_dma_state.size = dataout_size; if (mptsas_dma_alloc(mpt, &dataout_dma_state) != DDI_SUCCESS) { status = ENOMEM;
*** 9888,9897 **** --- 11511,11522 ---- goto out; } } mutex_enter(&mpt->m_mutex); } + else + bzero(&dataout_dma_state, sizeof (dataout_dma_state)); if ((rvalue = (mptsas_request_from_pool(mpt, &cmd, &pkt))) == -1) { status = EAGAIN; mptsas_log(mpt, CE_NOTE, "event ack command pool is full"); goto out;
*** 9904,9918 **** --- 11529,11545 ---- cmd->ioc_cmd_slot = (uint32_t)(rvalue); pt.request = (uint8_t *)request_msg; pt.direction = direction; + pt.simple = 0; pt.request_size = request_size; pt.data_size = data_size; pt.dataout_size = dataout_size; pt.data_cookie = data_dma_state.cookie; pt.dataout_cookie = dataout_dma_state.cookie; + mptsas_prep_sgl_offset(mpt, &pt); /* * Form a blank cmd/pkt to store the acknowledgement message */ pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb[0];
*** 9965,9975 **** pt_flags |= MPTSAS_ADDRESS_REPLY; (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply_msg = (pMPI2DefaultReply_t) (mpt->m_reply_frame + (cmd->cmd_rfm - ! mpt->m_reply_frame_dma_addr)); } mptsas_fma_check(mpt, cmd); if (pkt->pkt_reason == CMD_TRAN_ERR) { status = EAGAIN; --- 11592,11602 ---- pt_flags |= MPTSAS_ADDRESS_REPLY; (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply_msg = (pMPI2DefaultReply_t) (mpt->m_reply_frame + (cmd->cmd_rfm - ! (mpt->m_reply_frame_dma_addr&0xfffffffful))); } mptsas_fma_check(mpt, cmd); if (pkt->pkt_reason == CMD_TRAN_ERR) { status = EAGAIN;
*** 10121,10131 **** return (mptsas_do_passthru(mpt, (uint8_t *)((uintptr_t)data->PtrRequest), (uint8_t *)((uintptr_t)data->PtrReply), (uint8_t *)((uintptr_t)data->PtrData), data->RequestSize, data->ReplySize, ! data->DataSize, data->DataDirection, (uint8_t *)((uintptr_t)data->PtrDataOut), data->DataOutSize, data->Timeout, mode)); } else { return (EINVAL); } --- 11748,11758 ---- return (mptsas_do_passthru(mpt, (uint8_t *)((uintptr_t)data->PtrRequest), (uint8_t *)((uintptr_t)data->PtrReply), (uint8_t *)((uintptr_t)data->PtrData), data->RequestSize, data->ReplySize, ! data->DataSize, (uint8_t)data->DataDirection, (uint8_t *)((uintptr_t)data->PtrDataOut), data->DataOutSize, data->Timeout, mode)); } else { return (EINVAL); }
*** 10150,10160 **** { pMpi2DiagBufferPostRequest_t pDiag_post_msg; pMpi2DiagReleaseRequest_t pDiag_release_msg; struct scsi_pkt *pkt = cmd->cmd_pkt; mptsas_diag_request_t *diag = pkt->pkt_ha_private; ! uint32_t request_desc_low, i; ASSERT(mutex_owned(&mpt->m_mutex)); /* * Form the diag message depending on the post or release function. --- 11777,11788 ---- { pMpi2DiagBufferPostRequest_t pDiag_post_msg; pMpi2DiagReleaseRequest_t pDiag_release_msg; struct scsi_pkt *pkt = cmd->cmd_pkt; mptsas_diag_request_t *diag = pkt->pkt_ha_private; ! uint32_t i; ! uint64_t request_desc; ASSERT(mutex_owned(&mpt->m_mutex)); /* * Form the diag message depending on the post or release function.
*** 10203,10216 **** /* * Send the message */ (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); ! request_desc_low = (cmd->cmd_slot << 16) + MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cmd->cmd_rfm = NULL; ! MPTSAS_START_CMD(mpt, request_desc_low, 0); if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) != DDI_SUCCESS)) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED); --- 11831,11844 ---- /* * Send the message */ (void) ddi_dma_sync(mpt->m_dma_req_frame_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); ! request_desc = (cmd->cmd_slot << 16) | MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; cmd->cmd_rfm = NULL; ! MPTSAS_START_CMD(mpt, request_desc); if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) != DDI_SUCCESS)) { ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
*** 10304,10314 **** if (cmd->cmd_rfm) { post_flags |= MPTSAS_ADDRESS_REPLY; (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply = (pMpi2DiagBufferPostReply_t)(mpt->m_reply_frame + ! (cmd->cmd_rfm - mpt->m_reply_frame_dma_addr)); /* * Get the reply message data */ iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl, --- 11932,11943 ---- if (cmd->cmd_rfm) { post_flags |= MPTSAS_ADDRESS_REPLY; (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply = (pMpi2DiagBufferPostReply_t)(mpt->m_reply_frame + ! (cmd->cmd_rfm - ! (mpt->m_reply_frame_dma_addr&0xfffffffful))); /* * Get the reply message data */ iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
*** 10458,10468 **** if (cmd->cmd_rfm) { rel_flags |= MPTSAS_ADDRESS_REPLY; (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply = (pMpi2DiagReleaseReply_t)(mpt->m_reply_frame + ! (cmd->cmd_rfm - mpt->m_reply_frame_dma_addr)); /* * Get the reply message data */ iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl, --- 12087,12098 ---- if (cmd->cmd_rfm) { rel_flags |= MPTSAS_ADDRESS_REPLY; (void) ddi_dma_sync(mpt->m_dma_reply_frame_hdl, 0, 0, DDI_DMA_SYNC_FORCPU); reply = (pMpi2DiagReleaseReply_t)(mpt->m_reply_frame + ! (cmd->cmd_rfm - ! (mpt->m_reply_frame_dma_addr&0xfffffffful))); /* * Get the reply message data */ iocstatus = ddi_get16(mpt->m_acc_reply_frame_hdl,
*** 11206,11216 **** mptsas_read_adapter_data(mptsas_t *mpt, mptsas_adapter_data_t *adapter_data) { char *driver_verstr = MPTSAS_MOD_STRING; mptsas_lookup_pci_data(mpt, adapter_data); ! adapter_data->AdapterType = MPTIOCTL_ADAPTER_TYPE_SAS2; adapter_data->PCIDeviceHwId = (uint32_t)mpt->m_devid; adapter_data->PCIDeviceHwRev = (uint32_t)mpt->m_revid; adapter_data->SubSystemId = (uint32_t)mpt->m_ssid; adapter_data->SubsystemVendorId = (uint32_t)mpt->m_svid; (void) strcpy((char *)&adapter_data->DriverVersion[0], driver_verstr); --- 12836,12846 ---- mptsas_read_adapter_data(mptsas_t *mpt, mptsas_adapter_data_t *adapter_data) { char *driver_verstr = MPTSAS_MOD_STRING; mptsas_lookup_pci_data(mpt, adapter_data); ! adapter_data->AdapterType = MPTIOCTL_ADAPTER_TYPE_SAS3; adapter_data->PCIDeviceHwId = (uint32_t)mpt->m_devid; adapter_data->PCIDeviceHwRev = (uint32_t)mpt->m_revid; adapter_data->SubSystemId = (uint32_t)mpt->m_ssid; adapter_data->SubsystemVendorId = (uint32_t)mpt->m_svid; (void) strcpy((char *)&adapter_data->DriverVersion[0], driver_verstr);
*** 11480,11490 **** *rval = MPTIOCTL_STATUS_GOOD; if (secpolicy_sys_config(credp, B_FALSE) != 0) { return (EPERM); } ! mpt = ddi_get_soft_state(mptsas_state, MINOR2INST(getminor(dev))); if (mpt == NULL) { /* * Called from iport node, get the states */ iport_flag = 1; --- 13110,13120 ---- *rval = MPTIOCTL_STATUS_GOOD; if (secpolicy_sys_config(credp, B_FALSE) != 0) { return (EPERM); } ! mpt = ddi_get_soft_state(mptsas3_state, MINOR2INST(getminor(dev))); if (mpt == NULL) { /* * Called from iport node, get the states */ iport_flag = 1;
*** 11501,11511 **** if (mpt->m_power_level != PM_LEVEL_D0) { mutex_exit(&mpt->m_mutex); if (pm_raise_power(mpt->m_dip, 0, PM_LEVEL_D0) != DDI_SUCCESS) { mptsas_log(mpt, CE_WARN, ! "mptsas%d: mptsas_ioctl: Raise power " "request failed.", mpt->m_instance); (void) pm_idle_component(mpt->m_dip, 0); return (ENXIO); } } else { --- 13131,13141 ---- if (mpt->m_power_level != PM_LEVEL_D0) { mutex_exit(&mpt->m_mutex); if (pm_raise_power(mpt->m_dip, 0, PM_LEVEL_D0) != DDI_SUCCESS) { mptsas_log(mpt, CE_WARN, ! "mptsas3%d: mptsas_ioctl: Raise power " "request failed.", mpt->m_instance); (void) pm_idle_component(mpt->m_dip, 0); return (ENXIO); } } else {
*** 11741,11751 **** /* * Set all throttles to HOLD */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle(mpt, ptgt, HOLD_THROTTLE); } /* * Disable interrupts */ --- 13371,13381 ---- /* * Set all throttles to HOLD */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle_mtx(mpt, ptgt, HOLD_THROTTLE); } /* * Disable interrupts */
*** 11779,11789 **** /* * Reset the throttles */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle(mpt, ptgt, MAX_THROTTLE); } mptsas_doneq_empty(mpt); mptsas_restart_hba(mpt); --- 13409,13419 ---- /* * Reset the throttles */ for (ptgt = refhash_first(mpt->m_targets); ptgt != NULL; ptgt = refhash_next(mpt->m_targets, ptgt)) { ! mptsas_set_throttle_mtx(mpt, ptgt, MAX_THROTTLE); } mptsas_doneq_empty(mpt); mptsas_restart_hba(mpt);
*** 11802,11812 **** static int mptsas_init_chip(mptsas_t *mpt, int first_time) { ddi_dma_cookie_t cookie; ! uint32_t i; int rval; /* * Check to see if the firmware image is valid */ --- 13432,13443 ---- static int mptsas_init_chip(mptsas_t *mpt, int first_time) { ddi_dma_cookie_t cookie; ! mptsas_reply_pqueue_t *rpqp; ! uint32_t i, j; int rval; /* * Check to see if the firmware image is valid */
*** 11845,11854 **** --- 13476,13495 ---- if (mptsas_ioc_get_facts(mpt) == DDI_FAILURE) { mptsas_log(mpt, CE_WARN, "mptsas_ioc_get_facts failed"); goto fail; } + /* + * Now we know chip MSIX capabilitites and it's not been done + * previously register interrupts accordingly. Need to know this + * information before allocating the reply frames below. + */ + if (mpt->m_intr_cnt == 0) { + if (mptsas_register_intrs(mpt) == FALSE) + goto fail; + } + mpt->m_targets = refhash_create(MPTSAS_TARGET_BUCKET_COUNT, mptsas_target_addr_hash, mptsas_target_addr_cmp, mptsas_target_free, sizeof (mptsas_target_t), offsetof(mptsas_target_t, m_link), offsetof(mptsas_target_t, m_addr), KM_SLEEP);
*** 11862,11871 **** --- 13503,13516 ---- */ if (mptsas_alloc_request_frames(mpt) == DDI_FAILURE) { mptsas_log(mpt, CE_WARN, "mptsas_alloc_request_frames failed"); goto fail; } + if (mptsas_alloc_sense_bufs(mpt) == DDI_FAILURE) { + mptsas_log(mpt, CE_WARN, "mptsas_alloc_sense_bufs failed"); + goto fail; + } if (mptsas_alloc_free_queue(mpt) == DDI_FAILURE) { mptsas_log(mpt, CE_WARN, "mptsas_alloc_free_queue failed!"); goto fail; } if (mptsas_alloc_post_queue(mpt) == DDI_FAILURE) {
*** 11887,11906 **** } mptsas_alloc_reply_args(mpt); /* - * Initialize reply post index. Reply free index is initialized after - * the next loop. - */ - mpt->m_post_index = 0; - - /* * Initialize the Reply Free Queue with the physical addresses of our * reply frames. */ ! cookie.dmac_address = mpt->m_reply_frame_dma_addr; for (i = 0; i < mpt->m_max_replies; i++) { ddi_put32(mpt->m_acc_free_queue_hdl, &((uint32_t *)(void *)mpt->m_free_queue)[i], cookie.dmac_address); cookie.dmac_address += mpt->m_reply_frame_size; --- 13532,13545 ---- } mptsas_alloc_reply_args(mpt); /* * Initialize the Reply Free Queue with the physical addresses of our * reply frames. */ ! cookie.dmac_address = mpt->m_reply_frame_dma_addr&0xfffffffful; for (i = 0; i < mpt->m_max_replies; i++) { ddi_put32(mpt->m_acc_free_queue_hdl, &((uint32_t *)(void *)mpt->m_free_queue)[i], cookie.dmac_address); cookie.dmac_address += mpt->m_reply_frame_size;
*** 11914,11934 **** */ mpt->m_free_index = i; ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex, i); /* ! * Initialize the reply post queue to 0xFFFFFFFF,0xFFFFFFFF's. */ for (i = 0; i < mpt->m_post_queue_depth; i++) { ddi_put64(mpt->m_acc_post_queue_hdl, ! &((uint64_t *)(void *)mpt->m_post_queue)[i], 0xFFFFFFFFFFFFFFFF); } (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); /* * Enable ports */ if (mptsas_ioc_enable_port(mpt) == DDI_FAILURE) { mptsas_log(mpt, CE_WARN, "mptsas_ioc_enable_port failed"); goto fail; --- 13553,13587 ---- */ mpt->m_free_index = i; ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyFreeHostIndex, i); /* ! * Initialize the reply post queue to 0xFFFFFFFF,0xFFFFFFFF's ! * and the indexes to 0. */ + rpqp = mpt->m_rep_post_queues; + for (j = 0; j < mpt->m_post_reply_qcount; j++) { for (i = 0; i < mpt->m_post_queue_depth; i++) { ddi_put64(mpt->m_acc_post_queue_hdl, ! &((uint64_t *)(void *)rpqp->rpq_queue)[i], 0xFFFFFFFFFFFFFFFF); } + rpqp->rpq_index = 0; + rpqp++; + } (void) ddi_dma_sync(mpt->m_dma_post_queue_hdl, 0, 0, DDI_DMA_SYNC_FORDEV); /* + * Initialise all the reply post queue indexes. + */ + for (j = 0; j < mpt->m_post_reply_qcount; j++) { + ddi_put32(mpt->m_datap, &mpt->m_reg->ReplyPostHostIndex, + j << MPI2_RPHI_MSIX_INDEX_SHIFT); + } + + /* * Enable ports */ if (mptsas_ioc_enable_port(mpt) == DDI_FAILURE) { mptsas_log(mpt, CE_WARN, "mptsas_ioc_enable_port failed"); goto fail;
*** 11936,11955 **** --- 13589,13612 ---- /* * enable events */ if (mptsas_ioc_enable_event_notification(mpt)) { + mptsas_log(mpt, CE_WARN, + "mptsas_ioc_enable_event_notification failed"); goto fail; } /* * We need checks in attach and these. * chip_init is called in mult. places */ if ((mptsas_check_dma_handle(mpt->m_dma_req_frame_hdl) != DDI_SUCCESS) || + (mptsas_check_dma_handle(mpt->m_dma_req_sense_hdl) != + DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_reply_frame_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_free_queue_hdl) != DDI_SUCCESS) || (mptsas_check_dma_handle(mpt->m_dma_post_queue_hdl) !=
*** 11962,11971 **** --- 13619,13630 ---- /* Check all acc handles */ if ((mptsas_check_acc_handle(mpt->m_datap) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_req_frame_hdl) != DDI_SUCCESS) || + (mptsas_check_acc_handle(mpt->m_acc_req_sense_hdl) != + DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_reply_frame_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_free_queue_hdl) != DDI_SUCCESS) || (mptsas_check_acc_handle(mpt->m_acc_post_queue_hdl) !=
*** 12030,12059 **** */ cap = pci_config_get8(mpt->m_config_handle, caps_ptr); switch (cap) { case PCI_CAP_ID_PM: mptsas_log(mpt, CE_NOTE, ! "?mptsas%d supports power management.\n", mpt->m_instance); mpt->m_options |= MPTSAS_OPT_PM; /* Save PMCSR offset */ mpt->m_pmcsr_offset = caps_ptr + PCI_PMCSR; break; /* * The following capabilities are valid. Any others * will cause a message to be logged. */ case PCI_CAP_ID_VPD: - case PCI_CAP_ID_MSI: case PCI_CAP_ID_PCIX: case PCI_CAP_ID_PCI_E: - case PCI_CAP_ID_MSI_X: break; default: mptsas_log(mpt, CE_NOTE, ! "?mptsas%d unrecognized capability " "0x%x.\n", mpt->m_instance, cap); break; } /* --- 13689,13728 ---- */ cap = pci_config_get8(mpt->m_config_handle, caps_ptr); switch (cap) { case PCI_CAP_ID_PM: mptsas_log(mpt, CE_NOTE, ! "?mptsas3%d supports power management.\n", mpt->m_instance); mpt->m_options |= MPTSAS_OPT_PM; /* Save PMCSR offset */ mpt->m_pmcsr_offset = caps_ptr + PCI_PMCSR; break; + case PCI_CAP_ID_MSI: + mptsas_log(mpt, CE_NOTE, + "?mptsas3%d supports MSI.\n", + mpt->m_instance); + mpt->m_options |= MPTSAS_OPT_MSI; + break; + case PCI_CAP_ID_MSI_X: + mptsas_log(mpt, CE_NOTE, + "?mptsas3%d supports MSI-X.\n", + mpt->m_instance); + mpt->m_options |= MPTSAS_OPT_MSI_X; + break; /* * The following capabilities are valid. Any others * will cause a message to be logged. */ case PCI_CAP_ID_VPD: case PCI_CAP_ID_PCIX: case PCI_CAP_ID_PCI_E: break; default: mptsas_log(mpt, CE_NOTE, ! "?mptsas3%d unrecognized capability " "0x%x.\n", mpt->m_instance, cap); break; } /*
*** 12075,12104 **** "3=On (PCI D0 State)", NULL }; uint16_t pmcsr_stat; - if (mptsas_get_pci_cap(mpt) == FALSE) { - return (DDI_FAILURE); - } /* * If PCI's capability does not support PM, then don't need * to registe the pm-components */ if (!(mpt->m_options & MPTSAS_OPT_PM)) return (DDI_SUCCESS); /* * If power management is supported by this chip, create * pm-components property for the power management framework */ ! (void) sprintf(pmc_name, "NAME=mptsas%d", mpt->m_instance); pmc[0] = pmc_name; if (ddi_prop_update_string_array(DDI_DEV_T_NONE, mpt->m_dip, "pm-components", pmc, 3) != DDI_PROP_SUCCESS) { mpt->m_options &= ~MPTSAS_OPT_PM; mptsas_log(mpt, CE_WARN, ! "mptsas%d: pm-component property creation failed.", mpt->m_instance); return (DDI_FAILURE); } /* --- 13744,13770 ---- "3=On (PCI D0 State)", NULL }; uint16_t pmcsr_stat; /* * If PCI's capability does not support PM, then don't need * to registe the pm-components */ if (!(mpt->m_options & MPTSAS_OPT_PM)) return (DDI_SUCCESS); /* * If power management is supported by this chip, create * pm-components property for the power management framework */ ! (void) sprintf(pmc_name, "NAME=mptsas3%d", mpt->m_instance); pmc[0] = pmc_name; if (ddi_prop_update_string_array(DDI_DEV_T_NONE, mpt->m_dip, "pm-components", pmc, 3) != DDI_PROP_SUCCESS) { mpt->m_options &= ~MPTSAS_OPT_PM; mptsas_log(mpt, CE_WARN, ! "mptsas3%d: pm-component property creation failed.", mpt->m_instance); return (DDI_FAILURE); } /*
*** 12106,12116 **** */ (void) pm_busy_component(mpt->m_dip, 0); pmcsr_stat = pci_config_get16(mpt->m_config_handle, mpt->m_pmcsr_offset); if ((pmcsr_stat & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_D0) { ! mptsas_log(mpt, CE_WARN, "mptsas%d: Power up the device", mpt->m_instance); pci_config_put16(mpt->m_config_handle, mpt->m_pmcsr_offset, PCI_PMCSR_D0); } if (pm_power_has_changed(mpt->m_dip, 0, PM_LEVEL_D0) != DDI_SUCCESS) { --- 13772,13782 ---- */ (void) pm_busy_component(mpt->m_dip, 0); pmcsr_stat = pci_config_get16(mpt->m_config_handle, mpt->m_pmcsr_offset); if ((pmcsr_stat & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_D0) { ! mptsas_log(mpt, CE_WARN, "mptsas3%d: Power up the device", mpt->m_instance); pci_config_put16(mpt->m_config_handle, mpt->m_pmcsr_offset, PCI_PMCSR_D0); } if (pm_power_has_changed(mpt->m_dip, 0, PM_LEVEL_D0) != DDI_SUCCESS) {
*** 12143,12168 **** } NDBG6(("ddi_intr_get_supported_types() returned: 0x%x", intr_types)); /* * Try MSI, but fall back to FIXED */ if (mptsas_enable_msi && (intr_types & DDI_INTR_TYPE_MSI)) { if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_MSI) == DDI_SUCCESS) { ! NDBG0(("Using MSI interrupt type")); mpt->m_intr_type = DDI_INTR_TYPE_MSI; return (TRUE); } } if (intr_types & DDI_INTR_TYPE_FIXED) { if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_FIXED) == DDI_SUCCESS) { ! NDBG0(("Using FIXED interrupt type")); mpt->m_intr_type = DDI_INTR_TYPE_FIXED; return (TRUE); } else { ! NDBG0(("FIXED interrupt registration failed")); return (FALSE); } } return (FALSE); --- 13809,13845 ---- } NDBG6(("ddi_intr_get_supported_types() returned: 0x%x", intr_types)); /* + * Try MSIX first. + */ + if (mptsas_enable_msix && (intr_types & DDI_INTR_TYPE_MSIX)) { + if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_MSIX) == DDI_SUCCESS) { + NDBG6(("Using MSI-X interrupt type")); + mpt->m_intr_type = DDI_INTR_TYPE_MSIX; + return (TRUE); + } + } + + /* * Try MSI, but fall back to FIXED */ if (mptsas_enable_msi && (intr_types & DDI_INTR_TYPE_MSI)) { if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_MSI) == DDI_SUCCESS) { ! NDBG6(("Using MSI interrupt type")); mpt->m_intr_type = DDI_INTR_TYPE_MSI; return (TRUE); } } if (intr_types & DDI_INTR_TYPE_FIXED) { if (mptsas_add_intrs(mpt, DDI_INTR_TYPE_FIXED) == DDI_SUCCESS) { ! NDBG6(("Using FIXED interrupt type")); mpt->m_intr_type = DDI_INTR_TYPE_FIXED; return (TRUE); } else { ! NDBG6(("FIXED interrupt registration failed")); return (FALSE); } } return (FALSE);
*** 12195,12248 **** "ret %d count %d\n", ret, count); return (DDI_FAILURE); } ! /* Get number of available interrupts */ ret = ddi_intr_get_navail(dip, intr_type, &avail); if ((ret != DDI_SUCCESS) || (avail == 0)) { mptsas_log(mpt, CE_WARN, "ddi_intr_get_navail() failed, " "ret %d avail %d\n", ret, avail); return (DDI_FAILURE); } ! if (avail < count) { mptsas_log(mpt, CE_NOTE, "ddi_intr_get_nvail returned %d, " "navail() returned %d", count, avail); } ! /* Mpt only have one interrupt routine */ ! if ((intr_type == DDI_INTR_TYPE_MSI) && (count > 1)) { ! count = 1; } /* Allocate an array of interrupt handles */ ! mpt->m_intr_size = count * sizeof (ddi_intr_handle_t); mpt->m_htable = kmem_alloc(mpt->m_intr_size, KM_SLEEP); flag = DDI_INTR_ALLOC_NORMAL; /* call ddi_intr_alloc() */ ret = ddi_intr_alloc(dip, mpt->m_htable, intr_type, 0, ! count, &actual, flag); if ((ret != DDI_SUCCESS) || (actual == 0)) { mptsas_log(mpt, CE_WARN, "ddi_intr_alloc() failed, ret %d\n", ret); kmem_free(mpt->m_htable, mpt->m_intr_size); return (DDI_FAILURE); } /* use interrupt count returned or abort? */ ! if (actual < count) { ! mptsas_log(mpt, CE_NOTE, "Requested: %d, Received: %d\n", ! count, actual); } - mpt->m_intr_cnt = actual; - /* * Get priority for first msi, assume remaining are all the same */ if ((ret = ddi_intr_get_pri(mpt->m_htable[0], &mpt->m_intr_pri)) != DDI_SUCCESS) { --- 13872,13947 ---- "ret %d count %d\n", ret, count); return (DDI_FAILURE); } ! /* Get number of interrupts available to this device */ ret = ddi_intr_get_navail(dip, intr_type, &avail); if ((ret != DDI_SUCCESS) || (avail == 0)) { mptsas_log(mpt, CE_WARN, "ddi_intr_get_navail() failed, " "ret %d avail %d\n", ret, avail); return (DDI_FAILURE); } ! if (count < avail) { mptsas_log(mpt, CE_NOTE, "ddi_intr_get_nvail returned %d, " "navail() returned %d", count, avail); } ! NDBG6(("mptsas_add_intrs:count %d, avail %d", count, avail)); ! ! if (intr_type == DDI_INTR_TYPE_MSIX) { ! if (!mptsas3_max_msix_intrs) { ! return (DDI_FAILURE); ! } ! ! /* ! * Restrict the number of interrupts, firstly by ! * the number returned from the IOCInfo, then by ! * overall restriction. ! */ ! if (avail > mpt->m_max_msix_vectors) { ! avail = mpt->m_max_msix_vectors? ! mpt->m_max_msix_vectors:1; ! NDBG6(("mptsas_add_intrs: mmmv avail %d", avail)); ! } ! if (avail > mptsas3_max_msix_intrs) { ! avail = mptsas3_max_msix_intrs; ! NDBG6(("mptsas_add_intrs: m3mmi avail %d", avail)); ! } ! } ! if (intr_type == DDI_INTR_TYPE_MSI) { ! NDBG6(("mptsas_add_intrs: MSI avail %d", avail)); ! avail = 1; } /* Allocate an array of interrupt handles */ ! mpt->m_intr_size = avail * sizeof (ddi_intr_handle_t); mpt->m_htable = kmem_alloc(mpt->m_intr_size, KM_SLEEP); flag = DDI_INTR_ALLOC_NORMAL; /* call ddi_intr_alloc() */ ret = ddi_intr_alloc(dip, mpt->m_htable, intr_type, 0, ! avail, &actual, flag); if ((ret != DDI_SUCCESS) || (actual == 0)) { mptsas_log(mpt, CE_WARN, "ddi_intr_alloc() failed, ret %d\n", ret); kmem_free(mpt->m_htable, mpt->m_intr_size); return (DDI_FAILURE); } + NDBG6(("mptsas_add_intrs: actual %d, avail %d", actual, avail)); /* use interrupt count returned or abort? */ ! if (actual < avail) { ! mptsas_log(mpt, CE_NOTE, ! "Interrupts requested: %d, received: %d\n", ! avail, actual); } /* * Get priority for first msi, assume remaining are all the same */ if ((ret = ddi_intr_get_pri(mpt->m_htable[0], &mpt->m_intr_pri)) != DDI_SUCCESS) {
*** 12299,12308 **** --- 13998,14009 ---- kmem_free(mpt->m_htable, mpt->m_intr_size); return (DDI_FAILURE); } + mpt->m_intr_cnt = actual; + /* * Enable interrupts */ if (mpt->m_intr_cap & DDI_INTR_FLAG_BLOCK) { /* Call ddi_intr_block_enable() for MSI interrupts */
*** 12311,12320 **** --- 14012,14037 ---- /* Call ddi_intr_enable for MSI or FIXED interrupts */ for (i = 0; i < mpt->m_intr_cnt; i++) { (void) ddi_intr_enable(mpt->m_htable[i]); } } + + switch (intr_type) { + case DDI_INTR_TYPE_MSIX: + mptsas_log(mpt, CE_NOTE, "?Using %d MSI-X interrupt(s) " + "(Available sys %d, mpt %d, Requested %d)\n", + actual, count, mpt->m_max_msix_vectors, avail); + break; + case DDI_INTR_TYPE_MSI: + mptsas_log(mpt, CE_NOTE, "Using single MSI interrupt\n"); + break; + case DDI_INTR_TYPE_FIXED: + default: + mptsas_log(mpt, CE_NOTE, "Using single fixed interrupt\n"); + break; + } + return (DDI_SUCCESS); } /* * mptsas_rem_intrs:
*** 12341,12352 **** /* Call ddi_intr_remove_handler() */ for (i = 0; i < mpt->m_intr_cnt; i++) { (void) ddi_intr_remove_handler(mpt->m_htable[i]); (void) ddi_intr_free(mpt->m_htable[i]); } - kmem_free(mpt->m_htable, mpt->m_intr_size); } /* * The IO fault service error handling callback function */ --- 14058,14069 ---- /* Call ddi_intr_remove_handler() */ for (i = 0; i < mpt->m_intr_cnt; i++) { (void) ddi_intr_remove_handler(mpt->m_htable[i]); (void) ddi_intr_free(mpt->m_htable[i]); } kmem_free(mpt->m_htable, mpt->m_intr_size); + mpt->m_intr_cnt = 0; } /* * The IO fault service error handling callback function */
*** 12492,12508 **** mptsas_phymask_t phymask; uint8_t physport, phynum, config, disk; uint64_t devicename; uint16_t pdev_hdl; mptsas_target_t *tmp_tgt = NULL; ! uint16_t bay_num, enclosure; ASSERT(*pptgt == NULL); rval = mptsas_get_sas_device_page0(mpt, page_address, dev_handle, &sas_wwn, &dev_info, &physport, &phynum, &pdev_hdl, ! &bay_num, &enclosure); if (rval != DDI_SUCCESS) { rval = DEV_INFO_FAIL_PAGE0; return (rval); } --- 14209,14225 ---- mptsas_phymask_t phymask; uint8_t physport, phynum, config, disk; uint64_t devicename; uint16_t pdev_hdl; mptsas_target_t *tmp_tgt = NULL; ! uint16_t bay_num, enclosure, io_flags; ASSERT(*pptgt == NULL); rval = mptsas_get_sas_device_page0(mpt, page_address, dev_handle, &sas_wwn, &dev_info, &physport, &phynum, &pdev_hdl, ! &bay_num, &enclosure, &io_flags); if (rval != DDI_SUCCESS) { rval = DEV_INFO_FAIL_PAGE0; return (rval); }
*** 12543,12553 **** --- 14260,14272 ---- tmp_tgt->m_deviceinfo = dev_info; tmp_tgt->m_qfull_retries = QFULL_RETRIES; tmp_tgt->m_qfull_retry_interval = drv_usectohz(QFULL_RETRY_INTERVAL * 1000); tmp_tgt->m_t_throttle = MAX_THROTTLE; + mutex_init(&tmp_tgt->m_t_mutex, NULL, MUTEX_DRIVER, NULL); devicename = mptsas_get_sata_guid(mpt, tmp_tgt, 0); + mutex_destroy(&tmp_tgt->m_t_mutex); kmem_free(tmp_tgt, sizeof (struct mptsas_target)); mutex_enter(&mpt->m_mutex); if (devicename != 0 && (((devicename >> 56) & 0xf0) == 0x50)) { sas_wwn = devicename; } else if (dev_info & MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH) {
*** 12562,12571 **** --- 14281,14291 ---- mptsas_log(mpt, CE_WARN, "Failed to allocated target" "structure!"); rval = DEV_INFO_FAIL_ALLOC; return (rval); } + (*pptgt)->m_io_flags = io_flags; (*pptgt)->m_enclosure = enclosure; (*pptgt)->m_slot_num = bay_num; return (DEV_INFO_SUCCESS); }
*** 12699,12708 **** --- 14419,14429 ---- if (pktp == NULL) { goto out; } bcopy(cdb, pktp->pkt_cdbp, cdblen); pktp->pkt_flags = FLAG_NOPARITY; + pktp->pkt_time = mptsas_scsi_pkt_time; if (scsi_poll(pktp) < 0) { goto out; } if (((struct scsi_status *)pktp->pkt_scbp)->sts_chk) { goto out;
*** 13547,13557 **** * Return fail if not all the childs/paths are freed. * if there is any path under the HBA, the return value will be always fail * because we didn't call mdi_pi_free for path */ static int ! mptsas_offline_target(dev_info_t *pdip, char *name) { dev_info_t *child = NULL, *prechild = NULL; mdi_pathinfo_t *pip = NULL, *savepip = NULL; int tmp_rval, rval = DDI_SUCCESS; char *addr, *cp; --- 15268,15278 ---- * Return fail if not all the childs/paths are freed. * if there is any path under the HBA, the return value will be always fail * because we didn't call mdi_pi_free for path */ static int ! mptsas_offline_targetdev(dev_info_t *pdip, char *name) { dev_info_t *child = NULL, *prechild = NULL; mdi_pathinfo_t *pip = NULL, *savepip = NULL; int tmp_rval, rval = DDI_SUCCESS; char *addr, *cp;
*** 13582,13592 **** if (tmp_rval != DDI_SUCCESS) { rval = DDI_FAILURE; if (ndi_prop_create_boolean(DDI_DEV_T_NONE, prechild, MPTSAS_DEV_GONE) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas driver " "unable to create property for " "SAS %s (MPTSAS_DEV_GONE)", addr); } } } --- 15303,15313 ---- if (tmp_rval != DDI_SUCCESS) { rval = DDI_FAILURE; if (ndi_prop_create_boolean(DDI_DEV_T_NONE, prechild, MPTSAS_DEV_GONE) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "unable to create property for " "SAS %s (MPTSAS_DEV_GONE)", addr); } } }
*** 13959,13970 **** int mdi_rtn = MDI_FAILURE; int rval = DDI_FAILURE; char *old_guid = NULL; mptsas_t *mpt = DIP2MPT(pdip); char *lun_addr = NULL; ! char *wwn_str = NULL; ! char *attached_wwn_str = NULL; char *component = NULL; uint8_t phy = 0xFF; uint64_t sas_wwn; int64_t lun64 = 0; uint32_t devinfo; --- 15680,15690 ---- int mdi_rtn = MDI_FAILURE; int rval = DDI_FAILURE; char *old_guid = NULL; mptsas_t *mpt = DIP2MPT(pdip); char *lun_addr = NULL; ! char wwn_str[MPTSAS_WWN_STRLEN]; char *component = NULL; uint8_t phy = 0xFF; uint64_t sas_wwn; int64_t lun64 = 0; uint32_t devinfo;
*** 13974,13984 **** uint64_t pdev_sas_wwn; uint32_t pdev_info; uint8_t physport; uint8_t phy_id; uint32_t page_address; ! uint16_t bay_num, enclosure; char pdev_wwn_str[MPTSAS_WWN_STRLEN]; uint32_t dev_info; mutex_enter(&mpt->m_mutex); target = ptgt->m_devhdl; --- 15694,15704 ---- uint64_t pdev_sas_wwn; uint32_t pdev_info; uint8_t physport; uint8_t phy_id; uint32_t page_address; ! uint16_t bay_num, enclosure, io_flags; char pdev_wwn_str[MPTSAS_WWN_STRLEN]; uint32_t dev_info; mutex_enter(&mpt->m_mutex); target = ptgt->m_devhdl;
*** 14068,14084 **** /* * if nodename can't be determined then print a message and skip it */ if (nodename == NULL) { ! mptsas_log(mpt, CE_WARN, "mptsas driver found no compatible " "driver for target%d lun %d dtype:0x%02x", target, lun, inq->inq_dtype); return (DDI_FAILURE); } - wwn_str = kmem_zalloc(MPTSAS_WWN_STRLEN, KM_SLEEP); /* The property is needed by MPAPI */ (void) sprintf(wwn_str, "%016"PRIx64, sas_wwn); lun_addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP); if (guid) { --- 15788,15803 ---- /* * if nodename can't be determined then print a message and skip it */ if (nodename == NULL) { ! mptsas_log(mpt, CE_WARN, "found no compatible " "driver for target%d lun %d dtype:0x%02x", target, lun, inq->inq_dtype); return (DDI_FAILURE); } /* The property is needed by MPAPI */ (void) sprintf(wwn_str, "%016"PRIx64, sas_wwn); lun_addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP); if (guid) {
*** 14094,14149 **** 0, pip); if (mdi_rtn == MDI_SUCCESS) { if (mdi_prop_update_string(*pip, MDI_GUID, guid) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas driver unable to " "create prop for target %d lun %d (MDI_GUID)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } if (mdi_prop_update_int(*pip, LUN_PROP, lun) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas driver unable to " "create prop for target %d lun %d (LUN_PROP)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } lun64 = (int64_t)lun; if (mdi_prop_update_int64(*pip, LUN64_PROP, lun64) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas driver unable to " "create prop for target %d (LUN64_PROP)", target); mdi_rtn = MDI_FAILURE; goto virt_create_done; } if (mdi_prop_update_string_array(*pip, "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas driver unable to " "create prop for target %d lun %d (COMPATIBLE)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } if (sas_wwn && (mdi_prop_update_string(*pip, SCSI_ADDR_PROP_TARGET_PORT, wwn_str) != DDI_PROP_SUCCESS)) { ! mptsas_log(mpt, CE_WARN, "mptsas driver unable to " "create prop for target %d lun %d " "(target-port)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } else if ((sas_wwn == 0) && (mdi_prop_update_int(*pip, "sata-phy", phy) != DDI_PROP_SUCCESS)) { /* * Direct attached SATA device without DeviceName */ ! mptsas_log(mpt, CE_WARN, "mptsas driver unable to " "create prop for SAS target %d lun %d " "(sata-phy)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } --- 15813,15868 ---- 0, pip); if (mdi_rtn == MDI_SUCCESS) { if (mdi_prop_update_string(*pip, MDI_GUID, guid) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "unable to " "create prop for target %d lun %d (MDI_GUID)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } if (mdi_prop_update_int(*pip, LUN_PROP, lun) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "unable to " "create prop for target %d lun %d (LUN_PROP)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } lun64 = (int64_t)lun; if (mdi_prop_update_int64(*pip, LUN64_PROP, lun64) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "unable to " "create prop for target %d (LUN64_PROP)", target); mdi_rtn = MDI_FAILURE; goto virt_create_done; } if (mdi_prop_update_string_array(*pip, "compatible", compatible, ncompatible) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "unable to " "create prop for target %d lun %d (COMPATIBLE)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } if (sas_wwn && (mdi_prop_update_string(*pip, SCSI_ADDR_PROP_TARGET_PORT, wwn_str) != DDI_PROP_SUCCESS)) { ! mptsas_log(mpt, CE_WARN, "unable to " "create prop for target %d lun %d " "(target-port)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } else if ((sas_wwn == 0) && (mdi_prop_update_int(*pip, "sata-phy", phy) != DDI_PROP_SUCCESS)) { /* * Direct attached SATA device without DeviceName */ ! mptsas_log(mpt, CE_WARN, "unable to " "create prop for SAS target %d lun %d " "(sata-phy)", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; }
*** 14152,14162 **** page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)ptgt->m_devhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &dev_sas_wwn, &dev_info, &physport, ! &phy_id, &pdev_hdl, &bay_num, &enclosure); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get " "parent device for handle %d", page_address); mdi_rtn = MDI_FAILURE; --- 15871,15881 ---- page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)ptgt->m_devhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &dev_sas_wwn, &dev_info, &physport, ! &phy_id, &pdev_hdl, &bay_num, &enclosure, &io_flags); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get " "parent device for handle %d", page_address); mdi_rtn = MDI_FAILURE;
*** 14165,14175 **** page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)pdev_hdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &pdev_sas_wwn, &pdev_info, &physport, ! &phy_id, &pdev_hdl, &bay_num, &enclosure); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get" "device info for handle %d", page_address); mdi_rtn = MDI_FAILURE; --- 15884,15894 ---- page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)pdev_hdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &pdev_sas_wwn, &pdev_info, &physport, ! &phy_id, &pdev_hdl, &bay_num, &enclosure, &io_flags); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get" "device info for handle %d", page_address); mdi_rtn = MDI_FAILURE;
*** 14212,14224 **** } if (mdi_prop_update_string(*pip, SCSI_ADDR_PROP_ATTACHED_PORT, pdev_wwn_str) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas unable to create " "property for iport attached-port %s (sas_wwn)", ! attached_wwn_str); mdi_rtn = MDI_FAILURE; goto virt_create_done; } --- 15931,15943 ---- } if (mdi_prop_update_string(*pip, SCSI_ADDR_PROP_ATTACHED_PORT, pdev_wwn_str) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "unable to create " "property for iport attached-port %s (sas_wwn)", ! pdev_wwn_str); mdi_rtn = MDI_FAILURE; goto virt_create_done; }
*** 14230,14240 **** (void) snprintf(component, MAXPATHLEN, "disk@%s", lun_addr); if (mdi_pi_pathname_obp_set(*pip, component) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mpt_sas driver " "unable to set obp-path for object %s", component); mdi_rtn = MDI_FAILURE; goto virt_create_done; } --- 15949,15959 ---- (void) snprintf(component, MAXPATHLEN, "disk@%s", lun_addr); if (mdi_pi_pathname_obp_set(*pip, component) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "unable to set obp-path for object %s", component); mdi_rtn = MDI_FAILURE; goto virt_create_done; }
*** 14244,14254 **** if (devinfo & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE | MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) { if ((ndi_prop_update_int(DDI_DEV_T_NONE, *lun_dip, "pm-capable", 1)) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas driver" "failed to create pm-capable " "property, target %d", target); mdi_rtn = MDI_FAILURE; goto virt_create_done; } --- 15963,15973 ---- if (devinfo & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE | MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) { if ((ndi_prop_update_int(DDI_DEV_T_NONE, *lun_dip, "pm-capable", 1)) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "failed to create pm-capable " "property, target %d", target); mdi_rtn = MDI_FAILURE; goto virt_create_done; }
*** 14256,14266 **** /* * Create the phy-num property */ if (mdi_prop_update_int(*pip, "phy-num", ptgt->m_phynum) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas driver unable to " "create phy-num property for target %d lun %d", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; } --- 15975,15985 ---- /* * Create the phy-num property */ if (mdi_prop_update_int(*pip, "phy-num", ptgt->m_phynum) != DDI_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "unable to " "create phy-num property for target %d lun %d", target, lun); mdi_rtn = MDI_FAILURE; goto virt_create_done; }
*** 14285,14297 **** scsi_hba_nodename_compatible_free(nodename, compatible); if (lun_addr != NULL) { kmem_free(lun_addr, SCSI_MAXNAMELEN); } - if (wwn_str != NULL) { - kmem_free(wwn_str, MPTSAS_WWN_STRLEN); - } if (component != NULL) { kmem_free(component, MAXPATHLEN); } return ((mdi_rtn == MDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); --- 16004,16013 ----
*** 14308,14320 **** char *nodename = NULL; char **compatible = NULL; int ncompatible = 0; int instance = 0; mptsas_t *mpt = DIP2MPT(pdip); ! char *wwn_str = NULL; ! char *component = NULL; ! char *attached_wwn_str = NULL; uint8_t phy = 0xFF; uint64_t sas_wwn; uint32_t devinfo; uint16_t dev_hdl; uint16_t pdev_hdl; --- 16024,16035 ---- char *nodename = NULL; char **compatible = NULL; int ncompatible = 0; int instance = 0; mptsas_t *mpt = DIP2MPT(pdip); ! char wwn_str[MPTSAS_WWN_STRLEN]; ! char component[MAXPATHLEN]; uint8_t phy = 0xFF; uint64_t sas_wwn; uint32_t devinfo; uint16_t dev_hdl; uint16_t pdev_hdl;
*** 14322,14332 **** uint64_t dev_sas_wwn; uint32_t pdev_info; uint8_t physport; uint8_t phy_id; uint32_t page_address; ! uint16_t bay_num, enclosure; char pdev_wwn_str[MPTSAS_WWN_STRLEN]; uint32_t dev_info; int64_t lun64 = 0; mutex_enter(&mpt->m_mutex); --- 16037,16047 ---- uint64_t dev_sas_wwn; uint32_t pdev_info; uint8_t physport; uint8_t phy_id; uint32_t page_address; ! uint16_t bay_num, enclosure, io_flags; char pdev_wwn_str[MPTSAS_WWN_STRLEN]; uint32_t dev_info; int64_t lun64 = 0; mutex_enter(&mpt->m_mutex);
*** 14393,14403 **** * We need the SAS WWN for non-multipath devices, so * we'll use the same property as that multipathing * devices need to present for MPAPI. If we don't have * a WWN (e.g. parallel SCSI), don't create the prop. */ - wwn_str = kmem_zalloc(MPTSAS_WWN_STRLEN, KM_SLEEP); (void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn); if (sas_wwn && ndi_prop_update_string(DDI_DEV_T_NONE, *lun_dip, SCSI_ADDR_PROP_TARGET_PORT, wwn_str) != DDI_PROP_SUCCESS) { mptsas_log(mpt, CE_WARN, "mptsas unable to " --- 16108,16117 ----
*** 14459,14469 **** MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)ptgt->m_devhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &dev_sas_wwn, &dev_info, &physport, &phy_id, &pdev_hdl, ! &bay_num, &enclosure); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get" "parent device for handle %d.", page_address); ndi_rtn = NDI_FAILURE; --- 16173,16183 ---- MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)ptgt->m_devhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &dev_sas_wwn, &dev_info, &physport, &phy_id, &pdev_hdl, ! &bay_num, &enclosure, &io_flags); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get" "parent device for handle %d.", page_address); ndi_rtn = NDI_FAILURE;
*** 14471,14482 **** } page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)pdev_hdl; rval = mptsas_get_sas_device_page0(mpt, page_address, ! &dev_hdl, &pdev_sas_wwn, &pdev_info, ! &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to create " "device for handle %d.", page_address); ndi_rtn = NDI_FAILURE; --- 16185,16196 ---- } page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)pdev_hdl; rval = mptsas_get_sas_device_page0(mpt, page_address, ! &dev_hdl, &pdev_sas_wwn, &pdev_info, &physport, ! &phy_id, &pdev_hdl, &bay_num, &enclosure, &io_flags); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to create " "device for handle %d.", page_address); ndi_rtn = NDI_FAILURE;
*** 14522,14532 **** *lun_dip, SCSI_ADDR_PROP_ATTACHED_PORT, pdev_wwn_str) != DDI_PROP_SUCCESS) { mptsas_log(mpt, CE_WARN, "mptsas unable to create " "property for iport attached-port %s (sas_wwn)", ! attached_wwn_str); ndi_rtn = NDI_FAILURE; goto phys_create_done; } if (IS_SATA_DEVICE(dev_info)) { --- 16236,16246 ---- *lun_dip, SCSI_ADDR_PROP_ATTACHED_PORT, pdev_wwn_str) != DDI_PROP_SUCCESS) { mptsas_log(mpt, CE_WARN, "mptsas unable to create " "property for iport attached-port %s (sas_wwn)", ! pdev_wwn_str); ndi_rtn = NDI_FAILURE; goto phys_create_done; } if (IS_SATA_DEVICE(dev_info)) {
*** 14561,14571 **** * device. */ instance = ddi_get_instance(mpt->m_dip); if (devinfo & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE | MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) { ! NDBG2(("mptsas%d: creating pm-capable property, " "target %d", instance, target)); if ((ndi_prop_update_int(DDI_DEV_T_NONE, *lun_dip, "pm-capable", 1)) != DDI_PROP_SUCCESS) { --- 16275,16285 ---- * device. */ instance = ddi_get_instance(mpt->m_dip); if (devinfo & (MPI2_SAS_DEVICE_INFO_SATA_DEVICE | MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE)) { ! NDBG2(("mptsas3%d: creating pm-capable property, " "target %d", instance, target)); if ((ndi_prop_update_int(DDI_DEV_T_NONE, *lun_dip, "pm-capable", 1)) != DDI_PROP_SUCCESS) {
*** 14582,14592 **** /* * add 'obp-path' properties for devinfo */ bzero(wwn_str, sizeof (wwn_str)); (void) sprintf(wwn_str, "%016"PRIx64, sas_wwn); - component = kmem_zalloc(MAXPATHLEN, KM_SLEEP); if (guid) { (void) snprintf(component, MAXPATHLEN, "disk@w%s,%x", wwn_str, lun); } else { (void) snprintf(component, MAXPATHLEN, --- 16296,16305 ----
*** 14606,14616 **** */ if (ptgt->m_addr.mta_phymask != 0) { if (ndi_prop_update_int(DDI_DEV_T_NONE, *lun_dip, "phy-num", ptgt->m_phynum) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "mptsas driver " "failed to create phy-num property for " "target %d", target); ndi_rtn = NDI_FAILURE; goto phys_create_done; } --- 16319,16329 ---- */ if (ptgt->m_addr.mta_phymask != 0) { if (ndi_prop_update_int(DDI_DEV_T_NONE, *lun_dip, "phy-num", ptgt->m_phynum) != DDI_PROP_SUCCESS) { ! mptsas_log(mpt, CE_WARN, "failed to create phy-num property for " "target %d", target); ndi_rtn = NDI_FAILURE; goto phys_create_done; }
*** 14634,14661 **** /* * If success set rtn flag, else unwire alloc'd lun */ if (ndi_rtn != NDI_SUCCESS) { ! NDBG12(("mptsas driver unable to online " "target %d lun %d", target, lun)); ndi_prop_remove_all(*lun_dip); (void) ndi_devi_free(*lun_dip); *lun_dip = NULL; } } scsi_hba_nodename_compatible_free(nodename, compatible); - if (wwn_str != NULL) { - kmem_free(wwn_str, MPTSAS_WWN_STRLEN); - } - if (component != NULL) { - kmem_free(component, MAXPATHLEN); - } - - return ((ndi_rtn == NDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); } static int mptsas_probe_smp(dev_info_t *pdip, uint64_t wwn) --- 16347,16366 ---- /* * If success set rtn flag, else unwire alloc'd lun */ if (ndi_rtn != NDI_SUCCESS) { ! NDBG12(("unable to online " "target %d lun %d", target, lun)); ndi_prop_remove_all(*lun_dip); (void) ndi_devi_free(*lun_dip); *lun_dip = NULL; } } scsi_hba_nodename_compatible_free(nodename, compatible); return ((ndi_rtn == NDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE); } static int mptsas_probe_smp(dev_info_t *pdip, uint64_t wwn)
*** 14722,14732 **** uint16_t i = 0; char phymask[MPTSAS_MAX_PHYS]; char *iport = NULL; mptsas_phymask_t phy_mask = 0; uint16_t attached_devhdl; ! uint16_t bay_num, enclosure; (void) sprintf(wwn_str, "%"PRIx64, smp_node->m_addr.mta_wwn); /* * Probe smp device, prevent the node of removed device from being --- 16427,16437 ---- uint16_t i = 0; char phymask[MPTSAS_MAX_PHYS]; char *iport = NULL; mptsas_phymask_t phy_mask = 0; uint16_t attached_devhdl; ! uint16_t bay_num, enclosure, io_flags; (void) sprintf(wwn_str, "%"PRIx64, smp_node->m_addr.mta_wwn); /* * Probe smp device, prevent the node of removed device from being
*** 14789,14800 **** smp_node->m_pdevhdl = dev_info.m_pdevhdl; page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)dev_info.m_pdevhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, ! &dev_hdl, &sas_wwn, &smp_node->m_pdevinfo, ! &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get " "device info for %x", page_address); ndi_rtn = NDI_FAILURE; --- 16494,16505 ---- smp_node->m_pdevhdl = dev_info.m_pdevhdl; page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)dev_info.m_pdevhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, ! &dev_hdl, &sas_wwn, &smp_node->m_pdevinfo, &physport, ! &phy_id, &pdev_hdl, &bay_num, &enclosure, &io_flags); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get " "device info for %x", page_address); ndi_rtn = NDI_FAILURE;
*** 14804,14814 **** page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)dev_info.m_devhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &smp_sas_wwn, &smp_node->m_deviceinfo, ! &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get " "device info for %x", page_address); ndi_rtn = NDI_FAILURE; --- 16509,16520 ---- page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE & MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)dev_info.m_devhdl; rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl, &smp_sas_wwn, &smp_node->m_deviceinfo, ! &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure, ! &io_flags); if (rval != DDI_SUCCESS) { mutex_exit(&mpt->m_mutex); mptsas_log(mpt, CE_WARN, "mptsas unable to get " "device info for %x", page_address); ndi_rtn = NDI_FAILURE;
*** 14958,14968 **** static int mptsas_smp_start(struct smp_pkt *smp_pkt) { uint64_t wwn; Mpi2SmpPassthroughRequest_t req; Mpi2SmpPassthroughReply_t rep; ! uint32_t direction = 0; mptsas_t *mpt; int ret; uint64_t tmp64; mpt = (mptsas_t *)smp_pkt->smp_pkt_address-> --- 16664,16674 ---- static int mptsas_smp_start(struct smp_pkt *smp_pkt) { uint64_t wwn; Mpi2SmpPassthroughRequest_t req; Mpi2SmpPassthroughReply_t rep; ! uint8_t direction = 0; mptsas_t *mpt; int ret; uint64_t tmp64; mpt = (mptsas_t *)smp_pkt->smp_pkt_address->
*** 15262,15288 **** /* Initialized the tgt structure */ tmp_tgt->m_qfull_retries = QFULL_RETRIES; tmp_tgt->m_qfull_retry_interval = drv_usectohz(QFULL_RETRY_INTERVAL * 1000); tmp_tgt->m_t_throttle = MAX_THROTTLE; refhash_insert(mpt->m_targets, tmp_tgt); return (tmp_tgt); } static mptsas_smp_t * mptsas_smp_alloc(mptsas_t *mpt, mptsas_smp_t *data) { mptsas_target_addr_t addr; mptsas_smp_t *ret_data; addr.mta_wwn = data->m_addr.mta_wwn; addr.mta_phymask = data->m_addr.mta_phymask; ret_data = refhash_lookup(mpt->m_smp_targets, &addr); if (ret_data != NULL) { ! bcopy(data, ret_data, sizeof (mptsas_smp_t)); /* XXX - dupl */ return (ret_data); } ret_data = kmem_alloc(sizeof (mptsas_smp_t), KM_SLEEP); bcopy(data, ret_data, sizeof (mptsas_smp_t)); --- 16968,17011 ---- /* Initialized the tgt structure */ tmp_tgt->m_qfull_retries = QFULL_RETRIES; tmp_tgt->m_qfull_retry_interval = drv_usectohz(QFULL_RETRY_INTERVAL * 1000); tmp_tgt->m_t_throttle = MAX_THROTTLE; + mutex_init(&tmp_tgt->m_t_mutex, NULL, MUTEX_DRIVER, NULL); + TAILQ_INIT(&tmp_tgt->m_active_cmdq); refhash_insert(mpt->m_targets, tmp_tgt); return (tmp_tgt); } + static void + mptsas_smp_target_copy(mptsas_smp_t *src, mptsas_smp_t *dst) + { + dst->m_devhdl = src->m_devhdl; + dst->m_deviceinfo = src->m_deviceinfo; + dst->m_pdevhdl = src->m_pdevhdl; + dst->m_pdevinfo = src->m_pdevinfo; + } + static mptsas_smp_t * mptsas_smp_alloc(mptsas_t *mpt, mptsas_smp_t *data) { mptsas_target_addr_t addr; mptsas_smp_t *ret_data; addr.mta_wwn = data->m_addr.mta_wwn; addr.mta_phymask = data->m_addr.mta_phymask; ret_data = refhash_lookup(mpt->m_smp_targets, &addr); + /* + * If there's already a matching SMP target, update its fields + * in place. Since the address is not changing, it's safe to do + * this. We cannot just bcopy() here because the structure we've + * been given has invalid hash links. + */ if (ret_data != NULL) { ! mptsas_smp_target_copy(data, ret_data); return (ret_data); } ret_data = kmem_alloc(sizeof (mptsas_smp_t), KM_SLEEP); bcopy(data, ret_data, sizeof (mptsas_smp_t));
*** 15442,15469 **** if (cookiep == NULL) cookiep = &new_cookie; if (ddi_dma_alloc_handle(mpt->m_dip, &dma_attr, DDI_DMA_SLEEP, NULL, dma_hdp) != DDI_SUCCESS) { - dma_hdp = NULL; return (FALSE); } if (ddi_dma_mem_alloc(*dma_hdp, alloc_size, &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, dma_memp, &alloc_len, acc_hdp) != DDI_SUCCESS) { ddi_dma_free_handle(dma_hdp); - dma_hdp = NULL; return (FALSE); } if (ddi_dma_addr_bind_handle(*dma_hdp, NULL, *dma_memp, alloc_len, (DDI_DMA_RDWR | DDI_DMA_CONSISTENT), DDI_DMA_SLEEP, NULL, cookiep, &ncookie) != DDI_DMA_MAPPED) { (void) ddi_dma_mem_free(acc_hdp); ddi_dma_free_handle(dma_hdp); - dma_hdp = NULL; return (FALSE); } return (TRUE); } --- 17165,17189 ----
*** 15475,15481 **** return; (void) ddi_dma_unbind_handle(*dma_hdp); (void) ddi_dma_mem_free(acc_hdp); ddi_dma_free_handle(dma_hdp); - dma_hdp = NULL; } --- 17195,17200 ----