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 #pragma pack(1) 34 /* used for passing command parameters/results when issuing SIS commands */ 35 typedef struct sis_sync_cmd_params { 36 uint32_t mailbox[6]; /* mailboxes 0-5 */ 37 } sis_sync_cmd_params_t; 38 39 #define SIS_BASE_STRUCT_REVISION 9 40 41 typedef struct sis_base_struct { 42 uint32_t sb_revision; 43 uint32_t sb_flags; 44 uint32_t sb_error_buffer_paddr_low; 45 uint32_t sb_error_buffer_paddr_high; 46 uint32_t sb_error_elements_len; 47 uint32_t sb_error_elements_num; 48 } sis_base_struct_t; 49 #pragma pack() 50 51 /* ---- Forward declaration for support functions ---- */ 52 static boolean_t sis_send_sync_cmd(pqi_state_t s, uint32_t cmd, 53 sis_sync_cmd_params_t *params); 54 55 uint32_t 56 sis_read_scratch(pqi_state_t s) 57 { 58 return (G32(s, sis_driver_scratch)); 59 } 60 61 void 62 sis_write_scratch(pqi_state_t s, int mode) 63 { 64 S32(s, sis_driver_scratch, mode); 65 } 66 67 boolean_t 68 sis_reenable_mode(pqi_state_t s) 69 { 70 int loop_count; 71 uint32_t doorbell; 72 73 S32(s, sis_host_to_ctrl_doorbell, SIS_REENABLE_SIS_MODE); 74 75 for (loop_count = 0; loop_count < 1000; loop_count++) { 76 doorbell = G32(s, sis_ctrl_to_host_doorbell); 77 if ((doorbell & SIS_REENABLE_SIS_MODE) == 0) { 78 return (B_TRUE); 79 } 80 drv_usecwait(1000); /* ---- Wait 1ms ---- */ 81 } 82 return (B_FALSE); 83 } 84 85 boolean_t 86 sis_wait_for_ctrl_ready(pqi_state_t s) 87 { 88 int loop_count; 89 uint32_t status; 90 91 for (loop_count = 0; loop_count < 1000; loop_count++) { 92 status = G32(s, sis_firmware_status); 93 if (status & SIS_CTRL_KERNEL_PANIC) 94 return (B_FALSE); 95 if (status & SIS_CTRL_KERNEL_UP) 96 return (B_TRUE); 97 drv_usecwait(1000); /* ---- Wait 1ms ---- */ 98 } 99 return (B_FALSE); 100 } 101 102 /* 103 * sis_get_ctrl_props -- Verify we're talking to controller that speaks PQI 104 */ 105 boolean_t 106 sis_get_ctrl_props(pqi_state_t s) 107 { 108 sis_sync_cmd_params_t p; 109 uint32_t property; 110 uint32_t extended_property; 111 112 (void) memset(&p, 0, sizeof (p)); 113 if (sis_send_sync_cmd(s, SIS_CMD_GET_ADAPTER_PROPERTIES, &p) == B_FALSE) 114 return (B_FALSE); 115 116 property = p.mailbox[1]; 117 if (!(property & SIS_EXTENDED_PROPERTIES_SUPPORTED)) 118 return (B_FALSE); 119 120 extended_property = p.mailbox[4]; 121 if ((extended_property & SIS_REQUIRED_EXTENDED_PROPERTIES) != 122 SIS_REQUIRED_EXTENDED_PROPERTIES) 123 return (B_FALSE); 124 125 return (B_TRUE); 126 } 127 128 boolean_t 129 sis_get_pqi_capabilities(pqi_state_t s) 130 { 131 sis_sync_cmd_params_t p; 132 133 (void) memset(&p, 0, sizeof (p)); 134 if (sis_send_sync_cmd(s, SIS_CMD_GET_PQI_CAPABILITIES, &p) == B_FALSE) 135 return (B_FALSE); 136 137 s->s_max_sg_entries = p.mailbox[1]; 138 s->s_max_xfer_size = p.mailbox[2]; 139 s->s_max_outstanding_requests = p.mailbox[3]; 140 s->s_config_table_offset = p.mailbox[4]; 141 s->s_config_table_len = p.mailbox[5]; 142 return (B_TRUE); 143 } 144 145 #define SIS_ROUNDUP(a, align, type) \ 146 (type)((((uintptr_t)(a) + align - 1) & ~align)) 147 148 boolean_t 149 sis_init_base_struct_addr(pqi_state_t s) 150 { 151 sis_base_struct_t *base; 152 pqi_dma_overhead_t *o; 153 sis_sync_cmd_params_t params; 154 boolean_t rc; 155 void *dma_addr; 156 157 o = pqi_alloc_single(s, sizeof (*base) + SIS_BASE_STRUCT_ALIGNMENT); 158 if (o == NULL) 159 return (B_FALSE); 160 161 base = PQIALIGN_TYPED(o->alloc_memory, SIS_BASE_STRUCT_ALIGNMENT, 162 sis_base_struct_t *); 163 base->sb_revision = SIS_BASE_STRUCT_REVISION; 164 base->sb_error_buffer_paddr_low = (uint32_t)s->s_error_dma->dma_addr; 165 base->sb_error_buffer_paddr_high = 166 (uint32_t)(s->s_error_dma->dma_addr >> 32); 167 base->sb_error_elements_len = PQI_ERROR_BUFFER_ELEMENT_LENGTH; 168 base->sb_error_elements_num = s->s_max_outstanding_requests; 169 170 dma_addr = PQIALIGN_TYPED(o->dma_addr, SIS_BASE_STRUCT_ALIGNMENT, 171 void *); 172 (void) memset(¶ms, 0, sizeof (params)); 173 params.mailbox[1] = (uint32_t)(intptr_t)dma_addr; 174 params.mailbox[2] = (uint32_t)((uint64_t)((intptr_t)dma_addr) >> 32); 175 params.mailbox[3] = sizeof (*base); 176 (void) ddi_dma_sync(o->handle, 0, 0, DDI_DMA_SYNC_FORDEV); 177 rc = sis_send_sync_cmd(s, SIS_CMD_INIT_BASE_STRUCT_ADDRESS, ¶ms); 178 179 pqi_free_single(s, o); 180 181 return (rc); 182 } 183 184 /* 185 * []------------------------------------------------------------[] 186 * | Support functions for the visable legacy fucntions | 187 * []------------------------------------------------------------[] 188 */ 189 static boolean_t 190 sis_send_sync_cmd(pqi_state_t s, uint32_t cmd, 191 sis_sync_cmd_params_t *params) 192 { 193 uint32_t i; 194 uint32_t doorbell; 195 uint32_t cmd_status; 196 197 /* Write the command to mailbox 0. */ 198 S32(s, sis_mailbox[0], cmd); 199 200 /* 201 * Write the command parameters to mailboxes 1-4 (mailbox 5 is not used 202 * when sending a command to the controller). 203 */ 204 for (i = 1; i <= 4; i++) 205 S32(s, sis_mailbox[i], params->mailbox[i]); 206 207 /* Clear the command doorbell. */ 208 S32(s, sis_ctrl_to_host_doorbell_clear, 209 SIS_CLEAR_CTRL_TO_HOST_DOORBELL); 210 211 /* Disable doorbell interrupts by masking all interrupts. */ 212 S32(s, sis_interrupt_mask, ~0); 213 214 /* 215 * Force the completion of the interrupt mask register write before 216 * submitting the command. 217 */ 218 (void) G32(s, sis_interrupt_mask); 219 220 /* Submit the command to the controller. */ 221 S32(s, sis_host_to_ctrl_doorbell, SIS_CMD_READY); 222 223 /* 224 * Poll for command completion. Note that the call to msleep() is at 225 * the top of the loop in order to give the controller time to start 226 * processing the command before we start polling. 227 */ 228 for (i = 0; i < 10000; i++) { 229 drv_usecwait(1000); 230 doorbell = G32(s, sis_ctrl_to_host_doorbell); 231 if (doorbell & SIS_CMD_COMPLETE) 232 break; 233 } 234 if (i == 10000) 235 return (B_FALSE); 236 237 /* Read the command status from mailbox 0. */ 238 cmd_status = G32(s, sis_mailbox[0]); 239 if (cmd_status != SIS_CMD_STATUS_SUCCESS) 240 return (B_FALSE); 241 242 /* 243 * The command completed successfully, so save the command status and 244 * read the values returned in mailboxes 1-5. 245 */ 246 params->mailbox[0] = cmd_status; 247 for (i = 1; i < ARRAY_SIZE(params->mailbox); i++) 248 params->mailbox[i] = G32(s, sis_mailbox[i]); 249 250 return (B_TRUE); 251 } 252