1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2018 Nexenta Systems, Inc. 14 */ 15 16 /* 17 * A few simple method to access controller when it's in the base mode. 18 */ 19 #include <smartpqi.h> 20 21 /* ---- legacy SIS interface commands ---- */ 22 #define SIS_CMD_GET_ADAPTER_PROPERTIES 0x19 23 #define SIS_CMD_INIT_BASE_STRUCT_ADDRESS 0x1b 24 #define SIS_CMD_GET_PQI_CAPABILITIES 0x3000 25 26 /* ---- used with SIS_CMD_GET_ADAPTER_PROPERTIES command ---- */ 27 #define SIS_EXTENDED_PROPERTIES_SUPPORTED 0x800000 28 #define SIS_SMARTARRAY_FEATURES_SUPPORTED 0x2 29 #define SIS_PQI_MODE_SUPPORTED 0x4 30 #define SIS_REQUIRED_EXTENDED_PROPERTIES \ 31 (SIS_SMARTARRAY_FEATURES_SUPPORTED | SIS_PQI_MODE_SUPPORTED) 32 33 /* used for passing command parameters/results when issuing SIS commands */ 34 typedef struct sis_sync_cmd_params { 35 uint32_t mailbox[6]; /* mailboxes 0-5 */ 36 } __packed sis_sync_cmd_params_t; 37 38 #define SIS_BASE_STRUCT_REVISION 9 39 40 typedef struct sis_base_struct { 41 uint32_t sb_revision; 42 uint32_t sb_flags; 43 uint32_t sb_error_buffer_paddr_low; 44 uint32_t sb_error_buffer_paddr_high; 45 uint32_t sb_error_elements_len; 46 uint32_t sb_error_elements_num; 47 } __packed sis_base_struct_t; 48 49 /* ---- Forward declaration for support functions ---- */ 50 static boolean_t sis_send_sync_cmd(pqi_state_t *s, uint32_t cmd, 51 sis_sync_cmd_params_t *params); 52 53 uint32_t 54 sis_read_scratch(pqi_state_t *s) 55 { 56 return (G32(s, sis_driver_scratch)); 57 } 58 59 void 60 sis_write_scratch(pqi_state_t *s, int mode) 61 { 62 S32(s, sis_driver_scratch, mode); 63 } 64 65 boolean_t 66 sis_reenable_mode(pqi_state_t *s) 67 { 68 int loop_count; 69 uint32_t doorbell; 70 71 S32(s, sis_host_to_ctrl_doorbell, SIS_REENABLE_SIS_MODE); 72 73 for (loop_count = 0; loop_count < 1000; loop_count++) { 74 doorbell = G32(s, sis_ctrl_to_host_doorbell); 75 if ((doorbell & SIS_REENABLE_SIS_MODE) == 0) { 76 return (B_TRUE); 77 } 78 drv_usecwait(MICROSEC / MILLISEC); /* ---- Wait 1ms ---- */ 79 } 80 return (B_FALSE); 81 } 82 83 boolean_t 84 sis_wait_for_ctrl_ready(pqi_state_t *s) 85 { 86 int loop_count; 87 uint32_t status; 88 89 for (loop_count = 0; loop_count < 1000; loop_count++) { 90 status = G32(s, sis_firmware_status); 91 if (status & SIS_CTRL_KERNEL_PANIC) 92 return (B_FALSE); 93 if (status & SIS_CTRL_KERNEL_UP) 94 return (B_TRUE); 95 drv_usecwait(MICROSEC / MILLISEC); /* ---- Wait 1ms ---- */ 96 } 97 return (B_FALSE); 98 } 99 100 /* 101 * sis_get_ctrl_props -- Verify we're talking to controller that speaks PQI 102 */ 103 boolean_t 104 sis_get_ctrl_props(pqi_state_t *s) 105 { 106 sis_sync_cmd_params_t p; 107 uint32_t property; 108 uint32_t extended_property; 109 110 (void) memset(&p, 0, sizeof (p)); 111 if (sis_send_sync_cmd(s, SIS_CMD_GET_ADAPTER_PROPERTIES, &p) == B_FALSE) 112 return (B_FALSE); 113 114 property = p.mailbox[1]; 115 if (!(property & SIS_EXTENDED_PROPERTIES_SUPPORTED)) 116 return (B_FALSE); 117 118 extended_property = p.mailbox[4]; 119 if ((extended_property & SIS_REQUIRED_EXTENDED_PROPERTIES) != 120 SIS_REQUIRED_EXTENDED_PROPERTIES) 121 return (B_FALSE); 122 123 return (B_TRUE); 124 } 125 126 boolean_t 127 sis_get_pqi_capabilities(pqi_state_t *s) 128 { 129 sis_sync_cmd_params_t p; 130 131 (void) memset(&p, 0, sizeof (p)); 132 if (sis_send_sync_cmd(s, SIS_CMD_GET_PQI_CAPABILITIES, &p) == B_FALSE) 133 return (B_FALSE); 134 135 s->s_max_sg_entries = p.mailbox[1]; 136 s->s_max_xfer_size = p.mailbox[2]; 137 s->s_max_outstanding_requests = p.mailbox[3]; 138 s->s_config_table_offset = p.mailbox[4]; 139 s->s_config_table_len = p.mailbox[5]; 140 return (B_TRUE); 141 } 142 143 boolean_t 144 sis_init_base_struct_addr(pqi_state_t *s) 145 { 146 sis_base_struct_t *base; 147 pqi_dma_overhead_t *o; 148 sis_sync_cmd_params_t params; 149 boolean_t rc; 150 void *dma_addr; 151 152 o = pqi_alloc_single(s, sizeof (*base) + SIS_BASE_STRUCT_ALIGNMENT); 153 if (o == NULL) 154 return (B_FALSE); 155 156 base = PQIALIGN_TYPED(o->alloc_memory, SIS_BASE_STRUCT_ALIGNMENT, 157 sis_base_struct_t *); 158 base->sb_revision = SIS_BASE_STRUCT_REVISION; 159 base->sb_error_buffer_paddr_low = (uint32_t)s->s_error_dma->dma_addr; 160 base->sb_error_buffer_paddr_high = 161 (uint32_t)(s->s_error_dma->dma_addr >> 32); 162 base->sb_error_elements_len = PQI_ERROR_BUFFER_ELEMENT_LENGTH; 163 base->sb_error_elements_num = s->s_max_outstanding_requests; 164 165 dma_addr = PQIALIGN_TYPED(o->dma_addr, SIS_BASE_STRUCT_ALIGNMENT, 166 void *); 167 (void) memset(¶ms, 0, sizeof (params)); 168 params.mailbox[1] = (uint32_t)(uintptr_t)dma_addr; 169 params.mailbox[2] = (uint32_t)((uint64_t)((uintptr_t)dma_addr) >> 32); 170 params.mailbox[3] = sizeof (*base); 171 (void) ddi_dma_sync(o->handle, 0, 0, DDI_DMA_SYNC_FORDEV); 172 rc = sis_send_sync_cmd(s, SIS_CMD_INIT_BASE_STRUCT_ADDRESS, ¶ms); 173 174 pqi_free_single(s, o); 175 176 return (rc); 177 } 178 179 /* 180 * Support functions for the visible legacy functions 181 */ 182 static boolean_t 183 sis_send_sync_cmd(pqi_state_t *s, uint32_t cmd, 184 sis_sync_cmd_params_t *params) 185 { 186 uint32_t i; 187 uint32_t doorbell; 188 uint32_t cmd_status; 189 190 /* Write the command to mailbox 0. */ 191 S32(s, sis_mailbox[0], cmd); 192 193 /* 194 * Write the command parameters to mailboxes 1-4 (mailbox 5 is not used 195 * when sending a command to the controller). 196 */ 197 for (i = 1; i <= 4; i++) 198 S32(s, sis_mailbox[i], params->mailbox[i]); 199 200 /* Clear the command doorbell. */ 201 S32(s, sis_ctrl_to_host_doorbell_clear, 202 SIS_CLEAR_CTRL_TO_HOST_DOORBELL); 203 204 /* Disable doorbell interrupts by masking all interrupts. */ 205 S32(s, sis_interrupt_mask, ~0); 206 207 /* 208 * Force the completion of the interrupt mask register write before 209 * submitting the command. 210 */ 211 (void) G32(s, sis_interrupt_mask); 212 213 /* Submit the command to the controller. */ 214 S32(s, sis_host_to_ctrl_doorbell, SIS_CMD_READY); 215 216 /* 217 * Poll for command completion. Note that the call to msleep() is at 218 * the top of the loop in order to give the controller time to start 219 * processing the command before we start polling. 220 */ 221 for (i = 0; i < 10000; i++) { 222 drv_usecwait(MICROSEC / MILLISEC); 223 doorbell = G32(s, sis_ctrl_to_host_doorbell); 224 if (doorbell & SIS_CMD_COMPLETE) 225 break; 226 } 227 if (i == 10000) 228 return (B_FALSE); 229 230 /* Read the command status from mailbox 0. */ 231 cmd_status = G32(s, sis_mailbox[0]); 232 if (cmd_status != SIS_CMD_STATUS_SUCCESS) 233 return (B_FALSE); 234 235 /* 236 * The command completed successfully, so save the command status and 237 * read the values returned in mailboxes 1-5. 238 */ 239 params->mailbox[0] = cmd_status; 240 for (i = 1; i < ARRAY_SIZE(params->mailbox); i++) 241 params->mailbox[i] = G32(s, sis_mailbox[i]); 242 243 return (B_TRUE); 244 } 245