From: Marcus Barrow <mbarrow@redhat.com> Date: Wed, 20 Aug 2008 17:09:49 -0400 Subject: [scsi] qla2xxx - mgmt. API for FCoE, NetLink Message-id: 20080820210944.12317.94494.sendpatchset@file.bos.redhat.com O-Subject: [rhel 5.3 patch] [V3] qla2xxx - mgmt. API for FCoE, NetLink Bugzilla: 456900 RH-Acked-by: Mike Christie <mchristi@redhat.com> BZ 456900 qla2xxx- Netlink, FCoE management API This is version 3 of this patch. It now addresses a problem found by Dave Jones where the arguments for 2 uses of memset(0 where in the wrong order. In addition, during further testing, I found a debug printf() which executed a couple of times per hour. Support the NetLink interface for FCoE Management API. This code is currently submitted upstream. diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile index 90562c5..bcc2dfc 100644 --- a/drivers/scsi/qla2xxx/Makefile +++ b/drivers/scsi/qla2xxx/Makefile @@ -1,5 +1,6 @@ +EXTRA_CFLAGS += -DNETLINK_FCTRANSPORT=20 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ - qla_dbg.o qla_sup.o qla_attr.o qla_mid.o ql2100_fw.o \ + qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_nlnk.o ql2100_fw.o \ ql2200_fw.o ql2300_fw.o ql2322_fw.o ql2400_fw.o ql2500_fw.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index c3257d3..e446f0f 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2233,6 +2233,8 @@ struct qla_statistics { uint32_t total_isp_aborts; }; +#include "qla_nlnk.h" + /* * Linux Host Adapter structure */ @@ -2669,6 +2671,7 @@ typedef struct scsi_qla_host { int pass_thru_cmd_in_process; struct qla_chip_state_84xx *cs84xx; + struct qlfc_aen_log aen_log; struct qla_statistics qla_stats; } scsi_qla_host_t; @@ -2736,4 +2739,23 @@ typedef struct scsi_qla_host { #define CMD_ACTUAL_SNSLEN(Cmnd) ((Cmnd)->SCp.Message) #define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in) +/* + * qla2xxx_log_aen : Logs AENs. hardware_lock is assumed to be held. + */ +static inline void +qla2xxx_log_aen(scsi_qla_host_t *ha, uint16_t code, uint16_t p1, uint16_t p2, + uint16_t p3) +{ + struct qlfc_aen_entry *aen; + + if (ha->aen_log.num_events < QLFC_MAX_AEN) { + aen = &ha->aen_log.aen[ha->aen_log.num_events]; + aen->event_code = code; + aen->payload[0] = p1; + aen->payload[1] = p2; + aen->payload[2] = p3; + ha->aen_log.num_events++; + } +} + #endif diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 3106455..1da372d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -379,4 +379,10 @@ extern void qla2x00_init_host_attr(scsi_qla_host_t *); extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); +/* + * Global functions in qla_nlk.c + */ +extern int ql_nl_register(void); +extern void ql_nl_unregister(void); + #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index cef0cc1..08ad762 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -260,6 +260,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) uint8_t rscn_queue_index; unsigned long flags; + qla2xxx_log_aen(ha, mb[0], mb[1], mb[2], mb[3]); + /* Setup to process RIO completion. */ handle_cnt = 0; switch (mb[0]) { diff --git a/drivers/scsi/qla2xxx/qla_nlnk.c b/drivers/scsi/qla2xxx/qla_nlnk.c new file mode 100644 index 0000000..f65a7f0 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_nlnk.c @@ -0,0 +1,413 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2005 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ + +#include "qla_def.h" +#include <net/sock.h> +#include <net/netlink.h> +#include "qla_nlnk.h" + +static struct sock *ql_fc_nl_sock = NULL; +static int ql_fc_nl_event(struct notifier_block *this, + unsigned long event, void *ptr); + +static struct notifier_block ql_fc_nl_notifier = { + .notifier_call = ql_fc_nl_event, +}; + +static struct qlfc_aen_log aen_log; + +/* + * local functions + */ +static void ql_fc_nl_rcv_msg(struct sk_buff *skb); +static int ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, + struct nlmsghdr *nlh, int rcvlen); +static int ql_fc_nl_rsp(uint32_t pid, uint32_t seq, uint32_t type, + void *hdr, int hdr_len, void *payload, int size); + +static int qla84xx_update_fw(struct scsi_qla_host *ha, + uint32_t diag_fw, uint32_t len, uint8_t *fw_bytes) +{ + void *fw_buffer; + struct verify_chip_entry_84xx *mn; + dma_addr_t fw_dma, mn_dma; + int ret = 0; + uint32_t fw_ver; + uint16_t options; + + fw_ver = le32_to_cpu(*((uint32_t *)fw_bytes)); + if (!fw_ver) { + printk(KERN_ERR "%s(%lu): invalid fw revision 0x%x\n", + __FUNCTION__, ha->host_no, fw_ver); + return (-EINVAL); + } + + fw_buffer = dma_alloc_coherent(&ha->pdev->dev, len, &fw_dma, GFP_KERNEL); + if (fw_buffer == NULL) { + printk(KERN_ERR "%s: dma alloc for fw buffer failed%lu\n", + __FUNCTION__, ha->host_no); + return (-ENOMEM); + } + + mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); + if (mn == NULL) { + printk(KERN_ERR "%s: dma alloc for fw buffer failed%lu\n", + __FUNCTION__, ha->host_no); + ret = -ENOMEM; + goto exit_updfw; + } + + /* Copy the firmware into DMA Buffer */ + memcpy(fw_buffer, fw_bytes, len); + + /* Create iocb and issue it */ + memset(mn, 0, sizeof(*mn)); + + mn->entry_type = VERIFY_CHIP_IOCB_TYPE; + mn->entry_count = 1; + + options = VCO_FORCE_UPDATE | VCO_END_OF_DATA; + if (diag_fw) + options |= VCO_DIAG_FW; + mn->options = cpu_to_le16(options); + + mn->fw_ver = cpu_to_le32(fw_ver); + mn->fw_size = cpu_to_le32(len); + mn->fw_seq_size = cpu_to_le32(len); + + mn->dseg_address[0] = cpu_to_le32(LSD(fw_dma)); + mn->dseg_address[1] = cpu_to_le32(MSD(fw_dma)); + mn->dseg_length = cpu_to_le16(1); + + ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); + + if (ret != QLA_SUCCESS) { + printk(KERN_ERR "%s(%lu): failed\n", __func__, ha->host_no); + } + + dma_pool_free(ha->s_dma_pool, mn, mn_dma); +exit_updfw: + dma_free_coherent(&ha->pdev->dev, len, fw_buffer, fw_dma); + return ret; +} + +static int +qla84xx_mgmt_cmd(scsi_qla_host_t *ha, struct qla_fc_msg *cmd, + uint32_t pid, uint32_t seq, uint32_t type) +{ + struct access_chip_84xx *mn; + dma_addr_t mn_dma, mgmt_dma; + void *mgmt_b = NULL; + int ret = 0; + int rsp_hdr_len, len = 0; + struct qla84_msg_mgmt *ql84_mgmt; + + ql84_mgmt = &cmd->u.utok.mgmt; + rsp_hdr_len = offsetof(struct qla_fc_msg, u) + + offsetof(struct qla84_msg_mgmt, payload); + + mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); + if (mn == NULL) { + printk(KERN_ERR "%s: dma alloc for fw buffer failed%lu\n", + __FUNCTION__, ha->host_no); + return (-ENOMEM); + } + + memset(mn, 0, sizeof (*mn)); + + mn->entry_type = ACCESS_CHIP_IOCB_TYPE; + mn->entry_count = 1; + + switch (ql84_mgmt->cmd) { + case QLA84_MGMT_READ_MEM: + mn->options = cpu_to_le16(ACO_DUMP_MEMORY); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); + break; + case QLA84_MGMT_WRITE_MEM: + mn->options = cpu_to_le16(ACO_LOAD_MEMORY); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.mem.start_addr); + break; + case QLA84_MGMT_CHNG_CONFIG: + mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.id); + mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param0); + mn->parameter3 = cpu_to_le32(ql84_mgmt->mgmtp.u.config.param1); + break; + case QLA84_MGMT_GET_INFO: + mn->options = cpu_to_le16(ACO_REQUEST_INFO); + mn->parameter1 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.type); + mn->parameter2 = cpu_to_le32(ql84_mgmt->mgmtp.u.info.context); + break; + default: + ret = -EIO; + goto exit_mgmt0; + } + + if ((len = ql84_mgmt->len) && ql84_mgmt->cmd != QLA84_MGMT_CHNG_CONFIG) { + mgmt_b = dma_alloc_coherent(&ha->pdev->dev, len, + &mgmt_dma, GFP_KERNEL); + if (mgmt_b == NULL) { + printk(KERN_ERR "%s: dma alloc mgmt_b failed%lu\n", + __func__, ha->host_no); + ret = -ENOMEM; + goto exit_mgmt0; + } + mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->len); + mn->dseg_count = cpu_to_le16(1); + mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); + mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); + mn->dseg_length = cpu_to_le32(len); + + if (ql84_mgmt->cmd == QLA84_MGMT_WRITE_MEM) { + memcpy(mgmt_b, ql84_mgmt->payload, len); + } + } + + ret = qla2x00_issue_iocb(ha, mn, mn_dma, 0); + cmd->error = ret; + + if (ret != QLA_SUCCESS) { + printk(KERN_ERR "%s(%lu): failed\n", __func__, ha->host_no); + ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, NULL, 0); + } else if ((ql84_mgmt->cmd == QLA84_MGMT_READ_MEM)|| + (ql84_mgmt->cmd == QLA84_MGMT_GET_INFO)) { + ret = ql_fc_nl_rsp(pid, seq, type, cmd, rsp_hdr_len, mgmt_b, len); + } + + if (mgmt_b) + dma_free_coherent(&ha->pdev->dev, len, mgmt_b, mgmt_dma); + +exit_mgmt0: + dma_pool_free(ha->s_dma_pool, mn, mn_dma); + return ret; +} + +static void +ql_fc_get_aen(scsi_qla_host_t *ha) +{ + unsigned long flags; + + memset(&aen_log, 0, sizeof (struct qlfc_aen_log)); + + spin_lock_irqsave(&ha->hardware_lock, flags); + + memcpy(&aen_log, &ha->aen_log, sizeof(struct qlfc_aen_log)); + ha->aen_log.num_events = 0; + + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +/* + * Netlink Interface Related Functions + */ + +void +ql_fc_nl_rcv(struct sock *sk, int len) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&sk->sk_receive_queue))) { + ql_fc_nl_rcv_msg(skb); + kfree_skb(skb); + } +} + +static void +ql_fc_nl_rcv_msg(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + struct scsi_nl_hdr *snlh; + uint32_t rlen; + int err; + + while (skb->len >= NLMSG_SPACE(0)) { + err = 0; + + nlh = (struct nlmsghdr *) skb->data; + + if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*snlh))) || + (skb->len < nlh->nlmsg_len)) { + printk(KERN_WARNING "%s: discarding partial skb\n", + __FUNCTION__); + break; + } + + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) { + printk(KERN_WARNING "%s: rlen > skb->len\n", + __FUNCTION__); + rlen = skb->len; + } + + if (nlh->nlmsg_type != FC_TRANSPORT_MSG) { + printk(KERN_WARNING "%s: Not FC_TRANSPORT_MSG\n", + __FUNCTION__); + err = -EBADMSG; + goto next_msg; + } + + snlh = NLMSG_DATA(nlh); + if ((snlh->version != SCSI_NL_VERSION) || + (snlh->magic != SCSI_NL_MAGIC)) { + printk(KERN_WARNING "%s: Bad Version or Magic number\n", + __FUNCTION__); + err = -EPROTOTYPE; + goto next_msg; + } + err = ql_fc_proc_nl_rcv_msg(skb, nlh, rlen); +next_msg: + if (err) + netlink_ack(skb, nlh, err); + skb_pull(skb, rlen); + } +} + +static int +ql_fc_proc_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int rcvlen) +{ + struct scsi_nl_hdr *snlh; + struct qla_fc_msg *ql_cmd; + struct Scsi_Host *shost; + struct scsi_qla_host *ha; + int err = 0; + int rsp_hdr_len; + + snlh = NLMSG_DATA(nlh); + + /* Only vendor specific commands are supported */ + if (!(snlh->msgtype & FC_NL_VNDR_SPECIFIC)) + return -EBADMSG; + + ql_cmd = (struct qla_fc_msg *)((char *)snlh + sizeof (struct scsi_nl_hdr)); + + if (ql_cmd->magic != QL_FC_NL_MAGIC) + return -EBADMSG; + + shost = scsi_host_lookup(ql_cmd->host_no); + if (IS_ERR(shost)) { + printk(KERN_ERR "%s: could not find host no %u\n", __FUNCTION__, + ql_cmd->host_no); + err = -ENODEV; + goto exit_proc_nl_rcv_msg; + } + + ha = (struct scsi_qla_host *)shost->hostdata; + + if (!ha || !IS_QLA84XX(ha)) { + printk(KERN_ERR "%s: invalid host ha = %p dtype = 0x%x\n", + __FUNCTION__, ha, (ha ? DT_MASK(ha): ~0)); + err = -ENODEV; + goto exit_proc_nl_rcv_msg; + } + + switch (ql_cmd->cmd) { + + case QLA84_RESET: + + rsp_hdr_len = offsetof(struct qla_fc_msg, u); + err = qla84xx_reset(ha, ql_cmd->u.utok.qla84_reset.diag_fw); + ql_cmd->error = err; + + err = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, + (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0); + break; + + case QLA84_UPDATE_FW: + rsp_hdr_len = offsetof(struct qla_fc_msg, u); + err = qla84xx_update_fw(ha, + ql_cmd->u.utok.qla84_update_fw.diag_fw, + ql_cmd->u.utok.qla84_update_fw.len, + ql_cmd->u.utok.qla84_update_fw.fw_bytes); + ql_cmd->error = err; + + err = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, + (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, NULL, 0); + break; + + case QLA84_MGMT_CMD: + err = qla84xx_mgmt_cmd(ha, ql_cmd, NETLINK_CREDS(skb)->pid, + nlh->nlmsg_seq, (uint32_t)nlh->nlmsg_type); + break; + + case QLFC_GET_AEN: + rsp_hdr_len = offsetof(struct qla_fc_msg, u); + ql_cmd->error = 0; + ql_fc_get_aen(ha); + err = ql_fc_nl_rsp(NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, + (uint32_t)nlh->nlmsg_type, ql_cmd, rsp_hdr_len, + &aen_log, sizeof(struct qlfc_aen_log)); + break; + default: + err = -EBADMSG; + } + +exit_proc_nl_rcv_msg: + return err; +} + +static int +ql_fc_nl_event(struct notifier_block *this, unsigned long event, void *ptr) +{ + DEBUG16(printk(KERN_WARNING "%s: event 0x%lx ptr = %p\n", __func__, event, ptr)); + return NOTIFY_DONE; +} + +static int +ql_fc_nl_rsp(uint32_t pid, uint32_t seq, uint32_t type, void *hdr, int hdr_len, + void *payload, int size) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + int rc; + int len = NLMSG_SPACE(size + hdr_len); + + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "%s: Could not alloc skb\n", __func__); + return -ENOMEM; + } + nlh = __nlmsg_put(skb, pid, seq, type, (len - sizeof(*nlh)), 0); + nlh->nlmsg_flags = 0; + memcpy(NLMSG_DATA(nlh), hdr, hdr_len); + + if (payload) + memcpy((void *)((char *)(NLMSG_DATA(nlh)) + hdr_len), payload, size); + + rc = netlink_unicast(ql_fc_nl_sock, skb, pid, MSG_DONTWAIT); + if (rc < 0) { + printk(KERN_ERR "%s: netlink_unicast failed\n", __func__); + return rc; + } + return 0; +} + +int +ql_nl_register(void) +{ + int error = 0; + + error = netlink_register_notifier(&ql_fc_nl_notifier); + if (!error) { + ql_fc_nl_sock = netlink_kernel_create(NETLINK_FCTRANSPORT, + QL_FC_NL_GROUP_CNT, ql_fc_nl_rcv, + THIS_MODULE); + if (!ql_fc_nl_sock) { + netlink_unregister_notifier(&ql_fc_nl_notifier); + error = -ENODEV; + } + } + return (error); +} + +void +ql_nl_unregister() +{ + if (ql_fc_nl_sock) { + sock_release(ql_fc_nl_sock->sk_socket); + netlink_unregister_notifier(&ql_fc_nl_notifier); + } +} diff --git a/drivers/scsi/qla2xxx/qla_nlnk.h b/drivers/scsi/qla2xxx/qla_nlnk.h new file mode 100644 index 0000000..930ab14 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_nlnk.h @@ -0,0 +1,158 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2005 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#ifndef _QLA_NLNK_H_ +#define _QLA_NLNK_H_ + +#ifndef NETLINK_FCTRANSPORT +#define NETLINK_FCTRANSPORT 20 +#endif +#define QL_FC_NL_GROUP_CNT 0 + +#define FC_TRANSPORT_MSG NLMSG_MIN_TYPE + 1 + +/* + * Transport Message Types + */ +#define FC_NL_VNDR_SPECIFIC 0x8000 + +/* + * Structures + */ + +struct qla84_mgmt_param { + union { + struct { + uint32_t start_addr; + } mem; /* for QLA84_MGMT_READ/WRITE_MEM */ + struct { + uint32_t id; +#define QLA84_MGMT_CONFIG_ID_UIF 1 +#define QLA84_MGMT_CONFIG_ID_FCOE_COS 2 +#define QLA84_MGMT_CONFIG_ID_PAUSE 3 +#define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4 + + uint32_t param0; + uint32_t param1; + } config; /* for QLA84_MGMT_CHNG_CONFIG */ + + struct { + uint32_t type; +#define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */ +#define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */ +#define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */ +#define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */ +#define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */ +#define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */ +#define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */ + + uint32_t context; +/* + * context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA + */ +#define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0 +#define IC_LOG_DATA_LOG_ID_LEARN_LOG 1 +#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2 +#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3 +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4 +#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5 +#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6 +#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7 +#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8 +#define IC_LOG_DATA_LOG_ID_DCX_LOG 9 + +/* + * context definitions for QLA84_MGMT_INFO_PORT_STAT + */ +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0 +#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1 +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2 +#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3 +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4 +#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5 + + +/* + * context definitions for QLA84_MGMT_INFO_LIF_STAT + */ +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0 +#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1 +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2 +#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3 +#define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6 + + } info; /* for QLA84_MGMT_GET_INFO */ + } u; +}; + +#define QLFC_MAX_AEN 256 +struct qlfc_aen_entry { + uint16_t event_code; + uint16_t payload[3]; +}; + +struct qlfc_aen_log { + uint32_t num_events; + struct qlfc_aen_entry aen[QLFC_MAX_AEN]; +}; + +struct qla84_msg_mgmt { + uint16_t cmd; +#define QLA84_MGMT_READ_MEM 0x00 +#define QLA84_MGMT_WRITE_MEM 0x01 +#define QLA84_MGMT_CHNG_CONFIG 0x02 +#define QLA84_MGMT_GET_INFO 0x03 + uint16_t rsrvd; + struct qla84_mgmt_param mgmtp;/* parameters for cmd */ + uint32_t len; /* bytes in payload following this struct */ + uint8_t payload[0]; /* payload for cmd */ +}; + +struct qla_fc_msg { + + uint32_t magic; +#define QL_FC_NL_MAGIC 0xFCAB1FC1 + + uint32_t cmd; +#define QLA84_RESET 0x01 +#define QLA84_UPDATE_FW 0x02 +#define QLA84_MGMT_CMD 0x03 +#define QLFC_GET_AEN 0x04 + + uint32_t error; /* interface or resource error holder*/ + uint32_t host_no; + + union { + union { + struct msg_reset { + /* + * diag_fw = 0 for operational fw + * otherwise diagnostic fw + */ + uint32_t diag_fw; + } qla84_reset; + + struct msg_update_fw { + /* + * diag_fw = 0 for operational fw + * otherwise diagnostic fw + */ + uint32_t diag_fw; + uint32_t len; /* size of fw in bytes */ + uint8_t fw_bytes[0]; + } qla84_update_fw; + + struct qla84_msg_mgmt mgmt; + } utok; + + union { + struct qla84_msg_mgmt mgmt; + struct qlfc_aen_log aen_log; + } ktou; + } u; +} __attribute__ ((aligned (sizeof(uint64_t)))); + +#endif /* _QLA_NLNK_H_ */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 83386fe..807b80e 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2977,10 +2977,17 @@ qla2x00_module_init(void) kmem_cache_destroy(srb_cachep); return -ENODEV; } + if (ql_nl_register()) { + kmem_cache_destroy(srb_cachep); + fc_release_transport(qla2xxx_transport_template); + return -ENODEV; + } + printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n"); ret = pci_register_driver(&qla2xxx_pci_driver); if (ret) { + ql_nl_unregister(); kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); } @@ -2995,6 +3002,7 @@ qla2x00_module_exit(void) { pci_unregister_driver(&qla2xxx_pci_driver); /* qla2x00_release_firmware(); */ + ql_nl_unregister(); kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); }