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)
This commit is contained in:
David C Somayajulu 2013-05-07 22:58:42 +00:00
parent 16e073e57a
commit 088fc97186
16 changed files with 631 additions and 55 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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:
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,10 +949,16 @@ 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 *);
if ((mp->m_pkthdr.len > ha->max_frame_size)||(nsegs > Q8_TX_MAX_SEGMENTS)) {
bzero((void *)&tso_cmd, sizeof(q80_tx_cmd_t));
if (qla_tx_tso(ha, mp, &tso_cmd) == 0) {
src = ha->hw.frame_hdr;
ret = qla_tx_tso(ha, mp, &tso_cmd, src);
if (!(ret & ~1)) {
/* find the additional tx_cmd descriptors required */
hdr_len = tso_cmd.total_hdr_len;
@ -922,6 +975,10 @@ qla_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
num_tx_cmds++;
}
hdr_len = tso_cmd.total_hdr_len;
if (ret == 0)
src = (uint8_t *)eh;
}
}
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);
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

View File

@ -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) \

View File

@ -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

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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

View File

@ -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_hw(qla_host_t *ha)
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);
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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_ */