summaryrefslogtreecommitdiffstats
path: root/sys/dev/qlxgb
diff options
context:
space:
mode:
authordavidcs <davidcs@FreeBSD.org>2013-05-07 22:58:42 +0000
committerdavidcs <davidcs@FreeBSD.org>2013-05-07 22:58:42 +0000
commit2d772503dd0ee8db2017f6dec6126c0bcf3deafe (patch)
tree1d3855d723c99fe1c47b6d371ae2d72b5d7491ea /sys/dev/qlxgb
parente5932eeddb01068933c489eda23465fdcf8335b6 (diff)
downloadFreeBSD-src-2d772503dd0ee8db2017f6dec6126c0bcf3deafe.zip
FreeBSD-src-2d772503dd0ee8db2017f6dec6126c0bcf3deafe.tar.gz
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)
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 d9773cc..bd95f8b 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 5fc6f46..bdbe868 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 1f0d184..893b13f 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 d40d5e2..534f002 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 21ee99c..9f04583 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 477eb57..c866cf5 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 46780be..57012dd 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 6a6be5f..1f8bf6f 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 1e9557a..5afb1a4 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 160c46c..4f10051 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 382d565..3169fd1 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 fd86e2a..afed7a1 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 b22fa9f..7f622e3 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 955be5d..a2f4343 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 2f190f3..0cc66b0 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 8c33ff4..e32bd49 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_ */
OpenPOWER on IntegriCloud