11e091e43SHans Rosenfeld /*
21e091e43SHans Rosenfeld  * This file and its contents are supplied under the terms of the
31e091e43SHans Rosenfeld  * Common Development and Distribution License ("CDDL"), version 1.0.
41e091e43SHans Rosenfeld  * You may only use this file in accordance with the terms of version
51e091e43SHans Rosenfeld  * 1.0 of the CDDL.
61e091e43SHans Rosenfeld  *
71e091e43SHans Rosenfeld  * A full copy of the text of the CDDL should have accompanied this
81e091e43SHans Rosenfeld  * source.  A copy of the CDDL is also available via the Internet at
91e091e43SHans Rosenfeld  * http://www.illumos.org/license/CDDL.
101e091e43SHans Rosenfeld  */
111e091e43SHans Rosenfeld 
121e091e43SHans Rosenfeld /*
13d39213d9SHans Rosenfeld  * Copyright 2024 Racktop Systems, Inc.
141e091e43SHans Rosenfeld  */
151e091e43SHans Rosenfeld 
161e091e43SHans Rosenfeld /*
171e091e43SHans Rosenfeld  * This file implements the RAID iport and tgtmap of lmrc.
181e091e43SHans Rosenfeld  *
191e091e43SHans Rosenfeld  * When the RAID iport is attached, a FULLSET tgtmap is created for RAID
201e091e43SHans Rosenfeld  * devices (LDs). This does not only include RAID volumes, as one would expect,
211e091e43SHans Rosenfeld  * but also physical disk on some controllers in JBOD mode.
221e091e43SHans Rosenfeld  *
231e091e43SHans Rosenfeld  * During attach or as a result of an async event received from the hardware,
241e091e43SHans Rosenfeld  * we'll get the LD list from the HBA and populate the tgtmap with what we have
251e091e43SHans Rosenfeld  * found. For each LD we'll try to get the SAS WWN by sending an INQUIRY for
261e091e43SHans Rosenfeld  * VPD 0x83, setting up a temporary struct scsi_device to be able to use the
271e091e43SHans Rosenfeld  * normal SCSI I/O code path despite the device not being known to the system
281e091e43SHans Rosenfeld  * at this point.
291e091e43SHans Rosenfeld  *
301e091e43SHans Rosenfeld  * If the device has a SAS WWN, this will be used as device address. Otherwise
311e091e43SHans Rosenfeld  * we'll use the internal target ID the HBA uses.
321e091e43SHans Rosenfeld  *
331e091e43SHans Rosenfeld  * The target activate and deactivate callbacks for RAID devices are kept really
341e091e43SHans Rosenfeld  * simple, just calling the common lmrc_tgt init/clear functions.
351e091e43SHans Rosenfeld  */
361e091e43SHans Rosenfeld 
371e091e43SHans Rosenfeld #include <sys/ddi.h>
381e091e43SHans Rosenfeld #include <sys/sunddi.h>
391e091e43SHans Rosenfeld 
40*98f0a994SHans Rosenfeld #include <sys/scsi/adapters/mfi/mfi.h>
41*98f0a994SHans Rosenfeld #include <sys/scsi/adapters/mfi/mfi_evt.h>
42*98f0a994SHans Rosenfeld #include <sys/scsi/adapters/mfi/mfi_ld.h>
43*98f0a994SHans Rosenfeld 
441e091e43SHans Rosenfeld #include "lmrc.h"
451e091e43SHans Rosenfeld #include "lmrc_reg.h"
461e091e43SHans Rosenfeld #include "lmrc_raid.h"
471e091e43SHans Rosenfeld 
481e091e43SHans Rosenfeld static int lmrc_get_raidmap(lmrc_t *, lmrc_fw_raid_map_t **);
491e091e43SHans Rosenfeld static int lmrc_sync_raidmap(lmrc_t *);
501e091e43SHans Rosenfeld static void lmrc_sync_raidmap_again(lmrc_t *, lmrc_mfi_cmd_t *);
511e091e43SHans Rosenfeld static void lmrc_complete_sync_raidmap(lmrc_t *, lmrc_mfi_cmd_t *);
521e091e43SHans Rosenfeld static int lmrc_validate_raidmap(lmrc_t *, lmrc_fw_raid_map_t *);
531e091e43SHans Rosenfeld 
541e091e43SHans Rosenfeld static void lmrc_raid_tgt_activate_cb(void *, char *, scsi_tgtmap_tgt_type_t,
551e091e43SHans Rosenfeld     void **);
561e091e43SHans Rosenfeld static boolean_t lmrc_raid_tgt_deactivate_cb(void *, char *,
571e091e43SHans Rosenfeld     scsi_tgtmap_tgt_type_t, void *, scsi_tgtmap_deact_rsn_t);
581e091e43SHans Rosenfeld static struct buf *lmrc_raid_send_inquiry(lmrc_t *, lmrc_tgt_t *, uint8_t,
591e091e43SHans Rosenfeld     uint8_t);
601e091e43SHans Rosenfeld static uint64_t lmrc_raid_get_wwn(lmrc_t *, uint8_t);
61*98f0a994SHans Rosenfeld static int lmrc_raid_update_tgtmap(lmrc_t *, mfi_ld_tgtid_list_t *);
621e091e43SHans Rosenfeld 
631e091e43SHans Rosenfeld 
641e091e43SHans Rosenfeld /*
651e091e43SHans Rosenfeld  * lmrc_get_raidmap
661e091e43SHans Rosenfeld  *
671e091e43SHans Rosenfeld  * Get the RAID map from firmware. Return a minimally sized copy.
681e091e43SHans Rosenfeld  */
691e091e43SHans Rosenfeld static int
lmrc_get_raidmap(lmrc_t * lmrc,lmrc_fw_raid_map_t ** raidmap)701e091e43SHans Rosenfeld lmrc_get_raidmap(lmrc_t *lmrc, lmrc_fw_raid_map_t **raidmap)
711e091e43SHans Rosenfeld {
721e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi;
731e091e43SHans Rosenfeld 	lmrc_fw_raid_map_t *rm;
741e091e43SHans Rosenfeld 	int ret;
751e091e43SHans Rosenfeld 
76*98f0a994SHans Rosenfeld 	mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_READ, MFI_DCMD_LD_MAP_GET_INFO,
771e091e43SHans Rosenfeld 	    lmrc->l_max_map_sz, 4);
781e091e43SHans Rosenfeld 
791e091e43SHans Rosenfeld 	if (mfi == NULL)
801e091e43SHans Rosenfeld 		return (DDI_FAILURE);
811e091e43SHans Rosenfeld 
821e091e43SHans Rosenfeld 	ret = lmrc_issue_blocked_mfi(lmrc, mfi);
831e091e43SHans Rosenfeld 
841e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
851e091e43SHans Rosenfeld 		goto out;
861e091e43SHans Rosenfeld 
871e091e43SHans Rosenfeld 	(void) ddi_dma_sync(mfi->mfi_data_dma.ld_hdl, 0,
881e091e43SHans Rosenfeld 	    mfi->mfi_data_dma.ld_len, DDI_DMA_SYNC_FORKERNEL);
891e091e43SHans Rosenfeld 
901e091e43SHans Rosenfeld 	rm = mfi->mfi_data_dma.ld_buf;
911e091e43SHans Rosenfeld 	if (rm->rm_raidmap_sz > lmrc->l_max_map_sz) {
921e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN,
931e091e43SHans Rosenfeld 		    "!FW reports a too large RAID map size: %d",
941e091e43SHans Rosenfeld 		    rm->rm_raidmap_sz);
951e091e43SHans Rosenfeld 		ret = DDI_FAILURE;
961e091e43SHans Rosenfeld 		goto out;
971e091e43SHans Rosenfeld 	}
981e091e43SHans Rosenfeld 
991e091e43SHans Rosenfeld 	*raidmap = kmem_zalloc(rm->rm_raidmap_sz, KM_SLEEP);
1001e091e43SHans Rosenfeld 	bcopy(rm, *raidmap, rm->rm_raidmap_sz);
1011e091e43SHans Rosenfeld 
1021e091e43SHans Rosenfeld out:
1031e091e43SHans Rosenfeld 	lmrc_put_dcmd(lmrc, mfi);
1041e091e43SHans Rosenfeld 
1051e091e43SHans Rosenfeld 	return (ret);
1061e091e43SHans Rosenfeld }
1071e091e43SHans Rosenfeld 
1081e091e43SHans Rosenfeld /*
1091e091e43SHans Rosenfeld  * lmrc_sync_raidmap
1101e091e43SHans Rosenfeld  *
1111e091e43SHans Rosenfeld  * Generate a LD target map from the RAID map and send that to the firmware.
1121e091e43SHans Rosenfeld  * The command will complete when firmware detects a change, returning a new
1131e091e43SHans Rosenfeld  * RAID map in the DMA memory. The size of the RAID map isn't expected to
1141e091e43SHans Rosenfeld  * change, so thats what's used as size for the DMA memory.
1151e091e43SHans Rosenfeld  *
1161e091e43SHans Rosenfeld  * mbox byte values:
1171e091e43SHans Rosenfeld  * [0]:		number of LDs
1181e091e43SHans Rosenfeld  * [1]:		PEND_FLAG, delay completion until a config change pending
1191e091e43SHans Rosenfeld  */
1201e091e43SHans Rosenfeld static int
lmrc_sync_raidmap(lmrc_t * lmrc)1211e091e43SHans Rosenfeld lmrc_sync_raidmap(lmrc_t *lmrc)
1221e091e43SHans Rosenfeld {
1231e091e43SHans Rosenfeld 	lmrc_fw_raid_map_t *rm;
1241e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi;
125*98f0a994SHans Rosenfeld 	mfi_dcmd_payload_t *dcmd;
1261e091e43SHans Rosenfeld 
1271e091e43SHans Rosenfeld 	rw_enter(&lmrc->l_raidmap_lock, RW_READER);
1281e091e43SHans Rosenfeld 	rm = lmrc->l_raidmap;
129*98f0a994SHans Rosenfeld 	mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_WRITE, MFI_DCMD_LD_MAP_GET_INFO,
130*98f0a994SHans Rosenfeld 	    rm->rm_raidmap_sz, 4);
1311e091e43SHans Rosenfeld 
1321e091e43SHans Rosenfeld 	if (mfi == NULL) {
1331e091e43SHans Rosenfeld 		rw_exit(&lmrc->l_raidmap_lock);
1341e091e43SHans Rosenfeld 		return (DDI_FAILURE);
1351e091e43SHans Rosenfeld 	}
1361e091e43SHans Rosenfeld 
1371e091e43SHans Rosenfeld 	dcmd = &mfi->mfi_frame->mf_dcmd;
1381e091e43SHans Rosenfeld 	dcmd->md_mbox_8[0] = rm->rm_ld_count;
139*98f0a994SHans Rosenfeld 	dcmd->md_mbox_8[1] = MFI_DCMD_MBOX_PEND_FLAG;
1401e091e43SHans Rosenfeld 	rw_exit(&lmrc->l_raidmap_lock);
1411e091e43SHans Rosenfeld 
1421e091e43SHans Rosenfeld 	mutex_enter(&mfi->mfi_lock);
1431e091e43SHans Rosenfeld 	lmrc_sync_raidmap_again(lmrc, mfi);
1441e091e43SHans Rosenfeld 	mutex_exit(&mfi->mfi_lock);
1451e091e43SHans Rosenfeld 
1461e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
1471e091e43SHans Rosenfeld }
1481e091e43SHans Rosenfeld 
1491e091e43SHans Rosenfeld /*
1501e091e43SHans Rosenfeld  * lmrc_sync_raidmap_again
1511e091e43SHans Rosenfeld  *
1521e091e43SHans Rosenfeld  * Called by lmrc_sync_raidmap() and lmrc_complete_sync_raidmap() to avoid
1531e091e43SHans Rosenfeld  * deallocating and reallocating DMA memory and MFI command in the latter,
1541e091e43SHans Rosenfeld  * while executing in interrupt context.
1551e091e43SHans Rosenfeld  *
1561e091e43SHans Rosenfeld  * This is doing the actual work of building the LD target map for FW and
1571e091e43SHans Rosenfeld  * issuing the command, but it does no sleeping allocations and it cannot fail.
1581e091e43SHans Rosenfeld  */
1591e091e43SHans Rosenfeld static void
lmrc_sync_raidmap_again(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi)1601e091e43SHans Rosenfeld lmrc_sync_raidmap_again(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi)
1611e091e43SHans Rosenfeld {
1621e091e43SHans Rosenfeld 	lmrc_fw_raid_map_t *rm;
1631e091e43SHans Rosenfeld 	lmrc_dma_t *dma = &mfi->mfi_data_dma;
164*98f0a994SHans Rosenfeld 	mfi_ld_ref_t *ld_sync = dma->ld_buf;
165*98f0a994SHans Rosenfeld 	mfi_dcmd_payload_t *dcmd = &mfi->mfi_frame->mf_dcmd;
1661e091e43SHans Rosenfeld 	uint32_t ld;
1671e091e43SHans Rosenfeld 
1681e091e43SHans Rosenfeld 	bzero(dma->ld_buf, dma->ld_len);
1691e091e43SHans Rosenfeld 
1701e091e43SHans Rosenfeld 	rw_enter(&lmrc->l_raidmap_lock, RW_READER);
1711e091e43SHans Rosenfeld 	rm = lmrc->l_raidmap;
1721e091e43SHans Rosenfeld 	for (ld = 0; ld < rm->rm_ld_count; ld++) {
1731e091e43SHans Rosenfeld 		lmrc_ld_raid_t *lr = lmrc_ld_raid_get(ld, rm);
1741e091e43SHans Rosenfeld 
1751e091e43SHans Rosenfeld 		ASSERT(lr != NULL);
1761e091e43SHans Rosenfeld 
177*98f0a994SHans Rosenfeld 		ld_sync[ld].lr_tgtid = lr->lr_target_id;
178*98f0a994SHans Rosenfeld 		ld_sync[ld].lr_seqnum = lr->lr_seq_num;
1791e091e43SHans Rosenfeld 	}
1801e091e43SHans Rosenfeld 	dcmd->md_mbox_8[0] = rm->rm_ld_count;
1811e091e43SHans Rosenfeld 	rw_exit(&lmrc->l_raidmap_lock);
1821e091e43SHans Rosenfeld 
1831e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mfi->mfi_lock));
1841e091e43SHans Rosenfeld 	lmrc_issue_mfi(lmrc, mfi, lmrc_complete_sync_raidmap);
1851e091e43SHans Rosenfeld }
1861e091e43SHans Rosenfeld 
1871e091e43SHans Rosenfeld /*
1881e091e43SHans Rosenfeld  * lmrc_complete_sync_raidmap
1891e091e43SHans Rosenfeld  *
1901e091e43SHans Rosenfeld  * The firmware completed our request to sync the LD target map, indicating
1911e091e43SHans Rosenfeld  * that the configuration has changed. There's a new RAID map in the DMA memory.
1921e091e43SHans Rosenfeld  */
1931e091e43SHans Rosenfeld static void
lmrc_complete_sync_raidmap(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi)1941e091e43SHans Rosenfeld lmrc_complete_sync_raidmap(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi)
1951e091e43SHans Rosenfeld {
196*98f0a994SHans Rosenfeld 	mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
1971e091e43SHans Rosenfeld 	lmrc_dma_t *dma = &mfi->mfi_data_dma;
1981e091e43SHans Rosenfeld 	lmrc_fw_raid_map_t *rm = dma->ld_buf;
1991e091e43SHans Rosenfeld 
2001e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mfi->mfi_lock));
2011e091e43SHans Rosenfeld 
2021e091e43SHans Rosenfeld 	if (hdr->mh_cmd_status != MFI_STAT_OK) {
2031e091e43SHans Rosenfeld 		/* Was the command aborted? */
2041e091e43SHans Rosenfeld 		if (hdr->mh_cmd_status == MFI_STAT_NOT_FOUND)
2051e091e43SHans Rosenfeld 			return;
2061e091e43SHans Rosenfeld 
2071e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN,
2081e091e43SHans Rosenfeld 		    "!LD target map sync failed, status = %d",
2091e091e43SHans Rosenfeld 		    hdr->mh_cmd_status);
2101e091e43SHans Rosenfeld 		taskq_dispatch_ent(lmrc->l_taskq, (task_func_t *)lmrc_put_mfi,
2111e091e43SHans Rosenfeld 		    mfi, TQ_NOSLEEP, &mfi->mfi_tqent);
2121e091e43SHans Rosenfeld 		return;
2131e091e43SHans Rosenfeld 	}
2141e091e43SHans Rosenfeld 
2151e091e43SHans Rosenfeld 	if (lmrc_validate_raidmap(lmrc, rm) != DDI_SUCCESS)
2161e091e43SHans Rosenfeld 		return;
2171e091e43SHans Rosenfeld 
2181e091e43SHans Rosenfeld 	rw_enter(&lmrc->l_raidmap_lock, RW_WRITER);
2191e091e43SHans Rosenfeld 	VERIFY3U(lmrc->l_raidmap->rm_raidmap_sz, ==, dma->ld_len);
2201e091e43SHans Rosenfeld 	bcopy(rm, lmrc->l_raidmap, lmrc->l_raidmap->rm_raidmap_sz);
2211e091e43SHans Rosenfeld 	rw_exit(&lmrc->l_raidmap_lock);
2221e091e43SHans Rosenfeld 	lmrc_sync_raidmap_again(lmrc, mfi);
2231e091e43SHans Rosenfeld }
2241e091e43SHans Rosenfeld 
2251e091e43SHans Rosenfeld /*
2261e091e43SHans Rosenfeld  * lmrc_validata_raidmap
2271e091e43SHans Rosenfeld  *
2281e091e43SHans Rosenfeld  * Basic sanity checks of a RAID map as returned by the firmware.
2291e091e43SHans Rosenfeld  */
2301e091e43SHans Rosenfeld static int
lmrc_validate_raidmap(lmrc_t * lmrc,lmrc_fw_raid_map_t * raidmap)2311e091e43SHans Rosenfeld lmrc_validate_raidmap(lmrc_t *lmrc, lmrc_fw_raid_map_t *raidmap)
2321e091e43SHans Rosenfeld {
2331e091e43SHans Rosenfeld 	lmrc_raid_map_desc_t *desc;
2341e091e43SHans Rosenfeld 	int i;
2351e091e43SHans Rosenfeld 
2361e091e43SHans Rosenfeld 	/* Do a basic sanity check of the descriptor table offset and sizes. */
2371e091e43SHans Rosenfeld 	if (raidmap->rm_desc_table_off > raidmap->rm_raidmap_sz)
2381e091e43SHans Rosenfeld 		return (DDI_FAILURE);
2391e091e43SHans Rosenfeld 	if (raidmap->rm_desc_table_off + raidmap->rm_desc_table_sz >
2401e091e43SHans Rosenfeld 	    raidmap->rm_raidmap_sz)
2411e091e43SHans Rosenfeld 		return (DDI_FAILURE);
2421e091e43SHans Rosenfeld 	if (raidmap->rm_desc_table_nelem != LMRC_RAID_MAP_DESC_TYPES_COUNT)
2431e091e43SHans Rosenfeld 		return (DDI_FAILURE);
2441e091e43SHans Rosenfeld 	if (raidmap->rm_desc_table_sz !=
2451e091e43SHans Rosenfeld 	    raidmap->rm_desc_table_nelem * sizeof (lmrc_raid_map_desc_t))
2461e091e43SHans Rosenfeld 		return (DDI_FAILURE);
2471e091e43SHans Rosenfeld 
2481e091e43SHans Rosenfeld 	desc = (lmrc_raid_map_desc_t *)
2491e091e43SHans Rosenfeld 	    ((uint8_t *)raidmap + raidmap->rm_desc_table_off);
2501e091e43SHans Rosenfeld 
2511e091e43SHans Rosenfeld 	/* Fill in descriptor pointers */
2521e091e43SHans Rosenfeld 	for (i = 0; i < raidmap->rm_desc_table_nelem; i++) {
2531e091e43SHans Rosenfeld 		/* Do a basic sanity check of the descriptor itself. */
2541e091e43SHans Rosenfeld 		if (desc[i].rmd_type >= LMRC_RAID_MAP_DESC_TYPES_COUNT)
2551e091e43SHans Rosenfeld 			return (DDI_FAILURE);
2561e091e43SHans Rosenfeld 		if (desc[i].rmd_off + raidmap->rm_desc_table_off +
2571e091e43SHans Rosenfeld 		    raidmap->rm_desc_table_sz >
2581e091e43SHans Rosenfeld 		    raidmap->rm_raidmap_sz)
2591e091e43SHans Rosenfeld 			return (DDI_FAILURE);
2601e091e43SHans Rosenfeld 		if (desc[i].rmd_off + desc[i].rmd_bufsz +
2611e091e43SHans Rosenfeld 		    raidmap->rm_desc_table_off + raidmap->rm_desc_table_sz >
2621e091e43SHans Rosenfeld 		    raidmap->rm_raidmap_sz)
2631e091e43SHans Rosenfeld 			return (DDI_FAILURE);
2641e091e43SHans Rosenfeld 
2651e091e43SHans Rosenfeld 		raidmap->rm_desc_ptrs[desc[i].rmd_type] = (void *)
2661e091e43SHans Rosenfeld 		    ((uint8_t *)desc + raidmap->rm_desc_table_sz +
2671e091e43SHans Rosenfeld 		    desc[i].rmd_off);
2681e091e43SHans Rosenfeld 	}
2691e091e43SHans Rosenfeld 
2701e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
2711e091e43SHans Rosenfeld }
2721e091e43SHans Rosenfeld 
2731e091e43SHans Rosenfeld /*
2741e091e43SHans Rosenfeld  * lmrc_setup_raidmap
2751e091e43SHans Rosenfeld  *
2761e091e43SHans Rosenfeld  * Get the crrent RAID map from the firmware. If it validates, replace the
2771e091e43SHans Rosenfeld  * copy in the soft state and send a LD target map to the firmware.
2781e091e43SHans Rosenfeld  */
2791e091e43SHans Rosenfeld int
lmrc_setup_raidmap(lmrc_t * lmrc)2801e091e43SHans Rosenfeld lmrc_setup_raidmap(lmrc_t *lmrc)
2811e091e43SHans Rosenfeld {
2821e091e43SHans Rosenfeld 	lmrc_fw_raid_map_t *raidmap;
2831e091e43SHans Rosenfeld 	int ret;
2841e091e43SHans Rosenfeld 
2851e091e43SHans Rosenfeld 	ret = lmrc_get_raidmap(lmrc, &raidmap);
2861e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
2871e091e43SHans Rosenfeld 		return (ret);
2881e091e43SHans Rosenfeld 
2891e091e43SHans Rosenfeld 	ret = lmrc_validate_raidmap(lmrc, raidmap);
2901e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS) {
2911e091e43SHans Rosenfeld 		kmem_free(raidmap, raidmap->rm_raidmap_sz);
2921e091e43SHans Rosenfeld 		return (ret);
2931e091e43SHans Rosenfeld 	}
2941e091e43SHans Rosenfeld 
2951e091e43SHans Rosenfeld 	rw_enter(&lmrc->l_raidmap_lock, RW_WRITER);
2961e091e43SHans Rosenfeld 	lmrc_free_raidmap(lmrc);
2971e091e43SHans Rosenfeld 	lmrc->l_raidmap = raidmap;
2981e091e43SHans Rosenfeld 	rw_exit(&lmrc->l_raidmap_lock);
2991e091e43SHans Rosenfeld 
3001e091e43SHans Rosenfeld 	ret = lmrc_sync_raidmap(lmrc);
3011e091e43SHans Rosenfeld 
3021e091e43SHans Rosenfeld 	return (ret);
3031e091e43SHans Rosenfeld }
3041e091e43SHans Rosenfeld 
3051e091e43SHans Rosenfeld /*
3061e091e43SHans Rosenfeld  * lmrc_free_raidmap
3071e091e43SHans Rosenfeld  *
3081e091e43SHans Rosenfeld  * Free the buffer used to hold the RAID map.
3091e091e43SHans Rosenfeld  */
3101e091e43SHans Rosenfeld void
lmrc_free_raidmap(lmrc_t * lmrc)3111e091e43SHans Rosenfeld lmrc_free_raidmap(lmrc_t *lmrc)
3121e091e43SHans Rosenfeld {
3131e091e43SHans Rosenfeld 	if (lmrc->l_raidmap != NULL) {
3141e091e43SHans Rosenfeld 		kmem_free(lmrc->l_raidmap, lmrc->l_raidmap->rm_raidmap_sz);
3151e091e43SHans Rosenfeld 		lmrc->l_raidmap = NULL;
3161e091e43SHans Rosenfeld 	}
3171e091e43SHans Rosenfeld }
3181e091e43SHans Rosenfeld 
3191e091e43SHans Rosenfeld /*
3201e091e43SHans Rosenfeld  * lmrc_ld_tm_capable
3211e091e43SHans Rosenfeld  */
3221e091e43SHans Rosenfeld boolean_t
lmrc_ld_tm_capable(lmrc_t * lmrc,uint16_t tgtid)3231e091e43SHans Rosenfeld lmrc_ld_tm_capable(lmrc_t *lmrc, uint16_t tgtid)
3241e091e43SHans Rosenfeld {
3251e091e43SHans Rosenfeld 	boolean_t tm_capable = B_FALSE;
3261e091e43SHans Rosenfeld 
3271e091e43SHans Rosenfeld 	rw_enter(&lmrc->l_raidmap_lock, RW_READER);
3281e091e43SHans Rosenfeld 	if (lmrc->l_raidmap != NULL) {
3291e091e43SHans Rosenfeld 		uint16_t ld_id = lmrc_ld_id_get(tgtid, lmrc->l_raidmap);
3301e091e43SHans Rosenfeld 		lmrc_ld_raid_t *lr = lmrc_ld_raid_get(ld_id, lmrc->l_raidmap);
3311e091e43SHans Rosenfeld 
3321e091e43SHans Rosenfeld 		if (lr->lr_cap.lc_tm_cap != 0)
3331e091e43SHans Rosenfeld 			tm_capable = B_TRUE;
3341e091e43SHans Rosenfeld 	}
3351e091e43SHans Rosenfeld 	rw_exit(&lmrc->l_raidmap_lock);
3361e091e43SHans Rosenfeld 
3371e091e43SHans Rosenfeld 	return (tm_capable);
3381e091e43SHans Rosenfeld }
3391e091e43SHans Rosenfeld 
3401e091e43SHans Rosenfeld 
3411e091e43SHans Rosenfeld 
3421e091e43SHans Rosenfeld /*
3431e091e43SHans Rosenfeld  * lmrc_raid_tgt_activate_cb
3441e091e43SHans Rosenfeld  *
3451e091e43SHans Rosenfeld  * Set up a tgt structure for a newly discovered LD.
3461e091e43SHans Rosenfeld  */
3471e091e43SHans Rosenfeld static void
lmrc_raid_tgt_activate_cb(void * tgtmap_priv,char * tgt_addr,scsi_tgtmap_tgt_type_t type,void ** tgt_privp)3481e091e43SHans Rosenfeld lmrc_raid_tgt_activate_cb(void *tgtmap_priv, char *tgt_addr,
3491e091e43SHans Rosenfeld     scsi_tgtmap_tgt_type_t type, void **tgt_privp)
3501e091e43SHans Rosenfeld {
3511e091e43SHans Rosenfeld 	lmrc_t *lmrc = tgtmap_priv;
3521e091e43SHans Rosenfeld 	lmrc_tgt_t *tgt = *tgt_privp;
3531e091e43SHans Rosenfeld 	uint16_t tgtid = tgt - lmrc->l_targets;
3541e091e43SHans Rosenfeld 
3551e091e43SHans Rosenfeld 	VERIFY(lmrc == tgt->tgt_lmrc);
3561e091e43SHans Rosenfeld 
3571e091e43SHans Rosenfeld 	VERIFY3U(tgtid, <, LMRC_MAX_LD);
3581e091e43SHans Rosenfeld 
3591e091e43SHans Rosenfeld 	lmrc_tgt_init(tgt, tgtid, tgt_addr, NULL);
3601e091e43SHans Rosenfeld }
3611e091e43SHans Rosenfeld 
3621e091e43SHans Rosenfeld /*
3631e091e43SHans Rosenfeld  * lmrc_raid_tgt_deactivate_cb
3641e091e43SHans Rosenfeld  *
3651e091e43SHans Rosenfeld  * Tear down the tgt structure of a LD that is no longer present.
3661e091e43SHans Rosenfeld  */
3671e091e43SHans Rosenfeld static boolean_t
lmrc_raid_tgt_deactivate_cb(void * tgtmap_priv,char * tgtaddr,scsi_tgtmap_tgt_type_t type,void * tgt_priv,scsi_tgtmap_deact_rsn_t deact)3681e091e43SHans Rosenfeld lmrc_raid_tgt_deactivate_cb(void *tgtmap_priv, char *tgtaddr,
3691e091e43SHans Rosenfeld     scsi_tgtmap_tgt_type_t type, void *tgt_priv, scsi_tgtmap_deact_rsn_t deact)
3701e091e43SHans Rosenfeld {
3711e091e43SHans Rosenfeld 	lmrc_t *lmrc = tgtmap_priv;
3721e091e43SHans Rosenfeld 	lmrc_tgt_t *tgt = tgt_priv;
3731e091e43SHans Rosenfeld 
3741e091e43SHans Rosenfeld 	VERIFY(lmrc == tgt->tgt_lmrc);
3751e091e43SHans Rosenfeld 
3761e091e43SHans Rosenfeld 	lmrc_tgt_clear(tgt);
3771e091e43SHans Rosenfeld 
3781e091e43SHans Rosenfeld 	return (B_FALSE);
3791e091e43SHans Rosenfeld }
3801e091e43SHans Rosenfeld 
3811e091e43SHans Rosenfeld /*
3821e091e43SHans Rosenfeld  * lmrc_raid_send_inquiry
3831e091e43SHans Rosenfeld  *
3841e091e43SHans Rosenfeld  * Fake a scsi_device and scsi_address, use the SCSA functions to allocate
3851e091e43SHans Rosenfeld  * a buf and a scsi_pkt, and issue a INQUIRY command to the target. Return
3861e091e43SHans Rosenfeld  * the buf on success, NULL otherwise.
3871e091e43SHans Rosenfeld  */
3881e091e43SHans Rosenfeld static struct buf *
lmrc_raid_send_inquiry(lmrc_t * lmrc,lmrc_tgt_t * tgt,uint8_t evpd,uint8_t page_code)3891e091e43SHans Rosenfeld lmrc_raid_send_inquiry(lmrc_t *lmrc, lmrc_tgt_t *tgt, uint8_t evpd,
3901e091e43SHans Rosenfeld     uint8_t page_code)
3911e091e43SHans Rosenfeld {
3921e091e43SHans Rosenfeld 	struct buf *inq_bp = NULL;
3931e091e43SHans Rosenfeld 	struct scsi_pkt *inq_pkt = NULL;
3941e091e43SHans Rosenfeld 	const size_t len = 0xf0; /* max INQUIRY length */
3951e091e43SHans Rosenfeld 	struct scsi_device sd;
3961e091e43SHans Rosenfeld 	int ret;
3971e091e43SHans Rosenfeld 
3981e091e43SHans Rosenfeld 	/*
3991e091e43SHans Rosenfeld 	 * Fake a scsi_device and scsi_address so we can use the scsi functions,
4001e091e43SHans Rosenfeld 	 * which in turn call our tran_setup_pkt and tran_start functions.
4011e091e43SHans Rosenfeld 	 */
4021e091e43SHans Rosenfeld 	bzero(&sd, sizeof (sd));
4031e091e43SHans Rosenfeld 	sd.sd_address.a_hba_tran = ddi_get_driver_private(lmrc->l_raid_dip);
4041e091e43SHans Rosenfeld 	sd.sd_address.a.a_sd = &sd;
4051e091e43SHans Rosenfeld 	scsi_device_hba_private_set(&sd, tgt);
4061e091e43SHans Rosenfeld 
4071e091e43SHans Rosenfeld 	/*
4081e091e43SHans Rosenfeld 	 * Get a buffer for INQUIRY.
4091e091e43SHans Rosenfeld 	 */
4101e091e43SHans Rosenfeld 	inq_bp = scsi_alloc_consistent_buf(&sd.sd_address, NULL,
4111e091e43SHans Rosenfeld 	    len, B_READ, SLEEP_FUNC, NULL);
4121e091e43SHans Rosenfeld 
4131e091e43SHans Rosenfeld 	if (inq_bp == NULL)
4141e091e43SHans Rosenfeld 		goto out;
4151e091e43SHans Rosenfeld 
4161e091e43SHans Rosenfeld 	inq_pkt = scsi_init_pkt(&sd.sd_address, NULL, inq_bp, CDB_GROUP0,
4171e091e43SHans Rosenfeld 	    sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT, SLEEP_FUNC,
4181e091e43SHans Rosenfeld 	    NULL);
4191e091e43SHans Rosenfeld 
4201e091e43SHans Rosenfeld 	if (inq_pkt == NULL)
4211e091e43SHans Rosenfeld 		goto fail;
4221e091e43SHans Rosenfeld 
4231e091e43SHans Rosenfeld 	(void) scsi_setup_cdb((union scsi_cdb *)inq_pkt->pkt_cdbp,
4241e091e43SHans Rosenfeld 	    SCMD_INQUIRY, 0, len, 0);
4251e091e43SHans Rosenfeld 	inq_pkt->pkt_cdbp[1] = evpd;
4261e091e43SHans Rosenfeld 	inq_pkt->pkt_cdbp[2] = page_code;
4271e091e43SHans Rosenfeld 
4281e091e43SHans Rosenfeld 	ret = scsi_poll(inq_pkt);
4291e091e43SHans Rosenfeld 
4301e091e43SHans Rosenfeld 	scsi_destroy_pkt(inq_pkt);
4311e091e43SHans Rosenfeld 
4321e091e43SHans Rosenfeld 	if (ret != 0) {
4331e091e43SHans Rosenfeld fail:
4341e091e43SHans Rosenfeld 		scsi_free_consistent_buf(inq_bp);
4351e091e43SHans Rosenfeld 		inq_bp = NULL;
4361e091e43SHans Rosenfeld 	}
4371e091e43SHans Rosenfeld 
4381e091e43SHans Rosenfeld out:
4391e091e43SHans Rosenfeld 	return (inq_bp);
4401e091e43SHans Rosenfeld }
4411e091e43SHans Rosenfeld 
4421e091e43SHans Rosenfeld /*
4431e091e43SHans Rosenfeld  * lmrc_raid_get_wwn
4441e091e43SHans Rosenfeld  *
4451e091e43SHans Rosenfeld  * LDs may have a WWN, but the hardware doesn't just tell us about it.
4461e091e43SHans Rosenfeld  * Send an INQUIRY to the target and get VPD page 0x83. If the target
4471e091e43SHans Rosenfeld  * does have a WWN, return it.
4481e091e43SHans Rosenfeld  */
4491e091e43SHans Rosenfeld static uint64_t
lmrc_raid_get_wwn(lmrc_t * lmrc,uint8_t tgtid)4501e091e43SHans Rosenfeld lmrc_raid_get_wwn(lmrc_t *lmrc, uint8_t tgtid)
4511e091e43SHans Rosenfeld {
4521e091e43SHans Rosenfeld 	lmrc_tgt_t *tgt = &lmrc->l_targets[tgtid];
4531e091e43SHans Rosenfeld 	char *guid = NULL;
4541e091e43SHans Rosenfeld 	struct buf *inq_bp = NULL, *inq83_bp = NULL;
4551e091e43SHans Rosenfeld 	uint64_t wwn = 0;
4561e091e43SHans Rosenfeld 	ddi_devid_t devid;
4571e091e43SHans Rosenfeld 	int ret;
4581e091e43SHans Rosenfeld 
4591e091e43SHans Rosenfeld 	/*
4601e091e43SHans Rosenfeld 	 * Make sure we have the target ID set in the target structure.
4611e091e43SHans Rosenfeld 	 */
4621e091e43SHans Rosenfeld 	rw_enter(&tgt->tgt_lock, RW_WRITER);
4631e091e43SHans Rosenfeld 	VERIFY3U(tgt->tgt_lmrc, ==, lmrc);
4641e091e43SHans Rosenfeld 	if (tgt->tgt_dev_id == LMRC_DEVHDL_INVALID)
4651e091e43SHans Rosenfeld 		tgt->tgt_dev_id = tgtid;
4661e091e43SHans Rosenfeld 	else
4671e091e43SHans Rosenfeld 		VERIFY3U(tgt->tgt_dev_id, ==, tgtid);
4681e091e43SHans Rosenfeld 	rw_exit(&tgt->tgt_lock);
4691e091e43SHans Rosenfeld 
4701e091e43SHans Rosenfeld 	/* Get basic INQUIRY data from device. */
4711e091e43SHans Rosenfeld 	inq_bp = lmrc_raid_send_inquiry(lmrc, tgt, 0, 0);
4721e091e43SHans Rosenfeld 	if (inq_bp == NULL)
4731e091e43SHans Rosenfeld 		goto fail;
4741e091e43SHans Rosenfeld 
4751e091e43SHans Rosenfeld 	/* Get VPD 83 from INQUIRY. */
4761e091e43SHans Rosenfeld 	inq83_bp = lmrc_raid_send_inquiry(lmrc, tgt, 1, 0x83);
4771e091e43SHans Rosenfeld 	if (inq83_bp == NULL)
4781e091e43SHans Rosenfeld 		goto fail;
4791e091e43SHans Rosenfeld 
4801e091e43SHans Rosenfeld 	/* Try to turn the VPD83 data into a devid. */
4811e091e43SHans Rosenfeld 	ret = ddi_devid_scsi_encode(DEVID_SCSI_ENCODE_VERSION1,
4821e091e43SHans Rosenfeld 	    NULL, (uchar_t *)inq_bp->b_un.b_addr, sizeof (struct scsi_inquiry),
4831e091e43SHans Rosenfeld 	    NULL, 0, (uchar_t *)inq83_bp->b_un.b_addr, inq83_bp->b_bcount,
4841e091e43SHans Rosenfeld 	    &devid);
4851e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
4861e091e43SHans Rosenfeld 		goto fail;
4871e091e43SHans Rosenfeld 
4881e091e43SHans Rosenfeld 	/* Extract the GUID from the devid. */
4891e091e43SHans Rosenfeld 	guid = ddi_devid_to_guid(devid);
4901e091e43SHans Rosenfeld 	if (guid == NULL)
4911e091e43SHans Rosenfeld 		goto fail;
4921e091e43SHans Rosenfeld 
4931e091e43SHans Rosenfeld 	/* Convert the GUID to a WWN. */
4941e091e43SHans Rosenfeld 	(void) scsi_wwnstr_to_wwn(guid, &wwn);
4951e091e43SHans Rosenfeld 
4961e091e43SHans Rosenfeld 	ddi_devid_free_guid(guid);
4971e091e43SHans Rosenfeld 
4981e091e43SHans Rosenfeld fail:
4991e091e43SHans Rosenfeld 	if (inq_bp != NULL)
5001e091e43SHans Rosenfeld 		scsi_free_consistent_buf(inq_bp);
5011e091e43SHans Rosenfeld 	if (inq83_bp != NULL)
5021e091e43SHans Rosenfeld 		scsi_free_consistent_buf(inq83_bp);
5031e091e43SHans Rosenfeld 
5041e091e43SHans Rosenfeld 	return (wwn);
5051e091e43SHans Rosenfeld }
5061e091e43SHans Rosenfeld 
5071e091e43SHans Rosenfeld /*
5081e091e43SHans Rosenfeld  * lmrc_raid_update_tgtmap
5091e091e43SHans Rosenfeld  *
5101e091e43SHans Rosenfeld  * Feed the LD target ID list into the target map. Try to get a WWN for each LD.
5111e091e43SHans Rosenfeld  */
5121e091e43SHans Rosenfeld static int
lmrc_raid_update_tgtmap(lmrc_t * lmrc,mfi_ld_tgtid_list_t * ld_list)513*98f0a994SHans Rosenfeld lmrc_raid_update_tgtmap(lmrc_t *lmrc, mfi_ld_tgtid_list_t *ld_list)
5141e091e43SHans Rosenfeld {
5151e091e43SHans Rosenfeld 	int ret;
5161e091e43SHans Rosenfeld 	int i;
5171e091e43SHans Rosenfeld 
5181e091e43SHans Rosenfeld 	if (ld_list->ltl_count > lmrc->l_fw_supported_vd_count)
5191e091e43SHans Rosenfeld 		return (DDI_FAILURE);
5201e091e43SHans Rosenfeld 
5211e091e43SHans Rosenfeld 	ret = scsi_hba_tgtmap_set_begin(lmrc->l_raid_tgtmap);
5221e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
5231e091e43SHans Rosenfeld 		return (ret);
5241e091e43SHans Rosenfeld 
5251e091e43SHans Rosenfeld 	for (i = 0; i < ld_list->ltl_count; i++) {
5261e091e43SHans Rosenfeld 		uint8_t tgtid = ld_list->ltl_tgtid[i];
5271e091e43SHans Rosenfeld 		char name[SCSI_WWN_BUFLEN];
5281e091e43SHans Rosenfeld 		uint64_t wwn;
5291e091e43SHans Rosenfeld 
5301e091e43SHans Rosenfeld 		if (tgtid > lmrc->l_fw_supported_vd_count) {
5311e091e43SHans Rosenfeld 			dev_err(lmrc->l_dip, CE_WARN,
5321e091e43SHans Rosenfeld 			    "!%s: invalid LD tgt id %d", __func__, tgtid);
5331e091e43SHans Rosenfeld 			goto fail;
5341e091e43SHans Rosenfeld 		}
5351e091e43SHans Rosenfeld 
5361e091e43SHans Rosenfeld 		wwn = lmrc_raid_get_wwn(lmrc, tgtid);
5371e091e43SHans Rosenfeld 		if (wwn != 0)
5381e091e43SHans Rosenfeld 			(void) scsi_wwn_to_wwnstr(wwn, 0, name);
5391e091e43SHans Rosenfeld 		else
5401e091e43SHans Rosenfeld 			(void) snprintf(name, sizeof (name), "%d", tgtid);
5411e091e43SHans Rosenfeld 
5421e091e43SHans Rosenfeld 		ret = scsi_hba_tgtmap_set_add(lmrc->l_raid_tgtmap,
5431e091e43SHans Rosenfeld 		    SCSI_TGT_SCSI_DEVICE, name, &lmrc->l_targets[tgtid]);
5441e091e43SHans Rosenfeld 
5451e091e43SHans Rosenfeld 		if (ret != DDI_SUCCESS)
5461e091e43SHans Rosenfeld 			goto fail;
5471e091e43SHans Rosenfeld 	}
5481e091e43SHans Rosenfeld 
5491e091e43SHans Rosenfeld 	return (scsi_hba_tgtmap_set_end(lmrc->l_raid_tgtmap, 0));
5501e091e43SHans Rosenfeld 
5511e091e43SHans Rosenfeld fail:
5521e091e43SHans Rosenfeld 	(void) scsi_hba_tgtmap_set_flush(lmrc->l_raid_tgtmap);
5531e091e43SHans Rosenfeld 	return (DDI_FAILURE);
5541e091e43SHans Rosenfeld }
5551e091e43SHans Rosenfeld 
5561e091e43SHans Rosenfeld /*
5571e091e43SHans Rosenfeld  * lmrc_get_ld_list
5581e091e43SHans Rosenfeld  *
5591e091e43SHans Rosenfeld  * Query the controller for a list of currently known LDs. Use the information
5601e091e43SHans Rosenfeld  * to update the target map.
5611e091e43SHans Rosenfeld  */
5621e091e43SHans Rosenfeld int
lmrc_get_ld_list(lmrc_t * lmrc)5631e091e43SHans Rosenfeld lmrc_get_ld_list(lmrc_t *lmrc)
5641e091e43SHans Rosenfeld {
565*98f0a994SHans Rosenfeld 	mfi_dcmd_payload_t *dcmd;
5661e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi;
5671e091e43SHans Rosenfeld 	int ret;
5681e091e43SHans Rosenfeld 
569d39213d9SHans Rosenfeld 	/* If the raid iport isn't attached yet, just return success. */
570d39213d9SHans Rosenfeld 	if (!INITLEVEL_ACTIVE(lmrc, LMRC_INITLEVEL_RAID))
571d39213d9SHans Rosenfeld 		return (DDI_SUCCESS);
572d39213d9SHans Rosenfeld 
573*98f0a994SHans Rosenfeld 	mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_READ, MFI_DCMD_LD_LIST_QUERY,
574*98f0a994SHans Rosenfeld 	    sizeof (mfi_ld_tgtid_list_t) + lmrc->l_fw_supported_vd_count, 1);
5751e091e43SHans Rosenfeld 
5761e091e43SHans Rosenfeld 	if (mfi == NULL)
5771e091e43SHans Rosenfeld 		return (DDI_FAILURE);
5781e091e43SHans Rosenfeld 
5791e091e43SHans Rosenfeld 	dcmd = &mfi->mfi_frame->mf_dcmd;
580*98f0a994SHans Rosenfeld 	dcmd->md_mbox_8[0] = MFI_LD_QUERY_TYPE_EXPOSED_TO_HOST;
5811e091e43SHans Rosenfeld 
5821e091e43SHans Rosenfeld 	if (lmrc->l_max_256_vd_support)
5831e091e43SHans Rosenfeld 		dcmd->md_mbox_8[2] = 1;
5841e091e43SHans Rosenfeld 
5851e091e43SHans Rosenfeld 	ret = lmrc_issue_blocked_mfi(lmrc, mfi);
5861e091e43SHans Rosenfeld 
5871e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
5881e091e43SHans Rosenfeld 		goto out;
5891e091e43SHans Rosenfeld 
5901e091e43SHans Rosenfeld 	ret = lmrc_raid_update_tgtmap(lmrc, mfi->mfi_data_dma.ld_buf);
5911e091e43SHans Rosenfeld 
5921e091e43SHans Rosenfeld out:
5931e091e43SHans Rosenfeld 	lmrc_put_dcmd(lmrc, mfi);
5941e091e43SHans Rosenfeld 	return (ret);
5951e091e43SHans Rosenfeld }
5961e091e43SHans Rosenfeld 
5971e091e43SHans Rosenfeld /*
5981e091e43SHans Rosenfeld  * lmrc_raid_aen_handler
5991e091e43SHans Rosenfeld  *
600*98f0a994SHans Rosenfeld  * Handle AENs with locale code MFI_EVT_LOCALE_LD. If the LD configuration
6011e091e43SHans Rosenfeld  * changed, update the LD list and target map.
6021e091e43SHans Rosenfeld  */
6031e091e43SHans Rosenfeld int
lmrc_raid_aen_handler(lmrc_t * lmrc,mfi_evt_detail_t * evt)604*98f0a994SHans Rosenfeld lmrc_raid_aen_handler(lmrc_t *lmrc, mfi_evt_detail_t *evt)
6051e091e43SHans Rosenfeld {
6061e091e43SHans Rosenfeld 	int ret = DDI_SUCCESS;
6071e091e43SHans Rosenfeld 
6081e091e43SHans Rosenfeld 	switch (evt->evt_code) {
609*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_CC_STARTED:
610*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_CC_PROGRESS:
611*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_CC_COMPLETE:
6121e091e43SHans Rosenfeld 		/*
6131e091e43SHans Rosenfeld 		 * Consistency Check. I/O is possible during consistency check,
6141e091e43SHans Rosenfeld 		 * so there's no need to do anything.
6151e091e43SHans Rosenfeld 		 */
6161e091e43SHans Rosenfeld 		break;
6171e091e43SHans Rosenfeld 
618*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_FAST_INIT_STARTED:
619*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_FULL_INIT_STARTED:
6201e091e43SHans Rosenfeld 		/*
6211e091e43SHans Rosenfeld 		 * A LD initialization process has been started.
6221e091e43SHans Rosenfeld 		 */
6231e091e43SHans Rosenfeld 		ret = lmrc_get_ld_list(lmrc);
6241e091e43SHans Rosenfeld 		break;
6251e091e43SHans Rosenfeld 
626*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_BG_INIT_PROGRESS:
627*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_INIT_PROGRESS:
6281e091e43SHans Rosenfeld 		/*
6291e091e43SHans Rosenfeld 		 * FULL INIT reports these for every percent of completion.
6301e091e43SHans Rosenfeld 		 * Ignore.
6311e091e43SHans Rosenfeld 		 */
6321e091e43SHans Rosenfeld 		break;
6331e091e43SHans Rosenfeld 
634*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_INIT_ABORTED:
635*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_INIT_COMPLETE:
6361e091e43SHans Rosenfeld 		/*
6371e091e43SHans Rosenfeld 		 * The LD initialization has ended, one way or another.
6381e091e43SHans Rosenfeld 		 */
6391e091e43SHans Rosenfeld 		ret = lmrc_get_ld_list(lmrc);
6401e091e43SHans Rosenfeld 		break;
6411e091e43SHans Rosenfeld 
642*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_BBT_CLEARED:
6431e091e43SHans Rosenfeld 		/*
6441e091e43SHans Rosenfeld 		 * The Bad Block Table for the LD has been cleared. This usually
6451e091e43SHans Rosenfeld 		 * follows a INIT_COMPLETE, but may occur in other situations.
6461e091e43SHans Rosenfeld 		 * Ignore.
6471e091e43SHans Rosenfeld 		 */
6481e091e43SHans Rosenfeld 		break;
6491e091e43SHans Rosenfeld 
650*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_PROP_CHANGED:
6511e091e43SHans Rosenfeld 		/*
6521e091e43SHans Rosenfeld 		 * Happens when LD props are changed, such as setting the
6531e091e43SHans Rosenfeld 		 * "hidden" property. There's little we can do here as we
6541e091e43SHans Rosenfeld 		 * don't which property changed which way. In any case,
6551e091e43SHans Rosenfeld 		 * this is usually followed by a HOST BUS SCAN REQD which
6561e091e43SHans Rosenfeld 		 * will handle any changes.
6571e091e43SHans Rosenfeld 		 */
6581e091e43SHans Rosenfeld 		break;
6591e091e43SHans Rosenfeld 
660*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_OFFLINE:
6611e091e43SHans Rosenfeld 		/*
6621e091e43SHans Rosenfeld 		 * Not sure when this happens, but since the LD is offline we
6631e091e43SHans Rosenfeld 		 * should just remove it from the target map.
6641e091e43SHans Rosenfeld 		 */
6651e091e43SHans Rosenfeld 		ret = lmrc_get_ld_list(lmrc);
6661e091e43SHans Rosenfeld 		break;
6671e091e43SHans Rosenfeld 
668*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_DELETED:
6691e091e43SHans Rosenfeld 		/*
6701e091e43SHans Rosenfeld 		 * A LD was deleted, remove it from target map.
6711e091e43SHans Rosenfeld 		 */
6721e091e43SHans Rosenfeld 		ret = lmrc_get_ld_list(lmrc);
6731e091e43SHans Rosenfeld 		break;
6741e091e43SHans Rosenfeld 
675*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_OPTIMAL:
6761e091e43SHans Rosenfeld 		/*
6771e091e43SHans Rosenfeld 		 * There might be several cases when this event occurs,
6781e091e43SHans Rosenfeld 		 * in particular when a LD is created. In that case it's the
6791e091e43SHans Rosenfeld 		 * first of several events, so we can ignore it.
6801e091e43SHans Rosenfeld 		 */
6811e091e43SHans Rosenfeld 		break;
6821e091e43SHans Rosenfeld 
683*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_CREATED:
6841e091e43SHans Rosenfeld 		/*
6851e091e43SHans Rosenfeld 		 * This is the 2nd event generated when a LD is created, and
6861e091e43SHans Rosenfeld 		 * it's the one FreeBSD and Linux act on. Add the LD to the
6871e091e43SHans Rosenfeld 		 * target map.
6881e091e43SHans Rosenfeld 		 */
6891e091e43SHans Rosenfeld 		ret = lmrc_get_ld_list(lmrc);
6901e091e43SHans Rosenfeld 		break;
6911e091e43SHans Rosenfeld 
692*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_AVAILABLE:
6931e091e43SHans Rosenfeld 		/*
6941e091e43SHans Rosenfeld 		 * This event happens last when a LD is created, but there may
6951e091e43SHans Rosenfeld 		 * be other scenarios where this occurs. Ignore it for now.
6961e091e43SHans Rosenfeld 		 */
6971e091e43SHans Rosenfeld 		break;
6981e091e43SHans Rosenfeld 
699*98f0a994SHans Rosenfeld 	case MFI_EVT_LD_STATE_CHANGE:
7001e091e43SHans Rosenfeld 		/*
7011e091e43SHans Rosenfeld 		 * Not sure when this happens, but updating the LD list is
7021e091e43SHans Rosenfeld 		 * probably a good idea.
7031e091e43SHans Rosenfeld 		 */
7041e091e43SHans Rosenfeld 		ret = lmrc_get_ld_list(lmrc);
7051e091e43SHans Rosenfeld 		break;
7061e091e43SHans Rosenfeld 
7071e091e43SHans Rosenfeld 	default:
7081e091e43SHans Rosenfeld 		ret = DDI_FAILURE;
7091e091e43SHans Rosenfeld 	}
7101e091e43SHans Rosenfeld 
7111e091e43SHans Rosenfeld 	return (ret);
7121e091e43SHans Rosenfeld }
7131e091e43SHans Rosenfeld 
7141e091e43SHans Rosenfeld int
lmrc_raid_attach(dev_info_t * dip)7151e091e43SHans Rosenfeld lmrc_raid_attach(dev_info_t *dip)
7161e091e43SHans Rosenfeld {
7171e091e43SHans Rosenfeld 	scsi_hba_tran_t *tran = ddi_get_driver_private(dip);
7181e091e43SHans Rosenfeld 	dev_info_t *pdip = ddi_get_parent(dip);
7191e091e43SHans Rosenfeld 	lmrc_t *lmrc = ddi_get_soft_state(lmrc_state, ddi_get_instance(pdip));
7201e091e43SHans Rosenfeld 	int ret;
7211e091e43SHans Rosenfeld 
7221e091e43SHans Rosenfeld 	VERIFY(tran != NULL);
7231e091e43SHans Rosenfeld 	VERIFY(lmrc != NULL);
7241e091e43SHans Rosenfeld 
7251e091e43SHans Rosenfeld 	if (lmrc->l_fw_fault)
7261e091e43SHans Rosenfeld 		return (DDI_FAILURE);
7271e091e43SHans Rosenfeld 
7281e091e43SHans Rosenfeld 	tran->tran_hba_private = lmrc;
7291e091e43SHans Rosenfeld 	lmrc->l_raid_dip = dip;
7301e091e43SHans Rosenfeld 
7311e091e43SHans Rosenfeld 	ret = scsi_hba_tgtmap_create(dip, SCSI_TM_FULLSET, MICROSEC,
7321e091e43SHans Rosenfeld 	    2 * MICROSEC, lmrc, lmrc_raid_tgt_activate_cb,
7331e091e43SHans Rosenfeld 	    lmrc_raid_tgt_deactivate_cb, &lmrc->l_raid_tgtmap);
7341e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
7351e091e43SHans Rosenfeld 		return (ret);
7361e091e43SHans Rosenfeld 
7371e091e43SHans Rosenfeld 	ret = lmrc_setup_raidmap(lmrc);
7381e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS) {
7391e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN, "!RAID map setup failed.");
7401e091e43SHans Rosenfeld 		return (DDI_FAILURE);
7411e091e43SHans Rosenfeld 	}
7421e091e43SHans Rosenfeld 
743d39213d9SHans Rosenfeld 	INITLEVEL_SET(lmrc, LMRC_INITLEVEL_RAID);
744d39213d9SHans Rosenfeld 
7451e091e43SHans Rosenfeld 	ret = lmrc_get_ld_list(lmrc);
7461e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS) {
7471e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN, "!Failed to get LD list.");
7481e091e43SHans Rosenfeld 		return (ret);
7491e091e43SHans Rosenfeld 	}
7501e091e43SHans Rosenfeld 
7511e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
7521e091e43SHans Rosenfeld }
7531e091e43SHans Rosenfeld 
7541e091e43SHans Rosenfeld int
lmrc_raid_detach(dev_info_t * dip)7551e091e43SHans Rosenfeld lmrc_raid_detach(dev_info_t *dip)
7561e091e43SHans Rosenfeld {
7571e091e43SHans Rosenfeld 	dev_info_t *pdip = ddi_get_parent(dip);
7581e091e43SHans Rosenfeld 	lmrc_t *lmrc = ddi_get_soft_state(lmrc_state, ddi_get_instance(pdip));
7591e091e43SHans Rosenfeld 
7601e091e43SHans Rosenfeld 	VERIFY(lmrc != NULL);
761d39213d9SHans Rosenfeld 	INITLEVEL_CLEAR(lmrc, LMRC_INITLEVEL_RAID);
7621e091e43SHans Rosenfeld 
7631e091e43SHans Rosenfeld 	if (lmrc->l_raid_tgtmap != NULL) {
7641e091e43SHans Rosenfeld 		scsi_hba_tgtmap_destroy(lmrc->l_raid_tgtmap);
7651e091e43SHans Rosenfeld 		lmrc->l_raid_tgtmap = NULL;
7661e091e43SHans Rosenfeld 	}
7671e091e43SHans Rosenfeld 
7681e091e43SHans Rosenfeld 	lmrc->l_raid_dip = NULL;
7691e091e43SHans Rosenfeld 
7701e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
7711e091e43SHans Rosenfeld }
772