aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/qlxgb
diff options
context:
space:
mode:
authorDavid C Somayajulu <davidcs@FreeBSD.org>2013-05-07 22:58:42 +0000
committerDavid C Somayajulu <davidcs@FreeBSD.org>2013-05-07 22:58:42 +0000
commit088fc97186dc243619d00071b352f3f516df747d (patch)
tree1d3855d723c99fe1c47b6d371ae2d72b5d7491ea /sys/dev/qlxgb
parent16e073e57aca2b42740e75d661eb89fd7a0c4ab3 (diff)
downloadsrc-088fc97186dc243619d00071b352f3f516df747d.tar.gz
src-088fc97186dc243619d00071b352f3f516df747d.zip
1. Updated Copyright Information
2. Added Flash Read/Update Support 3. Fixed TSO Handling Submitted by: David C Somayajulu (davidcs@freebsd.org) Reviewed by: George Neville-Neil (gnn@freebsd.org) Approved by: George Neville-Neil (gnn@freebsd.org)
Notes
Notes: svn path=/head/; revision=250340
Diffstat (limited to 'sys/dev/qlxgb')
-rw-r--r--sys/dev/qlxgb/README.txt2
-rw-r--r--sys/dev/qlxgb/qla_dbg.c2
-rw-r--r--sys/dev/qlxgb/qla_dbg.h2
-rw-r--r--sys/dev/qlxgb/qla_def.h4
-rw-r--r--sys/dev/qlxgb/qla_glbl.h18
-rw-r--r--sys/dev/qlxgb/qla_hw.c124
-rw-r--r--sys/dev/qlxgb/qla_hw.h6
-rw-r--r--sys/dev/qlxgb/qla_inline.h2
-rw-r--r--sys/dev/qlxgb/qla_ioctl.c31
-rw-r--r--sys/dev/qlxgb/qla_ioctl.h39
-rw-r--r--sys/dev/qlxgb/qla_isr.c2
-rw-r--r--sys/dev/qlxgb/qla_misc.c430
-rw-r--r--sys/dev/qlxgb/qla_os.c12
-rw-r--r--sys/dev/qlxgb/qla_os.h2
-rw-r--r--sys/dev/qlxgb/qla_reg.h6
-rw-r--r--sys/dev/qlxgb/qla_ver.h4
16 files changed, 631 insertions, 55 deletions
diff --git a/sys/dev/qlxgb/README.txt b/sys/dev/qlxgb/README.txt
index d9773ccbd9b5..bd95f8bca623 100644
--- a/sys/dev/qlxgb/README.txt
+++ b/sys/dev/qlxgb/README.txt
@@ -93,7 +93,7 @@ Technical Support at any phase of integration for assistance. QLogic
Technical Support can be reached by the following methods:
Web: http://support.qlogic.com
E-mail: support@qlogic.com
-(c) Copyright 2011. All rights reserved worldwide. QLogic, the QLogic
+(c) Copyright 2013. All rights reserved worldwide. QLogic, the QLogic
logo, and the Powered by QLogic logo are registered trademarks of
QLogic Corporation. All other brand and product names are trademarks
or registered trademarks of their respective owners.
diff --git a/sys/dev/qlxgb/qla_dbg.c b/sys/dev/qlxgb/qla_dbg.c
index 5fc6f461e72c..bdbe8687f956 100644
--- a/sys/dev/qlxgb/qla_dbg.c
+++ b/sys/dev/qlxgb/qla_dbg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/qlxgb/qla_dbg.h b/sys/dev/qlxgb/qla_dbg.h
index 1f0d184cf013..893b13f7fdae 100644
--- a/sys/dev/qlxgb/qla_dbg.h
+++ b/sys/dev/qlxgb/qla_dbg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/qlxgb/qla_def.h b/sys/dev/qlxgb/qla_def.h
index d40d5e2af2bb..534f00266419 100644
--- a/sys/dev/qlxgb/qla_def.h
+++ b/sys/dev/qlxgb/qla_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -194,6 +194,8 @@ struct qla_host {
/* debug stuff */
volatile const char *qla_lock;
volatile const char *qla_unlock;
+
+ uint8_t fw_ver_str[32];
};
typedef struct qla_host qla_host_t;
diff --git a/sys/dev/qlxgb/qla_glbl.h b/sys/dev/qlxgb/qla_glbl.h
index 21ee99c3cc2d..9f045839313c 100644
--- a/sys/dev/qlxgb/qla_glbl.h
+++ b/sys/dev/qlxgb/qla_glbl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -56,14 +56,6 @@ extern void qla_start(struct ifnet *ifp);
extern int qla_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp,
uint32_t jumbo);
-
-/*
- * from qla_flash.c
- */
-extern int qla_flash_rd32_words(qla_host_t *ha, uint32_t addr,
- uint32_t *val, uint32_t num);
-extern int qla_flash_rd32(qla_host_t *ha, uint32_t addr, uint32_t *val);
-
/*
* from qla_hw.c
*/
@@ -97,6 +89,14 @@ extern int qla_init_hw(qla_host_t *ha);
extern int qla_rdwr_indreg32(qla_host_t *ha, uint32_t addr, uint32_t *val,
uint32_t rd);
extern int qla_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data);
+extern int qla_flash_rd32_words(qla_host_t *ha, uint32_t addr,
+ uint32_t *val, uint32_t num);
+extern int qla_flash_rd32(qla_host_t *ha, uint32_t addr, uint32_t *val);
+extern int qla_fw_update(qla_host_t *ha, void *fdata, uint32_t off,
+ uint32_t size);
+extern int qla_erase_flash(qla_host_t *ha, uint32_t off, uint32_t size);
+extern int qla_wr_flash_buffer(qla_host_t *ha, uint32_t off, uint32_t size,
+ void *buf, uint32_t pattern);
/*
* from qla_ioctl.c
diff --git a/sys/dev/qlxgb/qla_hw.c b/sys/dev/qlxgb/qla_hw.c
index 477eb5720eac..c866cf5824d4 100644
--- a/sys/dev/qlxgb/qla_hw.c
+++ b/sys/dev/qlxgb/qla_hw.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2012 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -711,20 +711,18 @@ qla_config_ipv4_addr(qla_host_t *ha, uint32_t ipv4_addr)
* Ring Structure are plugged in.
*/
static int
-qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd)
+qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd, uint8_t *hdr)
{
struct ether_vlan_header *eh;
struct ip *ip = NULL;
struct tcphdr *th = NULL;
- uint32_t ehdrlen, hdrlen, ip_hlen, tcp_hlen;
+ uint32_t ehdrlen, hdrlen = 0, ip_hlen, tcp_hlen, tcp_opt_off;
uint16_t etype, opcode, offload = 1;
+ uint8_t *tcp_opt;
device_t dev;
dev = ha->pci_dev;
- if (mp->m_pkthdr.len <= ha->max_frame_size)
- return (-1);
-
eh = mtod(mp, struct ether_vlan_header *);
if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
@@ -737,14 +735,26 @@ qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd)
switch (etype) {
case ETHERTYPE_IP:
- ip = (struct ip *)(mp->m_data + ehdrlen);
+
+ tcp_opt_off = ehdrlen + sizeof(struct ip) +
+ sizeof(struct tcphdr);
+
+ if (mp->m_len < tcp_opt_off) {
+ m_copydata(mp, 0, tcp_opt_off, hdr);
+ ip = (struct ip *)hdr;
+ } else {
+ ip = (struct ip *)(mp->m_data + ehdrlen);
+ }
+
ip_hlen = ip->ip_hl << 2;
opcode = Q8_TX_CMD_OP_XMT_TCP_LSO;
- if (ip->ip_p != IPPROTO_TCP) {
+ if ((ip->ip_p != IPPROTO_TCP) ||
+ (ip_hlen != sizeof (struct ip))) {
offload = 0;
- } else
+ } else {
th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
+ }
break;
default:
@@ -758,11 +768,43 @@ qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd)
tcp_hlen = th->th_off << 2;
+
hdrlen = ehdrlen + ip_hlen + tcp_hlen;
if (mp->m_len < hdrlen) {
- device_printf(dev, "%s: (mp->m_len < hdrlen)\n", __func__);
- return (-1);
+ if (mp->m_len < tcp_opt_off) {
+ if (tcp_hlen > sizeof(struct tcphdr)) {
+ m_copydata(mp, tcp_opt_off,
+ (tcp_hlen - sizeof(struct tcphdr)),
+ &hdr[tcp_opt_off]);
+ }
+ } else {
+ m_copydata(mp, 0, hdrlen, hdr);
+ }
+ }
+
+ if ((mp->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
+
+ /* If TCP options are preset only time stamp option is supported */
+ if ((tcp_hlen - sizeof(struct tcphdr)) != 10)
+ return -1;
+ else {
+
+ if (mp->m_len < hdrlen) {
+ tcp_opt = &hdr[tcp_opt_off];
+ } else {
+ tcp_opt = (uint8_t *)(mp->m_data + tcp_opt_off);
+ }
+
+ if ((*tcp_opt != 0x01) || (*(tcp_opt + 1) != 0x01) ||
+ (*(tcp_opt + 2) != 0x08) || (*(tcp_opt + 2) != 10)) {
+ return -1;
+ }
+ }
+
+ tx_cmd->mss = ha->max_frame_size - ETHER_CRC_LEN - hdrlen;
+ } else {
+ tx_cmd->mss = mp->m_pkthdr.tso_segsz;
}
tx_cmd->flags_opcode = opcode ;
@@ -776,6 +818,10 @@ qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd)
tx_cmd->flags_opcode = Q8_TX_CMD_FLAGS_MULTICAST;
}
+ if (mp->m_len < hdrlen) {
+ return (1);
+ }
+
return (0);
}
@@ -815,7 +861,7 @@ qla_tx_chksum(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd)
case ETHERTYPE_IP:
ip = (struct ip *)(mp->m_data + ehdrlen);
- ip_hlen = ip->ip_hl << 2;
+ ip_hlen = sizeof (struct ip);
if (mp->m_len < (ehdrlen + ip_hlen)) {
device_printf(dev, "%s: ipv4 mlen\n", __func__);
@@ -886,7 +932,8 @@ qla_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
uint32_t num_tx_cmds, hdr_len = 0;
uint32_t total_length = 0, bytes, tx_cmd_count = 0;
device_t dev;
- int i;
+ int i, ret;
+ uint8_t *src = NULL, *dst = NULL;
dev = ha->pci_dev;
@@ -902,26 +949,36 @@ qla_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
__func__, total_length);
return (-1);
}
+ eh = mtod(mp, struct ether_vlan_header *);
- bzero((void *)&tso_cmd, sizeof(q80_tx_cmd_t));
+ if ((mp->m_pkthdr.len > ha->max_frame_size)||(nsegs > Q8_TX_MAX_SEGMENTS)) {
- if (qla_tx_tso(ha, mp, &tso_cmd) == 0) {
- /* find the additional tx_cmd descriptors required */
+ bzero((void *)&tso_cmd, sizeof(q80_tx_cmd_t));
- hdr_len = tso_cmd.total_hdr_len;
+ src = ha->hw.frame_hdr;
+ ret = qla_tx_tso(ha, mp, &tso_cmd, src);
- bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
- bytes = QL_MIN(bytes, hdr_len);
+ if (!(ret & ~1)) {
+ /* find the additional tx_cmd descriptors required */
- num_tx_cmds++;
- hdr_len -= bytes;
+ hdr_len = tso_cmd.total_hdr_len;
- while (hdr_len) {
- bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
- hdr_len -= bytes;
+ bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
+ bytes = QL_MIN(bytes, hdr_len);
+
num_tx_cmds++;
+ hdr_len -= bytes;
+
+ while (hdr_len) {
+ bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
+ hdr_len -= bytes;
+ num_tx_cmds++;
+ }
+ hdr_len = tso_cmd.total_hdr_len;
+
+ if (ret == 0)
+ src = (uint8_t *)eh;
}
- hdr_len = tso_cmd.total_hdr_len;
}
if (hw->txr_free <= (num_tx_cmds + QLA_TX_MIN_FREE)) {
@@ -957,7 +1014,6 @@ qla_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
bcopy(&tso_cmd, tx_cmd, sizeof(q80_tx_cmd_t));
}
- eh = mtod(mp, struct ether_vlan_header *);
if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN))
tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_VLAN_TAGGED;
else if (mp->m_flags & M_VLANTAG) {
@@ -1015,9 +1071,6 @@ qla_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
if (hdr_len) {
/* TSO : Copy the header in the following tx cmd descriptors */
- uint8_t *src, *dst;
-
- src = (uint8_t *)eh;
tx_cmd = &hw->tx_ring_base[hw->txr_next];
bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
@@ -1704,6 +1757,7 @@ void
qla_update_link_state(qla_host_t *ha)
{
uint32_t link_state;
+ uint32_t prev_link_state;
if (!(ha->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
ha->hw.flags.link_up = 0;
@@ -1711,10 +1765,20 @@ qla_update_link_state(qla_host_t *ha)
}
link_state = READ_REG32(ha, Q8_LINK_STATE);
- if (ha->pci_func == 0)
+ prev_link_state = ha->hw.flags.link_up;
+
+ if (ha->pci_func == 0)
ha->hw.flags.link_up = (((link_state & 0xF) == 1)? 1 : 0);
else
ha->hw.flags.link_up = ((((link_state >> 4)& 0xF) == 1)? 1 : 0);
+
+ if (prev_link_state != ha->hw.flags.link_up) {
+ if (ha->hw.flags.link_up) {
+ if_link_state_change(ha->ifp, LINK_STATE_UP);
+ } else {
+ if_link_state_change(ha->ifp, LINK_STATE_DOWN);
+ }
+ }
}
int
diff --git a/sys/dev/qlxgb/qla_hw.h b/sys/dev/qlxgb/qla_hw.h
index 46780be9b2e9..57012dddbc72 100644
--- a/sys/dev/qlxgb/qla_hw.h
+++ b/sys/dev/qlxgb/qla_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -724,6 +724,8 @@ typedef struct _qla_sds {
volatile uint32_t rcv_active;
} qla_sds_t;
+#define QL_FRAME_HDR_SIZE (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +\
+ sizeof (struct ip) + sizeof (struct tcphdr) + 16)
/*
* struct for storing hardware specific information for a given interface
*/
@@ -791,6 +793,8 @@ typedef struct _qla_hw {
bus_addr_t rx_cntxt_rsp_paddr;
qla_sds_t sds[MAX_SDS_RINGS];
+
+ uint8_t frame_hdr[QL_FRAME_HDR_SIZE];
} qla_hw_t;
#define QL_UPDATE_RDS_PRODUCER_INDEX(ha, i, val) \
diff --git a/sys/dev/qlxgb/qla_inline.h b/sys/dev/qlxgb/qla_inline.h
index 6a6be5f98a47..1f8bf6f51ee8 100644
--- a/sys/dev/qlxgb/qla_inline.h
+++ b/sys/dev/qlxgb/qla_inline.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/qlxgb/qla_ioctl.c b/sys/dev/qlxgb/qla_ioctl.c
index 1e9557ab4e94..5afb1a477e16 100644
--- a/sys/dev/qlxgb/qla_ioctl.c
+++ b/sys/dev/qlxgb/qla_ioctl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -82,10 +82,15 @@ qla_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
int rval = 0;
qla_reg_val_t *rv;
qla_rd_flash_t *rdf;
+ qla_wr_flash_t *wrf;
+ qla_rd_pci_ids_t *pci_ids;
+ device_t pci_dev;
if ((ha = (qla_host_t *)dev->si_drv1) == NULL)
return ENXIO;
+ pci_dev= ha->pci_dev;
+
switch(cmd) {
case QLA_RDWR_REG:
@@ -110,6 +115,30 @@ qla_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
if ((rval = qla_rd_flash32(ha, rdf->off, &rdf->data)))
rval = ENXIO;
break;
+
+ case QLA_WR_FLASH:
+ wrf = (qla_wr_flash_t *)data;
+ if ((rval = qla_wr_flash_buffer(ha, wrf->off, wrf->size,
+ wrf->buffer, wrf->pattern)))
+ rval = ENXIO;
+ break;
+
+
+ case QLA_ERASE_FLASH:
+ if (qla_erase_flash(ha, ((qla_erase_flash_t *)data)->off,
+ ((qla_erase_flash_t *)data)->size))
+ rval = ENXIO;
+ break;
+
+ case QLA_RD_PCI_IDS:
+ pci_ids = (qla_rd_pci_ids_t *)data;
+ pci_ids->ven_id = pci_get_vendor(pci_dev);
+ pci_ids->dev_id = pci_get_device(pci_dev);
+ pci_ids->subsys_ven_id = pci_get_subvendor(pci_dev);
+ pci_ids->subsys_dev_id = pci_get_subdevice(pci_dev);
+ pci_ids->rev_id = pci_read_config(pci_dev, PCIR_REVID, 1);
+ break;
+
default:
break;
}
diff --git a/sys/dev/qlxgb/qla_ioctl.h b/sys/dev/qlxgb/qla_ioctl.h
index 160c46c50db0..4f100518d0e8 100644
--- a/sys/dev/qlxgb/qla_ioctl.h
+++ b/sys/dev/qlxgb/qla_ioctl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,28 @@ struct qla_rd_flash {
};
typedef struct qla_rd_flash qla_rd_flash_t;
+struct qla_wr_flash {
+ uint32_t off;
+ uint32_t size;
+ void *buffer;
+ uint32_t pattern;
+};
+typedef struct qla_wr_flash qla_wr_flash_t;
+
+struct qla_erase_flash {
+ uint32_t off;
+ uint32_t size;
+};
+typedef struct qla_erase_flash qla_erase_flash_t;
+
+struct qla_rd_pci_ids {
+ uint16_t ven_id;
+ uint16_t dev_id;
+ uint16_t subsys_ven_id;
+ uint16_t subsys_dev_id;
+ uint8_t rev_id;
+};
+typedef struct qla_rd_pci_ids qla_rd_pci_ids_t;
/*
* Read/Write Register
@@ -61,4 +83,19 @@ typedef struct qla_rd_flash qla_rd_flash_t;
*/
#define QLA_RD_FLASH _IOWR('q', 2, qla_rd_flash_t)
+/*
+ * Write Flash
+ */
+#define QLA_WR_FLASH _IOWR('q', 3, qla_wr_flash_t)
+
+/*
+ * Erase Flash
+ */
+#define QLA_ERASE_FLASH _IOWR('q', 5, qla_erase_flash_t)
+
+/*
+ * Read PCI IDs
+ */
+#define QLA_RD_PCI_IDS _IOWR('q', 6, qla_rd_pci_ids_t)
+
#endif /* #ifndef _QLA_IOCTL_H_ */
diff --git a/sys/dev/qlxgb/qla_isr.c b/sys/dev/qlxgb/qla_isr.c
index 382d565acedd..3169fd16a152 100644
--- a/sys/dev/qlxgb/qla_isr.c
+++ b/sys/dev/qlxgb/qla_isr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/qlxgb/qla_misc.c b/sys/dev/qlxgb/qla_misc.c
index fd86e2ab6cd2..afed7a1a4985 100644
--- a/sys/dev/qlxgb/qla_misc.c
+++ b/sys/dev/qlxgb/qla_misc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -344,6 +344,17 @@ qla_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data)
return 0;
}
+static int
+qla_p3p_sem_lock2(qla_host_t *ha)
+{
+ if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) {
+ device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__);
+ return (-1);
+ }
+ WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5);
+ return (0);
+}
+
/*
* Name: qla_int_to_pci_addr_map
* Function: Convert's Internal(CRB) Address to Indirect Address
@@ -402,7 +413,7 @@ qla_filter_pci_addr(qla_host_t *ha, uint32_t addr)
static int
qla_crb_init(qla_host_t *ha)
{
- uint32_t val, sig;
+ uint32_t val = 0, sig = 0;
uint32_t offset, count, i;
addr_val_t *addr_val_map, *avmap;
@@ -611,6 +622,21 @@ qla_init_hw(qla_host_t *ha)
if (val != CMDPEG_PHAN_INIT_COMPLETE) {
ret = qla_init_from_flash(ha);
qla_mdelay(__func__, 100);
+ } else {
+ ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR);
+ ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR);
+ ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB);
+
+ if (qla_rd_flash32(ha, 0x100004, &val) == 0) {
+
+ if (((val & 0xFF) != ha->fw_ver_major) ||
+ (((val >> 8) & 0xFF) != ha->fw_ver_minor) ||
+ (((val >> 16) & 0xFF) != ha->fw_ver_sub)) {
+
+ ret = qla_init_from_flash(ha);
+ qla_mdelay(__func__, 100);
+ }
+ }
}
qla_init_exit:
@@ -622,3 +648,403 @@ qla_init_exit:
return (ret);
}
+static int
+qla_wait_for_flash_busy(qla_host_t *ha)
+{
+ uint32_t count = 100;
+ uint32_t val;
+
+ QLA_USEC_DELAY(100);
+
+ while (count--) {
+ val = READ_OFFSET32(ha, Q8_ROM_STATUS);
+
+ if (val & BIT_1)
+ return 0;
+ qla_mdelay(__func__, 1);
+ }
+ return -1;
+}
+
+static int
+qla_flash_write_enable(qla_host_t *ha)
+{
+ uint32_t val, rval;
+
+ val = 0;
+ qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
+
+ val = ROM_OPCODE_WR_ENABLE;
+ qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
+
+ rval = qla_wait_for_flash_busy(ha);
+
+ if (rval)
+ device_printf(ha->pci_dev, "%s: failed \n", __func__);
+
+ return (rval);
+}
+
+static int
+qla_flash_unprotect(qla_host_t *ha)
+{
+ uint32_t val, rval;
+
+ if (qla_flash_write_enable(ha) != 0)
+ return(-1);
+
+ val = 0;
+ qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
+
+ val = ROM_OPCODE_WR_STATUS_REG;
+ qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
+
+ rval = qla_wait_for_flash_busy(ha);
+
+ if (rval) {
+ device_printf(ha->pci_dev, "%s: failed \n", __func__);
+ return rval;
+ }
+
+ if (qla_flash_write_enable(ha) != 0)
+ return(-1);
+
+ val = 0;
+ qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
+
+ val = ROM_OPCODE_WR_STATUS_REG;
+ qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
+
+ rval = qla_wait_for_flash_busy(ha);
+
+ if (rval)
+ device_printf(ha->pci_dev, "%s: failed \n", __func__);
+
+ return rval;
+}
+
+static int
+qla_flash_protect(qla_host_t *ha)
+{
+ uint32_t val, rval;
+
+ if (qla_flash_write_enable(ha) != 0)
+ return(-1);
+
+ val = 0x9C;
+ qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
+
+ val = ROM_OPCODE_WR_STATUS_REG;
+ qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
+
+ rval = qla_wait_for_flash_busy(ha);
+
+ if (rval)
+ device_printf(ha->pci_dev, "%s: failed \n", __func__);
+
+ return rval;
+}
+
+static uint32_t
+qla_flash_get_status(qla_host_t *ha)
+{
+ uint32_t count = 1000;
+ uint32_t val, rval;
+
+ while (count--) {
+ val = 0;
+ qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
+
+ val = ROM_OPCODE_RD_STATUS_REG;
+ qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
+
+ rval = qla_wait_for_flash_busy(ha);
+
+ if (rval == 0) {
+ qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, &val, 1);
+
+ if ((val & BIT_0) == 0)
+ return (val);
+ }
+ qla_mdelay(__func__, 1);
+ }
+ return -1;
+}
+
+static int
+qla_wait_for_flash_unprotect(qla_host_t *ha)
+{
+ uint32_t delay = 1000;
+
+ while (delay--) {
+
+ if (qla_flash_get_status(ha) == 0)
+ return 0;
+
+ qla_mdelay(__func__, 1);
+ }
+
+ return -1;
+}
+
+static int
+qla_wait_for_flash_protect(qla_host_t *ha)
+{
+ uint32_t delay = 1000;
+
+ while (delay--) {
+
+ if (qla_flash_get_status(ha) == 0x9C)
+ return 0;
+
+ qla_mdelay(__func__, 1);
+ }
+
+ return -1;
+}
+
+static int
+qla_erase_flash_sector(qla_host_t *ha, uint32_t start)
+{
+ uint32_t val;
+ int rval;
+
+ if (qla_flash_write_enable(ha) != 0)
+ return(-1);
+
+ val = start;
+ qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
+
+ val = 3;
+ qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
+
+ val = ROM_OPCODE_SECTOR_ERASE;
+ qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
+
+ rval = qla_wait_for_flash_busy(ha);
+
+ if (rval)
+ device_printf(ha->pci_dev, "%s: failed \n", __func__);
+ return rval;
+}
+
+#define Q8_FLASH_SECTOR_SIZE 0x10000
+int
+qla_erase_flash(qla_host_t *ha, uint32_t off, uint32_t size)
+{
+ int rval = 0;
+ uint32_t start;
+
+ if (off & (Q8_FLASH_SECTOR_SIZE -1))
+ return -1;
+
+ if ((rval = qla_p3p_sem_lock2(ha)))
+ goto qla_erase_flash_exit;
+
+ if ((rval = qla_flash_unprotect(ha)))
+ goto qla_erase_flash_unlock_exit;
+
+ if ((rval = qla_wait_for_flash_unprotect(ha)))
+ goto qla_erase_flash_unlock_exit;
+
+ for (start = off; start < (off + size); start = start + 0x10000) {
+ if (qla_erase_flash_sector(ha, start)) {
+ rval = -1;
+ break;
+ }
+ }
+
+ rval = qla_flash_protect(ha);
+
+qla_erase_flash_unlock_exit:
+ qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
+
+qla_erase_flash_exit:
+ return (rval);
+}
+
+static int
+qla_flash_write32(qla_host_t *ha, uint32_t off, uint32_t data)
+{
+ uint32_t val;
+ int rval = 0;
+
+ val = data;
+ qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
+
+ val = off;
+ qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
+
+ val = 3;
+ qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
+
+ val = ROM_OPCODE_PROG_PAGE;
+ qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
+
+ rval = qla_wait_for_flash_busy(ha);
+
+ if (rval)
+ device_printf(ha->pci_dev, "%s: failed \n", __func__);
+
+ return rval;
+}
+
+static int
+qla_flash_wait_for_write_complete(qla_host_t *ha)
+{
+ uint32_t val, count = 1000;
+ int rval = 0;
+
+ while (count--) {
+
+ val = 0;
+ qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
+
+ val = ROM_OPCODE_RD_STATUS_REG;
+ qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
+
+
+ rval = qla_wait_for_flash_busy(ha);
+
+ if (rval == 0) {
+ qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, &val, 1);
+
+ if ((val & BIT_0) == 0)
+ return (0);
+ }
+ qla_mdelay(__func__, 1);
+ }
+ return -1;
+}
+
+static int
+qla_flash_write(qla_host_t *ha, uint32_t off, uint32_t data)
+{
+ if (qla_flash_write_enable(ha) != 0)
+ return(-1);
+
+ if (qla_flash_write32(ha, off, data) != 0)
+ return -1;
+
+ if (qla_flash_wait_for_write_complete(ha))
+ return -1;
+
+ return 0;
+}
+
+
+static int
+qla_flash_write_pattern(qla_host_t *ha, uint32_t off, uint32_t size,
+ uint32_t pattern)
+{
+ int rval = 0;
+ uint32_t start;
+
+
+ if ((rval = qla_p3p_sem_lock2(ha)))
+ goto qla_wr_pattern_exit;
+
+ if ((rval = qla_flash_unprotect(ha)))
+ goto qla_wr_pattern_unlock_exit;
+
+ if ((rval = qla_wait_for_flash_unprotect(ha)))
+ goto qla_wr_pattern_unlock_exit;
+
+ for (start = off; start < (off + size); start = start + 4) {
+ if (qla_flash_write(ha, start, pattern)) {
+ rval = -1;
+ break;
+ }
+ }
+
+ rval = qla_flash_protect(ha);
+
+ if (rval == 0)
+ rval = qla_wait_for_flash_protect(ha);
+
+qla_wr_pattern_unlock_exit:
+ qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
+
+qla_wr_pattern_exit:
+ return (rval);
+}
+
+static int
+qla_flash_write_data(qla_host_t *ha, uint32_t off, uint32_t size,
+ void *data)
+{
+ int rval = 0;
+ uint32_t start;
+ uint32_t *data32 = data;
+
+
+ if ((rval = qla_p3p_sem_lock2(ha)))
+ goto qla_wr_pattern_exit;
+
+ if ((rval = qla_flash_unprotect(ha)))
+ goto qla_wr_pattern_unlock_exit;
+
+ if ((rval = qla_wait_for_flash_unprotect(ha)))
+ goto qla_wr_pattern_unlock_exit;
+
+ for (start = off; start < (off + size); start = start + 4) {
+
+ if (*data32 != 0xFFFFFFFF) {
+ if (qla_flash_write(ha, start, *data32)) {
+ rval = -1;
+ break;
+ }
+ }
+ data32++;
+ }
+
+ rval = qla_flash_protect(ha);
+
+ if (rval == 0)
+ rval = qla_wait_for_flash_protect(ha);
+
+qla_wr_pattern_unlock_exit:
+ qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
+
+qla_wr_pattern_exit:
+ return (rval);
+}
+
+int
+qla_wr_flash_buffer(qla_host_t *ha, uint32_t off, uint32_t size, void *buf,
+ uint32_t pattern)
+{
+ int rval = 0;
+ void *data;
+
+
+ if (size == 0)
+ return 0;
+
+ size = size << 2;
+
+ if (buf == NULL) {
+ rval = qla_flash_write_pattern(ha, off, size, pattern);
+ return (rval);
+ }
+
+ if ((data = malloc(size, M_QLA8XXXBUF, M_NOWAIT)) == NULL) {
+ device_printf(ha->pci_dev, "%s: malloc failed \n", __func__);
+ rval = -1;
+ goto qla_wr_flash_buffer_exit;
+ }
+
+ if ((rval = copyin(buf, data, size))) {
+ device_printf(ha->pci_dev, "%s copyin failed\n", __func__);
+ goto qla_wr_flash_buffer_free_exit;
+ }
+
+ rval = qla_flash_write_data(ha, off, size, data);
+
+qla_wr_flash_buffer_free_exit:
+ free(data, M_QLA8XXXBUF);
+
+qla_wr_flash_buffer_exit:
+ return (rval);
+}
+
diff --git a/sys/dev/qlxgb/qla_os.c b/sys/dev/qlxgb/qla_os.c
index b22fa9fc7d7d..7f622e3114a6 100644
--- a/sys/dev/qlxgb/qla_os.c
+++ b/sys/dev/qlxgb/qla_os.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -154,6 +154,11 @@ qla_add_sysctls(qla_host_t *ha)
(void *)ha, 0,
qla_sysctl_get_stats, "I", "Statistics");
+ SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+ OID_AUTO, "fw_version", CTLFLAG_RD,
+ &ha->fw_ver_str, 0, "firmware version");
+
dbg_level = 0;
SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
@@ -347,6 +352,10 @@ qla_pci_attach(device_t dev)
ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub,
ha->fw_ver_build);
+ snprintf(ha->fw_ver_str, sizeof(ha->fw_ver_str), "%d.%d.%d.%d",
+ ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub,
+ ha->fw_ver_build);
+
//qla_get_hw_caps(ha);
qla_read_mac_addr(ha);
@@ -660,6 +669,7 @@ qla_init_ifnet(device_t dev, qla_host_t *ha)
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_mtu = ETHERMTU;
ifp->if_baudrate = (1 * 1000 * 1000 *1000);
ifp->if_init = qla_init;
ifp->if_softc = ha;
diff --git a/sys/dev/qlxgb/qla_os.h b/sys/dev/qlxgb/qla_os.h
index 955be5d24be1..a2f4343cbeee 100644
--- a/sys/dev/qlxgb/qla_os.h
+++ b/sys/dev/qlxgb/qla_os.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/sys/dev/qlxgb/qla_reg.h b/sys/dev/qlxgb/qla_reg.h
index 2f190f3e26fe..0cc66b000843 100644
--- a/sys/dev/qlxgb/qla_reg.h
+++ b/sys/dev/qlxgb/qla_reg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -201,6 +201,10 @@
*/
#define Q8_ROM_RD_DATA 0x03310018
+#define Q8_ROM_WR_DATA 0x0331000C
+#define Q8_ROM_DIRECT_WINDOW 0x03310030
+#define Q8_ROM_DIRECT_DATA_OFFSET 0x03310000
+
#define Q8_NX_CDRP_CMD_RSP 0x1B2218
#define Q8_NX_CDRP_ARG1 0x1B221C
diff --git a/sys/dev/qlxgb/qla_ver.h b/sys/dev/qlxgb/qla_ver.h
index 8c33ff4535ba..e32bd496f7d2 100644
--- a/sys/dev/qlxgb/qla_ver.h
+++ b/sys/dev/qlxgb/qla_ver.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 Qlogic Corporation
+ * Copyright (c) 2011-2013 Qlogic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,6 @@
#define QLA_VERSION_MAJOR 1
#define QLA_VERSION_MINOR 1
-#define QLA_VERSION_BUILD 30
+#define QLA_VERSION_BUILD 36
#endif /* #ifndef _QLA_VER_H_ */