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 2023 Racktop Systems, Inc. 14 */ 15 16 /* 17 * This file implementes the iport and tgtmap for physical devices on lmrc. 18 * 19 * When the phys iport is attached, a FULLSET tgtmap is created for physical 20 * devices (PDs). 21 * 22 * During attach or as a result of an async event received from the hardware, 23 * we'll get the PD list from the HBA and populate the tgtmap with what we have 24 * found. The PD list includes the SAS WWN of each device found, which we will 25 * use for the unit address. 26 * 27 * In the target activation callback, we'll retrieve the PD info from the HBA 28 * and pass it to lmrc_tgt_init(). This contains additional information such as 29 * the device and interconnect types. 30 */ 31 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 35 #include "lmrc.h" 36 #include "lmrc_reg.h" 37 #include "lmrc_raid.h" 38 #include "lmrc_phys.h" 39 40 static int lmrc_get_pdmap(lmrc_t *, lmrc_pd_map_t **); 41 static int lmrc_sync_pdmap(lmrc_t *, size_t); 42 static void lmrc_complete_sync_pdmap(lmrc_t *, lmrc_mfi_cmd_t *); 43 44 static lmrc_pd_info_t *lmrc_get_pd_info(lmrc_t *, uint16_t); 45 static void lmrc_phys_tgt_activate_cb(void *, char *, scsi_tgtmap_tgt_type_t, 46 void **); 47 static boolean_t lmrc_phys_tgt_deactivate_cb(void *, char *, 48 scsi_tgtmap_tgt_type_t, void *, scsi_tgtmap_deact_rsn_t); 49 static int lmrc_phys_update_tgtmap(lmrc_t *, lmrc_pd_list_t *); 50 51 /* 52 * lmrc_get_pdmap 53 * 54 * Get the physical device map from the firmware. Return a minimally sized copy. 55 */ 56 static int 57 lmrc_get_pdmap(lmrc_t *lmrc, lmrc_pd_map_t **pdmap) 58 { 59 uint32_t pdmap_sz = sizeof (lmrc_pd_map_t) + 60 sizeof (lmrc_pd_cfg_t) * LMRC_MAX_PHYS_DEV; 61 lmrc_mfi_cmd_t *mfi; 62 lmrc_pd_map_t *pm; 63 int ret; 64 65 mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_READ, 66 LMRC_DCMD_SYSTEM_PD_MAP_GET_INFO, pdmap_sz, 4); 67 68 if (mfi == NULL) 69 return (DDI_FAILURE); 70 71 ret = lmrc_issue_blocked_mfi(lmrc, mfi); 72 73 if (ret != DDI_SUCCESS) 74 goto out; 75 76 pm = mfi->mfi_data_dma.ld_buf; 77 78 if (pm->pm_count > LMRC_MAX_PHYS_DEV) { 79 dev_err(lmrc->l_dip, CE_WARN, 80 "!FW reports too many PDs: %d", pm->pm_count); 81 ret = DDI_FAILURE; 82 goto out; 83 } 84 85 pdmap_sz = sizeof (lmrc_pd_map_t) + 86 pm->pm_count * sizeof (lmrc_pd_cfg_t); 87 *pdmap = kmem_zalloc(pdmap_sz, KM_SLEEP); 88 bcopy(pm, *pdmap, pdmap_sz); 89 90 out: 91 lmrc_put_dcmd(lmrc, mfi); 92 return (ret); 93 } 94 95 /* 96 * lmrc_sync_pdmap 97 * 98 * Get the physical device map to the firmware. The command will complete 99 * when the firmware detects a change. 100 * 101 * mbox byte values: 102 * [0]: PEND_FLAG, delay completion until a config change pending 103 */ 104 static int 105 lmrc_sync_pdmap(lmrc_t *lmrc, size_t pd_count) 106 { 107 uint32_t pdmap_sz = sizeof (lmrc_pd_map_t) + 108 pd_count * sizeof (lmrc_pd_cfg_t); 109 lmrc_mfi_dcmd_payload_t *dcmd; 110 lmrc_mfi_cmd_t *mfi; 111 112 mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_WRITE, 113 LMRC_DCMD_SYSTEM_PD_MAP_GET_INFO, pdmap_sz, 4); 114 115 if (mfi == NULL) 116 return (DDI_FAILURE); 117 118 dcmd = &mfi->mfi_frame->mf_dcmd; 119 dcmd->md_mbox_8[0] = LMRC_DCMD_MBOX_PEND_FLAG; 120 121 mutex_enter(&mfi->mfi_lock); 122 lmrc_issue_mfi(lmrc, mfi, lmrc_complete_sync_pdmap); 123 mutex_exit(&mfi->mfi_lock); 124 125 return (DDI_SUCCESS); 126 } 127 128 /* 129 * lmrc_complete_sync_pdmap 130 * 131 * The PDMAP GET INFO command completed, most likely due to the hardware 132 * detecting a change and informing us. 133 */ 134 static void 135 lmrc_complete_sync_pdmap(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi) 136 { 137 lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr; 138 lmrc_dma_t *dma = &mfi->mfi_data_dma; 139 lmrc_pd_map_t *pm = dma->ld_buf; 140 uint32_t pdmap_sz = sizeof (lmrc_pd_map_t) + 141 lmrc->l_pdmap->pm_count * sizeof (lmrc_pd_cfg_t); 142 143 ASSERT(mutex_owned(&mfi->mfi_lock)); 144 145 if (hdr->mh_cmd_status != MFI_STAT_OK) { 146 /* Was the command aborted? */ 147 if (hdr->mh_cmd_status == MFI_STAT_NOT_FOUND) 148 return; 149 150 /* 151 * In the case of any other error, log the error and schedule 152 * a taskq to clean up the command. 153 */ 154 dev_err(lmrc->l_dip, CE_WARN, 155 "!PD map sync failed, status = %d", 156 hdr->mh_cmd_status); 157 lmrc->l_use_seqnum_jbod_fp = B_FALSE; 158 taskq_dispatch_ent(lmrc->l_taskq, (task_func_t *)lmrc_put_mfi, 159 mfi, TQ_NOSLEEP, &mfi->mfi_tqent); 160 return; 161 } 162 163 VERIFY3U(pdmap_sz, ==, dma->ld_len); 164 165 /* Update our copy of the pdmap and restart the command. */ 166 rw_enter(&lmrc->l_pdmap_lock, RW_WRITER); 167 bcopy(pm, lmrc->l_pdmap, pdmap_sz); 168 rw_exit(&lmrc->l_pdmap_lock); 169 bzero(pm, pdmap_sz); 170 lmrc_issue_mfi(lmrc, mfi, lmrc_complete_sync_pdmap); 171 } 172 173 /* 174 * lmrc_setup_pdmap 175 * 176 * Get the physical device map from the firmware, and sync it back. 177 * Replace the copy in the soft state if successful. 178 */ 179 int 180 lmrc_setup_pdmap(lmrc_t *lmrc) 181 { 182 lmrc_pd_map_t *pdmap = NULL; 183 int ret; 184 185 ret = lmrc_get_pdmap(lmrc, &pdmap); 186 if (ret != DDI_SUCCESS) 187 return (ret); 188 189 rw_enter(&lmrc->l_pdmap_lock, RW_WRITER); 190 ASSERT(lmrc->l_pdmap == NULL); 191 lmrc->l_pdmap = pdmap; 192 rw_exit(&lmrc->l_pdmap_lock); 193 194 ret = lmrc_sync_pdmap(lmrc, pdmap->pm_count); 195 return (ret); 196 } 197 198 /* 199 * lmrc_free_pdmap 200 * 201 * Free the buffer used to hold the physical device map. 202 */ 203 void 204 lmrc_free_pdmap(lmrc_t *lmrc) 205 { 206 if (lmrc->l_pdmap != NULL) { 207 uint32_t pdmap_sz = sizeof (lmrc_pd_map_t) + 208 lmrc->l_pdmap->pm_count * sizeof (lmrc_pd_cfg_t); 209 kmem_free(lmrc->l_pdmap, pdmap_sz); 210 lmrc->l_pdmap = NULL; 211 } 212 } 213 214 /* 215 * lmrc_pd_tm_capable 216 * 217 * Determine whether a PD can be sent TASK MGMT requests. By default we assume 218 * it can't, unless the the PD map indicates otherwise. 219 */ 220 boolean_t 221 lmrc_pd_tm_capable(lmrc_t *lmrc, uint16_t tgtid) 222 { 223 boolean_t tm_capable = B_FALSE; 224 225 rw_enter(&lmrc->l_pdmap_lock, RW_READER); 226 if (lmrc->l_pdmap != NULL && 227 lmrc->l_pdmap->pm_pdcfg[tgtid].pd_tgtid != LMRC_DEVHDL_INVALID && 228 lmrc->l_pdmap->pm_pdcfg[tgtid].pd_tm_capable != 0) 229 tm_capable = B_TRUE; 230 rw_exit(&lmrc->l_pdmap_lock); 231 232 return (tm_capable); 233 } 234 235 /* 236 * lmrc_get_pd_info 237 * 238 * Get physical drive info from FW. 239 */ 240 static lmrc_pd_info_t * 241 lmrc_get_pd_info(lmrc_t *lmrc, uint16_t dev_id) 242 { 243 lmrc_pd_info_t *pdinfo = NULL; 244 lmrc_mfi_cmd_t *mfi; 245 lmrc_mfi_dcmd_payload_t *dcmd; 246 int ret; 247 248 mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_READ, LMRC_DCMD_PD_GET_INFO, 249 sizeof (lmrc_pd_info_t), 1); 250 251 if (mfi == NULL) 252 return (NULL); 253 254 dcmd = &mfi->mfi_frame->mf_dcmd; 255 dcmd->md_mbox_16[0] = dev_id; 256 257 ret = lmrc_issue_blocked_mfi(lmrc, mfi); 258 259 if (ret != DDI_SUCCESS) 260 goto out; 261 262 pdinfo = kmem_zalloc(sizeof (lmrc_pd_info_t), KM_SLEEP); 263 bcopy(mfi->mfi_data_dma.ld_buf, pdinfo, sizeof (lmrc_pd_info_t)); 264 265 out: 266 lmrc_put_dcmd(lmrc, mfi); 267 return (pdinfo); 268 } 269 270 /* 271 * lmrc_phys_tgt_activate_cb 272 * 273 * Set up a tgt structure for a newly discovered PD. 274 */ 275 static void 276 lmrc_phys_tgt_activate_cb(void *tgtmap_priv, char *tgt_addr, 277 scsi_tgtmap_tgt_type_t type, void **tgt_privp) 278 { 279 lmrc_t *lmrc = tgtmap_priv; 280 lmrc_tgt_t *tgt = *tgt_privp; 281 uint16_t dev_id = tgt - lmrc->l_targets; 282 lmrc_pd_info_t *pd_info; 283 284 VERIFY(lmrc == tgt->tgt_lmrc); 285 286 dev_id -= LMRC_MAX_LD; 287 288 VERIFY3U(dev_id, <, LMRC_MAX_PD); 289 290 pd_info = lmrc_get_pd_info(lmrc, dev_id); 291 if (pd_info == NULL) 292 return; 293 294 lmrc_tgt_init(tgt, dev_id, tgt_addr, pd_info); 295 } 296 297 /* 298 * lmrc_phys_tgt_deactivate_cb 299 * 300 * Tear down the tgt structure of a PD that is no longer present. 301 */ 302 static boolean_t 303 lmrc_phys_tgt_deactivate_cb(void *tgtmap_priv, char *tgt_addr, 304 scsi_tgtmap_tgt_type_t type, void *tgt_priv, scsi_tgtmap_deact_rsn_t deact) 305 { 306 lmrc_t *lmrc = tgtmap_priv; 307 lmrc_tgt_t *tgt = tgt_priv; 308 309 VERIFY(lmrc == tgt->tgt_lmrc); 310 311 lmrc_tgt_clear(tgt); 312 313 return (B_FALSE); 314 } 315 316 /* 317 * lmrc_phys_update_tgtmap 318 * 319 * Feed the PD list into the target map. 320 */ 321 static int 322 lmrc_phys_update_tgtmap(lmrc_t *lmrc, lmrc_pd_list_t *pd_list) 323 { 324 int ret; 325 int i; 326 327 if (pd_list->pl_count > LMRC_MAX_PD) 328 return (DDI_FAILURE); 329 330 ret = scsi_hba_tgtmap_set_begin(lmrc->l_phys_tgtmap); 331 if (ret != DDI_SUCCESS) 332 return (ret); 333 334 for (i = 0; i < pd_list->pl_count; i++) { 335 lmrc_pd_addr_t *pa = &pd_list->pl_addr[i]; 336 char name[SCSI_WWN_BUFLEN]; 337 338 if (pa->pa_dev_id > LMRC_MAX_PHYS_DEV) { 339 dev_err(lmrc->l_dip, CE_WARN, 340 "!%s: invalid PD dev id %d", __func__, 341 pa->pa_dev_id); 342 goto fail; 343 } 344 345 if (scsi_wwn_to_wwnstr(pa->pa_sas_addr[0], 1, name) == NULL) 346 goto fail; 347 348 ret = scsi_hba_tgtmap_set_add(lmrc->l_phys_tgtmap, 349 SCSI_TGT_SCSI_DEVICE, name, 350 &lmrc->l_targets[pa->pa_dev_id + LMRC_MAX_LD]); 351 352 if (ret != DDI_SUCCESS) 353 goto fail; 354 } 355 356 return (scsi_hba_tgtmap_set_end(lmrc->l_phys_tgtmap, 0)); 357 358 fail: 359 (void) scsi_hba_tgtmap_set_flush(lmrc->l_raid_tgtmap); 360 return (DDI_FAILURE); 361 } 362 363 /* 364 * lmrc_get_pd_list 365 * 366 * Get the list of physical devices from the firmware and update the target map. 367 */ 368 int 369 lmrc_get_pd_list(lmrc_t *lmrc) 370 { 371 lmrc_mfi_cmd_t *mfi; 372 lmrc_mfi_dcmd_payload_t *dcmd; 373 int ret; 374 375 mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_READ, LMRC_DCMD_PD_LIST_QUERY, 376 sizeof (lmrc_pd_list_t) + sizeof (lmrc_pd_addr_t) * LMRC_MAX_PD, 1); 377 378 if (mfi == NULL) 379 return (DDI_FAILURE); 380 381 dcmd = &mfi->mfi_frame->mf_dcmd; 382 dcmd->md_mbox_8[0] = LMRC_PD_QUERY_TYPE_EXPOSED_TO_HOST; 383 384 ret = lmrc_issue_blocked_mfi(lmrc, mfi); 385 386 if (ret != DDI_SUCCESS) 387 goto out; 388 389 ret = lmrc_phys_update_tgtmap(lmrc, mfi->mfi_data_dma.ld_buf); 390 391 out: 392 lmrc_put_dcmd(lmrc, mfi); 393 return (ret); 394 } 395 396 /* 397 * lmrc_phys_aen_handler 398 * 399 * Handle AENs with locale code LMRC_EVT_LOCALE_PD. If the PD configuration 400 * changed, update the PD list and target map. 401 */ 402 403 int 404 lmrc_phys_aen_handler(lmrc_t *lmrc, lmrc_evt_t *evt) 405 { 406 int ret = DDI_SUCCESS; 407 408 switch (evt->evt_code) { 409 case LMRC_EVT_PD_INSERTED: 410 case LMRC_EVT_PD_REMOVED: 411 case LMRC_EVT_PD_CHANGED: 412 /* 413 * For any change w.r.t. the PDs, refresh the PD list. 414 */ 415 ret = lmrc_get_pd_list(lmrc); 416 break; 417 418 case LMRC_EVT_PD_PATROL_READ_PROGRESS: 419 case LMRC_EVT_PD_RESET: 420 break; 421 422 default: 423 ret = DDI_FAILURE; 424 } 425 426 return (ret); 427 } 428 429 int 430 lmrc_phys_attach(dev_info_t *dip) 431 { 432 scsi_hba_tran_t *tran = ddi_get_driver_private(dip); 433 dev_info_t *pdip = ddi_get_parent(dip); 434 lmrc_t *lmrc = ddi_get_soft_state(lmrc_state, ddi_get_instance(pdip)); 435 int ret; 436 437 VERIFY(tran != NULL); 438 VERIFY(lmrc != NULL); 439 440 if (lmrc->l_fw_fault) 441 return (DDI_FAILURE); 442 443 tran->tran_hba_private = lmrc; 444 lmrc->l_phys_dip = dip; 445 446 ret = scsi_hba_tgtmap_create(dip, SCSI_TM_FULLSET, MICROSEC, 447 2 * MICROSEC, lmrc, lmrc_phys_tgt_activate_cb, 448 lmrc_phys_tgt_deactivate_cb, &lmrc->l_phys_tgtmap); 449 if (ret != DDI_SUCCESS) 450 return (DDI_FAILURE); 451 452 if (lmrc->l_use_seqnum_jbod_fp) 453 if (lmrc_setup_pdmap(lmrc) != DDI_SUCCESS) 454 lmrc->l_use_seqnum_jbod_fp = B_FALSE; 455 456 ret = lmrc_get_pd_list(lmrc); 457 if (ret != DDI_SUCCESS) { 458 dev_err(lmrc->l_dip, CE_WARN, "!Failed to get PD list."); 459 return (ret); 460 } 461 462 return (DDI_SUCCESS); 463 } 464 465 int 466 lmrc_phys_detach(dev_info_t *dip) 467 { 468 dev_info_t *pdip = ddi_get_parent(dip); 469 lmrc_t *lmrc = ddi_get_soft_state(lmrc_state, ddi_get_instance(pdip)); 470 471 VERIFY(lmrc != NULL); 472 473 if (lmrc->l_phys_tgtmap != NULL) { 474 scsi_hba_tgtmap_destroy(lmrc->l_phys_tgtmap); 475 lmrc->l_phys_tgtmap = NULL; 476 } 477 478 lmrc->l_phys_dip = NULL; 479 480 return (DDI_SUCCESS); 481 } 482