Print this page
MFV: illumos-omnios@aea0472ecb9ee91fa70556d6f6a941c10c989f1d
Add support for Emulex Corporation Lancer Gen6: LPe32000 FC Host Adapter
Author: Andy Fiddaman <omnios@citrus-it.co.uk>
NEX-8705 Drivers for ATTO Celerity FC-162E Gen 5 and Celerity FC-162P Gen 6 16GB FC cards support
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-1878 update emlxs from source provided by Emulex
@@ -20,10 +20,11 @@
*/
/*
* Copyright (c) 2004-2012 Emulex. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
*/
#include <emlxs.h>
@@ -119,10 +120,23 @@
static void emlxs_sli4_timer(emlxs_hba_t *hba);
static void emlxs_sli4_timer_check_mbox(emlxs_hba_t *hba);
+static void emlxs_sli4_gpio_timer_start(emlxs_hba_t *hba);
+
+static void emlxs_sli4_gpio_timer_stop(emlxs_hba_t *hba);
+
+static void emlxs_sli4_gpio_timer(void *arg);
+
+static void emlxs_sli4_check_gpio(emlxs_hba_t *hba);
+
+static uint32_t emlxs_sli4_fix_gpio(emlxs_hba_t *hba,
+ uint8_t *pin, uint8_t *pinval);
+
+static uint32_t emlxs_sli4_fix_gpio_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq);
+
static void emlxs_sli4_poll_erratt(emlxs_hba_t *hba);
extern XRIobj_t *emlxs_sli4_reserve_xri(emlxs_port_t *port,
RPIobj_t *rpip, uint32_t type, uint16_t rx_id);
static int emlxs_check_hdw_ready(emlxs_hba_t *);
@@ -330,19 +344,44 @@
cfg[CFG_NUM_WQ].current = 1;
hba->chan_count = hba->intr_count * cfg[CFG_NUM_WQ].current;
}
hba->channel_fcp = 0; /* First channel */
+ /* Gen6 chips only support P2P topologies */
+ if ((hba->model_info.flags & EMLXS_FC_GEN6) &&
+ cfg[CFG_TOPOLOGY].current != 2) {
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_msg,
+ "Loop topologies are not supported by this HBA. "
+ "Forcing topology to P2P.");
+ cfg[CFG_TOPOLOGY].current = 2;
+ }
+
/* Default channel for everything else is the last channel */
hba->channel_ip = hba->chan_count - 1;
hba->channel_els = hba->chan_count - 1;
hba->channel_ct = hba->chan_count - 1;
hba->fc_iotag = 1;
hba->io_count = 0;
hba->channel_tx_count = 0;
+ /* Specific to ATTO G5 boards */
+ if (hba->model_info.flags & EMLXS_GPIO_LEDS) {
+ /* Set hard-coded GPIO pins */
+ if (hba->pci_function_number) {
+ hba->gpio_pin[EMLXS_GPIO_PIN_LO] = 27;
+ hba->gpio_pin[EMLXS_GPIO_PIN_HI] = 28;
+ hba->gpio_pin[EMLXS_GPIO_PIN_ACT] = 29;
+ hba->gpio_pin[EMLXS_GPIO_PIN_LASER] = 8;
+ } else {
+ hba->gpio_pin[EMLXS_GPIO_PIN_LO] = 13;
+ hba->gpio_pin[EMLXS_GPIO_PIN_HI] = 25;
+ hba->gpio_pin[EMLXS_GPIO_PIN_ACT] = 26;
+ hba->gpio_pin[EMLXS_GPIO_PIN_LASER] = 12;
+ }
+ }
+
/* Initialize the local dump region buffer */
bzero(&hba->sli.sli4.dump_region, sizeof (MBUF_INFO));
hba->sli.sli4.dump_region.size = EMLXS_DUMP_REGION_SIZE;
hba->sli.sli4.dump_region.flags = FC_MBUF_DMA | FC_MBUF_SNGLSG
| FC_MBUF_DMA32;
@@ -1327,16 +1366,18 @@
emlxs_build_prog_types(hba, vpd);
}
/* Create the symbolic names */
(void) snprintf(hba->snn, (sizeof (hba->snn)-1),
- "Emulex %s FV%s DV%s %s",
- hba->model_info.model, hba->vpd.fw_version, emlxs_version,
+ "%s %s FV%s DV%s %s",
+ hba->model_info.manufacturer, hba->model_info.model,
+ hba->vpd.fw_version, emlxs_version,
(char *)utsname.nodename);
(void) snprintf(hba->spn, (sizeof (hba->spn)-1),
- "Emulex PPN-%01x%01x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ "%s PPN-%01x%01x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ hba->model_info.manufacturer,
hba->wwpn.nameType, hba->wwpn.IEEEextMsn, hba->wwpn.IEEEextLsb,
hba->wwpn.IEEE[0], hba->wwpn.IEEE[1], hba->wwpn.IEEE[2],
hba->wwpn.IEEE[3], hba->wwpn.IEEE[4], hba->wwpn.IEEE[5]);
@@ -1403,10 +1444,14 @@
if (mbq) {
(void) kmem_free((uint8_t *)mbq, sizeof (MAILBOXQ));
mbq = NULL;
mb = NULL;
}
+
+ if (hba->model_info.flags & EMLXS_GPIO_LEDS)
+ emlxs_sli4_gpio_timer_start(hba);
+
return (0);
failed3:
EMLXS_STATE_CHANGE(hba, FC_ERROR);
@@ -1448,10 +1493,13 @@
static void
emlxs_sli4_offline(emlxs_hba_t *hba, uint32_t reset_requested)
{
/* Reverse emlxs_sli4_online */
+ if (hba->model_info.flags & EMLXS_GPIO_LEDS)
+ emlxs_sli4_gpio_timer_stop(hba);
+
mutex_enter(&EMLXS_PORT_LOCK);
if (hba->flag & FC_INTERLOCKED) {
mutex_exit(&EMLXS_PORT_LOCK);
goto killed;
}
@@ -2361,10 +2409,19 @@
hba->heartbeat_active = 0;
hba->discovery_timer = 0;
hba->linkup_timer = 0;
hba->loopback_tics = 0;
+ /* Specific to ATTO G5 boards */
+ if (hba->model_info.flags & EMLXS_GPIO_LEDS) {
+ /* Assume the boot driver enabled all LEDs */
+ hba->gpio_current =
+ EMLXS_GPIO_LO | EMLXS_GPIO_HI | EMLXS_GPIO_ACT;
+ hba->gpio_desired = 0;
+ hba->gpio_bit = 0;
+ }
+
/* Reset the port objects */
for (i = 0; i < MAX_VPORTS; i++) {
vport = &VPORT(i);
vport->flag &= EMLXS_PORT_RESET_MASK;
@@ -2553,11 +2610,11 @@
iocbq = (IOCBQ *) &sbp->iocbq;
wqe = &iocbq->wqe;
pkt = PRIV2PKT(sbp);
xrip = sbp->xrip;
- sge = xrip->SGList.virt;
+ sge = xrip->SGList->virt;
#if (EMLXS_MODREV >= EMLXS_MODREV3)
cp_cmd = pkt->pkt_cmd_cookie;
cp_data = pkt->pkt_data_cookie;
#else
@@ -2703,11 +2760,11 @@
"fct_bde_setup: Only 1 sglist entry supported: %d",
sbp->fct_buf->db_sglist_length);
return (1);
}
- sge = xrip->SGList.virt;
+ sge = xrip->SGList->virt;
if (iocb->ULPCOMMAND == CMD_FCP_TRECEIVE64_CX) {
mp = emlxs_mem_buf_alloc(hba, EMLXS_XFER_RDY_SIZE);
if (!mp || !mp->virt || !mp->phys) {
@@ -3986,11 +4043,11 @@
/* Make size a multiple of 4 */
if (sge_size & 3) {
sge_size = (sge_size + 3) & 0xfffffffc;
}
sge_addr = cp_cmd->dmac_laddress;
- sge = xrip->SGList.virt;
+ sge = xrip->SGList->virt;
stage_sge.addrHigh = PADDR_HI(sge_addr);
stage_sge.addrLow = PADDR_LO(sge_addr);
stage_sge.length = sge_size;
stage_sge.offset = 0;
@@ -4178,11 +4235,10 @@
IOCBQ *iocbq;
IOCB *iocb;
NODELIST *node;
uint16_t iotag;
uint32_t did;
- off_t offset;
pkt = PRIV2PKT(sbp);
did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);
cp = &hba->chan[channel];
@@ -4240,27 +4296,23 @@
}
/* DEBUG */
#ifdef DEBUG_FCP
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
- "FCP: SGLaddr virt %p phys %p size %d", xrip->SGList.virt,
- xrip->SGList.phys, pkt->pkt_datalen);
- emlxs_data_dump(port, "FCP: SGL", (uint32_t *)xrip->SGList.virt, 20, 0);
+ "FCP: SGLaddr virt %p phys %p size %d", xrip->SGList->virt,
+ xrip->SGList->phys, pkt->pkt_datalen);
+ emlxs_data_dump(port, "FCP: SGL",
+ (uint32_t *)xrip->SGList->virt, 20, 0);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"FCP: CMD virt %p len %d:%d:%d",
pkt->pkt_cmd, pkt->pkt_cmdlen, pkt->pkt_rsplen, pkt->pkt_datalen);
emlxs_data_dump(port, "FCP: CMD", (uint32_t *)pkt->pkt_cmd, 10, 0);
#endif /* DEBUG_FCP */
- offset = (off_t)((uint64_t)((unsigned long)
- xrip->SGList.virt) -
- (uint64_t)((unsigned long)
- hba->sli.sli4.slim2.virt));
+ EMLXS_MPDATA_SYNC(xrip->SGList->dma_handle, 0,
+ xrip->SGList->size, DDI_DMA_SYNC_FORDEV);
- EMLXS_MPDATA_SYNC(xrip->SGList.dma_handle, offset,
- xrip->SGList.size, DDI_DMA_SYNC_FORDEV);
-
/* if device is FCP-2 device, set the following bit */
/* that says to run the FC-TAPE protocol. */
if (node->nlp_fcp_info & NLP_FCP_2_DEVICE) {
wqe->ERP = 1;
}
@@ -4340,11 +4392,10 @@
ULP_SGE64 stage_sge;
ULP_SGE64 *sge;
ddi_dma_cookie_t *cp_cmd;
ddi_dma_cookie_t *cp_resp;
emlxs_node_t *node;
- off_t offset;
pkt = PRIV2PKT(sbp);
did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);
iocbq = &sbp->iocbq;
@@ -4434,11 +4485,11 @@
wqe->OXId = xrip->rx_id;
sge->last = 1;
/* Now sge is fully staged */
- sge = xrip->SGList.virt;
+ sge = xrip->SGList->virt;
BE_SWAP32_BCOPY((uint8_t *)&stage_sge, (uint8_t *)sge,
sizeof (ULP_SGE64));
if (rpip->RPI == FABRIC_RPI) {
wqe->ContextTag = port->vpip->VPI;
@@ -4499,11 +4550,11 @@
iocb->un.elsreq64.remoteID = (did == BCAST_DID) ? 0 : did;
iocb->ULPPU = 1; /* Wd4 is relative offset */
sge->last = 0;
- sge = xrip->SGList.virt;
+ sge = xrip->SGList->virt;
BE_SWAP32_BCOPY((uint8_t *)&stage_sge, (uint8_t *)sge,
sizeof (ULP_SGE64));
wqe->un.ElsCmd.PayloadLength =
pkt->pkt_cmdlen; /* Byte offset of rsp data */
@@ -4515,23 +4566,23 @@
sge->length = pkt->pkt_rsplen;
sge->offset = 0;
sge->last = 1;
/* Now sge is fully staged */
- sge = xrip->SGList.virt;
+ sge = xrip->SGList->virt;
sge++;
BE_SWAP32_BCOPY((uint8_t *)&stage_sge, (uint8_t *)sge,
sizeof (ULP_SGE64));
#ifdef DEBUG_ELS
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"ELS: SGLaddr virt %p phys %p",
- xrip->SGList.virt, xrip->SGList.phys);
+ xrip->SGList->virt, xrip->SGList->phys);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"ELS: PAYLOAD virt %p phys %p",
pkt->pkt_cmd, cp_cmd->dmac_laddress);
- emlxs_data_dump(port, "ELS: SGL", (uint32_t *)xrip->SGList.virt,
- 12, 0);
+ emlxs_data_dump(port, "ELS: SGL",
+ (uint32_t *)xrip->SGList->virt, 12, 0);
#endif /* DEBUG_ELS */
switch (cmd) {
case ELS_CMD_FLOGI:
wqe->un.ElsCmd.SP = 1;
@@ -4633,18 +4684,13 @@
} else {
wqe->CmdSpecific = reserved_rpip->RPI;
}
}
- offset = (off_t)((uint64_t)((unsigned long)
- xrip->SGList.virt) -
- (uint64_t)((unsigned long)
- hba->sli.sli4.slim2.virt));
+ EMLXS_MPDATA_SYNC(xrip->SGList->dma_handle, 0,
+ xrip->SGList->size, DDI_DMA_SYNC_FORDEV);
- EMLXS_MPDATA_SYNC(xrip->SGList.dma_handle, offset,
- xrip->SGList.size, DDI_DMA_SYNC_FORDEV);
-
if (pkt->pkt_cmd_fhdr.f_ctl & F_CTL_CHAINED_SEQ) {
wqe->CCPE = 1;
wqe->CCP = pkt->pkt_cmd_fhdr.rsvd;
}
@@ -4678,11 +4724,10 @@
NODELIST *node = NULL;
CHANNEL *cp;
RPIobj_t *rpip;
XRIobj_t *xrip;
uint32_t did;
- off_t offset;
pkt = PRIV2PKT(sbp);
did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);
iocbq = &sbp->iocbq;
@@ -4830,13 +4875,13 @@
wqe->un.GenReq.Rctl = pkt->pkt_cmd_fhdr.r_ctl;
wqe->un.GenReq.Type = pkt->pkt_cmd_fhdr.type;
#ifdef DEBUG_CT
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
- "CT: SGLaddr virt %p phys %p", xrip->SGList.virt,
- xrip->SGList.phys);
- emlxs_data_dump(port, "CT: SGL", (uint32_t *)xrip->SGList.virt,
+ "CT: SGLaddr virt %p phys %p", xrip->SGList->virt,
+ xrip->SGList->phys);
+ emlxs_data_dump(port, "CT: SGL", (uint32_t *)xrip->SGList->virt,
12, 0);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"CT: CMD virt %p len %d:%d",
pkt->pkt_cmd, pkt->pkt_cmdlen, pkt->pkt_rsplen);
emlxs_data_dump(port, "CT: DATA", (uint32_t *)pkt->pkt_cmd,
@@ -4856,18 +4901,13 @@
iocb->un.genreq64.w5.hcsw.Rctl = pkt->pkt_cmd_fhdr.r_ctl;
iocb->un.genreq64.w5.hcsw.Type = pkt->pkt_cmd_fhdr.type;
iocb->un.genreq64.w5.hcsw.Dfctl = pkt->pkt_cmd_fhdr.df_ctl;
iocb->ULPPU = 1; /* Wd4 is relative offset */
- offset = (off_t)((uint64_t)((unsigned long)
- xrip->SGList.virt) -
- (uint64_t)((unsigned long)
- hba->sli.sli4.slim2.virt));
+ EMLXS_MPDATA_SYNC(xrip->SGList->dma_handle, 0,
+ xrip->SGList->size, DDI_DMA_SYNC_FORDEV);
- EMLXS_MPDATA_SYNC(xrip->SGList.dma_handle, offset,
- xrip->SGList.size, DDI_DMA_SYNC_FORDEV);
-
wqe->ContextTag = rpip->RPI;
wqe->ContextType = WQE_RPI_CONTEXT;
wqe->XRITag = xrip->XRI;
wqe->Timer = ((pkt->pkt_timeout > 0xff) ? 0 : pkt->pkt_timeout);
@@ -5106,11 +5146,32 @@
}
break;
case ASYNC_EVENT_CODE_PORT:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"SLI Port Async Event: type=%d", cqe->event_type);
- if (cqe->event_type == ASYNC_EVENT_MISCONFIG_PORT) {
+
+ switch (cqe->event_type) {
+ case ASYNC_EVENT_PORT_OTEMP:
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
+ "SLI Port Async Event: Temperature limit exceeded");
+ cmn_err(CE_WARN,
+ "^%s%d: Temperature limit exceeded. Fibre channel "
+ "controller temperature %u degrees C",
+ DRIVER_NAME, hba->ddiinst,
+ BE_SWAP32(*(uint32_t *)cqe->un.port.link_status));
+ break;
+
+ case ASYNC_EVENT_PORT_NTEMP:
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
+ "SLI Port Async Event: Temperature returned to "
+ "normal");
+ cmn_err(CE_WARN,
+ "^%s%d: Temperature returned to normal",
+ DRIVER_NAME, hba->ddiinst);
+ break;
+
+ case ASYNC_EVENT_MISCONFIG_PORT:
*((uint32_t *)cqe->un.port.link_status) =
BE_SWAP32(*((uint32_t *)cqe->un.port.link_status));
status =
cqe->un.port.link_status[hba->sli.sli4.link_number];
@@ -5159,11 +5220,13 @@
"^%s%d: Misconfigured port: status=0x%x - "
"Check optics on card.",
DRIVER_NAME, hba->ddiinst, status);
break;
}
+ break;
}
+
break;
case ASYNC_EVENT_CODE_VF:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"VF Async Event: type=%d",
cqe->event_type);
@@ -6597,23 +6660,10 @@
}
/* pass xrip to FCT in the iocbq */
iocbq->sbp = xrip;
-#define EMLXS_FIX_CISCO_BUG1
-#ifdef EMLXS_FIX_CISCO_BUG1
-{
-uint8_t *ptr;
-ptr = ((uint8_t *)seq_mp->virt);
-if (((*ptr+12) != 0xa0) && (*(ptr+20) == 0x8) && (*(ptr+21) == 0x8)) {
- EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
- "RQ ENTRY: Bad CDB fixed");
- *ptr++ = 0;
- *ptr = 0;
-}
-}
-#endif
(void) emlxs_fct_handle_unsol_req(port, cp, iocbq,
seq_mp, seq_len);
break;
#endif /* SFCT_SUPPORT */
@@ -7194,11 +7244,10 @@
hba->sli.sli4.flag &= ~EMLXS_SLI4_INTR_ENABLED;
/* Short of reset, we cannot disable interrupts */
} /* emlxs_sli4_disable_intr() */
-
static void
emlxs_sli4_resource_free(emlxs_hba_t *hba)
{
emlxs_port_t *port = &PPORT;
MBUF_INFO *buf_info;
@@ -7216,10 +7265,12 @@
if (buf_info->virt) {
bzero(buf_info, sizeof (MBUF_INFO));
}
if (hba->sli.sli4.XRIp) {
+ XRIobj_t *xrip;
+
if ((hba->sli.sli4.XRIinuse_f !=
(XRIobj_t *)&hba->sli.sli4.XRIinuse_f) ||
(hba->sli.sli4.XRIinuse_b !=
(XRIobj_t *)&hba->sli.sli4.XRIinuse_f)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
@@ -7226,10 +7277,21 @@
"XRIs in use during free!: %p %p != %p\n",
hba->sli.sli4.XRIinuse_f,
hba->sli.sli4.XRIinuse_b,
&hba->sli.sli4.XRIinuse_f);
}
+
+ xrip = hba->sli.sli4.XRIp;
+ for (i = 0; i < hba->sli.sli4.XRICount; i++) {
+ xrip->XRI = emlxs_sli4_index_to_xri(hba, i);
+
+ if (xrip->XRI != 0)
+ emlxs_mem_put(hba, xrip->SGSeg, xrip->SGList);
+
+ xrip++;
+ }
+
kmem_free(hba->sli.sli4.XRIp,
(sizeof (XRIobj_t) * hba->sli.sli4.XRICount));
hba->sli.sli4.XRIp = NULL;
hba->sli.sli4.XRIfree_f =
@@ -7270,13 +7332,16 @@
buf_info->flags = FC_MBUF_DMA;
emlxs_mem_free(hba, buf_info);
bzero(buf_info, sizeof (MBUF_INFO));
}
+ /* GPIO lock */
+ if (hba->model_info.flags & EMLXS_GPIO_LEDS)
+ mutex_destroy(&hba->gpio_lock);
+
} /* emlxs_sli4_resource_free() */
-
static int
emlxs_sli4_resource_alloc(emlxs_hba_t *hba)
{
emlxs_port_t *port = &PPORT;
emlxs_config_t *cfg = &CFG;
@@ -7350,14 +7415,10 @@
/* RQB/E */
count += RQB_COUNT * (RQB_DATA_SIZE + RQB_HEADER_SIZE);
count += (4096 - (count%4096)); /* Ensure 4K alignment */
- /* SGL */
- count += hba->sli.sli4.XRIExtSize * hba->sli.sli4.mem_sgl_size;
- count += (4096 - (count%4096)); /* Ensure 4K alignment */
-
/* RPI Header Templates */
if (hba->sli.sli4.param.HDRR) {
/* Bytes per extent */
j = hba->sli.sli4.RPIExtSize * sizeof (RPIHdrTmplate_t);
@@ -7374,10 +7435,13 @@
buf_info = &hba->sli.sli4.slim2;
buf_info->size = count;
buf_info->flags = FC_MBUF_DMA | FC_MBUF_SNGLSG | FC_MBUF_DMA32;
buf_info->align = ddi_ptob(hba->dip, 1L);
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
+ "Allocating memory for slim2: %d", count);
+
(void) emlxs_mem_alloc(hba, buf_info);
if (buf_info->virt == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_init_failed_msg,
@@ -7387,11 +7451,11 @@
}
bzero(buf_info->virt, buf_info->size);
EMLXS_MPDATA_SYNC(buf_info->dma_handle, 0,
buf_info->size, DDI_DMA_SYNC_FORDEV);
- /* Assign memory to SGL, Head Template, EQ, CQ, WQ, RQ and MQ */
+ /* Assign memory to Head Template, EQ, CQ, WQ, RQ and MQ */
data_handle = buf_info->data_handle;
dma_handle = buf_info->dma_handle;
phys = buf_info->phys;
virt = (char *)buf_info->virt;
@@ -7577,11 +7641,29 @@
/* 4K Alignment */
align = (4096 - (phys%4096));
phys += align;
virt += align;
+ /* RPI Header Templates */
+ if (hba->sli.sli4.param.HDRR) {
+ buf_info = &hba->sli.sli4.HeaderTmplate;
+ bzero(buf_info, sizeof (MBUF_INFO));
+ buf_info->size = hddr_size;
+ buf_info->flags = FC_MBUF_DMA | FC_MBUF_DMA32;
+ buf_info->align = ddi_ptob(hba->dip, 1L);
+ buf_info->phys = phys;
+ buf_info->virt = (void *)virt;
+ buf_info->data_handle = data_handle;
+ buf_info->dma_handle = dma_handle;
+ }
+
/* SGL */
+
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
+ "Allocating memory for %d SGLs: %d/%d",
+ hba->sli.sli4.XRICount, sizeof (XRIobj_t), size);
+
/* Initialize double linked lists */
hba->sli.sli4.XRIinuse_f =
(XRIobj_t *)&hba->sli.sli4.XRIinuse_f;
hba->sli.sli4.XRIinuse_b =
(XRIobj_t *)&hba->sli.sli4.XRIinuse_f;
@@ -7589,18 +7671,37 @@
hba->sli.sli4.XRIfree_f =
(XRIobj_t *)&hba->sli.sli4.XRIfree_f;
hba->sli.sli4.XRIfree_b =
(XRIobj_t *)&hba->sli.sli4.XRIfree_f;
- hba->sli.sli4.xria_count = 0;
+ hba->sli.sli4.xrif_count = 0;
+ uint32_t mseg;
+
+ switch (hba->sli.sli4.mem_sgl_size) {
+ case 1024:
+ mseg = MEM_SGL1K;
+ break;
+ case 2048:
+ mseg = MEM_SGL2K;
+ break;
+ case 4096:
+ mseg = MEM_SGL4K;
+ break;
+ default:
+ EMLXS_MSGF(EMLXS_CONTEXT,
+ &emlxs_init_failed_msg,
+ "Unsupported SGL Size: %d", hba->sli.sli4.mem_sgl_size);
+ goto failed;
+ }
+
hba->sli.sli4.XRIp = (XRIobj_t *)kmem_zalloc(
(sizeof (XRIobj_t) * hba->sli.sli4.XRICount), KM_SLEEP);
xrip = hba->sli.sli4.XRIp;
- size = hba->sli.sli4.mem_sgl_size;
iotag = 1;
+
for (i = 0; i < hba->sli.sli4.XRICount; i++) {
xrip->XRI = emlxs_sli4_index_to_xri(hba, i);
/* We don't use XRI==0, since it also represents an */
/* uninitialized exchange */
@@ -7619,44 +7720,29 @@
xrip->_f = (XRIobj_t *)&hba->sli.sli4.XRIfree_f;
hba->sli.sli4.XRIfree_b = xrip;
hba->sli.sli4.xrif_count++;
/* Allocate SGL for this xrip */
- buf_info = &xrip->SGList;
- buf_info->size = size;
- buf_info->flags =
- FC_MBUF_DMA | FC_MBUF_SNGLSG | FC_MBUF_DMA32;
- buf_info->align = size;
- buf_info->phys = phys;
- buf_info->virt = (void *)virt;
- buf_info->data_handle = data_handle;
- buf_info->dma_handle = dma_handle;
+ xrip->SGSeg = mseg;
+ xrip->SGList = emlxs_mem_get(hba, xrip->SGSeg);
- phys += size;
- virt += size;
-
- xrip++;
+ if (xrip->SGList == NULL) {
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
+ "Unable to allocate memory for SGL %d", i);
+ goto failed;
}
- /* 4K Alignment */
- align = (4096 - (phys%4096));
- phys += align;
- virt += align;
+ EMLXS_MPDATA_SYNC(xrip->SGList->dma_handle, 0,
+ xrip->SGList->size, DDI_DMA_SYNC_FORDEV);
- /* RPI Header Templates */
- if (hba->sli.sli4.param.HDRR) {
- buf_info = &hba->sli.sli4.HeaderTmplate;
- bzero(buf_info, sizeof (MBUF_INFO));
- buf_info->size = hddr_size;
- buf_info->flags = FC_MBUF_DMA | FC_MBUF_DMA32;
- buf_info->align = ddi_ptob(hba->dip, 1L);
- buf_info->phys = phys;
- buf_info->virt = (void *)virt;
- buf_info->data_handle = data_handle;
- buf_info->dma_handle = dma_handle;
+ xrip++;
}
+ /* GPIO lock */
+ if (hba->model_info.flags & EMLXS_GPIO_LEDS)
+ mutex_init(&hba->gpio_lock, NULL, MUTEX_DRIVER, NULL);
+
#ifdef FMA_SUPPORT
if (hba->sli.sli4.slim2.dma_handle) {
if (emlxs_fm_check_dma_handle(hba,
hba->sli.sli4.slim2.dma_handle)
!= DDI_FM_OK) {
@@ -8249,14 +8335,14 @@
for (i = 0; (i < xri_cnt) && cnt; i++) {
post_sgl->params.request.xri_count++;
post_sgl->params.request.pages[i].\
sgl_page0.addrLow =
- PADDR_LO(xrip->SGList.phys);
+ PADDR_LO(xrip->SGList->phys);
post_sgl->params.request.pages[i].\
sgl_page0.addrHigh =
- PADDR_HI(xrip->SGList.phys);
+ PADDR_HI(xrip->SGList->phys);
cnt--;
xrip++;
}
@@ -8670,11 +8756,204 @@
return;
} /* emlxs_sli4_timer_check_mbox() */
+static void
+emlxs_sli4_gpio_timer_start(emlxs_hba_t *hba)
+{
+ mutex_enter(&hba->gpio_lock);
+ if (!hba->gpio_timer) {
+ hba->gpio_timer = timeout(emlxs_sli4_gpio_timer, (void *)hba,
+ drv_usectohz(100000));
+ }
+
+ mutex_exit(&hba->gpio_lock);
+
+} /* emlxs_sli4_gpio_timer_start() */
+
+static void
+emlxs_sli4_gpio_timer_stop(emlxs_hba_t *hba)
+{
+ mutex_enter(&hba->gpio_lock);
+
+ if (hba->gpio_timer) {
+ (void) untimeout(hba->gpio_timer);
+ hba->gpio_timer = 0;
+ }
+
+ mutex_exit(&hba->gpio_lock);
+
+ delay(drv_usectohz(300000));
+} /* emlxs_sli4_gpio_timer_stop() */
+
+static void
+emlxs_sli4_gpio_timer(void *arg)
+{
+ emlxs_hba_t *hba = (emlxs_hba_t *)arg;
+
+ mutex_enter(&hba->gpio_lock);
+
+ if (hba->gpio_timer) {
+ emlxs_sli4_check_gpio(hba);
+ hba->gpio_timer = timeout(emlxs_sli4_gpio_timer, (void *)hba,
+ drv_usectohz(100000));
+ }
+
+ mutex_exit(&hba->gpio_lock);
+} /* emlxs_sli4_gpio_timer() */
+
+static void
+emlxs_sli4_check_gpio(emlxs_hba_t *hba)
+{
+ hba->gpio_desired = 0;
+
+ if (hba->flag & FC_GPIO_LINK_UP) {
+ if (hba->io_active)
+ hba->gpio_desired |= EMLXS_GPIO_ACT;
+
+ /* This is model specific to ATTO gen5 lancer cards */
+
+ switch (hba->linkspeed) {
+ case LA_4GHZ_LINK:
+ hba->gpio_desired |= EMLXS_GPIO_LO;
+ break;
+
+ case LA_8GHZ_LINK:
+ hba->gpio_desired |= EMLXS_GPIO_HI;
+ break;
+
+ case LA_16GHZ_LINK:
+ hba->gpio_desired |=
+ EMLXS_GPIO_LO | EMLXS_GPIO_HI;
+ break;
+ }
+ }
+
+ if (hba->gpio_current != hba->gpio_desired) {
+ emlxs_port_t *port = &PPORT;
+ uint8_t pin;
+ uint8_t pinval;
+ MAILBOXQ *mbq;
+ uint32_t rval;
+
+ if (!emlxs_sli4_fix_gpio(hba, &pin, &pinval))
+ return;
+
+ if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX)) == NULL) {
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
+ "Unable to allocate GPIO mailbox.");
+
+ hba->gpio_bit = 0;
+ return;
+ }
+
+ emlxs_mb_gpio_write(hba, mbq, pin, pinval);
+ mbq->mbox_cmpl = emlxs_sli4_fix_gpio_mbcmpl;
+
+ rval = emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_NOWAIT, 0);
+
+ if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
+ "Unable to start GPIO mailbox.");
+
+ hba->gpio_bit = 0;
+ emlxs_mem_put(hba, MEM_MBOX, mbq);
+ return;
+ }
+ }
+} /* emlxs_sli4_check_gpio */
+
+static uint32_t
+emlxs_sli4_fix_gpio(emlxs_hba_t *hba, uint8_t *pin, uint8_t *pinval)
+{
+ uint8_t dif = hba->gpio_desired ^ hba->gpio_current;
+ uint8_t bit;
+ uint8_t i;
+
+ /* Get out if no pins to set a GPIO request is pending */
+
+ if (dif == 0 || hba->gpio_bit)
+ return (0);
+
+ /* Fix one pin at a time */
+
+ bit = dif & -dif;
+ hba->gpio_bit = bit;
+ dif = hba->gpio_current ^ bit;
+
+ for (i = EMLXS_GPIO_PIN_LO; bit > 1; ++i) {
+ dif >>= 1;
+ bit >>= 1;
+ }
+
+ /* Pins are active low so invert the bit value */
+
+ *pin = hba->gpio_pin[i];
+ *pinval = ~dif & bit;
+
+ return (1);
+} /* emlxs_sli4_fix_gpio */
+
+static uint32_t
+emlxs_sli4_fix_gpio_mbcmpl(emlxs_hba_t *hba, MAILBOXQ *mbq)
+{
+ MAILBOX *mb;
+ uint8_t pin;
+ uint8_t pinval;
+
+ mb = (MAILBOX *)mbq;
+
+ mutex_enter(&hba->gpio_lock);
+
+ if (mb->mbxStatus == 0)
+ hba->gpio_current ^= hba->gpio_bit;
+
+ hba->gpio_bit = 0;
+
+ if (emlxs_sli4_fix_gpio(hba, &pin, &pinval)) {
+ emlxs_port_t *port = &PPORT;
+ MAILBOXQ *mbq;
+ uint32_t rval;
+
+ /*
+ * We're not using the mb_retry routine here because for some
+ * reason it doesn't preserve the completion routine. Just let
+ * this mbox cmd fail to start here and run when the mailbox
+ * is no longer busy.
+ */
+
+ if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX)) == NULL) {
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
+ "Unable to allocate GPIO mailbox.");
+
+ hba->gpio_bit = 0;
+ goto done;
+ }
+
+ emlxs_mb_gpio_write(hba, mbq, pin, pinval);
+ mbq->mbox_cmpl = emlxs_sli4_fix_gpio_mbcmpl;
+
+ rval = emlxs_sli4_issue_mbox_cmd(hba, mbq, MBX_NOWAIT, 0);
+
+ if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
+ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
+ "Unable to start GPIO mailbox.");
+
+ hba->gpio_bit = 0;
+ emlxs_mem_put(hba, MEM_MBOX, mbq);
+ goto done;
+ }
+ }
+
+done:
+ mutex_exit(&hba->gpio_lock);
+
+ return (0);
+}
+
extern void
emlxs_data_dump(emlxs_port_t *port, char *str, uint32_t *iptr, int cnt, int err)
{
void *msg;
@@ -9111,10 +9390,13 @@
hba->linkspeed = LA_10GHZ_LINK;
break;
case 16:
hba->linkspeed = LA_16GHZ_LINK;
break;
+ case 32:
+ hba->linkspeed = LA_32GHZ_LINK;
+ break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"sli4_handle_fc_link_att: Unknown link speed=%x.",
cqe->un.fc.port_speed);
hba->linkspeed = 0;