diff --git a/sys/dev/smartpqi/smartpqi_helper.c b/sys/dev/smartpqi/smartpqi_helper.c index 68f105001fa0..741ac0a05a06 100644 --- a/sys/dev/smartpqi/smartpqi_helper.c +++ b/sys/dev/smartpqi/smartpqi_helper.c @@ -1,459 +1,447 @@ /*- * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "smartpqi_includes.h" /* * Function used to validate the adapter health. */ boolean_t pqisrc_ctrl_offline(pqisrc_softstate_t *softs) { DBG_FUNC("IN\n"); DBG_FUNC("OUT\n"); return !softs->ctrl_online; } /* Function used set/clear legacy INTx bit in Legacy Interrupt INTx * mask clear pqi register */ void pqisrc_configure_legacy_intx(pqisrc_softstate_t *softs, boolean_t enable_intx) { uint32_t intx_mask; DBG_FUNC("IN\n"); intx_mask = PCI_MEM_GET32(softs, 0, PQI_LEGACY_INTR_MASK_CLR); intx_mask |= PQISRC_LEGACY_INTX_MASK; PCI_MEM_PUT32(softs, 0, PQI_LEGACY_INTR_MASK_CLR ,intx_mask); DBG_FUNC("OUT\n"); } /* * Function used to take exposed devices to OS as offline. */ void pqisrc_take_devices_offline(pqisrc_softstate_t *softs) { pqi_scsi_dev_t *device = NULL; int i; DBG_FUNC("IN\n"); for(i = 0; i < PQI_MAX_DEVICES; i++) { device = softs->dev_list[i]; if(device == NULL) continue; pqisrc_remove_device(softs, device); } DBG_FUNC("OUT\n"); } /* * Function used to take adapter offline. */ void pqisrc_take_ctrl_offline(pqisrc_softstate_t *softs) { DBG_FUNC("IN\n"); int lockupcode = 0; softs->ctrl_online = false; if (SIS_IS_KERNEL_PANIC(softs)) { lockupcode = PCI_MEM_GET32(softs, &softs->ioa_reg->mb[7], LEGACY_SIS_SRCV_OFFSET_MAILBOX_7); DBG_ERR("Controller FW is not running, Lockup code = %x\n", lockupcode); } else { pqisrc_trigger_nmi_sis(softs); } os_complete_outstanding_cmds_nodevice(softs); pqisrc_wait_for_rescan_complete(softs); pqisrc_take_devices_offline(softs); DBG_FUNC("OUT\n"); } /* * Timer handler for the adapter heart-beat. */ void pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *softs) { uint8_t take_offline = false; uint64_t new_heartbeat; static uint32_t running_ping_cnt = 0; DBG_FUNC("IN\n"); new_heartbeat = CTRLR_HEARTBEAT_CNT(softs); DBG_IO("heartbeat old=%lx new=%lx\n", softs->prev_heartbeat_count, new_heartbeat); if (new_heartbeat == softs->prev_heartbeat_count) { take_offline = true; goto take_ctrl_offline; } #if 1 /* print every 30 calls (should print once/minute) */ running_ping_cnt++; if ((running_ping_cnt % 30) == 0) print_all_counters(softs, COUNTER_FLAG_ONLY_NON_ZERO); #endif softs->prev_heartbeat_count = new_heartbeat; take_ctrl_offline: if (take_offline){ DBG_ERR("controller is offline\n"); os_stop_heartbeat_timer(softs); pqisrc_take_ctrl_offline(softs); } DBG_FUNC("OUT\n"); } /* * Conditional variable management routine for internal commands. */ int pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb, uint32_t timeout_in_msec) { DBG_FUNC("IN\n"); int ret = PQI_STATUS_SUCCESS; /* 1 msec = 500 usec * 2 */ uint32_t loop_cnt = timeout_in_msec * 2; uint32_t i = 0; while (rcb->req_pending == true) { OS_SLEEP(500); /* Micro sec */ /* Polling needed for FreeBSD : since ithread routine is not scheduled * during bootup, we could use polling until interrupts are * enabled (using 'if (cold)'to check for the boot time before * interrupts are enabled). */ IS_POLLING_REQUIRED(softs); if ((timeout_in_msec != TIMEOUT_INFINITE) && (i++ == loop_cnt)) { DBG_ERR("ERR: Requested cmd timed out !!!\n"); ret = PQI_STATUS_TIMEOUT; rcb->timedout = true; break; } if (pqisrc_ctrl_offline(softs)) { DBG_ERR("Controller is Offline"); ret = PQI_STATUS_FAILURE; break; } } rcb->req_pending = true; DBG_FUNC("OUT\n"); return ret; } /* Function used to validate the device wwid. */ boolean_t pqisrc_device_equal(pqi_scsi_dev_t *dev1, pqi_scsi_dev_t *dev2) { return dev1->wwid == dev2->wwid; } /* Function used to validate the device scsi3addr. */ boolean_t pqisrc_scsi3addr_equal(uint8_t *scsi3addr1, uint8_t *scsi3addr2) { return memcmp(scsi3addr1, scsi3addr2, 8) == 0; } /* Function used to validate hba_lunid */ boolean_t pqisrc_is_hba_lunid(uint8_t *scsi3addr) { return pqisrc_scsi3addr_equal(scsi3addr, RAID_CTLR_LUNID); } /* Function used to validate type of device */ boolean_t pqisrc_is_logical_device(pqi_scsi_dev_t *device) { return !device->is_physical_device; } /* Function used to sanitize inquiry string */ void pqisrc_sanitize_inquiry_string(unsigned char *s, int len) { boolean_t terminated = false; DBG_FUNC("IN\n"); for (; len > 0; (--len, ++s)) { if (*s == 0) terminated = true; if (terminated || *s < 0x20 || *s > 0x7e) *s = ' '; } DBG_FUNC("OUT\n"); } static char *raid_levels[] = { "RAID 0", "RAID 4", "RAID 1(1+0)", "RAID 5", "RAID 5+1", "RAID 6", "RAID 1(Triple)", }; /* Get the RAID level from the index */ char * pqisrc_raidlevel_to_string(uint8_t raid_level) { DBG_FUNC("IN\n"); if (raid_level < ARRAY_SIZE(raid_levels)) return raid_levels[raid_level]; DBG_FUNC("OUT\n"); return " "; } /* Debug routine for displaying device info */ void pqisrc_display_device_info(pqisrc_softstate_t *softs, char *action, pqi_scsi_dev_t *device) { if (device->is_physical_device) { DBG_NOTE("%s scsi BTL %d:%d:%d: %.8s %.16s %-12s " "SSDSmartPathCap%c En%c Exp%c qd=%d\n", action, device->bus, device->target, device->lun, device->vendor, device->model, "Physical", device->offload_config ? '+' : '-', device->offload_enabled_pending ? '+' : '-', device->expose_device ? '+' : '-', device->queue_depth); } else if (device->devtype == RAID_DEVICE) { DBG_NOTE("%s scsi BTL %d:%d:%d: %.8s %.16s %-12s " "SSDSmartPathCap%c En%c Exp%c qd=%d\n", action, device->bus, device->target, device->lun, device->vendor, device->model, "Controller", device->offload_config ? '+' : '-', device->offload_enabled_pending ? '+' : '-', device->expose_device ? '+' : '-', device->queue_depth); } else if (device->devtype == CONTROLLER_DEVICE) { DBG_NOTE("%s scsi BTL %d:%d:%d: %.8s %.16s %-12s " "SSDSmartPathCap%c En%c Exp%c qd=%d\n", action, device->bus, device->target, device->lun, device->vendor, device->model, "External", device->offload_config ? '+' : '-', device->offload_enabled_pending ? '+' : '-', device->expose_device ? '+' : '-', device->queue_depth); } else { DBG_NOTE("%s scsi BTL %d:%d:%d: %.8s %.16s %-12s " "SSDSmartPathCap%c En%c Exp%c qd=%d devtype=%d\n", action, device->bus, device->target, device->lun, device->vendor, device->model, pqisrc_raidlevel_to_string(device->raid_level), device->offload_config ? '+' : '-', device->offload_enabled_pending ? '+' : '-', device->expose_device ? '+' : '-', device->queue_depth, device->devtype); pqisrc_raidlevel_to_string(device->raid_level); /* To use this function */ } } /* validate the structure sizes */ void check_struct_sizes(void) { ASSERT(sizeof(SCSI3Addr_struct)== 2); ASSERT(sizeof(PhysDevAddr_struct) == 8); ASSERT(sizeof(LogDevAddr_struct)== 8); ASSERT(sizeof(LUNAddr_struct)==8); ASSERT(sizeof(RequestBlock_struct) == 20); ASSERT(sizeof(MoreErrInfo_struct)== 8); ASSERT(sizeof(ErrorInfo_struct)== 48); /* Checking the size of IOCTL_Command_struct for both 64 bit and 32 bit system*/ ASSERT(sizeof(IOCTL_Command_struct)== 86 || sizeof(IOCTL_Command_struct)== 82); ASSERT(sizeof(struct bmic_host_wellness_driver_version)== 42); ASSERT(sizeof(struct bmic_host_wellness_time)== 20); ASSERT(sizeof(struct pqi_dev_adminq_cap)== 8); ASSERT(sizeof(struct admin_q_param)== 4); ASSERT(sizeof(struct pqi_registers)== 256); ASSERT(sizeof(struct ioa_registers)== 4128); ASSERT(sizeof(struct pqi_pref_settings)==4); ASSERT(sizeof(struct pqi_cap)== 20); ASSERT(sizeof(iu_header_t)== 4); ASSERT(sizeof(gen_adm_req_iu_t)== 64); ASSERT(sizeof(gen_adm_resp_iu_t)== 64); ASSERT(sizeof(op_q_params) == 9); ASSERT(sizeof(raid_path_error_info_elem_t)== 276); ASSERT(sizeof(aio_path_error_info_elem_t)== 276); ASSERT(sizeof(struct init_base_struct)== 24); ASSERT(sizeof(pqi_iu_layer_desc_t)== 16); ASSERT(sizeof(pqi_dev_cap_t)== 576); ASSERT(sizeof(pqi_aio_req_t)== 128); ASSERT(sizeof(pqisrc_raid_req_t)== 128); ASSERT(sizeof(pqi_raid_tmf_req_t)== 32); ASSERT(sizeof(pqi_aio_tmf_req_t)== 32); ASSERT(sizeof(struct pqi_io_response)== 16); ASSERT(sizeof(struct sense_header_scsi)== 8); ASSERT(sizeof(reportlun_header_t)==8); ASSERT(sizeof(reportlun_ext_entry_t)== 24); ASSERT(sizeof(reportlun_data_ext_t)== 32); ASSERT(sizeof(raidmap_data_t)==8); ASSERT(sizeof(pqisrc_raid_map_t)== 8256); ASSERT(sizeof(bmic_ident_ctrl_t)== 325); ASSERT(sizeof(bmic_ident_physdev_t)==2048); } #if 0 uint32_t pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { uint32_t i, active_io = 0; rcb_t* rcb; for(i = 1; i <= softs->max_outstanding_io; i++) { rcb = &softs->rcb[i]; if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) { active_io++; } } return active_io; } void check_device_pending_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { uint32_t tag = softs->max_outstanding_io, active_requests; uint64_t timeout = 0, delay_in_usec = 1000; /* In micro Seconds */ rcb_t* rcb; DBG_FUNC("IN\n"); active_requests = pqisrc_count_num_scsi_active_requests_on_dev(softs, device); DBG_WARN("Device Outstanding IO count = %u\n", active_requests); if(!active_requests) return; do { rcb = &softs->rcb[tag]; if(rcb && IS_OS_SCSICMD(rcb) && (rcb->dvp == device) && rcb->req_pending) { OS_SLEEP(delay_in_usec); timeout += delay_in_usec; } else tag--; if(timeout >= PQISRC_PENDING_IO_TIMEOUT_USEC) { DBG_WARN("timed out waiting for pending IO\n"); return; } } while(tag); } #endif -extern inline uint64_t -pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); - -extern inline uint64_t -pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); - -extern inline void -pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); - -extern inline uint64_t -pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); - void pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { uint64_t timeout_in_usec = 0, delay_in_usec = 1000; /* In microseconds */ DBG_FUNC("IN\n"); if(!softs->ctrl_online) return; #if PQISRC_DEVICE_IO_COUNTER DBG_WARN_BTL(device,"Device Outstanding IO count = %lu\n", pqisrc_read_device_active_io(softs, device)); while(pqisrc_read_device_active_io(softs, device)) { OS_BUSYWAIT(delay_in_usec); /* In microseconds */ if(!softs->ctrl_online) { DBG_WARN("Controller Offline was detected.\n"); } timeout_in_usec += delay_in_usec; if(timeout_in_usec >= PQISRC_PENDING_IO_TIMEOUT_USEC) { DBG_WARN_BTL(device,"timed out waiting for pending IO. DeviceOutStandingIo's=%lu\n", pqisrc_read_device_active_io(softs, device)); return; } } #else check_device_pending_commands_to_complete(softs, device); #endif } diff --git a/sys/dev/smartpqi/smartpqi_helper.h b/sys/dev/smartpqi/smartpqi_helper.h index cc7030de74ad..507caeb9b0b6 100644 --- a/sys/dev/smartpqi/smartpqi_helper.h +++ b/sys/dev/smartpqi/smartpqi_helper.h @@ -1,66 +1,66 @@ /*- * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _PQI_HELPER_H #define _PQI_HELPER_H -inline uint64_t +static inline uint64_t pqisrc_increment_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { #if PQISRC_DEVICE_IO_COUNTER /*Increment device active io count by one*/ return OS_ATOMIC64_INC(&device->active_requests); #endif } -inline uint64_t +static inline uint64_t pqisrc_decrement_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { #if PQISRC_DEVICE_IO_COUNTER /*Decrement device active io count by one*/ return OS_ATOMIC64_DEC(&device->active_requests); #endif } -inline void +static inline void pqisrc_init_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { #if PQISRC_DEVICE_IO_COUNTER /* Reset device count to Zero */ OS_ATOMIC64_INIT(&device->active_requests, 0); #endif } -inline uint64_t +static inline uint64_t pqisrc_read_device_active_io(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { #if PQISRC_DEVICE_IO_COUNTER /* read device active count*/ return OS_ATOMIC64_READ(&device->active_requests); #endif } #endif /* _PQI_HELPER_H */ diff --git a/sys/dev/smartpqi/smartpqi_prototypes.h b/sys/dev/smartpqi/smartpqi_prototypes.h index 8eabe5c47cf4..a10e5031d85e 100644 --- a/sys/dev/smartpqi/smartpqi_prototypes.h +++ b/sys/dev/smartpqi/smartpqi_prototypes.h @@ -1,331 +1,327 @@ /*- * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _PQI_PROTOTYPES_H #define _PQI_PROTOTYPES_H /* Function prototypes */ /*smartpqi_init.c */ int pqisrc_init(pqisrc_softstate_t *); void pqisrc_uninit(pqisrc_softstate_t *); void pqisrc_pqi_uninit(pqisrc_softstate_t *); int pqisrc_process_config_table(pqisrc_softstate_t *); int pqisrc_flush_cache(pqisrc_softstate_t *, enum pqisrc_flush_cache_event_type); int pqisrc_wait_for_pqi_reset_completion(pqisrc_softstate_t *); int pqisrc_wait_for_cmnd_complete(pqisrc_softstate_t *); void pqisrc_complete_internal_cmds(pqisrc_softstate_t *); void sanity_check_os_behavior(pqisrc_softstate_t *); /* smartpqi_sis.c*/ int pqisrc_sis_init(pqisrc_softstate_t *); void pqisrc_sis_uninit(pqisrc_softstate_t *); int pqisrc_reenable_sis(pqisrc_softstate_t *); void pqisrc_trigger_nmi_sis(pqisrc_softstate_t *); void sis_disable_msix(pqisrc_softstate_t *); void sis_enable_intx(pqisrc_softstate_t *); void sis_disable_intx(pqisrc_softstate_t *softs); int pqisrc_force_sis(pqisrc_softstate_t *); int pqisrc_sis_wait_for_db_bit_to_clear(pqisrc_softstate_t *, uint32_t); void sis_disable_interrupt(pqisrc_softstate_t*); /* smartpqi_queue.c */ int pqisrc_submit_admin_req(pqisrc_softstate_t *, gen_adm_req_iu_t *, gen_adm_resp_iu_t *); int pqisrc_create_admin_queue(pqisrc_softstate_t *); int pqisrc_destroy_admin_queue(pqisrc_softstate_t *); int pqisrc_create_op_queues(pqisrc_softstate_t *); int pqisrc_allocate_and_init_inbound_q(pqisrc_softstate_t *, ib_queue_t *, char *); int pqisrc_allocate_and_init_outbound_q(pqisrc_softstate_t *, ob_queue_t *, char *); /* smartpqi_cmd.c */ int pqisrc_submit_cmnd(pqisrc_softstate_t *,ib_queue_t *,void *); /* smartpqi_tag.c */ #ifndef LOCKFREE_STACK int pqisrc_init_taglist(pqisrc_softstate_t *,pqi_taglist_t *,uint32_t); void pqisrc_destroy_taglist(pqisrc_softstate_t *,pqi_taglist_t *); void pqisrc_put_tag(pqi_taglist_t *,uint32_t); uint32_t pqisrc_get_tag(pqi_taglist_t *); #else int pqisrc_init_taglist(pqisrc_softstate_t *, lockless_stack_t *, uint32_t); void pqisrc_destroy_taglist(pqisrc_softstate_t *, lockless_stack_t *); void pqisrc_put_tag(lockless_stack_t *,uint32_t); uint32_t pqisrc_get_tag(lockless_stack_t *); #endif /* LOCKFREE_STACK */ /* smartpqi_discovery.c */ void pqisrc_remove_device(pqisrc_softstate_t *, pqi_scsi_dev_t *); boolean_t pqisrc_add_softs_entry(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device, uint8_t *scsi3addr); int pqisrc_get_ctrl_fw_version(pqisrc_softstate_t *); int pqisrc_rescan_devices(pqisrc_softstate_t *); int pqisrc_scan_devices(pqisrc_softstate_t *); void pqisrc_cleanup_devices(pqisrc_softstate_t *); void pqisrc_device_mem_free(pqisrc_softstate_t *, pqi_scsi_dev_t *); boolean_t pqisrc_is_external_raid_device(pqi_scsi_dev_t *device); void pqisrc_free_device(pqisrc_softstate_t * softs,pqi_scsi_dev_t *device); void pqisrc_init_bitmap(pqisrc_softstate_t *softs); void pqisrc_remove_target_bit(pqisrc_softstate_t *softs, int target); int pqisrc_find_avail_target(pqisrc_softstate_t *softs); int pqisrc_find_device_list_index(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); int pqisrc_find_btl_list_index(pqisrc_softstate_t *softs, int bus, int target, int lun); int pqisrc_delete_softs_entry(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device); int pqisrc_get_physical_logical_luns(pqisrc_softstate_t *softs, uint8_t cmd, reportlun_data_ext_t **buff, size_t *data_length); int pqisrc_send_scsi_inquiry(pqisrc_softstate_t *softs, uint8_t *scsi3addr, uint16_t vpd_page, uint8_t *buff, int buf_len); int pqisrc_simple_dma_alloc(pqisrc_softstate_t *, struct dma_mem *, size_t, sgt_t *); int pqisrc_prepare_send_raid(pqisrc_softstate_t *, pqisrc_raid_req_t *, void *, size_t , uint8_t *, raid_path_error_info_elem_t *); /* smartpqi_helper.c */ boolean_t pqisrc_ctrl_offline(pqisrc_softstate_t *); void pqisrc_heartbeat_timer_handler(pqisrc_softstate_t *); int pqisrc_wait_on_condition(pqisrc_softstate_t *softs, rcb_t *rcb, uint32_t timeout); boolean_t pqisrc_device_equal(pqi_scsi_dev_t *, pqi_scsi_dev_t *); boolean_t pqisrc_is_hba_lunid(uint8_t *); boolean_t pqisrc_is_logical_device(pqi_scsi_dev_t *); void pqisrc_sanitize_inquiry_string(unsigned char *, int ); void pqisrc_display_device_info(pqisrc_softstate_t *, char *, pqi_scsi_dev_t *); boolean_t pqisrc_scsi3addr_equal(uint8_t *, uint8_t *); void check_struct_sizes(void); char *pqisrc_raidlevel_to_string(uint8_t); void pqisrc_configure_legacy_intx(pqisrc_softstate_t*, boolean_t); void pqisrc_ctrl_diagnostic_options(pqisrc_softstate_t *); void pqisrc_wait_for_device_commands_to_complete(pqisrc_softstate_t *, pqi_scsi_dev_t *); int pqisrc_QuerySenseFeatures(pqisrc_softstate_t *); void check_device_pending_commands_to_complete(pqisrc_softstate_t *, pqi_scsi_dev_t *); uint32_t pqisrc_count_num_scsi_active_requests_on_dev(pqisrc_softstate_t *, pqi_scsi_dev_t *); /* smartpqi_response.c */ void pqisrc_process_internal_raid_response_success(pqisrc_softstate_t *, rcb_t *); void pqisrc_process_internal_raid_response_error(pqisrc_softstate_t *, rcb_t *, uint16_t); void pqisrc_process_io_response_success(pqisrc_softstate_t *, rcb_t *); void pqisrc_show_sense_data_full(pqisrc_softstate_t *, rcb_t *, sense_data_u_t *sense_data); void pqisrc_process_aio_response_error(pqisrc_softstate_t *, rcb_t *, uint16_t); void pqisrc_process_raid_response_error(pqisrc_softstate_t *, rcb_t *, uint16_t); void pqisrc_process_response_queue(pqisrc_softstate_t *, int); void pqisrc_show_aio_error_info(pqisrc_softstate_t *softs, rcb_t *rcb, aio_path_error_info_elem_t *aio_err); void pqisrc_show_raid_error_info(pqisrc_softstate_t *softs, rcb_t *rcb, raid_path_error_info_elem_t *aio_err); boolean_t suppress_innocuous_error_prints(pqisrc_softstate_t *softs, rcb_t *rcb); uint8_t pqisrc_get_cmd_from_rcb(rcb_t *); boolean_t pqisrc_is_innocuous_error(pqisrc_softstate_t *, rcb_t *, void *); /* smartpqi_request.c */ int pqisrc_build_send_vendor_request(pqisrc_softstate_t *softs, struct pqi_vendor_general_request *request); int pqisrc_build_send_io(pqisrc_softstate_t *,rcb_t *); int pqisrc_build_scsi_cmd_raidbypass(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device, rcb_t *rcb); int pqisrc_send_tmf(pqisrc_softstate_t *, pqi_scsi_dev_t *, rcb_t *, rcb_t *, int); int pqisrc_write_current_time_to_host_wellness(pqisrc_softstate_t *softs); int pqisrc_write_driver_version_to_host_wellness(pqisrc_softstate_t *softs); -extern inline void pqisrc_aio_build_cdb(aio_req_locator_t *, uint32_t, - rcb_t *, uint8_t *); -extern inline boolean_t pqisrc_aio_req_too_big(pqisrc_softstate_t *, pqi_scsi_dev_t *, - rcb_t *, aio_req_locator_t *, uint32_t); void pqisrc_build_aio_common(pqisrc_softstate_t *, pqi_aio_req_t *, rcb_t *, uint32_t); void pqisrc_build_aio_R1_write(pqisrc_softstate_t *, pqi_aio_raid1_write_req_t *, rcb_t *, uint32_t); void pqisrc_build_aio_R5or6_write(pqisrc_softstate_t *, pqi_aio_raid5or6_write_req_t *, rcb_t *, uint32_t); void pqisrc_show_cdb(pqisrc_softstate_t *softs, char *msg, rcb_t *rcb, uint8_t *cdb); void pqisrc_print_buffer(pqisrc_softstate_t *softs, char *msg, void *user_buf, uint32_t total_len, uint32_t flags); void pqisrc_show_rcb_details(pqisrc_softstate_t *softs, rcb_t *rcb, char *msg, void *err_info); void pqisrc_show_aio_io(pqisrc_softstate_t *, rcb_t *, pqi_aio_req_t *, uint32_t); void pqisrc_show_aio_common(pqisrc_softstate_t *, rcb_t *, pqi_aio_req_t *); void pqisrc_show_aio_R1_write(pqisrc_softstate_t *, rcb_t *, pqi_aio_raid1_write_req_t *); void pqisrc_show_aio_R5or6_write(pqisrc_softstate_t *, rcb_t *, pqi_aio_raid5or6_write_req_t *); boolean_t pqisrc_cdb_is_write(uint8_t *); void print_this_counter(pqisrc_softstate_t *softs, io_counters_t *pcounter, char *msg); void print_all_counters(pqisrc_softstate_t *softs, uint32_t flags); char *io_path_to_ascii(IO_PATH_T path); void int_to_scsilun(uint64_t, uint8_t *); boolean_t pqisrc_cdb_is_read(uint8_t *); void pqisrc_build_aio_io(pqisrc_softstate_t *, rcb_t *, pqi_aio_req_t *, uint32_t); uint8_t pqisrc_get_aio_data_direction(rcb_t *); uint8_t pqisrc_get_raid_data_direction(rcb_t *); void dump_tmf_details(pqisrc_softstate_t *, rcb_t *, char *); io_type_t get_io_type_from_cdb(uint8_t *); OS_ATOMIC64_T increment_this_counter(io_counters_t *, IO_PATH_T , io_type_t ); boolean_t is_buffer_zero(void *, uint32_t ); /* smartpqi_event.c*/ int pqisrc_report_event_config(pqisrc_softstate_t *); int pqisrc_set_event_config(pqisrc_softstate_t *); int pqisrc_process_event_intr_src(pqisrc_softstate_t *,int); void pqisrc_ack_all_events(void *arg); void pqisrc_wait_for_rescan_complete(pqisrc_softstate_t *softs); int pqisrc_prepare_send_ctrlr_request(pqisrc_softstate_t *softs, pqisrc_raid_req_t *request, void *buff, size_t datasize); int pqisrc_submit_management_req(pqisrc_softstate_t *, pqi_event_config_request_t *); void pqisrc_take_devices_offline(pqisrc_softstate_t *); void pqisrc_take_ctrl_offline(pqisrc_softstate_t *); void pqisrc_free_rcb(pqisrc_softstate_t *, int); void pqisrc_decide_opq_config(pqisrc_softstate_t *); int pqisrc_configure_op_queues(pqisrc_softstate_t *); int pqisrc_pqi_init(pqisrc_softstate_t *); int pqi_reset(pqisrc_softstate_t *); int pqisrc_check_pqimode(pqisrc_softstate_t *); int pqisrc_check_fw_status(pqisrc_softstate_t *); int pqisrc_init_struct_base(pqisrc_softstate_t *); int pqisrc_get_sis_pqi_cap(pqisrc_softstate_t *); int pqisrc_get_preferred_settings(pqisrc_softstate_t *); int pqisrc_get_adapter_properties(pqisrc_softstate_t *, uint32_t *, uint32_t *); void pqisrc_get_admin_queue_config(pqisrc_softstate_t *); void pqisrc_decide_admin_queue_config(pqisrc_softstate_t *); int pqisrc_allocate_and_init_adminq(pqisrc_softstate_t *); int pqisrc_create_delete_adminq(pqisrc_softstate_t *, uint32_t); void pqisrc_print_adminq_config(pqisrc_softstate_t *); int pqisrc_delete_op_queue(pqisrc_softstate_t *, uint32_t, boolean_t); void pqisrc_destroy_event_queue(pqisrc_softstate_t *); void pqisrc_destroy_op_ib_queues(pqisrc_softstate_t *); void pqisrc_destroy_op_ob_queues(pqisrc_softstate_t *); int pqisrc_change_op_ibq_queue_prop(pqisrc_softstate_t *, ib_queue_t *, uint32_t); int pqisrc_create_op_obq(pqisrc_softstate_t *, ob_queue_t *); int pqisrc_create_op_ibq(pqisrc_softstate_t *, ib_queue_t *); int pqisrc_create_op_aio_ibq(pqisrc_softstate_t *, ib_queue_t *); int pqisrc_create_op_raid_ibq(pqisrc_softstate_t *, ib_queue_t *); int pqisrc_alloc_and_create_event_queue(pqisrc_softstate_t *); int pqisrc_alloc_and_create_ib_queues(pqisrc_softstate_t *); int pqisrc_alloc_and_create_ib_queues(pqisrc_softstate_t *); int pqisrc_alloc_and_create_ob_queues(pqisrc_softstate_t *); int pqisrc_process_task_management_response(pqisrc_softstate_t *, pqi_tmf_resp_t *); /* smartpqi_ioctl.c*/ int pqisrc_passthru_ioctl(struct pqisrc_softstate *, void *, int); /* Functions Prototypes */ /* smartpqi_mem.c */ int os_dma_mem_alloc(pqisrc_softstate_t *,struct dma_mem *); void os_dma_mem_free(pqisrc_softstate_t *,struct dma_mem *); void *os_mem_alloc(pqisrc_softstate_t *,size_t); void os_mem_free(pqisrc_softstate_t *,void *,size_t); void os_resource_free(pqisrc_softstate_t *); int os_dma_setup(pqisrc_softstate_t *); int os_dma_destroy(pqisrc_softstate_t *); void os_update_dma_attributes(pqisrc_softstate_t *); /* smartpqi_intr.c */ int os_get_intr_config(pqisrc_softstate_t *); int os_setup_intr(pqisrc_softstate_t *); int os_destroy_intr(pqisrc_softstate_t *); int os_get_processor_config(pqisrc_softstate_t *); void os_free_intr_config(pqisrc_softstate_t *); /* smartpqi_ioctl.c */ int os_copy_to_user(struct pqisrc_softstate *, void *, void *, int, int); int os_copy_from_user(struct pqisrc_softstate *, void *, void *, int, int); int create_char_dev(struct pqisrc_softstate *, int); void destroy_char_dev(struct pqisrc_softstate *); /* smartpqi_misc.c*/ int os_init_spinlock(struct pqisrc_softstate *, struct mtx *, char *); void os_uninit_spinlock(struct mtx *); int os_create_semaphore(const char *, int,struct sema *); int os_destroy_semaphore(struct sema *); void os_sema_lock(struct sema *); void os_sema_unlock(struct sema *); void bsd_set_hint_adapter_cap(struct pqisrc_softstate *); void bsd_set_hint_adapter_cpu_config(struct pqisrc_softstate *); int os_strlcpy(char *dst, char *src, int len); void os_complete_outstanding_cmds_nodevice(pqisrc_softstate_t *); void os_stop_heartbeat_timer(pqisrc_softstate_t *); void os_start_heartbeat_timer(void *); /* smartpqi_cam.c */ uint8_t os_get_task_attr(rcb_t *); void smartpqi_target_rescan(struct pqisrc_softstate *); void os_rescan_target(struct pqisrc_softstate *, pqi_scsi_dev_t *); /* smartpqi_intr.c smartpqi_main.c */ void pqisrc_event_worker(void *, int); void os_add_device(pqisrc_softstate_t *, pqi_scsi_dev_t *); void os_remove_device(pqisrc_softstate_t *, pqi_scsi_dev_t *); void os_io_response_success(rcb_t *); void os_aio_response_error(rcb_t *, aio_path_error_info_elem_t *); boolean_t check_device_hint_status(struct pqisrc_softstate *, unsigned int ); void smartpqi_adjust_queue_depth(struct cam_path *, uint32_t ); void os_raid_response_error(rcb_t *, raid_path_error_info_elem_t *); void os_wellness_periodic(void *); void os_reset_rcb( rcb_t *); int register_sim(struct pqisrc_softstate *, int); void deregister_sim(struct pqisrc_softstate *); int check_for_scsi_opcode(uint8_t *, boolean_t *, uint64_t *, uint32_t *); int register_legacy_intr(pqisrc_softstate_t *); int register_msix_intr(pqisrc_softstate_t *); void deregister_pqi_intx(pqisrc_softstate_t *); void deregister_pqi_msix(pqisrc_softstate_t *); void os_get_time(struct bmic_host_wellness_time *); void os_eventtaskqueue_enqueue(pqisrc_softstate_t *); void pqisrc_save_controller_info(struct pqisrc_softstate *); /* Domain status conversion */ int bsd_status_to_pqi_status(int ); #endif diff --git a/sys/dev/smartpqi/smartpqi_request.c b/sys/dev/smartpqi/smartpqi_request.c index 246ab891126d..1c0bbc2a1db5 100644 --- a/sys/dev/smartpqi/smartpqi_request.c +++ b/sys/dev/smartpqi/smartpqi_request.c @@ -1,2324 +1,2324 @@ /*- * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "smartpqi_includes.h" /* Change this if need to debug why AIO is not being used */ #define DBG_AIO DBG_IO #define SG_FLAG_LAST 0x40000000 #define SG_FLAG_CHAIN 0x80000000 /* Local Prototypes */ static void pqisrc_increment_io_counters(pqisrc_softstate_t *softs, rcb_t *rcb); static int fill_lba_for_scsi_rw(pqisrc_softstate_t *softs, uint8_t *cdb, aio_req_locator_t *l); /* Subroutine to find out embedded sgl count in IU */ static inline uint32_t pqisrc_embedded_sgl_count(uint32_t elem_alloted, uint8_t iu_type) { uint32_t embedded_sgl_count = MAX_EMBEDDED_SG_IN_FIRST_IU_DEFAULT; DBG_FUNC("IN\n"); if (iu_type == PQI_IU_TYPE_RAID5_WRITE_BYPASS_REQUEST || iu_type == PQI_IU_TYPE_RAID6_WRITE_BYPASS_REQUEST) embedded_sgl_count = MAX_EMBEDDED_SG_IN_FIRST_IU_RAID56_AIO; /** calculate embedded sgl count using num_elem_alloted for IO **/ if(elem_alloted - 1) embedded_sgl_count += ((elem_alloted - 1) * MAX_EMBEDDED_SG_IN_IU); /* DBG_IO("embedded_sgl_count :%d\n", embedded_sgl_count); */ DBG_FUNC("OUT\n"); return embedded_sgl_count; } /* Subroutine to find out contiguous free elem in IU */ static inline uint32_t pqisrc_contiguous_free_elem(uint32_t pi, uint32_t ci, uint32_t elem_in_q) { uint32_t contiguous_free_elem = 0; DBG_FUNC("IN\n"); if(pi >= ci) { contiguous_free_elem = (elem_in_q - pi); if(ci == 0) contiguous_free_elem -= 1; } else { contiguous_free_elem = (ci - pi - 1); } DBG_FUNC("OUT\n"); return contiguous_free_elem; } /* Subroutine to find out num of elements need for the request */ static uint32_t pqisrc_num_elem_needed(pqisrc_softstate_t *softs, uint32_t SG_Count, pqi_scsi_dev_t *devp, boolean_t is_write, IO_PATH_T io_path) { uint32_t num_sg; uint32_t num_elem_required = 1; uint32_t sg_in_first_iu = MAX_EMBEDDED_SG_IN_FIRST_IU_DEFAULT; DBG_FUNC("IN\n"); DBG_IO("SGL_Count :%u\n",SG_Count); if ((devp->raid_level == SA_RAID_5 || devp->raid_level == SA_RAID_6) && is_write && (io_path == AIO_PATH)) sg_in_first_iu = MAX_EMBEDDED_SG_IN_FIRST_IU_RAID56_AIO; /******** If SG_Count greater than max sg per IU i.e 4 or 68 (4 is with out spanning or 68 is with spanning) chaining is required. OR, If SG_Count <= MAX_EMBEDDED_SG_IN_FIRST_IU_* then, on these two cases one element is enough. ********/ if(SG_Count > softs->max_sg_per_spanning_cmd || SG_Count <= sg_in_first_iu) return num_elem_required; /* SGL Count Other Than First IU */ num_sg = SG_Count - sg_in_first_iu; num_elem_required += PQISRC_DIV_ROUND_UP(num_sg, MAX_EMBEDDED_SG_IN_IU); DBG_FUNC("OUT\n"); return num_elem_required; } /* Subroutine to build SG list for the IU submission*/ static boolean_t pqisrc_build_sgl(sgt_t *sg_array, rcb_t *rcb, iu_header_t *iu_hdr, uint32_t num_elem_alloted) { uint32_t i; uint32_t num_sg = OS_GET_IO_SG_COUNT(rcb); sgt_t *sgt = sg_array; sgt_t *sg_chain = NULL; boolean_t partial = false; DBG_FUNC("IN\n"); /* DBG_IO("SGL_Count :%d",num_sg); */ if (0 == num_sg) { goto out; } if (num_sg <= pqisrc_embedded_sgl_count(num_elem_alloted, iu_hdr->iu_type)) { for (i = 0; i < num_sg; i++, sgt++) { sgt->addr= OS_GET_IO_SG_ADDR(rcb,i); sgt->len= OS_GET_IO_SG_LEN(rcb,i); sgt->flags= 0; } sg_array[num_sg - 1].flags = SG_FLAG_LAST; } else { /** SGL Chaining **/ sg_chain = rcb->sg_chain_virt; sgt->addr = rcb->sg_chain_dma; sgt->len = num_sg * sizeof(sgt_t); sgt->flags = SG_FLAG_CHAIN; sgt = sg_chain; for (i = 0; i < num_sg; i++, sgt++) { sgt->addr = OS_GET_IO_SG_ADDR(rcb,i); sgt->len = OS_GET_IO_SG_LEN(rcb,i); sgt->flags = 0; } sg_chain[num_sg - 1].flags = SG_FLAG_LAST; num_sg = 1; partial = true; } out: iu_hdr->iu_length = num_sg * sizeof(sgt_t); DBG_FUNC("OUT\n"); return partial; } #if 0 static inline void pqisrc_show_raid_req(pqisrc_softstate_t *softs, pqisrc_raid_req_t *raid_req) { DBG_IO("%30s: 0x%x\n", "raid_req->header.iu_type", raid_req->header.iu_type); DBG_IO("%30s: 0x%d\n", "raid_req->response_queue_id", raid_req->response_queue_id); DBG_IO("%30s: 0x%x\n", "raid_req->request_id", raid_req->request_id); DBG_IO("%30s: 0x%x\n", "raid_req->buffer_length", raid_req->buffer_length); DBG_IO("%30s: 0x%x\n", "raid_req->task_attribute", raid_req->task_attribute); DBG_IO("%30s: 0x%llx\n", "raid_req->lun_number", *((long long unsigned int*)raid_req->lun_number)); DBG_IO("%30s: 0x%x\n", "raid_req->error_index", raid_req->error_index); DBG_IO("%30s: 0x%p\n", "raid_req->sg_descriptors[0].addr", (void *)raid_req->sg_descriptors[0].addr); DBG_IO("%30s: 0x%x\n", "raid_req->sg_descriptors[0].len", raid_req->sg_descriptors[0].len); DBG_IO("%30s: 0x%x\n", "raid_req->sg_descriptors[0].flags", raid_req->sg_descriptors[0].flags); } #endif /*Subroutine used to Build the RAID request */ static void pqisrc_build_raid_io(pqisrc_softstate_t *softs, rcb_t *rcb, pqisrc_raid_req_t *raid_req, uint32_t num_elem_alloted) { DBG_FUNC("IN\n"); raid_req->header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST; raid_req->header.comp_feature = 0; raid_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb); raid_req->work_area[0] = 0; raid_req->work_area[1] = 0; raid_req->request_id = rcb->tag; raid_req->nexus_id = 0; raid_req->buffer_length = GET_SCSI_BUFFLEN(rcb); memcpy(raid_req->lun_number, rcb->dvp->scsi3addr, sizeof(raid_req->lun_number)); raid_req->protocol_spec = 0; raid_req->data_direction = rcb->data_dir; raid_req->reserved1 = 0; raid_req->fence = 0; raid_req->error_index = raid_req->request_id; raid_req->reserved2 = 0; raid_req->task_attribute = OS_GET_TASK_ATTR(rcb); raid_req->command_priority = 0; raid_req->reserved3 = 0; raid_req->reserved4 = 0; raid_req->reserved5 = 0; raid_req->ml_device_lun_number = (uint8_t)rcb->cm_ccb->ccb_h.target_lun; /* As cdb and additional_cdb_bytes are contiguous, update them in a single statement */ memcpy(raid_req->cmd.cdb, rcb->cdbp, rcb->cmdlen); #if 0 DBG_IO("CDB :"); for(i = 0; i < rcb->cmdlen ; i++) DBG_IO(" 0x%x \n ",raid_req->cdb[i]); #endif switch (rcb->cmdlen) { case 6: case 10: case 12: case 16: raid_req->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0; break; case 20: raid_req->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_4; break; case 24: raid_req->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_8; break; case 28: raid_req->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_12; break; case 32: default: /* todo:review again */ raid_req->additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_16; break; } /* Frame SGL Descriptor */ raid_req->partial = pqisrc_build_sgl(&raid_req->sg_descriptors[0], rcb, &raid_req->header, num_elem_alloted); raid_req->header.iu_length += offsetof(pqisrc_raid_req_t, sg_descriptors) - sizeof(iu_header_t); #if 0 pqisrc_show_raid_req(softs, raid_req); #endif rcb->success_cmp_callback = pqisrc_process_io_response_success; rcb->error_cmp_callback = pqisrc_process_raid_response_error; rcb->resp_qid = raid_req->response_queue_id; DBG_FUNC("OUT\n"); } /* We will need to expand this to handle different types of * aio request structures. */ #if 0 static inline void pqisrc_show_aio_req(pqisrc_softstate_t *softs, pqi_aio_req_t *aio_req) { DBG_IO("%30s: 0x%x\n", "aio_req->header.iu_type", aio_req->header.iu_type); DBG_IO("%30s: 0x%x\n", "aio_req->resp_qid", aio_req->response_queue_id); DBG_IO("%30s: 0x%x\n", "aio_req->req_id", aio_req->req_id); DBG_IO("%30s: 0x%x\n", "aio_req->nexus", aio_req->nexus); DBG_IO("%30s: 0x%x\n", "aio_req->buf_len", aio_req->buf_len); DBG_IO("%30s: 0x%x\n", "aio_req->cmd_flags.data_dir", aio_req->cmd_flags.data_dir); DBG_IO("%30s: 0x%x\n", "aio_req->attr_prio.task_attr", aio_req->attr_prio.task_attr); DBG_IO("%30s: 0x%x\n", "aio_req->err_idx", aio_req->err_idx); DBG_IO("%30s: 0x%x\n", "aio_req->num_sg", aio_req->num_sg); DBG_IO("%30s: 0x%p\n", "aio_req->sg_desc[0].addr", (void *)aio_req->sg_desc[0].addr); DBG_IO("%30s: 0x%x\n", "aio_req->sg_desc[0].len", aio_req->sg_desc[0].len); DBG_IO("%30s: 0x%x\n", "aio_req->sg_desc[0].flags", aio_req->sg_desc[0].flags); } #endif void int_to_scsilun(uint64_t lun, uint8_t *scsi_lun) { int i; memset(scsi_lun, 0, sizeof(lun)); for (i = 0; i < sizeof(lun); i += 2) { scsi_lun[i] = (lun >> 8) & 0xFF; scsi_lun[i+1] = lun & 0xFF; lun = lun >> 16; } } /*Subroutine used to populate AIO IUs. */ void pqisrc_build_aio_common(pqisrc_softstate_t *softs, pqi_aio_req_t *aio_req, rcb_t *rcb, uint32_t num_elem_alloted) { DBG_FUNC("IN\n"); aio_req->header.iu_type = PQI_IU_TYPE_AIO_PATH_IO_REQUEST; aio_req->header.comp_feature = 0; aio_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb); aio_req->work_area[0] = 0; aio_req->work_area[1] = 0; aio_req->req_id = rcb->tag; aio_req->res1[0] = 0; aio_req->res1[1] = 0; aio_req->nexus = rcb->ioaccel_handle; aio_req->buf_len = GET_SCSI_BUFFLEN(rcb); aio_req->cmd_flags.data_dir = rcb->data_dir; aio_req->cmd_flags.mem_type = 0; aio_req->cmd_flags.fence = 0; aio_req->cmd_flags.res2 = 0; aio_req->attr_prio.task_attr = OS_GET_TASK_ATTR(rcb); aio_req->attr_prio.cmd_prio = 0; aio_req->attr_prio.res3 = 0; aio_req->err_idx = aio_req->req_id; aio_req->cdb_len = rcb->cmdlen; if (rcb->cmdlen > sizeof(aio_req->cdb)) rcb->cmdlen = sizeof(aio_req->cdb); memcpy(aio_req->cdb, rcb->cdbp, rcb->cmdlen); memset(aio_req->res4, 0, sizeof(aio_req->res4)); uint64_t lun = rcb->cm_ccb->ccb_h.target_lun; if (lun && (rcb->dvp->is_multi_lun)) { int_to_scsilun(lun, aio_req->lun); } else { memset(aio_req->lun, 0, sizeof(aio_req->lun)); } /* handle encryption fields */ if (rcb->encrypt_enable == true) { aio_req->cmd_flags.encrypt_enable = true; aio_req->encrypt_key_index = LE_16(rcb->enc_info.data_enc_key_index); aio_req->encrypt_twk_low = LE_32(rcb->enc_info.encrypt_tweak_lower); aio_req->encrypt_twk_high = LE_32(rcb->enc_info.encrypt_tweak_upper); } else { aio_req->cmd_flags.encrypt_enable = 0; aio_req->encrypt_key_index = 0; aio_req->encrypt_twk_high = 0; aio_req->encrypt_twk_low = 0; } /* Frame SGL Descriptor */ aio_req->cmd_flags.partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb, &aio_req->header, num_elem_alloted); aio_req->num_sg = aio_req->header.iu_length / sizeof(sgt_t); /* DBG_INFO("aio_req->num_sg :%d\n", aio_req->num_sg); */ aio_req->header.iu_length += offsetof(pqi_aio_req_t, sg_desc) - sizeof(iu_header_t); /* set completion and error handlers. */ rcb->success_cmp_callback = pqisrc_process_io_response_success; rcb->error_cmp_callback = pqisrc_process_aio_response_error; rcb->resp_qid = aio_req->response_queue_id; DBG_FUNC("OUT\n"); } /*Subroutine used to show standard AIO IU fields */ void pqisrc_show_aio_common(pqisrc_softstate_t *softs, rcb_t *rcb, pqi_aio_req_t *aio_req) { #ifdef DEBUG_AIO DBG_INFO("AIO IU Content, tag# 0x%08x", rcb->tag); DBG_INFO("%15s: 0x%x\n", "iu_type", aio_req->header.iu_type); DBG_INFO("%15s: 0x%x\n", "comp_feat", aio_req->header.comp_feature); DBG_INFO("%15s: 0x%x\n", "length", aio_req->header.iu_length); DBG_INFO("%15s: 0x%x\n", "resp_qid", aio_req->response_queue_id); DBG_INFO("%15s: 0x%x\n", "req_id", aio_req->req_id); DBG_INFO("%15s: 0x%x\n", "nexus", aio_req->nexus); DBG_INFO("%15s: 0x%x\n", "buf_len", aio_req->buf_len); DBG_INFO("%15s:\n", "cmd_flags"); DBG_INFO("%15s: 0x%x\n", "data_dir", aio_req->cmd_flags.data_dir); DBG_INFO("%15s: 0x%x\n", "partial", aio_req->cmd_flags.partial); DBG_INFO("%15s: 0x%x\n", "mem_type", aio_req->cmd_flags.mem_type); DBG_INFO("%15s: 0x%x\n", "fence", aio_req->cmd_flags.fence); DBG_INFO("%15s: 0x%x\n", "encryption", aio_req->cmd_flags.encrypt_enable); DBG_INFO("%15s:\n", "attr_prio"); DBG_INFO("%15s: 0x%x\n", "task_attr", aio_req->attr_prio.task_attr); DBG_INFO("%15s: 0x%x\n", "cmd_prio", aio_req->attr_prio.cmd_prio); DBG_INFO("%15s: 0x%x\n", "dek_index", aio_req->encrypt_key_index); DBG_INFO("%15s: 0x%x\n", "tweak_lower", aio_req->encrypt_twk_low); DBG_INFO("%15s: 0x%x\n", "tweak_upper", aio_req->encrypt_twk_high); pqisrc_show_cdb(softs, "AIOC", rcb, aio_req->cdb); DBG_INFO("%15s: 0x%x\n", "err_idx", aio_req->err_idx); DBG_INFO("%15s: 0x%x\n", "num_sg", aio_req->num_sg); DBG_INFO("%15s: 0x%x\n", "cdb_len", aio_req->cdb_len); #if 0 DBG_INFO("%15s: 0x%x\n", "lun", aio_req->lun); DBG_INFO("%15s: 0x%p\n", "sg_desc[0].addr", (void *)aio_req->sg_desc[0].addr); DBG_INFO("%15s: 0x%x\n", "sg_desc[0].len", aio_req->sg_desc[0].len); DBG_INFO("%15s: 0x%x\n", "sg_desc[0].flags", aio_req->sg_desc[0].flags); #endif #endif /* DEBUG_AIO */ } /*Subroutine used to populate AIO RAID 1 write bypass IU. */ void pqisrc_build_aio_R1_write(pqisrc_softstate_t *softs, pqi_aio_raid1_write_req_t *aio_req, rcb_t *rcb, uint32_t num_elem_alloted) { DBG_FUNC("IN\n"); if (!rcb->dvp) { DBG_WARN("%s: DEBUG: dev ptr is null", __func__); return; } if (!rcb->dvp->raid_map) { DBG_WARN("%s: DEBUG: raid_map is null", __func__); return; } aio_req->header.iu_type = PQI_IU_TYPE_RAID1_WRITE_BYPASS_REQUEST; aio_req->header.comp_feature = 0; aio_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb); aio_req->work_area[0] = 0; aio_req->work_area[1] = 0; aio_req->req_id = rcb->tag; aio_req->volume_id = (LE_32(rcb->dvp->scsi3addr[0]) & 0x3FFF); aio_req->nexus_1 = rcb->it_nexus[0]; aio_req->nexus_2 = rcb->it_nexus[1]; aio_req->nexus_3 = rcb->it_nexus[2]; aio_req->buf_len = GET_SCSI_BUFFLEN(rcb); aio_req->cmd_flags.data_dir = rcb->data_dir; aio_req->cmd_flags.mem_type = 0; aio_req->cmd_flags.fence = 0; aio_req->cmd_flags.res2 = 0; aio_req->attr_prio.task_attr = OS_GET_TASK_ATTR(rcb); aio_req->attr_prio.cmd_prio = 0; aio_req->attr_prio.res3 = 0; if(rcb->cmdlen > sizeof(aio_req->cdb)) rcb->cmdlen = sizeof(aio_req->cdb); memcpy(aio_req->cdb, rcb->cdbp, rcb->cmdlen); aio_req->err_idx = aio_req->req_id; aio_req->cdb_len = rcb->cmdlen; aio_req->num_drives = LE_16(rcb->dvp->raid_map->layout_map_count); /* handle encryption fields */ if (rcb->encrypt_enable == true) { aio_req->cmd_flags.encrypt_enable = true; aio_req->encrypt_key_index = LE_16(rcb->enc_info.data_enc_key_index); aio_req->encrypt_twk_low = LE_32(rcb->enc_info.encrypt_tweak_lower); aio_req->encrypt_twk_high = LE_32(rcb->enc_info.encrypt_tweak_upper); } else { aio_req->cmd_flags.encrypt_enable = 0; aio_req->encrypt_key_index = 0; aio_req->encrypt_twk_high = 0; aio_req->encrypt_twk_low = 0; } /* Frame SGL Descriptor */ aio_req->cmd_flags.partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb, &aio_req->header, num_elem_alloted); aio_req->num_sg = aio_req->header.iu_length / sizeof(sgt_t); /* DBG_INFO("aio_req->num_sg :%d\n", aio_req->num_sg); */ aio_req->header.iu_length += offsetof(pqi_aio_raid1_write_req_t, sg_desc) - sizeof(iu_header_t); /* set completion and error handlers. */ rcb->success_cmp_callback = pqisrc_process_io_response_success; rcb->error_cmp_callback = pqisrc_process_aio_response_error; rcb->resp_qid = aio_req->response_queue_id; DBG_FUNC("OUT\n"); } /*Subroutine used to show AIO RAID1 Write bypass IU fields */ void pqisrc_show_aio_R1_write(pqisrc_softstate_t *softs, rcb_t *rcb, pqi_aio_raid1_write_req_t *aio_req) { #ifdef DEBUG_AIO DBG_INFO("AIO RAID1 Write IU Content, tag# 0x%08x", rcb->tag); DBG_INFO("%15s: 0x%x\n", "iu_type", aio_req->header.iu_type); DBG_INFO("%15s: 0x%x\n", "comp_feat", aio_req->header.comp_feature); DBG_INFO("%15s: 0x%x\n", "length", aio_req->header.iu_length); DBG_INFO("%15s: 0x%x\n", "resp_qid", aio_req->response_queue_id); DBG_INFO("%15s: 0x%x\n", "req_id", aio_req->req_id); DBG_INFO("%15s: 0x%x\n", "volume_id", aio_req->volume_id); DBG_INFO("%15s: 0x%x\n", "nexus_1", aio_req->nexus_1); DBG_INFO("%15s: 0x%x\n", "nexus_2", aio_req->nexus_2); DBG_INFO("%15s: 0x%x\n", "nexus_3", aio_req->nexus_3); DBG_INFO("%15s: 0x%x\n", "buf_len", aio_req->buf_len); DBG_INFO("%15s:\n", "cmd_flags"); DBG_INFO("%15s: 0x%x\n", "data_dir", aio_req->cmd_flags.data_dir); DBG_INFO("%15s: 0x%x\n", "partial", aio_req->cmd_flags.partial); DBG_INFO("%15s: 0x%x\n", "mem_type", aio_req->cmd_flags.mem_type); DBG_INFO("%15s: 0x%x\n", "fence", aio_req->cmd_flags.fence); DBG_INFO("%15s: 0x%x\n", "encryption", aio_req->cmd_flags.encrypt_enable); DBG_INFO("%15s:\n", "attr_prio"); DBG_INFO("%15s: 0x%x\n", "task_attr", aio_req->attr_prio.task_attr); DBG_INFO("%15s: 0x%x\n", "cmd_prio", aio_req->attr_prio.cmd_prio); DBG_INFO("%15s: 0x%x\n", "dek_index", aio_req->encrypt_key_index); pqisrc_show_cdb(softs, "AIOR1W", rcb, aio_req->cdb); DBG_INFO("%15s: 0x%x\n", "err_idx", aio_req->err_idx); DBG_INFO("%15s: 0x%x\n", "num_sg", aio_req->num_sg); DBG_INFO("%15s: 0x%x\n", "cdb_len", aio_req->cdb_len); DBG_INFO("%15s: 0x%x\n", "num_drives", aio_req->num_drives); DBG_INFO("%15s: 0x%x\n", "tweak_lower", aio_req->encrypt_twk_low); DBG_INFO("%15s: 0x%x\n", "tweak_upper", aio_req->encrypt_twk_high); #if 0 DBG_INFO("%15s: 0x%p\n", "sg_desc[0].addr", (void *)aio_req->sg_desc[0].addr); DBG_INFO("%15s: 0x%x\n", "sg_desc[0].len", aio_req->sg_desc[0].len); DBG_INFO("%15s: 0x%x\n", "sg_desc[0].flags", aio_req->sg_desc[0].flags); #endif #endif /* DEBUG_AIO */ } /*Subroutine used to populate AIO Raid5 or 6 write bypass IU */ void pqisrc_build_aio_R5or6_write(pqisrc_softstate_t *softs, pqi_aio_raid5or6_write_req_t *aio_req, rcb_t *rcb, uint32_t num_elem_alloted) { DBG_FUNC("IN\n"); uint32_t index; unsigned num_data_disks; unsigned num_metadata_disks; unsigned total_disks; num_data_disks = LE_16(rcb->dvp->raid_map->data_disks_per_row); num_metadata_disks = LE_16(rcb->dvp->raid_map->metadata_disks_per_row); total_disks = num_data_disks + num_metadata_disks; index = PQISRC_DIV_ROUND_UP(rcb->raid_map_index + 1, total_disks); index *= total_disks; index -= num_metadata_disks; switch (rcb->dvp->raid_level) { case SA_RAID_5: aio_req->header.iu_type = PQI_IU_TYPE_RAID5_WRITE_BYPASS_REQUEST; break; case SA_RAID_6: aio_req->header.iu_type = PQI_IU_TYPE_RAID6_WRITE_BYPASS_REQUEST; break; default: DBG_ERR("WRONG RAID TYPE FOR FUNCTION\n"); } aio_req->header.comp_feature = 0; aio_req->response_queue_id = OS_GET_IO_RESP_QID(softs, rcb); aio_req->work_area[0] = 0; aio_req->work_area[1] = 0; aio_req->req_id = rcb->tag; aio_req->volume_id = (LE_32(rcb->dvp->scsi3addr[0]) & 0x3FFF); aio_req->data_it_nexus = rcb->dvp->raid_map->dev_data[rcb->raid_map_index].ioaccel_handle; aio_req->p_parity_it_nexus = rcb->dvp->raid_map->dev_data[index].ioaccel_handle; if (aio_req->header.iu_type == PQI_IU_TYPE_RAID6_WRITE_BYPASS_REQUEST) { aio_req->q_parity_it_nexus = rcb->dvp->raid_map->dev_data[index + 1].ioaccel_handle; } aio_req->xor_multiplier = rcb->dvp->raid_map->dev_data[rcb->raid_map_index].xor_mult[1]; aio_req->row = rcb->row_num; /*aio_req->reserved = rcb->row_num * rcb->blocks_per_row + rcb->dvp->raid_map->disk_starting_blk;*/ aio_req->buf_len = GET_SCSI_BUFFLEN(rcb); aio_req->cmd_flags.data_dir = rcb->data_dir; aio_req->cmd_flags.mem_type = 0; aio_req->cmd_flags.fence = 0; aio_req->cmd_flags.res2 = 0; aio_req->attr_prio.task_attr = OS_GET_TASK_ATTR(rcb); aio_req->attr_prio.cmd_prio = 0; aio_req->attr_prio.res3 = 0; if (rcb->cmdlen > sizeof(aio_req->cdb)) rcb->cmdlen = sizeof(aio_req->cdb); memcpy(aio_req->cdb, rcb->cdbp, rcb->cmdlen); aio_req->err_idx = aio_req->req_id; aio_req->cdb_len = rcb->cmdlen; #if 0 /* Stubbed out for later */ aio_req->header.iu_type = iu_type; aio_req->data_it_nexus = ; aio_req->p_parity_it_nexus = ; aio_req->q_parity_it_nexus = ; aio_req->row = ; aio_req->stripe_lba = ; #endif /* handle encryption fields */ if (rcb->encrypt_enable == true) { aio_req->cmd_flags.encrypt_enable = true; aio_req->encrypt_key_index = LE_16(rcb->enc_info.data_enc_key_index); aio_req->encrypt_twk_low = LE_32(rcb->enc_info.encrypt_tweak_lower); aio_req->encrypt_twk_high = LE_32(rcb->enc_info.encrypt_tweak_upper); } else { aio_req->cmd_flags.encrypt_enable = 0; aio_req->encrypt_key_index = 0; aio_req->encrypt_twk_high = 0; aio_req->encrypt_twk_low = 0; } /* Frame SGL Descriptor */ aio_req->cmd_flags.partial = pqisrc_build_sgl(&aio_req->sg_desc[0], rcb, &aio_req->header, num_elem_alloted); aio_req->num_sg = aio_req->header.iu_length / sizeof(sgt_t); /* DBG_INFO("aio_req->num_sg :%d\n", aio_req->num_sg); */ aio_req->header.iu_length += offsetof(pqi_aio_raid5or6_write_req_t, sg_desc) - sizeof(iu_header_t); /* set completion and error handlers. */ rcb->success_cmp_callback = pqisrc_process_io_response_success; rcb->error_cmp_callback = pqisrc_process_aio_response_error; rcb->resp_qid = aio_req->response_queue_id; DBG_FUNC("OUT\n"); } /*Subroutine used to show AIO RAID5/6 Write bypass IU fields */ void pqisrc_show_aio_R5or6_write(pqisrc_softstate_t *softs, rcb_t *rcb, pqi_aio_raid5or6_write_req_t *aio_req) { #ifdef DEBUG_AIO DBG_INFO("AIO RAID5or6 Write IU Content, tag# 0x%08x\n", rcb->tag); DBG_INFO("%15s: 0x%x\n", "iu_type", aio_req->header.iu_type); DBG_INFO("%15s: 0x%x\n", "comp_feat", aio_req->header.comp_feature); DBG_INFO("%15s: 0x%x\n", "length", aio_req->header.iu_length); DBG_INFO("%15s: 0x%x\n", "resp_qid", aio_req->response_queue_id); DBG_INFO("%15s: 0x%x\n", "req_id", aio_req->req_id); DBG_INFO("%15s: 0x%x\n", "volume_id", aio_req->volume_id); DBG_INFO("%15s: 0x%x\n", "data_it_nexus", aio_req->data_it_nexus); DBG_INFO("%15s: 0x%x\n", "p_parity_it_nexus", aio_req->p_parity_it_nexus); DBG_INFO("%15s: 0x%x\n", "q_parity_it_nexus", aio_req->q_parity_it_nexus); DBG_INFO("%15s: 0x%x\n", "buf_len", aio_req->buf_len); DBG_INFO("%15s:\n", "cmd_flags"); DBG_INFO("%15s: 0x%x\n", "data_dir", aio_req->cmd_flags.data_dir); DBG_INFO("%15s: 0x%x\n", "partial", aio_req->cmd_flags.partial); DBG_INFO("%15s: 0x%x\n", "mem_type", aio_req->cmd_flags.mem_type); DBG_INFO("%15s: 0x%x\n", "fence", aio_req->cmd_flags.fence); DBG_INFO("%15s: 0x%x\n", "encryption", aio_req->cmd_flags.encrypt_enable); DBG_INFO("%15s:\n", "attr_prio"); DBG_INFO("%15s: 0x%x\n", "task_attr", aio_req->attr_prio.task_attr); DBG_INFO("%15s: 0x%x\n", "cmd_prio", aio_req->attr_prio.cmd_prio); DBG_INFO("%15s: 0x%x\n", "dek_index", aio_req->encrypt_key_index); pqisrc_show_cdb(softs, "AIOR56W", rcb, aio_req->cdb); DBG_INFO("%15s: 0x%x\n", "err_idx", aio_req->err_idx); DBG_INFO("%15s: 0x%x\n", "num_sg", aio_req->num_sg); DBG_INFO("%15s: 0x%x\n", "cdb_len", aio_req->cdb_len); DBG_INFO("%15s: 0x%x\n", "tweak_lower", aio_req->encrypt_twk_low); DBG_INFO("%15s: 0x%x\n", "tweak_upper", aio_req->encrypt_twk_high); DBG_INFO("%15s: 0x%lx\n", "row", aio_req->row); #if 0 DBG_INFO("%15s: 0x%lx\n", "stripe_lba", aio_req->stripe_lba); DBG_INFO("%15s: 0x%p\n", "sg_desc[0].addr", (void *)aio_req->sg_desc[0].addr); DBG_INFO("%15s: 0x%x\n", "sg_desc[0].len", aio_req->sg_desc[0].len); DBG_INFO("%15s: 0x%x\n", "sg_desc[0].flags", aio_req->sg_desc[0].flags); #endif #endif /* DEBUG_AIO */ } /* Is the cdb a read command? */ boolean_t pqisrc_cdb_is_read(uint8_t *cdb) { if (cdb[0] == SCMD_READ_6 || cdb[0] == SCMD_READ_10 || cdb[0] == SCMD_READ_12 || cdb[0] == SCMD_READ_16) return true; return false; } /* Is the cdb a write command? */ boolean_t pqisrc_cdb_is_write(uint8_t *cdb) { if (cdb == NULL) return false; if (cdb[0] == SCMD_WRITE_6 || cdb[0] == SCMD_WRITE_10 || cdb[0] == SCMD_WRITE_12 || cdb[0] == SCMD_WRITE_16) return true; return false; } /*Subroutine used to show the AIO request */ void pqisrc_show_aio_io(pqisrc_softstate_t *softs, rcb_t *rcb, pqi_aio_req_t *aio_req, uint32_t num_elem_alloted) { boolean_t is_write; DBG_FUNC("IN\n"); is_write = pqisrc_cdb_is_write(rcb->cdbp); if (!is_write) { pqisrc_show_aio_common(softs, rcb, aio_req); goto out; } switch (rcb->dvp->raid_level) { case SA_RAID_0: pqisrc_show_aio_common(softs, rcb, aio_req); break; case SA_RAID_1: case SA_RAID_ADM: pqisrc_show_aio_R1_write(softs, rcb, (pqi_aio_raid1_write_req_t *)aio_req); break; case SA_RAID_5: case SA_RAID_6: pqisrc_show_aio_R5or6_write(softs, rcb, (pqi_aio_raid5or6_write_req_t *)aio_req); break; } out: DBG_FUNC("OUT\n"); } void pqisrc_build_aio_io(pqisrc_softstate_t *softs, rcb_t *rcb, pqi_aio_req_t *aio_req, uint32_t num_elem_alloted) { boolean_t is_write; DBG_FUNC("IN\n"); is_write = pqisrc_cdb_is_write(rcb->cdbp); if (is_write) { switch (rcb->dvp->raid_level) { case SA_RAID_0: pqisrc_build_aio_common(softs, aio_req, rcb, num_elem_alloted); break; case SA_RAID_1: case SA_RAID_ADM: pqisrc_build_aio_R1_write(softs, (pqi_aio_raid1_write_req_t *)aio_req, rcb, num_elem_alloted); break; case SA_RAID_5: case SA_RAID_6: pqisrc_build_aio_R5or6_write(softs, (pqi_aio_raid5or6_write_req_t *)aio_req, rcb, num_elem_alloted); break; } } else { pqisrc_build_aio_common(softs, aio_req, rcb, num_elem_alloted); } pqisrc_show_aio_io(softs, rcb, aio_req, num_elem_alloted); DBG_FUNC("OUT\n"); } /* * Return true from this function to prevent AIO from handling this request. * True is returned if the request is determined to be part of a stream, or * if the controller does not handle AIO at the appropriate RAID level. */ static boolean_t pqisrc_is_parity_write_stream(pqisrc_softstate_t *softs, rcb_t *rcb) { os_ticks_t oldest_ticks; uint8_t lru_index; int i; int rc; pqi_scsi_dev_t *device; struct pqi_stream_data *pqi_stream_data; aio_req_locator_t loc; DBG_FUNC("IN\n"); rc = fill_lba_for_scsi_rw(softs, rcb->cdbp , &loc); if (rc != PQI_STATUS_SUCCESS) { return false; } /* check writes only */ if (!pqisrc_cdb_is_write(rcb->cdbp)) { return false; } if (!softs->enable_stream_detection) { return false; } device = rcb->dvp; if (!device) { return false; } /* * check for R5/R6 streams. */ if (device->raid_level != SA_RAID_5 && device->raid_level != SA_RAID_6) { return false; } /* * If controller does not support AIO R{5,6} writes, need to send * requests down non-aio path. */ if ((device->raid_level == SA_RAID_5 && !softs->aio_raid5_write_bypass) || (device->raid_level == SA_RAID_6 && !softs->aio_raid6_write_bypass)) { return true; } lru_index = 0; oldest_ticks = INT_MAX; for (i = 0; i < NUM_STREAMS_PER_LUN; i++) { pqi_stream_data = &device->stream_data[i]; /* * check for adjacent request or request is within * the previous request. */ if ((pqi_stream_data->next_lba && loc.block.first >= pqi_stream_data->next_lba) && loc.block.first <= pqi_stream_data->next_lba + loc.block.cnt) { pqi_stream_data->next_lba = loc.block.first + loc.block.cnt; pqi_stream_data->last_accessed = TICKS; return true; } /* unused entry */ if (pqi_stream_data->last_accessed == 0) { lru_index = i; break; } /* Find entry with oldest last accessed time */ if (pqi_stream_data->last_accessed <= oldest_ticks) { oldest_ticks = pqi_stream_data->last_accessed; lru_index = i; } } /* * Set LRU entry */ pqi_stream_data = &device->stream_data[lru_index]; pqi_stream_data->last_accessed = TICKS; pqi_stream_data->next_lba = loc.block.first + loc.block.cnt; DBG_FUNC("OUT\n"); return false; } /** Determine if a request is eligible for AIO. Build/map the request if using AIO path to a RAID volume. return the path that should be used for this request */ static IO_PATH_T determine_io_path_build_bypass(pqisrc_softstate_t *softs,rcb_t *rcb) { IO_PATH_T io_path = AIO_PATH; pqi_scsi_dev_t *devp = rcb->dvp; int ret = PQI_STATUS_FAILURE; /* Default to using the host CDB directly (will be used if targeting RAID path or HBA mode */ rcb->cdbp = OS_GET_CDBP(rcb); if(!rcb->aio_retry) { /** IO for Physical Drive, Send in AIO PATH **/ if(IS_AIO_PATH(devp)) { rcb->ioaccel_handle = devp->ioaccel_handle; return io_path; } /** IO for RAID Volume, ByPass IO, Send in AIO PATH unless part of stream **/ if (devp->offload_enabled && !pqisrc_is_parity_write_stream(softs, rcb)) { ret = pqisrc_build_scsi_cmd_raidbypass(softs, devp, rcb); } if (PQI_STATUS_FAILURE == ret) { io_path = RAID_PATH; } else { ASSERT(rcb->cdbp == rcb->bypass_cdb); } } else { /* Retrying failed AIO IO */ io_path = RAID_PATH; } return io_path; } uint8_t pqisrc_get_aio_data_direction(rcb_t *rcb) { switch (rcb->cm_ccb->ccb_h.flags & CAM_DIR_MASK) { case CAM_DIR_IN: return SOP_DATA_DIR_FROM_DEVICE; case CAM_DIR_OUT: return SOP_DATA_DIR_TO_DEVICE; case CAM_DIR_NONE: return SOP_DATA_DIR_NONE; default: return SOP_DATA_DIR_UNKNOWN; } } uint8_t pqisrc_get_raid_data_direction(rcb_t *rcb) { switch (rcb->cm_ccb->ccb_h.flags & CAM_DIR_MASK) { case CAM_DIR_IN: return SOP_DATA_DIR_TO_DEVICE; case CAM_DIR_OUT: return SOP_DATA_DIR_FROM_DEVICE; case CAM_DIR_NONE: return SOP_DATA_DIR_NONE; default: return SOP_DATA_DIR_UNKNOWN; } } /* Function used to build and send RAID/AIO */ int pqisrc_build_send_io(pqisrc_softstate_t *softs,rcb_t *rcb) { ib_queue_t *ib_q_array = softs->op_aio_ib_q; ib_queue_t *ib_q = NULL; char *ib_iu = NULL; IO_PATH_T io_path; uint32_t TraverseCount = 0; int first_qindex = OS_GET_IO_REQ_QINDEX(softs, rcb); int qindex = first_qindex; uint32_t num_op_ib_q = softs->num_op_aio_ibq; uint32_t num_elem_needed; uint32_t num_elem_alloted = 0; pqi_scsi_dev_t *devp = rcb->dvp; boolean_t is_write; DBG_FUNC("IN\n"); /* Note: this will determine if the request is eligble for AIO */ io_path = determine_io_path_build_bypass(softs, rcb); if (io_path == RAID_PATH) { /* Update direction for RAID path */ rcb->data_dir = pqisrc_get_raid_data_direction(rcb); num_op_ib_q = softs->num_op_raid_ibq; ib_q_array = softs->op_raid_ib_q; } else { rcb->data_dir = pqisrc_get_aio_data_direction(rcb); if (rcb->data_dir == SOP_DATA_DIR_UNKNOWN) { DBG_ERR("Unknown Direction\n"); } } is_write = pqisrc_cdb_is_write(rcb->cdbp); /* coverity[unchecked_value] */ num_elem_needed = pqisrc_num_elem_needed(softs, OS_GET_IO_SG_COUNT(rcb), devp, is_write, io_path); DBG_IO("num_elem_needed :%u",num_elem_needed); do { uint32_t num_elem_available; ib_q = (ib_q_array + qindex); PQI_LOCK(&ib_q->lock); num_elem_available = pqisrc_contiguous_free_elem(ib_q->pi_local, *(ib_q->ci_virt_addr), ib_q->num_elem); DBG_IO("num_elem_avialable :%u\n",num_elem_available); if(num_elem_available >= num_elem_needed) { num_elem_alloted = num_elem_needed; break; } DBG_IO("Current queue is busy! Hop to next queue\n"); PQI_UNLOCK(&ib_q->lock); qindex = (qindex + 1) % num_op_ib_q; if(qindex == first_qindex) { if (num_elem_needed == 1) break; TraverseCount += 1; num_elem_needed = 1; } }while(TraverseCount < 2); DBG_IO("num_elem_alloted :%u",num_elem_alloted); if (num_elem_alloted == 0) { DBG_WARN("OUT: IB Queues were full\n"); return PQI_STATUS_QFULL; } pqisrc_increment_device_active_io(softs,devp); /* Get IB Queue Slot address to build IU */ ib_iu = ib_q->array_virt_addr + (ib_q->pi_local * ib_q->elem_size); if(io_path == AIO_PATH) { /* Fill in the AIO IU per request and raid type */ pqisrc_build_aio_io(softs, rcb, (pqi_aio_req_t *)ib_iu, num_elem_alloted); } else { /** Build RAID structure **/ pqisrc_build_raid_io(softs, rcb, (pqisrc_raid_req_t *)ib_iu, num_elem_alloted); } rcb->req_pending = true; rcb->req_q = ib_q; rcb->path = io_path; pqisrc_increment_io_counters(softs, rcb); /* Update the local PI */ ib_q->pi_local = (ib_q->pi_local + num_elem_alloted) % ib_q->num_elem; DBG_IO("ib_q->pi_local : %x\n", ib_q->pi_local); DBG_IO("*ib_q->ci_virt_addr: %x\n",*(ib_q->ci_virt_addr)); /* Inform the fw about the new IU */ PCI_MEM_PUT32(softs, ib_q->pi_register_abs, ib_q->pi_register_offset, ib_q->pi_local); PQI_UNLOCK(&ib_q->lock); DBG_FUNC("OUT\n"); return PQI_STATUS_SUCCESS; } /* Subroutine used to set encryption info as part of RAID bypass IO*/ static inline void pqisrc_set_enc_info(struct pqi_enc_info *enc_info, struct raid_map *raid_map, uint64_t first_block) { uint32_t volume_blk_size; /* * Set the encryption tweak values based on logical block address. * If the block size is 512, the tweak value is equal to the LBA. * For other block sizes, tweak value is (LBA * block size) / 512. */ volume_blk_size = GET_LE32((uint8_t *)&raid_map->volume_blk_size); if (volume_blk_size != 512) first_block = (first_block * volume_blk_size) / 512; enc_info->data_enc_key_index = GET_LE16((uint8_t *)&raid_map->data_encryption_key_index); enc_info->encrypt_tweak_upper = ((uint32_t)(((first_block) >> 16) >> 16)); enc_info->encrypt_tweak_lower = ((uint32_t)(first_block)); } /* * Attempt to perform offload RAID mapping for a logical volume I/O. */ #define HPSA_RAID_0 0 #define HPSA_RAID_4 1 #define HPSA_RAID_1 2 /* also used for RAID 10 */ #define HPSA_RAID_5 3 /* also used for RAID 50 */ #define HPSA_RAID_51 4 #define HPSA_RAID_6 5 /* also used for RAID 60 */ #define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */ #define HPSA_RAID_MAX HPSA_RAID_ADM #define HPSA_RAID_UNKNOWN 0xff /* Subroutine used to parse the scsi opcode and build the CDB for RAID bypass*/ static int fill_lba_for_scsi_rw(pqisrc_softstate_t *softs, uint8_t *cdb, aio_req_locator_t *l) { if (!l) { DBG_INFO("No locator ptr: AIO ineligible"); return PQI_STATUS_FAILURE; } if (cdb == NULL) return PQI_STATUS_FAILURE; switch (cdb[0]) { case SCMD_WRITE_6: l->is_write = true; /* coverity[fallthrough] */ case SCMD_READ_6: l->block.first = (uint64_t)(((cdb[1] & 0x1F) << 16) | (cdb[2] << 8) | cdb[3]); l->block.cnt = (uint32_t)cdb[4]; if (l->block.cnt == 0) l->block.cnt = 256; /*blkcnt 0 means 256 */ break; case SCMD_WRITE_10: l->is_write = true; /* coverity[fallthrough] */ case SCMD_READ_10: l->block.first = (uint64_t)GET_BE32(&cdb[2]); l->block.cnt = (uint32_t)GET_BE16(&cdb[7]); break; case SCMD_WRITE_12: l->is_write = true; /* coverity[fallthrough] */ case SCMD_READ_12: l->block.first = (uint64_t)GET_BE32(&cdb[2]); l->block.cnt = GET_BE32(&cdb[6]); break; case SCMD_WRITE_16: l->is_write = true; /* coverity[fallthrough] */ case SCMD_READ_16: l->block.first = GET_BE64(&cdb[2]); l->block.cnt = GET_BE32(&cdb[10]); break; default: /* Process via normal I/O path. */ DBG_AIO("NOT read or write 6/10/12/16: AIO ineligible"); return PQI_STATUS_FAILURE; } return PQI_STATUS_SUCCESS; } /* determine whether writes to certain types of RAID are supported. */ -inline boolean_t +static boolean_t pqisrc_is_supported_write(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) { DBG_FUNC("IN\n"); /* Raid0 was always supported */ if (device->raid_level == SA_RAID_0) return true; /* module params for individual adv. aio write features may be on, * which affects ALL controllers, but some controllers * do not support adv. aio write. */ if (!softs->adv_aio_capable) return false; /* if the raid write bypass feature is turned on, * then the write is supported. */ switch (device->raid_level) { case SA_RAID_1: case SA_RAID_ADM: if (softs->aio_raid1_write_bypass) return true; break; case SA_RAID_5: if (softs->aio_raid5_write_bypass) return true; break; case SA_RAID_6: if (softs->aio_raid6_write_bypass) return true; } /* otherwise, it must be an unsupported write. */ DBG_IO("AIO ineligible: write not supported for raid type\n"); DBG_FUNC("OUT\n"); return false; } /* check for zero-byte transfers, invalid blocks, and wraparound */ static inline boolean_t pqisrc_is_invalid_block(pqisrc_softstate_t *softs, aio_req_locator_t *l) { DBG_FUNC("IN\n"); if (l->block.cnt == 0) { DBG_AIO("AIO ineligible: blk_cnt=0\n"); DBG_FUNC("OUT\n"); return true; } if (l->block.last < l->block.first || l->block.last >= GET_LE64((uint8_t *)&l->raid_map->volume_blk_cnt)) { DBG_AIO("AIO ineligible: last block < first\n"); DBG_FUNC("OUT\n"); return true; } DBG_FUNC("OUT\n"); return false; } /* Compute various attributes of request's location */ static inline boolean_t pqisrc_calc_disk_params(pqisrc_softstate_t *softs, aio_req_locator_t *l, rcb_t *rcb) { DBG_FUNC("IN\n"); /* grab #disks, strip size, and layout map count from raid map */ l->row.data_disks = GET_LE16((uint8_t *)&l->raid_map->data_disks_per_row); l->strip_sz = GET_LE16((uint8_t *)(&l->raid_map->strip_size)); l->map.layout_map_count = GET_LE16((uint8_t *)(&l->raid_map->layout_map_count)); /* Calculate stripe information for the request. */ l->row.blks_per_row = l->row.data_disks * l->strip_sz; if (!l->row.blks_per_row || !l->strip_sz) { DBG_AIO("AIO ineligible\n"); DBG_FUNC("OUT\n"); return false; } /* use __udivdi3 ? */ rcb->blocks_per_row = l->row.blks_per_row; l->row.first = l->block.first / l->row.blks_per_row; rcb->row_num = l->row.first; l->row.last = l->block.last / l->row.blks_per_row; l->row.offset_first = (uint32_t)(l->block.first - (l->row.first * l->row.blks_per_row)); l->row.offset_last = (uint32_t)(l->block.last - (l->row.last * l->row.blks_per_row)); l->col.first = l->row.offset_first / l->strip_sz; l->col.last = l->row.offset_last / l->strip_sz; DBG_FUNC("OUT\n"); return true; } /* Not AIO-eligible if it isnt' a single row/column. */ static inline boolean_t pqisrc_is_single_row_column(pqisrc_softstate_t *softs, aio_req_locator_t *l) { boolean_t ret = true; DBG_FUNC("IN\n"); if (l->row.first != l->row.last || l->col.first != l->col.last) { DBG_AIO("AIO ineligible\n"); ret = false; } DBG_FUNC("OUT\n"); return ret; } /* figure out disks/row, row, and map index. */ static inline boolean_t pqisrc_set_map_row_and_idx(pqisrc_softstate_t *softs, aio_req_locator_t *l, rcb_t *rcb) { if (!l->row.data_disks) { DBG_INFO("AIO ineligible: no data disks?\n"); return false; } l->row.total_disks = l->row.data_disks + LE_16(l->raid_map->metadata_disks_per_row); l->map.row = ((uint32_t)(l->row.first >> l->raid_map->parity_rotation_shift)) % GET_LE16((uint8_t *)(&l->raid_map->row_cnt)); l->map.idx = (l->map.row * l->row.total_disks) + l->col.first; rcb->raid_map_index = l->map.idx; rcb->raid_map_row = l->map.row; return true; } /* set the mirror for a raid 1/10/ADM */ static inline void pqisrc_set_read_mirror(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device, aio_req_locator_t *l) { /* Avoid direct use of device->offload_to_mirror within this * function since multiple threads might simultaneously * increment it beyond the range of device->layout_map_count -1. */ int mirror = device->offload_to_mirror[l->map.idx]; int next_mirror = mirror + 1; if (next_mirror >= l->map.layout_map_count) next_mirror = 0; device->offload_to_mirror[l->map.idx] = next_mirror; l->map.idx += mirror * l->row.data_disks; } /* collect ioaccel handles for mirrors of given location. */ static inline boolean_t pqisrc_set_write_mirrors( pqisrc_softstate_t *softs, pqi_scsi_dev_t *device, aio_req_locator_t *l, rcb_t *rcb) { uint32_t mirror = 0; uint32_t index; if (l->map.layout_map_count > PQISRC_MAX_SUPPORTED_MIRRORS) return false; do { index = l->map.idx + (l->row.data_disks * mirror); rcb->it_nexus[mirror] = l->raid_map->dev_data[index].ioaccel_handle; mirror++; } while (mirror != l->map.layout_map_count); return true; } /* Make sure first and last block are in the same R5/R6 RAID group. */ static inline boolean_t pqisrc_is_r5or6_single_group(pqisrc_softstate_t *softs, aio_req_locator_t *l) { boolean_t ret = true; DBG_FUNC("IN\n"); l->r5or6.row.blks_per_row = l->strip_sz * l->row.data_disks; l->stripesz = l->r5or6.row.blks_per_row * l->map.layout_map_count; l->group.first = (l->block.first % l->stripesz) / l->r5or6.row.blks_per_row; l->group.last = (l->block.last % l->stripesz) / l->r5or6.row.blks_per_row; if (l->group.first != l->group.last) { DBG_AIO("AIO ineligible"); ret = false; } DBG_FUNC("OUT\n"); ASSERT(ret == true); return ret; } /* Make sure R5 or R6 request doesn't span rows. */ static inline boolean_t pqisrc_is_r5or6_single_row(pqisrc_softstate_t *softs, aio_req_locator_t *l) { boolean_t ret = true; DBG_FUNC("IN\n"); /* figure row nums containing first & last block */ l->row.first = l->r5or6.row.first = l->block.first / l->stripesz; l->r5or6.row.last = l->block.last / l->stripesz; if (l->r5or6.row.first != l->r5or6.row.last) { DBG_AIO("AIO ineligible"); ret = false; } DBG_FUNC("OUT\n"); ASSERT(ret == true); return ret; } /* Make sure R5 or R6 request doesn't span columns. */ static inline boolean_t pqisrc_is_r5or6_single_column(pqisrc_softstate_t *softs, aio_req_locator_t *l) { boolean_t ret = true; /* Find the columns of the first and last block */ l->row.offset_first = l->r5or6.row.offset_first = (uint32_t)((l->block.first % l->stripesz) % l->r5or6.row.blks_per_row); l->r5or6.row.offset_last = (uint32_t)((l->block.last % l->stripesz) % l->r5or6.row.blks_per_row); l->col.first = l->r5or6.row.offset_first / l->strip_sz; l->r5or6.col.first = l->col.first; l->r5or6.col.last = l->r5or6.row.offset_last / l->strip_sz; if (l->r5or6.col.first != l->r5or6.col.last) { DBG_AIO("AIO ineligible"); ret = false; } ASSERT(ret == true); return ret; } /* Set the map row and index for a R5 or R6 AIO request */ static inline void pqisrc_set_r5or6_row_and_index(aio_req_locator_t *l, rcb_t *rcb) { l->map.row = ((uint32_t) (l->row.first >> l->raid_map->parity_rotation_shift)) % GET_LE16((uint8_t *)(&l->raid_map->row_cnt)); l->map.idx = (l->group.first * (GET_LE16((uint8_t *)(&l->raid_map->row_cnt)) * l->row.total_disks)) + (l->map.row * l->row.total_disks) + l->col.first; rcb->raid_map_index = l->map.idx; rcb->raid_map_row = l->map.row; } /* calculate physical disk block for aio request */ static inline boolean_t pqisrc_calc_aio_block(aio_req_locator_t *l) { boolean_t ret = true; l->block.disk_block = GET_LE64((uint8_t *) (&l->raid_map->disk_starting_blk)) + (l->row.first * l->strip_sz) + ((uint64_t)(l->row.offset_first) - (uint64_t)(l->col.first) * l->strip_sz); /* any values we should be checking here? if not convert to void */ return ret; } /* Handle differing logical/physical block sizes. */ static inline uint32_t pqisrc_handle_blk_size_diffs(aio_req_locator_t *l) { uint32_t disk_blk_cnt; disk_blk_cnt = l->block.cnt; if (l->raid_map->phys_blk_shift) { l->block.disk_block <<= l->raid_map->phys_blk_shift; disk_blk_cnt <<= l->raid_map->phys_blk_shift; } return disk_blk_cnt; } /* Make sure AIO request doesn't exceed the max that AIO device can * handle based on dev type, Raid level, and encryption status. * TODO: make limits dynamic when this becomes possible. */ -inline boolean_t +static boolean_t pqisrc_aio_req_too_big(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device, rcb_t *rcb, aio_req_locator_t *l, uint32_t disk_blk_cnt) { boolean_t ret = false; uint32_t dev_max; uint32_t size = disk_blk_cnt * device->raid_map->volume_blk_size; dev_max = size; /* filter for nvme crypto */ if (device->is_nvme && rcb->encrypt_enable) { if (softs->max_aio_rw_xfer_crypto_nvme != 0) { dev_max = MIN(dev_max,softs->max_aio_rw_xfer_crypto_nvme); } } /* filter for RAID 5/6/50/60 */ if (!device->is_physical_device && (device->raid_level == SA_RAID_5 || device->raid_level == SA_RAID_51 || device->raid_level == SA_RAID_6)) { if (softs->max_aio_write_raid5_6 != 0) { dev_max = MIN(dev_max,softs->max_aio_write_raid5_6); } } /* filter for RAID ADM */ if (!device->is_physical_device && (device->raid_level == SA_RAID_ADM) && (softs->max_aio_write_raid1_10_3drv != 0)) { dev_max = MIN(dev_max, softs->max_aio_write_raid1_10_3drv); } /* filter for RAID 1/10 */ if (!device->is_physical_device && (device->raid_level == SA_RAID_1) && (softs->max_aio_write_raid1_10_2drv != 0)) { dev_max = MIN(dev_max, softs->max_aio_write_raid1_10_2drv); } if (size > dev_max) { DBG_AIO("AIO ineligible: size=%u, max=%u", size, dev_max); ret = true; } return ret; } #ifdef DEBUG_RAID_MAP static inline void pqisrc_aio_show_raid_map(pqisrc_softstate_t *softs, struct raid_map *m) { int i; if (!m) { DBG_WARN("No RAID MAP!\n"); return; } DBG_INFO("======= Raid Map ================\n"); DBG_INFO("%-25s: 0x%x\n", "StructureSize", m->structure_size); DBG_INFO("%-25s: 0x%x\n", "LogicalBlockSize", m->volume_blk_size); DBG_INFO("%-25s: 0x%lx\n", "LogicalBlockCount", m->volume_blk_cnt); DBG_INFO("%-25s: 0x%x\n", "PhysicalBlockShift", m->phys_blk_shift); DBG_INFO("%-25s: 0x%x\n", "ParityRotationShift", m->parity_rotation_shift); DBG_INFO("%-25s: 0x%x\n", "StripSize", m->strip_size); DBG_INFO("%-25s: 0x%lx\n", "DiskStartingBlock", m->disk_starting_blk); DBG_INFO("%-25s: 0x%lx\n", "DiskBlockCount", m->disk_blk_cnt); DBG_INFO("%-25s: 0x%x\n", "DataDisksPerRow", m->data_disks_per_row); DBG_INFO("%-25s: 0x%x\n", "MetdataDisksPerRow", m->metadata_disks_per_row); DBG_INFO("%-25s: 0x%x\n", "RowCount", m->row_cnt); DBG_INFO("%-25s: 0x%x\n", "LayoutMapCnt", m->layout_map_count); DBG_INFO("%-25s: 0x%x\n", "fEncryption", m->flags); DBG_INFO("%-25s: 0x%x\n", "DEK", m->data_encryption_key_index); for (i = 0; i < RAID_MAP_MAX_ENTRIES; i++) { if (m->dev_data[i].ioaccel_handle == 0) break; DBG_INFO("%-25s: %d: 0x%04x\n", "ioaccel_handle, disk", i, m->dev_data[i].ioaccel_handle); } } #endif /* DEBUG_RAID_MAP */ static inline void pqisrc_aio_show_locator_info(pqisrc_softstate_t *softs, aio_req_locator_t *l, uint32_t disk_blk_cnt, rcb_t *rcb) { #ifdef DEBUG_AIO_LOCATOR pqisrc_aio_show_raid_map(softs, l->raid_map); DBG_INFO("======= AIO Locator Content, tag#0x%08x =====\n", rcb->tag); DBG_INFO("%-25s: 0x%lx\n", "block.first", l->block.first); DBG_INFO("%-25s: 0x%lx\n", "block.last", l->block.last); DBG_INFO("%-25s: 0x%x\n", "block.cnt", l->block.cnt); DBG_INFO("%-25s: 0x%lx\n", "block.disk_block", l->block.disk_block); DBG_INFO("%-25s: 0x%x\n", "row.blks_per_row", l->row.blks_per_row); DBG_INFO("%-25s: 0x%lx\n", "row.first", l->row.first); DBG_INFO("%-25s: 0x%lx\n", "row.last", l->row.last); DBG_INFO("%-25s: 0x%x\n", "row.offset_first", l->row.offset_first); DBG_INFO("%-25s: 0x%x\n", "row.offset_last", l->row.offset_last); DBG_INFO("%-25s: 0x%x\n", "row.data_disks", l->row.data_disks); DBG_INFO("%-25s: 0x%x\n", "row.total_disks", l->row.total_disks); DBG_INFO("%-25s: 0x%x\n", "col.first", l->col.first); DBG_INFO("%-25s: 0x%x\n", "col.last", l->col.last); if (l->raid_level == SA_RAID_5 || l->raid_level == SA_RAID_6) { DBG_INFO("%-25s: 0x%x\n", "r5or6.row.blks_per_row", l->r5or6.row.blks_per_row); DBG_INFO("%-25s: 0x%lx\n", "r5or6.row.first", l->r5or6.row.first); DBG_INFO("%-25s: 0x%lx\n", "r5or6.row.last", l->r5or6.row.last); DBG_INFO("%-25s: 0x%x\n", "r5or6.row.offset_first", l->r5or6.row.offset_first); DBG_INFO("%-25s: 0x%x\n", "r5or6.row.offset_last", l->r5or6.row.offset_last); DBG_INFO("%-25s: 0x%x\n", "r5or6.row.data_disks", l->r5or6.row.data_disks); DBG_INFO("%-25s: 0x%x\n", "r5or6.row.total_disks", l->r5or6.row.total_disks); DBG_INFO("%-25s: 0x%x\n", "r5or6.col.first", l->r5or6.col.first); DBG_INFO("%-25s: 0x%x\n", "r5or6.col.last", l->r5or6.col.last); } DBG_INFO("%-25s: 0x%x\n", "map.row", l->map.row); DBG_INFO("%-25s: 0x%x\n", "map.idx", l->map.idx); DBG_INFO("%-25s: 0x%x\n", "map.layout_map_count", l->map.layout_map_count); DBG_INFO("%-25s: 0x%x\n", "group.first", l->group.first); DBG_INFO("%-25s: 0x%x\n", "group.last", l->group.last); DBG_INFO("%-25s: 0x%x\n", "group.cur", l->group.cur); DBG_INFO("%-25s: %d\n", "is_write", l->is_write); DBG_INFO("%-25s: 0x%x\n", "stripesz", l->stripesz); DBG_INFO("%-25s: 0x%x\n", "strip_sz", l->strip_sz); DBG_INFO("%-25s: %d\n", "offload_to_mirror", l->offload_to_mirror); DBG_INFO("%-25s: %d\n", "raid_level", l->raid_level); #endif /* DEBUG_AIO_LOCATOR */ } /* build the aio cdb */ -inline void +static void pqisrc_aio_build_cdb(aio_req_locator_t *l, uint32_t disk_blk_cnt, rcb_t *rcb, uint8_t *cdb) { uint8_t cdb_length; if (l->block.disk_block > 0xffffffff) { cdb[0] = l->is_write ? SCMD_WRITE_16 : SCMD_READ_16; cdb[1] = 0; PUT_BE64(l->block.disk_block, &cdb[2]); PUT_BE32(disk_blk_cnt, &cdb[10]); cdb[15] = 0; cdb_length = 16; } else { cdb[0] = l->is_write ? SCMD_WRITE_10 : SCMD_READ_10; cdb[1] = 0; PUT_BE32(l->block.disk_block, &cdb[2]); cdb[6] = 0; PUT_BE16(disk_blk_cnt, &cdb[7]); cdb[9] = 0; cdb_length = 10; } rcb->cmdlen = cdb_length; } /* print any arbitrary buffer of length total_len */ void pqisrc_print_buffer(pqisrc_softstate_t *softs, char *msg, void *user_buf, uint32_t total_len, uint32_t flags) { #define LINE_BUF_LEN 60 #define INDEX_PER_LINE 16 uint32_t buf_consumed = 0; int ii; char line_buf[LINE_BUF_LEN]; int line_len; /* written length per line */ uint8_t this_char; if (user_buf == NULL) return; memset(line_buf, 0, LINE_BUF_LEN); /* Print index columns */ if (flags & PRINT_FLAG_HDR_COLUMN) { for (ii = 0, line_len = 0; ii < MIN(total_len, 16); ii++) { line_len += snprintf(line_buf + line_len, (LINE_BUF_LEN - line_len), "%02d ", ii); if ((line_len + 4) >= LINE_BUF_LEN) break; } DBG_INFO("%15.15s:[ %s ]\n", "header", line_buf); } /* Print index columns */ while(buf_consumed < total_len) { memset(line_buf, 0, LINE_BUF_LEN); for (ii = 0, line_len = 0; ii < INDEX_PER_LINE; ii++) { this_char = *((char*)(user_buf) + buf_consumed); line_len += snprintf(line_buf + line_len, (LINE_BUF_LEN - line_len), "%02x ", this_char); buf_consumed++; if (buf_consumed >= total_len || (line_len + 4) >= LINE_BUF_LEN) break; } DBG_INFO("%15.15s:[ %s ]\n", msg, line_buf); } } /* print CDB with column header */ void pqisrc_show_cdb(pqisrc_softstate_t *softs, char *msg, rcb_t *rcb, uint8_t *cdb) { /* Print the CDB contents */ pqisrc_print_buffer(softs, msg, cdb, rcb->cmdlen, PRINT_FLAG_HDR_COLUMN); } void pqisrc_show_rcb_details(pqisrc_softstate_t *softs, rcb_t *rcb, char *msg, void *err_info) { pqi_scsi_dev_t *devp; if (rcb == NULL || rcb->dvp == NULL) { DBG_ERR("Invalid rcb or dev ptr! rcb=%p\n", rcb); return; } devp = rcb->dvp; /* print the host and mapped CDB */ DBG_INFO("\n"); DBG_INFO("----- Start Dump: %s -----\n", msg); pqisrc_print_buffer(softs, "host cdb", OS_GET_CDBP(rcb), rcb->cmdlen, PRINT_FLAG_HDR_COLUMN); if (OS_GET_CDBP(rcb) != rcb->cdbp) pqisrc_print_buffer(softs, "aio mapped cdb", rcb->cdbp, rcb->cmdlen, 0); DBG_INFO("tag=0x%x dir=%u host_timeout=%ums\n", rcb->tag, rcb->data_dir, (uint32_t)rcb->host_timeout_ms); DBG_INFO("BTL: %d:%d:%d addr=0x%x\n", devp->bus, devp->target, devp->lun, GET_LE32(devp->scsi3addr)); if (rcb->path == AIO_PATH) { DBG_INFO("handle=0x%x\n", rcb->ioaccel_handle); DBG_INFO("row=%u blk/row=%u index=%u map_row=%u\n", rcb->row_num, rcb->blocks_per_row, rcb->raid_map_index, rcb->raid_map_row); if (err_info) pqisrc_show_aio_error_info(softs, rcb, err_info); } else /* RAID path */ { if (err_info) pqisrc_show_raid_error_info(softs, rcb, err_info); } DBG_INFO("----- Done -----\n\n"); } /* * Function used to build and send RAID bypass request to the adapter */ int pqisrc_build_scsi_cmd_raidbypass(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device, rcb_t *rcb) { uint32_t disk_blk_cnt; struct aio_req_locator loc; struct aio_req_locator *l = &loc; int rc; memset(l, 0, sizeof(*l)); DBG_FUNC("IN\n"); if (device == NULL) { DBG_INFO("device is NULL\n"); return PQI_STATUS_FAILURE; } if (device->raid_map == NULL) { DBG_INFO("tag=0x%x BTL: %d:%d:%d Raid map is NULL\n", rcb->tag, device->bus, device->target, device->lun); return PQI_STATUS_FAILURE; } /* Check for eligible op, get LBA and block count. */ rc = fill_lba_for_scsi_rw(softs, OS_GET_CDBP(rcb), l); if (rc == PQI_STATUS_FAILURE) return PQI_STATUS_FAILURE; if (l->is_write && !pqisrc_is_supported_write(softs, device)) return PQI_STATUS_FAILURE; l->raid_map = device->raid_map; l->block.last = l->block.first + l->block.cnt - 1; l->raid_level = device->raid_level; if (pqisrc_is_invalid_block(softs, l)) return PQI_STATUS_FAILURE; if (!pqisrc_calc_disk_params(softs, l, rcb)) return PQI_STATUS_FAILURE; if (!pqisrc_is_single_row_column(softs, l)) return PQI_STATUS_FAILURE; if (!pqisrc_set_map_row_and_idx(softs, l, rcb)) return PQI_STATUS_FAILURE; /* Proceeding with driver mapping. */ switch (device->raid_level) { case SA_RAID_1: case SA_RAID_ADM: if (l->is_write) { if (!pqisrc_set_write_mirrors(softs, device, l, rcb)) return PQI_STATUS_FAILURE; } else pqisrc_set_read_mirror(softs, device, l); break; case SA_RAID_5: case SA_RAID_6: if (l->map.layout_map_count > 1 || l->is_write) { if (!pqisrc_is_r5or6_single_group(softs, l)) return PQI_STATUS_FAILURE; if (!pqisrc_is_r5or6_single_row(softs, l)) return PQI_STATUS_FAILURE; if (!pqisrc_is_r5or6_single_column(softs, l)) return PQI_STATUS_FAILURE; pqisrc_set_r5or6_row_and_index(l, rcb); } break; } if (l->map.idx >= RAID_MAP_MAX_ENTRIES) { DBG_INFO("AIO ineligible: index exceeds max map entries"); return PQI_STATUS_FAILURE; } rcb->ioaccel_handle = l->raid_map->dev_data[l->map.idx].ioaccel_handle; if (!pqisrc_calc_aio_block(l)) return PQI_STATUS_FAILURE; disk_blk_cnt = pqisrc_handle_blk_size_diffs(l); /* Set encryption flag if needed. */ rcb->encrypt_enable = false; if (GET_LE16((uint8_t *)(&l->raid_map->flags)) & RAID_MAP_ENCRYPTION_ENABLED) { pqisrc_set_enc_info(&rcb->enc_info, l->raid_map, l->block.first); rcb->encrypt_enable = true; } if (pqisrc_aio_req_too_big(softs, device, rcb, l, disk_blk_cnt)) return PQI_STATUS_FAILURE; /* set the cdb ptr to the local bypass cdb */ rcb->cdbp = &rcb->bypass_cdb[0]; /* Build the new CDB for the physical disk I/O. */ pqisrc_aio_build_cdb(l, disk_blk_cnt, rcb, rcb->cdbp); pqisrc_aio_show_locator_info(softs, l, disk_blk_cnt, rcb); DBG_FUNC("OUT\n"); return PQI_STATUS_SUCCESS; } /* Function used to submit an AIO TMF to the adapter * DEVICE_RESET is not supported. */ static int pqisrc_send_aio_tmf(pqisrc_softstate_t *softs, pqi_scsi_dev_t *devp, rcb_t *rcb, rcb_t *rcb_to_manage, int tmf_type) { int rval = PQI_STATUS_SUCCESS; pqi_aio_tmf_req_t tmf_req; ib_queue_t *op_ib_q = NULL; boolean_t is_write; memset(&tmf_req, 0, sizeof(pqi_aio_tmf_req_t)); DBG_FUNC("IN\n"); tmf_req.header.iu_type = PQI_REQUEST_IU_AIO_TASK_MANAGEMENT; tmf_req.header.iu_length = sizeof(tmf_req) - sizeof(iu_header_t); tmf_req.req_id = rcb->tag; tmf_req.error_idx = rcb->tag; tmf_req.nexus = devp->ioaccel_handle; /* memcpy(tmf_req.lun, devp->scsi3addr, sizeof(tmf_req.lun)); */ tmf_req.tmf = tmf_type; tmf_req.resp_qid = OS_GET_TMF_RESP_QID(softs, rcb); op_ib_q = &softs->op_aio_ib_q[0]; is_write = pqisrc_cdb_is_write(rcb->cdbp); uint64_t lun = rcb->cm_ccb->ccb_h.target_lun; if (lun && (rcb->dvp->is_multi_lun)) { int_to_scsilun(lun, tmf_req.lun); } else { memset(tmf_req.lun, 0, sizeof(tmf_req.lun)); } if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK) { tmf_req.req_id_to_manage = rcb_to_manage->tag; tmf_req.nexus = rcb_to_manage->ioaccel_handle; } if (devp->raid_level == SA_RAID_1 || devp->raid_level == SA_RAID_5 || devp->raid_level == SA_RAID_6) { if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK && is_write) tmf_req.header.iu_type = PQI_REQUEST_IU_AIO_BYPASS_TASK_MGMT; } DBG_WARN("aio tmf: iu_type=0x%x req_id_to_manage=0x%x\n", tmf_req.header.iu_type, tmf_req.req_id_to_manage); DBG_WARN("aio tmf: req_id=0x%x nexus=0x%x tmf=0x%x QID=%u\n", tmf_req.req_id, tmf_req.nexus, tmf_req.tmf, op_ib_q->q_id); rcb->path = AIO_PATH; rcb->req_pending = true; /* Timedout tmf response goes here */ rcb->error_cmp_callback = pqisrc_process_aio_response_error; rval = pqisrc_submit_cmnd(softs, op_ib_q, &tmf_req); if (rval != PQI_STATUS_SUCCESS) { DBG_ERR("Unable to submit command rval=%d\n", rval); return rval; } rval = pqisrc_wait_on_condition(softs, rcb, PQISRC_TMF_TIMEOUT); if (rval != PQI_STATUS_SUCCESS){ DBG_ERR("Task Management tmf_type : %d timeout\n", tmf_type); rcb->status = rval; } if (rcb->status != PQI_STATUS_SUCCESS) { DBG_ERR_BTL(devp, "Task Management failed tmf_type:%d " "stat:0x%x\n", tmf_type, rcb->status); rval = PQI_STATUS_FAILURE; } DBG_FUNC("OUT\n"); return rval; } /* Function used to submit a Raid TMF to the adapter */ static int pqisrc_send_raid_tmf(pqisrc_softstate_t *softs, pqi_scsi_dev_t *devp, rcb_t *rcb, rcb_t *rcb_to_manage, int tmf_type) { int rval = PQI_STATUS_SUCCESS; pqi_raid_tmf_req_t tmf_req; ib_queue_t *op_ib_q = NULL; memset(&tmf_req, 0, sizeof(pqi_raid_tmf_req_t)); DBG_FUNC("IN\n"); tmf_req.header.iu_type = PQI_REQUEST_IU_RAID_TASK_MANAGEMENT; tmf_req.header.iu_length = sizeof(tmf_req) - sizeof(iu_header_t); tmf_req.req_id = rcb->tag; memcpy(tmf_req.lun, devp->scsi3addr, sizeof(tmf_req.lun)); tmf_req.ml_device_lun_number = (uint8_t)rcb->cm_ccb->ccb_h.target_lun; tmf_req.tmf = tmf_type; tmf_req.resp_qid = OS_GET_TMF_RESP_QID(softs, rcb); /* Decide the queue where the tmf request should be submitted */ if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK) { tmf_req.obq_id_to_manage = rcb_to_manage->resp_qid; tmf_req.req_id_to_manage = rcb_to_manage->tag; } if (softs->timeout_in_tmf && tmf_type == SOP_TASK_MANAGEMENT_LUN_RESET) { /* OS_TMF_TIMEOUT_SEC - 1 to accomodate driver processing */ tmf_req.timeout_in_sec = OS_TMF_TIMEOUT_SEC - 1; /* if OS tmf timeout is 0, set minimum value for timeout */ if (!tmf_req.timeout_in_sec) tmf_req.timeout_in_sec = 1; } op_ib_q = &softs->op_raid_ib_q[0]; DBG_WARN("raid tmf: iu_type=0x%x req_id_to_manage=%d\n", tmf_req.header.iu_type, tmf_req.req_id_to_manage); rcb->path = RAID_PATH; rcb->req_pending = true; /* Timedout tmf response goes here */ rcb->error_cmp_callback = pqisrc_process_raid_response_error; rval = pqisrc_submit_cmnd(softs, op_ib_q, &tmf_req); if (rval != PQI_STATUS_SUCCESS) { DBG_ERR("Unable to submit command rval=%d\n", rval); return rval; } rval = pqisrc_wait_on_condition(softs, rcb, PQISRC_TMF_TIMEOUT); if (rval != PQI_STATUS_SUCCESS) { DBG_ERR("Task Management tmf_type : %d timeout\n", tmf_type); rcb->status = rval; } if (rcb->status != PQI_STATUS_SUCCESS) { DBG_NOTE("Task Management failed tmf_type:%d " "stat:0x%x\n", tmf_type, rcb->status); rval = PQI_STATUS_FAILURE; } DBG_FUNC("OUT\n"); return rval; } void dump_tmf_details(pqisrc_softstate_t *softs, rcb_t *rcb, char *msg) { uint32_t qid = rcb->req_q ? rcb->req_q->q_id : -1; DBG_INFO("%s: pending=%d path=%d tag=0x%x=%u qid=%u timeout=%ums\n", msg, rcb->req_pending, rcb->path, rcb->tag, rcb->tag, qid, (uint32_t)rcb->host_timeout_ms); } int pqisrc_send_tmf(pqisrc_softstate_t *softs, pqi_scsi_dev_t *devp, rcb_t *rcb, rcb_t *rcb_to_manage, int tmf_type) { int ret = PQI_STATUS_SUCCESS; DBG_FUNC("IN\n"); DBG_WARN("sending TMF. io outstanding=%u\n", softs->max_outstanding_io - softs->taglist.num_elem); rcb->is_abort_cmd_from_host = true; rcb->softs = softs; /* No target rcb for general purpose TMFs like LUN RESET */ if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK) { rcb_to_manage->host_wants_to_abort_this = true; dump_tmf_details(softs, rcb_to_manage, "rcb_to_manage"); } dump_tmf_details(softs, rcb, "rcb"); if(!devp->is_physical_device) { if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK) { if(rcb_to_manage->path == AIO_PATH) { if(devp->offload_enabled) ret = pqisrc_send_aio_tmf(softs, devp, rcb, rcb_to_manage, tmf_type); } else { DBG_INFO("TASK ABORT not supported in raid\n"); ret = PQI_STATUS_FAILURE; } } else { ret = pqisrc_send_raid_tmf(softs, devp, rcb, rcb_to_manage, tmf_type); } } else { if (tmf_type == SOP_TASK_MANAGEMENT_FUNCTION_ABORT_TASK) ret = pqisrc_send_aio_tmf(softs, devp, rcb, rcb_to_manage, tmf_type); else ret = pqisrc_send_raid_tmf(softs, devp, rcb, rcb_to_manage, tmf_type); } DBG_FUNC("OUT\n"); return ret; } /* return index into the global (softs) counters based on raid level */ static counter_types_t get_counter_index(rcb_t *rcb) { if (IS_AIO_PATH(rcb->dvp)) return HBA_COUNTER; switch (rcb->dvp->raid_level) { case SA_RAID_0: return RAID0_COUNTER; case SA_RAID_1: case SA_RAID_ADM: return RAID1_COUNTER; case SA_RAID_5: return RAID5_COUNTER; case SA_RAID_6: return RAID6_COUNTER; case SA_RAID_UNKNOWN: default: { static boolean_t asserted = false; if (!asserted) { asserted = true; ASSERT(rcb->path == RAID_PATH); ASSERT(0); } return UNKNOWN_COUNTER; } } } /* return the counter type as ASCII-string */ static char * counter_type_to_raid_ascii(counter_types_t type) { switch (type) { case UNKNOWN_COUNTER: return "Unknown"; case HBA_COUNTER: return "HbaPath"; case RAID0_COUNTER: return "Raid0"; case RAID1_COUNTER: return "Raid1"; case RAID5_COUNTER: return "Raid5"; case RAID6_COUNTER: return "Raid6"; default: return "Unsupported"; } } /* return the path as ASCII-string */ char * io_path_to_ascii(IO_PATH_T path) { switch (path) { case AIO_PATH: return "Aio"; case RAID_PATH: return "Raid"; default: return "Unknown"; } } /* return the io type as ASCII-string */ static char * io_type_to_ascii(io_type_t io_type) { switch (io_type) { case UNKNOWN_IO_TYPE: return "Unknown"; case READ_IO_TYPE: return "Read"; case WRITE_IO_TYPE: return "Write"; case NON_RW_IO_TYPE: return "NonRW"; default: return "Unsupported"; } } /* return the io type based on cdb */ io_type_t get_io_type_from_cdb(uint8_t *cdb) { if (cdb == NULL) return UNKNOWN_IO_TYPE; else if (pqisrc_cdb_is_read(cdb)) return READ_IO_TYPE; else if (pqisrc_cdb_is_write(cdb)) return WRITE_IO_TYPE; return NON_RW_IO_TYPE; } /* increment this counter based on path and read/write */ OS_ATOMIC64_T increment_this_counter(io_counters_t *pcounter, IO_PATH_T path, io_type_t io_type) { OS_ATOMIC64_T ret_val; if (path == AIO_PATH) { if (io_type == READ_IO_TYPE) ret_val = OS_ATOMIC64_INC(&pcounter->aio_read_cnt); else if (io_type == WRITE_IO_TYPE) ret_val = OS_ATOMIC64_INC(&pcounter->aio_write_cnt); else ret_val = OS_ATOMIC64_INC(&pcounter->aio_non_read_write); } else { if (io_type == READ_IO_TYPE) ret_val = OS_ATOMIC64_INC(&pcounter->raid_read_cnt); else if (io_type == WRITE_IO_TYPE) ret_val = OS_ATOMIC64_INC(&pcounter->raid_write_cnt); else ret_val = OS_ATOMIC64_INC(&pcounter->raid_non_read_write); } return ret_val; } /* increment appropriate counter(s) anytime we post a new request */ static void pqisrc_increment_io_counters(pqisrc_softstate_t *softs, rcb_t *rcb) { io_type_t io_type = get_io_type_from_cdb(rcb->cdbp); counter_types_t type_index = get_counter_index(rcb); io_counters_t *pcounter = &softs->counters[type_index]; OS_ATOMIC64_T ret_val; ret_val = increment_this_counter(pcounter, rcb->path, io_type); #if 1 /* leave this enabled while we gain confidence for each io path */ if (ret_val == 1) { char *raid_type = counter_type_to_raid_ascii(type_index); char *path = io_path_to_ascii(rcb->path); char *io_ascii = io_type_to_ascii(io_type); DBG_INFO("Got first path/type hit. " "Path=%s RaidType=%s IoType=%s\n", path, raid_type, io_ascii); } #endif /* @todo future: may want to make a per-dev counter */ } /* public routine to print a particular counter with header msg */ void print_this_counter(pqisrc_softstate_t *softs, io_counters_t *pcounter, char *msg) { io_counters_t counter; uint32_t percent_reads; uint32_t percent_aio; if (!softs->log_io_counters) return; /* Use a cached copy so percentages are based on the data that is printed */ memcpy(&counter, pcounter, sizeof(counter)); DBG_NOTE("Counter: %s (ptr=%p)\n", msg, pcounter); percent_reads = CALC_PERCENT_VS(counter.aio_read_cnt + counter.raid_read_cnt, counter.aio_write_cnt + counter.raid_write_cnt); percent_aio = CALC_PERCENT_VS(counter.aio_read_cnt + counter.aio_write_cnt, counter.raid_read_cnt + counter.raid_write_cnt); DBG_NOTE(" R/W Percentages: Reads=%3u%% AIO=%3u%%\n", percent_reads, percent_aio); /* Print the Read counts */ percent_aio = CALC_PERCENT_VS(counter.aio_read_cnt, counter.raid_read_cnt); DBG_NOTE(" Reads : AIO=%8u(%3u%%) RAID=%8u\n", (uint32_t)counter.aio_read_cnt, percent_aio, (uint32_t)counter.raid_read_cnt); /* Print the Write counts */ percent_aio = CALC_PERCENT_VS(counter.aio_write_cnt, counter.raid_write_cnt); DBG_NOTE(" Writes: AIO=%8u(%3u%%) RAID=%8u\n", (uint32_t)counter.aio_write_cnt, percent_aio, (uint32_t)counter.raid_write_cnt); /* Print the Non-Rw counts */ percent_aio = CALC_PERCENT_VS(counter.aio_non_read_write, counter.raid_non_read_write); DBG_NOTE(" Non-RW: AIO=%8u(%3u%%) RAID=%8u\n", (uint32_t)counter.aio_non_read_write, percent_aio, (uint32_t)counter.raid_non_read_write); } /* return true if buffer is all zeroes */ boolean_t is_buffer_zero(void *buffer, uint32_t size) { char *buf = buffer; DWORD ii; if (buffer == NULL || size == 0) return false; for (ii = 0; ii < size; ii++) { if (buf[ii] != 0x00) return false; } return true; } /* public routine to print a all global counter types */ void print_all_counters(pqisrc_softstate_t *softs, uint32_t flags) { int ii; io_counters_t *pcounter; char *raid_type; for (ii = 0; ii < MAX_IO_COUNTER; ii++) { pcounter = &softs->counters[ii]; raid_type = counter_type_to_raid_ascii(ii); if ((flags & COUNTER_FLAG_ONLY_NON_ZERO) && is_buffer_zero(pcounter, sizeof(*pcounter))) { continue; } print_this_counter(softs, pcounter, raid_type); } if (flags & COUNTER_FLAG_CLEAR_COUNTS) { DBG_NOTE("Clearing all counters\n"); memset(softs->counters, 0, sizeof(softs->counters)); } }