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