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 /*
13*d25078f9SHans Rosenfeld  * Copyright 2024 Racktop Systems, Inc.
141e091e43SHans Rosenfeld  */
151e091e43SHans Rosenfeld 
161e091e43SHans Rosenfeld /*
171e091e43SHans Rosenfeld  * This file implements the interfaces for communicating with the MegaRAID HBA.
181e091e43SHans Rosenfeld  * There are three basic interfaces:
191e091e43SHans Rosenfeld  * - the device registers, which provide basic information about the controller
201e091e43SHans Rosenfeld  *   hardware and the features it supports, as well as control registers used
211e091e43SHans Rosenfeld  *   during sending and reception of I/O frames
221e091e43SHans Rosenfeld  * - Fusion-MPT v2.5, perhaps later, which defines the format of the I/O frames
231e091e43SHans Rosenfeld  *   used for communicating with the HBA and virtual and physical devices that
241e091e43SHans Rosenfeld  *   are attached to it
251e091e43SHans Rosenfeld  * - MFI, the MegaRAID Firmware Interface, which are sent and received as MPT
261e091e43SHans Rosenfeld  *   payloads to control and communicate with the RAID controller.
271e091e43SHans Rosenfeld  */
281e091e43SHans Rosenfeld 
291e091e43SHans Rosenfeld #include <sys/types.h>
301e091e43SHans Rosenfeld #include <sys/ddi.h>
311e091e43SHans Rosenfeld #include <sys/sunddi.h>
321e091e43SHans Rosenfeld #include <sys/scsi/scsi.h>
331e091e43SHans Rosenfeld 
341e091e43SHans Rosenfeld #include <sys/cpuvar.h>
351e091e43SHans Rosenfeld 
361e091e43SHans Rosenfeld #include "lmrc.h"
371e091e43SHans Rosenfeld #include "lmrc_reg.h"
381e091e43SHans Rosenfeld #include "lmrc_raid.h"
391e091e43SHans Rosenfeld #include "lmrc_phys.h"
401e091e43SHans Rosenfeld 
411e091e43SHans Rosenfeld static uint32_t lmrc_read_reg(lmrc_t *, uint32_t);
421e091e43SHans Rosenfeld static void lmrc_write_reg(lmrc_t *, uint32_t, uint32_t);
431e091e43SHans Rosenfeld static int lmrc_transition_to_ready(lmrc_t *);
441e091e43SHans Rosenfeld static void lmrc_process_mptmfi_passthru(lmrc_t *, lmrc_mpt_cmd_t *);
451e091e43SHans Rosenfeld static int lmrc_poll_mfi(lmrc_t *, lmrc_mfi_cmd_t *, uint8_t);
461e091e43SHans Rosenfeld static boolean_t lmrc_check_fw_fault(lmrc_t *);
471e091e43SHans Rosenfeld static int lmrc_get_event_log_info(lmrc_t *, lmrc_evt_log_info_t *);
481e091e43SHans Rosenfeld static void lmrc_aen_handler(void *);
491e091e43SHans Rosenfeld static void lmrc_complete_aen(lmrc_t *, lmrc_mfi_cmd_t *);
501e091e43SHans Rosenfeld static int lmrc_register_aen(lmrc_t *, uint32_t);
511e091e43SHans Rosenfeld 
521e091e43SHans Rosenfeld /*
531e091e43SHans Rosenfeld  * Device register access functions.
541e091e43SHans Rosenfeld  *
551e091e43SHans Rosenfeld  * Due to the way ddi_get* and ddi_put* work, we'll need to calculate the
561e091e43SHans Rosenfeld  * absolute virtual address of the registers ourselves.
571e091e43SHans Rosenfeld  *
581e091e43SHans Rosenfeld  * For read accesses, employ a erratum workaround for Aero controllers. In some
591e091e43SHans Rosenfeld  * cases, reads of certain registers will intermittently return all zeros. As a
601e091e43SHans Rosenfeld  * workaround, retry the read up to three times until a non-zero value is read.
611e091e43SHans Rosenfeld  * Supposedly this is enough, every other driver I looked at does this.
621e091e43SHans Rosenfeld  */
631e091e43SHans Rosenfeld static uint32_t
lmrc_read_reg_1(lmrc_t * lmrc,uint32_t reg)641e091e43SHans Rosenfeld lmrc_read_reg_1(lmrc_t *lmrc, uint32_t reg)
651e091e43SHans Rosenfeld {
661e091e43SHans Rosenfeld 	uint32_t *addr = (uint32_t *)((uintptr_t)lmrc->l_regmap + reg);
671e091e43SHans Rosenfeld 	return (ddi_get32(lmrc->l_reghandle, addr));
681e091e43SHans Rosenfeld }
691e091e43SHans Rosenfeld 
701e091e43SHans Rosenfeld static uint32_t
lmrc_read_reg(lmrc_t * lmrc,uint32_t reg)711e091e43SHans Rosenfeld lmrc_read_reg(lmrc_t *lmrc, uint32_t reg)
721e091e43SHans Rosenfeld {
731e091e43SHans Rosenfeld 	if (lmrc->l_class != LMRC_ACLASS_AERO)
741e091e43SHans Rosenfeld 		return (lmrc_read_reg_1(lmrc, reg));
751e091e43SHans Rosenfeld 
761e091e43SHans Rosenfeld 	/* Workaround for the hardware erratum in Aero controllers */
771e091e43SHans Rosenfeld 	for (uint_t i = 0; i < 3; i++) {
781e091e43SHans Rosenfeld 		uint32_t val = lmrc_read_reg_1(lmrc, reg);
791e091e43SHans Rosenfeld 
801e091e43SHans Rosenfeld 		if (val != 0)
811e091e43SHans Rosenfeld 			return (val);
821e091e43SHans Rosenfeld 	}
831e091e43SHans Rosenfeld 
841e091e43SHans Rosenfeld 	return (0);
851e091e43SHans Rosenfeld }
861e091e43SHans Rosenfeld 
871e091e43SHans Rosenfeld static void
lmrc_write_reg(lmrc_t * lmrc,uint32_t reg,uint32_t val)881e091e43SHans Rosenfeld lmrc_write_reg(lmrc_t *lmrc, uint32_t reg, uint32_t val)
891e091e43SHans Rosenfeld {
901e091e43SHans Rosenfeld 	uint32_t *addr = (uint32_t *)((uintptr_t)lmrc->l_regmap + reg);
911e091e43SHans Rosenfeld 	ddi_put32(lmrc->l_reghandle, addr, val);
921e091e43SHans Rosenfeld }
931e091e43SHans Rosenfeld 
941e091e43SHans Rosenfeld static void
lmrc_write_reg64(lmrc_t * lmrc,uint32_t reg,uint64_t val)951e091e43SHans Rosenfeld lmrc_write_reg64(lmrc_t *lmrc, uint32_t reg, uint64_t val)
961e091e43SHans Rosenfeld {
971e091e43SHans Rosenfeld 	uint64_t *addr = (uint64_t *)((uintptr_t)lmrc->l_regmap + reg);
981e091e43SHans Rosenfeld 	ddi_put64(lmrc->l_reghandle, addr, val);
991e091e43SHans Rosenfeld }
1001e091e43SHans Rosenfeld 
1011e091e43SHans Rosenfeld /*
1021e091e43SHans Rosenfeld  * Interrupt control
1031e091e43SHans Rosenfeld  *
104e9ff209aSHans Rosenfeld  * There are two interrupt registers for host driver use, HostInterruptStatus
105e9ff209aSHans Rosenfeld  * and HostInterruptMask. Most of the bits in each register are reserved and
106e9ff209aSHans Rosenfeld  * must masked and/or preserved when used.
1071e091e43SHans Rosenfeld  */
1081e091e43SHans Rosenfeld void
lmrc_disable_intr(lmrc_t * lmrc)1091e091e43SHans Rosenfeld lmrc_disable_intr(lmrc_t *lmrc)
1101e091e43SHans Rosenfeld {
111e9ff209aSHans Rosenfeld 	uint32_t mask = lmrc_read_reg(lmrc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
112e9ff209aSHans Rosenfeld 
113e9ff209aSHans Rosenfeld 	/* Disable all known interrupt: reset, reply, and doorbell. */
114e9ff209aSHans Rosenfeld 	mask |= MPI2_HIM_RESET_IRQ_MASK;
115e9ff209aSHans Rosenfeld 	mask |= MPI2_HIM_REPLY_INT_MASK;
116e9ff209aSHans Rosenfeld 	mask |= MPI2_HIM_IOC2SYS_DB_MASK;
1171e091e43SHans Rosenfeld 
118e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
119e9ff209aSHans Rosenfeld 
120e9ff209aSHans Rosenfeld 	/* Dummy read to force pci flush. Probably bogus but harmless. */
121e9ff209aSHans Rosenfeld 	(void) lmrc_read_reg(lmrc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
1221e091e43SHans Rosenfeld }
1231e091e43SHans Rosenfeld 
1241e091e43SHans Rosenfeld void
lmrc_enable_intr(lmrc_t * lmrc)1251e091e43SHans Rosenfeld lmrc_enable_intr(lmrc_t *lmrc)
1261e091e43SHans Rosenfeld {
127e9ff209aSHans Rosenfeld 	uint32_t mask = lmrc_read_reg(lmrc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
128e9ff209aSHans Rosenfeld 
129e9ff209aSHans Rosenfeld 	/* Enable the reply interrupts and the doorbell interrupts. */
130e9ff209aSHans Rosenfeld 	mask &= ~MPI2_HIM_REPLY_INT_MASK;
131e9ff209aSHans Rosenfeld 	mask &= ~MPI2_HIM_IOC2SYS_DB_MASK;
1321e091e43SHans Rosenfeld 
133e9ff209aSHans Rosenfeld 	/* Clear outstanding interrupts before enabling any. */
134e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0);
135e9ff209aSHans Rosenfeld 	/* Dummy read to force pci flush. Probably bogus but harmless. */
136e9ff209aSHans Rosenfeld 	(void) lmrc_read_reg(lmrc, MPI2_HOST_INTERRUPT_STATUS_OFFSET);
1371e091e43SHans Rosenfeld 
138e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
139e9ff209aSHans Rosenfeld 	/* Dummy read to force pci flush. Probably bogus but harmless. */
140e9ff209aSHans Rosenfeld 	(void) lmrc_read_reg(lmrc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
1411e091e43SHans Rosenfeld }
1421e091e43SHans Rosenfeld 
1431e091e43SHans Rosenfeld uint_t
lmrc_intr_ack(lmrc_t * lmrc)1441e091e43SHans Rosenfeld lmrc_intr_ack(lmrc_t *lmrc)
1451e091e43SHans Rosenfeld {
146e9ff209aSHans Rosenfeld 	uint32_t mask =
147e9ff209aSHans Rosenfeld 	    MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT | MPI2_HIS_IOC2SYS_DB_STATUS;
1481e091e43SHans Rosenfeld 	uint32_t status;
1491e091e43SHans Rosenfeld 
150e9ff209aSHans Rosenfeld 	status = lmrc_read_reg(lmrc, MPI2_HOST_INTERRUPT_STATUS_OFFSET);
1511e091e43SHans Rosenfeld 
152e9ff209aSHans Rosenfeld 	if ((status & mask) == 0)
1531e091e43SHans Rosenfeld 		return (DDI_INTR_UNCLAIMED);
1541e091e43SHans Rosenfeld 
1551e091e43SHans Rosenfeld 	if (lmrc_check_acc_handle(lmrc->l_reghandle) != DDI_SUCCESS) {
1561e091e43SHans Rosenfeld 		ddi_fm_service_impact(lmrc->l_dip, DDI_SERVICE_LOST);
1571e091e43SHans Rosenfeld 		return (DDI_INTR_UNCLAIMED);
1581e091e43SHans Rosenfeld 	}
1591e091e43SHans Rosenfeld 
1601e091e43SHans Rosenfeld 	return (DDI_INTR_CLAIMED);
1611e091e43SHans Rosenfeld }
1621e091e43SHans Rosenfeld 
1631e091e43SHans Rosenfeld /*
1641e091e43SHans Rosenfeld  * Fusion-MPT requests
1651e091e43SHans Rosenfeld  *
1661e091e43SHans Rosenfeld  * The controller expects to have access to a large chunk of DMA memory, into
1671e091e43SHans Rosenfeld  * which the driver writes fixed-size I/O requests for the controller to
1681e091e43SHans Rosenfeld  * process. To notify the hardware about a new request, a request descriptor is
1691e091e43SHans Rosenfeld  * written to the queue port registers which includes the SMID of the request.
1701e091e43SHans Rosenfeld  * This memory isn't really a queue, though, as it seems there are no
1711e091e43SHans Rosenfeld  * constraints about ordering of the requests. All that matters is that there
1721e091e43SHans Rosenfeld  * is a valid request at the address that corresponds with the SMID in the
1731e091e43SHans Rosenfeld  * descriptor.
1741e091e43SHans Rosenfeld  *
1751e091e43SHans Rosenfeld  * If the hardware supports MPI 2.6 atomic request descriptors, which are a
1761e091e43SHans Rosenfeld  * 32bit subset of the 64bit MPI 2.0/2.5 request descriptors, the descriptor is
1771e091e43SHans Rosenfeld  * sent to the controller in a single 32bit write into a device register.
1781e091e43SHans Rosenfeld  *
1791e091e43SHans Rosenfeld  * For all other descriptor types, we'll employ a 64bit write to the queue
1801e091e43SHans Rosenfeld  * registers, assuming that provides the required atomicity.
1811e091e43SHans Rosenfeld  */
1821e091e43SHans Rosenfeld void
lmrc_send_atomic_request(lmrc_t * lmrc,lmrc_atomic_req_desc_t req_desc)1831e091e43SHans Rosenfeld lmrc_send_atomic_request(lmrc_t *lmrc, lmrc_atomic_req_desc_t req_desc)
1841e091e43SHans Rosenfeld {
1851e091e43SHans Rosenfeld 	if (lmrc->l_atomic_desc_support) {
186e9ff209aSHans Rosenfeld 		lmrc_write_reg(lmrc,
187e9ff209aSHans Rosenfeld 		    MPI26_ATOMIC_REQUEST_DESCRIPTOR_POST_OFFSET,
1881e091e43SHans Rosenfeld 		    req_desc.rd_reg);
1891e091e43SHans Rosenfeld 	} else {
1901e091e43SHans Rosenfeld 		lmrc_req_desc_t rd;
1911e091e43SHans Rosenfeld 
1921e091e43SHans Rosenfeld 		bzero(&rd, sizeof (rd));
1931e091e43SHans Rosenfeld 		rd.rd_atomic = req_desc;
1941e091e43SHans Rosenfeld 
1951e091e43SHans Rosenfeld 		lmrc_send_request(lmrc, rd);
1961e091e43SHans Rosenfeld 	}
1971e091e43SHans Rosenfeld }
1981e091e43SHans Rosenfeld 
1991e091e43SHans Rosenfeld void
lmrc_send_request(lmrc_t * lmrc,lmrc_req_desc_t req_desc)2001e091e43SHans Rosenfeld lmrc_send_request(lmrc_t *lmrc, lmrc_req_desc_t req_desc)
2011e091e43SHans Rosenfeld {
202e9ff209aSHans Rosenfeld 	lmrc_write_reg64(lmrc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET,
203e9ff209aSHans Rosenfeld 	    req_desc.rd_reg);
2041e091e43SHans Rosenfeld }
2051e091e43SHans Rosenfeld 
2061e091e43SHans Rosenfeld lmrc_atomic_req_desc_t
lmrc_build_atomic_request(lmrc_t * lmrc,lmrc_mpt_cmd_t * mpt,uint8_t flags)2071e091e43SHans Rosenfeld lmrc_build_atomic_request(lmrc_t *lmrc, lmrc_mpt_cmd_t *mpt, uint8_t flags)
2081e091e43SHans Rosenfeld {
2091e091e43SHans Rosenfeld 	lmrc_atomic_req_desc_t req_desc;
2101e091e43SHans Rosenfeld 
2111e091e43SHans Rosenfeld 	VERIFY3U(mpt->mpt_smid, !=, 0);
2121e091e43SHans Rosenfeld 
2131e091e43SHans Rosenfeld 	/*
2141e091e43SHans Rosenfeld 	 * Select the reply queue based on the CPU id to distribute reply load
2151e091e43SHans Rosenfeld 	 * among queues.
2161e091e43SHans Rosenfeld 	 */
2171e091e43SHans Rosenfeld 	mpt->mpt_queue = CPU->cpu_id % lmrc->l_max_reply_queues;
2181e091e43SHans Rosenfeld 
2191e091e43SHans Rosenfeld 	bzero(&req_desc, sizeof (req_desc));
2201e091e43SHans Rosenfeld 
2211e091e43SHans Rosenfeld 	req_desc.rd_atomic.RequestFlags = flags;
2221e091e43SHans Rosenfeld 	req_desc.rd_atomic.MSIxIndex = mpt->mpt_queue;
2231e091e43SHans Rosenfeld 	req_desc.rd_atomic.SMID = mpt->mpt_smid;
2241e091e43SHans Rosenfeld 
2251e091e43SHans Rosenfeld 	return (req_desc);
2261e091e43SHans Rosenfeld }
2271e091e43SHans Rosenfeld 
2281e091e43SHans Rosenfeld /*
2291e091e43SHans Rosenfeld  * Reply Processing
2301e091e43SHans Rosenfeld  *
2311e091e43SHans Rosenfeld  * The controller will post replies to completed requests in the DMA memory
2321e091e43SHans Rosenfeld  * provided for that purpose. This memory is divided in equally-sized chunks,
2331e091e43SHans Rosenfeld  * each being a separate reply queue that is also associated with an interrupt
2341e091e43SHans Rosenfeld  * vector. The replies are fixed size structures and will be written by the
2351e091e43SHans Rosenfeld  * hardware in order of completion into the queue. For each queue, there is a
2361e091e43SHans Rosenfeld  * register to tell the hardware which replies have been consumed by the driver.
2371e091e43SHans Rosenfeld  *
2381e091e43SHans Rosenfeld  * In response to an interrupt, the driver will walk the reply queue associated
2391e091e43SHans Rosenfeld  * with the interrupt vector at the last known position and processess all
2401e091e43SHans Rosenfeld  * completed replies. After a number of replies has been processed, or if no
2411e091e43SHans Rosenfeld  * more replies are ready to be processed, the controller will be notified about
2421e091e43SHans Rosenfeld  * the last reply index to be processed by writing the appropriate register.
2431e091e43SHans Rosenfeld  */
2441e091e43SHans Rosenfeld 
2451e091e43SHans Rosenfeld /*
2461e091e43SHans Rosenfeld  * lmrc_get_next_reply_desc
2471e091e43SHans Rosenfeld  *
2481e091e43SHans Rosenfeld  * Get the next unprocessed reply descriptor for a queue, or NULL if there is
2491e091e43SHans Rosenfeld  * none.
2501e091e43SHans Rosenfeld  */
2511e091e43SHans Rosenfeld static Mpi2ReplyDescriptorsUnion_t *
lmrc_get_next_reply_desc(lmrc_t * lmrc,int queue)2521e091e43SHans Rosenfeld lmrc_get_next_reply_desc(lmrc_t *lmrc, int queue)
2531e091e43SHans Rosenfeld {
2541e091e43SHans Rosenfeld 	Mpi2ReplyDescriptorsUnion_t *desc;
2551e091e43SHans Rosenfeld 
2561e091e43SHans Rosenfeld 	desc = lmrc->l_reply_dma.ld_buf;
2571e091e43SHans Rosenfeld 
2581e091e43SHans Rosenfeld 	desc += (queue * lmrc->l_reply_alloc_sz) / sizeof (*desc);
2591e091e43SHans Rosenfeld 	desc += lmrc->l_last_reply_idx[queue];
2601e091e43SHans Rosenfeld 
2611e091e43SHans Rosenfeld 	VERIFY3S(ddi_dma_sync(lmrc->l_reply_dma.ld_hdl,
2621e091e43SHans Rosenfeld 	    (void *)desc - lmrc->l_reply_dma.ld_buf, sizeof (*desc),
2631e091e43SHans Rosenfeld 	    DDI_DMA_SYNC_FORKERNEL), ==, DDI_SUCCESS);
2641e091e43SHans Rosenfeld 
2651e091e43SHans Rosenfeld 	/*
2661e091e43SHans Rosenfeld 	 * Check if this is an unused reply descriptor, indicating that
2671e091e43SHans Rosenfeld 	 * we've reached the end of replies in this queue.
2681e091e43SHans Rosenfeld 	 *
2691e091e43SHans Rosenfeld 	 * Even if the descriptor is only "half unused" we can't use it.
2701e091e43SHans Rosenfeld 	 */
2711e091e43SHans Rosenfeld 	if (desc->Words.Low == MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK ||
2721e091e43SHans Rosenfeld 	    desc->Words.High == MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK)
2731e091e43SHans Rosenfeld 		return (NULL);
2741e091e43SHans Rosenfeld 
2751e091e43SHans Rosenfeld 	/* advance last reply index, wrap around if necessary */
2761e091e43SHans Rosenfeld 	lmrc->l_last_reply_idx[queue]++;
2771e091e43SHans Rosenfeld 	if (lmrc->l_last_reply_idx[queue] >= lmrc->l_reply_q_depth)
2781e091e43SHans Rosenfeld 		lmrc->l_last_reply_idx[queue] = 0;
2791e091e43SHans Rosenfeld 
2801e091e43SHans Rosenfeld 	return (desc);
2811e091e43SHans Rosenfeld }
2821e091e43SHans Rosenfeld 
2831e091e43SHans Rosenfeld /*
2841e091e43SHans Rosenfeld  * lmrc_write_rphi
2851e091e43SHans Rosenfeld  *
2861e091e43SHans Rosenfeld  * Write the Reply Post Host Index register for queue.
2871e091e43SHans Rosenfeld  */
2881e091e43SHans Rosenfeld static void
lmrc_write_rphi(lmrc_t * lmrc,uint32_t queue)2891e091e43SHans Rosenfeld lmrc_write_rphi(lmrc_t *lmrc, uint32_t queue)
2901e091e43SHans Rosenfeld {
2911e091e43SHans Rosenfeld 	int reg = 0;
2921e091e43SHans Rosenfeld 	uint32_t val = (queue << 24) | lmrc->l_last_reply_idx[queue];
2931e091e43SHans Rosenfeld 
2941e091e43SHans Rosenfeld 	if (lmrc->l_intr_type != DDI_INTR_TYPE_MSIX)
2951e091e43SHans Rosenfeld 		VERIFY3U(queue, ==, 0);
2961e091e43SHans Rosenfeld 
2971e091e43SHans Rosenfeld 	if (lmrc->l_msix_combined) {
2981e091e43SHans Rosenfeld 		reg = queue / 8;
2991e091e43SHans Rosenfeld 		val &= 0x07ffffff;
3001e091e43SHans Rosenfeld 	}
3011e091e43SHans Rosenfeld 
3021e091e43SHans Rosenfeld 	lmrc_write_reg(lmrc, lmrc->l_rphi[reg], val);
3031e091e43SHans Rosenfeld }
3041e091e43SHans Rosenfeld 
3051e091e43SHans Rosenfeld /*
3061e091e43SHans Rosenfeld  * lmrc_process_mpt_pkt
3071e091e43SHans Rosenfeld  *
3081e091e43SHans Rosenfeld  * Process a reply to a MPT IO request. Update the scsi_pkt according to status,
3091e091e43SHans Rosenfeld  * ex_status, and data_len, setting up the ARQ pkt if necessary.
3101e091e43SHans Rosenfeld  */
3111e091e43SHans Rosenfeld static void
lmrc_process_mpt_pkt(lmrc_t * lmrc,struct scsi_pkt * pkt,uint8_t status,uint8_t ex_status,uint32_t data_len)3121e091e43SHans Rosenfeld lmrc_process_mpt_pkt(lmrc_t *lmrc, struct scsi_pkt *pkt, uint8_t status,
3131e091e43SHans Rosenfeld     uint8_t ex_status, uint32_t data_len)
3141e091e43SHans Rosenfeld {
3151e091e43SHans Rosenfeld 	pkt->pkt_statistics = 0;
3161e091e43SHans Rosenfeld 	pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
3171e091e43SHans Rosenfeld 	    STATE_XFERRED_DATA | STATE_GOT_STATUS;
3181e091e43SHans Rosenfeld 
3191e091e43SHans Rosenfeld 	pkt->pkt_resid = pkt->pkt_dma_len - data_len;
3201e091e43SHans Rosenfeld 
3211e091e43SHans Rosenfeld 	switch (status) {
3221e091e43SHans Rosenfeld 	case MFI_STAT_OK:
3231e091e43SHans Rosenfeld 	case MFI_STAT_LD_CC_IN_PROGRESS:
3241e091e43SHans Rosenfeld 	case MFI_STAT_LD_RECON_IN_PROGRESS:
3251e091e43SHans Rosenfeld 		pkt->pkt_reason = CMD_CMPLT;
3261e091e43SHans Rosenfeld 		pkt->pkt_scbp[0] = STATUS_GOOD;
3271e091e43SHans Rosenfeld 		break;
3281e091e43SHans Rosenfeld 
3291e091e43SHans Rosenfeld 	case MFI_STAT_SCSI_DONE_WITH_ERROR:
3301e091e43SHans Rosenfeld 	case MFI_STAT_LD_LBA_OUT_OF_RANGE: {
3311e091e43SHans Rosenfeld 		struct scsi_arq_status *arq =
3321e091e43SHans Rosenfeld 		    (struct scsi_arq_status *)pkt->pkt_scbp;
3331e091e43SHans Rosenfeld 
3341e091e43SHans Rosenfeld 		pkt->pkt_reason = CMD_CMPLT;
3351e091e43SHans Rosenfeld 		arq->sts_status.sts_chk = 1;
3361e091e43SHans Rosenfeld 
3371e091e43SHans Rosenfeld 		pkt->pkt_state |= STATE_ARQ_DONE;
3381e091e43SHans Rosenfeld 		arq->sts_rqpkt_reason = CMD_CMPLT;
3391e091e43SHans Rosenfeld 		arq->sts_rqpkt_resid = 0;
3401e091e43SHans Rosenfeld 		arq->sts_rqpkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
3411e091e43SHans Rosenfeld 		    STATE_SENT_CMD | STATE_XFERRED_DATA;
3421e091e43SHans Rosenfeld 		*(uint8_t *)&arq->sts_rqpkt_status = STATUS_GOOD;
3431e091e43SHans Rosenfeld 		break;
3441e091e43SHans Rosenfeld 	}
3451e091e43SHans Rosenfeld 	case MFI_STAT_LD_OFFLINE:
3461e091e43SHans Rosenfeld 	case MFI_STAT_DEVICE_NOT_FOUND:
3471e091e43SHans Rosenfeld 		pkt->pkt_reason = CMD_DEV_GONE;
3481e091e43SHans Rosenfeld 		pkt->pkt_statistics = STAT_DISCON;
3491e091e43SHans Rosenfeld 		break;
3501e091e43SHans Rosenfeld 
3511e091e43SHans Rosenfeld 	default:
352*d25078f9SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN, "!command failed, status = %x, "
3531e091e43SHans Rosenfeld 		    "ex_status = %x, cdb[0] = %x", status, ex_status,
3541e091e43SHans Rosenfeld 		    pkt->pkt_cdbp[0]);
3551e091e43SHans Rosenfeld 		pkt->pkt_reason = CMD_TRAN_ERR;
3561e091e43SHans Rosenfeld 		break;
3571e091e43SHans Rosenfeld 	}
3581e091e43SHans Rosenfeld }
3591e091e43SHans Rosenfeld 
3601e091e43SHans Rosenfeld /*
3611e091e43SHans Rosenfeld  * lmrc_poll_for_reply
3621e091e43SHans Rosenfeld  *
3631e091e43SHans Rosenfeld  * During a panic we'll have to resort to polled I/O to write core dumps.
3641e091e43SHans Rosenfeld  * Repeatedly check the reply queue for a new reply associated with the
3651e091e43SHans Rosenfeld  * given request descriptor and complete it, or return an error if we get
3661e091e43SHans Rosenfeld  * no reply within a reasonable time.
3671e091e43SHans Rosenfeld  */
3681e091e43SHans Rosenfeld int
lmrc_poll_for_reply(lmrc_t * lmrc,lmrc_mpt_cmd_t * mpt)3691e091e43SHans Rosenfeld lmrc_poll_for_reply(lmrc_t *lmrc, lmrc_mpt_cmd_t *mpt)
3701e091e43SHans Rosenfeld {
3711e091e43SHans Rosenfeld 	clock_t max_wait = LMRC_IO_TIMEOUT * MILLISEC * 10;
3721e091e43SHans Rosenfeld 	Mpi25SCSIIORequest_t *io_req = mpt->mpt_io_frame;
3731e091e43SHans Rosenfeld 	Mpi2ReplyDescriptorsUnion_t *desc;
3741e091e43SHans Rosenfeld 	uint16_t desc_smid;
3751e091e43SHans Rosenfeld 
3761e091e43SHans Rosenfeld 	VERIFY(ddi_in_panic());
3771e091e43SHans Rosenfeld 
3781e091e43SHans Rosenfeld 	/*
3791e091e43SHans Rosenfeld 	 * Walk the reply queue. Discard entries which we aren't
3801e091e43SHans Rosenfeld 	 * looking for.
3811e091e43SHans Rosenfeld 	 */
3821e091e43SHans Rosenfeld 	do {
3831e091e43SHans Rosenfeld 		desc = lmrc_get_next_reply_desc(lmrc, mpt->mpt_queue);
3841e091e43SHans Rosenfeld 		if (desc == NULL) {
3851e091e43SHans Rosenfeld 			if (max_wait == 0)
3861e091e43SHans Rosenfeld 				return (TRAN_FATAL_ERROR);
3871e091e43SHans Rosenfeld 
3881e091e43SHans Rosenfeld 			drv_usecwait(100);
3891e091e43SHans Rosenfeld 			max_wait--;
3901e091e43SHans Rosenfeld 			continue;
3911e091e43SHans Rosenfeld 		}
3921e091e43SHans Rosenfeld 
3931e091e43SHans Rosenfeld 		desc_smid = desc->SCSIIOSuccess.SMID;
3941e091e43SHans Rosenfeld 
3951e091e43SHans Rosenfeld 		/* reset descriptor */
3961e091e43SHans Rosenfeld 		desc->Words.Low = MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK;
3971e091e43SHans Rosenfeld 		desc->Words.High = MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK;
3981e091e43SHans Rosenfeld 
3991e091e43SHans Rosenfeld 		lmrc_write_rphi(lmrc, mpt->mpt_queue);
4001e091e43SHans Rosenfeld 	} while (desc == NULL || desc_smid != mpt->mpt_smid);
4011e091e43SHans Rosenfeld 
4021e091e43SHans Rosenfeld 	VERIFY3S(ddi_dma_sync(lmrc->l_ioreq_dma.ld_hdl,
4031e091e43SHans Rosenfeld 	    (void *)io_req - lmrc->l_ioreq_dma.ld_buf,
4041e091e43SHans Rosenfeld 	    LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, DDI_DMA_SYNC_FORKERNEL),
4051e091e43SHans Rosenfeld 	    ==, DDI_SUCCESS);
4061e091e43SHans Rosenfeld 
4071e091e43SHans Rosenfeld 	/* If this is I/O, process it. */
4081e091e43SHans Rosenfeld 	if (io_req->Function == LMRC_MPI2_FUNCTION_LD_IO_REQUEST ||
4091e091e43SHans Rosenfeld 	    io_req->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) {
4101e091e43SHans Rosenfeld 		lmrc_process_mpt_pkt(lmrc, mpt->mpt_pkt,
4111e091e43SHans Rosenfeld 		    io_req->VendorRegion.rc_status,
4121e091e43SHans Rosenfeld 		    io_req->VendorRegion.rc_exstatus, io_req->DataLength);
4131e091e43SHans Rosenfeld 	}
4141e091e43SHans Rosenfeld 
4151e091e43SHans Rosenfeld 	return (TRAN_ACCEPT);
4161e091e43SHans Rosenfeld }
4171e091e43SHans Rosenfeld 
4181e091e43SHans Rosenfeld /*
4191e091e43SHans Rosenfeld  * lmrc_process_replies
4201e091e43SHans Rosenfeld  *
4211e091e43SHans Rosenfeld  * Process all new reply entries in a queue in response to an interrupt.
4221e091e43SHans Rosenfeld  */
4231e091e43SHans Rosenfeld int
lmrc_process_replies(lmrc_t * lmrc,uint8_t queue)4241e091e43SHans Rosenfeld lmrc_process_replies(lmrc_t *lmrc, uint8_t queue)
4251e091e43SHans Rosenfeld {
4261e091e43SHans Rosenfeld 	int nprocessed = 0;
4271e091e43SHans Rosenfeld 	Mpi2ReplyDescriptorsUnion_t *desc;
4281e091e43SHans Rosenfeld 
4291e091e43SHans Rosenfeld 	for (desc = lmrc_get_next_reply_desc(lmrc, queue);
4301e091e43SHans Rosenfeld 	    desc != NULL;
4311e091e43SHans Rosenfeld 	    desc = lmrc_get_next_reply_desc(lmrc, queue)) {
4321e091e43SHans Rosenfeld 		Mpi2SCSIIOSuccessReplyDescriptor_t *reply =
4331e091e43SHans Rosenfeld 		    &desc->SCSIIOSuccess;
4341e091e43SHans Rosenfeld 		uint16_t smid = reply->SMID;
4351e091e43SHans Rosenfeld 		lmrc_mpt_cmd_t *mpt = lmrc->l_mpt_cmds[smid - 1];
4361e091e43SHans Rosenfeld 		lmrc_tgt_t *tgt = NULL;
4371e091e43SHans Rosenfeld 		Mpi25SCSIIORequest_t *io_req;
4381e091e43SHans Rosenfeld 		struct scsi_pkt *pkt;
4391e091e43SHans Rosenfeld 		struct scsi_device *sd;
4401e091e43SHans Rosenfeld 
4411e091e43SHans Rosenfeld 		VERIFY3U(reply->SMID, <=, lmrc->l_max_fw_cmds);
4421e091e43SHans Rosenfeld 
4431e091e43SHans Rosenfeld 		mutex_enter(&mpt->mpt_lock);
4441e091e43SHans Rosenfeld 		mpt->mpt_complete = B_TRUE;
4451e091e43SHans Rosenfeld 		pkt = mpt->mpt_pkt;
4461e091e43SHans Rosenfeld 		io_req = mpt->mpt_io_frame;
4471e091e43SHans Rosenfeld 
4481e091e43SHans Rosenfeld 		VERIFY3S(ddi_dma_sync(lmrc->l_ioreq_dma.ld_hdl,
4491e091e43SHans Rosenfeld 		    (void *)io_req - lmrc->l_ioreq_dma.ld_buf,
4501e091e43SHans Rosenfeld 		    LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE,
4511e091e43SHans Rosenfeld 		    DDI_DMA_SYNC_FORKERNEL), ==, DDI_SUCCESS);
4521e091e43SHans Rosenfeld 
4531e091e43SHans Rosenfeld 
4541e091e43SHans Rosenfeld 		switch (io_req->Function) {
4551e091e43SHans Rosenfeld 		case MPI2_FUNCTION_SCSI_TASK_MGMT:
4561e091e43SHans Rosenfeld 			VERIFY0(pkt);
4571e091e43SHans Rosenfeld 			VERIFY0(list_link_active(&mpt->mpt_node));
4581e091e43SHans Rosenfeld 			cv_signal(&mpt->mpt_cv);
4591e091e43SHans Rosenfeld 			break;
4601e091e43SHans Rosenfeld 
4611e091e43SHans Rosenfeld 		case MPI2_FUNCTION_SCSI_IO_REQUEST:
4621e091e43SHans Rosenfeld 		case LMRC_MPI2_FUNCTION_LD_IO_REQUEST:
4631e091e43SHans Rosenfeld 			VERIFY(pkt != NULL);
4641e091e43SHans Rosenfeld 
4651e091e43SHans Rosenfeld 			sd = scsi_address_device(&pkt->pkt_address);
4661e091e43SHans Rosenfeld 			VERIFY(sd != NULL);
4671e091e43SHans Rosenfeld 
4681e091e43SHans Rosenfeld 			tgt = scsi_device_hba_private_get(sd);
4691e091e43SHans Rosenfeld 			VERIFY(tgt != NULL);
4701e091e43SHans Rosenfeld 
4711e091e43SHans Rosenfeld 			lmrc_process_mpt_pkt(lmrc, pkt,
4721e091e43SHans Rosenfeld 			    io_req->VendorRegion.rc_status,
4731e091e43SHans Rosenfeld 			    io_req->VendorRegion.rc_exstatus,
4741e091e43SHans Rosenfeld 			    io_req->DataLength);
4751e091e43SHans Rosenfeld 
4761e091e43SHans Rosenfeld 			break;
4771e091e43SHans Rosenfeld 
4781e091e43SHans Rosenfeld 		case LMRC_MPI2_FUNCTION_PASSTHRU_IO_REQUEST:
4791e091e43SHans Rosenfeld 			VERIFY0(pkt);
4801e091e43SHans Rosenfeld 			VERIFY0(list_link_active(&mpt->mpt_node));
4811e091e43SHans Rosenfeld 			lmrc_process_mptmfi_passthru(lmrc, mpt);
4821e091e43SHans Rosenfeld 			break;
4831e091e43SHans Rosenfeld 
4841e091e43SHans Rosenfeld 		default:
4851e091e43SHans Rosenfeld 			mutex_exit(&mpt->mpt_lock);
4861e091e43SHans Rosenfeld 			dev_err(lmrc->l_dip, CE_PANIC,
487*d25078f9SHans Rosenfeld 			    "reply received for unknown Function %x",
4881e091e43SHans Rosenfeld 			    io_req->Function);
4891e091e43SHans Rosenfeld 		}
4901e091e43SHans Rosenfeld 
4911e091e43SHans Rosenfeld 		mutex_exit(&mpt->mpt_lock);
4921e091e43SHans Rosenfeld 
4931e091e43SHans Rosenfeld 		if (pkt != NULL) {
4941e091e43SHans Rosenfeld 			lmrc_tgt_rem_active_mpt(tgt, mpt);
4951e091e43SHans Rosenfeld 			atomic_dec_uint(&lmrc->l_fw_outstanding_cmds);
4961e091e43SHans Rosenfeld 			scsi_hba_pkt_comp(pkt);
4971e091e43SHans Rosenfeld 		}
4981e091e43SHans Rosenfeld 
4991e091e43SHans Rosenfeld 		/* reset descriptor */
5001e091e43SHans Rosenfeld 		desc->Words.Low = MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK;
5011e091e43SHans Rosenfeld 		desc->Words.High = MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK;
5021e091e43SHans Rosenfeld 
5031e091e43SHans Rosenfeld 		nprocessed++;
5041e091e43SHans Rosenfeld 
5051e091e43SHans Rosenfeld 		if (nprocessed % LMRC_THRESHOLD_REPLY_COUNT == 0)
5061e091e43SHans Rosenfeld 			lmrc_write_rphi(lmrc, queue);
5071e091e43SHans Rosenfeld 	}
5081e091e43SHans Rosenfeld 
5091e091e43SHans Rosenfeld 	if (nprocessed != 0 && nprocessed % LMRC_THRESHOLD_REPLY_COUNT != 0)
5101e091e43SHans Rosenfeld 		lmrc_write_rphi(lmrc, queue);
5111e091e43SHans Rosenfeld 
5121e091e43SHans Rosenfeld 	return (DDI_INTR_CLAIMED);
5131e091e43SHans Rosenfeld }
5141e091e43SHans Rosenfeld 
5151e091e43SHans Rosenfeld 
5161e091e43SHans Rosenfeld /*
5171e091e43SHans Rosenfeld  * MFI - MegaRAID Firmware Interface
5181e091e43SHans Rosenfeld  */
5191e091e43SHans Rosenfeld 
5201e091e43SHans Rosenfeld /*
5211e091e43SHans Rosenfeld  * lmrc_build_mptmfi_passthru
5221e091e43SHans Rosenfeld  *
523d8b83e34SHans Rosenfeld  * MFI commands are send as MPT MFI passthrough I/O requests. To be able to send
524d8b83e34SHans Rosenfeld  * a MFI frame to the RAID controller, we need to have a MPT command set up as
525d8b83e34SHans Rosenfeld  * MPT I/O request and a one-entry SGL pointing to the MFI command.
526d8b83e34SHans Rosenfeld  *
527d8b83e34SHans Rosenfeld  * As there's only a small number of MFI commands compared to the amound of MPT
528d8b83e34SHans Rosenfeld  * commands, the MPT command for each MFI is pre-allocated at attach time and
529d8b83e34SHans Rosenfeld  * initialized here.
5301e091e43SHans Rosenfeld  */
531d8b83e34SHans Rosenfeld int
lmrc_build_mptmfi_passthru(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi)5321e091e43SHans Rosenfeld lmrc_build_mptmfi_passthru(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi)
5331e091e43SHans Rosenfeld {
5341e091e43SHans Rosenfeld 	Mpi25SCSIIORequest_t *io_req;
5351e091e43SHans Rosenfeld 	const ddi_dma_cookie_t *cookie;
5361e091e43SHans Rosenfeld 	lmrc_mpt_cmd_t *mpt;
5371e091e43SHans Rosenfeld 
5381e091e43SHans Rosenfeld 	mpt = lmrc_get_mpt(lmrc);
539d8b83e34SHans Rosenfeld 	if (mpt == NULL)
540d8b83e34SHans Rosenfeld 		return (DDI_FAILURE);
541d8b83e34SHans Rosenfeld 
542d8b83e34SHans Rosenfeld 	/* lmrc_get_mpt() should return the mpt locked */
5431e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mpt->mpt_lock));
5441e091e43SHans Rosenfeld 
5451e091e43SHans Rosenfeld 	mfi->mfi_mpt = mpt;
5461e091e43SHans Rosenfeld 	mpt->mpt_mfi = mfi;
5471e091e43SHans Rosenfeld 
5481e091e43SHans Rosenfeld 	io_req = mpt->mpt_io_frame;
5491e091e43SHans Rosenfeld 	io_req->Function = LMRC_MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
5501e091e43SHans Rosenfeld 	io_req->ChainOffset = lmrc->l_chain_offset_mfi_pthru;
5511e091e43SHans Rosenfeld 
5521e091e43SHans Rosenfeld 	cookie = ddi_dma_cookie_one(mfi->mfi_frame_dma.ld_hdl);
5531e091e43SHans Rosenfeld 	lmrc_dma_build_sgl(lmrc, mpt, cookie, 1);
5541e091e43SHans Rosenfeld 
5551e091e43SHans Rosenfeld 	VERIFY3S(ddi_dma_sync(lmrc->l_ioreq_dma.ld_hdl,
5561e091e43SHans Rosenfeld 	    (void *)io_req - lmrc->l_ioreq_dma.ld_buf,
5571e091e43SHans Rosenfeld 	    LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, DDI_DMA_SYNC_FORDEV),
5581e091e43SHans Rosenfeld 	    ==, DDI_SUCCESS);
559d8b83e34SHans Rosenfeld 
560d8b83e34SHans Rosenfeld 	/*
561d8b83e34SHans Rosenfeld 	 * As we're not sending this command to the hardware any time soon,
562d8b83e34SHans Rosenfeld 	 * drop the mutex before we return.
563d8b83e34SHans Rosenfeld 	 */
564d8b83e34SHans Rosenfeld 	mutex_exit(&mpt->mpt_lock);
565d8b83e34SHans Rosenfeld 
566d8b83e34SHans Rosenfeld 	return (DDI_SUCCESS);
5671e091e43SHans Rosenfeld }
5681e091e43SHans Rosenfeld 
5691e091e43SHans Rosenfeld /*
5701e091e43SHans Rosenfeld  * lmrc_process_mptmfi_passthru
5711e091e43SHans Rosenfeld  *
5721e091e43SHans Rosenfeld  * When a MPT MFI passthrough command completes, invoke the callback if there
5731e091e43SHans Rosenfeld  * is one. Panic if an invalid command completed as that should never happen.
5741e091e43SHans Rosenfeld  */
5751e091e43SHans Rosenfeld static void
lmrc_process_mptmfi_passthru(lmrc_t * lmrc,lmrc_mpt_cmd_t * mpt)5761e091e43SHans Rosenfeld lmrc_process_mptmfi_passthru(lmrc_t *lmrc, lmrc_mpt_cmd_t *mpt)
5771e091e43SHans Rosenfeld {
5781e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi;
5791e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr;
5801e091e43SHans Rosenfeld 
5811e091e43SHans Rosenfeld 	VERIFY3P(mpt->mpt_mfi, !=, NULL);
5821e091e43SHans Rosenfeld 	mfi = mpt->mpt_mfi;
5831e091e43SHans Rosenfeld 	VERIFY0(list_link_active(&mfi->mfi_node));
5841e091e43SHans Rosenfeld 
5851e091e43SHans Rosenfeld 	hdr = &mfi->mfi_frame->mf_hdr;
5861e091e43SHans Rosenfeld 
5871e091e43SHans Rosenfeld 	if ((hdr->mh_flags & MFI_FRAME_DIR_READ) != 0)
5881e091e43SHans Rosenfeld 		(void) ddi_dma_sync(mfi->mfi_data_dma.ld_hdl, 0,
5891e091e43SHans Rosenfeld 		    mfi->mfi_data_dma.ld_len, DDI_DMA_SYNC_FORKERNEL);
5901e091e43SHans Rosenfeld 
5911e091e43SHans Rosenfeld 	switch (hdr->mh_cmd) {
5921e091e43SHans Rosenfeld 	case MFI_CMD_DCMD:
5931e091e43SHans Rosenfeld 	case MFI_CMD_LD_SCSI_IO:
5941e091e43SHans Rosenfeld 	case MFI_CMD_PD_SCSI_IO:
5951e091e43SHans Rosenfeld 	case MFI_CMD_ABORT:
5961e091e43SHans Rosenfeld 		mutex_enter(&mfi->mfi_lock);
5971e091e43SHans Rosenfeld 		if (mfi->mfi_callback != NULL)
5981e091e43SHans Rosenfeld 			mfi->mfi_callback(lmrc, mfi);
5991e091e43SHans Rosenfeld 		mutex_exit(&mfi->mfi_lock);
6001e091e43SHans Rosenfeld 		break;
6011e091e43SHans Rosenfeld 
6021e091e43SHans Rosenfeld 	case MFI_CMD_INVALID:
6031e091e43SHans Rosenfeld 	default:
6041e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_PANIC,
605*d25078f9SHans Rosenfeld 		    "invalid MFI cmd completion received, cmd = %x",
6061e091e43SHans Rosenfeld 		    hdr->mh_cmd);
6071e091e43SHans Rosenfeld 		break;
6081e091e43SHans Rosenfeld 	}
6091e091e43SHans Rosenfeld }
6101e091e43SHans Rosenfeld 
6111e091e43SHans Rosenfeld /*
6121e091e43SHans Rosenfeld  * lmrc_issue_mfi
6131e091e43SHans Rosenfeld  *
6141e091e43SHans Rosenfeld  * Post a MFI command to the firmware. Reset the cmd_status to invalid. Build
6151e091e43SHans Rosenfeld  * a MPT MFI passthru command if necessary and a MPT atomic request descriptor
616d8b83e34SHans Rosenfeld  * before posting the request. The MFI command's mutex must be held.
6171e091e43SHans Rosenfeld  */
6181e091e43SHans Rosenfeld void
lmrc_issue_mfi(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi,lmrc_mfi_cmd_cb_t * cb)6191e091e43SHans Rosenfeld lmrc_issue_mfi(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi, lmrc_mfi_cmd_cb_t *cb)
6201e091e43SHans Rosenfeld {
6211e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
6221e091e43SHans Rosenfeld 	lmrc_atomic_req_desc_t req_desc;
6231e091e43SHans Rosenfeld 
6241e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mfi->mfi_lock));
6251e091e43SHans Rosenfeld 
6261e091e43SHans Rosenfeld 	if ((hdr->mh_flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE) == 0) {
6271e091e43SHans Rosenfeld 		VERIFY3U(cb, !=, NULL);
6281e091e43SHans Rosenfeld 		mfi->mfi_callback = cb;
6291e091e43SHans Rosenfeld 	} else {
6301e091e43SHans Rosenfeld 		VERIFY3U(cb, ==, NULL);
6311e091e43SHans Rosenfeld 	}
6321e091e43SHans Rosenfeld 
6331e091e43SHans Rosenfeld 	hdr->mh_cmd_status = MFI_STAT_INVALID_STATUS;
6341e091e43SHans Rosenfeld 
6351e091e43SHans Rosenfeld 	req_desc = lmrc_build_atomic_request(lmrc, mfi->mfi_mpt,
6361e091e43SHans Rosenfeld 	    MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO);
6371e091e43SHans Rosenfeld 
6381e091e43SHans Rosenfeld 	(void) ddi_dma_sync(mfi->mfi_frame_dma.ld_hdl, 0,
6391e091e43SHans Rosenfeld 	    mfi->mfi_frame_dma.ld_len, DDI_DMA_SYNC_FORDEV);
6401e091e43SHans Rosenfeld 
6411e091e43SHans Rosenfeld 	if ((hdr->mh_flags & MFI_FRAME_DIR_WRITE) != 0)
6421e091e43SHans Rosenfeld 		(void) ddi_dma_sync(mfi->mfi_data_dma.ld_hdl, 0,
6431e091e43SHans Rosenfeld 		    mfi->mfi_data_dma.ld_len, DDI_DMA_SYNC_FORDEV);
6441e091e43SHans Rosenfeld 
6451e091e43SHans Rosenfeld 	lmrc_send_atomic_request(lmrc, req_desc);
6461e091e43SHans Rosenfeld }
6471e091e43SHans Rosenfeld 
6481e091e43SHans Rosenfeld /*
6491e091e43SHans Rosenfeld  * lmrc_poll_mfi
6501e091e43SHans Rosenfeld  *
6511e091e43SHans Rosenfeld  * Poll a MFI command for completion, waiting up to max_wait secs. Repeatedly
6521e091e43SHans Rosenfeld  * check the command status until it changes to something that is not invalid.
6531e091e43SHans Rosenfeld  *
6541e091e43SHans Rosenfeld  * Trigger an online controller reset on timeout.
6551e091e43SHans Rosenfeld  */
6561e091e43SHans Rosenfeld static int
lmrc_poll_mfi(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi,uint8_t max_wait)6571e091e43SHans Rosenfeld lmrc_poll_mfi(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi, uint8_t max_wait)
6581e091e43SHans Rosenfeld {
6591e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
6601e091e43SHans Rosenfeld 	lmrc_dma_t *dma = &mfi->mfi_frame_dma;
6611e091e43SHans Rosenfeld 	clock_t timeout = ddi_get_lbolt() + drv_usectohz(max_wait * MICROSEC);
6621e091e43SHans Rosenfeld 	clock_t now;
6631e091e43SHans Rosenfeld 
6641e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mfi->mfi_lock));
6651e091e43SHans Rosenfeld 
6661e091e43SHans Rosenfeld 	do {
6671e091e43SHans Rosenfeld 		(void) ddi_dma_sync(dma->ld_hdl, 0, dma->ld_len,
6681e091e43SHans Rosenfeld 		    DDI_DMA_SYNC_FORKERNEL);
6691e091e43SHans Rosenfeld 		if (hdr->mh_cmd_status != MFI_STAT_INVALID_STATUS)
6701e091e43SHans Rosenfeld 			break;
6711e091e43SHans Rosenfeld 
6721e091e43SHans Rosenfeld 		(void) cv_reltimedwait(&mfi->mfi_cv, &mfi->mfi_lock,
6731e091e43SHans Rosenfeld 		    drv_usectohz(MILLISEC), TR_MILLISEC);
6741e091e43SHans Rosenfeld 		now = ddi_get_lbolt();
6751e091e43SHans Rosenfeld 	} while (!lmrc->l_fw_fault && now <= timeout);
6761e091e43SHans Rosenfeld 
6771e091e43SHans Rosenfeld 	if (hdr->mh_cmd_status != MFI_STAT_INVALID_STATUS)
6781e091e43SHans Rosenfeld 		return (DDI_SUCCESS);
6791e091e43SHans Rosenfeld 
6801e091e43SHans Rosenfeld 	if (now > timeout) {
6811e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN,
6821e091e43SHans Rosenfeld 		    "!%s: command timeout after %ds", __func__, max_wait);
6831e091e43SHans Rosenfeld 
6841e091e43SHans Rosenfeld 		/*
6851e091e43SHans Rosenfeld 		 * Signal the housekeeping thread to check for FW/HW faults,
6861e091e43SHans Rosenfeld 		 * performing a reset if necessary.
6871e091e43SHans Rosenfeld 		 */
6881e091e43SHans Rosenfeld 		cv_signal(&lmrc->l_thread_cv);
6891e091e43SHans Rosenfeld 	}
6901e091e43SHans Rosenfeld 
6911e091e43SHans Rosenfeld 	return (DDI_FAILURE);
6921e091e43SHans Rosenfeld }
6931e091e43SHans Rosenfeld 
6941e091e43SHans Rosenfeld /*
6951e091e43SHans Rosenfeld  * lmrc_wait_mfi
6961e091e43SHans Rosenfeld  *
6971e091e43SHans Rosenfeld  * Wait for up to max_wait secs for a MFI command to complete. The cmd mutex
6981e091e43SHans Rosenfeld  * must be held.
6991e091e43SHans Rosenfeld  *
7001e091e43SHans Rosenfeld  * Trigger an online controller reset on timeout.
7011e091e43SHans Rosenfeld  */
7021e091e43SHans Rosenfeld int
lmrc_wait_mfi(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi,uint8_t max_wait)7031e091e43SHans Rosenfeld lmrc_wait_mfi(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi, uint8_t max_wait)
7041e091e43SHans Rosenfeld {
7051e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
7061e091e43SHans Rosenfeld 	lmrc_dma_t *dma = &mfi->mfi_frame_dma;
7071e091e43SHans Rosenfeld 	clock_t timeout = ddi_get_lbolt() + drv_usectohz(max_wait * MICROSEC);
7081e091e43SHans Rosenfeld 	int ret;
7091e091e43SHans Rosenfeld 
7101e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mfi->mfi_lock));
7111e091e43SHans Rosenfeld 
7121e091e43SHans Rosenfeld 	do {
7131e091e43SHans Rosenfeld 		ret = cv_timedwait(&mfi->mfi_cv, &mfi->mfi_lock, timeout);
7141e091e43SHans Rosenfeld 
7151e091e43SHans Rosenfeld 		(void) ddi_dma_sync(dma->ld_hdl, 0, dma->ld_len,
7161e091e43SHans Rosenfeld 		    DDI_DMA_SYNC_FORKERNEL);
7171e091e43SHans Rosenfeld 
7181e091e43SHans Rosenfeld 	} while (!lmrc->l_fw_fault &&
7191e091e43SHans Rosenfeld 	    hdr->mh_cmd_status == MFI_STAT_INVALID_STATUS && ret != -1);
7201e091e43SHans Rosenfeld 
7211e091e43SHans Rosenfeld 	if (!lmrc->l_fw_fault && ret != -1)
7221e091e43SHans Rosenfeld 		return (DDI_SUCCESS);
7231e091e43SHans Rosenfeld 
7241e091e43SHans Rosenfeld 	if (ret == -1) {
7251e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN, "!%s: blocked command timeout "
7261e091e43SHans Rosenfeld 		    "after %ds, cmd = %d, status = %d", __func__, max_wait,
7271e091e43SHans Rosenfeld 		    hdr->mh_cmd, hdr->mh_cmd_status);
7281e091e43SHans Rosenfeld 
7291e091e43SHans Rosenfeld 		/*
7301e091e43SHans Rosenfeld 		 * Signal the housekeeping thread to check for FW/HW faults,
7311e091e43SHans Rosenfeld 		 * performing a reset if necessary.
7321e091e43SHans Rosenfeld 		 */
7331e091e43SHans Rosenfeld 		cv_signal(&lmrc->l_thread_cv);
7341e091e43SHans Rosenfeld 	}
7351e091e43SHans Rosenfeld 
7361e091e43SHans Rosenfeld 	return (DDI_FAILURE);
7371e091e43SHans Rosenfeld }
7381e091e43SHans Rosenfeld 
7391e091e43SHans Rosenfeld /*
7401e091e43SHans Rosenfeld  * lmrc_wakeup_mfi
7411e091e43SHans Rosenfeld  *
7421e091e43SHans Rosenfeld  * Signal the CV associated with a MFI command to wake up the thread waiting
7431e091e43SHans Rosenfeld  * for its completion.
7441e091e43SHans Rosenfeld  */
7451e091e43SHans Rosenfeld void
lmrc_wakeup_mfi(lmrc_t * lmrc,lmrc_mfi_cmd_t * cmd)7461e091e43SHans Rosenfeld lmrc_wakeup_mfi(lmrc_t *lmrc, lmrc_mfi_cmd_t *cmd)
7471e091e43SHans Rosenfeld {
7481e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&cmd->mfi_lock));
7491e091e43SHans Rosenfeld 	cv_signal(&cmd->mfi_cv);
7501e091e43SHans Rosenfeld }
7511e091e43SHans Rosenfeld 
7521e091e43SHans Rosenfeld /*
7531e091e43SHans Rosenfeld  * lmrc_issue_blocked_mfi
7541e091e43SHans Rosenfeld  *
7551e091e43SHans Rosenfeld  * Post a MFI command to the firmware and wait for the command to complete.
7561e091e43SHans Rosenfeld  */
7571e091e43SHans Rosenfeld int
lmrc_issue_blocked_mfi(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi)7581e091e43SHans Rosenfeld lmrc_issue_blocked_mfi(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi)
7591e091e43SHans Rosenfeld {
7601e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
7611e091e43SHans Rosenfeld 	int ret;
7621e091e43SHans Rosenfeld 
7631e091e43SHans Rosenfeld 	mutex_enter(&mfi->mfi_lock);
7641e091e43SHans Rosenfeld 	lmrc_issue_mfi(lmrc, mfi, lmrc_wakeup_mfi);
7651e091e43SHans Rosenfeld 	ret = lmrc_wait_mfi(lmrc, mfi, LMRC_INTERNAL_CMD_WAIT_TIME);
7661e091e43SHans Rosenfeld 	mutex_exit(&mfi->mfi_lock);
7671e091e43SHans Rosenfeld 
7681e091e43SHans Rosenfeld 	if (ret == DDI_SUCCESS && hdr->mh_cmd_status == MFI_STAT_OK)
7691e091e43SHans Rosenfeld 		return (DDI_SUCCESS);
7701e091e43SHans Rosenfeld 
7711e091e43SHans Rosenfeld 	dev_err(lmrc->l_dip, CE_WARN,
7721e091e43SHans Rosenfeld 	    "!%s: blocked command failure, cmd = %d, status = %d",
7731e091e43SHans Rosenfeld 	    __func__, hdr->mh_cmd, hdr->mh_cmd_status);
7741e091e43SHans Rosenfeld 
7751e091e43SHans Rosenfeld 	return (ret);
7761e091e43SHans Rosenfeld }
7771e091e43SHans Rosenfeld 
7781e091e43SHans Rosenfeld /*
7791e091e43SHans Rosenfeld  * lmrc_abort_cb
7801e091e43SHans Rosenfeld  *
7811e091e43SHans Rosenfeld  * Callback for any command that is to be aborted.
7821e091e43SHans Rosenfeld  *
7831e091e43SHans Rosenfeld  * If the command completed normally before it could be aborted, set the status
7841e091e43SHans Rosenfeld  * to indicate the intended abortion.
7851e091e43SHans Rosenfeld  */
7861e091e43SHans Rosenfeld static void
lmrc_abort_cb(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi)7871e091e43SHans Rosenfeld lmrc_abort_cb(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi)
7881e091e43SHans Rosenfeld {
7891e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
7901e091e43SHans Rosenfeld 
7911e091e43SHans Rosenfeld 	if (hdr->mh_cmd_status == MFI_STAT_OK)
7921e091e43SHans Rosenfeld 		hdr->mh_cmd_status = MFI_STAT_NOT_FOUND;
7931e091e43SHans Rosenfeld }
7941e091e43SHans Rosenfeld 
7951e091e43SHans Rosenfeld /*
7961e091e43SHans Rosenfeld  * lmrc_abort_mfi
7971e091e43SHans Rosenfeld  *
7981e091e43SHans Rosenfeld  * Abort a MFI command. This is a bit tricky as the hardware may still complete
7991e091e43SHans Rosenfeld  * it at any time.
8001e091e43SHans Rosenfeld  *
8011e091e43SHans Rosenfeld  * The mutex of the command to be aborted must be held to prevent it from
8021e091e43SHans Rosenfeld  * completing behind our back. We'll replace its callback with our own, issue an
8031e091e43SHans Rosenfeld  * ABORT command, and drop the mutex before we wait for the ABORT command to
8041e091e43SHans Rosenfeld  * complete.
8051e091e43SHans Rosenfeld  */
8061e091e43SHans Rosenfeld static int
lmrc_abort_cmd(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi_to_abort)8071e091e43SHans Rosenfeld lmrc_abort_cmd(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi_to_abort)
8081e091e43SHans Rosenfeld {
8091e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi = lmrc_get_mfi(lmrc);
8101e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
8111e091e43SHans Rosenfeld 	lmrc_mfi_abort_payload_t *abort = &mfi->mfi_frame->mf_abort;
8121e091e43SHans Rosenfeld 	lmrc_mfi_cmd_cb_t *orig_cb = mfi_to_abort->mfi_callback;
8131e091e43SHans Rosenfeld 	int ret;
8141e091e43SHans Rosenfeld 
8151e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mfi_to_abort->mfi_lock));
8161e091e43SHans Rosenfeld 
8171e091e43SHans Rosenfeld 	/* Replace the commands callback with our own. */
8181e091e43SHans Rosenfeld 	mfi_to_abort->mfi_callback = lmrc_abort_cb;
8191e091e43SHans Rosenfeld 
8201e091e43SHans Rosenfeld 	hdr->mh_cmd = MFI_CMD_ABORT;
8211e091e43SHans Rosenfeld 	abort->ma_abort_context = mfi_to_abort->mfi_idx;
8221e091e43SHans Rosenfeld 	lmrc_dma_set_addr64(&mfi_to_abort->mfi_frame_dma,
8231e091e43SHans Rosenfeld 	    &abort->ma_abort_mfi_phys_addr);
8241e091e43SHans Rosenfeld 
8251e091e43SHans Rosenfeld 	/* Send the ABORT. */
8261e091e43SHans Rosenfeld 	mutex_enter(&mfi->mfi_lock);
8271e091e43SHans Rosenfeld 	lmrc_issue_mfi(lmrc, mfi, lmrc_wakeup_mfi);
8281e091e43SHans Rosenfeld 
8291e091e43SHans Rosenfeld 	/*
8301e091e43SHans Rosenfeld 	 * Drop the mutex of the command to be aborted, allowing it to proceed
8311e091e43SHans Rosenfeld 	 * while we wait for the ABORT command to complete.
8321e091e43SHans Rosenfeld 	 */
8331e091e43SHans Rosenfeld 	mutex_exit(&mfi_to_abort->mfi_lock);
8341e091e43SHans Rosenfeld 	ret = lmrc_wait_mfi(lmrc, mfi, LMRC_INTERNAL_CMD_WAIT_TIME);
8351e091e43SHans Rosenfeld 	mutex_exit(&mfi->mfi_lock);
8361e091e43SHans Rosenfeld 
8371e091e43SHans Rosenfeld 	/*
8381e091e43SHans Rosenfeld 	 * The ABORT command may fail if cmd_to_abort has completed already.
8391e091e43SHans Rosenfeld 	 * Treat any other failure as fatal, restore the callback and fail.
8401e091e43SHans Rosenfeld 	 */
8411e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS && hdr->mh_cmd_status != MFI_STAT_NOT_FOUND) {
8421e091e43SHans Rosenfeld 		mutex_enter(&mfi_to_abort->mfi_lock);
8431e091e43SHans Rosenfeld 		mfi_to_abort->mfi_callback = orig_cb;
8441e091e43SHans Rosenfeld 		goto out;
8451e091e43SHans Rosenfeld 	}
8461e091e43SHans Rosenfeld 
8471e091e43SHans Rosenfeld 	/*
8481e091e43SHans Rosenfeld 	 * Wait for the aborted command to complete. If we time out on this
8491e091e43SHans Rosenfeld 	 * there's little we can do here, so we restore the callback and fail.
8501e091e43SHans Rosenfeld 	 */
8511e091e43SHans Rosenfeld 	mutex_enter(&mfi_to_abort->mfi_lock);
8521e091e43SHans Rosenfeld 	ret = lmrc_poll_mfi(lmrc, mfi_to_abort, LMRC_INTERNAL_CMD_WAIT_TIME);
8531e091e43SHans Rosenfeld 	mfi_to_abort->mfi_callback = orig_cb;
8541e091e43SHans Rosenfeld 
8551e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
8561e091e43SHans Rosenfeld 		goto out;
8571e091e43SHans Rosenfeld 
8581e091e43SHans Rosenfeld 	/* Wake up anyone waiting on the aborted command. */
8591e091e43SHans Rosenfeld 	if (mfi_to_abort->mfi_callback != NULL)
8601e091e43SHans Rosenfeld 		mfi_to_abort->mfi_callback(lmrc, mfi_to_abort);
8611e091e43SHans Rosenfeld 
8621e091e43SHans Rosenfeld out:
8631e091e43SHans Rosenfeld 	lmrc_put_mfi(mfi);
8641e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mfi_to_abort->mfi_lock));
8651e091e43SHans Rosenfeld 	return (ret);
8661e091e43SHans Rosenfeld }
8671e091e43SHans Rosenfeld 
8681e091e43SHans Rosenfeld 
8691e091e43SHans Rosenfeld /*
8701e091e43SHans Rosenfeld  * Controller Initialization and Housekeeping
8711e091e43SHans Rosenfeld  */
8721e091e43SHans Rosenfeld 
8731e091e43SHans Rosenfeld /*
8741e091e43SHans Rosenfeld  * lmrc_check_fw_fault
8751e091e43SHans Rosenfeld  *
8761e091e43SHans Rosenfeld  * Check the firmware state. If faulted, return B_TRUE.
8771e091e43SHans Rosenfeld  * Return B_FALSE otherwise.
8781e091e43SHans Rosenfeld  */
8791e091e43SHans Rosenfeld static boolean_t
lmrc_check_fw_fault(lmrc_t * lmrc)8801e091e43SHans Rosenfeld lmrc_check_fw_fault(lmrc_t *lmrc)
8811e091e43SHans Rosenfeld {
882e9ff209aSHans Rosenfeld 	uint32_t status = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD0_OFFSET);
8831e091e43SHans Rosenfeld 	uint32_t fw_state = LMRC_FW_STATE(status);
8841e091e43SHans Rosenfeld 
8851e091e43SHans Rosenfeld 	if (fw_state == LMRC_FW_STATE_FAULT)
8861e091e43SHans Rosenfeld 		return (B_TRUE);
8871e091e43SHans Rosenfeld 
8881e091e43SHans Rosenfeld 	return (B_FALSE);
8891e091e43SHans Rosenfeld }
8901e091e43SHans Rosenfeld 
8911e091e43SHans Rosenfeld /*
8921e091e43SHans Rosenfeld  * lmrc_wait_for_reg
8931e091e43SHans Rosenfeld  *
8941e091e43SHans Rosenfeld  * Repeatedly read the register and check that 'bits' match 'exp'.
8951e091e43SHans Rosenfeld  */
8961e091e43SHans Rosenfeld static boolean_t
lmrc_wait_for_reg(lmrc_t * lmrc,uint32_t reg,uint32_t bits,uint32_t exp,uint64_t max_wait)8971e091e43SHans Rosenfeld lmrc_wait_for_reg(lmrc_t *lmrc, uint32_t reg, uint32_t bits, uint32_t exp,
898e9ff209aSHans Rosenfeld     uint64_t max_wait)
8991e091e43SHans Rosenfeld {
9001e091e43SHans Rosenfeld 	uint32_t val;
901e9ff209aSHans Rosenfeld 	uint64_t i;
9021e091e43SHans Rosenfeld 
9031e091e43SHans Rosenfeld 	max_wait *= MILLISEC / 100;
9041e091e43SHans Rosenfeld 
9051e091e43SHans Rosenfeld 	for (i = 0; i < max_wait; i++) {
9061e091e43SHans Rosenfeld 		delay(drv_usectohz(100 * MILLISEC));
9071e091e43SHans Rosenfeld 		val = lmrc_read_reg(lmrc, reg);
9081e091e43SHans Rosenfeld 
9091e091e43SHans Rosenfeld 		if ((val & bits) == exp)
9101e091e43SHans Rosenfeld 			return (B_TRUE);
9111e091e43SHans Rosenfeld 	}
9121e091e43SHans Rosenfeld 
9131e091e43SHans Rosenfeld 	return (B_FALSE);
9141e091e43SHans Rosenfeld }
9151e091e43SHans Rosenfeld 
916e9ff209aSHans Rosenfeld static int
lmrc_hard_reset(lmrc_t * lmrc)917e9ff209aSHans Rosenfeld lmrc_hard_reset(lmrc_t *lmrc)
918e9ff209aSHans Rosenfeld {
919e9ff209aSHans Rosenfeld 	int ret = DDI_SUCCESS;
920e9ff209aSHans Rosenfeld 
921e9ff209aSHans Rosenfeld 	/* Write the reset key sequence. */
922e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_WRITE_SEQUENCE_OFFSET,
923e9ff209aSHans Rosenfeld 	    MPI2_WRSEQ_FLUSH_KEY_VALUE);
924e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_WRITE_SEQUENCE_OFFSET,
925e9ff209aSHans Rosenfeld 	    MPI2_WRSEQ_1ST_KEY_VALUE);
926e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_WRITE_SEQUENCE_OFFSET,
927e9ff209aSHans Rosenfeld 	    MPI2_WRSEQ_2ND_KEY_VALUE);
928e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_WRITE_SEQUENCE_OFFSET,
929e9ff209aSHans Rosenfeld 	    MPI2_WRSEQ_3RD_KEY_VALUE);
930e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_WRITE_SEQUENCE_OFFSET,
931e9ff209aSHans Rosenfeld 	    MPI2_WRSEQ_4TH_KEY_VALUE);
932e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_WRITE_SEQUENCE_OFFSET,
933e9ff209aSHans Rosenfeld 	    MPI2_WRSEQ_5TH_KEY_VALUE);
934e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_WRITE_SEQUENCE_OFFSET,
935e9ff209aSHans Rosenfeld 	    MPI2_WRSEQ_6TH_KEY_VALUE);
936e9ff209aSHans Rosenfeld 
937e9ff209aSHans Rosenfeld 	/* Check diag write enable. */
938e9ff209aSHans Rosenfeld 	if (!lmrc_wait_for_reg(lmrc, MPI2_HOST_DIAGNOSTIC_OFFSET,
939e9ff209aSHans Rosenfeld 	    MPI2_DIAG_DIAG_WRITE_ENABLE, MPI2_DIAG_DIAG_WRITE_ENABLE,
940e9ff209aSHans Rosenfeld 	    LMRC_RESET_TIMEOUT)) {
941e9ff209aSHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN, "diag unlock failed");
942e9ff209aSHans Rosenfeld 		return (DDI_FAILURE);
943e9ff209aSHans Rosenfeld 	}
944e9ff209aSHans Rosenfeld 
945e9ff209aSHans Rosenfeld 	/* Reset IOC. */
946e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_HOST_DIAGNOSTIC_OFFSET,
947e9ff209aSHans Rosenfeld 	    lmrc_read_reg(lmrc, MPI2_HOST_DIAGNOSTIC_OFFSET) |
948e9ff209aSHans Rosenfeld 	    MPI2_DIAG_RESET_ADAPTER);
949e9ff209aSHans Rosenfeld 	delay(drv_usectohz(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC));
950e9ff209aSHans Rosenfeld 
951e9ff209aSHans Rosenfeld 	/* Check the reset adapter bit. */
952e9ff209aSHans Rosenfeld 	if ((lmrc_read_reg(lmrc, MPI2_HOST_DIAGNOSTIC_OFFSET) &
953e9ff209aSHans Rosenfeld 	    MPI2_DIAG_RESET_ADAPTER) == 0)
954e9ff209aSHans Rosenfeld 		goto out;
955e9ff209aSHans Rosenfeld 
956e9ff209aSHans Rosenfeld 	delay(drv_usectohz(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC));
957e9ff209aSHans Rosenfeld 
958e9ff209aSHans Rosenfeld 	/* Check the reset adapter bit again. */
959e9ff209aSHans Rosenfeld 	if ((lmrc_read_reg(lmrc, MPI2_HOST_DIAGNOSTIC_OFFSET) &
960e9ff209aSHans Rosenfeld 	    MPI2_DIAG_RESET_ADAPTER) == 0)
961e9ff209aSHans Rosenfeld 		goto out;
962e9ff209aSHans Rosenfeld 
963e9ff209aSHans Rosenfeld 	ret = DDI_FAILURE;
964e9ff209aSHans Rosenfeld out:
965e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_WRITE_SEQUENCE_OFFSET,
966e9ff209aSHans Rosenfeld 	    MPI2_WRSEQ_FLUSH_KEY_VALUE);
967e9ff209aSHans Rosenfeld 	return (ret);
968e9ff209aSHans Rosenfeld }
969e9ff209aSHans Rosenfeld 
9701e091e43SHans Rosenfeld /*
9711e091e43SHans Rosenfeld  * lmrc_reset_ctrl
9721e091e43SHans Rosenfeld  *
9731e091e43SHans Rosenfeld  * Attempt to reset the controller, if the hardware supports it.
9741e091e43SHans Rosenfeld  * If reset is unsupported or the reset fails repeatedly, we shut the
9751e091e43SHans Rosenfeld  * controller down.
9761e091e43SHans Rosenfeld  */
9771e091e43SHans Rosenfeld static int
lmrc_reset_ctrl(lmrc_t * lmrc)9781e091e43SHans Rosenfeld lmrc_reset_ctrl(lmrc_t *lmrc)
9791e091e43SHans Rosenfeld {
9801e091e43SHans Rosenfeld 	uint32_t status, fw_state, reset_adapter;
9811e091e43SHans Rosenfeld 	int max_wait, i;
9821e091e43SHans Rosenfeld 
9831e091e43SHans Rosenfeld 	if (lmrc->l_disable_online_ctrl_reset)
9841e091e43SHans Rosenfeld 		return (DDI_FAILURE);
9851e091e43SHans Rosenfeld 
986e9ff209aSHans Rosenfeld 	status = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD0_OFFSET);
9871e091e43SHans Rosenfeld 	fw_state = LMRC_FW_STATE(status);
9881e091e43SHans Rosenfeld 	reset_adapter = LMRC_FW_RESET_ADAPTER(status);
9891e091e43SHans Rosenfeld 
9901e091e43SHans Rosenfeld 	if (fw_state == LMRC_FW_STATE_FAULT && reset_adapter == 0) {
9911e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN,
9921e091e43SHans Rosenfeld 		    "FW in fault state, but reset not supported");
9931e091e43SHans Rosenfeld 		goto out;
9941e091e43SHans Rosenfeld 	}
9951e091e43SHans Rosenfeld 
9961e091e43SHans Rosenfeld 	for (i = 0; i < LMRC_MAX_RESET_TRIES; i++) {
9971e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN, "resetting...");
9981e091e43SHans Rosenfeld 
999e9ff209aSHans Rosenfeld 		if (lmrc_hard_reset(lmrc) != DDI_SUCCESS)
10001e091e43SHans Rosenfeld 			continue;
10011e091e43SHans Rosenfeld 
10021e091e43SHans Rosenfeld 		/* Wait for the FW state to move beyond INIT. */
10031e091e43SHans Rosenfeld 		max_wait = LMRC_IO_TIMEOUT * MILLISEC / 100;
10041e091e43SHans Rosenfeld 		do {
1005e9ff209aSHans Rosenfeld 			status = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD0_OFFSET);
10061e091e43SHans Rosenfeld 			fw_state = LMRC_FW_STATE(status);
10071e091e43SHans Rosenfeld 
10081e091e43SHans Rosenfeld 			if (fw_state <= LMRC_FW_STATE_FW_INIT)
10091e091e43SHans Rosenfeld 				delay(drv_usectohz(100 * MILLISEC));
10101e091e43SHans Rosenfeld 		} while (fw_state <= LMRC_FW_STATE_FW_INIT && max_wait > 0);
10111e091e43SHans Rosenfeld 
10121e091e43SHans Rosenfeld 		if (fw_state <= LMRC_FW_STATE_FW_INIT) {
10131e091e43SHans Rosenfeld 			dev_err(lmrc->l_dip, CE_WARN,
10141e091e43SHans Rosenfeld 			    "fw state <= LMRC_FW_STATE_FW_INIT, state = %x",
10151e091e43SHans Rosenfeld 			    fw_state);
10161e091e43SHans Rosenfeld 			continue;
10171e091e43SHans Rosenfeld 		}
10181e091e43SHans Rosenfeld 
10191e091e43SHans Rosenfeld 		return (DDI_SUCCESS);
10201e091e43SHans Rosenfeld 	}
10211e091e43SHans Rosenfeld 
10221e091e43SHans Rosenfeld 	dev_err(lmrc->l_dip, CE_WARN, "reset failed");
10231e091e43SHans Rosenfeld out:
10241e091e43SHans Rosenfeld 	/* Stop the controller. */
1025e9ff209aSHans Rosenfeld 	lmrc_write_reg(lmrc, MPI2_DOORBELL_OFFSET, MFI_STOP_ADP);
1026e9ff209aSHans Rosenfeld 	(void) lmrc_read_reg(lmrc, MPI2_DOORBELL_OFFSET);
10271e091e43SHans Rosenfeld 
10281e091e43SHans Rosenfeld 	return (DDI_FAILURE);
10291e091e43SHans Rosenfeld }
10301e091e43SHans Rosenfeld 
10311e091e43SHans Rosenfeld /*
10321e091e43SHans Rosenfeld  * lmrc_tgt_complete_cmd
10331e091e43SHans Rosenfeld  *
10341e091e43SHans Rosenfeld  * In case of a controller reset, complete the cmd and clean up. This is done
10351e091e43SHans Rosenfeld  * in a taskq to avoid locking and list manipulation headaches.
10361e091e43SHans Rosenfeld  */
10371e091e43SHans Rosenfeld static void
lmrc_tgt_complete_cmd(void * arg)10381e091e43SHans Rosenfeld lmrc_tgt_complete_cmd(void *arg)
10391e091e43SHans Rosenfeld {
10401e091e43SHans Rosenfeld 	lmrc_scsa_cmd_t *cmd = arg;
10411e091e43SHans Rosenfeld 	struct scsi_pkt *pkt;
10421e091e43SHans Rosenfeld 	lmrc_t *lmrc;
10431e091e43SHans Rosenfeld 
10441e091e43SHans Rosenfeld 	mutex_enter(&cmd->sc_mpt->mpt_lock);
10451e091e43SHans Rosenfeld 
10461e091e43SHans Rosenfeld 	/* Just in case the command completed before the taskq was run... */
10471e091e43SHans Rosenfeld 	if (cmd->sc_mpt->mpt_complete) {
10481e091e43SHans Rosenfeld 		mutex_exit(&cmd->sc_mpt->mpt_lock);
10491e091e43SHans Rosenfeld 		return;
10501e091e43SHans Rosenfeld 	}
10511e091e43SHans Rosenfeld 
10521e091e43SHans Rosenfeld 	lmrc = cmd->sc_mpt->mpt_lmrc;
10531e091e43SHans Rosenfeld 	pkt = cmd->sc_mpt->mpt_pkt;
10541e091e43SHans Rosenfeld 
10551e091e43SHans Rosenfeld 	pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD;
10561e091e43SHans Rosenfeld 	pkt->pkt_reason = CMD_RESET;
10571e091e43SHans Rosenfeld 	pkt->pkt_statistics = STAT_BUS_RESET;
10581e091e43SHans Rosenfeld 	mutex_exit(&cmd->sc_mpt->mpt_lock);
10591e091e43SHans Rosenfeld 
10601e091e43SHans Rosenfeld 	lmrc_tgt_rem_active_mpt(cmd->sc_tgt, cmd->sc_mpt);
10611e091e43SHans Rosenfeld 	atomic_dec_uint(&lmrc->l_fw_outstanding_cmds);
10621e091e43SHans Rosenfeld 
10631e091e43SHans Rosenfeld 	scsi_hba_pkt_comp(pkt);
10641e091e43SHans Rosenfeld }
10651e091e43SHans Rosenfeld 
10661e091e43SHans Rosenfeld /*
10671e091e43SHans Rosenfeld  * lmrc_tgt_complete_cmds
10681e091e43SHans Rosenfeld  *
10691e091e43SHans Rosenfeld  * Walk the list of active commands of a target. Schedule a taskq to handle the
10701e091e43SHans Rosenfeld  * timeout processing and clean up.
10711e091e43SHans Rosenfeld  */
10721e091e43SHans Rosenfeld static void
lmrc_tgt_complete_cmds(lmrc_t * lmrc,lmrc_tgt_t * tgt)10731e091e43SHans Rosenfeld lmrc_tgt_complete_cmds(lmrc_t *lmrc, lmrc_tgt_t *tgt)
10741e091e43SHans Rosenfeld {
10751e091e43SHans Rosenfeld 	lmrc_mpt_cmd_t *mpt;
10761e091e43SHans Rosenfeld 
10771e091e43SHans Rosenfeld 	mutex_enter(&tgt->tgt_mpt_active_lock);
10781e091e43SHans Rosenfeld 	if (list_is_empty(&tgt->tgt_mpt_active)) {
10791e091e43SHans Rosenfeld 		mutex_exit(&tgt->tgt_mpt_active_lock);
10801e091e43SHans Rosenfeld 		return;
10811e091e43SHans Rosenfeld 	}
10821e091e43SHans Rosenfeld 
10831e091e43SHans Rosenfeld 	for (mpt = lmrc_tgt_first_active_mpt(tgt);
10841e091e43SHans Rosenfeld 	    mpt != NULL;
10851e091e43SHans Rosenfeld 	    mpt = lmrc_tgt_next_active_mpt(tgt, mpt)) {
10861e091e43SHans Rosenfeld 		lmrc_scsa_cmd_t *cmd = mpt->mpt_pkt->pkt_ha_private;
10871e091e43SHans Rosenfeld 
10881e091e43SHans Rosenfeld 		ASSERT(mutex_owned(&mpt->mpt_lock));
10891e091e43SHans Rosenfeld 		VERIFY(mpt->mpt_pkt != NULL);
10901e091e43SHans Rosenfeld 		VERIFY(cmd != NULL);
10911e091e43SHans Rosenfeld 
10921e091e43SHans Rosenfeld 		if (mpt->mpt_complete)
10931e091e43SHans Rosenfeld 			continue;
10941e091e43SHans Rosenfeld 
10951e091e43SHans Rosenfeld 		taskq_dispatch_ent(lmrc->l_taskq, lmrc_tgt_complete_cmd, cmd,
10961e091e43SHans Rosenfeld 		    TQ_NOSLEEP, &mpt->mpt_tqent);
10971e091e43SHans Rosenfeld 	}
10981e091e43SHans Rosenfeld 	mutex_exit(&tgt->tgt_mpt_active_lock);
10991e091e43SHans Rosenfeld }
11001e091e43SHans Rosenfeld 
11011e091e43SHans Rosenfeld /*
11021e091e43SHans Rosenfeld  * lmrc_tgt_timeout_cmds
11031e091e43SHans Rosenfeld  *
11041e091e43SHans Rosenfeld  * Walk the list of active commands of a target. Try to abort commands which are
11051e091e43SHans Rosenfeld  * overdue.
11061e091e43SHans Rosenfeld  */
11071e091e43SHans Rosenfeld static int
lmrc_tgt_timeout_cmds(lmrc_t * lmrc,lmrc_tgt_t * tgt)11081e091e43SHans Rosenfeld lmrc_tgt_timeout_cmds(lmrc_t *lmrc, lmrc_tgt_t *tgt)
11091e091e43SHans Rosenfeld {
11101e091e43SHans Rosenfeld 	lmrc_mpt_cmd_t *mpt;
11111e091e43SHans Rosenfeld 	int ret = DDI_SUCCESS;
11121e091e43SHans Rosenfeld 
11131e091e43SHans Rosenfeld 	mutex_enter(&tgt->tgt_mpt_active_lock);
11141e091e43SHans Rosenfeld 	if (list_is_empty(&tgt->tgt_mpt_active))
11151e091e43SHans Rosenfeld 		goto out;
11161e091e43SHans Rosenfeld 
11171e091e43SHans Rosenfeld 	for (mpt = lmrc_tgt_first_active_mpt(tgt);
11181e091e43SHans Rosenfeld 	    mpt != NULL;
11191e091e43SHans Rosenfeld 	    mpt = lmrc_tgt_next_active_mpt(tgt, mpt)) {
11201e091e43SHans Rosenfeld 		hrtime_t now;
11211e091e43SHans Rosenfeld 
11221e091e43SHans Rosenfeld 		ASSERT(mutex_owned(&mpt->mpt_lock));
11231e091e43SHans Rosenfeld 		VERIFY(mpt->mpt_pkt != NULL);
11241e091e43SHans Rosenfeld 
11251e091e43SHans Rosenfeld 		/* Just in case the command completed by now... */
11261e091e43SHans Rosenfeld 		if (mpt->mpt_complete)
11271e091e43SHans Rosenfeld 			continue;
11281e091e43SHans Rosenfeld 
11291e091e43SHans Rosenfeld 		now = gethrtime();
11301e091e43SHans Rosenfeld 
11311e091e43SHans Rosenfeld 		if (now > mpt->mpt_timeout) {
11321e091e43SHans Rosenfeld 			/*
11331e091e43SHans Rosenfeld 			 * Give the packet a bit more time for the abort to
11341e091e43SHans Rosenfeld 			 * complete.
11351e091e43SHans Rosenfeld 			 */
11361e091e43SHans Rosenfeld 			mpt->mpt_timeout = now + LMRC_IO_TIMEOUT * NANOSEC;
11371e091e43SHans Rosenfeld 
11381e091e43SHans Rosenfeld 			/*
11391e091e43SHans Rosenfeld 			 * If the abort failed for whatever reason,
11401e091e43SHans Rosenfeld 			 * we can stop here as only a controller reset
11411e091e43SHans Rosenfeld 			 * can get us back into a sane state.
11421e091e43SHans Rosenfeld 			 */
11431e091e43SHans Rosenfeld 			if (lmrc_abort_mpt(lmrc, tgt, mpt) != 1) {
11441e091e43SHans Rosenfeld 				mutex_exit(&mpt->mpt_lock);
11451e091e43SHans Rosenfeld 				ret = DDI_FAILURE;
11461e091e43SHans Rosenfeld 				goto out;
11471e091e43SHans Rosenfeld 			}
11481e091e43SHans Rosenfeld 		}
11491e091e43SHans Rosenfeld 	}
11501e091e43SHans Rosenfeld 
11511e091e43SHans Rosenfeld out:
11521e091e43SHans Rosenfeld 	mutex_exit(&tgt->tgt_mpt_active_lock);
11531e091e43SHans Rosenfeld 	return (ret);
11541e091e43SHans Rosenfeld }
11551e091e43SHans Rosenfeld 
11561e091e43SHans Rosenfeld /*
11571e091e43SHans Rosenfeld  * lmrc_thread
11581e091e43SHans Rosenfeld  *
11591e091e43SHans Rosenfeld  * Check whether the controller is FW fault state. Check all targets for
11601e091e43SHans Rosenfeld  * commands which have timed out.
11611e091e43SHans Rosenfeld  */
11621e091e43SHans Rosenfeld void
lmrc_thread(void * arg)11631e091e43SHans Rosenfeld lmrc_thread(void *arg)
11641e091e43SHans Rosenfeld {
11651e091e43SHans Rosenfeld 	lmrc_t *lmrc = arg;
11661e091e43SHans Rosenfeld 
11671e091e43SHans Rosenfeld 	do {
11681e091e43SHans Rosenfeld 		int i;
11691e091e43SHans Rosenfeld 
11701e091e43SHans Rosenfeld 		/* Wake up at least once a minute. */
11711e091e43SHans Rosenfeld 		mutex_enter(&lmrc->l_thread_lock);
11721e091e43SHans Rosenfeld 		(void) cv_reltimedwait(&lmrc->l_thread_cv, &lmrc->l_thread_lock,
11731e091e43SHans Rosenfeld 		    drv_usectohz(60 * MICROSEC), TR_SEC);
11741e091e43SHans Rosenfeld 		mutex_exit(&lmrc->l_thread_lock);
11751e091e43SHans Rosenfeld 
11761e091e43SHans Rosenfeld 		if (lmrc->l_thread_stop)
11771e091e43SHans Rosenfeld 			continue;
11781e091e43SHans Rosenfeld 
11791e091e43SHans Rosenfeld 		lmrc->l_fw_fault = lmrc_check_fw_fault(lmrc);
11801e091e43SHans Rosenfeld 
11811e091e43SHans Rosenfeld 		/*
11821e091e43SHans Rosenfeld 		 * Check all targets for timed-out commands. If we find any
11831e091e43SHans Rosenfeld 		 * and fail to abort them, we pretend the FW has faulted to
11841e091e43SHans Rosenfeld 		 * trigger a reset.
11851e091e43SHans Rosenfeld 		 */
11861e091e43SHans Rosenfeld 		if (!lmrc->l_fw_fault) {
11871e091e43SHans Rosenfeld 			for (i = 0; i < ARRAY_SIZE(lmrc->l_targets); i++) {
11881e091e43SHans Rosenfeld 				if (lmrc_tgt_timeout_cmds(lmrc,
11891e091e43SHans Rosenfeld 				    &lmrc->l_targets[i]) != DDI_SUCCESS) {
11901e091e43SHans Rosenfeld 					lmrc->l_fw_fault = B_TRUE;
11911e091e43SHans Rosenfeld 					break;
11921e091e43SHans Rosenfeld 				}
11931e091e43SHans Rosenfeld 			}
11941e091e43SHans Rosenfeld 		}
11951e091e43SHans Rosenfeld 
11961e091e43SHans Rosenfeld 		/*
11971e091e43SHans Rosenfeld 		 * If the FW is faulted, try to recover by performing a reset.
11981e091e43SHans Rosenfeld 		 */
11991e091e43SHans Rosenfeld 		if (lmrc->l_fw_fault) {
12001e091e43SHans Rosenfeld 			int ret;
12011e091e43SHans Rosenfeld 
12021e091e43SHans Rosenfeld 			lmrc_disable_intr(lmrc);
12031e091e43SHans Rosenfeld 
12041e091e43SHans Rosenfeld 			/*
12051e091e43SHans Rosenfeld 			 * Even if the reset failed, it will have stopped the
12061e091e43SHans Rosenfeld 			 * controller and we can complete all outstanding
12071e091e43SHans Rosenfeld 			 * commands.
12081e091e43SHans Rosenfeld 			 */
12091e091e43SHans Rosenfeld 			ret = lmrc_reset_ctrl(lmrc);
12101e091e43SHans Rosenfeld 
12111e091e43SHans Rosenfeld 			(void) lmrc_abort_outstanding_mfi(lmrc,
12121e091e43SHans Rosenfeld 			    LMRC_MAX_MFI_CMDS);
12131e091e43SHans Rosenfeld 
12141e091e43SHans Rosenfeld 			for (i = 0; i < ARRAY_SIZE(lmrc->l_targets); i++)
12151e091e43SHans Rosenfeld 				lmrc_tgt_complete_cmds(lmrc,
12161e091e43SHans Rosenfeld 				    &lmrc->l_targets[i]);
12171e091e43SHans Rosenfeld 
12181e091e43SHans Rosenfeld 			if (ret != DDI_SUCCESS) {
12191e091e43SHans Rosenfeld 				dev_err(lmrc->l_dip, CE_WARN, "reset failed");
12201e091e43SHans Rosenfeld 				continue;
12211e091e43SHans Rosenfeld 			}
12221e091e43SHans Rosenfeld 
12231e091e43SHans Rosenfeld 			if (lmrc_transition_to_ready(lmrc) != DDI_SUCCESS)
12241e091e43SHans Rosenfeld 				continue;
12251e091e43SHans Rosenfeld 
12261e091e43SHans Rosenfeld 			if (lmrc_ioc_init(lmrc) != DDI_SUCCESS)
12271e091e43SHans Rosenfeld 				continue;
12281e091e43SHans Rosenfeld 
12291e091e43SHans Rosenfeld 			lmrc_enable_intr(lmrc);
12301e091e43SHans Rosenfeld 
12311e091e43SHans Rosenfeld 			if (lmrc_start_aen(lmrc) != DDI_SUCCESS) {
12321e091e43SHans Rosenfeld 				dev_err(lmrc->l_dip, CE_WARN,
12331e091e43SHans Rosenfeld 				    "failed to re-initiate AEN");
12341e091e43SHans Rosenfeld 				continue;
12351e091e43SHans Rosenfeld 			}
12361e091e43SHans Rosenfeld 
12371e091e43SHans Rosenfeld 			lmrc->l_fw_fault = lmrc_check_fw_fault(lmrc);
12381e091e43SHans Rosenfeld 		}
12391e091e43SHans Rosenfeld 	} while (!lmrc->l_thread_stop);
12401e091e43SHans Rosenfeld 
12411e091e43SHans Rosenfeld 	thread_exit();
12421e091e43SHans Rosenfeld }
12431e091e43SHans Rosenfeld 
12441e091e43SHans Rosenfeld /*
12451e091e43SHans Rosenfeld  * lmrc_transition_to_ready
12461e091e43SHans Rosenfeld  *
12471e091e43SHans Rosenfeld  * Move firmware to ready state. At attach time, the FW can potentially be in
12481e091e43SHans Rosenfeld  * any one of several possible states. If the FW is in operational, waiting-for-
12491e091e43SHans Rosenfeld  * handshake states, take steps to bring it to ready state. Otherwise, wait for
12501e091e43SHans Rosenfeld  * the FW to reach ready state.
12511e091e43SHans Rosenfeld  */
12521e091e43SHans Rosenfeld static int
lmrc_transition_to_ready(lmrc_t * lmrc)12531e091e43SHans Rosenfeld lmrc_transition_to_ready(lmrc_t *lmrc)
12541e091e43SHans Rosenfeld {
12551e091e43SHans Rosenfeld 	uint32_t status, new_status;
12561e091e43SHans Rosenfeld 	uint32_t fw_state;
12571e091e43SHans Rosenfeld 	uint8_t max_wait;
12581e091e43SHans Rosenfeld 	uint_t i;
12591e091e43SHans Rosenfeld 
1260e9ff209aSHans Rosenfeld 	status = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD0_OFFSET);
12611e091e43SHans Rosenfeld 	fw_state = LMRC_FW_STATE(status);
12621e091e43SHans Rosenfeld 	max_wait = LMRC_RESET_TIMEOUT;
12631e091e43SHans Rosenfeld 
12641e091e43SHans Rosenfeld 	while (fw_state != LMRC_FW_STATE_READY) {
12651e091e43SHans Rosenfeld 		switch (fw_state) {
12661e091e43SHans Rosenfeld 		case LMRC_FW_STATE_FAULT:
12671e091e43SHans Rosenfeld 			dev_err(lmrc->l_dip, CE_NOTE, "FW is in fault state!");
12681e091e43SHans Rosenfeld 			if (lmrc_reset_ctrl(lmrc) != DDI_SUCCESS)
12691e091e43SHans Rosenfeld 				return (DDI_FAILURE);
12701e091e43SHans Rosenfeld 			break;
12711e091e43SHans Rosenfeld 
12721e091e43SHans Rosenfeld 		case LMRC_FW_STATE_WAIT_HANDSHAKE:
12731e091e43SHans Rosenfeld 			/* Set the CLR bit in inbound doorbell */
1274e9ff209aSHans Rosenfeld 			lmrc_write_reg(lmrc, MPI2_DOORBELL_OFFSET,
12751e091e43SHans Rosenfeld 			    MFI_INIT_CLEAR_HANDSHAKE | MFI_INIT_HOTPLUG);
12761e091e43SHans Rosenfeld 			break;
12771e091e43SHans Rosenfeld 
12781e091e43SHans Rosenfeld 		case LMRC_FW_STATE_BOOT_MSG_PENDING:
1279e9ff209aSHans Rosenfeld 			lmrc_write_reg(lmrc, MPI2_DOORBELL_OFFSET,
12801e091e43SHans Rosenfeld 			    MFI_INIT_HOTPLUG);
12811e091e43SHans Rosenfeld 			break;
12821e091e43SHans Rosenfeld 
12831e091e43SHans Rosenfeld 		case LMRC_FW_STATE_OPERATIONAL:
12841e091e43SHans Rosenfeld 			/* Bring it to READY state, wait up to 10s */
12851e091e43SHans Rosenfeld 			lmrc_disable_intr(lmrc);
1286e9ff209aSHans Rosenfeld 			lmrc_write_reg(lmrc, MPI2_DOORBELL_OFFSET,
1287e9ff209aSHans Rosenfeld 			    MFI_RESET_FLAGS);
1288e9ff209aSHans Rosenfeld 			(void) lmrc_wait_for_reg(lmrc, MPI2_DOORBELL_OFFSET, 1,
1289e9ff209aSHans Rosenfeld 			    0, 10);
12901e091e43SHans Rosenfeld 			break;
12911e091e43SHans Rosenfeld 
12921e091e43SHans Rosenfeld 		case LMRC_FW_STATE_UNDEFINED:
12931e091e43SHans Rosenfeld 			/* This state should not last for more than 2 sec */
12941e091e43SHans Rosenfeld 		case LMRC_FW_STATE_BB_INIT:
12951e091e43SHans Rosenfeld 		case LMRC_FW_STATE_FW_INIT:
12961e091e43SHans Rosenfeld 		case LMRC_FW_STATE_FW_INIT_2:
12971e091e43SHans Rosenfeld 		case LMRC_FW_STATE_DEVICE_SCAN:
12981e091e43SHans Rosenfeld 		case LMRC_FW_STATE_FLUSH_CACHE:
12991e091e43SHans Rosenfeld 			break;
13001e091e43SHans Rosenfeld 		default:
13011e091e43SHans Rosenfeld 			dev_err(lmrc->l_dip, CE_WARN, "Unknown FW state %x",
13021e091e43SHans Rosenfeld 			    fw_state);
13031e091e43SHans Rosenfeld 			return (DDI_FAILURE);
13041e091e43SHans Rosenfeld 		}
13051e091e43SHans Rosenfeld 
13061e091e43SHans Rosenfeld 		/*
13071e091e43SHans Rosenfeld 		 * The current state should not last for more than max_wait
13081e091e43SHans Rosenfeld 		 * seconds.
13091e091e43SHans Rosenfeld 		 */
13101e091e43SHans Rosenfeld 		for (i = 0; i < max_wait * 1000; i++) {
13111e091e43SHans Rosenfeld 			new_status = lmrc_read_reg(lmrc,
1312e9ff209aSHans Rosenfeld 			    MPI26_SCRATCHPAD0_OFFSET);
13131e091e43SHans Rosenfeld 
13141e091e43SHans Rosenfeld 			if (status != new_status)
13151e091e43SHans Rosenfeld 				break;
13161e091e43SHans Rosenfeld 
13171e091e43SHans Rosenfeld 			delay(drv_usectohz(MILLISEC));
13181e091e43SHans Rosenfeld 		}
13191e091e43SHans Rosenfeld 
13201e091e43SHans Rosenfeld 		if (new_status == status) {
13211e091e43SHans Rosenfeld 			dev_err(lmrc->l_dip, CE_WARN,
13221e091e43SHans Rosenfeld 			    "FW state (%x) hasn't changed in %d seconds",
13231e091e43SHans Rosenfeld 			    fw_state, max_wait);
13241e091e43SHans Rosenfeld 			return (DDI_FAILURE);
13251e091e43SHans Rosenfeld 		}
13261e091e43SHans Rosenfeld 
13271e091e43SHans Rosenfeld 		status = new_status;
13281e091e43SHans Rosenfeld 		fw_state = LMRC_FW_STATE(status);
13291e091e43SHans Rosenfeld 	}
13301e091e43SHans Rosenfeld 
13311e091e43SHans Rosenfeld 	if (lmrc_check_acc_handle(lmrc->l_reghandle) != DDI_FM_OK)
13321e091e43SHans Rosenfeld 		return (DDI_FAILURE);
13331e091e43SHans Rosenfeld 
13341e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
13351e091e43SHans Rosenfeld }
13361e091e43SHans Rosenfeld 
13371e091e43SHans Rosenfeld /*
13381e091e43SHans Rosenfeld  * lmrc_adapter_init
13391e091e43SHans Rosenfeld  *
13401e091e43SHans Rosenfeld  * Get the hardware and firmware into a usable state, and fetch some basic
13411e091e43SHans Rosenfeld  * information from the registers to calculate sizes of basic data structures.
13421e091e43SHans Rosenfeld  */
13431e091e43SHans Rosenfeld int
lmrc_adapter_init(lmrc_t * lmrc)13441e091e43SHans Rosenfeld lmrc_adapter_init(lmrc_t *lmrc)
13451e091e43SHans Rosenfeld {
13461e091e43SHans Rosenfeld 	uint32_t reg;
13471e091e43SHans Rosenfeld 	int ret;
13481e091e43SHans Rosenfeld 	int i;
13491e091e43SHans Rosenfeld 
13501e091e43SHans Rosenfeld 	ret = lmrc_transition_to_ready(lmrc);
13511e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
13521e091e43SHans Rosenfeld 		return (ret);
13531e091e43SHans Rosenfeld 
13541e091e43SHans Rosenfeld 	/*
13551e091e43SHans Rosenfeld 	 * Get maximum RAID map size.
13561e091e43SHans Rosenfeld 	 */
1357e9ff209aSHans Rosenfeld 	reg = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD2_OFFSET);
13581e091e43SHans Rosenfeld 	lmrc->l_max_raid_map_sz = LMRC_MAX_RAID_MAP_SZ(reg);
13591e091e43SHans Rosenfeld 
13601e091e43SHans Rosenfeld 	lmrc->l_max_reply_queues = 1;
1361e9ff209aSHans Rosenfeld 	lmrc->l_rphi[0] = MPI2_REPLY_POST_HOST_INDEX_OFFSET;
13621e091e43SHans Rosenfeld 
13631e091e43SHans Rosenfeld 	/*
13641e091e43SHans Rosenfeld 	 * Apparently, bit 27 of the scratch pad register indicates whether
13651e091e43SHans Rosenfeld 	 * MSI-X is supported by the firmware.
13661e091e43SHans Rosenfeld 	 */
1367e9ff209aSHans Rosenfeld 	reg = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD0_OFFSET);
13681e091e43SHans Rosenfeld 
13691e091e43SHans Rosenfeld 	if (LMRC_FW_MSIX_ENABLED(reg)) {
13701e091e43SHans Rosenfeld 		lmrc->l_fw_msix_enabled = B_TRUE;
13711e091e43SHans Rosenfeld 
1372e9ff209aSHans Rosenfeld 		reg = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD1_OFFSET);
13731e091e43SHans Rosenfeld 		lmrc->l_max_reply_queues = LMRC_MAX_REPLY_QUEUES_EXT(reg);
13741e091e43SHans Rosenfeld 
13751e091e43SHans Rosenfeld 		if (lmrc->l_max_reply_queues > LMRC_MAX_REPLY_POST_HOST_INDEX) {
13761e091e43SHans Rosenfeld 			lmrc->l_msix_combined = B_TRUE;
13771e091e43SHans Rosenfeld 			lmrc->l_rphi[0] =
1378e9ff209aSHans Rosenfeld 			    MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET;
13791e091e43SHans Rosenfeld 		}
13801e091e43SHans Rosenfeld 
13811e091e43SHans Rosenfeld 		/*
13821e091e43SHans Rosenfeld 		 * Compute reply post index register addresses 1-15.
13831e091e43SHans Rosenfeld 		 */
13841e091e43SHans Rosenfeld 		for (i = 1; i < LMRC_MAX_REPLY_POST_HOST_INDEX; i++) {
13851e091e43SHans Rosenfeld 			lmrc->l_rphi[i] = i * 0x10 +
1386e9ff209aSHans Rosenfeld 			    MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET;
13871e091e43SHans Rosenfeld 		}
13881e091e43SHans Rosenfeld 	}
13891e091e43SHans Rosenfeld 
13901e091e43SHans Rosenfeld 	/*
13911e091e43SHans Rosenfeld 	 * Get the number of commands the firmware supports. Use one less,
13921e091e43SHans Rosenfeld 	 * because reply_q_depth is based on one more than this. XXX: Why?
13931e091e43SHans Rosenfeld 	 */
1394e9ff209aSHans Rosenfeld 	reg = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD0_OFFSET);
13951e091e43SHans Rosenfeld 	lmrc->l_max_fw_cmds = LMRC_FW_MAX_CMD(reg) - 1;
13961e091e43SHans Rosenfeld 
13971e091e43SHans Rosenfeld 	if (lmrc->l_max_fw_cmds < LMRC_MAX_MFI_CMDS) {
13981e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN, "!max_fw_cmds too low: %d",
13991e091e43SHans Rosenfeld 		    lmrc->l_max_fw_cmds);
14001e091e43SHans Rosenfeld 		return (DDI_FAILURE);
14011e091e43SHans Rosenfeld 	}
14021e091e43SHans Rosenfeld 
14031e091e43SHans Rosenfeld 	/*
14041e091e43SHans Rosenfeld 	 * Reserve some commands for MFI, the remainder is for SCSI commands.
14051e091e43SHans Rosenfeld 	 */
14061e091e43SHans Rosenfeld 	lmrc->l_max_scsi_cmds = lmrc->l_max_fw_cmds - LMRC_MAX_MFI_CMDS;
14071e091e43SHans Rosenfeld 
14081e091e43SHans Rosenfeld 	/*
14091e091e43SHans Rosenfeld 	 * XXX: This magic calculation isn't explained anywhere. Let's see...
14101e091e43SHans Rosenfeld 	 * lmrc_max_fw_cmds + 1 gives us what was reported in the register,
14111e091e43SHans Rosenfeld 	 * That + 15 is for rounding it up the next multiple of 16, which
14121e091e43SHans Rosenfeld 	 * / 16 * 16 does.
14131e091e43SHans Rosenfeld 	 * And apparently we want twice that much for queue depth. Why?
14141e091e43SHans Rosenfeld 	 *
14151e091e43SHans Rosenfeld 	 * So in reality, the queue depth is based on at least one more than
14161e091e43SHans Rosenfeld 	 * lmrc_max_fw_cmds, but it could be even more. That makes the above
14171e091e43SHans Rosenfeld 	 * statement about lmrc_max_fw_cmds questionable.
14181e091e43SHans Rosenfeld 	 */
14191e091e43SHans Rosenfeld 	lmrc->l_reply_q_depth = (lmrc->l_max_fw_cmds + 1 + 15) / 16 * 16 * 2;
14201e091e43SHans Rosenfeld 
14211e091e43SHans Rosenfeld 	/* Allocation size of one reply queue, based on depth. */
14221e091e43SHans Rosenfeld 	lmrc->l_reply_alloc_sz =
14231e091e43SHans Rosenfeld 	    sizeof (Mpi2ReplyDescriptorsUnion_t) * lmrc->l_reply_q_depth;
14241e091e43SHans Rosenfeld 
14251e091e43SHans Rosenfeld 	/* Allocation size of the DMA memory used for all MPI I/O frames. */
14261e091e43SHans Rosenfeld 	lmrc->l_io_frames_alloc_sz = LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
14271e091e43SHans Rosenfeld 	    (lmrc->l_max_fw_cmds + 2);
14281e091e43SHans Rosenfeld 
14291e091e43SHans Rosenfeld 	/*
14301e091e43SHans Rosenfeld 	 * If LMRC_EXT_CHAIN_SIZE_SUPPORT is set in scratch pad 1, firmware
14311e091e43SHans Rosenfeld 	 * supports an extended IO chain frame which is 4 times the size of a
14321e091e43SHans Rosenfeld 	 * legacy firmware frame.
14331e091e43SHans Rosenfeld 	 * Legacy Firmware frame size is (8 * 128) = 1K
14341e091e43SHans Rosenfeld 	 * 1M IO Firmware frame size is (8 * 128 * 4) = 4K
14351e091e43SHans Rosenfeld 	 */
1436e9ff209aSHans Rosenfeld 	reg = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD1_OFFSET);
14371e091e43SHans Rosenfeld 	lmrc->l_max_chain_frame_sz = LMRC_MAX_CHAIN_SIZE(reg) *
14381e091e43SHans Rosenfeld 	    (LMRC_EXT_CHAIN_SIZE_SUPPORT(reg) ? LMRC_1MB_IO : LMRC_256K_IO);
14391e091e43SHans Rosenfeld 
14401e091e43SHans Rosenfeld 	/*
14411e091e43SHans Rosenfeld 	 * Check whether the controller supports DMA to the full 64bit address
14421e091e43SHans Rosenfeld 	 * space.
14431e091e43SHans Rosenfeld 	 */
14441e091e43SHans Rosenfeld 	lmrc->l_64bit_dma_support = LMRC_64BIT_DMA_SUPPORT(reg);
14451e091e43SHans Rosenfeld 
14461e091e43SHans Rosenfeld 	/*
14471e091e43SHans Rosenfeld 	 * We use a I/O frame size of 256 bytes, that is what
14481e091e43SHans Rosenfeld 	 * LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE is set to.
14491e091e43SHans Rosenfeld 	 *
14501e091e43SHans Rosenfeld 	 * The offset of the SGL in the I/O frame is 128, so
14511e091e43SHans Rosenfeld 	 * there are 128 bytes left for 8 SGEs of 16 bytes each.
14521e091e43SHans Rosenfeld 	 */
14531e091e43SHans Rosenfeld 	lmrc->l_max_sge_in_main_msg =
14541e091e43SHans Rosenfeld 	    (LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
14551e091e43SHans Rosenfeld 	    offsetof(Mpi25SCSIIORequest_t, SGL)) / sizeof (Mpi25SGEIOUnion_t);
14561e091e43SHans Rosenfeld 
14571e091e43SHans Rosenfeld 	/*
14581e091e43SHans Rosenfeld 	 * Similarly, number of SGE in a SGE chain frame.
14591e091e43SHans Rosenfeld 	 */
14601e091e43SHans Rosenfeld 	lmrc->l_max_sge_in_chain =
14611e091e43SHans Rosenfeld 	    lmrc->l_max_chain_frame_sz / sizeof (Mpi25SGEIOUnion_t);
14621e091e43SHans Rosenfeld 
14631e091e43SHans Rosenfeld 	/*
14641e091e43SHans Rosenfeld 	 * The total number of SGE we support in a transfer is sum of
14651e091e43SHans Rosenfeld 	 * the above two, minus one for the link (last SGE in main msg).
14661e091e43SHans Rosenfeld 	 *
14671e091e43SHans Rosenfeld 	 * XXX: So why -2?
14681e091e43SHans Rosenfeld 	 */
14691e091e43SHans Rosenfeld 	lmrc->l_max_num_sge =
14701e091e43SHans Rosenfeld 	    lmrc->l_max_sge_in_main_msg + lmrc->l_max_sge_in_chain - 2;
14711e091e43SHans Rosenfeld 
14721e091e43SHans Rosenfeld 	/*
14731e091e43SHans Rosenfeld 	 * The offset of the last SGE in the I/O request, used for linking
14741e091e43SHans Rosenfeld 	 * the SGE chain frame if necessary.
14751e091e43SHans Rosenfeld 	 */
14761e091e43SHans Rosenfeld 	lmrc->l_chain_offset_io_request =
14771e091e43SHans Rosenfeld 	    (LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
14781e091e43SHans Rosenfeld 	    sizeof (Mpi25SGEIOUnion_t)) / sizeof (Mpi25SGEIOUnion_t);
14791e091e43SHans Rosenfeld 
14801e091e43SHans Rosenfeld 	/*
14811e091e43SHans Rosenfeld 	 * For MFI passthru, the link to the SGE chain frame is always
14821e091e43SHans Rosenfeld 	 * the first SGE in the I/O frame, the other SGEs in the I/O frame
14831e091e43SHans Rosenfeld 	 * will not be used.
14841e091e43SHans Rosenfeld 	 */
14851e091e43SHans Rosenfeld 	lmrc->l_chain_offset_mfi_pthru =
14861e091e43SHans Rosenfeld 	    offsetof(Mpi25SCSIIORequest_t, SGL) / sizeof (Mpi25SGEIOUnion_t);
14871e091e43SHans Rosenfeld 
14881e091e43SHans Rosenfeld 
1489e9ff209aSHans Rosenfeld 	reg = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD3_OFFSET);
14901e091e43SHans Rosenfeld 	if (LMRC_NVME_PAGE_SHIFT(reg) > LMRC_DEFAULT_NVME_PAGE_SHIFT) {
14911e091e43SHans Rosenfeld 		lmrc->l_nvme_page_sz = 1 << LMRC_NVME_PAGE_SHIFT(reg);
14921e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_NOTE, "!NVME page size: %ld",
14931e091e43SHans Rosenfeld 		    lmrc->l_nvme_page_sz);
14941e091e43SHans Rosenfeld 	}
14951e091e43SHans Rosenfeld 
1496e9ff209aSHans Rosenfeld 	reg = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD1_OFFSET);
14971e091e43SHans Rosenfeld 	lmrc->l_fw_sync_cache_support = LMRC_SYNC_CACHE_SUPPORT(reg);
14981e091e43SHans Rosenfeld 
14991e091e43SHans Rosenfeld 	if (lmrc->l_class == LMRC_ACLASS_AERO) {
1500e9ff209aSHans Rosenfeld 		reg = lmrc_read_reg(lmrc, MPI26_SCRATCHPAD1_OFFSET);
15011e091e43SHans Rosenfeld 		lmrc->l_atomic_desc_support =
15021e091e43SHans Rosenfeld 		    LMRC_ATOMIC_DESCRIPTOR_SUPPORT(reg);
15031e091e43SHans Rosenfeld 	}
15041e091e43SHans Rosenfeld 
15051e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
15061e091e43SHans Rosenfeld }
15071e091e43SHans Rosenfeld 
15081e091e43SHans Rosenfeld /*
15091e091e43SHans Rosenfeld  * lmrc_ioc_init
15101e091e43SHans Rosenfeld  *
15111e091e43SHans Rosenfeld  * Manually build a MFI IOC INIT command to setup basic operating parameters
15121e091e43SHans Rosenfeld  * such as the DMA parameters for the I/O request frames and the reply post
15131e091e43SHans Rosenfeld  * queues. Send the IOC INIT command using a special request descriptor which
15141e091e43SHans Rosenfeld  * directly includes the physical address of the MFI command frame.
15151e091e43SHans Rosenfeld  *
15161e091e43SHans Rosenfeld  * After this command completes, the controller is ready to accept MPT commands
15171e091e43SHans Rosenfeld  * using the normal method of placing it in the I/O request DMA memory and
15181e091e43SHans Rosenfeld  * writing a MPT request descripter to the appropriate registers.
15191e091e43SHans Rosenfeld  */
15201e091e43SHans Rosenfeld int
lmrc_ioc_init(lmrc_t * lmrc)15211e091e43SHans Rosenfeld lmrc_ioc_init(lmrc_t *lmrc)
15221e091e43SHans Rosenfeld {
15231e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi = lmrc_get_mfi(lmrc);
15241e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
15251e091e43SHans Rosenfeld 	lmrc_mfi_init_payload_t *init = &mfi->mfi_frame->mf_init;
15261e091e43SHans Rosenfeld 	lmrc_req_desc_t req_desc;
15271e091e43SHans Rosenfeld 	Mpi2IOCInitRequest_t *IOCInitMsg;
15281e091e43SHans Rosenfeld 	lmrc_dma_t dma;
15291e091e43SHans Rosenfeld 	int ret = DDI_SUCCESS;
15301e091e43SHans Rosenfeld 
15311e091e43SHans Rosenfeld 	ret = lmrc_dma_alloc(lmrc, lmrc->l_dma_attr, &dma,
15321e091e43SHans Rosenfeld 	    sizeof (Mpi2IOCInitRequest_t), 256, DDI_DMA_CONSISTENT);
15331e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS) {
15341e091e43SHans Rosenfeld 		lmrc_put_mfi(mfi);
15351e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN,
15361e091e43SHans Rosenfeld 		    "!%s: failed to allocate IOC command", __func__);
15371e091e43SHans Rosenfeld 		return (DDI_FAILURE);
15381e091e43SHans Rosenfeld 	}
15391e091e43SHans Rosenfeld 
15401e091e43SHans Rosenfeld 	IOCInitMsg = dma.ld_buf;
15411e091e43SHans Rosenfeld 	IOCInitMsg->Function = MPI2_FUNCTION_IOC_INIT;
15421e091e43SHans Rosenfeld 	IOCInitMsg->WhoInit = MPI2_WHOINIT_HOST_DRIVER;
15431e091e43SHans Rosenfeld 	IOCInitMsg->MsgVersion = MPI2_VERSION;
15441e091e43SHans Rosenfeld 	IOCInitMsg->HeaderVersion = MPI2_HEADER_VERSION;
15451e091e43SHans Rosenfeld 	IOCInitMsg->SystemRequestFrameSize =
15461e091e43SHans Rosenfeld 	    LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4;
15471e091e43SHans Rosenfeld 	IOCInitMsg->ReplyDescriptorPostQueueDepth = lmrc->l_reply_q_depth;
15481e091e43SHans Rosenfeld 	lmrc_dma_set_addr64(&lmrc->l_reply_dma,
15491e091e43SHans Rosenfeld 	    (uint64_t *)&IOCInitMsg->ReplyDescriptorPostQueueAddress);
15501e091e43SHans Rosenfeld 	lmrc_dma_set_addr64(&lmrc->l_ioreq_dma,
15511e091e43SHans Rosenfeld 	    (uint64_t *)&IOCInitMsg->SystemRequestFrameBaseAddress);
15521e091e43SHans Rosenfeld 	IOCInitMsg->HostMSIxVectors = lmrc->l_max_reply_queues;
15531e091e43SHans Rosenfeld 	/* XXX: Why NVMe? */
15541e091e43SHans Rosenfeld 	IOCInitMsg->HostPageSize = LMRC_DEFAULT_NVME_PAGE_SHIFT;
15551e091e43SHans Rosenfeld 
15561e091e43SHans Rosenfeld 	hdr->mh_cmd = MFI_CMD_INIT;
15571e091e43SHans Rosenfeld 	hdr->mh_cmd_status = MFI_STAT_INVALID_STATUS;
15581e091e43SHans Rosenfeld 	hdr->mh_flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
15591e091e43SHans Rosenfeld 
15601e091e43SHans Rosenfeld 	hdr->mh_drv_opts.mc_support_additional_msix = 1;
15611e091e43SHans Rosenfeld 	hdr->mh_drv_opts.mc_support_max_255lds = 1;
15621e091e43SHans Rosenfeld 	hdr->mh_drv_opts.mc_support_ndrive_r1_lb = 1;
15631e091e43SHans Rosenfeld 	hdr->mh_drv_opts.mc_support_security_protocol_cmds_fw = 1;
15641e091e43SHans Rosenfeld 	hdr->mh_drv_opts.mc_support_ext_io_size = 1;
15651e091e43SHans Rosenfeld 
15661e091e43SHans Rosenfeld 	hdr->mh_data_xfer_len = lmrc_dma_get_size(&dma);
15671e091e43SHans Rosenfeld 
15681e091e43SHans Rosenfeld 	lmrc_dma_set_addr64(&dma, &init->mi_queue_info_new_phys_addr);
15691e091e43SHans Rosenfeld 
15701e091e43SHans Rosenfeld 	lmrc_dma_set_addr64(&mfi->mfi_frame_dma, &req_desc.rd_reg);
15711e091e43SHans Rosenfeld 	VERIFY0(req_desc.rd_mfa_io.RequestFlags);
15721e091e43SHans Rosenfeld 	req_desc.rd_mfa_io.RequestFlags = LMRC_REQ_DESCRIPT_FLAGS_MFA;
15731e091e43SHans Rosenfeld 
15741e091e43SHans Rosenfeld 	lmrc_disable_intr(lmrc);
1575e9ff209aSHans Rosenfeld 	if (!lmrc_wait_for_reg(lmrc, MPI2_DOORBELL_OFFSET, 1, 0, 10))
15761e091e43SHans Rosenfeld 		return (DDI_FAILURE);
15771e091e43SHans Rosenfeld 
15781e091e43SHans Rosenfeld 	(void) ddi_dma_sync(dma.ld_hdl, 0, dma.ld_len, DDI_DMA_SYNC_FORDEV);
15791e091e43SHans Rosenfeld 	(void) ddi_dma_sync(mfi->mfi_frame_dma.ld_hdl, 0,
15801e091e43SHans Rosenfeld 	    mfi->mfi_frame_dma.ld_len, DDI_DMA_SYNC_FORDEV);
15811e091e43SHans Rosenfeld 
15821e091e43SHans Rosenfeld 	lmrc_send_request(lmrc, req_desc);
15831e091e43SHans Rosenfeld 
15841e091e43SHans Rosenfeld 	mutex_enter(&mfi->mfi_lock);
15851e091e43SHans Rosenfeld 	ret = lmrc_poll_mfi(lmrc, mfi, LMRC_INTERNAL_CMD_WAIT_TIME);
15861e091e43SHans Rosenfeld 	mutex_exit(&mfi->mfi_lock);
15871e091e43SHans Rosenfeld 
15881e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS) {
15891e091e43SHans Rosenfeld 		if (hdr->mh_cmd_status != MFI_STAT_INVALID_STATUS)
15901e091e43SHans Rosenfeld 			dev_err(lmrc->l_dip, CE_WARN,
15911e091e43SHans Rosenfeld 			    "!IOC Init failed, status = 0x%x",
15921e091e43SHans Rosenfeld 			    hdr->mh_cmd_status);
15931e091e43SHans Rosenfeld 	}
15941e091e43SHans Rosenfeld 
15951e091e43SHans Rosenfeld 	lmrc_dma_free(&dma);
15961e091e43SHans Rosenfeld 	lmrc_put_mfi(mfi);
15971e091e43SHans Rosenfeld 
15981e091e43SHans Rosenfeld 	return (ret);
15991e091e43SHans Rosenfeld }
16001e091e43SHans Rosenfeld 
16011e091e43SHans Rosenfeld /*
16021e091e43SHans Rosenfeld  * lmrc_get_ctrl_info
16031e091e43SHans Rosenfeld  *
16041e091e43SHans Rosenfeld  * Build a MFI DCMD to get controller information from FW. Update the copy in
16051e091e43SHans Rosenfeld  * the soft state.
16061e091e43SHans Rosenfeld  */
16071e091e43SHans Rosenfeld static int
lmrc_get_ctrl_info(lmrc_t * lmrc)16081e091e43SHans Rosenfeld lmrc_get_ctrl_info(lmrc_t *lmrc)
16091e091e43SHans Rosenfeld {
16101e091e43SHans Rosenfeld 	lmrc_ctrl_info_t *ci = lmrc->l_ctrl_info;
16111e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi;
16121e091e43SHans Rosenfeld 	int ret;
16131e091e43SHans Rosenfeld 
16141e091e43SHans Rosenfeld 	mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_READ, LMRC_DCMD_CTRL_GET_INFO,
16151e091e43SHans Rosenfeld 	    sizeof (lmrc_ctrl_info_t), 1);
16161e091e43SHans Rosenfeld 
16171e091e43SHans Rosenfeld 	if (mfi == NULL)
16181e091e43SHans Rosenfeld 		return (DDI_FAILURE);
16191e091e43SHans Rosenfeld 
16201e091e43SHans Rosenfeld 	ret = lmrc_issue_blocked_mfi(lmrc, mfi);
16211e091e43SHans Rosenfeld 
16221e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
16231e091e43SHans Rosenfeld 		goto out;
16241e091e43SHans Rosenfeld 
16251e091e43SHans Rosenfeld 	(void) ddi_dma_sync(mfi->mfi_data_dma.ld_hdl, 0,
16261e091e43SHans Rosenfeld 	    mfi->mfi_data_dma.ld_len, DDI_DMA_SYNC_FORKERNEL);
16271e091e43SHans Rosenfeld 	bcopy(mfi->mfi_data_dma.ld_buf, ci, sizeof (lmrc_ctrl_info_t));
16281e091e43SHans Rosenfeld 
16291e091e43SHans Rosenfeld out:
16301e091e43SHans Rosenfeld 	lmrc_put_dcmd(lmrc, mfi);
16311e091e43SHans Rosenfeld 	return (ret);
16321e091e43SHans Rosenfeld }
16331e091e43SHans Rosenfeld 
16341e091e43SHans Rosenfeld /*
16351e091e43SHans Rosenfeld  * lmrc_fw_init
16361e091e43SHans Rosenfeld  *
16371e091e43SHans Rosenfeld  * Complete firmware initialization. At this point, we can already send MFI
16381e091e43SHans Rosenfeld  * commands. so we can start by getting the controller information from the
16391e091e43SHans Rosenfeld  * firmware and set up things in our soft state. Next we issue the commands
16401e091e43SHans Rosenfeld  * to get the PD map and RAID map, which will complete asynchronously when
16411e091e43SHans Rosenfeld  * new information is available and then re-send themselves.
16421e091e43SHans Rosenfeld  */
16431e091e43SHans Rosenfeld int
lmrc_fw_init(lmrc_t * lmrc)16441e091e43SHans Rosenfeld lmrc_fw_init(lmrc_t *lmrc)
16451e091e43SHans Rosenfeld {
16461e091e43SHans Rosenfeld 	int drv_max_lds = LMRC_MAX_LOGICAL_DRIVES;
16471e091e43SHans Rosenfeld 	lmrc_ctrl_info_t *ci = lmrc->l_ctrl_info;
16481e091e43SHans Rosenfeld 	int ret;
16491e091e43SHans Rosenfeld 
16501e091e43SHans Rosenfeld 	ret = lmrc_get_ctrl_info(lmrc);
16511e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS) {
16521e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN, "!Unable to get FW ctrl info.");
16531e091e43SHans Rosenfeld 		return (DDI_FAILURE);
16541e091e43SHans Rosenfeld 	}
16551e091e43SHans Rosenfeld 
16561e091e43SHans Rosenfeld 	lmrc->l_disable_online_ctrl_reset =
16571e091e43SHans Rosenfeld 	    ci->ci_prop.cp_disable_online_ctrl_reset == 1;
16581e091e43SHans Rosenfeld 
16591e091e43SHans Rosenfeld 	lmrc->l_max_256_vd_support =
16601e091e43SHans Rosenfeld 	    ci->ci_adapter_opts3.ao3_support_max_ext_lds == 1;
16611e091e43SHans Rosenfeld 
16621e091e43SHans Rosenfeld 	if (ci->ci_max_lds > 64) {
16631e091e43SHans Rosenfeld 		lmrc->l_max_256_vd_support = B_TRUE;
16641e091e43SHans Rosenfeld 		drv_max_lds = LMRC_MAX_LOGICAL_DRIVES_EXT;
16651e091e43SHans Rosenfeld 	}
16661e091e43SHans Rosenfeld 
16671e091e43SHans Rosenfeld 	lmrc->l_fw_supported_vd_count = min(ci->ci_max_lds, drv_max_lds);
16681e091e43SHans Rosenfeld 
16691e091e43SHans Rosenfeld 	lmrc->l_fw_supported_pd_count = min(ci->ci_max_pds, LMRC_MAX_PHYS_DEV);
16701e091e43SHans Rosenfeld 
16711e091e43SHans Rosenfeld 	lmrc->l_max_map_sz = lmrc->l_current_map_sz =
16721e091e43SHans Rosenfeld 	    lmrc->l_max_raid_map_sz * LMRC_MIN_MAP_SIZE;
16731e091e43SHans Rosenfeld 
16741e091e43SHans Rosenfeld 	lmrc->l_use_seqnum_jbod_fp =
16751e091e43SHans Rosenfeld 	    ci->ci_adapter_opts3.ao3_use_seq_num_jbod_FP != 0;
16761e091e43SHans Rosenfeld 
16771e091e43SHans Rosenfeld 	lmrc->l_pdmap_tgtid_support =
16781e091e43SHans Rosenfeld 	    ci->ci_adapter_opts4.ao4_support_pd_map_target_id != 0;
16791e091e43SHans Rosenfeld 
16801e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
16811e091e43SHans Rosenfeld }
16821e091e43SHans Rosenfeld 
16831e091e43SHans Rosenfeld 
16841e091e43SHans Rosenfeld /*
16851e091e43SHans Rosenfeld  * lmrc_ctrl_shutdown
16861e091e43SHans Rosenfeld  *
16871e091e43SHans Rosenfeld  * Called by lmrc_quiesce() to send a shutdown command to the controller.
16881e091e43SHans Rosenfeld  * Cannot use locks, therefore cannot use lmrc_get_dcmd() or lmrc_get_mfi().
16891e091e43SHans Rosenfeld  */
16901e091e43SHans Rosenfeld int
lmrc_ctrl_shutdown(lmrc_t * lmrc)16911e091e43SHans Rosenfeld lmrc_ctrl_shutdown(lmrc_t *lmrc)
16921e091e43SHans Rosenfeld {
16931e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi = list_remove_head(&lmrc->l_mfi_cmd_list);
16941e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr;
16951e091e43SHans Rosenfeld 	lmrc_mfi_dcmd_payload_t *dcmd;
16961e091e43SHans Rosenfeld 
16971e091e43SHans Rosenfeld 	if (mfi == NULL)
16981e091e43SHans Rosenfeld 		return (DDI_FAILURE);
16991e091e43SHans Rosenfeld 
17001e091e43SHans Rosenfeld 	hdr = &mfi->mfi_frame->mf_hdr;
17011e091e43SHans Rosenfeld 	dcmd = &mfi->mfi_frame->mf_dcmd;
17021e091e43SHans Rosenfeld 
17031e091e43SHans Rosenfeld 	hdr->mh_cmd = MFI_CMD_DCMD;
17041e091e43SHans Rosenfeld 	hdr->mh_flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
17051e091e43SHans Rosenfeld 	dcmd->md_opcode = LMRC_DCMD_CTRL_SHUTDOWN;
17061e091e43SHans Rosenfeld 
17071e091e43SHans Rosenfeld 	lmrc_disable_intr(lmrc);
17081e091e43SHans Rosenfeld 	lmrc_issue_mfi(lmrc, mfi, NULL);
17091e091e43SHans Rosenfeld 
17101e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
17111e091e43SHans Rosenfeld }
17121e091e43SHans Rosenfeld 
17131e091e43SHans Rosenfeld /*
17141e091e43SHans Rosenfeld  * driver target state management
17151e091e43SHans Rosenfeld  *
17161e091e43SHans Rosenfeld  * The soft state of the controller instance keeps a pre-allocated array of
17171e091e43SHans Rosenfeld  * target structures for all possible targets, even though only a small number
17181e091e43SHans Rosenfeld  * of them are likely to be used. Each target structure contains back link to
17191e091e43SHans Rosenfeld  * the soft state and a mutex, which are never cleared or changed when a target
17201e091e43SHans Rosenfeld  * is added or removed.
17211e091e43SHans Rosenfeld  */
17221e091e43SHans Rosenfeld 
17231e091e43SHans Rosenfeld /*
17241e091e43SHans Rosenfeld  * lmrc_tgt_init
17251e091e43SHans Rosenfeld  *
17261e091e43SHans Rosenfeld  * Initialize the tgt structure for a newly discovered tgt. The same tgt
17271e091e43SHans Rosenfeld  * structure is used for PDs and LDs, the distinction can be made by the
17281e091e43SHans Rosenfeld  * presence or absence of tgt_pd_info. LDs are always of type disk, the type
17291e091e43SHans Rosenfeld  * of PDs is taken from their pd_info. If a device has no SAS WWN, we'll fake
17301e091e43SHans Rosenfeld  * the interconnect type to be PARALLEL to make sure device address isn't
17311e091e43SHans Rosenfeld  * misunderstood as a WWN by devfsadm.
17321e091e43SHans Rosenfeld  */
17331e091e43SHans Rosenfeld void
lmrc_tgt_init(lmrc_tgt_t * tgt,uint16_t dev_id,char * addr,lmrc_pd_info_t * pd_info)17341e091e43SHans Rosenfeld lmrc_tgt_init(lmrc_tgt_t *tgt, uint16_t dev_id, char *addr,
17351e091e43SHans Rosenfeld     lmrc_pd_info_t *pd_info)
17361e091e43SHans Rosenfeld {
17371e091e43SHans Rosenfeld 	rw_enter(&tgt->tgt_lock, RW_WRITER);
17381e091e43SHans Rosenfeld 
17391e091e43SHans Rosenfeld 	bzero(&tgt->tgt_dev_id,
17401e091e43SHans Rosenfeld 	    sizeof (lmrc_tgt_t) - offsetof(lmrc_tgt_t, tgt_dev_id));
17411e091e43SHans Rosenfeld 
17421e091e43SHans Rosenfeld 	tgt->tgt_dev_id = dev_id;
17431e091e43SHans Rosenfeld 	tgt->tgt_pd_info = pd_info;
17441e091e43SHans Rosenfeld 	tgt->tgt_interconnect_type = INTERCONNECT_SAS;
17451e091e43SHans Rosenfeld 
17461e091e43SHans Rosenfeld 	if (pd_info == NULL) {
17471e091e43SHans Rosenfeld 		tgt->tgt_type = DTYPE_DIRECT;
17481e091e43SHans Rosenfeld 	} else {
17491e091e43SHans Rosenfeld 		tgt->tgt_type = pd_info->pd_scsi_dev_type;
17501e091e43SHans Rosenfeld 	}
17511e091e43SHans Rosenfeld 
17521e091e43SHans Rosenfeld 	(void) strlcpy(tgt->tgt_wwnstr, addr, sizeof (tgt->tgt_wwnstr));
17531e091e43SHans Rosenfeld 	if (scsi_wwnstr_to_wwn(tgt->tgt_wwnstr, &tgt->tgt_wwn) != DDI_SUCCESS) {
17541e091e43SHans Rosenfeld 		tgt->tgt_interconnect_type = INTERCONNECT_PARALLEL;
17551e091e43SHans Rosenfeld 		tgt->tgt_wwn = dev_id;
17561e091e43SHans Rosenfeld 	}
17571e091e43SHans Rosenfeld 
17581e091e43SHans Rosenfeld 	rw_exit(&tgt->tgt_lock);
17591e091e43SHans Rosenfeld }
17601e091e43SHans Rosenfeld 
17611e091e43SHans Rosenfeld /*
17621e091e43SHans Rosenfeld  * lmrc_tgt_clear
17631e091e43SHans Rosenfeld  *
17641e091e43SHans Rosenfeld  * Reset the tgt structure of a target which is no longer present.
17651e091e43SHans Rosenfeld  */
17661e091e43SHans Rosenfeld void
lmrc_tgt_clear(lmrc_tgt_t * tgt)17671e091e43SHans Rosenfeld lmrc_tgt_clear(lmrc_tgt_t *tgt)
17681e091e43SHans Rosenfeld {
17691e091e43SHans Rosenfeld 	rw_enter(&tgt->tgt_lock, RW_WRITER);
17701e091e43SHans Rosenfeld 
17711e091e43SHans Rosenfeld 	if (tgt->tgt_pd_info != NULL)
17721e091e43SHans Rosenfeld 		kmem_free(tgt->tgt_pd_info, sizeof (lmrc_pd_info_t));
17731e091e43SHans Rosenfeld 
17741e091e43SHans Rosenfeld 	bzero(&tgt->tgt_dev_id,
17751e091e43SHans Rosenfeld 	    sizeof (lmrc_tgt_t) - offsetof(lmrc_tgt_t, tgt_dev_id));
17761e091e43SHans Rosenfeld 	tgt->tgt_dev_id = LMRC_DEVHDL_INVALID;
17771e091e43SHans Rosenfeld 	rw_exit(&tgt->tgt_lock);
17781e091e43SHans Rosenfeld }
17791e091e43SHans Rosenfeld 
17801e091e43SHans Rosenfeld /*
17811e091e43SHans Rosenfeld  * lmrc_tgt_find
17821e091e43SHans Rosenfeld  *
17831e091e43SHans Rosenfeld  * Walk the target list and find a tgt matching the given scsi_device.
17841e091e43SHans Rosenfeld  * Return the tgt read-locked. The targets_lock mutex must be held the
17851e091e43SHans Rosenfeld  * whole time.
17861e091e43SHans Rosenfeld  */
17871e091e43SHans Rosenfeld lmrc_tgt_t *
lmrc_tgt_find(lmrc_t * lmrc,struct scsi_device * sd)17881e091e43SHans Rosenfeld lmrc_tgt_find(lmrc_t *lmrc, struct scsi_device *sd)
17891e091e43SHans Rosenfeld {
17901e091e43SHans Rosenfeld 	const char *ua = scsi_device_unit_address(sd);
17911e091e43SHans Rosenfeld 	char *comma, wwnstr[SCSI_WWN_BUFLEN];
17921e091e43SHans Rosenfeld 	uint64_t wwn;
17931e091e43SHans Rosenfeld 	unsigned long tgtid;
17941e091e43SHans Rosenfeld 	lmrc_tgt_t *tgt;
17951e091e43SHans Rosenfeld 	size_t i;
17961e091e43SHans Rosenfeld 
17971e091e43SHans Rosenfeld 	VERIFY(ua != NULL);
17981e091e43SHans Rosenfeld 
17991e091e43SHans Rosenfeld 	(void) strlcpy(wwnstr, ua, sizeof (wwnstr));
18001e091e43SHans Rosenfeld 
18011e091e43SHans Rosenfeld 	/*
18021e091e43SHans Rosenfeld 	 * If the unit address is a valid target ID and within range for
18031e091e43SHans Rosenfeld 	 * VD IDs, use that.
18041e091e43SHans Rosenfeld 	 */
18051e091e43SHans Rosenfeld 	if (ddi_strtoul(wwnstr, &comma, 10, &tgtid) == 0 &&
18061e091e43SHans Rosenfeld 	    *comma == ',' &&
18071e091e43SHans Rosenfeld 	    tgtid <= lmrc->l_fw_supported_vd_count) {
18081e091e43SHans Rosenfeld 		tgt = &lmrc->l_targets[tgtid];
18091e091e43SHans Rosenfeld 
18101e091e43SHans Rosenfeld 		rw_enter(&tgt->tgt_lock, RW_READER);
18111e091e43SHans Rosenfeld 		if (tgt->tgt_dev_id == tgtid &&
18121e091e43SHans Rosenfeld 		    tgt->tgt_wwn == tgtid) {
18131e091e43SHans Rosenfeld 			return (tgt);
18141e091e43SHans Rosenfeld 		}
18151e091e43SHans Rosenfeld 		rw_exit(&tgt->tgt_lock);
18161e091e43SHans Rosenfeld 	}
18171e091e43SHans Rosenfeld 
18181e091e43SHans Rosenfeld 	/* Chop off ",lun" as scsi_wwnstr_to_wwn() can't handle it. */
18191e091e43SHans Rosenfeld 	comma = strchr(wwnstr, ',');
18201e091e43SHans Rosenfeld 	if (comma != NULL)
18211e091e43SHans Rosenfeld 		*comma = '\0';
18221e091e43SHans Rosenfeld 
18231e091e43SHans Rosenfeld 	/* Else, if unit address is a valid WWN, look for that. */
18241e091e43SHans Rosenfeld 	if (scsi_wwnstr_to_wwn(wwnstr, &wwn) == DDI_SUCCESS) {
18251e091e43SHans Rosenfeld 		for (i = 0; i < ARRAY_SIZE(lmrc->l_targets); i++) {
18261e091e43SHans Rosenfeld 			tgt = &lmrc->l_targets[i];
18271e091e43SHans Rosenfeld 
18281e091e43SHans Rosenfeld 			rw_enter(&tgt->tgt_lock, RW_READER);
18291e091e43SHans Rosenfeld 			if (tgt->tgt_wwn == wwn) {
18301e091e43SHans Rosenfeld 				return (tgt);
18311e091e43SHans Rosenfeld 			}
18321e091e43SHans Rosenfeld 			rw_exit(&tgt->tgt_lock);
18331e091e43SHans Rosenfeld 		}
18341e091e43SHans Rosenfeld 	} else {
18351e091e43SHans Rosenfeld 		/* Do it the hard way and compare wwnstr. */
18361e091e43SHans Rosenfeld 		for (i = 0; i < ARRAY_SIZE(lmrc->l_targets); i++) {
18371e091e43SHans Rosenfeld 			tgt = &lmrc->l_targets[i];
18381e091e43SHans Rosenfeld 
18391e091e43SHans Rosenfeld 			rw_enter(&tgt->tgt_lock, RW_READER);
18401e091e43SHans Rosenfeld 			if (strcmp(tgt->tgt_wwnstr, wwnstr) == 0) {
18411e091e43SHans Rosenfeld 				return (tgt);
18421e091e43SHans Rosenfeld 			}
18431e091e43SHans Rosenfeld 			rw_exit(&tgt->tgt_lock);
18441e091e43SHans Rosenfeld 		}
18451e091e43SHans Rosenfeld 	}
18461e091e43SHans Rosenfeld 
18471e091e43SHans Rosenfeld 	return (NULL);
18481e091e43SHans Rosenfeld }
18491e091e43SHans Rosenfeld 
18501e091e43SHans Rosenfeld /*
18511e091e43SHans Rosenfeld  * MPT/MFI command management
18521e091e43SHans Rosenfeld  *
18531e091e43SHans Rosenfeld  * For each kind of command, MFI and MPT, the driver keeps an array of pre-
18541e091e43SHans Rosenfeld  * allocated and pre-initialized commands. Additionally, it keeps two lists of
18551e091e43SHans Rosenfeld  * currently unused commands. A set of functions is provided for each list to
18561e091e43SHans Rosenfeld  * get and put commands from/to the list. Commands are initialized during get(),
18571e091e43SHans Rosenfeld  * because having completed commands on the list can help in certain cases
18581e091e43SHans Rosenfeld  * during debugging.
18591e091e43SHans Rosenfeld  *
18601e091e43SHans Rosenfeld  * MPT commands in use for I/O are kept on a active command list of the target
18611e091e43SHans Rosenfeld  * they are addressing. All other types of commands are not kept on any list
18621e091e43SHans Rosenfeld  * while they are being processed by the hardware. When walking the command
18631e091e43SHans Rosenfeld  * arrays, busy commands not associated with a target can be distinguished by
18641e091e43SHans Rosenfeld  * not being linked on any list.
18651e091e43SHans Rosenfeld  */
18661e091e43SHans Rosenfeld 
18671e091e43SHans Rosenfeld /*
18681e091e43SHans Rosenfeld  * lmrc_get_mpt
18691e091e43SHans Rosenfeld  *
18701e091e43SHans Rosenfeld  * Get a MPT command from the list and initialize it. Return the command locked.
1871d8b83e34SHans Rosenfeld  * Return NULL if the MPT command list is empty.
18721e091e43SHans Rosenfeld  */
18731e091e43SHans Rosenfeld lmrc_mpt_cmd_t *
lmrc_get_mpt(lmrc_t * lmrc)18741e091e43SHans Rosenfeld lmrc_get_mpt(lmrc_t *lmrc)
18751e091e43SHans Rosenfeld {
18761e091e43SHans Rosenfeld 	lmrc_mpt_cmd_t *mpt;
18771e091e43SHans Rosenfeld 	Mpi25SCSIIORequest_t *io_req;
18781e091e43SHans Rosenfeld 
18791e091e43SHans Rosenfeld 	mutex_enter(&lmrc->l_mpt_cmd_lock);
18801e091e43SHans Rosenfeld 	mpt = list_remove_head(&lmrc->l_mpt_cmd_list);
18811e091e43SHans Rosenfeld 	mutex_exit(&lmrc->l_mpt_cmd_lock);
1882d8b83e34SHans Rosenfeld 	if (mpt == NULL)
1883d8b83e34SHans Rosenfeld 		return (NULL);
18841e091e43SHans Rosenfeld 
18851e091e43SHans Rosenfeld 	mutex_enter(&mpt->mpt_lock);
18861e091e43SHans Rosenfeld 	bzero(mpt->mpt_io_frame, LMRC_MPI2_RAID_DEFAULT_IO_FRAME_SIZE);
18871e091e43SHans Rosenfeld 	bzero(mpt->mpt_chain_dma.ld_buf, mpt->mpt_chain_dma.ld_len);
18881e091e43SHans Rosenfeld 	bzero(mpt->mpt_sense_dma.ld_buf, mpt->mpt_sense_dma.ld_len);
18891e091e43SHans Rosenfeld 
18901e091e43SHans Rosenfeld 	mpt->mpt_mfi = NULL;
18911e091e43SHans Rosenfeld 	mpt->mpt_pkt = NULL;
18921e091e43SHans Rosenfeld 
18931e091e43SHans Rosenfeld 	/* Set the offset of the SGL entries inside the MPT command. */
18941e091e43SHans Rosenfeld 	io_req = mpt->mpt_io_frame;
18951e091e43SHans Rosenfeld 	io_req->SGLOffset0 = offsetof(Mpi25SCSIIORequest_t, SGL) / 4;
18961e091e43SHans Rosenfeld 
18971e091e43SHans Rosenfeld 	mpt->mpt_complete = B_FALSE;
18981e091e43SHans Rosenfeld 	cv_init(&mpt->mpt_cv, NULL, CV_DRIVER, NULL);
18991e091e43SHans Rosenfeld 
19001e091e43SHans Rosenfeld 	return (mpt);
19011e091e43SHans Rosenfeld }
19021e091e43SHans Rosenfeld 
19031e091e43SHans Rosenfeld /*
19041e091e43SHans Rosenfeld  * lmrc_put_mpt
19051e091e43SHans Rosenfeld  *
1906d8b83e34SHans Rosenfeld  * Put a MPT command back on the list. The command lock must be held when this
1907d8b83e34SHans Rosenfeld  * function is called, being unlocked only after the command has been put on
1908d8b83e34SHans Rosenfeld  * the free list. The command CV is destroyed, thereby asserting that no one is
1909d8b83e34SHans Rosenfeld  * still waiting on it.
19101e091e43SHans Rosenfeld  */
19111e091e43SHans Rosenfeld void
lmrc_put_mpt(lmrc_mpt_cmd_t * mpt)19121e091e43SHans Rosenfeld lmrc_put_mpt(lmrc_mpt_cmd_t *mpt)
19131e091e43SHans Rosenfeld {
19141e091e43SHans Rosenfeld 	lmrc_t *lmrc = mpt->mpt_lmrc;
19151e091e43SHans Rosenfeld 
19161e091e43SHans Rosenfeld 	VERIFY(lmrc != NULL);
19171e091e43SHans Rosenfeld 
19181e091e43SHans Rosenfeld 	ASSERT0(list_link_active(&mpt->mpt_node));
19191e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mpt->mpt_lock));
19201e091e43SHans Rosenfeld 	cv_destroy(&mpt->mpt_cv);
19211e091e43SHans Rosenfeld 
19221e091e43SHans Rosenfeld 	mutex_enter(&lmrc->l_mpt_cmd_lock);
19231e091e43SHans Rosenfeld 	list_insert_tail(&lmrc->l_mpt_cmd_list, mpt);
19241e091e43SHans Rosenfeld 	mutex_exit(&lmrc->l_mpt_cmd_lock);
19251e091e43SHans Rosenfeld 	mutex_exit(&mpt->mpt_lock);
19261e091e43SHans Rosenfeld }
19271e091e43SHans Rosenfeld 
19281e091e43SHans Rosenfeld /*
19291e091e43SHans Rosenfeld  * lmrc_get_mfi
19301e091e43SHans Rosenfeld  *
19311e091e43SHans Rosenfeld  * Get a MFI command from the list and initialize it.
19321e091e43SHans Rosenfeld  */
19331e091e43SHans Rosenfeld lmrc_mfi_cmd_t *
lmrc_get_mfi(lmrc_t * lmrc)19341e091e43SHans Rosenfeld lmrc_get_mfi(lmrc_t *lmrc)
19351e091e43SHans Rosenfeld {
19361e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi;
19371e091e43SHans Rosenfeld 
19381e091e43SHans Rosenfeld 	mutex_enter(&lmrc->l_mfi_cmd_lock);
19391e091e43SHans Rosenfeld 	mfi = list_remove_head(&lmrc->l_mfi_cmd_list);
19401e091e43SHans Rosenfeld 	mutex_exit(&lmrc->l_mfi_cmd_lock);
19411e091e43SHans Rosenfeld 	VERIFY(mfi != NULL);
19421e091e43SHans Rosenfeld 
19431e091e43SHans Rosenfeld 	mutex_enter(&mfi->mfi_lock);
19441e091e43SHans Rosenfeld 	bzero(mfi->mfi_frame, sizeof (lmrc_mfi_frame_t));
19451e091e43SHans Rosenfeld 	mfi->mfi_frame->mf_hdr.mh_context = mfi->mfi_idx;
19461e091e43SHans Rosenfeld 	mfi->mfi_callback = NULL;
19471e091e43SHans Rosenfeld 
19481e091e43SHans Rosenfeld 	cv_init(&mfi->mfi_cv, NULL, CV_DRIVER, NULL);
19491e091e43SHans Rosenfeld 	mutex_exit(&mfi->mfi_lock);
19501e091e43SHans Rosenfeld 
19511e091e43SHans Rosenfeld 	return (mfi);
19521e091e43SHans Rosenfeld }
19531e091e43SHans Rosenfeld 
19541e091e43SHans Rosenfeld /*
19551e091e43SHans Rosenfeld  * lmrc_put_mfi
19561e091e43SHans Rosenfeld  *
19571e091e43SHans Rosenfeld  * Put a MFI command back on the list. Destroy the CV, thereby
19581e091e43SHans Rosenfeld  * asserting that no one is waiting on it.
19591e091e43SHans Rosenfeld  */
19601e091e43SHans Rosenfeld void
lmrc_put_mfi(lmrc_mfi_cmd_t * mfi)19611e091e43SHans Rosenfeld lmrc_put_mfi(lmrc_mfi_cmd_t *mfi)
19621e091e43SHans Rosenfeld {
19631e091e43SHans Rosenfeld 	lmrc_t *lmrc = mfi->mfi_lmrc;
19641e091e43SHans Rosenfeld 
19651e091e43SHans Rosenfeld 	VERIFY(lmrc != NULL);
19661e091e43SHans Rosenfeld 
19671e091e43SHans Rosenfeld 	ASSERT0(list_link_active(&mfi->mfi_node));
19681e091e43SHans Rosenfeld 
19691e091e43SHans Rosenfeld 	mutex_enter(&mfi->mfi_lock);
19701e091e43SHans Rosenfeld 
19711e091e43SHans Rosenfeld 	cv_destroy(&mfi->mfi_cv);
19721e091e43SHans Rosenfeld 
19731e091e43SHans Rosenfeld 	mutex_enter(&lmrc->l_mfi_cmd_lock);
19741e091e43SHans Rosenfeld 	list_insert_tail(&lmrc->l_mfi_cmd_list, mfi);
19751e091e43SHans Rosenfeld 	mutex_exit(&lmrc->l_mfi_cmd_lock);
19761e091e43SHans Rosenfeld 	mutex_exit(&mfi->mfi_lock);
19771e091e43SHans Rosenfeld }
19781e091e43SHans Rosenfeld 
19791e091e43SHans Rosenfeld /*
19801e091e43SHans Rosenfeld  * lmrc_abort_outstanding_mfi
19811e091e43SHans Rosenfeld  *
19821e091e43SHans Rosenfeld  * Walk the MFI cmd array and abort each command which is still outstanding,
19831e091e43SHans Rosenfeld  * which is indicated by not being linked on l_mfi_cmd_list.
19841e091e43SHans Rosenfeld  *
19851e091e43SHans Rosenfeld  * As a special case, if the FW is in fault state, just call each commands
19861e091e43SHans Rosenfeld  * completion callback.
19871e091e43SHans Rosenfeld  */
19881e091e43SHans Rosenfeld int
lmrc_abort_outstanding_mfi(lmrc_t * lmrc,const size_t ncmd)19891e091e43SHans Rosenfeld lmrc_abort_outstanding_mfi(lmrc_t *lmrc, const size_t ncmd)
19901e091e43SHans Rosenfeld {
19911e091e43SHans Rosenfeld 	int ret;
19921e091e43SHans Rosenfeld 	int i;
19931e091e43SHans Rosenfeld 
19941e091e43SHans Rosenfeld 	for (i = 0; i < ncmd; i++) {
19951e091e43SHans Rosenfeld 		lmrc_mfi_cmd_t *mfi = lmrc->l_mfi_cmds[i];
19961e091e43SHans Rosenfeld 
19971e091e43SHans Rosenfeld 		mutex_enter(&mfi->mfi_lock);
19981e091e43SHans Rosenfeld 		if (list_link_active(&mfi->mfi_node)) {
19991e091e43SHans Rosenfeld 			mutex_exit(&mfi->mfi_lock);
20001e091e43SHans Rosenfeld 			continue;
20011e091e43SHans Rosenfeld 		}
20021e091e43SHans Rosenfeld 
20031e091e43SHans Rosenfeld 		/*
20041e091e43SHans Rosenfeld 		 * If the FW is faulted, wake up anyone waiting on the command
20051e091e43SHans Rosenfeld 		 * to clean it up.
20061e091e43SHans Rosenfeld 		 */
20071e091e43SHans Rosenfeld 		if (lmrc->l_fw_fault) {
20081e091e43SHans Rosenfeld 			if (mfi->mfi_callback != NULL)
20091e091e43SHans Rosenfeld 				mfi->mfi_callback(lmrc, mfi);
20101e091e43SHans Rosenfeld 			mutex_exit(&mfi->mfi_lock);
20111e091e43SHans Rosenfeld 			continue;
20121e091e43SHans Rosenfeld 		}
20131e091e43SHans Rosenfeld 
20141e091e43SHans Rosenfeld 		ret = lmrc_abort_cmd(lmrc, mfi);
20151e091e43SHans Rosenfeld 		mutex_exit(&mfi->mfi_lock);
20161e091e43SHans Rosenfeld 		if (ret != DDI_SUCCESS)
20171e091e43SHans Rosenfeld 			return (ret);
20181e091e43SHans Rosenfeld 
20191e091e43SHans Rosenfeld 		lmrc_dma_free(&mfi->mfi_data_dma);
20201e091e43SHans Rosenfeld 		lmrc_put_mfi(mfi);
20211e091e43SHans Rosenfeld 	}
20221e091e43SHans Rosenfeld 
20231e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
20241e091e43SHans Rosenfeld }
20251e091e43SHans Rosenfeld 
20261e091e43SHans Rosenfeld /*
20271e091e43SHans Rosenfeld  * lmrc_get_dcmd
20281e091e43SHans Rosenfeld  *
20291e091e43SHans Rosenfeld  * Build a MFI DCMD with DMA memory for data transfers.
20301e091e43SHans Rosenfeld  */
20311e091e43SHans Rosenfeld lmrc_mfi_cmd_t *
lmrc_get_dcmd(lmrc_t * lmrc,uint16_t flags,uint32_t opcode,uint32_t xferlen,uint_t align)20321e091e43SHans Rosenfeld lmrc_get_dcmd(lmrc_t *lmrc, uint16_t flags, uint32_t opcode, uint32_t xferlen,
20331e091e43SHans Rosenfeld     uint_t align)
20341e091e43SHans Rosenfeld {
20351e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi = lmrc_get_mfi(lmrc);
20361e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
20371e091e43SHans Rosenfeld 	lmrc_mfi_dcmd_payload_t *dcmd = &mfi->mfi_frame->mf_dcmd;
20381e091e43SHans Rosenfeld 	lmrc_dma_t *dma = &mfi->mfi_data_dma;
20391e091e43SHans Rosenfeld 	int ret;
20401e091e43SHans Rosenfeld 
20411e091e43SHans Rosenfeld 	hdr->mh_cmd = MFI_CMD_DCMD;
20421e091e43SHans Rosenfeld 	hdr->mh_flags = flags;
20431e091e43SHans Rosenfeld 
20441e091e43SHans Rosenfeld 	dcmd->md_opcode = opcode;
20451e091e43SHans Rosenfeld 
20461e091e43SHans Rosenfeld 	if ((flags & MFI_FRAME_DIR_READ) != 0 ||
20471e091e43SHans Rosenfeld 	    (flags & MFI_FRAME_DIR_WRITE) != 0) {
20481e091e43SHans Rosenfeld 		ret = lmrc_dma_alloc(lmrc, lmrc->l_dma_attr, dma, xferlen,
20491e091e43SHans Rosenfeld 		    align, DDI_DMA_CONSISTENT);
20501e091e43SHans Rosenfeld 		if (ret != DDI_SUCCESS) {
20511e091e43SHans Rosenfeld 			lmrc_put_mfi(mfi);
20521e091e43SHans Rosenfeld 			return (NULL);
20531e091e43SHans Rosenfeld 		}
20541e091e43SHans Rosenfeld 
20551e091e43SHans Rosenfeld 		hdr->mh_flags |= MFI_FRAME_SGL64;
20561e091e43SHans Rosenfeld 		hdr->mh_sge_count = 1;
20571e091e43SHans Rosenfeld 		hdr->mh_data_xfer_len = lmrc_dma_get_size(dma);
20581e091e43SHans Rosenfeld 
20591e091e43SHans Rosenfeld 		dcmd->md_sgl.ms64_length = lmrc_dma_get_size(dma);
20601e091e43SHans Rosenfeld 		lmrc_dma_set_addr64(dma, &dcmd->md_sgl.ms64_phys_addr);
20611e091e43SHans Rosenfeld 	}
20621e091e43SHans Rosenfeld 
20631e091e43SHans Rosenfeld 	return (mfi);
20641e091e43SHans Rosenfeld }
20651e091e43SHans Rosenfeld 
20661e091e43SHans Rosenfeld /*
20671e091e43SHans Rosenfeld  * lmrc_put_dcmd
20681e091e43SHans Rosenfeld  *
20691e091e43SHans Rosenfeld  * Free the DMA memory of a MFI DCMD and return the command back on the list.
20701e091e43SHans Rosenfeld  */
20711e091e43SHans Rosenfeld void
lmrc_put_dcmd(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi)20721e091e43SHans Rosenfeld lmrc_put_dcmd(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi)
20731e091e43SHans Rosenfeld {
20741e091e43SHans Rosenfeld 	lmrc_dma_free(&mfi->mfi_data_dma);
20751e091e43SHans Rosenfeld 	lmrc_put_mfi(mfi);
20761e091e43SHans Rosenfeld }
20771e091e43SHans Rosenfeld 
20781e091e43SHans Rosenfeld 
20791e091e43SHans Rosenfeld /*
20801e091e43SHans Rosenfeld  * Asynchronous Event Notifications
20811e091e43SHans Rosenfeld  */
20821e091e43SHans Rosenfeld /*
20831e091e43SHans Rosenfeld  * lmrc_get_event_log_info
20841e091e43SHans Rosenfeld  *
20851e091e43SHans Rosenfeld  * Get the Event Log Info from the firmware.
20861e091e43SHans Rosenfeld  */
20871e091e43SHans Rosenfeld static int
lmrc_get_event_log_info(lmrc_t * lmrc,lmrc_evt_log_info_t * eli)20881e091e43SHans Rosenfeld lmrc_get_event_log_info(lmrc_t *lmrc, lmrc_evt_log_info_t *eli)
20891e091e43SHans Rosenfeld {
20901e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi;
20911e091e43SHans Rosenfeld 	int ret;
20921e091e43SHans Rosenfeld 
20931e091e43SHans Rosenfeld 	mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_READ,
20941e091e43SHans Rosenfeld 	    LMRC_DCMD_CTRL_EVENT_GET_INFO, sizeof (lmrc_evt_log_info_t), 1);
20951e091e43SHans Rosenfeld 
20961e091e43SHans Rosenfeld 	if (mfi == NULL)
20971e091e43SHans Rosenfeld 		return (DDI_FAILURE);
20981e091e43SHans Rosenfeld 
20991e091e43SHans Rosenfeld 	ret = lmrc_issue_blocked_mfi(lmrc, mfi);
21001e091e43SHans Rosenfeld 
21011e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
21021e091e43SHans Rosenfeld 		goto out;
21031e091e43SHans Rosenfeld 
21041e091e43SHans Rosenfeld 	bcopy(mfi->mfi_data_dma.ld_buf, eli, sizeof (lmrc_evt_log_info_t));
21051e091e43SHans Rosenfeld 
21061e091e43SHans Rosenfeld out:
21071e091e43SHans Rosenfeld 	lmrc_put_dcmd(lmrc, mfi);
21081e091e43SHans Rosenfeld 	return (ret);
21091e091e43SHans Rosenfeld }
21101e091e43SHans Rosenfeld 
21111e091e43SHans Rosenfeld /*
21121e091e43SHans Rosenfeld  * lmrc_aen_handler
21131e091e43SHans Rosenfeld  *
21141e091e43SHans Rosenfeld  * Check the event code and handle it as needed. In the case of PD or LD related
21151e091e43SHans Rosenfeld  * events, invoke their special handlers.
21161e091e43SHans Rosenfeld  */
21171e091e43SHans Rosenfeld static void
lmrc_aen_handler(void * arg)21181e091e43SHans Rosenfeld lmrc_aen_handler(void *arg)
21191e091e43SHans Rosenfeld {
21201e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi = arg;
21211e091e43SHans Rosenfeld 	lmrc_t *lmrc = mfi->mfi_lmrc;
21221e091e43SHans Rosenfeld 	lmrc_evt_t *evt = mfi->mfi_data_dma.ld_buf;
21231e091e43SHans Rosenfeld 	lmrc_mfi_dcmd_payload_t *dcmd = &mfi->mfi_frame->mf_dcmd;
21241e091e43SHans Rosenfeld 	int ret = DDI_FAILURE;
21251e091e43SHans Rosenfeld 
21261e091e43SHans Rosenfeld 	/* Controller & Configuration specific events */
21271e091e43SHans Rosenfeld 	switch (evt->evt_code) {
21281e091e43SHans Rosenfeld 	case LMRC_EVT_CFG_CLEARED:
21291e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_HOST_BUS_SCAN_REQD:
21301e091e43SHans Rosenfeld 	case LMRC_EVT_FOREIGN_CFG_IMPORTED:
21311e091e43SHans Rosenfeld 		ret = lmrc_get_pd_list(lmrc);
21321e091e43SHans Rosenfeld 		if (ret != DDI_SUCCESS)
21331e091e43SHans Rosenfeld 			break;
21341e091e43SHans Rosenfeld 
21351e091e43SHans Rosenfeld 		ret = lmrc_get_ld_list(lmrc);
21361e091e43SHans Rosenfeld 		break;
21371e091e43SHans Rosenfeld 
21381e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_PROP_CHANGED:
21391e091e43SHans Rosenfeld 		ret = lmrc_get_ctrl_info(lmrc);
21401e091e43SHans Rosenfeld 		break;
21411e091e43SHans Rosenfeld 
21421e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_PATROL_READ_START:
21431e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_PATROL_READ_RESUMED:
21441e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_PATROL_READ_COMPLETE:
21451e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_PATROL_READ_CANT_START:
21461e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_PERF_COLLECTION:
21471e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_BOOTDEV_SET:
21481e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_BOOTDEV_RESET:
21491e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_PERSONALITY_CHANGE:
21501e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_PERSONALITY_CHANGE_PEND:
21511e091e43SHans Rosenfeld 	case LMRC_EVT_CTRL_NR_OF_VALID_SNAPDUMP:
21521e091e43SHans Rosenfeld 		break;
21531e091e43SHans Rosenfeld 
21541e091e43SHans Rosenfeld 	default:
21551e091e43SHans Rosenfeld 		/* LD-specific events */
21561e091e43SHans Rosenfeld 		if ((evt->evt_locale & LMRC_EVT_LOCALE_LD) != 0)
21571e091e43SHans Rosenfeld 			ret = lmrc_raid_aen_handler(lmrc, evt);
21581e091e43SHans Rosenfeld 
21591e091e43SHans Rosenfeld 		/* PD-specific events */
21601e091e43SHans Rosenfeld 		else if ((evt->evt_locale & LMRC_EVT_LOCALE_PD) != 0)
21611e091e43SHans Rosenfeld 			ret = lmrc_phys_aen_handler(lmrc, evt);
21621e091e43SHans Rosenfeld 
21631e091e43SHans Rosenfeld 		if (ret != DDI_SUCCESS) {
21641e091e43SHans Rosenfeld 			dev_err(lmrc->l_dip, CE_NOTE, "!unknown AEN received, "
21651e091e43SHans Rosenfeld 			    "seqnum = %d, timestamp = %d, code = %x, "
21661e091e43SHans Rosenfeld 			    "locale = %x, class = %d, argtype = %d",
21671e091e43SHans Rosenfeld 			    evt->evt_seqnum, evt->evt_timestamp, evt->evt_code,
21681e091e43SHans Rosenfeld 			    evt->evt_locale, evt->evt_class, evt->evt_argtype);
21691e091e43SHans Rosenfeld 		}
21701e091e43SHans Rosenfeld 	}
21711e091e43SHans Rosenfeld 
21721e091e43SHans Rosenfeld 	dev_err(lmrc->l_dip, CE_NOTE, "!%s", evt->evt_descr);
21731e091e43SHans Rosenfeld 
21741e091e43SHans Rosenfeld 	/*
21751e091e43SHans Rosenfeld 	 * Just reuse the command in its entirety. Increase the sequence
21761e091e43SHans Rosenfeld 	 * number.
21771e091e43SHans Rosenfeld 	 */
21781e091e43SHans Rosenfeld 	dcmd->md_mbox_32[0] = evt->evt_seqnum + 1;
21791e091e43SHans Rosenfeld 	mutex_enter(&mfi->mfi_lock);
21801e091e43SHans Rosenfeld 	lmrc_issue_mfi(lmrc, mfi, lmrc_complete_aen);
21811e091e43SHans Rosenfeld 	mutex_exit(&mfi->mfi_lock);
21821e091e43SHans Rosenfeld }
21831e091e43SHans Rosenfeld 
21841e091e43SHans Rosenfeld /*
21851e091e43SHans Rosenfeld  * lmrc_complete_aen
21861e091e43SHans Rosenfeld  *
21871e091e43SHans Rosenfeld  * An AEN was received, so schedule a taskq to process it.
21881e091e43SHans Rosenfeld  */
21891e091e43SHans Rosenfeld static void
lmrc_complete_aen(lmrc_t * lmrc,lmrc_mfi_cmd_t * mfi)21901e091e43SHans Rosenfeld lmrc_complete_aen(lmrc_t *lmrc, lmrc_mfi_cmd_t *mfi)
21911e091e43SHans Rosenfeld {
21921e091e43SHans Rosenfeld 	lmrc_mfi_header_t *hdr = &mfi->mfi_frame->mf_hdr;
21931e091e43SHans Rosenfeld 
21941e091e43SHans Rosenfeld 	ASSERT(mutex_owned(&mfi->mfi_lock));
21951e091e43SHans Rosenfeld 
21961e091e43SHans Rosenfeld 	if (hdr->mh_cmd_status != MFI_STAT_OK) {
21971e091e43SHans Rosenfeld 		/* Was the command aborted? */
21981e091e43SHans Rosenfeld 		if (hdr->mh_cmd_status == MFI_STAT_NOT_FOUND)
21991e091e43SHans Rosenfeld 			return;
22001e091e43SHans Rosenfeld 
22011e091e43SHans Rosenfeld 		dev_err(lmrc->l_dip, CE_WARN,
22021e091e43SHans Rosenfeld 		    "!AEN failed, status = %d",
22031e091e43SHans Rosenfeld 		    hdr->mh_cmd_status);
22041e091e43SHans Rosenfeld 		taskq_dispatch_ent(lmrc->l_taskq, (task_func_t *)lmrc_put_mfi,
22051e091e43SHans Rosenfeld 		    mfi, TQ_NOSLEEP, &mfi->mfi_tqent);
22061e091e43SHans Rosenfeld 		return;
22071e091e43SHans Rosenfeld 	}
22081e091e43SHans Rosenfeld 
22091e091e43SHans Rosenfeld 	taskq_dispatch_ent(lmrc->l_taskq, lmrc_aen_handler, mfi, TQ_NOSLEEP,
22101e091e43SHans Rosenfeld 	    &mfi->mfi_tqent);
22111e091e43SHans Rosenfeld }
22121e091e43SHans Rosenfeld 
22131e091e43SHans Rosenfeld /*
22141e091e43SHans Rosenfeld  * lmrc_register_aen
22151e091e43SHans Rosenfeld  *
22161e091e43SHans Rosenfeld  * In FreeBSD, this function checks for an existing AEN. If its class and locale
22171e091e43SHans Rosenfeld  * already include what is requested here they just return. In the other case,
22181e091e43SHans Rosenfeld  * the existing AEN is aborted and a new one is created, which includes
22191e091e43SHans Rosenfeld  * the previous locale and class and new ones.
22201e091e43SHans Rosenfeld  *
22211e091e43SHans Rosenfeld  * Given that the driver (same as in FreeBSD) calls this function during attach
22221e091e43SHans Rosenfeld  * to create an AEN with LOCALE_ALL and CLASS_DEBUG, all of this would be dead
22231e091e43SHans Rosenfeld  * code anyway.
22241e091e43SHans Rosenfeld  */
22251e091e43SHans Rosenfeld static int
lmrc_register_aen(lmrc_t * lmrc,uint32_t seqnum)22261e091e43SHans Rosenfeld lmrc_register_aen(lmrc_t *lmrc, uint32_t seqnum)
22271e091e43SHans Rosenfeld {
22281e091e43SHans Rosenfeld 	lmrc_evt_class_locale_t ecl = {
22291e091e43SHans Rosenfeld 		.ecl_class = LMRC_EVT_CLASS_DEBUG,
22301e091e43SHans Rosenfeld 		.ecl_locale = LMRC_EVT_LOCALE_ALL
22311e091e43SHans Rosenfeld 	};
22321e091e43SHans Rosenfeld 
22331e091e43SHans Rosenfeld 	lmrc_mfi_cmd_t *mfi;
22341e091e43SHans Rosenfeld 	lmrc_mfi_dcmd_payload_t *dcmd;
22351e091e43SHans Rosenfeld 
22361e091e43SHans Rosenfeld 	mfi = lmrc_get_dcmd(lmrc, MFI_FRAME_DIR_READ, LMRC_DCMD_CTRL_EVENT_WAIT,
22371e091e43SHans Rosenfeld 	    sizeof (lmrc_evt_t), 1);
22381e091e43SHans Rosenfeld 
22391e091e43SHans Rosenfeld 	if (mfi == NULL)
22401e091e43SHans Rosenfeld 		return (DDI_FAILURE);
22411e091e43SHans Rosenfeld 
22421e091e43SHans Rosenfeld 	dcmd = &mfi->mfi_frame->mf_dcmd;
22431e091e43SHans Rosenfeld 	dcmd->md_mbox_32[0] = seqnum;
22441e091e43SHans Rosenfeld 	dcmd->md_mbox_32[1] = ecl.ecl_word;
22451e091e43SHans Rosenfeld 
22461e091e43SHans Rosenfeld 	mutex_enter(&mfi->mfi_lock);
22471e091e43SHans Rosenfeld 	lmrc_issue_mfi(lmrc, mfi, lmrc_complete_aen);
22481e091e43SHans Rosenfeld 	mutex_exit(&mfi->mfi_lock);
22491e091e43SHans Rosenfeld 
22501e091e43SHans Rosenfeld 	return (DDI_SUCCESS);
22511e091e43SHans Rosenfeld }
22521e091e43SHans Rosenfeld 
22531e091e43SHans Rosenfeld /*
22541e091e43SHans Rosenfeld  * lmrc_start_aen
22551e091e43SHans Rosenfeld  *
22561e091e43SHans Rosenfeld  * Set up and enable AEN processing.
22571e091e43SHans Rosenfeld  */
22581e091e43SHans Rosenfeld int
lmrc_start_aen(lmrc_t * lmrc)22591e091e43SHans Rosenfeld lmrc_start_aen(lmrc_t *lmrc)
22601e091e43SHans Rosenfeld {
22611e091e43SHans Rosenfeld 	lmrc_evt_log_info_t eli;
22621e091e43SHans Rosenfeld 	int ret;
22631e091e43SHans Rosenfeld 
22641e091e43SHans Rosenfeld 	bzero(&eli, sizeof (eli));
22651e091e43SHans Rosenfeld 
22661e091e43SHans Rosenfeld 	/* Get the latest sequence number from the Event Log Info. */
22671e091e43SHans Rosenfeld 	ret = lmrc_get_event_log_info(lmrc, &eli);
22681e091e43SHans Rosenfeld 	if (ret != DDI_SUCCESS)
22691e091e43SHans Rosenfeld 		return (ret);
22701e091e43SHans Rosenfeld 
22711e091e43SHans Rosenfeld 	/* Register AEN with FW for latest sequence number + 1. */
22721e091e43SHans Rosenfeld 	ret = lmrc_register_aen(lmrc, eli.eli_newest_seqnum + 1);
22731e091e43SHans Rosenfeld 	return (ret);
22741e091e43SHans Rosenfeld }
2275