mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-10 07:10:27 +00:00
SCSI misc on 20130903
This patch set is a set of driver updates (ufs, zfcp, lpfc, mpt2/3sas, qla4xxx, qla2xxx [adding support for ISP8044 + other things]) we also have a new driver: esas2r which has a number of static checker problems, but which I expect to resolve over the -rc course of 3.12 under the new driver exception. We also have the error return updates that were discussed at LSF. Signed-off-by: James Bottomley <JBottomley@Parallels.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQEcBAABAgAGBQJSJfX5AAoJEDeqqVYsXL0M8u8H+gN65iA4YeNc3Eq9F6mliLfg JOIfn6GRz7ChbQ1ZZKdH/5xCOtzXphrkg7kRGmr9frsvYZ4X2c7W3xweQTA08gqP wPH7/xyPffPnUm/r+V+SV41pm39bEjmltknLwiF572a6iOoVYQpnmDjdZQKT0jU0 QZEqI81+646m8edCnApLw3Tlsn2gBwHaDrkd55H2IQGTkOD016C0CQbM+cNMU440 qdqDcfRWCsp1fhLo3JH2kWTx8BihhyfEYAFz4tZwuFdGGkRZxF20HwyzV0h3hZOG kZ2Gd1BFf0SybxOcESQmAukbcH5hyumX1Y7HMYKZbS2ubD4MCO1MO8UUtLXlxNc= =PDBQ -----END PGP SIGNATURE----- Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull first round of SCSI updates from James Bottomley: "This patch set is a set of driver updates (ufs, zfcp, lpfc, mpt2/3sas, qla4xxx, qla2xxx [adding support for ISP8044 + other things]). We also have a new driver: esas2r which has a number of static checker problems, but which I expect to resolve over the -rc course of 3.12 under the new driver exception. We also have the error return that were discussed at LSF" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (118 commits) [SCSI] sg: push file descriptor list locking down to per-device locking [SCSI] sg: checking sdp->detached isn't protected when open [SCSI] sg: no need sg_open_exclusive_lock [SCSI] sg: use rwsem to solve race during exclusive open [SCSI] scsi_debug: fix logical block provisioning support when unmap_alignment != 0 [SCSI] scsi_debug: fix endianness bug in sdebug_build_parts() [SCSI] qla2xxx: Update the driver version to 8.06.00.08-k. [SCSI] qla2xxx: print MAC via %pMR. [SCSI] qla2xxx: Correction to message ids. [SCSI] qla2xxx: Correctly print out/in mailbox registers. [SCSI] qla2xxx: Add a new interface to update versions. [SCSI] qla2xxx: Move queue depth ramp down message to i/o debug level. [SCSI] qla2xxx: Select link initialization option bits from current operating mode. [SCSI] qla2xxx: Add loopback IDC-TIME-EXTEND aen handling support. [SCSI] qla2xxx: Set default critical temperature value in cases when ISPFX00 firmware doesn't provide it [SCSI] qla2xxx: QLAFX00 make over temperature AEN handling informational, add log for normal temperature AEN [SCSI] qla2xxx: Correct Interrupt Register offset for ISPFX00 [SCSI] qla2xxx: Remove handling of Shutdown Requested AEN from qlafx00_process_aen(). [SCSI] qla2xxx: Send all AENs for ISPFx00 to above layers. [SCSI] qla2xxx: Add changes in initialization for ISPFX00 cards with BIOS ...
This commit is contained in:
commit
f66c83d059
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2003-2012 QLogic Corporation
|
||||
Copyright (c) 2003-2013 QLogic Corporation
|
||||
QLogic Linux iSCSI Driver
|
||||
|
||||
This program includes a device driver for Linux 3.x.
|
||||
|
15
MAINTAINERS
15
MAINTAINERS
@ -1547,6 +1547,13 @@ W: http://atmelwlandriver.sourceforge.net/
|
||||
S: Maintained
|
||||
F: drivers/net/wireless/atmel*
|
||||
|
||||
ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
|
||||
M: Bradley Grove <linuxdrivers@attotech.com>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
W: http://www.attotech.com
|
||||
S: Supported
|
||||
F: drivers/scsi/esas2r
|
||||
|
||||
AUDIT SUBSYSTEM
|
||||
M: Al Viro <viro@zeniv.linux.org.uk>
|
||||
M: Eric Paris <eparis@redhat.com>
|
||||
@ -1823,6 +1830,12 @@ L: linux-scsi@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/scsi/bnx2fc/
|
||||
|
||||
BROADCOM BNX2I 1/10 GIGABIT iSCSI DRIVER
|
||||
M: Eddie Wai <eddie.wai@broadcom.com>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/scsi/bnx2i/
|
||||
|
||||
BROADCOM SPECIFIC AMBA DRIVER (BCMA)
|
||||
M: Rafał Miłecki <zajec5@gmail.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
@ -6676,11 +6689,11 @@ F: Documentation/scsi/LICENSE.qla2xxx
|
||||
F: drivers/scsi/qla2xxx/
|
||||
|
||||
QLOGIC QLA4XXX iSCSI DRIVER
|
||||
M: Ravi Anand <ravi.anand@qlogic.com>
|
||||
M: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
|
||||
M: iscsi-driver@qlogic.com
|
||||
L: linux-scsi@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/scsi/LICENSE.qla4xxx
|
||||
F: drivers/scsi/qla4xxx/
|
||||
|
||||
QLOGIC QLA3XXX NETWORK DRIVER
|
||||
|
@ -2318,6 +2318,12 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
|
||||
case -ETIMEDOUT:
|
||||
error_type = "timeout";
|
||||
break;
|
||||
case -ENOSPC:
|
||||
error_type = "critical space allocation";
|
||||
break;
|
||||
case -ENODATA:
|
||||
error_type = "critical medium";
|
||||
break;
|
||||
case -EIO:
|
||||
default:
|
||||
error_type = "I/O";
|
||||
|
@ -672,6 +672,7 @@ static umode_t iser_attr_is_visible(int param_type, int param)
|
||||
case ISCSI_PARAM_TGT_RESET_TMO:
|
||||
case ISCSI_PARAM_IFACE_NAME:
|
||||
case ISCSI_PARAM_INITIATOR_NAME:
|
||||
case ISCSI_PARAM_DISCOVERY_SESS:
|
||||
return S_IRUGO;
|
||||
default:
|
||||
return 0;
|
||||
@ -701,7 +702,7 @@ static struct scsi_host_template iscsi_iser_sht = {
|
||||
static struct iscsi_transport iscsi_iser_transport = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "iser",
|
||||
.caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T,
|
||||
.caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_TEXT_NEGO,
|
||||
/* session management */
|
||||
.create_session = iscsi_iser_session_create,
|
||||
.destroy_session = iscsi_iser_session_destroy,
|
||||
|
@ -234,6 +234,7 @@ void iser_free_rx_descriptors(struct iser_conn *ib_conn)
|
||||
static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
|
||||
{
|
||||
struct iscsi_iser_conn *iser_conn = conn->dd_data;
|
||||
struct iscsi_session *session = conn->session;
|
||||
|
||||
iser_dbg("req op %x flags %x\n", req->opcode, req->flags);
|
||||
/* check if this is the last login - going to full feature phase */
|
||||
@ -248,7 +249,13 @@ static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
|
||||
WARN_ON(iser_conn->ib_conn->post_recv_buf_count != 1);
|
||||
WARN_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
|
||||
|
||||
iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);
|
||||
if (session->discovery_sess) {
|
||||
iser_info("Discovery session, re-using login RX buffer\n");
|
||||
return 0;
|
||||
} else
|
||||
iser_info("Normal session, posting batch of RX %d buffers\n",
|
||||
ISER_MIN_POSTED_RX);
|
||||
|
||||
/* Initial post receive buffers */
|
||||
if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX))
|
||||
return -ENOMEM;
|
||||
@ -425,6 +432,8 @@ int iser_send_control(struct iscsi_conn *conn,
|
||||
}
|
||||
|
||||
if (task == conn->login_task) {
|
||||
iser_dbg("op %x dsl %lx, posting login rx buffer\n",
|
||||
task->hdr->opcode, data_seg_len);
|
||||
err = iser_post_recvl(iser_conn->ib_conn);
|
||||
if (err)
|
||||
goto send_control_error;
|
||||
|
@ -1261,6 +1261,20 @@ static void activate_path(struct work_struct *work)
|
||||
pg_init_done, pgpath);
|
||||
}
|
||||
|
||||
static int noretry_error(int error)
|
||||
{
|
||||
switch (error) {
|
||||
case -EOPNOTSUPP:
|
||||
case -EREMOTEIO:
|
||||
case -EILSEQ:
|
||||
case -ENODATA:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Anything else could be a path failure, so should be retried */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* end_io handling
|
||||
*/
|
||||
@ -1284,7 +1298,7 @@ static int do_end_io(struct multipath *m, struct request *clone,
|
||||
if (!error && !clone->errors)
|
||||
return 0; /* I/O complete */
|
||||
|
||||
if (error == -EOPNOTSUPP || error == -EREMOTEIO || error == -EILSEQ)
|
||||
if (noretry_error(error))
|
||||
return error;
|
||||
|
||||
if (mpio->pgpath)
|
||||
|
@ -104,11 +104,11 @@ static void __init zfcp_init_device_setup(char *devstr)
|
||||
strncpy(busid, token, ZFCP_BUS_ID_SIZE);
|
||||
|
||||
token = strsep(&str, ",");
|
||||
if (!token || strict_strtoull(token, 0, (unsigned long long *) &wwpn))
|
||||
if (!token || kstrtoull(token, 0, (unsigned long long *) &wwpn))
|
||||
goto err_out;
|
||||
|
||||
token = strsep(&str, ",");
|
||||
if (!token || strict_strtoull(token, 0, (unsigned long long *) &lun))
|
||||
if (!token || kstrtoull(token, 0, (unsigned long long *) &lun))
|
||||
goto err_out;
|
||||
|
||||
kfree(str_saved);
|
||||
|
@ -126,8 +126,6 @@ extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
|
||||
extern int zfcp_qdio_open(struct zfcp_qdio *);
|
||||
extern void zfcp_qdio_close(struct zfcp_qdio *);
|
||||
extern void zfcp_qdio_siosl(struct zfcp_adapter *);
|
||||
extern struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *,
|
||||
struct qdio_buffer *);
|
||||
|
||||
/* zfcp_scsi.c */
|
||||
extern struct scsi_transport_template *zfcp_scsi_transport_template;
|
||||
|
@ -770,7 +770,8 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
|
||||
if (zfcp_qdio_sbal_get(qdio))
|
||||
goto out;
|
||||
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0,
|
||||
req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS,
|
||||
SBAL_SFLAGS0_TYPE_STATUS,
|
||||
adapter->pool.status_read_req);
|
||||
if (IS_ERR(req)) {
|
||||
retval = PTR_ERR(req);
|
||||
@ -2387,12 +2388,3 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *qdio,
|
||||
struct qdio_buffer *sbal)
|
||||
{
|
||||
struct qdio_buffer_element *sbale = &sbal->element[0];
|
||||
u64 req_id = (unsigned long) sbale->addr;
|
||||
|
||||
return zfcp_reqlist_find(qdio->adapter->req_list, req_id);
|
||||
}
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
|
||||
|
||||
static bool enable_multibuffer;
|
||||
static bool enable_multibuffer = 1;
|
||||
module_param_named(datarouter, enable_multibuffer, bool, 0400);
|
||||
MODULE_PARM_DESC(datarouter, "Enable hardware data router support");
|
||||
MODULE_PARM_DESC(datarouter, "Enable hardware data router support (default on)");
|
||||
|
||||
static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ static ssize_t zfcp_sysfs_port_failed_store(struct device *dev,
|
||||
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
|
||||
unsigned long val;
|
||||
|
||||
if (strict_strtoul(buf, 0, &val) || val != 0)
|
||||
if (kstrtoul(buf, 0, &val) || val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING);
|
||||
@ -146,7 +146,7 @@ static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev,
|
||||
unsigned long val;
|
||||
struct scsi_device *sdev;
|
||||
|
||||
if (strict_strtoul(buf, 0, &val) || val != 0)
|
||||
if (kstrtoul(buf, 0, &val) || val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
sdev = zfcp_unit_sdev(unit);
|
||||
@ -196,7 +196,7 @@ static ssize_t zfcp_sysfs_adapter_failed_store(struct device *dev,
|
||||
if (!adapter)
|
||||
return -ENODEV;
|
||||
|
||||
if (strict_strtoul(buf, 0, &val) || val != 0) {
|
||||
if (kstrtoul(buf, 0, &val) || val != 0) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@ -248,7 +248,7 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
|
||||
if (!adapter)
|
||||
return -ENODEV;
|
||||
|
||||
if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn))
|
||||
if (kstrtoull(buf, 0, (unsigned long long *) &wwpn))
|
||||
goto out;
|
||||
|
||||
port = zfcp_get_port_by_wwpn(adapter, wwpn);
|
||||
@ -309,7 +309,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
|
||||
u64 fcp_lun;
|
||||
int retval;
|
||||
|
||||
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
|
||||
if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
|
||||
return -EINVAL;
|
||||
|
||||
retval = zfcp_unit_add(port, fcp_lun);
|
||||
@ -327,7 +327,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
|
||||
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
|
||||
u64 fcp_lun;
|
||||
|
||||
if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
|
||||
if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
|
||||
return -EINVAL;
|
||||
|
||||
if (zfcp_unit_remove(port, fcp_lun))
|
||||
|
@ -601,6 +601,7 @@ config SCSI_ARCMSR
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called arcmsr (modprobe arcmsr).
|
||||
|
||||
source "drivers/scsi/esas2r/Kconfig"
|
||||
source "drivers/scsi/megaraid/Kconfig.megaraid"
|
||||
source "drivers/scsi/mpt2sas/Kconfig"
|
||||
source "drivers/scsi/mpt3sas/Kconfig"
|
||||
|
@ -141,6 +141,7 @@ obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/
|
||||
obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/
|
||||
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
|
||||
obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
|
||||
obj-$(CONFIG_SCSI_ESAS2R) += esas2r/
|
||||
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
|
||||
obj-$(CONFIG_SCSI_VIRTIO) += virtio_scsi.o
|
||||
obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
|
||||
|
@ -63,9 +63,9 @@ int max_rport_logins = BFA_FCS_MAX_RPORT_LOGINS;
|
||||
u32 bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size;
|
||||
u32 *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2;
|
||||
|
||||
#define BFAD_FW_FILE_CB "cbfw-3.2.1.0.bin"
|
||||
#define BFAD_FW_FILE_CT "ctfw-3.2.1.0.bin"
|
||||
#define BFAD_FW_FILE_CT2 "ct2fw-3.2.1.0.bin"
|
||||
#define BFAD_FW_FILE_CB "cbfw-3.2.1.1.bin"
|
||||
#define BFAD_FW_FILE_CT "ctfw-3.2.1.1.bin"
|
||||
#define BFAD_FW_FILE_CT2 "ct2fw-3.2.1.1.bin"
|
||||
|
||||
static u32 *bfad_load_fwimg(struct pci_dev *pdev);
|
||||
static void bfad_free_fwimg(void);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
|
||||
*
|
||||
* Copyright (c) 2006 - 2012 Broadcom Corporation
|
||||
* Copyright (c) 2006 - 2013 Broadcom Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
|
||||
*
|
||||
* Copyright (c) 2006 - 2012 Broadcom Corporation
|
||||
* Copyright (c) 2006 - 2013 Broadcom Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
|
||||
*
|
||||
* Copyright (c) 2006 - 2012 Broadcom Corporation
|
||||
* Copyright (c) 2006 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (c) 2007, 2008 Mike Christie
|
||||
*
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
|
||||
*
|
||||
* Copyright (c) 2006 - 2012 Broadcom Corporation
|
||||
* Copyright (c) 2006 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (c) 2007, 2008 Mike Christie
|
||||
*
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
|
||||
*
|
||||
* Copyright (c) 2006 - 2012 Broadcom Corporation
|
||||
* Copyright (c) 2006 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (c) 2007, 2008 Mike Christie
|
||||
*
|
||||
@ -18,8 +18,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
|
||||
static u32 adapter_count;
|
||||
|
||||
#define DRV_MODULE_NAME "bnx2i"
|
||||
#define DRV_MODULE_VERSION "2.7.2.2"
|
||||
#define DRV_MODULE_RELDATE "Apr 25, 2012"
|
||||
#define DRV_MODULE_VERSION "2.7.6.2"
|
||||
#define DRV_MODULE_RELDATE "Jun 06, 2013"
|
||||
|
||||
static char version[] =
|
||||
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
|
||||
*
|
||||
* Copyright (c) 2006 - 2012 Broadcom Corporation
|
||||
* Copyright (c) 2006 - 2013 Broadcom Corporation
|
||||
* Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (c) 2007, 2008 Mike Christie
|
||||
*
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
|
||||
*
|
||||
* Copyright (c) 2004 - 2012 Broadcom Corporation
|
||||
* Copyright (c) 2004 - 2013 Broadcom Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -919,7 +919,7 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
|
||||
find_pio_EISA(&gc);
|
||||
find_pio_ISA(&gc);
|
||||
|
||||
for (i = 0; i <= MAXIRQ; i++)
|
||||
for (i = 0; i < MAXIRQ; i++)
|
||||
if (reg_IRQ[i])
|
||||
request_irq(i, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", NULL);
|
||||
|
||||
|
5
drivers/scsi/esas2r/Kconfig
Normal file
5
drivers/scsi/esas2r/Kconfig
Normal file
@ -0,0 +1,5 @@
|
||||
config SCSI_ESAS2R
|
||||
tristate "ATTO Technology's ExpressSAS RAID adapter driver"
|
||||
depends on PCI && SCSI
|
||||
---help---
|
||||
This driver supports the ATTO ExpressSAS R6xx SAS/SATA RAID controllers.
|
5
drivers/scsi/esas2r/Makefile
Normal file
5
drivers/scsi/esas2r/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
obj-$(CONFIG_SCSI_ESAS2R) += esas2r.o
|
||||
|
||||
esas2r-objs := esas2r_log.o esas2r_disc.o esas2r_flash.o esas2r_init.o \
|
||||
esas2r_int.o esas2r_io.o esas2r_ioctl.o esas2r_targdb.o \
|
||||
esas2r_vda.o esas2r_main.o
|
1254
drivers/scsi/esas2r/atioctl.h
Normal file
1254
drivers/scsi/esas2r/atioctl.h
Normal file
File diff suppressed because it is too large
Load Diff
1319
drivers/scsi/esas2r/atvda.h
Normal file
1319
drivers/scsi/esas2r/atvda.h
Normal file
File diff suppressed because it is too large
Load Diff
1441
drivers/scsi/esas2r/esas2r.h
Normal file
1441
drivers/scsi/esas2r/esas2r.h
Normal file
File diff suppressed because it is too large
Load Diff
1189
drivers/scsi/esas2r/esas2r_disc.c
Normal file
1189
drivers/scsi/esas2r/esas2r_disc.c
Normal file
File diff suppressed because it is too large
Load Diff
1512
drivers/scsi/esas2r/esas2r_flash.c
Normal file
1512
drivers/scsi/esas2r/esas2r_flash.c
Normal file
File diff suppressed because it is too large
Load Diff
1773
drivers/scsi/esas2r/esas2r_init.c
Normal file
1773
drivers/scsi/esas2r/esas2r_init.c
Normal file
File diff suppressed because it is too large
Load Diff
941
drivers/scsi/esas2r/esas2r_int.c
Normal file
941
drivers/scsi/esas2r/esas2r_int.c
Normal file
@ -0,0 +1,941 @@
|
||||
/*
|
||||
* linux/drivers/scsi/esas2r/esas2r_int.c
|
||||
* esas2r interrupt handling
|
||||
*
|
||||
* Copyright (c) 2001-2013 ATTO Technology, Inc.
|
||||
* (mailto:linuxdrivers@attotech.com)
|
||||
*/
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
||||
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
||||
* solely responsible for determining the appropriateness of using and
|
||||
* distributing the Program and assumes all risks associated with its
|
||||
* exercise of rights under this Agreement, including but not limited to
|
||||
* the risks and costs of program errors, damage to or loss of data,
|
||||
* programs or equipment, and unavailability or interruption of operations.
|
||||
*
|
||||
* DISCLAIMER OF LIABILITY
|
||||
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
||||
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
|
||||
#include "esas2r.h"
|
||||
|
||||
/* Local function prototypes */
|
||||
static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell);
|
||||
static void esas2r_get_outbound_responses(struct esas2r_adapter *a);
|
||||
static void esas2r_process_bus_reset(struct esas2r_adapter *a);
|
||||
|
||||
/*
|
||||
* Poll the adapter for interrupts and service them.
|
||||
* This function handles both legacy interrupts and MSI.
|
||||
*/
|
||||
void esas2r_polled_interrupt(struct esas2r_adapter *a)
|
||||
{
|
||||
u32 intstat;
|
||||
u32 doorbell;
|
||||
|
||||
esas2r_disable_chip_interrupts(a);
|
||||
|
||||
intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
|
||||
|
||||
if (intstat & MU_INTSTAT_POST_OUT) {
|
||||
/* clear the interrupt */
|
||||
|
||||
esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
|
||||
MU_OLIS_INT);
|
||||
esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
|
||||
|
||||
esas2r_get_outbound_responses(a);
|
||||
}
|
||||
|
||||
if (intstat & MU_INTSTAT_DRBL) {
|
||||
doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
|
||||
if (doorbell != 0)
|
||||
esas2r_doorbell_interrupt(a, doorbell);
|
||||
}
|
||||
|
||||
esas2r_enable_chip_interrupts(a);
|
||||
|
||||
if (atomic_read(&a->disable_cnt) == 0)
|
||||
esas2r_do_deferred_processes(a);
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy and MSI interrupt handlers. Note that the legacy interrupt handler
|
||||
* schedules a TASKLET to process events, whereas the MSI handler just
|
||||
* processes interrupt events directly.
|
||||
*/
|
||||
irqreturn_t esas2r_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;
|
||||
|
||||
if (!esas2r_adapter_interrupt_pending(a))
|
||||
return IRQ_NONE;
|
||||
|
||||
esas2r_lock_set_flags(&a->flags2, AF2_INT_PENDING);
|
||||
esas2r_schedule_tasklet(a);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void esas2r_adapter_interrupt(struct esas2r_adapter *a)
|
||||
{
|
||||
u32 doorbell;
|
||||
|
||||
if (likely(a->int_stat & MU_INTSTAT_POST_OUT)) {
|
||||
/* clear the interrupt */
|
||||
esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
|
||||
MU_OLIS_INT);
|
||||
esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
|
||||
esas2r_get_outbound_responses(a);
|
||||
}
|
||||
|
||||
if (unlikely(a->int_stat & MU_INTSTAT_DRBL)) {
|
||||
doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
|
||||
if (doorbell != 0)
|
||||
esas2r_doorbell_interrupt(a, doorbell);
|
||||
}
|
||||
|
||||
a->int_mask = ESAS2R_INT_STS_MASK;
|
||||
|
||||
esas2r_enable_chip_interrupts(a);
|
||||
|
||||
if (likely(atomic_read(&a->disable_cnt) == 0))
|
||||
esas2r_do_deferred_processes(a);
|
||||
}
|
||||
|
||||
irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;
|
||||
u32 intstat;
|
||||
u32 doorbell;
|
||||
|
||||
intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
|
||||
|
||||
if (likely(intstat & MU_INTSTAT_POST_OUT)) {
|
||||
/* clear the interrupt */
|
||||
|
||||
esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
|
||||
MU_OLIS_INT);
|
||||
esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
|
||||
|
||||
esas2r_get_outbound_responses(a);
|
||||
}
|
||||
|
||||
if (unlikely(intstat & MU_INTSTAT_DRBL)) {
|
||||
doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
|
||||
if (doorbell != 0)
|
||||
esas2r_doorbell_interrupt(a, doorbell);
|
||||
}
|
||||
|
||||
/*
|
||||
* Work around a chip bug and force a new MSI to be sent if one is
|
||||
* still pending.
|
||||
*/
|
||||
esas2r_disable_chip_interrupts(a);
|
||||
esas2r_enable_chip_interrupts(a);
|
||||
|
||||
if (likely(atomic_read(&a->disable_cnt) == 0))
|
||||
esas2r_do_deferred_processes(a);
|
||||
|
||||
esas2r_do_tasklet_tasks(a);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void esas2r_handle_outbound_rsp_err(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq,
|
||||
struct atto_vda_ob_rsp *rsp)
|
||||
{
|
||||
|
||||
/*
|
||||
* For I/O requests, only copy the response if an error
|
||||
* occurred and setup a callback to do error processing.
|
||||
*/
|
||||
if (unlikely(rq->req_stat != RS_SUCCESS)) {
|
||||
memcpy(&rq->func_rsp, &rsp->func_rsp, sizeof(rsp->func_rsp));
|
||||
|
||||
if (rq->req_stat == RS_ABORTED) {
|
||||
if (rq->timeout > RQ_MAX_TIMEOUT)
|
||||
rq->req_stat = RS_TIMEOUT;
|
||||
} else if (rq->req_stat == RS_SCSI_ERROR) {
|
||||
u8 scsistatus = rq->func_rsp.scsi_rsp.scsi_stat;
|
||||
|
||||
esas2r_trace("scsistatus: %x", scsistatus);
|
||||
|
||||
/* Any of these are a good result. */
|
||||
if (scsistatus == SAM_STAT_GOOD || scsistatus ==
|
||||
SAM_STAT_CONDITION_MET || scsistatus ==
|
||||
SAM_STAT_INTERMEDIATE || scsistatus ==
|
||||
SAM_STAT_INTERMEDIATE_CONDITION_MET) {
|
||||
rq->req_stat = RS_SUCCESS;
|
||||
rq->func_rsp.scsi_rsp.scsi_stat =
|
||||
SAM_STAT_GOOD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void esas2r_get_outbound_responses(struct esas2r_adapter *a)
|
||||
{
|
||||
struct atto_vda_ob_rsp *rsp;
|
||||
u32 rspput_ptr;
|
||||
u32 rspget_ptr;
|
||||
struct esas2r_request *rq;
|
||||
u32 handle;
|
||||
unsigned long flags;
|
||||
|
||||
LIST_HEAD(comp_list);
|
||||
|
||||
esas2r_trace_enter();
|
||||
|
||||
spin_lock_irqsave(&a->queue_lock, flags);
|
||||
|
||||
/* Get the outbound limit and pointers */
|
||||
rspput_ptr = le32_to_cpu(*a->outbound_copy) & MU_OLC_WRT_PTR;
|
||||
rspget_ptr = a->last_read;
|
||||
|
||||
esas2r_trace("rspput_ptr: %x, rspget_ptr: %x", rspput_ptr, rspget_ptr);
|
||||
|
||||
/* If we don't have anything to process, get out */
|
||||
if (unlikely(rspget_ptr == rspput_ptr)) {
|
||||
spin_unlock_irqrestore(&a->queue_lock, flags);
|
||||
esas2r_trace_exit();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure the firmware is healthy */
|
||||
if (unlikely(rspput_ptr >= a->list_size)) {
|
||||
spin_unlock_irqrestore(&a->queue_lock, flags);
|
||||
esas2r_bugon();
|
||||
esas2r_local_reset_adapter(a);
|
||||
esas2r_trace_exit();
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
rspget_ptr++;
|
||||
|
||||
if (rspget_ptr >= a->list_size)
|
||||
rspget_ptr = 0;
|
||||
|
||||
rsp = (struct atto_vda_ob_rsp *)a->outbound_list_md.virt_addr
|
||||
+ rspget_ptr;
|
||||
|
||||
handle = rsp->handle;
|
||||
|
||||
/* Verify the handle range */
|
||||
if (unlikely(LOWORD(handle) == 0
|
||||
|| LOWORD(handle) > num_requests +
|
||||
num_ae_requests + 1)) {
|
||||
esas2r_bugon();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the request for this handle */
|
||||
rq = a->req_table[LOWORD(handle)];
|
||||
|
||||
if (unlikely(rq == NULL || rq->vrq->scsi.handle != handle)) {
|
||||
esas2r_bugon();
|
||||
continue;
|
||||
}
|
||||
|
||||
list_del(&rq->req_list);
|
||||
|
||||
/* Get the completion status */
|
||||
rq->req_stat = rsp->req_stat;
|
||||
|
||||
esas2r_trace("handle: %x", handle);
|
||||
esas2r_trace("rq: %p", rq);
|
||||
esas2r_trace("req_status: %x", rq->req_stat);
|
||||
|
||||
if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)) {
|
||||
esas2r_handle_outbound_rsp_err(a, rq, rsp);
|
||||
} else {
|
||||
/*
|
||||
* Copy the outbound completion struct for non-I/O
|
||||
* requests.
|
||||
*/
|
||||
memcpy(&rq->func_rsp, &rsp->func_rsp,
|
||||
sizeof(rsp->func_rsp));
|
||||
}
|
||||
|
||||
/* Queue the request for completion. */
|
||||
list_add_tail(&rq->comp_list, &comp_list);
|
||||
|
||||
} while (rspget_ptr != rspput_ptr);
|
||||
|
||||
a->last_read = rspget_ptr;
|
||||
spin_unlock_irqrestore(&a->queue_lock, flags);
|
||||
|
||||
esas2r_comp_list_drain(a, &comp_list);
|
||||
esas2r_trace_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform all deferred processes for the adapter. Deferred
|
||||
* processes can only be done while the current interrupt
|
||||
* disable_cnt for the adapter is zero.
|
||||
*/
|
||||
void esas2r_do_deferred_processes(struct esas2r_adapter *a)
|
||||
{
|
||||
int startreqs = 2;
|
||||
struct esas2r_request *rq;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* startreqs is used to control starting requests
|
||||
* that are on the deferred queue
|
||||
* = 0 - do not start any requests
|
||||
* = 1 - can start discovery requests
|
||||
* = 2 - can start any request
|
||||
*/
|
||||
|
||||
if (a->flags & (AF_CHPRST_PENDING | AF_FLASHING))
|
||||
startreqs = 0;
|
||||
else if (a->flags & AF_DISC_PENDING)
|
||||
startreqs = 1;
|
||||
|
||||
atomic_inc(&a->disable_cnt);
|
||||
|
||||
/* Clear off the completed list to be processed later. */
|
||||
|
||||
if (esas2r_is_tasklet_pending(a)) {
|
||||
esas2r_schedule_tasklet(a);
|
||||
|
||||
startreqs = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we can start requests then traverse the defer queue
|
||||
* looking for requests to start or complete
|
||||
*/
|
||||
if (startreqs && !list_empty(&a->defer_list)) {
|
||||
LIST_HEAD(comp_list);
|
||||
struct list_head *element, *next;
|
||||
|
||||
spin_lock_irqsave(&a->queue_lock, flags);
|
||||
|
||||
list_for_each_safe(element, next, &a->defer_list) {
|
||||
rq = list_entry(element, struct esas2r_request,
|
||||
req_list);
|
||||
|
||||
if (rq->req_stat != RS_PENDING) {
|
||||
list_del(element);
|
||||
list_add_tail(&rq->comp_list, &comp_list);
|
||||
}
|
||||
/*
|
||||
* Process discovery and OS requests separately. We
|
||||
* can't hold up discovery requests when discovery is
|
||||
* pending. In general, there may be different sets of
|
||||
* conditions for starting different types of requests.
|
||||
*/
|
||||
else if (rq->req_type == RT_DISC_REQ) {
|
||||
list_del(element);
|
||||
esas2r_disc_local_start_request(a, rq);
|
||||
} else if (startreqs == 2) {
|
||||
list_del(element);
|
||||
esas2r_local_start_request(a, rq);
|
||||
|
||||
/*
|
||||
* Flashing could have been set by last local
|
||||
* start
|
||||
*/
|
||||
if (a->flags & AF_FLASHING)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&a->queue_lock, flags);
|
||||
esas2r_comp_list_drain(a, &comp_list);
|
||||
}
|
||||
|
||||
atomic_dec(&a->disable_cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an adapter reset (or one that is about to happen)
|
||||
* by making sure all outstanding requests are completed that
|
||||
* haven't been already.
|
||||
*/
|
||||
void esas2r_process_adapter_reset(struct esas2r_adapter *a)
|
||||
{
|
||||
struct esas2r_request *rq = &a->general_req;
|
||||
unsigned long flags;
|
||||
struct esas2r_disc_context *dc;
|
||||
|
||||
LIST_HEAD(comp_list);
|
||||
struct list_head *element;
|
||||
|
||||
esas2r_trace_enter();
|
||||
|
||||
spin_lock_irqsave(&a->queue_lock, flags);
|
||||
|
||||
/* abort the active discovery, if any. */
|
||||
|
||||
if (rq->interrupt_cx) {
|
||||
dc = (struct esas2r_disc_context *)rq->interrupt_cx;
|
||||
|
||||
dc->disc_evt = 0;
|
||||
|
||||
esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
|
||||
}
|
||||
|
||||
/*
|
||||
* just clear the interrupt callback for now. it will be dequeued if
|
||||
* and when we find it on the active queue and we don't want the
|
||||
* callback called. also set the dummy completion callback in case we
|
||||
* were doing an I/O request.
|
||||
*/
|
||||
|
||||
rq->interrupt_cx = NULL;
|
||||
rq->interrupt_cb = NULL;
|
||||
|
||||
rq->comp_cb = esas2r_dummy_complete;
|
||||
|
||||
/* Reset the read and write pointers */
|
||||
|
||||
*a->outbound_copy =
|
||||
a->last_write =
|
||||
a->last_read = a->list_size - 1;
|
||||
|
||||
esas2r_lock_set_flags(&a->flags, AF_COMM_LIST_TOGGLE);
|
||||
|
||||
/* Kill all the requests on the active list */
|
||||
list_for_each(element, &a->defer_list) {
|
||||
rq = list_entry(element, struct esas2r_request, req_list);
|
||||
|
||||
if (rq->req_stat == RS_STARTED)
|
||||
if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
|
||||
list_add_tail(&rq->comp_list, &comp_list);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&a->queue_lock, flags);
|
||||
esas2r_comp_list_drain(a, &comp_list);
|
||||
esas2r_process_bus_reset(a);
|
||||
esas2r_trace_exit();
|
||||
}
|
||||
|
||||
static void esas2r_process_bus_reset(struct esas2r_adapter *a)
|
||||
{
|
||||
struct esas2r_request *rq;
|
||||
struct list_head *element;
|
||||
unsigned long flags;
|
||||
|
||||
LIST_HEAD(comp_list);
|
||||
|
||||
esas2r_trace_enter();
|
||||
|
||||
esas2r_hdebug("reset detected");
|
||||
|
||||
spin_lock_irqsave(&a->queue_lock, flags);
|
||||
|
||||
/* kill all the requests on the deferred queue */
|
||||
list_for_each(element, &a->defer_list) {
|
||||
rq = list_entry(element, struct esas2r_request, req_list);
|
||||
if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
|
||||
list_add_tail(&rq->comp_list, &comp_list);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&a->queue_lock, flags);
|
||||
|
||||
esas2r_comp_list_drain(a, &comp_list);
|
||||
|
||||
if (atomic_read(&a->disable_cnt) == 0)
|
||||
esas2r_do_deferred_processes(a);
|
||||
|
||||
esas2r_lock_clear_flags(&a->flags, AF_OS_RESET);
|
||||
|
||||
esas2r_trace_exit();
|
||||
}
|
||||
|
||||
static void esas2r_chip_rst_needed_during_tasklet(struct esas2r_adapter *a)
|
||||
{
|
||||
|
||||
esas2r_lock_clear_flags(&a->flags, AF_CHPRST_NEEDED);
|
||||
esas2r_lock_clear_flags(&a->flags, AF_BUSRST_NEEDED);
|
||||
esas2r_lock_clear_flags(&a->flags, AF_BUSRST_DETECTED);
|
||||
esas2r_lock_clear_flags(&a->flags, AF_BUSRST_PENDING);
|
||||
/*
|
||||
* Make sure we don't get attempt more than 3 resets
|
||||
* when the uptime between resets does not exceed one
|
||||
* minute. This will stop any situation where there is
|
||||
* really something wrong with the hardware. The way
|
||||
* this works is that we start with uptime ticks at 0.
|
||||
* Each time we do a reset, we add 20 seconds worth to
|
||||
* the count. Each time a timer tick occurs, as long
|
||||
* as a chip reset is not pending, we decrement the
|
||||
* tick count. If the uptime ticks ever gets to 60
|
||||
* seconds worth, we disable the adapter from that
|
||||
* point forward. Three strikes, you're out.
|
||||
*/
|
||||
if (!esas2r_is_adapter_present(a) || (a->chip_uptime >=
|
||||
ESAS2R_CHP_UPTIME_MAX)) {
|
||||
esas2r_hdebug("*** adapter disabled ***");
|
||||
|
||||
/*
|
||||
* Ok, some kind of hard failure. Make sure we
|
||||
* exit this loop with chip interrupts
|
||||
* permanently disabled so we don't lock up the
|
||||
* entire system. Also flag degraded mode to
|
||||
* prevent the heartbeat from trying to recover.
|
||||
*/
|
||||
|
||||
esas2r_lock_set_flags(&a->flags, AF_DEGRADED_MODE);
|
||||
esas2r_lock_set_flags(&a->flags, AF_DISABLED);
|
||||
esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
|
||||
esas2r_lock_clear_flags(&a->flags, AF_DISC_PENDING);
|
||||
|
||||
esas2r_disable_chip_interrupts(a);
|
||||
a->int_mask = 0;
|
||||
esas2r_process_adapter_reset(a);
|
||||
|
||||
esas2r_log(ESAS2R_LOG_CRIT,
|
||||
"Adapter disabled because of hardware failure");
|
||||
} else {
|
||||
u32 flags =
|
||||
esas2r_lock_set_flags(&a->flags, AF_CHPRST_STARTED);
|
||||
|
||||
if (!(flags & AF_CHPRST_STARTED))
|
||||
/*
|
||||
* Only disable interrupts if this is
|
||||
* the first reset attempt.
|
||||
*/
|
||||
esas2r_disable_chip_interrupts(a);
|
||||
|
||||
if ((a->flags & AF_POWER_MGT) && !(a->flags & AF_FIRST_INIT) &&
|
||||
!(flags & AF_CHPRST_STARTED)) {
|
||||
/*
|
||||
* Don't reset the chip on the first
|
||||
* deferred power up attempt.
|
||||
*/
|
||||
} else {
|
||||
esas2r_hdebug("*** resetting chip ***");
|
||||
esas2r_reset_chip(a);
|
||||
}
|
||||
|
||||
/* Kick off the reinitialization */
|
||||
a->chip_uptime += ESAS2R_CHP_UPTIME_CNT;
|
||||
a->chip_init_time = jiffies_to_msecs(jiffies);
|
||||
if (!(a->flags & AF_POWER_MGT)) {
|
||||
esas2r_process_adapter_reset(a);
|
||||
|
||||
if (!(flags & AF_CHPRST_STARTED)) {
|
||||
/* Remove devices now that I/O is cleaned up. */
|
||||
a->prev_dev_cnt =
|
||||
esas2r_targ_db_get_tgt_cnt(a);
|
||||
esas2r_targ_db_remove_all(a, false);
|
||||
}
|
||||
}
|
||||
|
||||
a->int_mask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void esas2r_handle_chip_rst_during_tasklet(struct esas2r_adapter *a)
|
||||
{
|
||||
while (a->flags & AF_CHPRST_DETECTED) {
|
||||
/*
|
||||
* Balance the enable in esas2r_initadapter_hw.
|
||||
* Esas2r_power_down already took care of it for power
|
||||
* management.
|
||||
*/
|
||||
if (!(a->flags & AF_DEGRADED_MODE) && !(a->flags &
|
||||
AF_POWER_MGT))
|
||||
esas2r_disable_chip_interrupts(a);
|
||||
|
||||
/* Reinitialize the chip. */
|
||||
esas2r_check_adapter(a);
|
||||
esas2r_init_adapter_hw(a, 0);
|
||||
|
||||
if (a->flags & AF_CHPRST_NEEDED)
|
||||
break;
|
||||
|
||||
if (a->flags & AF_POWER_MGT) {
|
||||
/* Recovery from power management. */
|
||||
if (a->flags & AF_FIRST_INIT) {
|
||||
/* Chip reset during normal power up */
|
||||
esas2r_log(ESAS2R_LOG_CRIT,
|
||||
"The firmware was reset during a normal power-up sequence");
|
||||
} else {
|
||||
/* Deferred power up complete. */
|
||||
esas2r_lock_clear_flags(&a->flags,
|
||||
AF_POWER_MGT);
|
||||
esas2r_send_reset_ae(a, true);
|
||||
}
|
||||
} else {
|
||||
/* Recovery from online chip reset. */
|
||||
if (a->flags & AF_FIRST_INIT) {
|
||||
/* Chip reset during driver load */
|
||||
} else {
|
||||
/* Chip reset after driver load */
|
||||
esas2r_send_reset_ae(a, false);
|
||||
}
|
||||
|
||||
esas2r_log(ESAS2R_LOG_CRIT,
|
||||
"Recovering from a chip reset while the chip was online");
|
||||
}
|
||||
|
||||
esas2r_lock_clear_flags(&a->flags, AF_CHPRST_STARTED);
|
||||
esas2r_enable_chip_interrupts(a);
|
||||
|
||||
/*
|
||||
* Clear this flag last! this indicates that the chip has been
|
||||
* reset already during initialization.
|
||||
*/
|
||||
esas2r_lock_clear_flags(&a->flags, AF_CHPRST_DETECTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Perform deferred tasks when chip interrupts are disabled */
|
||||
void esas2r_do_tasklet_tasks(struct esas2r_adapter *a)
|
||||
{
|
||||
if (a->flags & (AF_CHPRST_NEEDED | AF_CHPRST_DETECTED)) {
|
||||
if (a->flags & AF_CHPRST_NEEDED)
|
||||
esas2r_chip_rst_needed_during_tasklet(a);
|
||||
|
||||
esas2r_handle_chip_rst_during_tasklet(a);
|
||||
}
|
||||
|
||||
if (a->flags & AF_BUSRST_NEEDED) {
|
||||
esas2r_hdebug("hard resetting bus");
|
||||
|
||||
esas2r_lock_clear_flags(&a->flags, AF_BUSRST_NEEDED);
|
||||
|
||||
if (a->flags & AF_FLASHING)
|
||||
esas2r_lock_set_flags(&a->flags, AF_BUSRST_DETECTED);
|
||||
else
|
||||
esas2r_write_register_dword(a, MU_DOORBELL_IN,
|
||||
DRBL_RESET_BUS);
|
||||
}
|
||||
|
||||
if (a->flags & AF_BUSRST_DETECTED) {
|
||||
esas2r_process_bus_reset(a);
|
||||
|
||||
esas2r_log_dev(ESAS2R_LOG_WARN,
|
||||
&(a->host->shost_gendev),
|
||||
"scsi_report_bus_reset() called");
|
||||
|
||||
scsi_report_bus_reset(a->host, 0);
|
||||
|
||||
esas2r_lock_clear_flags(&a->flags, AF_BUSRST_DETECTED);
|
||||
esas2r_lock_clear_flags(&a->flags, AF_BUSRST_PENDING);
|
||||
|
||||
esas2r_log(ESAS2R_LOG_WARN, "Bus reset complete");
|
||||
}
|
||||
|
||||
if (a->flags & AF_PORT_CHANGE) {
|
||||
esas2r_lock_clear_flags(&a->flags, AF_PORT_CHANGE);
|
||||
|
||||
esas2r_targ_db_report_changes(a);
|
||||
}
|
||||
|
||||
if (atomic_read(&a->disable_cnt) == 0)
|
||||
esas2r_do_deferred_processes(a);
|
||||
}
|
||||
|
||||
static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell)
|
||||
{
|
||||
if (!(doorbell & DRBL_FORCE_INT)) {
|
||||
esas2r_trace_enter();
|
||||
esas2r_trace("doorbell: %x", doorbell);
|
||||
}
|
||||
|
||||
/* First clear the doorbell bits */
|
||||
esas2r_write_register_dword(a, MU_DOORBELL_OUT, doorbell);
|
||||
|
||||
if (doorbell & DRBL_RESET_BUS)
|
||||
esas2r_lock_set_flags(&a->flags, AF_BUSRST_DETECTED);
|
||||
|
||||
if (doorbell & DRBL_FORCE_INT)
|
||||
esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT);
|
||||
|
||||
if (doorbell & DRBL_PANIC_REASON_MASK) {
|
||||
esas2r_hdebug("*** Firmware Panic ***");
|
||||
esas2r_log(ESAS2R_LOG_CRIT, "The firmware has panicked");
|
||||
}
|
||||
|
||||
if (doorbell & DRBL_FW_RESET) {
|
||||
esas2r_lock_set_flags(&a->flags2, AF2_COREDUMP_AVAIL);
|
||||
esas2r_local_reset_adapter(a);
|
||||
}
|
||||
|
||||
if (!(doorbell & DRBL_FORCE_INT))
|
||||
esas2r_trace_exit();
|
||||
}
|
||||
|
||||
void esas2r_force_interrupt(struct esas2r_adapter *a)
|
||||
{
|
||||
esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_FORCE_INT |
|
||||
DRBL_DRV_VER);
|
||||
}
|
||||
|
||||
|
||||
static void esas2r_lun_event(struct esas2r_adapter *a, union atto_vda_ae *ae,
|
||||
u16 target, u32 length)
|
||||
{
|
||||
struct esas2r_target *t = a->targetdb + target;
|
||||
u32 cplen = length;
|
||||
unsigned long flags;
|
||||
|
||||
if (cplen > sizeof(t->lu_event))
|
||||
cplen = sizeof(t->lu_event);
|
||||
|
||||
esas2r_trace("ae->lu.dwevent: %x", ae->lu.dwevent);
|
||||
esas2r_trace("ae->lu.bystate: %x", ae->lu.bystate);
|
||||
|
||||
spin_lock_irqsave(&a->mem_lock, flags);
|
||||
|
||||
t->new_target_state = TS_INVALID;
|
||||
|
||||
if (ae->lu.dwevent & VDAAE_LU_LOST) {
|
||||
t->new_target_state = TS_NOT_PRESENT;
|
||||
} else {
|
||||
switch (ae->lu.bystate) {
|
||||
case VDAAE_LU_NOT_PRESENT:
|
||||
case VDAAE_LU_OFFLINE:
|
||||
case VDAAE_LU_DELETED:
|
||||
case VDAAE_LU_FACTORY_DISABLED:
|
||||
t->new_target_state = TS_NOT_PRESENT;
|
||||
break;
|
||||
|
||||
case VDAAE_LU_ONLINE:
|
||||
case VDAAE_LU_DEGRADED:
|
||||
t->new_target_state = TS_PRESENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (t->new_target_state != TS_INVALID) {
|
||||
memcpy(&t->lu_event, &ae->lu, cplen);
|
||||
|
||||
esas2r_disc_queue_event(a, DCDE_DEV_CHANGE);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&a->mem_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void esas2r_ae_complete(struct esas2r_adapter *a, struct esas2r_request *rq)
|
||||
{
|
||||
union atto_vda_ae *ae =
|
||||
(union atto_vda_ae *)rq->vda_rsp_data->ae_data.event_data;
|
||||
u32 length = le32_to_cpu(rq->func_rsp.ae_rsp.length);
|
||||
union atto_vda_ae *last =
|
||||
(union atto_vda_ae *)(rq->vda_rsp_data->ae_data.event_data
|
||||
+ length);
|
||||
|
||||
esas2r_trace_enter();
|
||||
esas2r_trace("length: %d", length);
|
||||
|
||||
if (length > sizeof(struct atto_vda_ae_data)
|
||||
|| (length & 3) != 0
|
||||
|| length == 0) {
|
||||
esas2r_log(ESAS2R_LOG_WARN,
|
||||
"The AE request response length (%p) is too long: %d",
|
||||
rq, length);
|
||||
|
||||
esas2r_hdebug("aereq->length (0x%x) too long", length);
|
||||
esas2r_bugon();
|
||||
|
||||
last = ae;
|
||||
}
|
||||
|
||||
while (ae < last) {
|
||||
u16 target;
|
||||
|
||||
esas2r_trace("ae: %p", ae);
|
||||
esas2r_trace("ae->hdr: %p", &(ae->hdr));
|
||||
|
||||
length = ae->hdr.bylength;
|
||||
|
||||
if (length > (u32)((u8 *)last - (u8 *)ae)
|
||||
|| (length & 3) != 0
|
||||
|| length == 0) {
|
||||
esas2r_log(ESAS2R_LOG_CRIT,
|
||||
"the async event length is invalid (%p): %d",
|
||||
ae, length);
|
||||
|
||||
esas2r_hdebug("ae->hdr.length (0x%x) invalid", length);
|
||||
esas2r_bugon();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
esas2r_nuxi_ae_data(ae);
|
||||
|
||||
esas2r_queue_fw_event(a, fw_event_vda_ae, ae,
|
||||
sizeof(union atto_vda_ae));
|
||||
|
||||
switch (ae->hdr.bytype) {
|
||||
case VDAAE_HDR_TYPE_RAID:
|
||||
|
||||
if (ae->raid.dwflags & (VDAAE_GROUP_STATE
|
||||
| VDAAE_RBLD_STATE
|
||||
| VDAAE_MEMBER_CHG
|
||||
| VDAAE_PART_CHG)) {
|
||||
esas2r_log(ESAS2R_LOG_INFO,
|
||||
"RAID event received - name:%s rebuild_state:%d group_state:%d",
|
||||
ae->raid.acname,
|
||||
ae->raid.byrebuild_state,
|
||||
ae->raid.bygroup_state);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VDAAE_HDR_TYPE_LU:
|
||||
esas2r_log(ESAS2R_LOG_INFO,
|
||||
"LUN event received: event:%d target_id:%d LUN:%d state:%d",
|
||||
ae->lu.dwevent,
|
||||
ae->lu.id.tgtlun.wtarget_id,
|
||||
ae->lu.id.tgtlun.bylun,
|
||||
ae->lu.bystate);
|
||||
|
||||
target = ae->lu.id.tgtlun.wtarget_id;
|
||||
|
||||
if (target < ESAS2R_MAX_TARGETS)
|
||||
esas2r_lun_event(a, ae, target, length);
|
||||
|
||||
break;
|
||||
|
||||
case VDAAE_HDR_TYPE_DISK:
|
||||
esas2r_log(ESAS2R_LOG_INFO, "Disk event received");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* Silently ignore the rest and let the apps deal with
|
||||
* them.
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ae = (union atto_vda_ae *)((u8 *)ae + length);
|
||||
}
|
||||
|
||||
/* Now requeue it. */
|
||||
esas2r_start_ae_request(a, rq);
|
||||
esas2r_trace_exit();
|
||||
}
|
||||
|
||||
/* Send an asynchronous event for a chip reset or power management. */
|
||||
void esas2r_send_reset_ae(struct esas2r_adapter *a, bool pwr_mgt)
|
||||
{
|
||||
struct atto_vda_ae_hdr ae;
|
||||
|
||||
if (pwr_mgt)
|
||||
ae.bytype = VDAAE_HDR_TYPE_PWRMGT;
|
||||
else
|
||||
ae.bytype = VDAAE_HDR_TYPE_RESET;
|
||||
|
||||
ae.byversion = VDAAE_HDR_VER_0;
|
||||
ae.byflags = 0;
|
||||
ae.bylength = (u8)sizeof(struct atto_vda_ae_hdr);
|
||||
|
||||
if (pwr_mgt)
|
||||
esas2r_hdebug("*** sending power management AE ***");
|
||||
else
|
||||
esas2r_hdebug("*** sending reset AE ***");
|
||||
|
||||
esas2r_queue_fw_event(a, fw_event_vda_ae, &ae,
|
||||
sizeof(union atto_vda_ae));
|
||||
}
|
||||
|
||||
void esas2r_dummy_complete(struct esas2r_adapter *a, struct esas2r_request *rq)
|
||||
{}
|
||||
|
||||
static void esas2r_check_req_rsp_sense(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq)
|
||||
{
|
||||
u8 snslen, snslen2;
|
||||
|
||||
snslen = snslen2 = rq->func_rsp.scsi_rsp.sense_len;
|
||||
|
||||
if (snslen > rq->sense_len)
|
||||
snslen = rq->sense_len;
|
||||
|
||||
if (snslen) {
|
||||
if (rq->sense_buf)
|
||||
memcpy(rq->sense_buf, rq->data_buf, snslen);
|
||||
else
|
||||
rq->sense_buf = (u8 *)rq->data_buf;
|
||||
|
||||
/* See about possible sense data */
|
||||
if (snslen2 > 0x0c) {
|
||||
u8 *s = (u8 *)rq->data_buf;
|
||||
|
||||
esas2r_trace_enter();
|
||||
|
||||
/* Report LUNS data has changed */
|
||||
if (s[0x0c] == 0x3f && s[0x0d] == 0x0E) {
|
||||
esas2r_trace("rq->target_id: %d",
|
||||
rq->target_id);
|
||||
esas2r_target_state_changed(a, rq->target_id,
|
||||
TS_LUN_CHANGE);
|
||||
}
|
||||
|
||||
esas2r_trace("add_sense_key=%x", s[0x0c]);
|
||||
esas2r_trace("add_sense_qual=%x", s[0x0d]);
|
||||
esas2r_trace_exit();
|
||||
}
|
||||
}
|
||||
|
||||
rq->sense_len = snslen;
|
||||
}
|
||||
|
||||
|
||||
void esas2r_complete_request(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq)
|
||||
{
|
||||
if (rq->vrq->scsi.function == VDA_FUNC_FLASH
|
||||
&& rq->vrq->flash.sub_func == VDA_FLASH_COMMIT)
|
||||
esas2r_lock_clear_flags(&a->flags, AF_FLASHING);
|
||||
|
||||
/* See if we setup a callback to do special processing */
|
||||
|
||||
if (rq->interrupt_cb) {
|
||||
(*rq->interrupt_cb)(a, rq);
|
||||
|
||||
if (rq->req_stat == RS_PENDING) {
|
||||
esas2r_start_request(a, rq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)
|
||||
&& unlikely(rq->req_stat != RS_SUCCESS)) {
|
||||
esas2r_check_req_rsp_sense(a, rq);
|
||||
esas2r_log_request_failure(a, rq);
|
||||
}
|
||||
|
||||
(*rq->comp_cb)(a, rq);
|
||||
}
|
880
drivers/scsi/esas2r/esas2r_io.c
Normal file
880
drivers/scsi/esas2r/esas2r_io.c
Normal file
@ -0,0 +1,880 @@
|
||||
/*
|
||||
* linux/drivers/scsi/esas2r/esas2r_io.c
|
||||
* For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
|
||||
*
|
||||
* Copyright (c) 2001-2013 ATTO Technology, Inc.
|
||||
* (mailto:linuxdrivers@attotech.com)mpt3sas/mpt3sas_trigger_diag.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
||||
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
||||
* solely responsible for determining the appropriateness of using and
|
||||
* distributing the Program and assumes all risks associated with its
|
||||
* exercise of rights under this Agreement, including but not limited to
|
||||
* the risks and costs of program errors, damage to or loss of data,
|
||||
* programs or equipment, and unavailability or interruption of operations.
|
||||
*
|
||||
* DISCLAIMER OF LIABILITY
|
||||
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
||||
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include "esas2r.h"
|
||||
|
||||
void esas2r_start_request(struct esas2r_adapter *a, struct esas2r_request *rq)
|
||||
{
|
||||
struct esas2r_target *t = NULL;
|
||||
struct esas2r_request *startrq = rq;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(a->flags & (AF_DEGRADED_MODE | AF_POWER_DOWN))) {
|
||||
if (rq->vrq->scsi.function == VDA_FUNC_SCSI)
|
||||
rq->req_stat = RS_SEL2;
|
||||
else
|
||||
rq->req_stat = RS_DEGRADED;
|
||||
} else if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)) {
|
||||
t = a->targetdb + rq->target_id;
|
||||
|
||||
if (unlikely(t >= a->targetdb_end
|
||||
|| !(t->flags & TF_USED))) {
|
||||
rq->req_stat = RS_SEL;
|
||||
} else {
|
||||
/* copy in the target ID. */
|
||||
rq->vrq->scsi.target_id = cpu_to_le16(t->virt_targ_id);
|
||||
|
||||
/*
|
||||
* Test if we want to report RS_SEL for missing target.
|
||||
* Note that if AF_DISC_PENDING is set than this will
|
||||
* go on the defer queue.
|
||||
*/
|
||||
if (unlikely(t->target_state != TS_PRESENT
|
||||
&& !(a->flags & AF_DISC_PENDING)))
|
||||
rq->req_stat = RS_SEL;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(rq->req_stat != RS_PENDING)) {
|
||||
esas2r_complete_request(a, rq);
|
||||
return;
|
||||
}
|
||||
|
||||
esas2r_trace("rq=%p", rq);
|
||||
esas2r_trace("rq->vrq->scsi.handle=%x", rq->vrq->scsi.handle);
|
||||
|
||||
if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {
|
||||
esas2r_trace("rq->target_id=%d", rq->target_id);
|
||||
esas2r_trace("rq->vrq->scsi.flags=%x", rq->vrq->scsi.flags);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&a->queue_lock, flags);
|
||||
|
||||
if (likely(list_empty(&a->defer_list) &&
|
||||
!(a->flags &
|
||||
(AF_CHPRST_PENDING | AF_FLASHING | AF_DISC_PENDING))))
|
||||
esas2r_local_start_request(a, startrq);
|
||||
else
|
||||
list_add_tail(&startrq->req_list, &a->defer_list);
|
||||
|
||||
spin_unlock_irqrestore(&a->queue_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Starts the specified request. all requests have RS_PENDING set when this
|
||||
* routine is called. The caller is usually esas2r_start_request, but
|
||||
* esas2r_do_deferred_processes will start request that are deferred.
|
||||
*
|
||||
* The caller must ensure that requests can be started.
|
||||
*
|
||||
* esas2r_start_request will defer a request if there are already requests
|
||||
* waiting or there is a chip reset pending. once the reset condition clears,
|
||||
* esas2r_do_deferred_processes will call this function to start the request.
|
||||
*
|
||||
* When a request is started, it is placed on the active list and queued to
|
||||
* the controller.
|
||||
*/
|
||||
void esas2r_local_start_request(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq)
|
||||
{
|
||||
esas2r_trace_enter();
|
||||
esas2r_trace("rq=%p", rq);
|
||||
esas2r_trace("rq->vrq:%p", rq->vrq);
|
||||
esas2r_trace("rq->vrq_md->phys_addr:%x", rq->vrq_md->phys_addr);
|
||||
|
||||
if (unlikely(rq->vrq->scsi.function == VDA_FUNC_FLASH
|
||||
&& rq->vrq->flash.sub_func == VDA_FLASH_COMMIT))
|
||||
esas2r_lock_set_flags(&a->flags, AF_FLASHING);
|
||||
|
||||
list_add_tail(&rq->req_list, &a->active_list);
|
||||
esas2r_start_vda_request(a, rq);
|
||||
esas2r_trace_exit();
|
||||
return;
|
||||
}
|
||||
|
||||
void esas2r_start_vda_request(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq)
|
||||
{
|
||||
struct esas2r_inbound_list_source_entry *element;
|
||||
u32 dw;
|
||||
|
||||
rq->req_stat = RS_STARTED;
|
||||
/*
|
||||
* Calculate the inbound list entry location and the current state of
|
||||
* toggle bit.
|
||||
*/
|
||||
a->last_write++;
|
||||
if (a->last_write >= a->list_size) {
|
||||
a->last_write = 0;
|
||||
/* update the toggle bit */
|
||||
if (a->flags & AF_COMM_LIST_TOGGLE)
|
||||
esas2r_lock_clear_flags(&a->flags,
|
||||
AF_COMM_LIST_TOGGLE);
|
||||
else
|
||||
esas2r_lock_set_flags(&a->flags, AF_COMM_LIST_TOGGLE);
|
||||
}
|
||||
|
||||
element =
|
||||
(struct esas2r_inbound_list_source_entry *)a->inbound_list_md.
|
||||
virt_addr
|
||||
+ a->last_write;
|
||||
|
||||
/* Set the VDA request size if it was never modified */
|
||||
if (rq->vda_req_sz == RQ_SIZE_DEFAULT)
|
||||
rq->vda_req_sz = (u16)(a->max_vdareq_size / sizeof(u32));
|
||||
|
||||
element->address = cpu_to_le64(rq->vrq_md->phys_addr);
|
||||
element->length = cpu_to_le32(rq->vda_req_sz);
|
||||
|
||||
/* Update the write pointer */
|
||||
dw = a->last_write;
|
||||
|
||||
if (a->flags & AF_COMM_LIST_TOGGLE)
|
||||
dw |= MU_ILW_TOGGLE;
|
||||
|
||||
esas2r_trace("rq->vrq->scsi.handle:%x", rq->vrq->scsi.handle);
|
||||
esas2r_trace("dw:%x", dw);
|
||||
esas2r_trace("rq->vda_req_sz:%x", rq->vda_req_sz);
|
||||
esas2r_write_register_dword(a, MU_IN_LIST_WRITE, dw);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the scatter/gather list for an I/O request according to the
|
||||
* specifications placed in the s/g context. The caller must initialize
|
||||
* context prior to the initial call by calling esas2r_sgc_init().
|
||||
*/
|
||||
bool esas2r_build_sg_list_sge(struct esas2r_adapter *a,
|
||||
struct esas2r_sg_context *sgc)
|
||||
{
|
||||
struct esas2r_request *rq = sgc->first_req;
|
||||
union atto_vda_req *vrq = rq->vrq;
|
||||
|
||||
while (sgc->length) {
|
||||
u32 rem = 0;
|
||||
u64 addr;
|
||||
u32 len;
|
||||
|
||||
len = (*sgc->get_phys_addr)(sgc, &addr);
|
||||
|
||||
if (unlikely(len == 0))
|
||||
return false;
|
||||
|
||||
/* if current length is more than what's left, stop there */
|
||||
if (unlikely(len > sgc->length))
|
||||
len = sgc->length;
|
||||
|
||||
another_entry:
|
||||
/* limit to a round number less than the maximum length */
|
||||
if (len > SGE_LEN_MAX) {
|
||||
/*
|
||||
* Save the remainder of the split. Whenever we limit
|
||||
* an entry we come back around to build entries out
|
||||
* of the leftover. We do this to prevent multiple
|
||||
* calls to the get_phys_addr() function for an SGE
|
||||
* that is too large.
|
||||
*/
|
||||
rem = len - SGE_LEN_MAX;
|
||||
len = SGE_LEN_MAX;
|
||||
}
|
||||
|
||||
/* See if we need to allocate a new SGL */
|
||||
if (unlikely(sgc->sge.a64.curr > sgc->sge.a64.limit)) {
|
||||
u8 sgelen;
|
||||
struct esas2r_mem_desc *sgl;
|
||||
|
||||
/*
|
||||
* If no SGls are available, return failure. The
|
||||
* caller can call us later with the current context
|
||||
* to pick up here.
|
||||
*/
|
||||
sgl = esas2r_alloc_sgl(a);
|
||||
|
||||
if (unlikely(sgl == NULL))
|
||||
return false;
|
||||
|
||||
/* Calculate the length of the last SGE filled in */
|
||||
sgelen = (u8)((u8 *)sgc->sge.a64.curr
|
||||
- (u8 *)sgc->sge.a64.last);
|
||||
|
||||
/*
|
||||
* Copy the last SGE filled in to the first entry of
|
||||
* the new SGL to make room for the chain entry.
|
||||
*/
|
||||
memcpy(sgl->virt_addr, sgc->sge.a64.last, sgelen);
|
||||
|
||||
/* Figure out the new curr pointer in the new segment */
|
||||
sgc->sge.a64.curr =
|
||||
(struct atto_vda_sge *)((u8 *)sgl->virt_addr +
|
||||
sgelen);
|
||||
|
||||
/* Set the limit pointer and build the chain entry */
|
||||
sgc->sge.a64.limit =
|
||||
(struct atto_vda_sge *)((u8 *)sgl->virt_addr
|
||||
+ sgl_page_size
|
||||
- sizeof(struct
|
||||
atto_vda_sge));
|
||||
sgc->sge.a64.last->length = cpu_to_le32(
|
||||
SGE_CHAIN | SGE_ADDR_64);
|
||||
sgc->sge.a64.last->address =
|
||||
cpu_to_le64(sgl->phys_addr);
|
||||
|
||||
/*
|
||||
* Now, if there was a previous chain entry, then
|
||||
* update it to contain the length of this segment
|
||||
* and size of this chain. otherwise this is the
|
||||
* first SGL, so set the chain_offset in the request.
|
||||
*/
|
||||
if (sgc->sge.a64.chain) {
|
||||
sgc->sge.a64.chain->length |=
|
||||
cpu_to_le32(
|
||||
((u8 *)(sgc->sge.a64.
|
||||
last + 1)
|
||||
- (u8 *)rq->sg_table->
|
||||
virt_addr)
|
||||
+ sizeof(struct atto_vda_sge) *
|
||||
LOBIT(SGE_CHAIN_SZ));
|
||||
} else {
|
||||
vrq->scsi.chain_offset = (u8)
|
||||
((u8 *)sgc->
|
||||
sge.a64.last -
|
||||
(u8 *)vrq);
|
||||
|
||||
/*
|
||||
* This is the first SGL, so set the
|
||||
* chain_offset and the VDA request size in
|
||||
* the request.
|
||||
*/
|
||||
rq->vda_req_sz =
|
||||
(vrq->scsi.chain_offset +
|
||||
sizeof(struct atto_vda_sge) +
|
||||
3)
|
||||
/ sizeof(u32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remember this so when we get a new SGL filled in we
|
||||
* can update the length of this chain entry.
|
||||
*/
|
||||
sgc->sge.a64.chain = sgc->sge.a64.last;
|
||||
|
||||
/* Now link the new SGL onto the primary request. */
|
||||
list_add(&sgl->next_desc, &rq->sg_table_head);
|
||||
}
|
||||
|
||||
/* Update last one filled in */
|
||||
sgc->sge.a64.last = sgc->sge.a64.curr;
|
||||
|
||||
/* Build the new SGE and update the S/G context */
|
||||
sgc->sge.a64.curr->length = cpu_to_le32(SGE_ADDR_64 | len);
|
||||
sgc->sge.a64.curr->address = cpu_to_le32(addr);
|
||||
sgc->sge.a64.curr++;
|
||||
sgc->cur_offset += len;
|
||||
sgc->length -= len;
|
||||
|
||||
/*
|
||||
* Check if we previously split an entry. If so we have to
|
||||
* pick up where we left off.
|
||||
*/
|
||||
if (rem) {
|
||||
addr += len;
|
||||
len = rem;
|
||||
rem = 0;
|
||||
goto another_entry;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark the end of the SGL */
|
||||
sgc->sge.a64.last->length |= cpu_to_le32(SGE_LAST);
|
||||
|
||||
/*
|
||||
* If there was a previous chain entry, update the length to indicate
|
||||
* the length of this last segment.
|
||||
*/
|
||||
if (sgc->sge.a64.chain) {
|
||||
sgc->sge.a64.chain->length |= cpu_to_le32(
|
||||
((u8 *)(sgc->sge.a64.curr) -
|
||||
(u8 *)rq->sg_table->virt_addr));
|
||||
} else {
|
||||
u16 reqsize;
|
||||
|
||||
/*
|
||||
* The entire VDA request was not used so lets
|
||||
* set the size of the VDA request to be DMA'd
|
||||
*/
|
||||
reqsize =
|
||||
((u16)((u8 *)sgc->sge.a64.last - (u8 *)vrq)
|
||||
+ sizeof(struct atto_vda_sge) + 3) / sizeof(u32);
|
||||
|
||||
/*
|
||||
* Only update the request size if it is bigger than what is
|
||||
* already there. We can come in here twice for some management
|
||||
* commands.
|
||||
*/
|
||||
if (reqsize > rq->vda_req_sz)
|
||||
rq->vda_req_sz = reqsize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create PRD list for each I-block consumed by the command. This routine
|
||||
* determines how much data is required from each I-block being consumed
|
||||
* by the command. The first and last I-blocks can be partials and all of
|
||||
* the I-blocks in between are for a full I-block of data.
|
||||
*
|
||||
* The interleave size is used to determine the number of bytes in the 1st
|
||||
* I-block and the remaining I-blocks are what remeains.
|
||||
*/
|
||||
static bool esas2r_build_prd_iblk(struct esas2r_adapter *a,
|
||||
struct esas2r_sg_context *sgc)
|
||||
{
|
||||
struct esas2r_request *rq = sgc->first_req;
|
||||
u64 addr;
|
||||
u32 len;
|
||||
struct esas2r_mem_desc *sgl;
|
||||
u32 numchain = 1;
|
||||
u32 rem = 0;
|
||||
|
||||
while (sgc->length) {
|
||||
/* Get the next address/length pair */
|
||||
|
||||
len = (*sgc->get_phys_addr)(sgc, &addr);
|
||||
|
||||
if (unlikely(len == 0))
|
||||
return false;
|
||||
|
||||
/* If current length is more than what's left, stop there */
|
||||
|
||||
if (unlikely(len > sgc->length))
|
||||
len = sgc->length;
|
||||
|
||||
another_entry:
|
||||
/* Limit to a round number less than the maximum length */
|
||||
|
||||
if (len > PRD_LEN_MAX) {
|
||||
/*
|
||||
* Save the remainder of the split. whenever we limit
|
||||
* an entry we come back around to build entries out
|
||||
* of the leftover. We do this to prevent multiple
|
||||
* calls to the get_phys_addr() function for an SGE
|
||||
* that is too large.
|
||||
*/
|
||||
rem = len - PRD_LEN_MAX;
|
||||
len = PRD_LEN_MAX;
|
||||
}
|
||||
|
||||
/* See if we need to allocate a new SGL */
|
||||
if (sgc->sge.prd.sge_cnt == 0) {
|
||||
if (len == sgc->length) {
|
||||
/*
|
||||
* We only have 1 PRD entry left.
|
||||
* It can be placed where the chain
|
||||
* entry would have gone
|
||||
*/
|
||||
|
||||
/* Build the simple SGE */
|
||||
sgc->sge.prd.curr->ctl_len = cpu_to_le32(
|
||||
PRD_DATA | len);
|
||||
sgc->sge.prd.curr->address = cpu_to_le64(addr);
|
||||
|
||||
/* Adjust length related fields */
|
||||
sgc->cur_offset += len;
|
||||
sgc->length -= len;
|
||||
|
||||
/* We use the reserved chain entry for data */
|
||||
numchain = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (sgc->sge.prd.chain) {
|
||||
/*
|
||||
* Fill # of entries of current SGL in previous
|
||||
* chain the length of this current SGL may not
|
||||
* full.
|
||||
*/
|
||||
|
||||
sgc->sge.prd.chain->ctl_len |= cpu_to_le32(
|
||||
sgc->sge.prd.sgl_max_cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* If no SGls are available, return failure. The
|
||||
* caller can call us later with the current context
|
||||
* to pick up here.
|
||||
*/
|
||||
|
||||
sgl = esas2r_alloc_sgl(a);
|
||||
|
||||
if (unlikely(sgl == NULL))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Link the new SGL onto the chain
|
||||
* They are in reverse order
|
||||
*/
|
||||
list_add(&sgl->next_desc, &rq->sg_table_head);
|
||||
|
||||
/*
|
||||
* An SGL was just filled in and we are starting
|
||||
* a new SGL. Prime the chain of the ending SGL with
|
||||
* info that points to the new SGL. The length gets
|
||||
* filled in when the new SGL is filled or ended
|
||||
*/
|
||||
|
||||
sgc->sge.prd.chain = sgc->sge.prd.curr;
|
||||
|
||||
sgc->sge.prd.chain->ctl_len = cpu_to_le32(PRD_CHAIN);
|
||||
sgc->sge.prd.chain->address =
|
||||
cpu_to_le64(sgl->phys_addr);
|
||||
|
||||
/*
|
||||
* Start a new segment.
|
||||
* Take one away and save for chain SGE
|
||||
*/
|
||||
|
||||
sgc->sge.prd.curr =
|
||||
(struct atto_physical_region_description *)sgl
|
||||
->
|
||||
virt_addr;
|
||||
sgc->sge.prd.sge_cnt = sgc->sge.prd.sgl_max_cnt - 1;
|
||||
}
|
||||
|
||||
sgc->sge.prd.sge_cnt--;
|
||||
/* Build the simple SGE */
|
||||
sgc->sge.prd.curr->ctl_len = cpu_to_le32(PRD_DATA | len);
|
||||
sgc->sge.prd.curr->address = cpu_to_le64(addr);
|
||||
|
||||
/* Used another element. Point to the next one */
|
||||
|
||||
sgc->sge.prd.curr++;
|
||||
|
||||
/* Adjust length related fields */
|
||||
|
||||
sgc->cur_offset += len;
|
||||
sgc->length -= len;
|
||||
|
||||
/*
|
||||
* Check if we previously split an entry. If so we have to
|
||||
* pick up where we left off.
|
||||
*/
|
||||
|
||||
if (rem) {
|
||||
addr += len;
|
||||
len = rem;
|
||||
rem = 0;
|
||||
goto another_entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (!list_empty(&rq->sg_table_head)) {
|
||||
if (sgc->sge.prd.chain) {
|
||||
sgc->sge.prd.chain->ctl_len |=
|
||||
cpu_to_le32(sgc->sge.prd.sgl_max_cnt
|
||||
- sgc->sge.prd.sge_cnt
|
||||
- numchain);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool esas2r_build_sg_list_prd(struct esas2r_adapter *a,
|
||||
struct esas2r_sg_context *sgc)
|
||||
{
|
||||
struct esas2r_request *rq = sgc->first_req;
|
||||
u32 len = sgc->length;
|
||||
struct esas2r_target *t = a->targetdb + rq->target_id;
|
||||
u8 is_i_o = 0;
|
||||
u16 reqsize;
|
||||
struct atto_physical_region_description *curr_iblk_chn;
|
||||
u8 *cdb = (u8 *)&rq->vrq->scsi.cdb[0];
|
||||
|
||||
/*
|
||||
* extract LBA from command so we can determine
|
||||
* the I-Block boundary
|
||||
*/
|
||||
|
||||
if (rq->vrq->scsi.function == VDA_FUNC_SCSI
|
||||
&& t->target_state == TS_PRESENT
|
||||
&& !(t->flags & TF_PASS_THRU)) {
|
||||
u32 lbalo = 0;
|
||||
|
||||
switch (rq->vrq->scsi.cdb[0]) {
|
||||
case READ_16:
|
||||
case WRITE_16:
|
||||
{
|
||||
lbalo =
|
||||
MAKEDWORD(MAKEWORD(cdb[9],
|
||||
cdb[8]),
|
||||
MAKEWORD(cdb[7],
|
||||
cdb[6]));
|
||||
is_i_o = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case READ_12:
|
||||
case WRITE_12:
|
||||
case READ_10:
|
||||
case WRITE_10:
|
||||
{
|
||||
lbalo =
|
||||
MAKEDWORD(MAKEWORD(cdb[5],
|
||||
cdb[4]),
|
||||
MAKEWORD(cdb[3],
|
||||
cdb[2]));
|
||||
is_i_o = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case READ_6:
|
||||
case WRITE_6:
|
||||
{
|
||||
lbalo =
|
||||
MAKEDWORD(MAKEWORD(cdb[3],
|
||||
cdb[2]),
|
||||
MAKEWORD(cdb[1] & 0x1F,
|
||||
0));
|
||||
is_i_o = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_i_o) {
|
||||
u32 startlba;
|
||||
|
||||
rq->vrq->scsi.iblk_cnt_prd = 0;
|
||||
|
||||
/* Determine size of 1st I-block PRD list */
|
||||
startlba = t->inter_block - (lbalo & (t->inter_block -
|
||||
1));
|
||||
sgc->length = startlba * t->block_size;
|
||||
|
||||
/* Chk if the 1st iblk chain starts at base of Iblock */
|
||||
if ((lbalo & (t->inter_block - 1)) == 0)
|
||||
rq->flags |= RF_1ST_IBLK_BASE;
|
||||
|
||||
if (sgc->length > len)
|
||||
sgc->length = len;
|
||||
} else {
|
||||
sgc->length = len;
|
||||
}
|
||||
} else {
|
||||
sgc->length = len;
|
||||
}
|
||||
|
||||
/* get our starting chain address */
|
||||
|
||||
curr_iblk_chn =
|
||||
(struct atto_physical_region_description *)sgc->sge.a64.curr;
|
||||
|
||||
sgc->sge.prd.sgl_max_cnt = sgl_page_size /
|
||||
sizeof(struct
|
||||
atto_physical_region_description);
|
||||
|
||||
/* create all of the I-block PRD lists */
|
||||
|
||||
while (len) {
|
||||
sgc->sge.prd.sge_cnt = 0;
|
||||
sgc->sge.prd.chain = NULL;
|
||||
sgc->sge.prd.curr = curr_iblk_chn;
|
||||
|
||||
/* increment to next I-Block */
|
||||
|
||||
len -= sgc->length;
|
||||
|
||||
/* go build the next I-Block PRD list */
|
||||
|
||||
if (unlikely(!esas2r_build_prd_iblk(a, sgc)))
|
||||
return false;
|
||||
|
||||
curr_iblk_chn++;
|
||||
|
||||
if (is_i_o) {
|
||||
rq->vrq->scsi.iblk_cnt_prd++;
|
||||
|
||||
if (len > t->inter_byte)
|
||||
sgc->length = t->inter_byte;
|
||||
else
|
||||
sgc->length = len;
|
||||
}
|
||||
}
|
||||
|
||||
/* figure out the size used of the VDA request */
|
||||
|
||||
reqsize = ((u16)((u8 *)curr_iblk_chn - (u8 *)rq->vrq))
|
||||
/ sizeof(u32);
|
||||
|
||||
/*
|
||||
* only update the request size if it is bigger than what is
|
||||
* already there. we can come in here twice for some management
|
||||
* commands.
|
||||
*/
|
||||
|
||||
if (reqsize > rq->vda_req_sz)
|
||||
rq->vda_req_sz = reqsize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void esas2r_handle_pending_reset(struct esas2r_adapter *a, u32 currtime)
|
||||
{
|
||||
u32 delta = currtime - a->chip_init_time;
|
||||
|
||||
if (delta <= ESAS2R_CHPRST_WAIT_TIME) {
|
||||
/* Wait before accessing registers */
|
||||
} else if (delta >= ESAS2R_CHPRST_TIME) {
|
||||
/*
|
||||
* The last reset failed so try again. Reset
|
||||
* processing will give up after three tries.
|
||||
*/
|
||||
esas2r_local_reset_adapter(a);
|
||||
} else {
|
||||
/* We can now see if the firmware is ready */
|
||||
u32 doorbell;
|
||||
|
||||
doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
|
||||
if (doorbell == 0xFFFFFFFF || !(doorbell & DRBL_FORCE_INT)) {
|
||||
esas2r_force_interrupt(a);
|
||||
} else {
|
||||
u32 ver = (doorbell & DRBL_FW_VER_MSK);
|
||||
|
||||
/* Driver supports API version 0 and 1 */
|
||||
esas2r_write_register_dword(a, MU_DOORBELL_OUT,
|
||||
doorbell);
|
||||
if (ver == DRBL_FW_VER_0) {
|
||||
esas2r_lock_set_flags(&a->flags,
|
||||
AF_CHPRST_DETECTED);
|
||||
esas2r_lock_set_flags(&a->flags,
|
||||
AF_LEGACY_SGE_MODE);
|
||||
|
||||
a->max_vdareq_size = 128;
|
||||
a->build_sgl = esas2r_build_sg_list_sge;
|
||||
} else if (ver == DRBL_FW_VER_1) {
|
||||
esas2r_lock_set_flags(&a->flags,
|
||||
AF_CHPRST_DETECTED);
|
||||
esas2r_lock_clear_flags(&a->flags,
|
||||
AF_LEGACY_SGE_MODE);
|
||||
|
||||
a->max_vdareq_size = 1024;
|
||||
a->build_sgl = esas2r_build_sg_list_prd;
|
||||
} else {
|
||||
esas2r_local_reset_adapter(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This function must be called once per timer tick */
|
||||
void esas2r_timer_tick(struct esas2r_adapter *a)
|
||||
{
|
||||
u32 currtime = jiffies_to_msecs(jiffies);
|
||||
u32 deltatime = currtime - a->last_tick_time;
|
||||
|
||||
a->last_tick_time = currtime;
|
||||
|
||||
/* count down the uptime */
|
||||
if (a->chip_uptime
|
||||
&& !(a->flags & (AF_CHPRST_PENDING | AF_DISC_PENDING))) {
|
||||
if (deltatime >= a->chip_uptime)
|
||||
a->chip_uptime = 0;
|
||||
else
|
||||
a->chip_uptime -= deltatime;
|
||||
}
|
||||
|
||||
if (a->flags & AF_CHPRST_PENDING) {
|
||||
if (!(a->flags & AF_CHPRST_NEEDED)
|
||||
&& !(a->flags & AF_CHPRST_DETECTED))
|
||||
esas2r_handle_pending_reset(a, currtime);
|
||||
} else {
|
||||
if (a->flags & AF_DISC_PENDING)
|
||||
esas2r_disc_check_complete(a);
|
||||
|
||||
if (a->flags & AF_HEARTBEAT_ENB) {
|
||||
if (a->flags & AF_HEARTBEAT) {
|
||||
if ((currtime - a->heartbeat_time) >=
|
||||
ESAS2R_HEARTBEAT_TIME) {
|
||||
esas2r_lock_clear_flags(&a->flags,
|
||||
AF_HEARTBEAT);
|
||||
esas2r_hdebug("heartbeat failed");
|
||||
esas2r_log(ESAS2R_LOG_CRIT,
|
||||
"heartbeat failed");
|
||||
esas2r_bugon();
|
||||
esas2r_local_reset_adapter(a);
|
||||
}
|
||||
} else {
|
||||
esas2r_lock_set_flags(&a->flags, AF_HEARTBEAT);
|
||||
a->heartbeat_time = currtime;
|
||||
esas2r_force_interrupt(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic_read(&a->disable_cnt) == 0)
|
||||
esas2r_do_deferred_processes(a);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the specified task management function to the target and LUN
|
||||
* specified in rqaux. in addition, immediately abort any commands that
|
||||
* are queued but not sent to the device according to the rules specified
|
||||
* by the task management function.
|
||||
*/
|
||||
bool esas2r_send_task_mgmt(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rqaux, u8 task_mgt_func)
|
||||
{
|
||||
u16 targetid = rqaux->target_id;
|
||||
u8 lun = (u8)le32_to_cpu(rqaux->vrq->scsi.flags);
|
||||
bool ret = false;
|
||||
struct esas2r_request *rq;
|
||||
struct list_head *next, *element;
|
||||
unsigned long flags;
|
||||
|
||||
LIST_HEAD(comp_list);
|
||||
|
||||
esas2r_trace_enter();
|
||||
esas2r_trace("rqaux:%p", rqaux);
|
||||
esas2r_trace("task_mgt_func:%x", task_mgt_func);
|
||||
spin_lock_irqsave(&a->queue_lock, flags);
|
||||
|
||||
/* search the defer queue looking for requests for the device */
|
||||
list_for_each_safe(element, next, &a->defer_list) {
|
||||
rq = list_entry(element, struct esas2r_request, req_list);
|
||||
|
||||
if (rq->vrq->scsi.function == VDA_FUNC_SCSI
|
||||
&& rq->target_id == targetid
|
||||
&& (((u8)le32_to_cpu(rq->vrq->scsi.flags)) == lun
|
||||
|| task_mgt_func == 0x20)) { /* target reset */
|
||||
/* Found a request affected by the task management */
|
||||
if (rq->req_stat == RS_PENDING) {
|
||||
/*
|
||||
* The request is pending or waiting. We can
|
||||
* safelycomplete the request now.
|
||||
*/
|
||||
if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
|
||||
list_add_tail(&rq->comp_list,
|
||||
&comp_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the task management request to the firmware */
|
||||
rqaux->sense_len = 0;
|
||||
rqaux->vrq->scsi.length = 0;
|
||||
rqaux->target_id = targetid;
|
||||
rqaux->vrq->scsi.flags |= cpu_to_le32(lun);
|
||||
memset(rqaux->vrq->scsi.cdb, 0, sizeof(rqaux->vrq->scsi.cdb));
|
||||
rqaux->vrq->scsi.flags |=
|
||||
cpu_to_le16(task_mgt_func * LOBIT(FCP_CMND_TM_MASK));
|
||||
|
||||
if (a->flags & AF_FLASHING) {
|
||||
/* Assume success. if there are active requests, return busy */
|
||||
rqaux->req_stat = RS_SUCCESS;
|
||||
|
||||
list_for_each_safe(element, next, &a->active_list) {
|
||||
rq = list_entry(element, struct esas2r_request,
|
||||
req_list);
|
||||
if (rq->vrq->scsi.function == VDA_FUNC_SCSI
|
||||
&& rq->target_id == targetid
|
||||
&& (((u8)le32_to_cpu(rq->vrq->scsi.flags)) == lun
|
||||
|| task_mgt_func == 0x20)) /* target reset */
|
||||
rqaux->req_stat = RS_BUSY;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&a->queue_lock, flags);
|
||||
|
||||
if (!(a->flags & AF_FLASHING))
|
||||
esas2r_start_request(a, rqaux);
|
||||
|
||||
esas2r_comp_list_drain(a, &comp_list);
|
||||
|
||||
if (atomic_read(&a->disable_cnt) == 0)
|
||||
esas2r_do_deferred_processes(a);
|
||||
|
||||
esas2r_trace_exit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void esas2r_reset_bus(struct esas2r_adapter *a)
|
||||
{
|
||||
esas2r_log(ESAS2R_LOG_INFO, "performing a bus reset");
|
||||
|
||||
if (!(a->flags & AF_DEGRADED_MODE)
|
||||
&& !(a->flags & (AF_CHPRST_PENDING | AF_DISC_PENDING))) {
|
||||
esas2r_lock_set_flags(&a->flags, AF_BUSRST_NEEDED);
|
||||
esas2r_lock_set_flags(&a->flags, AF_BUSRST_PENDING);
|
||||
esas2r_lock_set_flags(&a->flags, AF_OS_RESET);
|
||||
|
||||
esas2r_schedule_tasklet(a);
|
||||
}
|
||||
}
|
||||
|
||||
bool esas2r_ioreq_aborted(struct esas2r_adapter *a, struct esas2r_request *rq,
|
||||
u8 status)
|
||||
{
|
||||
esas2r_trace_enter();
|
||||
esas2r_trace("rq:%p", rq);
|
||||
list_del_init(&rq->req_list);
|
||||
if (rq->timeout > RQ_MAX_TIMEOUT) {
|
||||
/*
|
||||
* The request timed out, but we could not abort it because a
|
||||
* chip reset occurred. Return busy status.
|
||||
*/
|
||||
rq->req_stat = RS_BUSY;
|
||||
esas2r_trace_exit();
|
||||
return true;
|
||||
}
|
||||
|
||||
rq->req_stat = status;
|
||||
esas2r_trace_exit();
|
||||
return true;
|
||||
}
|
2110
drivers/scsi/esas2r/esas2r_ioctl.c
Normal file
2110
drivers/scsi/esas2r/esas2r_ioctl.c
Normal file
File diff suppressed because it is too large
Load Diff
254
drivers/scsi/esas2r/esas2r_log.c
Normal file
254
drivers/scsi/esas2r/esas2r_log.c
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* linux/drivers/scsi/esas2r/esas2r_log.c
|
||||
* For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
|
||||
*
|
||||
* Copyright (c) 2001-2013 ATTO Technology, Inc.
|
||||
* (mailto:linuxdrivers@attotech.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
||||
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
||||
* solely responsible for determining the appropriateness of using and
|
||||
* distributing the Program and assumes all risks associated with its
|
||||
* exercise of rights under this Agreement, including but not limited to
|
||||
* the risks and costs of program errors, damage to or loss of data,
|
||||
* programs or equipment, and unavailability or interruption of operations.
|
||||
*
|
||||
* DISCLAIMER OF LIABILITY
|
||||
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
||||
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include "esas2r.h"
|
||||
|
||||
/*
|
||||
* this module within the driver is tasked with providing logging functionality.
|
||||
* the event_log_level module parameter controls the level of messages that are
|
||||
* written to the system log. the default level of messages that are written
|
||||
* are critical and warning messages. if other types of messages are desired,
|
||||
* one simply needs to load the module with the correct value for the
|
||||
* event_log_level module parameter. for example:
|
||||
*
|
||||
* insmod <module> event_log_level=1
|
||||
*
|
||||
* will load the module and only critical events will be written by this module
|
||||
* to the system log. if critical, warning, and information-level messages are
|
||||
* desired, the correct value for the event_log_level module parameter
|
||||
* would be as follows:
|
||||
*
|
||||
* insmod <module> event_log_level=3
|
||||
*/
|
||||
|
||||
#define EVENT_LOG_BUFF_SIZE 1024
|
||||
|
||||
static long event_log_level = ESAS2R_LOG_DFLT;
|
||||
|
||||
module_param(event_log_level, long, S_IRUGO | S_IRUSR);
|
||||
MODULE_PARM_DESC(event_log_level,
|
||||
"Specifies the level of events to report to the system log. Critical and warning level events are logged by default.");
|
||||
|
||||
/* A shared buffer to use for formatting messages. */
|
||||
static char event_buffer[EVENT_LOG_BUFF_SIZE];
|
||||
|
||||
/* A lock to protect the shared buffer used for formatting messages. */
|
||||
static DEFINE_SPINLOCK(event_buffer_lock);
|
||||
|
||||
/**
|
||||
* translates an esas2r-defined logging event level to a kernel logging level.
|
||||
*
|
||||
* @param [in] level the esas2r-defined logging event level to translate
|
||||
*
|
||||
* @return the corresponding kernel logging level.
|
||||
*/
|
||||
static const char *translate_esas2r_event_level_to_kernel(const long level)
|
||||
{
|
||||
switch (level) {
|
||||
case ESAS2R_LOG_CRIT:
|
||||
return KERN_CRIT;
|
||||
|
||||
case ESAS2R_LOG_WARN:
|
||||
return KERN_WARNING;
|
||||
|
||||
case ESAS2R_LOG_INFO:
|
||||
return KERN_INFO;
|
||||
|
||||
case ESAS2R_LOG_DEBG:
|
||||
case ESAS2R_LOG_TRCE:
|
||||
default:
|
||||
return KERN_DEBUG;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* the master logging function. this function will format the message as
|
||||
* outlined by the formatting string, the input device information and the
|
||||
* substitution arguments and output the resulting string to the system log.
|
||||
*
|
||||
* @param [in] level the event log level of the message
|
||||
* @param [in] dev the device information
|
||||
* @param [in] format the formatting string for the message
|
||||
* @param [in] args the substition arguments to the formatting string
|
||||
*
|
||||
* @return 0 on success, or -1 if an error occurred.
|
||||
*/
|
||||
static int esas2r_log_master(const long level,
|
||||
const struct device *dev,
|
||||
const char *format,
|
||||
va_list args)
|
||||
{
|
||||
if (level <= event_log_level) {
|
||||
unsigned long flags = 0;
|
||||
int retval = 0;
|
||||
char *buffer = event_buffer;
|
||||
size_t buflen = EVENT_LOG_BUFF_SIZE;
|
||||
const char *fmt_nodev = "%s%s: ";
|
||||
const char *fmt_dev = "%s%s [%s, %s, %s]";
|
||||
const char *slevel =
|
||||
translate_esas2r_event_level_to_kernel(level);
|
||||
|
||||
spin_lock_irqsave(&event_buffer_lock, flags);
|
||||
|
||||
if (buffer == NULL) {
|
||||
spin_unlock_irqrestore(&event_buffer_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buffer, 0, buflen);
|
||||
|
||||
/*
|
||||
* format the level onto the beginning of the string and do
|
||||
* some pointer arithmetic to move the pointer to the point
|
||||
* where the actual message can be inserted.
|
||||
*/
|
||||
|
||||
if (dev == NULL) {
|
||||
snprintf(buffer, buflen, fmt_nodev, slevel,
|
||||
ESAS2R_DRVR_NAME);
|
||||
} else {
|
||||
snprintf(buffer, buflen, fmt_dev, slevel,
|
||||
ESAS2R_DRVR_NAME,
|
||||
(dev->driver ? dev->driver->name : "unknown"),
|
||||
(dev->bus ? dev->bus->name : "unknown"),
|
||||
dev_name(dev));
|
||||
}
|
||||
|
||||
buffer += strlen(event_buffer);
|
||||
buflen -= strlen(event_buffer);
|
||||
|
||||
retval = vsnprintf(buffer, buflen, format, args);
|
||||
if (retval < 0) {
|
||||
spin_unlock_irqrestore(&event_buffer_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a line break at the end of the formatted string so that
|
||||
* we don't wind up with run-on messages. only append if there
|
||||
* is enough space in the buffer.
|
||||
*/
|
||||
if (strlen(event_buffer) < buflen)
|
||||
strcat(buffer, "\n");
|
||||
|
||||
printk(event_buffer);
|
||||
|
||||
spin_unlock_irqrestore(&event_buffer_lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* formats and logs a message to the system log.
|
||||
*
|
||||
* @param [in] level the event level of the message
|
||||
* @param [in] format the formating string for the message
|
||||
* @param [in] ... the substitution arguments to the formatting string
|
||||
*
|
||||
* @return 0 on success, or -1 if an error occurred.
|
||||
*/
|
||||
int esas2r_log(const long level, const char *format, ...)
|
||||
{
|
||||
int retval = 0;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
retval = esas2r_log_master(level, NULL, format, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* formats and logs a message to the system log. this message will include
|
||||
* device information.
|
||||
*
|
||||
* @param [in] level the event level of the message
|
||||
* @param [in] dev the device information
|
||||
* @param [in] format the formatting string for the message
|
||||
* @param [in] ... the substitution arguments to the formatting string
|
||||
*
|
||||
* @return 0 on success, or -1 if an error occurred.
|
||||
*/
|
||||
int esas2r_log_dev(const long level,
|
||||
const struct device *dev,
|
||||
const char *format,
|
||||
...)
|
||||
{
|
||||
int retval = 0;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
retval = esas2r_log_master(level, dev, format, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* formats and logs a message to the system log. this message will include
|
||||
* device information.
|
||||
*
|
||||
* @param [in] level the event level of the message
|
||||
* @param [in] buf
|
||||
* @param [in] len
|
||||
*
|
||||
* @return 0 on success, or -1 if an error occurred.
|
||||
*/
|
||||
int esas2r_log_hexdump(const long level,
|
||||
const void *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (level <= event_log_level) {
|
||||
print_hex_dump(translate_esas2r_event_level_to_kernel(level),
|
||||
"", DUMP_PREFIX_OFFSET, 16, 1, buf,
|
||||
len, true);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
118
drivers/scsi/esas2r/esas2r_log.h
Normal file
118
drivers/scsi/esas2r/esas2r_log.h
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* linux/drivers/scsi/esas2r/esas2r_log.h
|
||||
* For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
|
||||
*
|
||||
* Copyright (c) 2001-2013 ATTO Technology, Inc.
|
||||
* (mailto:linuxdrivers@attotech.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
||||
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
||||
* solely responsible for determining the appropriateness of using and
|
||||
* distributing the Program and assumes all risks associated with its
|
||||
* exercise of rights under this Agreement, including but not limited to
|
||||
* the risks and costs of program errors, damage to or loss of data,
|
||||
* programs or equipment, and unavailability or interruption of operations.
|
||||
*
|
||||
* DISCLAIMER OF LIABILITY
|
||||
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
||||
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifndef __esas2r_log_h__
|
||||
#define __esas2r_log_h__
|
||||
|
||||
struct device;
|
||||
|
||||
enum {
|
||||
ESAS2R_LOG_NONE = 0, /* no events logged */
|
||||
ESAS2R_LOG_CRIT = 1, /* critical events */
|
||||
ESAS2R_LOG_WARN = 2, /* warning events */
|
||||
ESAS2R_LOG_INFO = 3, /* info events */
|
||||
ESAS2R_LOG_DEBG = 4, /* debugging events */
|
||||
ESAS2R_LOG_TRCE = 5, /* tracing events */
|
||||
|
||||
#ifdef ESAS2R_TRACE
|
||||
ESAS2R_LOG_DFLT = ESAS2R_LOG_TRCE
|
||||
#else
|
||||
ESAS2R_LOG_DFLT = ESAS2R_LOG_WARN
|
||||
#endif
|
||||
};
|
||||
|
||||
int esas2r_log(const long level, const char *format, ...);
|
||||
int esas2r_log_dev(const long level,
|
||||
const struct device *dev,
|
||||
const char *format,
|
||||
...);
|
||||
int esas2r_log_hexdump(const long level,
|
||||
const void *buf,
|
||||
size_t len);
|
||||
|
||||
/*
|
||||
* the following macros are provided specifically for debugging and tracing
|
||||
* messages. esas2r_debug() is provided for generic non-hardware layer
|
||||
* debugging and tracing events. esas2r_hdebug is provided specifically for
|
||||
* hardware layer debugging and tracing events.
|
||||
*/
|
||||
|
||||
#ifdef ESAS2R_DEBUG
|
||||
#define esas2r_debug(f, args ...) esas2r_log(ESAS2R_LOG_DEBG, f, ## args)
|
||||
#define esas2r_hdebug(f, args ...) esas2r_log(ESAS2R_LOG_DEBG, f, ## args)
|
||||
#else
|
||||
#define esas2r_debug(f, args ...)
|
||||
#define esas2r_hdebug(f, args ...)
|
||||
#endif /* ESAS2R_DEBUG */
|
||||
|
||||
/*
|
||||
* the following macros are provided in order to trace the driver and catch
|
||||
* some more serious bugs. be warned, enabling these macros may *severely*
|
||||
* impact performance.
|
||||
*/
|
||||
|
||||
#ifdef ESAS2R_TRACE
|
||||
#define esas2r_bugon() \
|
||||
do { \
|
||||
esas2r_log(ESAS2R_LOG_TRCE, "esas2r_bugon() called in %s:%d" \
|
||||
" - dumping stack and stopping kernel", __func__, \
|
||||
__LINE__); \
|
||||
dump_stack(); \
|
||||
BUG(); \
|
||||
} while (0)
|
||||
|
||||
#define esas2r_trace_enter() esas2r_log(ESAS2R_LOG_TRCE, "entered %s (%s:%d)", \
|
||||
__func__, __FILE__, __LINE__)
|
||||
#define esas2r_trace_exit() esas2r_log(ESAS2R_LOG_TRCE, "exited %s (%s:%d)", \
|
||||
__func__, __FILE__, __LINE__)
|
||||
#define esas2r_trace(f, args ...) esas2r_log(ESAS2R_LOG_TRCE, "(%s:%s:%d): " \
|
||||
f, __func__, __FILE__, __LINE__, \
|
||||
## args)
|
||||
#else
|
||||
#define esas2r_bugon()
|
||||
#define esas2r_trace_enter()
|
||||
#define esas2r_trace_exit()
|
||||
#define esas2r_trace(f, args ...)
|
||||
#endif /* ESAS2R_TRACE */
|
||||
|
||||
#endif /* __esas2r_log_h__ */
|
2032
drivers/scsi/esas2r/esas2r_main.c
Normal file
2032
drivers/scsi/esas2r/esas2r_main.c
Normal file
File diff suppressed because it is too large
Load Diff
306
drivers/scsi/esas2r/esas2r_targdb.c
Normal file
306
drivers/scsi/esas2r/esas2r_targdb.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* linux/drivers/scsi/esas2r/esas2r_targdb.c
|
||||
* For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
|
||||
*
|
||||
* Copyright (c) 2001-2013 ATTO Technology, Inc.
|
||||
* (mailto:linuxdrivers@attotech.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
||||
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
||||
* solely responsible for determining the appropriateness of using and
|
||||
* distributing the Program and assumes all risks associated with its
|
||||
* exercise of rights under this Agreement, including but not limited to
|
||||
* the risks and costs of program errors, damage to or loss of data,
|
||||
* programs or equipment, and unavailability or interruption of operations.
|
||||
*
|
||||
* DISCLAIMER OF LIABILITY
|
||||
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
||||
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include "esas2r.h"
|
||||
|
||||
void esas2r_targ_db_initialize(struct esas2r_adapter *a)
|
||||
{
|
||||
struct esas2r_target *t;
|
||||
|
||||
for (t = a->targetdb; t < a->targetdb_end; t++) {
|
||||
memset(t, 0, sizeof(struct esas2r_target));
|
||||
|
||||
t->target_state = TS_NOT_PRESENT;
|
||||
t->buffered_target_state = TS_NOT_PRESENT;
|
||||
t->new_target_state = TS_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
void esas2r_targ_db_remove_all(struct esas2r_adapter *a, bool notify)
|
||||
{
|
||||
struct esas2r_target *t;
|
||||
unsigned long flags;
|
||||
|
||||
for (t = a->targetdb; t < a->targetdb_end; t++) {
|
||||
if (t->target_state != TS_PRESENT)
|
||||
continue;
|
||||
|
||||
spin_lock_irqsave(&a->mem_lock, flags);
|
||||
esas2r_targ_db_remove(a, t);
|
||||
spin_unlock_irqrestore(&a->mem_lock, flags);
|
||||
|
||||
if (notify) {
|
||||
esas2r_trace("remove id:%d", esas2r_targ_get_id(t,
|
||||
a));
|
||||
esas2r_target_state_changed(a, esas2r_targ_get_id(t,
|
||||
a),
|
||||
TS_NOT_PRESENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void esas2r_targ_db_report_changes(struct esas2r_adapter *a)
|
||||
{
|
||||
struct esas2r_target *t;
|
||||
unsigned long flags;
|
||||
|
||||
esas2r_trace_enter();
|
||||
|
||||
if (a->flags & AF_DISC_PENDING) {
|
||||
esas2r_trace_exit();
|
||||
return;
|
||||
}
|
||||
|
||||
for (t = a->targetdb; t < a->targetdb_end; t++) {
|
||||
u8 state = TS_INVALID;
|
||||
|
||||
spin_lock_irqsave(&a->mem_lock, flags);
|
||||
if (t->buffered_target_state != t->target_state)
|
||||
state = t->buffered_target_state = t->target_state;
|
||||
|
||||
spin_unlock_irqrestore(&a->mem_lock, flags);
|
||||
if (state != TS_INVALID) {
|
||||
esas2r_trace("targ_db_report_changes:%d",
|
||||
esas2r_targ_get_id(
|
||||
t,
|
||||
a));
|
||||
esas2r_trace("state:%d", state);
|
||||
|
||||
esas2r_target_state_changed(a,
|
||||
esas2r_targ_get_id(t,
|
||||
a),
|
||||
state);
|
||||
}
|
||||
}
|
||||
|
||||
esas2r_trace_exit();
|
||||
}
|
||||
|
||||
struct esas2r_target *esas2r_targ_db_add_raid(struct esas2r_adapter *a,
|
||||
struct esas2r_disc_context *
|
||||
dc)
|
||||
{
|
||||
struct esas2r_target *t;
|
||||
|
||||
esas2r_trace_enter();
|
||||
|
||||
if (dc->curr_virt_id >= ESAS2R_MAX_TARGETS) {
|
||||
esas2r_bugon();
|
||||
esas2r_trace_exit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = a->targetdb + dc->curr_virt_id;
|
||||
|
||||
if (t->target_state == TS_PRESENT) {
|
||||
esas2r_trace_exit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esas2r_hdebug("add RAID %s, T:%d", dc->raid_grp_name,
|
||||
esas2r_targ_get_id(
|
||||
t,
|
||||
a));
|
||||
|
||||
if (dc->interleave == 0
|
||||
|| dc->block_size == 0) {
|
||||
/* these are invalid values, don't create the target entry. */
|
||||
|
||||
esas2r_hdebug("invalid RAID group dimensions");
|
||||
|
||||
esas2r_trace_exit();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t->block_size = dc->block_size;
|
||||
t->inter_byte = dc->interleave;
|
||||
t->inter_block = dc->interleave / dc->block_size;
|
||||
t->virt_targ_id = dc->curr_virt_id;
|
||||
t->phys_targ_id = ESAS2R_TARG_ID_INV;
|
||||
|
||||
t->flags &= ~TF_PASS_THRU;
|
||||
t->flags |= TF_USED;
|
||||
|
||||
t->identifier_len = 0;
|
||||
|
||||
t->target_state = TS_PRESENT;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
struct esas2r_target *esas2r_targ_db_add_pthru(struct esas2r_adapter *a,
|
||||
struct esas2r_disc_context *dc,
|
||||
u8 *ident,
|
||||
u8 ident_len)
|
||||
{
|
||||
struct esas2r_target *t;
|
||||
|
||||
esas2r_trace_enter();
|
||||
|
||||
if (dc->curr_virt_id >= ESAS2R_MAX_TARGETS) {
|
||||
esas2r_bugon();
|
||||
esas2r_trace_exit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* see if we found this device before. */
|
||||
|
||||
t = esas2r_targ_db_find_by_ident(a, ident, ident_len);
|
||||
|
||||
if (t == NULL) {
|
||||
t = a->targetdb + dc->curr_virt_id;
|
||||
|
||||
if (ident_len > sizeof(t->identifier)
|
||||
|| t->target_state == TS_PRESENT) {
|
||||
esas2r_trace_exit();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
esas2r_hdebug("add PT; T:%d, V:%d, P:%d", esas2r_targ_get_id(t, a),
|
||||
dc->curr_virt_id,
|
||||
dc->curr_phys_id);
|
||||
|
||||
t->block_size = 0;
|
||||
t->inter_byte = 0;
|
||||
t->inter_block = 0;
|
||||
t->virt_targ_id = dc->curr_virt_id;
|
||||
t->phys_targ_id = dc->curr_phys_id;
|
||||
t->identifier_len = ident_len;
|
||||
|
||||
memcpy(t->identifier, ident, ident_len);
|
||||
|
||||
t->flags |= TF_PASS_THRU | TF_USED;
|
||||
|
||||
t->target_state = TS_PRESENT;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void esas2r_targ_db_remove(struct esas2r_adapter *a, struct esas2r_target *t)
|
||||
{
|
||||
esas2r_trace_enter();
|
||||
|
||||
t->target_state = TS_NOT_PRESENT;
|
||||
|
||||
esas2r_trace("remove id:%d", esas2r_targ_get_id(t, a));
|
||||
|
||||
esas2r_trace_exit();
|
||||
}
|
||||
|
||||
struct esas2r_target *esas2r_targ_db_find_by_sas_addr(struct esas2r_adapter *a,
|
||||
u64 *sas_addr)
|
||||
{
|
||||
struct esas2r_target *t;
|
||||
|
||||
for (t = a->targetdb; t < a->targetdb_end; t++)
|
||||
if (t->sas_addr == *sas_addr)
|
||||
return t;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct esas2r_target *esas2r_targ_db_find_by_ident(struct esas2r_adapter *a,
|
||||
void *identifier,
|
||||
u8 ident_len)
|
||||
{
|
||||
struct esas2r_target *t;
|
||||
|
||||
for (t = a->targetdb; t < a->targetdb_end; t++) {
|
||||
if (ident_len == t->identifier_len
|
||||
&& memcmp(&t->identifier[0], identifier,
|
||||
ident_len) == 0)
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u16 esas2r_targ_db_find_next_present(struct esas2r_adapter *a, u16 target_id)
|
||||
{
|
||||
u16 id = target_id + 1;
|
||||
|
||||
while (id < ESAS2R_MAX_TARGETS) {
|
||||
struct esas2r_target *t = a->targetdb + id;
|
||||
|
||||
if (t->target_state == TS_PRESENT)
|
||||
break;
|
||||
|
||||
id++;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
struct esas2r_target *esas2r_targ_db_find_by_virt_id(struct esas2r_adapter *a,
|
||||
u16 virt_id)
|
||||
{
|
||||
struct esas2r_target *t;
|
||||
|
||||
for (t = a->targetdb; t < a->targetdb_end; t++) {
|
||||
if (t->target_state != TS_PRESENT)
|
||||
continue;
|
||||
|
||||
if (t->virt_targ_id == virt_id)
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u16 esas2r_targ_db_get_tgt_cnt(struct esas2r_adapter *a)
|
||||
{
|
||||
u16 devcnt = 0;
|
||||
struct esas2r_target *t;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&a->mem_lock, flags);
|
||||
for (t = a->targetdb; t < a->targetdb_end; t++)
|
||||
if (t->target_state == TS_PRESENT)
|
||||
devcnt++;
|
||||
|
||||
spin_unlock_irqrestore(&a->mem_lock, flags);
|
||||
|
||||
return devcnt;
|
||||
}
|
521
drivers/scsi/esas2r/esas2r_vda.c
Normal file
521
drivers/scsi/esas2r/esas2r_vda.c
Normal file
@ -0,0 +1,521 @@
|
||||
/*
|
||||
* linux/drivers/scsi/esas2r/esas2r_vda.c
|
||||
* esas2r driver VDA firmware interface functions
|
||||
*
|
||||
* Copyright (c) 2001-2013 ATTO Technology, Inc.
|
||||
* (mailto:linuxdrivers@attotech.com)
|
||||
*/
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
||||
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
|
||||
* solely responsible for determining the appropriateness of using and
|
||||
* distributing the Program and assumes all risks associated with its
|
||||
* exercise of rights under this Agreement, including but not limited to
|
||||
* the risks and costs of program errors, damage to or loss of data,
|
||||
* programs or equipment, and unavailability or interruption of operations.
|
||||
*
|
||||
* DISCLAIMER OF LIABILITY
|
||||
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
|
||||
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
|
||||
#include "esas2r.h"
|
||||
|
||||
static u8 esas2r_vdaioctl_versions[] = {
|
||||
ATTO_VDA_VER_UNSUPPORTED,
|
||||
ATTO_VDA_FLASH_VER,
|
||||
ATTO_VDA_VER_UNSUPPORTED,
|
||||
ATTO_VDA_VER_UNSUPPORTED,
|
||||
ATTO_VDA_CLI_VER,
|
||||
ATTO_VDA_VER_UNSUPPORTED,
|
||||
ATTO_VDA_CFG_VER,
|
||||
ATTO_VDA_MGT_VER,
|
||||
ATTO_VDA_GSV_VER
|
||||
};
|
||||
|
||||
static void clear_vda_request(struct esas2r_request *rq);
|
||||
|
||||
static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq);
|
||||
|
||||
/* Prepare a VDA IOCTL request to be sent to the firmware. */
|
||||
bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
|
||||
struct atto_ioctl_vda *vi,
|
||||
struct esas2r_request *rq,
|
||||
struct esas2r_sg_context *sgc)
|
||||
{
|
||||
u32 datalen = 0;
|
||||
struct atto_vda_sge *firstsg = NULL;
|
||||
u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions);
|
||||
|
||||
vi->status = ATTO_STS_SUCCESS;
|
||||
vi->vda_status = RS_PENDING;
|
||||
|
||||
if (vi->function >= vercnt) {
|
||||
vi->status = ATTO_STS_INV_FUNC;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vi->version > esas2r_vdaioctl_versions[vi->function]) {
|
||||
vi->status = ATTO_STS_INV_VERSION;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a->flags & AF_DEGRADED_MODE) {
|
||||
vi->status = ATTO_STS_DEGRADED;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vi->function != VDA_FUNC_SCSI)
|
||||
clear_vda_request(rq);
|
||||
|
||||
rq->vrq->scsi.function = vi->function;
|
||||
rq->interrupt_cb = esas2r_complete_vda_ioctl;
|
||||
rq->interrupt_cx = vi;
|
||||
|
||||
switch (vi->function) {
|
||||
case VDA_FUNC_FLASH:
|
||||
|
||||
if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD
|
||||
&& vi->cmd.flash.sub_func != VDA_FLASH_FWRITE
|
||||
&& vi->cmd.flash.sub_func != VDA_FLASH_FINFO) {
|
||||
vi->status = ATTO_STS_INV_FUNC;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO)
|
||||
datalen = vi->data_length;
|
||||
|
||||
rq->vrq->flash.length = cpu_to_le32(datalen);
|
||||
rq->vrq->flash.sub_func = vi->cmd.flash.sub_func;
|
||||
|
||||
memcpy(rq->vrq->flash.data.file.file_name,
|
||||
vi->cmd.flash.data.file.file_name,
|
||||
sizeof(vi->cmd.flash.data.file.file_name));
|
||||
|
||||
firstsg = rq->vrq->flash.data.file.sge;
|
||||
break;
|
||||
|
||||
case VDA_FUNC_CLI:
|
||||
|
||||
datalen = vi->data_length;
|
||||
|
||||
rq->vrq->cli.cmd_rsp_len =
|
||||
cpu_to_le32(vi->cmd.cli.cmd_rsp_len);
|
||||
rq->vrq->cli.length = cpu_to_le32(datalen);
|
||||
|
||||
firstsg = rq->vrq->cli.sge;
|
||||
break;
|
||||
|
||||
case VDA_FUNC_MGT:
|
||||
{
|
||||
u8 *cmdcurr_offset = sgc->cur_offset
|
||||
- offsetof(struct atto_ioctl_vda, data)
|
||||
+ offsetof(struct atto_ioctl_vda, cmd)
|
||||
+ offsetof(struct atto_ioctl_vda_mgt_cmd,
|
||||
data);
|
||||
/*
|
||||
* build the data payload SGL here first since
|
||||
* esas2r_sgc_init() will modify the S/G list offset for the
|
||||
* management SGL (which is built below where the data SGL is
|
||||
* usually built).
|
||||
*/
|
||||
|
||||
if (vi->data_length) {
|
||||
u32 payldlen = 0;
|
||||
|
||||
if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ
|
||||
|| vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) {
|
||||
rq->vrq->mgt.payld_sglst_offset =
|
||||
(u8)offsetof(struct atto_vda_mgmt_req,
|
||||
payld_sge);
|
||||
|
||||
payldlen = vi->data_length;
|
||||
datalen = vi->cmd.mgt.data_length;
|
||||
} else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2
|
||||
|| vi->cmd.mgt.mgt_func ==
|
||||
VDAMGT_DEV_INFO2_BYADDR) {
|
||||
datalen = vi->data_length;
|
||||
cmdcurr_offset = sgc->cur_offset;
|
||||
} else {
|
||||
vi->status = ATTO_STS_INV_PARAM;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Setup the length so building the payload SGL works */
|
||||
rq->vrq->mgt.length = cpu_to_le32(datalen);
|
||||
|
||||
if (payldlen) {
|
||||
rq->vrq->mgt.payld_length =
|
||||
cpu_to_le32(payldlen);
|
||||
|
||||
esas2r_sgc_init(sgc, a, rq,
|
||||
rq->vrq->mgt.payld_sge);
|
||||
sgc->length = payldlen;
|
||||
|
||||
if (!esas2r_build_sg_list(a, rq, sgc)) {
|
||||
vi->status = ATTO_STS_OUT_OF_RSRC;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
datalen = vi->cmd.mgt.data_length;
|
||||
|
||||
rq->vrq->mgt.length = cpu_to_le32(datalen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that the payload SGL is built, if any, setup to build
|
||||
* the management SGL.
|
||||
*/
|
||||
firstsg = rq->vrq->mgt.sge;
|
||||
sgc->cur_offset = cmdcurr_offset;
|
||||
|
||||
/* Finish initializing the management request. */
|
||||
rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func;
|
||||
rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation;
|
||||
rq->vrq->mgt.dev_index =
|
||||
cpu_to_le32(vi->cmd.mgt.dev_index);
|
||||
|
||||
esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
|
||||
break;
|
||||
}
|
||||
|
||||
case VDA_FUNC_CFG:
|
||||
|
||||
if (vi->data_length
|
||||
|| vi->cmd.cfg.data_length == 0) {
|
||||
vi->status = ATTO_STS_INV_PARAM;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) {
|
||||
vi->status = ATTO_STS_INV_FUNC;
|
||||
return false;
|
||||
}
|
||||
|
||||
rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func;
|
||||
rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length);
|
||||
|
||||
if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
|
||||
memcpy(&rq->vrq->cfg.data,
|
||||
&vi->cmd.cfg.data,
|
||||
vi->cmd.cfg.data_length);
|
||||
|
||||
esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
|
||||
&rq->vrq->cfg.data);
|
||||
} else {
|
||||
vi->status = ATTO_STS_INV_FUNC;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VDA_FUNC_GSV:
|
||||
|
||||
vi->cmd.gsv.rsp_len = vercnt;
|
||||
|
||||
memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions,
|
||||
vercnt);
|
||||
|
||||
vi->vda_status = RS_SUCCESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
vi->status = ATTO_STS_INV_FUNC;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (datalen) {
|
||||
esas2r_sgc_init(sgc, a, rq, firstsg);
|
||||
sgc->length = datalen;
|
||||
|
||||
if (!esas2r_build_sg_list(a, rq, sgc)) {
|
||||
vi->status = ATTO_STS_OUT_OF_RSRC;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
esas2r_start_request(a, rq);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq)
|
||||
{
|
||||
struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx;
|
||||
|
||||
vi->vda_status = rq->req_stat;
|
||||
|
||||
switch (vi->function) {
|
||||
case VDA_FUNC_FLASH:
|
||||
|
||||
if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO
|
||||
|| vi->cmd.flash.sub_func == VDA_FLASH_FREAD)
|
||||
vi->cmd.flash.data.file.file_size =
|
||||
le32_to_cpu(rq->func_rsp.flash_rsp.file_size);
|
||||
|
||||
break;
|
||||
|
||||
case VDA_FUNC_MGT:
|
||||
|
||||
vi->cmd.mgt.scan_generation =
|
||||
rq->func_rsp.mgt_rsp.scan_generation;
|
||||
vi->cmd.mgt.dev_index = le16_to_cpu(
|
||||
rq->func_rsp.mgt_rsp.dev_index);
|
||||
|
||||
if (vi->data_length == 0)
|
||||
vi->cmd.mgt.data_length =
|
||||
le32_to_cpu(rq->func_rsp.mgt_rsp.length);
|
||||
|
||||
esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
|
||||
break;
|
||||
|
||||
case VDA_FUNC_CFG:
|
||||
|
||||
if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
|
||||
struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
|
||||
struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
|
||||
|
||||
cfg->data_length =
|
||||
cpu_to_le32(sizeof(struct atto_vda_cfg_init));
|
||||
cfg->data.init.vda_version =
|
||||
le32_to_cpu(rsp->vda_version);
|
||||
cfg->data.init.fw_build = rsp->fw_build;
|
||||
|
||||
sprintf((char *)&cfg->data.init.fw_release,
|
||||
"%1d.%02d",
|
||||
(int)LOBYTE(le16_to_cpu(rsp->fw_release)),
|
||||
(int)HIBYTE(le16_to_cpu(rsp->fw_release)));
|
||||
|
||||
if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
|
||||
cfg->data.init.fw_version =
|
||||
cfg->data.init.fw_build;
|
||||
else
|
||||
cfg->data.init.fw_version =
|
||||
cfg->data.init.fw_release;
|
||||
} else {
|
||||
esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
|
||||
&vi->cmd.cfg.data);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case VDA_FUNC_CLI:
|
||||
|
||||
vi->cmd.cli.cmd_rsp_len =
|
||||
le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a flash VDA request. */
|
||||
void esas2r_build_flash_req(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq,
|
||||
u8 sub_func,
|
||||
u8 cksum,
|
||||
u32 addr,
|
||||
u32 length)
|
||||
{
|
||||
struct atto_vda_flash_req *vrq = &rq->vrq->flash;
|
||||
|
||||
clear_vda_request(rq);
|
||||
|
||||
rq->vrq->scsi.function = VDA_FUNC_FLASH;
|
||||
|
||||
if (sub_func == VDA_FLASH_BEGINW
|
||||
|| sub_func == VDA_FLASH_WRITE
|
||||
|| sub_func == VDA_FLASH_READ)
|
||||
vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req,
|
||||
data.sge);
|
||||
|
||||
vrq->length = cpu_to_le32(length);
|
||||
vrq->flash_addr = cpu_to_le32(addr);
|
||||
vrq->checksum = cksum;
|
||||
vrq->sub_func = sub_func;
|
||||
}
|
||||
|
||||
/* Build a VDA management request. */
|
||||
void esas2r_build_mgt_req(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq,
|
||||
u8 sub_func,
|
||||
u8 scan_gen,
|
||||
u16 dev_index,
|
||||
u32 length,
|
||||
void *data)
|
||||
{
|
||||
struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt;
|
||||
|
||||
clear_vda_request(rq);
|
||||
|
||||
rq->vrq->scsi.function = VDA_FUNC_MGT;
|
||||
|
||||
vrq->mgt_func = sub_func;
|
||||
vrq->scan_generation = scan_gen;
|
||||
vrq->dev_index = cpu_to_le16(dev_index);
|
||||
vrq->length = cpu_to_le32(length);
|
||||
|
||||
if (vrq->length) {
|
||||
if (a->flags & AF_LEGACY_SGE_MODE) {
|
||||
vrq->sg_list_offset = (u8)offsetof(
|
||||
struct atto_vda_mgmt_req, sge);
|
||||
|
||||
vrq->sge[0].length = cpu_to_le32(SGE_LAST | length);
|
||||
vrq->sge[0].address = cpu_to_le64(
|
||||
rq->vrq_md->phys_addr +
|
||||
sizeof(union atto_vda_req));
|
||||
} else {
|
||||
vrq->sg_list_offset = (u8)offsetof(
|
||||
struct atto_vda_mgmt_req, prde);
|
||||
|
||||
vrq->prde[0].ctl_len = cpu_to_le32(length);
|
||||
vrq->prde[0].address = cpu_to_le64(
|
||||
rq->vrq_md->phys_addr +
|
||||
sizeof(union atto_vda_req));
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
esas2r_nuxi_mgt_data(sub_func, data);
|
||||
|
||||
memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data,
|
||||
length);
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a VDA asyncronous event (AE) request. */
|
||||
void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq)
|
||||
{
|
||||
struct atto_vda_ae_req *vrq = &rq->vrq->ae;
|
||||
|
||||
clear_vda_request(rq);
|
||||
|
||||
rq->vrq->scsi.function = VDA_FUNC_AE;
|
||||
|
||||
vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data));
|
||||
|
||||
if (a->flags & AF_LEGACY_SGE_MODE) {
|
||||
vrq->sg_list_offset =
|
||||
(u8)offsetof(struct atto_vda_ae_req, sge);
|
||||
vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length);
|
||||
vrq->sge[0].address = cpu_to_le64(
|
||||
rq->vrq_md->phys_addr +
|
||||
sizeof(union atto_vda_req));
|
||||
} else {
|
||||
vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req,
|
||||
prde);
|
||||
vrq->prde[0].ctl_len = cpu_to_le32(vrq->length);
|
||||
vrq->prde[0].address = cpu_to_le64(
|
||||
rq->vrq_md->phys_addr +
|
||||
sizeof(union atto_vda_req));
|
||||
}
|
||||
}
|
||||
|
||||
/* Build a VDA CLI request. */
|
||||
void esas2r_build_cli_req(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq,
|
||||
u32 length,
|
||||
u32 cmd_rsp_len)
|
||||
{
|
||||
struct atto_vda_cli_req *vrq = &rq->vrq->cli;
|
||||
|
||||
clear_vda_request(rq);
|
||||
|
||||
rq->vrq->scsi.function = VDA_FUNC_CLI;
|
||||
|
||||
vrq->length = cpu_to_le32(length);
|
||||
vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len);
|
||||
vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge);
|
||||
}
|
||||
|
||||
/* Build a VDA IOCTL request. */
|
||||
void esas2r_build_ioctl_req(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq,
|
||||
u32 length,
|
||||
u8 sub_func)
|
||||
{
|
||||
struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl;
|
||||
|
||||
clear_vda_request(rq);
|
||||
|
||||
rq->vrq->scsi.function = VDA_FUNC_IOCTL;
|
||||
|
||||
vrq->length = cpu_to_le32(length);
|
||||
vrq->sub_func = sub_func;
|
||||
vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge);
|
||||
}
|
||||
|
||||
/* Build a VDA configuration request. */
|
||||
void esas2r_build_cfg_req(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq,
|
||||
u8 sub_func,
|
||||
u32 length,
|
||||
void *data)
|
||||
{
|
||||
struct atto_vda_cfg_req *vrq = &rq->vrq->cfg;
|
||||
|
||||
clear_vda_request(rq);
|
||||
|
||||
rq->vrq->scsi.function = VDA_FUNC_CFG;
|
||||
|
||||
vrq->sub_func = sub_func;
|
||||
vrq->length = cpu_to_le32(length);
|
||||
|
||||
if (data) {
|
||||
esas2r_nuxi_cfg_data(sub_func, data);
|
||||
|
||||
memcpy(&vrq->data, data, length);
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_vda_request(struct esas2r_request *rq)
|
||||
{
|
||||
u32 handle = rq->vrq->scsi.handle;
|
||||
|
||||
memset(rq->vrq, 0, sizeof(*rq->vrq));
|
||||
|
||||
rq->vrq->scsi.handle = handle;
|
||||
|
||||
rq->req_stat = RS_PENDING;
|
||||
|
||||
/* since the data buffer is separate clear that too */
|
||||
|
||||
memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN);
|
||||
|
||||
/*
|
||||
* Setup next and prev pointer in case the request is not going through
|
||||
* esas2r_start_request().
|
||||
*/
|
||||
|
||||
INIT_LIST_HEAD(&rq->req_list);
|
||||
}
|
@ -583,7 +583,7 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
|
||||
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
|
||||
if (likely(h->msix_vector))
|
||||
c->Header.ReplyQueue =
|
||||
smp_processor_id() % h->nreply_queues;
|
||||
raw_smp_processor_id() % h->nreply_queues;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1205,8 +1205,8 @@ static void complete_scsi_command(struct CommandList *cp)
|
||||
scsi_set_resid(cmd, ei->ResidualCnt);
|
||||
|
||||
if (ei->CommandStatus == 0) {
|
||||
cmd->scsi_done(cmd);
|
||||
cmd_free(h, cp);
|
||||
cmd->scsi_done(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1379,8 +1379,8 @@ static void complete_scsi_command(struct CommandList *cp)
|
||||
dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
|
||||
cp, ei->CommandStatus);
|
||||
}
|
||||
cmd->scsi_done(cmd);
|
||||
cmd_free(h, cp);
|
||||
cmd->scsi_done(cmd);
|
||||
}
|
||||
|
||||
static void hpsa_pci_unmap(struct pci_dev *pdev,
|
||||
@ -2721,7 +2721,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
|
||||
} while (test_and_set_bit
|
||||
(i & (BITS_PER_LONG - 1),
|
||||
h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
|
||||
h->nr_allocs++;
|
||||
spin_unlock_irqrestore(&h->lock, flags);
|
||||
|
||||
c = h->cmd_pool + i;
|
||||
@ -2793,7 +2792,6 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c)
|
||||
spin_lock_irqsave(&h->lock, flags);
|
||||
clear_bit(i & (BITS_PER_LONG - 1),
|
||||
h->cmd_pool_bits + (i / BITS_PER_LONG));
|
||||
h->nr_frees++;
|
||||
spin_unlock_irqrestore(&h->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -98,8 +98,6 @@ struct ctlr_info {
|
||||
struct ErrorInfo *errinfo_pool;
|
||||
dma_addr_t errinfo_pool_dhandle;
|
||||
unsigned long *cmd_pool_bits;
|
||||
int nr_allocs;
|
||||
int nr_frees;
|
||||
int scan_finished;
|
||||
spinlock_t scan_lock;
|
||||
wait_queue_head_t scan_wait_queue;
|
||||
|
@ -9990,6 +9990,20 @@ static struct pci_device_id ipr_pci_table[] = {
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D7, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D8, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D9, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EB, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EC, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57ED, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EE, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EF, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57F0, 0, 0, 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
|
||||
|
@ -100,6 +100,13 @@
|
||||
#define IPR_SUBS_DEV_ID_57D6 0x03FC
|
||||
#define IPR_SUBS_DEV_ID_57D7 0x03FF
|
||||
#define IPR_SUBS_DEV_ID_57D8 0x03FE
|
||||
#define IPR_SUBS_DEV_ID_57D9 0x046D
|
||||
#define IPR_SUBS_DEV_ID_57EB 0x0474
|
||||
#define IPR_SUBS_DEV_ID_57EC 0x0475
|
||||
#define IPR_SUBS_DEV_ID_57ED 0x0499
|
||||
#define IPR_SUBS_DEV_ID_57EE 0x049A
|
||||
#define IPR_SUBS_DEV_ID_57EF 0x049B
|
||||
#define IPR_SUBS_DEV_ID_57F0 0x049C
|
||||
#define IPR_NAME "ipr"
|
||||
|
||||
/*
|
||||
|
@ -311,9 +311,9 @@ sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost,
|
||||
&ihost->phys[phy_index]);
|
||||
|
||||
assigned_phy_mask |= (1 << phy_index);
|
||||
phy_index++;
|
||||
}
|
||||
|
||||
phy_index++;
|
||||
}
|
||||
|
||||
return sci_port_configuration_agent_validate_ports(ihost, port_agent);
|
||||
|
@ -2812,6 +2812,8 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
|
||||
kfree(session->boot_nic);
|
||||
kfree(session->boot_target);
|
||||
kfree(session->ifacename);
|
||||
kfree(session->portal_type);
|
||||
kfree(session->discovery_parent_type);
|
||||
|
||||
iscsi_destroy_session(cls_session);
|
||||
iscsi_host_dec_session_cnt(shost);
|
||||
@ -3168,6 +3170,7 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
||||
{
|
||||
struct iscsi_conn *conn = cls_conn->dd_data;
|
||||
struct iscsi_session *session = conn->session;
|
||||
int val;
|
||||
|
||||
switch(param) {
|
||||
case ISCSI_PARAM_FAST_ABORT:
|
||||
@ -3257,6 +3260,15 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
||||
return iscsi_switch_str_param(&session->boot_nic, buf);
|
||||
case ISCSI_PARAM_BOOT_TARGET:
|
||||
return iscsi_switch_str_param(&session->boot_target, buf);
|
||||
case ISCSI_PARAM_PORTAL_TYPE:
|
||||
return iscsi_switch_str_param(&session->portal_type, buf);
|
||||
case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
|
||||
return iscsi_switch_str_param(&session->discovery_parent_type,
|
||||
buf);
|
||||
case ISCSI_PARAM_DISCOVERY_SESS:
|
||||
sscanf(buf, "%d", &val);
|
||||
session->discovery_sess = !!val;
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
@ -3305,6 +3317,9 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
|
||||
case ISCSI_PARAM_DATASEQ_INORDER_EN:
|
||||
len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
|
||||
break;
|
||||
case ISCSI_PARAM_DEF_TASKMGMT_TMO:
|
||||
len = sprintf(buf, "%d\n", session->def_taskmgmt_tmo);
|
||||
break;
|
||||
case ISCSI_PARAM_ERL:
|
||||
len = sprintf(buf, "%d\n", session->erl);
|
||||
break;
|
||||
@ -3344,6 +3359,52 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
|
||||
case ISCSI_PARAM_BOOT_TARGET:
|
||||
len = sprintf(buf, "%s\n", session->boot_target);
|
||||
break;
|
||||
case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
|
||||
len = sprintf(buf, "%u\n", session->auto_snd_tgt_disable);
|
||||
break;
|
||||
case ISCSI_PARAM_DISCOVERY_SESS:
|
||||
len = sprintf(buf, "%u\n", session->discovery_sess);
|
||||
break;
|
||||
case ISCSI_PARAM_PORTAL_TYPE:
|
||||
len = sprintf(buf, "%s\n", session->portal_type);
|
||||
break;
|
||||
case ISCSI_PARAM_CHAP_AUTH_EN:
|
||||
len = sprintf(buf, "%u\n", session->chap_auth_en);
|
||||
break;
|
||||
case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
|
||||
len = sprintf(buf, "%u\n", session->discovery_logout_en);
|
||||
break;
|
||||
case ISCSI_PARAM_BIDI_CHAP_EN:
|
||||
len = sprintf(buf, "%u\n", session->bidi_chap_en);
|
||||
break;
|
||||
case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
|
||||
len = sprintf(buf, "%u\n", session->discovery_auth_optional);
|
||||
break;
|
||||
case ISCSI_PARAM_DEF_TIME2WAIT:
|
||||
len = sprintf(buf, "%d\n", session->time2wait);
|
||||
break;
|
||||
case ISCSI_PARAM_DEF_TIME2RETAIN:
|
||||
len = sprintf(buf, "%d\n", session->time2retain);
|
||||
break;
|
||||
case ISCSI_PARAM_TSID:
|
||||
len = sprintf(buf, "%u\n", session->tsid);
|
||||
break;
|
||||
case ISCSI_PARAM_ISID:
|
||||
len = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
|
||||
session->isid[0], session->isid[1],
|
||||
session->isid[2], session->isid[3],
|
||||
session->isid[4], session->isid[5]);
|
||||
break;
|
||||
case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
|
||||
len = sprintf(buf, "%u\n", session->discovery_parent_idx);
|
||||
break;
|
||||
case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
|
||||
if (session->discovery_parent_type)
|
||||
len = sprintf(buf, "%s\n",
|
||||
session->discovery_parent_type);
|
||||
else
|
||||
len = sprintf(buf, "\n");
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
@ -3433,6 +3494,54 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
|
||||
case ISCSI_PARAM_PERSISTENT_ADDRESS:
|
||||
len = sprintf(buf, "%s\n", conn->persistent_address);
|
||||
break;
|
||||
case ISCSI_PARAM_STATSN:
|
||||
len = sprintf(buf, "%u\n", conn->statsn);
|
||||
break;
|
||||
case ISCSI_PARAM_MAX_SEGMENT_SIZE:
|
||||
len = sprintf(buf, "%u\n", conn->max_segment_size);
|
||||
break;
|
||||
case ISCSI_PARAM_KEEPALIVE_TMO:
|
||||
len = sprintf(buf, "%u\n", conn->keepalive_tmo);
|
||||
break;
|
||||
case ISCSI_PARAM_LOCAL_PORT:
|
||||
len = sprintf(buf, "%u\n", conn->local_port);
|
||||
break;
|
||||
case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
|
||||
len = sprintf(buf, "%u\n", conn->tcp_timestamp_stat);
|
||||
break;
|
||||
case ISCSI_PARAM_TCP_NAGLE_DISABLE:
|
||||
len = sprintf(buf, "%u\n", conn->tcp_nagle_disable);
|
||||
break;
|
||||
case ISCSI_PARAM_TCP_WSF_DISABLE:
|
||||
len = sprintf(buf, "%u\n", conn->tcp_wsf_disable);
|
||||
break;
|
||||
case ISCSI_PARAM_TCP_TIMER_SCALE:
|
||||
len = sprintf(buf, "%u\n", conn->tcp_timer_scale);
|
||||
break;
|
||||
case ISCSI_PARAM_TCP_TIMESTAMP_EN:
|
||||
len = sprintf(buf, "%u\n", conn->tcp_timestamp_en);
|
||||
break;
|
||||
case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
|
||||
len = sprintf(buf, "%u\n", conn->fragment_disable);
|
||||
break;
|
||||
case ISCSI_PARAM_IPV4_TOS:
|
||||
len = sprintf(buf, "%u\n", conn->ipv4_tos);
|
||||
break;
|
||||
case ISCSI_PARAM_IPV6_TC:
|
||||
len = sprintf(buf, "%u\n", conn->ipv6_traffic_class);
|
||||
break;
|
||||
case ISCSI_PARAM_IPV6_FLOW_LABEL:
|
||||
len = sprintf(buf, "%u\n", conn->ipv6_flow_label);
|
||||
break;
|
||||
case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
|
||||
len = sprintf(buf, "%u\n", conn->is_fw_assigned_ipv6);
|
||||
break;
|
||||
case ISCSI_PARAM_TCP_XMIT_WSF:
|
||||
len = sprintf(buf, "%u\n", conn->tcp_xmit_wsf);
|
||||
break;
|
||||
case ISCSI_PARAM_TCP_RECV_WSF:
|
||||
len = sprintf(buf, "%u\n", conn->tcp_recv_wsf);
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
@ -421,6 +421,7 @@ struct lpfc_vport {
|
||||
uint32_t cfg_enable_da_id;
|
||||
uint32_t cfg_max_scsicmpl_time;
|
||||
uint32_t cfg_tgt_queue_depth;
|
||||
uint32_t cfg_first_burst_size;
|
||||
|
||||
uint32_t dev_loss_tmo_changed;
|
||||
|
||||
@ -710,8 +711,6 @@ struct lpfc_hba {
|
||||
uint32_t cfg_use_msi;
|
||||
uint32_t cfg_fcp_imax;
|
||||
uint32_t cfg_fcp_cpu_map;
|
||||
uint32_t cfg_fcp_wq_count;
|
||||
uint32_t cfg_fcp_eq_count;
|
||||
uint32_t cfg_fcp_io_channel;
|
||||
uint32_t cfg_total_seg_cnt;
|
||||
uint32_t cfg_sg_seg_cnt;
|
||||
|
@ -674,9 +674,6 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
if (phba->pport->fc_flag & FC_OFFLINE_MODE)
|
||||
return 0;
|
||||
|
||||
init_completion(&online_compl);
|
||||
rc = lpfc_workq_post_event(phba, &status, &online_compl,
|
||||
LPFC_EVT_OFFLINE_PREP);
|
||||
@ -744,14 +741,15 @@ lpfc_selective_reset(struct lpfc_hba *phba)
|
||||
int status = 0;
|
||||
int rc;
|
||||
|
||||
if ((!phba->cfg_enable_hba_reset) ||
|
||||
(phba->pport->fc_flag & FC_OFFLINE_MODE))
|
||||
if (!phba->cfg_enable_hba_reset)
|
||||
return -EACCES;
|
||||
|
||||
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
|
||||
if (!(phba->pport->fc_flag & FC_OFFLINE_MODE)) {
|
||||
status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
|
||||
|
||||
if (status != 0)
|
||||
return status;
|
||||
if (status != 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
init_completion(&online_compl);
|
||||
rc = lpfc_workq_post_event(phba, &status, &online_compl,
|
||||
@ -2591,9 +2589,12 @@ LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1,
|
||||
|
||||
/*
|
||||
# lun_queue_depth: This parameter is used to limit the number of outstanding
|
||||
# commands per FCP LUN. Value range is [1,128]. Default value is 30.
|
||||
# commands per FCP LUN. Value range is [1,512]. Default value is 30.
|
||||
# If this parameter value is greater than 1/8th the maximum number of exchanges
|
||||
# supported by the HBA port, then the lun queue depth will be reduced to
|
||||
# 1/8th the maximum number of exchanges.
|
||||
*/
|
||||
LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
|
||||
LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512,
|
||||
"Max number of FCP commands we can queue to a specific LUN");
|
||||
|
||||
/*
|
||||
@ -2601,7 +2602,7 @@ LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
|
||||
# commands per target port. Value range is [10,65535]. Default value is 65535.
|
||||
*/
|
||||
LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
|
||||
"Max number of FCP commands we can queue to a specific target port");
|
||||
"Max number of FCP commands we can queue to a specific target port");
|
||||
|
||||
/*
|
||||
# hba_queue_depth: This parameter is used to limit the number of outstanding
|
||||
@ -3948,6 +3949,14 @@ LPFC_VPORT_ATTR_R(fcp_class, 3, 2, 3,
|
||||
LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
|
||||
"Use ADISC on rediscovery to authenticate FCP devices");
|
||||
|
||||
/*
|
||||
# lpfc_first_burst_size: First burst size to use on the NPorts
|
||||
# that support first burst.
|
||||
# Value range is [0,65536]. Default value is 0.
|
||||
*/
|
||||
LPFC_VPORT_ATTR_RW(first_burst_size, 0, 0, 65536,
|
||||
"First burst size for Targets that support first burst");
|
||||
|
||||
/*
|
||||
# lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue
|
||||
# depth. Default value is 0. When the value of this parameter is zero the
|
||||
@ -4111,25 +4120,6 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
|
||||
LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or "
|
||||
"MSI-X (2), if possible");
|
||||
|
||||
/*
|
||||
# lpfc_fcp_wq_count: Set the number of fast-path FCP work queues
|
||||
# This parameter is ignored and will eventually be depricated
|
||||
#
|
||||
# Value range is [1,7]. Default value is 4.
|
||||
*/
|
||||
LPFC_ATTR_R(fcp_wq_count, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN,
|
||||
LPFC_FCP_IO_CHAN_MAX,
|
||||
"Set the number of fast-path FCP work queues, if possible");
|
||||
|
||||
/*
|
||||
# lpfc_fcp_eq_count: Set the number of FCP EQ/CQ/WQ IO channels
|
||||
#
|
||||
# Value range is [1,7]. Default value is 4.
|
||||
*/
|
||||
LPFC_ATTR_R(fcp_eq_count, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN,
|
||||
LPFC_FCP_IO_CHAN_MAX,
|
||||
"Set the number of fast-path FCP event queues, if possible");
|
||||
|
||||
/*
|
||||
# lpfc_fcp_io_channel: Set the number of FCP EQ/CQ/WQ IO channels
|
||||
#
|
||||
@ -4276,6 +4266,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
|
||||
&dev_attr_lpfc_devloss_tmo,
|
||||
&dev_attr_lpfc_fcp_class,
|
||||
&dev_attr_lpfc_use_adisc,
|
||||
&dev_attr_lpfc_first_burst_size,
|
||||
&dev_attr_lpfc_ack0,
|
||||
&dev_attr_lpfc_topology,
|
||||
&dev_attr_lpfc_scan_down,
|
||||
@ -4307,8 +4298,6 @@ struct device_attribute *lpfc_hba_attrs[] = {
|
||||
&dev_attr_lpfc_use_msi,
|
||||
&dev_attr_lpfc_fcp_imax,
|
||||
&dev_attr_lpfc_fcp_cpu_map,
|
||||
&dev_attr_lpfc_fcp_wq_count,
|
||||
&dev_attr_lpfc_fcp_eq_count,
|
||||
&dev_attr_lpfc_fcp_io_channel,
|
||||
&dev_attr_lpfc_enable_bg,
|
||||
&dev_attr_lpfc_soft_wwnn,
|
||||
@ -4352,6 +4341,7 @@ struct device_attribute *lpfc_vport_attrs[] = {
|
||||
&dev_attr_lpfc_restrict_login,
|
||||
&dev_attr_lpfc_fcp_class,
|
||||
&dev_attr_lpfc_use_adisc,
|
||||
&dev_attr_lpfc_first_burst_size,
|
||||
&dev_attr_lpfc_fdmi_on,
|
||||
&dev_attr_lpfc_max_luns,
|
||||
&dev_attr_nport_evt_cnt,
|
||||
@ -5290,8 +5280,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
|
||||
lpfc_use_msi_init(phba, lpfc_use_msi);
|
||||
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
|
||||
lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
|
||||
lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count);
|
||||
lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count);
|
||||
lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
|
||||
lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
|
||||
lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
|
||||
@ -5331,6 +5319,7 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
|
||||
lpfc_restrict_login_init(vport, lpfc_restrict_login);
|
||||
lpfc_fcp_class_init(vport, lpfc_fcp_class);
|
||||
lpfc_use_adisc_init(vport, lpfc_use_adisc);
|
||||
lpfc_first_burst_size_init(vport, lpfc_first_burst_size);
|
||||
lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
|
||||
lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
|
||||
lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
|
||||
|
@ -2498,7 +2498,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
|
||||
struct lpfc_sli_ct_request *ctreq = NULL;
|
||||
int ret_val = 0;
|
||||
int time_left;
|
||||
int iocb_stat = 0;
|
||||
int iocb_stat = IOCB_SUCCESS;
|
||||
unsigned long flags;
|
||||
|
||||
*txxri = 0;
|
||||
@ -2574,6 +2574,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
|
||||
|
||||
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
|
||||
cmdiocbq->vport = phba->pport;
|
||||
cmdiocbq->iocb_cmpl = NULL;
|
||||
|
||||
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
|
||||
rspiocbq,
|
||||
@ -2963,7 +2964,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
||||
uint8_t *ptr = NULL, *rx_databuf = NULL;
|
||||
int rc = 0;
|
||||
int time_left;
|
||||
int iocb_stat;
|
||||
int iocb_stat = IOCB_SUCCESS;
|
||||
unsigned long flags;
|
||||
void *dataout = NULL;
|
||||
uint32_t total_mem;
|
||||
@ -3149,6 +3150,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
||||
}
|
||||
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
|
||||
cmdiocbq->vport = phba->pport;
|
||||
cmdiocbq->iocb_cmpl = NULL;
|
||||
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
|
||||
rspiocbq, (phba->fc_ratov * 2) +
|
||||
LPFC_DRVR_TIMEOUT);
|
||||
@ -3209,7 +3211,7 @@ err_loopback_test_exit:
|
||||
lpfc_bsg_event_unref(evt); /* delete */
|
||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
||||
|
||||
if (cmdiocbq != NULL)
|
||||
if ((cmdiocbq != NULL) && (iocb_stat != IOCB_TIMEDOUT))
|
||||
lpfc_sli_release_iocbq(phba, cmdiocbq);
|
||||
|
||||
if (rspiocbq != NULL)
|
||||
|
@ -895,7 +895,7 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
|
||||
if (irsp->ulpStatus) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
|
||||
"0268 NS cmd %x Error (%d %d)\n",
|
||||
"0268 NS cmd x%x Error (x%x x%x)\n",
|
||||
cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
|
||||
|
||||
if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*******************************************************************
|
||||
* This file is part of the Emulex Linux Device Driver for *
|
||||
* Fibre Channel Host Bus Adapters. *
|
||||
* Copyright (C) 2004-2008 Emulex. All rights reserved. *
|
||||
* Copyright (C) 2004-2013 Emulex. All rights reserved. *
|
||||
* EMULEX and SLI are trademarks of Emulex. *
|
||||
* www.emulex.com *
|
||||
* *
|
||||
@ -154,6 +154,7 @@ struct lpfc_node_rrq {
|
||||
#define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */
|
||||
#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
|
||||
#define NLP_SC_REQ 0x20000000 /* Target requires authentication */
|
||||
#define NLP_FIRSTBURST 0x40000000 /* Target supports FirstBurst */
|
||||
#define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */
|
||||
|
||||
/* ndlp usage management macros */
|
||||
|
@ -2122,6 +2122,8 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
}
|
||||
npr->estabImagePair = 1;
|
||||
npr->readXferRdyDis = 1;
|
||||
if (vport->cfg_first_burst_size)
|
||||
npr->writeXferRdyDis = 1;
|
||||
|
||||
/* For FCP support */
|
||||
npr->prliType = PRLI_FCP_TYPE;
|
||||
|
@ -234,6 +234,9 @@ struct ulp_bde64 {
|
||||
uint32_t addrHigh;
|
||||
};
|
||||
|
||||
/* Maximun size of immediate data that can fit into a 128 byte WQE */
|
||||
#define LPFC_MAX_BDE_IMM_SIZE 64
|
||||
|
||||
struct lpfc_sli4_flags {
|
||||
uint32_t word0;
|
||||
#define lpfc_idx_rsrc_rdy_SHIFT 0
|
||||
@ -2585,6 +2588,9 @@ struct lpfc_sli4_parameters {
|
||||
#define cfg_mqv_WORD word6
|
||||
uint32_t word7;
|
||||
uint32_t word8;
|
||||
#define cfg_wqsize_SHIFT 8
|
||||
#define cfg_wqsize_MASK 0x0000000f
|
||||
#define cfg_wqsize_WORD word8
|
||||
#define cfg_wqv_SHIFT 14
|
||||
#define cfg_wqv_MASK 0x00000003
|
||||
#define cfg_wqv_WORD word8
|
||||
@ -3622,6 +3628,13 @@ union lpfc_wqe {
|
||||
struct gen_req64_wqe gen_req;
|
||||
};
|
||||
|
||||
union lpfc_wqe128 {
|
||||
uint32_t words[32];
|
||||
struct lpfc_wqe_generic generic;
|
||||
struct xmit_seq64_wqe xmit_sequence;
|
||||
struct gen_req64_wqe gen_req;
|
||||
};
|
||||
|
||||
#define LPFC_GROUP_OJECT_MAGIC_NUM 0xfeaa0001
|
||||
#define LPFC_FILE_TYPE_GROUP 0xf7
|
||||
#define LPFC_FILE_ID_GROUP 0xa2
|
||||
|
@ -472,10 +472,22 @@ lpfc_config_port_post(struct lpfc_hba *phba)
|
||||
lpfc_sli_read_link_ste(phba);
|
||||
|
||||
/* Reset the DFT_HBA_Q_DEPTH to the max xri */
|
||||
if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1))
|
||||
phba->cfg_hba_queue_depth =
|
||||
(mb->un.varRdConfig.max_xri + 1) -
|
||||
lpfc_sli4_get_els_iocb_cnt(phba);
|
||||
i = (mb->un.varRdConfig.max_xri + 1);
|
||||
if (phba->cfg_hba_queue_depth > i) {
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
||||
"3359 HBA queue depth changed from %d to %d\n",
|
||||
phba->cfg_hba_queue_depth, i);
|
||||
phba->cfg_hba_queue_depth = i;
|
||||
}
|
||||
|
||||
/* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */
|
||||
i = (mb->un.varRdConfig.max_xri >> 3);
|
||||
if (phba->pport->cfg_lun_queue_depth > i) {
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
||||
"3360 LUN queue depth changed from %d to %d\n",
|
||||
phba->pport->cfg_lun_queue_depth, i);
|
||||
phba->pport->cfg_lun_queue_depth = i;
|
||||
}
|
||||
|
||||
phba->lmt = mb->un.varRdConfig.lmt;
|
||||
|
||||
@ -4901,9 +4913,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
||||
lpfc_get_cfgparam(phba);
|
||||
phba->max_vpi = LPFC_MAX_VPI;
|
||||
|
||||
/* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */
|
||||
phba->cfg_fcp_io_channel = phba->cfg_fcp_eq_count;
|
||||
|
||||
/* This will be set to correct value after the read_config mbox */
|
||||
phba->max_vports = 0;
|
||||
|
||||
@ -6664,12 +6673,14 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
|
||||
goto read_cfg_out;
|
||||
|
||||
/* Reset the DFT_HBA_Q_DEPTH to the max xri */
|
||||
if (phba->cfg_hba_queue_depth >
|
||||
(phba->sli4_hba.max_cfg_param.max_xri -
|
||||
lpfc_sli4_get_els_iocb_cnt(phba)))
|
||||
phba->cfg_hba_queue_depth =
|
||||
phba->sli4_hba.max_cfg_param.max_xri -
|
||||
lpfc_sli4_get_els_iocb_cnt(phba);
|
||||
length = phba->sli4_hba.max_cfg_param.max_xri -
|
||||
lpfc_sli4_get_els_iocb_cnt(phba);
|
||||
if (phba->cfg_hba_queue_depth > length) {
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
||||
"3361 HBA queue depth changed from %d to %d\n",
|
||||
phba->cfg_hba_queue_depth, length);
|
||||
phba->cfg_hba_queue_depth = length;
|
||||
}
|
||||
|
||||
if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
|
||||
LPFC_SLI_INTF_IF_TYPE_2)
|
||||
@ -6859,11 +6870,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)
|
||||
cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq;
|
||||
}
|
||||
|
||||
/* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */
|
||||
|
||||
/* The actual number of FCP event queues adopted */
|
||||
phba->cfg_fcp_eq_count = cfg_fcp_io_channel;
|
||||
phba->cfg_fcp_wq_count = cfg_fcp_io_channel;
|
||||
phba->cfg_fcp_io_channel = cfg_fcp_io_channel;
|
||||
|
||||
/* Get EQ depth from module parameter, fake the default for now */
|
||||
@ -9154,6 +9161,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
||||
sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
|
||||
sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
|
||||
sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters);
|
||||
sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters);
|
||||
sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt,
|
||||
mbx_sli4_parameters);
|
||||
sli4_params->sgl_pp_align = bf_get(cfg_sgl_pp_align,
|
||||
|
@ -178,7 +178,8 @@ lpfc_dump_wakeup_param(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
||||
mb->mbxOwner = OWN_HOST;
|
||||
mb->un.varDmp.cv = 1;
|
||||
mb->un.varDmp.type = DMP_NV_PARAMS;
|
||||
mb->un.varDmp.entry_index = 0;
|
||||
if (phba->sli_rev < LPFC_SLI_REV4)
|
||||
mb->un.varDmp.entry_index = 0;
|
||||
mb->un.varDmp.region_id = WAKE_UP_PARMS_REGION_ID;
|
||||
mb->un.varDmp.word_cnt = WAKE_UP_PARMS_WORD_SIZE;
|
||||
mb->un.varDmp.co = 0;
|
||||
@ -361,7 +362,7 @@ lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||
/* NEW_FEATURE
|
||||
* SLI-2, Coalescing Response Feature.
|
||||
*/
|
||||
if (phba->cfg_cr_delay) {
|
||||
if (phba->cfg_cr_delay && (phba->sli_rev < LPFC_SLI_REV4)) {
|
||||
mb->un.varCfgLnk.cr = 1;
|
||||
mb->un.varCfgLnk.ci = 1;
|
||||
mb->un.varCfgLnk.cr_delay = phba->cfg_cr_delay;
|
||||
@ -377,7 +378,7 @@ lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||
mb->un.varCfgLnk.crtov = phba->fc_crtov;
|
||||
mb->un.varCfgLnk.citov = phba->fc_citov;
|
||||
|
||||
if (phba->cfg_ack0)
|
||||
if (phba->cfg_ack0 && (phba->sli_rev < LPFC_SLI_REV4))
|
||||
mb->un.varCfgLnk.ack0_enable = 1;
|
||||
|
||||
mb->mbxCommand = MBX_CONFIG_LINK;
|
||||
|
@ -690,11 +690,15 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
|
||||
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
|
||||
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
|
||||
ndlp->nlp_flag &= ~NLP_FIRSTBURST;
|
||||
if (npr->prliType == PRLI_FCP_TYPE) {
|
||||
if (npr->initiatorFunc)
|
||||
ndlp->nlp_type |= NLP_FCP_INITIATOR;
|
||||
if (npr->targetFunc)
|
||||
if (npr->targetFunc) {
|
||||
ndlp->nlp_type |= NLP_FCP_TARGET;
|
||||
if (npr->writeXferRdyDis)
|
||||
ndlp->nlp_flag |= NLP_FIRSTBURST;
|
||||
}
|
||||
if (npr->Retry)
|
||||
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
|
||||
}
|
||||
@ -1676,12 +1680,16 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
/* Check out PRLI rsp */
|
||||
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
|
||||
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
|
||||
ndlp->nlp_flag &= ~NLP_FIRSTBURST;
|
||||
if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
|
||||
(npr->prliType == PRLI_FCP_TYPE)) {
|
||||
if (npr->initiatorFunc)
|
||||
ndlp->nlp_type |= NLP_FCP_INITIATOR;
|
||||
if (npr->targetFunc)
|
||||
if (npr->targetFunc) {
|
||||
ndlp->nlp_type |= NLP_FCP_TARGET;
|
||||
if (npr->writeXferRdyDis)
|
||||
ndlp->nlp_flag |= NLP_FIRSTBURST;
|
||||
}
|
||||
if (npr->Retry)
|
||||
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
|
||||
}
|
||||
|
@ -4386,11 +4386,11 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
|
||||
if (scsi_sg_count(scsi_cmnd)) {
|
||||
if (datadir == DMA_TO_DEVICE) {
|
||||
iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
|
||||
if (sli4)
|
||||
iocb_cmd->ulpPU = PARM_READ_CHECK;
|
||||
else {
|
||||
iocb_cmd->un.fcpi.fcpi_parm = 0;
|
||||
iocb_cmd->ulpPU = 0;
|
||||
iocb_cmd->ulpPU = PARM_READ_CHECK;
|
||||
if (vport->cfg_first_burst_size &&
|
||||
(pnode->nlp_flag & NLP_FIRSTBURST)) {
|
||||
piocbq->iocb.un.fcpi.fcpi_XRdy =
|
||||
vport->cfg_first_burst_size;
|
||||
}
|
||||
fcp_cmnd->fcpCntl3 = WRITE_DATA;
|
||||
phba->fc4OutputRequests++;
|
||||
@ -5022,6 +5022,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
|
||||
lpfc_release_scsi_buf(phba, lpfc_cmd);
|
||||
return FAILED;
|
||||
}
|
||||
iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
|
||||
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
|
||||
"0702 Issue %s to TGT %d LUN %d "
|
||||
@ -5034,7 +5035,6 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
|
||||
iocbq, iocbqrsp, lpfc_cmd->timeout);
|
||||
if (status != IOCB_SUCCESS) {
|
||||
if (status == IOCB_TIMEDOUT) {
|
||||
iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
|
||||
ret = TIMEOUT_ERROR;
|
||||
} else
|
||||
ret = FAILED;
|
||||
|
@ -6163,6 +6163,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
|
||||
kfree(vpd);
|
||||
goto out_free_mbox;
|
||||
}
|
||||
|
||||
mqe = &mboxq->u.mqe;
|
||||
phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
|
||||
if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev))
|
||||
@ -6249,6 +6250,16 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
|
||||
phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow,
|
||||
phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow);
|
||||
|
||||
/* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3) */
|
||||
rc = (phba->sli4_hba.max_cfg_param.max_xri >> 3);
|
||||
if (phba->pport->cfg_lun_queue_depth > rc) {
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
||||
"3362 LUN queue depth changed from %d to %d\n",
|
||||
phba->pport->cfg_lun_queue_depth, rc);
|
||||
phba->pport->cfg_lun_queue_depth = rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Discover the port's supported feature set and match it against the
|
||||
* hosts requests.
|
||||
@ -9889,6 +9900,24 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
|
||||
struct lpfc_scsi_buf *lpfc_cmd;
|
||||
|
||||
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||
if (cmdiocbq->iocb_flag & LPFC_IO_WAKE_TMO) {
|
||||
|
||||
/*
|
||||
* A time out has occurred for the iocb. If a time out
|
||||
* completion handler has been supplied, call it. Otherwise,
|
||||
* just free the iocbq.
|
||||
*/
|
||||
|
||||
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||
cmdiocbq->iocb_cmpl = cmdiocbq->wait_iocb_cmpl;
|
||||
cmdiocbq->wait_iocb_cmpl = NULL;
|
||||
if (cmdiocbq->iocb_cmpl)
|
||||
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq, NULL);
|
||||
else
|
||||
lpfc_sli_release_iocbq(phba, cmdiocbq);
|
||||
return;
|
||||
}
|
||||
|
||||
cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
|
||||
if (cmdiocbq->context2 && rspiocbq)
|
||||
memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
|
||||
@ -9944,10 +9973,16 @@ lpfc_chk_iocb_flg(struct lpfc_hba *phba,
|
||||
* @timeout: Timeout in number of seconds.
|
||||
*
|
||||
* This function issues the iocb to firmware and waits for the
|
||||
* iocb to complete. If the iocb command is not
|
||||
* completed within timeout seconds, it returns IOCB_TIMEDOUT.
|
||||
* Caller should not free the iocb resources if this function
|
||||
* returns IOCB_TIMEDOUT.
|
||||
* iocb to complete. The iocb_cmpl field of the shall be used
|
||||
* to handle iocbs which time out. If the field is NULL, the
|
||||
* function shall free the iocbq structure. If more clean up is
|
||||
* needed, the caller is expected to provide a completion function
|
||||
* that will provide the needed clean up. If the iocb command is
|
||||
* not completed within timeout seconds, the function will either
|
||||
* free the iocbq structure (if iocb_cmpl == NULL) or execute the
|
||||
* completion function set in the iocb_cmpl field and then return
|
||||
* a status of IOCB_TIMEDOUT. The caller should not free the iocb
|
||||
* resources if this function returns IOCB_TIMEDOUT.
|
||||
* The function waits for the iocb completion using an
|
||||
* non-interruptible wait.
|
||||
* This function will sleep while waiting for iocb completion.
|
||||
@ -9980,6 +10015,9 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
|
||||
int txq_cnt = 0;
|
||||
int txcmplq_cnt = 0;
|
||||
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
|
||||
unsigned long iflags;
|
||||
bool iocb_completed = true;
|
||||
|
||||
/*
|
||||
* If the caller has provided a response iocbq buffer, then context2
|
||||
* is NULL or its an error.
|
||||
@ -9990,9 +10028,10 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
|
||||
piocb->context2 = prspiocbq;
|
||||
}
|
||||
|
||||
piocb->wait_iocb_cmpl = piocb->iocb_cmpl;
|
||||
piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait;
|
||||
piocb->context_un.wait_queue = &done_q;
|
||||
piocb->iocb_flag &= ~LPFC_IO_WAKE;
|
||||
piocb->iocb_flag &= ~(LPFC_IO_WAKE | LPFC_IO_WAKE_TMO);
|
||||
|
||||
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
|
||||
if (lpfc_readl(phba->HCregaddr, &creg_val))
|
||||
@ -10009,8 +10048,19 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
|
||||
timeleft = wait_event_timeout(done_q,
|
||||
lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE),
|
||||
timeout_req);
|
||||
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||
if (!(piocb->iocb_flag & LPFC_IO_WAKE)) {
|
||||
|
||||
if (piocb->iocb_flag & LPFC_IO_WAKE) {
|
||||
/*
|
||||
* IOCB timed out. Inform the wake iocb wait
|
||||
* completion function and set local status
|
||||
*/
|
||||
|
||||
iocb_completed = false;
|
||||
piocb->iocb_flag |= LPFC_IO_WAKE_TMO;
|
||||
}
|
||||
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||
if (iocb_completed) {
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||
"0331 IOCB wake signaled\n");
|
||||
} else if (timeleft == 0) {
|
||||
@ -10122,7 +10172,6 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
|
||||
*/
|
||||
if (pmboxq->mbox_flag & LPFC_MBX_WAKE) {
|
||||
retval = MBX_SUCCESS;
|
||||
lpfc_sli4_swap_str(phba, pmboxq);
|
||||
} else {
|
||||
retval = MBX_TIMEOUT;
|
||||
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
@ -12820,10 +12869,44 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
|
||||
wq->page_count);
|
||||
bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
|
||||
cq->queue_id);
|
||||
|
||||
/* wqv is the earliest version supported, NOT the latest */
|
||||
bf_set(lpfc_mbox_hdr_version, &shdr->request,
|
||||
phba->sli4_hba.pc_sli4_params.wqv);
|
||||
|
||||
if (phba->sli4_hba.pc_sli4_params.wqv == LPFC_Q_CREATE_VERSION_1) {
|
||||
switch (phba->sli4_hba.pc_sli4_params.wqv) {
|
||||
case LPFC_Q_CREATE_VERSION_0:
|
||||
switch (wq->entry_size) {
|
||||
default:
|
||||
case 64:
|
||||
/* Nothing to do, version 0 ONLY supports 64 byte */
|
||||
page = wq_create->u.request.page;
|
||||
break;
|
||||
case 128:
|
||||
if (!(phba->sli4_hba.pc_sli4_params.wqsize &
|
||||
LPFC_WQ_SZ128_SUPPORT)) {
|
||||
status = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
/* If we get here the HBA MUST also support V1 and
|
||||
* we MUST use it
|
||||
*/
|
||||
bf_set(lpfc_mbox_hdr_version, &shdr->request,
|
||||
LPFC_Q_CREATE_VERSION_1);
|
||||
|
||||
bf_set(lpfc_mbx_wq_create_wqe_count,
|
||||
&wq_create->u.request_1, wq->entry_count);
|
||||
bf_set(lpfc_mbx_wq_create_wqe_size,
|
||||
&wq_create->u.request_1,
|
||||
LPFC_WQ_WQE_SIZE_128);
|
||||
bf_set(lpfc_mbx_wq_create_page_size,
|
||||
&wq_create->u.request_1,
|
||||
(PAGE_SIZE/SLI4_PAGE_SIZE));
|
||||
page = wq_create->u.request_1.page;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LPFC_Q_CREATE_VERSION_1:
|
||||
bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
|
||||
wq->entry_count);
|
||||
switch (wq->entry_size) {
|
||||
@ -12834,6 +12917,11 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
|
||||
LPFC_WQ_WQE_SIZE_64);
|
||||
break;
|
||||
case 128:
|
||||
if (!(phba->sli4_hba.pc_sli4_params.wqsize &
|
||||
LPFC_WQ_SZ128_SUPPORT)) {
|
||||
status = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
bf_set(lpfc_mbx_wq_create_wqe_size,
|
||||
&wq_create->u.request_1,
|
||||
LPFC_WQ_WQE_SIZE_128);
|
||||
@ -12842,9 +12930,12 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
|
||||
bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1,
|
||||
(PAGE_SIZE/SLI4_PAGE_SIZE));
|
||||
page = wq_create->u.request_1.page;
|
||||
} else {
|
||||
page = wq_create->u.request.page;
|
||||
break;
|
||||
default:
|
||||
status = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_for_each_entry(dmabuf, &wq->page_list, list) {
|
||||
memset(dmabuf->virt, 0, hw_page_size);
|
||||
page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys);
|
||||
@ -14665,14 +14756,20 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
|
||||
first_iocbq->iocb.unsli3.rcvsli3.vpi =
|
||||
vport->phba->vpi_ids[vport->vpi];
|
||||
/* put the first buffer into the first IOCBq */
|
||||
tot_len = bf_get(lpfc_rcqe_length,
|
||||
&seq_dmabuf->cq_event.cqe.rcqe_cmpl);
|
||||
|
||||
first_iocbq->context2 = &seq_dmabuf->dbuf;
|
||||
first_iocbq->context3 = NULL;
|
||||
first_iocbq->iocb.ulpBdeCount = 1;
|
||||
first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
|
||||
if (tot_len > LPFC_DATA_BUF_SIZE)
|
||||
first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
|
||||
LPFC_DATA_BUF_SIZE;
|
||||
else
|
||||
first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = tot_len;
|
||||
|
||||
first_iocbq->iocb.un.rcvels.remoteID = sid;
|
||||
tot_len = bf_get(lpfc_rcqe_length,
|
||||
&seq_dmabuf->cq_event.cqe.rcqe_cmpl);
|
||||
|
||||
first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
|
||||
}
|
||||
iocbq = first_iocbq;
|
||||
@ -14688,14 +14785,17 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
|
||||
if (!iocbq->context3) {
|
||||
iocbq->context3 = d_buf;
|
||||
iocbq->iocb.ulpBdeCount++;
|
||||
pbde = (struct ulp_bde64 *)
|
||||
&iocbq->iocb.unsli3.sli3Words[4];
|
||||
pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
|
||||
|
||||
/* We need to get the size out of the right CQE */
|
||||
hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
|
||||
len = bf_get(lpfc_rcqe_length,
|
||||
&hbq_buf->cq_event.cqe.rcqe_cmpl);
|
||||
pbde = (struct ulp_bde64 *)
|
||||
&iocbq->iocb.unsli3.sli3Words[4];
|
||||
if (len > LPFC_DATA_BUF_SIZE)
|
||||
pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
|
||||
else
|
||||
pbde->tus.f.bdeSize = len;
|
||||
|
||||
iocbq->iocb.unsli3.rcvsli3.acc_len += len;
|
||||
tot_len += len;
|
||||
} else {
|
||||
@ -14710,16 +14810,19 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
|
||||
lpfc_in_buf_free(vport->phba, d_buf);
|
||||
continue;
|
||||
}
|
||||
iocbq->context2 = d_buf;
|
||||
iocbq->context3 = NULL;
|
||||
iocbq->iocb.ulpBdeCount = 1;
|
||||
iocbq->iocb.un.cont64[0].tus.f.bdeSize =
|
||||
LPFC_DATA_BUF_SIZE;
|
||||
|
||||
/* We need to get the size out of the right CQE */
|
||||
hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
|
||||
len = bf_get(lpfc_rcqe_length,
|
||||
&hbq_buf->cq_event.cqe.rcqe_cmpl);
|
||||
iocbq->context2 = d_buf;
|
||||
iocbq->context3 = NULL;
|
||||
iocbq->iocb.ulpBdeCount = 1;
|
||||
if (len > LPFC_DATA_BUF_SIZE)
|
||||
iocbq->iocb.un.cont64[0].tus.f.bdeSize =
|
||||
LPFC_DATA_BUF_SIZE;
|
||||
else
|
||||
iocbq->iocb.un.cont64[0].tus.f.bdeSize = len;
|
||||
|
||||
tot_len += len;
|
||||
iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*******************************************************************
|
||||
* This file is part of the Emulex Linux Device Driver for *
|
||||
* Fibre Channel Host Bus Adapters. *
|
||||
* Copyright (C) 2004-2007 Emulex. All rights reserved. *
|
||||
* Copyright (C) 2004-2013 Emulex. All rights reserved. *
|
||||
* EMULEX and SLI are trademarks of Emulex. *
|
||||
* www.emulex.com *
|
||||
* *
|
||||
@ -60,7 +60,8 @@ struct lpfc_iocbq {
|
||||
uint8_t retry; /* retry counter for IOCB cmd - if needed */
|
||||
uint16_t iocb_flag;
|
||||
#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
|
||||
#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
|
||||
#define LPFC_IO_WAKE 2 /* Synchronous I/O completed */
|
||||
#define LPFC_IO_WAKE_TMO LPFC_IO_WAKE /* Synchronous I/O timed out */
|
||||
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
|
||||
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
|
||||
#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
|
||||
@ -93,6 +94,8 @@ struct lpfc_iocbq {
|
||||
|
||||
void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
||||
struct lpfc_iocbq *);
|
||||
void (*wait_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
||||
struct lpfc_iocbq *);
|
||||
void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
||||
struct lpfc_iocbq *);
|
||||
};
|
||||
|
@ -117,6 +117,7 @@ union sli4_qe {
|
||||
struct lpfc_rcqe_complete *rcqe_complete;
|
||||
struct lpfc_mqe *mqe;
|
||||
union lpfc_wqe *wqe;
|
||||
union lpfc_wqe128 *wqe128;
|
||||
struct lpfc_rqe *rqe;
|
||||
};
|
||||
|
||||
@ -325,12 +326,14 @@ struct lpfc_bmbx {
|
||||
#define LPFC_EQE_SIZE_16B 16
|
||||
#define LPFC_CQE_SIZE 16
|
||||
#define LPFC_WQE_SIZE 64
|
||||
#define LPFC_WQE128_SIZE 128
|
||||
#define LPFC_MQE_SIZE 256
|
||||
#define LPFC_RQE_SIZE 8
|
||||
|
||||
#define LPFC_EQE_DEF_COUNT 1024
|
||||
#define LPFC_CQE_DEF_COUNT 1024
|
||||
#define LPFC_WQE_DEF_COUNT 256
|
||||
#define LPFC_WQE128_DEF_COUNT 128
|
||||
#define LPFC_MQE_DEF_COUNT 16
|
||||
#define LPFC_RQE_DEF_COUNT 512
|
||||
|
||||
@ -416,6 +419,9 @@ struct lpfc_pc_sli4_params {
|
||||
uint8_t mqv;
|
||||
uint8_t wqv;
|
||||
uint8_t rqv;
|
||||
uint8_t wqsize;
|
||||
#define LPFC_WQ_SZ64_SUPPORT 1
|
||||
#define LPFC_WQ_SZ128_SUPPORT 2
|
||||
};
|
||||
|
||||
struct lpfc_iov {
|
||||
|
@ -18,7 +18,7 @@
|
||||
* included with this package. *
|
||||
*******************************************************************/
|
||||
|
||||
#define LPFC_DRIVER_VERSION "8.3.40"
|
||||
#define LPFC_DRIVER_VERSION "8.3.41"
|
||||
#define LPFC_DRIVER_NAME "lpfc"
|
||||
|
||||
/* Used for SLI 2/3 */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*******************************************************************
|
||||
* This file is part of the Emulex Linux Device Driver for *
|
||||
* Fibre Channel Host Bus Adapters. *
|
||||
* Copyright (C) 2004-2008 Emulex. All rights reserved. *
|
||||
* Copyright (C) 2004-2013 Emulex. All rights reserved. *
|
||||
* EMULEX and SLI are trademarks of Emulex. *
|
||||
* www.emulex.com *
|
||||
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
|
||||
@ -387,6 +387,9 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
|
||||
/* Create binary sysfs attribute for vport */
|
||||
lpfc_alloc_sysfs_attr(vport);
|
||||
|
||||
/* Set the DFT_LUN_Q_DEPTH accordingly */
|
||||
vport->cfg_lun_queue_depth = phba->pport->cfg_lun_queue_depth;
|
||||
|
||||
*(struct lpfc_vport **)fc_vport->dd_data = vport;
|
||||
vport->fc_vport = fc_vport;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2012 LSI Corporation.
|
||||
* Copyright (c) 2000-2013 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2.h
|
||||
@ -8,7 +8,7 @@
|
||||
* scatter/gather formats.
|
||||
* Creation Date: June 21, 2006
|
||||
*
|
||||
* mpi2.h Version: 02.00.27
|
||||
* mpi2.h Version: 02.00.28
|
||||
*
|
||||
* Version History
|
||||
* ---------------
|
||||
@ -77,6 +77,7 @@
|
||||
* Added Hard Reset delay timings.
|
||||
* 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -102,7 +103,7 @@
|
||||
#define MPI2_VERSION_02_00 (0x0200)
|
||||
|
||||
/* versioning for this MPI header set */
|
||||
#define MPI2_HEADER_VERSION_UNIT (0x1B)
|
||||
#define MPI2_HEADER_VERSION_UNIT (0x1C)
|
||||
#define MPI2_HEADER_VERSION_DEV (0x00)
|
||||
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
|
||||
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
|
||||
|
@ -1,12 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2011 LSI Corporation.
|
||||
* Copyright (c) 2000-2013 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_cnfg.h
|
||||
* Title: MPI Configuration messages and pages
|
||||
* Creation Date: November 10, 2006
|
||||
*
|
||||
* mpi2_cnfg.h Version: 02.00.22
|
||||
* mpi2_cnfg.h Version: 02.00.23
|
||||
*
|
||||
* Version History
|
||||
* ---------------
|
||||
@ -149,6 +149,8 @@
|
||||
* 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
|
||||
* Added UEFIVersion field to BIOS Page 1 and defined new
|
||||
* BiosOptions bits.
|
||||
* 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
|
||||
* Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -698,6 +700,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7
|
||||
#define MPI2_MANUFACTURING7_PAGEVERSION (0x01)
|
||||
|
||||
/* defines for the Flags field */
|
||||
#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002)
|
||||
#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
|
||||
|
||||
|
||||
@ -1224,6 +1227,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1
|
||||
#define MPI2_BIOSPAGE1_PAGEVERSION (0x05)
|
||||
|
||||
/* values for BIOS Page 1 BiosOptions field */
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000)
|
||||
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000)
|
||||
#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2012 LSI Corporation.
|
||||
* Copyright (c) 2000-2013 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_init.h
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2012 LSI Corporation.
|
||||
* Copyright (c) 2000-2013 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_ioc.h
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2012 LSI Corporation.
|
||||
* Copyright (c) 2000-2013 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_raid.h
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2010 LSI Corporation.
|
||||
* Copyright (c) 2000-2013 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_sas.h
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2012 LSI Corporation.
|
||||
* Copyright (c) 2000-2013 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_tool.h
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2007 LSI Corporation.
|
||||
* Copyright (c) 2000-2013 LSI Corporation.
|
||||
*
|
||||
*
|
||||
* Name: mpi2_type.h
|
||||
|
@ -3,7 +3,7 @@
|
||||
* for access to MPT (Message Passing Technology) firmware.
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
|
||||
* Copyright (C) 2007-2012 LSI Corporation
|
||||
* Copyright (C) 2007-2013 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -768,10 +768,9 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
|
||||
* @msix_index: MSIX table index supplied by the OS
|
||||
* @reply: reply message frame(lower 32bit addr)
|
||||
*
|
||||
* Return 1 meaning mf should be freed from _base_interrupt
|
||||
* 0 means the mf is freed from this function.
|
||||
* Returns void.
|
||||
*/
|
||||
static u8
|
||||
static void
|
||||
_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
|
||||
{
|
||||
Mpi2EventNotificationReply_t *mpi_reply;
|
||||
@ -780,9 +779,9 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
|
||||
|
||||
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
|
||||
if (!mpi_reply)
|
||||
return 1;
|
||||
return;
|
||||
if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
|
||||
return 1;
|
||||
return;
|
||||
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
|
||||
_base_display_event_data(ioc, mpi_reply);
|
||||
#endif
|
||||
@ -812,7 +811,7 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
|
||||
/* ctl callback handler */
|
||||
mpt2sas_ctl_event_callback(ioc, msix_index, reply);
|
||||
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1409,8 +1408,6 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
||||
int i;
|
||||
u8 try_msix = 0;
|
||||
|
||||
INIT_LIST_HEAD(&ioc->reply_queue_list);
|
||||
|
||||
if (msix_disable == -1 || msix_disable == 0)
|
||||
try_msix = 1;
|
||||
|
||||
@ -1489,6 +1486,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
||||
if (pci_enable_device_mem(pdev)) {
|
||||
printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "
|
||||
"failed\n", ioc->name);
|
||||
ioc->bars = 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -1497,6 +1495,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
||||
MPT2SAS_DRIVER_NAME)) {
|
||||
printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "
|
||||
"failed\n", ioc->name);
|
||||
ioc->bars = 0;
|
||||
r = -ENODEV;
|
||||
goto out_fail;
|
||||
}
|
||||
@ -4229,18 +4228,25 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
|
||||
dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
||||
__func__));
|
||||
|
||||
_base_mask_interrupts(ioc);
|
||||
ioc->shost_recovery = 1;
|
||||
_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
|
||||
ioc->shost_recovery = 0;
|
||||
if (ioc->chip_phys && ioc->chip) {
|
||||
_base_mask_interrupts(ioc);
|
||||
ioc->shost_recovery = 1;
|
||||
_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
|
||||
ioc->shost_recovery = 0;
|
||||
}
|
||||
|
||||
_base_free_irq(ioc);
|
||||
_base_disable_msix(ioc);
|
||||
if (ioc->chip_phys)
|
||||
|
||||
if (ioc->chip_phys && ioc->chip)
|
||||
iounmap(ioc->chip);
|
||||
ioc->chip_phys = 0;
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
||||
if (pci_is_enabled(pdev)) {
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* for access to MPT (Message Passing Technology) firmware.
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_base.h
|
||||
* Copyright (C) 2007-2012 LSI Corporation
|
||||
* Copyright (C) 2007-2013 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -69,8 +69,8 @@
|
||||
#define MPT2SAS_DRIVER_NAME "mpt2sas"
|
||||
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
|
||||
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
|
||||
#define MPT2SAS_DRIVER_VERSION "15.100.00.00"
|
||||
#define MPT2SAS_MAJOR_VERSION 15
|
||||
#define MPT2SAS_DRIVER_VERSION "16.100.00.00"
|
||||
#define MPT2SAS_MAJOR_VERSION 16
|
||||
#define MPT2SAS_MINOR_VERSION 100
|
||||
#define MPT2SAS_BUILD_VERSION 00
|
||||
#define MPT2SAS_RELEASE_VERSION 00
|
||||
@ -1061,7 +1061,7 @@ void mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
|
||||
int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc);
|
||||
|
||||
/* scsih shared API */
|
||||
u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
u32 reply);
|
||||
int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
|
||||
uint channel, uint id, uint lun, u8 type, u16 smid_task,
|
||||
@ -1144,7 +1144,7 @@ void mpt2sas_ctl_exit(void);
|
||||
u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
|
||||
u32 reply);
|
||||
void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
|
||||
u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
u32 reply);
|
||||
void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
|
||||
Mpi2EventNotificationReply_t *mpi_reply);
|
||||
|
@ -2,7 +2,7 @@
|
||||
* This module provides common API for accessing firmware configuration pages
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
|
||||
* Copyright (C) 2007-2012 LSI Corporation
|
||||
* Copyright (C) 2007-2013 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -3,7 +3,7 @@
|
||||
* controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
|
||||
* Copyright (C) 2007-2012 LSI Corporation
|
||||
* Copyright (C) 2007-2013 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -397,18 +397,22 @@ mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
|
||||
* This function merely adds a new work task into ioc->firmware_event_thread.
|
||||
* The tasks are worked from _firmware_event_work in user context.
|
||||
*
|
||||
* Return 1 meaning mf should be freed from _base_interrupt
|
||||
* 0 means the mf is freed from this function.
|
||||
* Returns void.
|
||||
*/
|
||||
u8
|
||||
void
|
||||
mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
u32 reply)
|
||||
{
|
||||
Mpi2EventNotificationReply_t *mpi_reply;
|
||||
|
||||
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
|
||||
if (unlikely(!mpi_reply)) {
|
||||
printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
return;
|
||||
}
|
||||
mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,7 +3,7 @@
|
||||
* controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
|
||||
* Copyright (C) 2007-2012 LSI Corporation
|
||||
* Copyright (C) 2007-2013 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Logging Support for MPT (Message Passing Technology) based controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
|
||||
* Copyright (C) 2007-2012 LSI Corporation
|
||||
* Copyright (C) 2007-2013 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Scsi Host Layer for MPT (Message Passing Technology) based controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
|
||||
* Copyright (C) 2007-2012 LSI Corporation
|
||||
* Copyright (C) 2007-2013 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -628,11 +628,12 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
|
||||
* devices while scanning is turned on due to an oops in
|
||||
* scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start()
|
||||
*/
|
||||
if (!ioc->is_driver_loading)
|
||||
if (!ioc->is_driver_loading) {
|
||||
mpt2sas_transport_port_remove(ioc,
|
||||
sas_device->sas_address,
|
||||
sas_device->sas_address_parent);
|
||||
_scsih_sas_device_remove(ioc, sas_device);
|
||||
_scsih_sas_device_remove(ioc, sas_device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1402,6 +1403,7 @@ _scsih_slave_alloc(struct scsi_device *sdev)
|
||||
struct MPT2SAS_DEVICE *sas_device_priv_data;
|
||||
struct scsi_target *starget;
|
||||
struct _raid_device *raid_device;
|
||||
struct _sas_device *sas_device;
|
||||
unsigned long flags;
|
||||
|
||||
sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
|
||||
@ -1430,6 +1432,19 @@ _scsih_slave_alloc(struct scsi_device *sdev)
|
||||
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
|
||||
}
|
||||
|
||||
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
|
||||
sas_target_priv_data->sas_address);
|
||||
if (sas_device && (sas_device->starget == NULL)) {
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s : sas_device->starget set to starget @ %d\n",
|
||||
__func__, __LINE__);
|
||||
sas_device->starget = starget;
|
||||
}
|
||||
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -6753,7 +6768,7 @@ _scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
|
||||
handle))) {
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
|
||||
break;
|
||||
handle = le16_to_cpu(sas_device_pg0.DevHandle);
|
||||
device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
|
||||
@ -6862,7 +6877,7 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
|
||||
&volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
|
||||
break;
|
||||
handle = le16_to_cpu(volume_pg1.DevHandle);
|
||||
|
||||
@ -6887,7 +6902,7 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
|
||||
phys_disk_num))) {
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
|
||||
break;
|
||||
phys_disk_num = pd_pg0.PhysDiskNum;
|
||||
handle = le16_to_cpu(pd_pg0.DevHandle);
|
||||
@ -6967,7 +6982,7 @@ _scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
|
||||
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
|
||||
break;
|
||||
|
||||
handle = le16_to_cpu(expander_pg0.DevHandle);
|
||||
@ -7109,8 +7124,6 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||||
MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
break;
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||||
printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: "
|
||||
"ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||||
@ -7153,8 +7166,6 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||||
phys_disk_num))) {
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
break;
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||||
printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:"
|
||||
"ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||||
@ -7219,8 +7230,6 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||||
&volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
break;
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||||
printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
|
||||
"ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||||
@ -7278,8 +7287,6 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
|
||||
handle))) {
|
||||
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
|
||||
MPI2_IOCSTATUS_MASK;
|
||||
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
|
||||
break;
|
||||
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
|
||||
printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:"
|
||||
" ioc_status(0x%04x), loginfo(0x%08x)\n",
|
||||
@ -7471,10 +7478,9 @@ _firmware_event_work(struct work_struct *work)
|
||||
* This function merely adds a new work task into ioc->firmware_event_thread.
|
||||
* The tasks are worked from _firmware_event_work in user context.
|
||||
*
|
||||
* Return 1 meaning mf should be freed from _base_interrupt
|
||||
* 0 means the mf is freed from this function.
|
||||
* Returns void.
|
||||
*/
|
||||
u8
|
||||
void
|
||||
mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
u32 reply)
|
||||
{
|
||||
@ -7485,14 +7491,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
|
||||
/* events turned off due to host reset or driver unloading */
|
||||
if (ioc->remove_host || ioc->pci_error_recovery)
|
||||
return 1;
|
||||
return;
|
||||
|
||||
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
|
||||
|
||||
if (unlikely(!mpi_reply)) {
|
||||
printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
event = le16_to_cpu(mpi_reply->Event);
|
||||
@ -7507,11 +7513,11 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
|
||||
if (baen_data->Primitive !=
|
||||
MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
|
||||
return 1;
|
||||
return;
|
||||
|
||||
if (ioc->broadcast_aen_busy) {
|
||||
ioc->broadcast_aen_pending++;
|
||||
return 1;
|
||||
return;
|
||||
} else
|
||||
ioc->broadcast_aen_busy = 1;
|
||||
break;
|
||||
@ -7587,14 +7593,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
break;
|
||||
|
||||
default: /* ignore the rest */
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
|
||||
if (!fw_event) {
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
|
||||
fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
|
||||
@ -7602,7 +7608,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
|
||||
ioc->name, __FILE__, __LINE__, __func__);
|
||||
kfree(fw_event);
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(fw_event->event_data, mpi_reply->EventData,
|
||||
@ -7612,7 +7618,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
|
||||
fw_event->VP_ID = mpi_reply->VP_ID;
|
||||
fw_event->event = event;
|
||||
_scsih_fw_event_add(ioc, fw_event);
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* shost template */
|
||||
@ -7711,10 +7717,6 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
|
||||
if (!ioc->ir_firmware)
|
||||
return;
|
||||
|
||||
/* are there any volumes ? */
|
||||
if (list_empty(&ioc->raid_device_list))
|
||||
return;
|
||||
|
||||
mutex_lock(&ioc->scsih_cmds.mutex);
|
||||
|
||||
if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
|
||||
@ -7929,10 +7931,12 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
|
||||
sas_device->sas_address_parent)) {
|
||||
_scsih_sas_device_remove(ioc, sas_device);
|
||||
} else if (!sas_device->starget) {
|
||||
if (!ioc->is_driver_loading)
|
||||
mpt2sas_transport_port_remove(ioc, sas_address,
|
||||
if (!ioc->is_driver_loading) {
|
||||
mpt2sas_transport_port_remove(ioc,
|
||||
sas_address,
|
||||
sas_address_parent);
|
||||
_scsih_sas_device_remove(ioc, sas_device);
|
||||
_scsih_sas_device_remove(ioc, sas_device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7985,14 +7989,14 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
|
||||
kfree(sas_device);
|
||||
continue;
|
||||
} else if (!sas_device->starget) {
|
||||
if (!ioc->is_driver_loading)
|
||||
if (!ioc->is_driver_loading) {
|
||||
mpt2sas_transport_port_remove(ioc,
|
||||
sas_device->sas_address,
|
||||
sas_device->sas_address_parent);
|
||||
list_del(&sas_device->list);
|
||||
kfree(sas_device);
|
||||
continue;
|
||||
|
||||
list_del(&sas_device->list);
|
||||
kfree(sas_device);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
spin_lock_irqsave(&ioc->sas_device_lock, flags);
|
||||
list_move_tail(&sas_device->list, &ioc->sas_device_list);
|
||||
@ -8175,6 +8179,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
|
||||
INIT_LIST_HEAD(&ioc->delayed_tr_list);
|
||||
INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
|
||||
INIT_LIST_HEAD(&ioc->reply_queue_list);
|
||||
|
||||
/* init shost parameters */
|
||||
shost->max_cmd_len = 32;
|
||||
@ -8280,6 +8285,7 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
|
||||
mpt2sas_base_stop_watchdog(ioc);
|
||||
scsi_block_requests(shost);
|
||||
_scsih_ir_shutdown(ioc);
|
||||
device_state = pci_choose_state(pdev, state);
|
||||
printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
|
||||
"operating state [D%d]\n", ioc->name, pdev,
|
||||
|
@ -2,7 +2,7 @@
|
||||
* SAS Transport Layer for MPT (Message Passing Technology) based controllers
|
||||
*
|
||||
* This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
|
||||
* Copyright (C) 2007-2012 LSI Corporation
|
||||
* Copyright (C) 2007-2013 LSI Corporation
|
||||
* (mailto:DL-MPTFusionLinux@lsi.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -1006,9 +1006,12 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
|
||||
&mpt2sas_phy->remote_identify);
|
||||
_transport_add_phy_to_an_existing_port(ioc, sas_node,
|
||||
mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address);
|
||||
} else
|
||||
} else {
|
||||
memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
|
||||
sas_identify));
|
||||
_transport_del_phy_from_an_existing_port(ioc, sas_node,
|
||||
mpt2sas_phy);
|
||||
}
|
||||
|
||||
if (mpt2sas_phy->phy)
|
||||
mpt2sas_phy->phy->negotiated_linkrate =
|
||||
|
@ -82,6 +82,10 @@ static int msix_disable = -1;
|
||||
module_param(msix_disable, int, 0);
|
||||
MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
|
||||
|
||||
static int max_msix_vectors = 8;
|
||||
module_param(max_msix_vectors, int, 0);
|
||||
MODULE_PARM_DESC(max_msix_vectors,
|
||||
" max msix vectors - (default=8)");
|
||||
|
||||
static int mpt3sas_fwfault_debug;
|
||||
MODULE_PARM_DESC(mpt3sas_fwfault_debug,
|
||||
@ -1709,8 +1713,6 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
|
||||
int i;
|
||||
u8 try_msix = 0;
|
||||
|
||||
INIT_LIST_HEAD(&ioc->reply_queue_list);
|
||||
|
||||
if (msix_disable == -1 || msix_disable == 0)
|
||||
try_msix = 1;
|
||||
|
||||
@ -1723,6 +1725,16 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc)
|
||||
ioc->reply_queue_count = min_t(int, ioc->cpu_count,
|
||||
ioc->msix_vector_count);
|
||||
|
||||
printk(MPT3SAS_FMT "MSI-X vectors supported: %d, no of cores"
|
||||
": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count,
|
||||
ioc->cpu_count, max_msix_vectors);
|
||||
|
||||
if (max_msix_vectors > 0) {
|
||||
ioc->reply_queue_count = min_t(int, max_msix_vectors,
|
||||
ioc->reply_queue_count);
|
||||
ioc->msix_vector_count = ioc->reply_queue_count;
|
||||
}
|
||||
|
||||
entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
|
||||
GFP_KERNEL);
|
||||
if (!entries) {
|
||||
@ -1790,6 +1802,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
if (pci_enable_device_mem(pdev)) {
|
||||
pr_warn(MPT3SAS_FMT "pci_enable_device_mem: failed\n",
|
||||
ioc->name);
|
||||
ioc->bars = 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -1798,6 +1811,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
MPT3SAS_DRIVER_NAME)) {
|
||||
pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n",
|
||||
ioc->name);
|
||||
ioc->bars = 0;
|
||||
r = -ENODEV;
|
||||
goto out_fail;
|
||||
}
|
||||
@ -4393,18 +4407,25 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
|
||||
dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
|
||||
__func__));
|
||||
|
||||
_base_mask_interrupts(ioc);
|
||||
ioc->shost_recovery = 1;
|
||||
_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
|
||||
ioc->shost_recovery = 0;
|
||||
if (ioc->chip_phys && ioc->chip) {
|
||||
_base_mask_interrupts(ioc);
|
||||
ioc->shost_recovery = 1;
|
||||
_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
|
||||
ioc->shost_recovery = 0;
|
||||
}
|
||||
|
||||
_base_free_irq(ioc);
|
||||
_base_disable_msix(ioc);
|
||||
if (ioc->chip_phys)
|
||||
|
||||
if (ioc->chip_phys && ioc->chip)
|
||||
iounmap(ioc->chip);
|
||||
ioc->chip_phys = 0;
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
||||
if (pci_is_enabled(pdev)) {
|
||||
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7779,6 +7779,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
|
||||
INIT_LIST_HEAD(&ioc->delayed_tr_list);
|
||||
INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
|
||||
INIT_LIST_HEAD(&ioc->reply_queue_list);
|
||||
|
||||
/* init shost parameters */
|
||||
shost->max_cmd_len = 32;
|
||||
|
@ -1003,9 +1003,12 @@ mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc,
|
||||
&mpt3sas_phy->remote_identify);
|
||||
_transport_add_phy_to_an_existing_port(ioc, sas_node,
|
||||
mpt3sas_phy, mpt3sas_phy->remote_identify.sas_address);
|
||||
} else
|
||||
} else {
|
||||
memset(&mpt3sas_phy->remote_identify, 0 , sizeof(struct
|
||||
sas_identify));
|
||||
_transport_del_phy_from_an_existing_port(ioc, sas_node,
|
||||
mpt3sas_phy);
|
||||
}
|
||||
|
||||
if (mpt3sas_phy->phy)
|
||||
mpt3sas_phy->phy->negotiated_linkrate =
|
||||
|
@ -424,7 +424,8 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
|
||||
PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
|
||||
"base addr %llx virt_addr=%llx len=%d\n",
|
||||
(u64)pm8001_ha->io_mem[logicalBar].membase,
|
||||
(u64)pm8001_ha->io_mem[logicalBar].memvirtaddr,
|
||||
(u64)(unsigned long)
|
||||
pm8001_ha->io_mem[logicalBar].memvirtaddr,
|
||||
pm8001_ha->io_mem[logicalBar].memsize));
|
||||
} else {
|
||||
pm8001_ha->io_mem[logicalBar].membase = 0;
|
||||
@ -734,7 +735,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
|
||||
pdev = pm8001_ha->pdev;
|
||||
|
||||
#ifdef PM8001_USE_MSIX
|
||||
if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
|
||||
if (pdev->msix_cap)
|
||||
return pm8001_setup_msix(pm8001_ha);
|
||||
else {
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
|
@ -1,6 +1,6 @@
|
||||
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 qla_dfs.o qla_bsg.o \
|
||||
qla_nx.o qla_mr.o qla_target.o
|
||||
qla_nx.o qla_mr.o qla_nx2.o qla_target.o
|
||||
|
||||
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
|
||||
obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o
|
||||
|
@ -29,7 +29,7 @@ qla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
|
||||
if (!(ha->fw_dump_reading || ha->mctp_dump_reading))
|
||||
return 0;
|
||||
|
||||
if (IS_QLA82XX(ha)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
if (off < ha->md_template_size) {
|
||||
rval = memory_read_from_buffer(buf, count,
|
||||
&off, ha->md_tmplt_hdr, ha->md_template_size);
|
||||
@ -71,7 +71,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
|
||||
ql_log(ql_log_info, vha, 0x705d,
|
||||
"Firmware dump cleared on (%ld).\n", vha->host_no);
|
||||
|
||||
if (IS_QLA82XX(vha->hw)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
qla82xx_md_free(vha);
|
||||
qla82xx_md_prep(vha);
|
||||
}
|
||||
@ -95,11 +95,15 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
|
||||
qla82xx_idc_lock(ha);
|
||||
qla82xx_set_reset_owner(vha);
|
||||
qla82xx_idc_unlock(ha);
|
||||
} else if (IS_QLA8044(ha)) {
|
||||
qla8044_idc_lock(ha);
|
||||
qla82xx_set_reset_owner(vha);
|
||||
qla8044_idc_unlock(ha);
|
||||
} else
|
||||
qla2x00_system_error(vha);
|
||||
break;
|
||||
case 4:
|
||||
if (IS_QLA82XX(ha)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
if (ha->md_tmplt_hdr)
|
||||
ql_dbg(ql_dbg_user, vha, 0x705b,
|
||||
"MiniDump supported with this firmware.\n");
|
||||
@ -109,7 +113,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
break;
|
||||
case 6:
|
||||
@ -586,7 +590,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
||||
int type;
|
||||
uint32_t idc_control;
|
||||
|
||||
uint8_t *tmp_data = NULL;
|
||||
if (off != 0)
|
||||
return -EINVAL;
|
||||
|
||||
@ -597,14 +601,23 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
"Issuing ISP reset.\n");
|
||||
|
||||
scsi_block_requests(vha->host);
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
if (IS_QLA82XX(ha)) {
|
||||
ha->flags.isp82xx_no_md_cap = 1;
|
||||
qla82xx_idc_lock(ha);
|
||||
qla82xx_set_reset_owner(vha);
|
||||
qla82xx_idc_unlock(ha);
|
||||
} else if (IS_QLA8044(ha)) {
|
||||
qla8044_idc_lock(ha);
|
||||
idc_control = qla8044_rd_reg(ha,
|
||||
QLA8044_IDC_DRV_CTRL);
|
||||
qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
|
||||
(idc_control | GRACEFUL_RESET_BIT1));
|
||||
qla82xx_set_reset_owner(vha);
|
||||
qla8044_idc_unlock(ha);
|
||||
} else {
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
qla2xxx_wake_dpc(vha);
|
||||
}
|
||||
qla2xxx_wake_dpc(vha);
|
||||
qla2x00_wait_for_chip_reset(vha);
|
||||
scsi_unblock_requests(vha->host);
|
||||
break;
|
||||
@ -640,7 +653,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
break;
|
||||
}
|
||||
case 0x2025e:
|
||||
if (!IS_QLA82XX(ha) || vha != base_vha) {
|
||||
if (!IS_P3P_TYPE(ha) || vha != base_vha) {
|
||||
ql_log(ql_log_info, vha, 0x7071,
|
||||
"FCoE ctx reset no supported.\n");
|
||||
return -EPERM;
|
||||
@ -674,7 +687,19 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
__qla83xx_set_idc_control(vha, idc_control);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
break;
|
||||
case 0x20261:
|
||||
ql_dbg(ql_dbg_user, vha, 0x70e0,
|
||||
"Updating cache versions without reset ");
|
||||
|
||||
tmp_data = vmalloc(256);
|
||||
if (!tmp_data) {
|
||||
ql_log(ql_log_warn, vha, 0x70e1,
|
||||
"Unable to allocate memory for VPD information update.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ha->isp_ops->get_flash_version(vha, tmp_data);
|
||||
vfree(tmp_data);
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@ -1212,7 +1237,7 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
|
||||
@ -1265,10 +1290,7 @@ qla2x00_vn_port_mac_address_show(struct device *dev,
|
||||
if (!IS_CNA_CAPABLE(vha->hw))
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
vha->fcoe_vn_port_mac[5], vha->fcoe_vn_port_mac[4],
|
||||
vha->fcoe_vn_port_mac[3], vha->fcoe_vn_port_mac[2],
|
||||
vha->fcoe_vn_port_mac[1], vha->fcoe_vn_port_mac[0]);
|
||||
return snprintf(buf, PAGE_SIZE, "%pMR\n", vha->fcoe_vn_port_mac);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@ -1287,12 +1309,6 @@ qla2x00_thermal_temp_show(struct device *dev,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
uint16_t temp = 0;
|
||||
|
||||
if (!vha->hw->thermal_support) {
|
||||
ql_log(ql_log_warn, vha, 0x70db,
|
||||
"Thermal not supported by this card.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (qla2x00_reset_active(vha)) {
|
||||
ql_log(ql_log_warn, vha, 0x70dc, "ISP reset active.\n");
|
||||
goto done;
|
||||
@ -1725,11 +1741,21 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
|
||||
pfc_host_stat->lip_count = stats->lip_cnt;
|
||||
pfc_host_stat->tx_frames = stats->tx_frames;
|
||||
pfc_host_stat->rx_frames = stats->rx_frames;
|
||||
pfc_host_stat->dumped_frames = stats->dumped_frames;
|
||||
pfc_host_stat->dumped_frames = stats->discarded_frames;
|
||||
pfc_host_stat->nos_count = stats->nos_rcvd;
|
||||
pfc_host_stat->error_frames =
|
||||
stats->dropped_frames + stats->discarded_frames;
|
||||
pfc_host_stat->rx_words = vha->qla_stats.input_bytes;
|
||||
pfc_host_stat->tx_words = vha->qla_stats.output_bytes;
|
||||
}
|
||||
pfc_host_stat->fcp_control_requests = vha->qla_stats.control_requests;
|
||||
pfc_host_stat->fcp_input_requests = vha->qla_stats.input_requests;
|
||||
pfc_host_stat->fcp_output_requests = vha->qla_stats.output_requests;
|
||||
pfc_host_stat->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20;
|
||||
pfc_host_stat->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20;
|
||||
pfc_host_stat->seconds_since_last_reset =
|
||||
get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset;
|
||||
do_div(pfc_host_stat->seconds_since_last_reset, HZ);
|
||||
|
||||
done_free:
|
||||
dma_pool_free(ha->s_dma_pool, stats, stats_dma);
|
||||
@ -1737,6 +1763,16 @@ done:
|
||||
return pfc_host_stat;
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_reset_host_stats(struct Scsi_Host *shost)
|
||||
{
|
||||
scsi_qla_host_t *vha = shost_priv(shost);
|
||||
|
||||
memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
|
||||
|
||||
vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
|
||||
{
|
||||
@ -2043,6 +2079,7 @@ struct fc_function_template qla2xxx_transport_functions = {
|
||||
.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
|
||||
.terminate_rport_io = qla2x00_terminate_rport_io,
|
||||
.get_fc_host_stats = qla2x00_get_fc_host_stats,
|
||||
.reset_fc_host_stats = qla2x00_reset_host_stats,
|
||||
|
||||
.vport_create = qla24xx_vport_create,
|
||||
.vport_disable = qla24xx_vport_disable,
|
||||
@ -2089,6 +2126,8 @@ struct fc_function_template qla2xxx_transport_vport_functions = {
|
||||
.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
|
||||
.terminate_rport_io = qla2x00_terminate_rport_io,
|
||||
.get_fc_host_stats = qla2x00_get_fc_host_stats,
|
||||
.reset_fc_host_stats = qla2x00_reset_host_stats,
|
||||
|
||||
.bsg_request = qla24xx_bsg_request,
|
||||
.bsg_timeout = qla24xx_bsg_timeout,
|
||||
};
|
||||
|
@ -125,7 +125,7 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
|
||||
uint32_t len;
|
||||
uint32_t oper;
|
||||
|
||||
if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA82XX(ha))) {
|
||||
if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_P3P_TYPE(ha))) {
|
||||
ret = -EINVAL;
|
||||
goto exit_fcp_prio_cfg;
|
||||
}
|
||||
@ -559,7 +559,7 @@ qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
|
||||
uint16_t new_config[4];
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
|
||||
goto done_reset_internal;
|
||||
|
||||
memset(new_config, 0 , sizeof(new_config));
|
||||
@ -627,9 +627,10 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
|
||||
{
|
||||
int ret = 0;
|
||||
int rval = 0;
|
||||
unsigned long rem_tmo = 0, current_tmo = 0;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
|
||||
goto done_set_internal;
|
||||
|
||||
if (mode == INTERNAL_LOOPBACK)
|
||||
@ -652,8 +653,19 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
|
||||
}
|
||||
|
||||
/* Wait for DCBX complete event */
|
||||
if (!wait_for_completion_timeout(&ha->dcbx_comp,
|
||||
(DCBX_COMP_TIMEOUT * HZ))) {
|
||||
current_tmo = DCBX_COMP_TIMEOUT * HZ;
|
||||
while (1) {
|
||||
rem_tmo = wait_for_completion_timeout(&ha->dcbx_comp,
|
||||
current_tmo);
|
||||
if (!ha->idc_extend_tmo || rem_tmo) {
|
||||
ha->idc_extend_tmo = 0;
|
||||
break;
|
||||
}
|
||||
current_tmo = ha->idc_extend_tmo * HZ;
|
||||
ha->idc_extend_tmo = 0;
|
||||
}
|
||||
|
||||
if (!rem_tmo) {
|
||||
ql_dbg(ql_dbg_user, vha, 0x7022,
|
||||
"DCBX completion not received.\n");
|
||||
ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0);
|
||||
@ -678,6 +690,7 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
|
||||
}
|
||||
|
||||
ha->notify_dcbx_comp = 0;
|
||||
ha->idc_extend_tmo = 0;
|
||||
|
||||
done_set_internal:
|
||||
return rval;
|
||||
@ -773,7 +786,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
|
||||
if (atomic_read(&vha->loop_state) == LOOP_READY &&
|
||||
(ha->current_topology == ISP_CFG_F ||
|
||||
((IS_QLA81XX(ha) || IS_QLA8031(ha)) &&
|
||||
((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) &&
|
||||
le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
|
||||
&& req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
|
||||
elreq.options == EXTERNAL_LOOPBACK) {
|
||||
@ -783,7 +796,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
command_sent = INT_DEF_LB_ECHO_CMD;
|
||||
rval = qla2x00_echo_test(vha, &elreq, response);
|
||||
} else {
|
||||
if (IS_QLA81XX(ha) || IS_QLA8031(ha)) {
|
||||
if (IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) {
|
||||
memset(config, 0, sizeof(config));
|
||||
memset(new_config, 0, sizeof(new_config));
|
||||
|
||||
@ -806,7 +819,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
"elreq.options=%04x\n", elreq.options);
|
||||
|
||||
if (elreq.options == EXTERNAL_LOOPBACK)
|
||||
if (IS_QLA8031(ha))
|
||||
if (IS_QLA8031(ha) || IS_QLA8044(ha))
|
||||
rval = qla81xx_set_loopback_mode(vha,
|
||||
config, new_config, elreq.options);
|
||||
else
|
||||
@ -1266,6 +1279,7 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
|
||||
int rval = 0;
|
||||
struct qla_port_param *port_param = NULL;
|
||||
fc_port_t *fcport = NULL;
|
||||
int found = 0;
|
||||
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
||||
uint8_t *rsp_ptr = NULL;
|
||||
|
||||
@ -1288,10 +1302,12 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
|
||||
if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn,
|
||||
fcport->port_name, sizeof(fcport->port_name)))
|
||||
continue;
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fcport) {
|
||||
if (!found) {
|
||||
ql_log(ql_log_warn, vha, 0x7049,
|
||||
"Failed to find port.\n");
|
||||
return -EINVAL;
|
||||
@ -1318,12 +1334,9 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
|
||||
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x704c,
|
||||
"iIDMA cmd failed for %02x%02x%02x%02x%02x%02x%02x%02x -- "
|
||||
"%04x %x %04x %04x.\n", fcport->port_name[0],
|
||||
fcport->port_name[1], fcport->port_name[2],
|
||||
fcport->port_name[3], fcport->port_name[4],
|
||||
fcport->port_name[5], fcport->port_name[6],
|
||||
fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1]);
|
||||
"iIDMA cmd failed for %8phN -- "
|
||||
"%04x %x %04x %04x.\n", fcport->port_name,
|
||||
rval, fcport->fp_speed, mb[0], mb[1]);
|
||||
rval = (DID_ERROR << 16);
|
||||
} else {
|
||||
if (!port_param->mode) {
|
||||
|
@ -11,9 +11,12 @@
|
||||
* ----------------------------------------------------------------------
|
||||
* | Level | Last Value Used | Holes |
|
||||
* ----------------------------------------------------------------------
|
||||
* | Module Init and Probe | 0x014f | 0x4b,0xba,0xfa |
|
||||
* | Mailbox commands | 0x117a | 0x111a-0x111b |
|
||||
* | Module Init and Probe | 0x0159 | 0x4b,0xba,0xfa |
|
||||
* | Mailbox commands | 0x1181 | 0x111a-0x111b |
|
||||
* | | | 0x1155-0x1158 |
|
||||
* | | | 0x1018-0x1019 |
|
||||
* | | | 0x1115-0x1116 |
|
||||
* | | | 0x10ca |
|
||||
* | Device Discovery | 0x2095 | 0x2020-0x2022, |
|
||||
* | | | 0x2011-0x2012, |
|
||||
* | | | 0x2016 |
|
||||
@ -24,11 +27,12 @@
|
||||
* | | | 0x3036,0x3038 |
|
||||
* | | | 0x303a |
|
||||
* | DPC Thread | 0x4022 | 0x4002,0x4013 |
|
||||
* | Async Events | 0x5081 | 0x502b-0x502f |
|
||||
* | Async Events | 0x5087 | 0x502b-0x502f |
|
||||
* | | | 0x5047,0x5052 |
|
||||
* | | | 0x5040,0x5075 |
|
||||
* | Timer Routines | 0x6011 | |
|
||||
* | User Space Interactions | 0x70dd | 0x7018,0x702e, |
|
||||
* | | | 0x5084,0x5075 |
|
||||
* | | | 0x503d,0x5044 |
|
||||
* | Timer Routines | 0x6012 | |
|
||||
* | User Space Interactions | 0x70e1 | 0x7018,0x702e, |
|
||||
* | | | 0x7020,0x7024, |
|
||||
* | | | 0x7039,0x7045, |
|
||||
* | | | 0x7073-0x7075, |
|
||||
@ -36,17 +40,28 @@
|
||||
* | | | 0x70a5,0x70a6, |
|
||||
* | | | 0x70a8,0x70ab, |
|
||||
* | | | 0x70ad-0x70ae, |
|
||||
* | | | 0x70d1-0x70da, |
|
||||
* | | | 0x70d1-0x70db, |
|
||||
* | | | 0x7047,0x703b |
|
||||
* | Task Management | 0x803c | 0x8025-0x8026 |
|
||||
* | | | 0x70de-0x70df, |
|
||||
* | Task Management | 0x803d | 0x8025-0x8026 |
|
||||
* | | | 0x800b,0x8039 |
|
||||
* | AER/EEH | 0x9011 | |
|
||||
* | Virtual Port | 0xa007 | |
|
||||
* | ISP82XX Specific | 0xb086 | 0xb002,0xb024 |
|
||||
* | ISP82XX Specific | 0xb14c | 0xb002,0xb024 |
|
||||
* | | | 0xb09e,0xb0ae |
|
||||
* | | | 0xb0e0-0xb0ef |
|
||||
* | | | 0xb085,0xb0dc |
|
||||
* | | | 0xb107,0xb108 |
|
||||
* | | | 0xb111,0xb11e |
|
||||
* | | | 0xb12c,0xb12d |
|
||||
* | | | 0xb13a,0xb142 |
|
||||
* | | | 0xb13c-0xb140 |
|
||||
* | | | 0xb149 |
|
||||
* | MultiQ | 0xc00c | |
|
||||
* | Misc | 0xd010 | |
|
||||
* | Target Mode | 0xe070 | |
|
||||
* | Target Mode Management | 0xf072 | |
|
||||
* | Target Mode | 0xe070 | 0xe021 |
|
||||
* | Target Mode Management | 0xf072 | 0xf002-0xf003 |
|
||||
* | | | 0xf046-0xf049 |
|
||||
* | Target Mode Task Management | 0x1000b | |
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
@ -519,7 +534,7 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
|
||||
uint32_t cnt, que_idx;
|
||||
uint8_t que_cnt;
|
||||
struct qla2xxx_mq_chain *mq = ptr;
|
||||
struct device_reg_25xxmq __iomem *reg;
|
||||
device_reg_t __iomem *reg;
|
||||
|
||||
if (!ha->mqenable || IS_QLA83XX(ha))
|
||||
return ptr;
|
||||
@ -533,13 +548,16 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
|
||||
ha->max_req_queues : ha->max_rsp_queues;
|
||||
mq->count = htonl(que_cnt);
|
||||
for (cnt = 0; cnt < que_cnt; cnt++) {
|
||||
reg = (struct device_reg_25xxmq __iomem *)
|
||||
(ha->mqiobase + cnt * QLA_QUE_PAGE);
|
||||
reg = ISP_QUE_REG(ha, cnt);
|
||||
que_idx = cnt * 4;
|
||||
mq->qregs[que_idx] = htonl(RD_REG_DWORD(®->req_q_in));
|
||||
mq->qregs[que_idx+1] = htonl(RD_REG_DWORD(®->req_q_out));
|
||||
mq->qregs[que_idx+2] = htonl(RD_REG_DWORD(®->rsp_q_in));
|
||||
mq->qregs[que_idx+3] = htonl(RD_REG_DWORD(®->rsp_q_out));
|
||||
mq->qregs[que_idx] =
|
||||
htonl(RD_REG_DWORD(®->isp25mq.req_q_in));
|
||||
mq->qregs[que_idx+1] =
|
||||
htonl(RD_REG_DWORD(®->isp25mq.req_q_out));
|
||||
mq->qregs[que_idx+2] =
|
||||
htonl(RD_REG_DWORD(®->isp25mq.rsp_q_in));
|
||||
mq->qregs[que_idx+3] =
|
||||
htonl(RD_REG_DWORD(®->isp25mq.rsp_q_out));
|
||||
}
|
||||
|
||||
return ptr + sizeof(struct qla2xxx_mq_chain);
|
||||
@ -941,7 +959,7 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
|
||||
uint32_t *last_chain = NULL;
|
||||
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
return;
|
||||
|
||||
risc_address = ext_mem_cnt = 0;
|
||||
@ -2530,7 +2548,7 @@ ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id)
|
||||
if (!ql_mask_match(level))
|
||||
return;
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
mbx_reg = ®82->mailbox_in[0];
|
||||
else if (IS_FWI2_CAPABLE(ha))
|
||||
mbx_reg = ®24->mailbox0;
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#include "qla_bsg.h"
|
||||
#include "qla_nx.h"
|
||||
#include "qla_nx2.h"
|
||||
#define QLA2XXX_DRIVER_NAME "qla2xxx"
|
||||
#define QLA2XXX_APIDEV "ql2xapidev"
|
||||
#define QLA2XXX_MANUFACTURER "QLogic Corporation"
|
||||
@ -642,6 +643,7 @@ struct device_reg_fx00 {
|
||||
uint32_t initval6; /* C8 */
|
||||
uint32_t initval7; /* CC */
|
||||
uint32_t fwheartbeat; /* D0 */
|
||||
uint32_t pseudoaen; /* D4 */
|
||||
};
|
||||
|
||||
|
||||
@ -805,6 +807,7 @@ struct mbx_cmd_32 {
|
||||
#define MBA_MIRROR_LUN_CHANGE 0x8402 /* Mirror LUN State Change
|
||||
Notification */
|
||||
#define MBA_FW_POLL_STATE 0x8600 /* Firmware in poll diagnostic state */
|
||||
#define MBA_FW_RESET_FCT 0x8502 /* Firmware reset factory defaults */
|
||||
|
||||
/* 83XX FCoE specific */
|
||||
#define MBA_IDC_AEN 0x8200 /* FCoE: NIC Core state change AEN */
|
||||
@ -997,6 +1000,7 @@ struct mbx_cmd_32 {
|
||||
#define MBX_1 BIT_1
|
||||
#define MBX_0 BIT_0
|
||||
|
||||
#define RNID_TYPE_SET_VERSION 0x9
|
||||
#define RNID_TYPE_ASIC_TEMP 0xC
|
||||
|
||||
/*
|
||||
@ -1233,8 +1237,9 @@ struct link_statistics {
|
||||
uint32_t unused1[0x1a];
|
||||
uint32_t tx_frames;
|
||||
uint32_t rx_frames;
|
||||
uint32_t dumped_frames;
|
||||
uint32_t unused2[2];
|
||||
uint32_t discarded_frames;
|
||||
uint32_t dropped_frames;
|
||||
uint32_t unused2[1];
|
||||
uint32_t nos_rcvd;
|
||||
};
|
||||
|
||||
@ -2656,6 +2661,11 @@ struct qla_statistics {
|
||||
uint32_t total_isp_aborts;
|
||||
uint64_t input_bytes;
|
||||
uint64_t output_bytes;
|
||||
uint64_t input_requests;
|
||||
uint64_t output_requests;
|
||||
uint32_t control_requests;
|
||||
|
||||
uint64_t jiffies_at_last_reset;
|
||||
};
|
||||
|
||||
struct bidi_statistics {
|
||||
@ -2670,9 +2680,8 @@ struct bidi_statistics {
|
||||
#define QLA_MAX_QUEUES 256
|
||||
#define ISP_QUE_REG(ha, id) \
|
||||
((ha->mqenable || IS_QLA83XX(ha)) ? \
|
||||
((device_reg_t __iomem *)(ha->mqiobase) +\
|
||||
(QLA_QUE_PAGE * id)) :\
|
||||
((device_reg_t __iomem *)(ha->iobase)))
|
||||
((void __iomem *)ha->mqiobase + (QLA_QUE_PAGE * id)) :\
|
||||
((void __iomem *)ha->iobase))
|
||||
#define QLA_REQ_QUE_ID(tag) \
|
||||
((tag < QLA_MAX_QUEUES && tag > 0) ? tag : 0)
|
||||
#define QLA_DEFAULT_QUE_QOS 5
|
||||
@ -2935,7 +2944,8 @@ struct qla_hw_data {
|
||||
#define DT_ISP2031 BIT_15
|
||||
#define DT_ISP8031 BIT_16
|
||||
#define DT_ISPFX00 BIT_17
|
||||
#define DT_ISP_LAST (DT_ISPFX00 << 1)
|
||||
#define DT_ISP8044 BIT_18
|
||||
#define DT_ISP_LAST (DT_ISP8044 << 1)
|
||||
|
||||
#define DT_T10_PI BIT_25
|
||||
#define DT_IIDMA BIT_26
|
||||
@ -2961,6 +2971,7 @@ struct qla_hw_data {
|
||||
#define IS_QLA8001(ha) (DT_MASK(ha) & DT_ISP8001)
|
||||
#define IS_QLA81XX(ha) (IS_QLA8001(ha))
|
||||
#define IS_QLA82XX(ha) (DT_MASK(ha) & DT_ISP8021)
|
||||
#define IS_QLA8044(ha) (DT_MASK(ha) & DT_ISP8044)
|
||||
#define IS_QLA2031(ha) (DT_MASK(ha) & DT_ISP2031)
|
||||
#define IS_QLA8031(ha) (DT_MASK(ha) & DT_ISP8031)
|
||||
#define IS_QLAFX00(ha) (DT_MASK(ha) & DT_ISPFX00)
|
||||
@ -2975,10 +2986,12 @@ struct qla_hw_data {
|
||||
#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
|
||||
IS_QLA84XX(ha))
|
||||
#define IS_CNA_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha) || \
|
||||
IS_QLA8031(ha))
|
||||
IS_QLA8031(ha) || IS_QLA8044(ha))
|
||||
#define IS_P3P_TYPE(ha) (IS_QLA82XX(ha) || IS_QLA8044(ha))
|
||||
#define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
|
||||
IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
|
||||
IS_QLA82XX(ha) || IS_QLA83XX(ha))
|
||||
IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
|
||||
IS_QLA8044(ha))
|
||||
#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
|
||||
#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
|
||||
IS_QLA83XX(ha)) && (ha)->flags.msix_enabled)
|
||||
@ -3187,10 +3200,12 @@ struct qla_hw_data {
|
||||
uint32_t nvram_data_off;
|
||||
|
||||
uint32_t fdt_wrt_disable;
|
||||
uint32_t fdt_wrt_enable;
|
||||
uint32_t fdt_erase_cmd;
|
||||
uint32_t fdt_block_size;
|
||||
uint32_t fdt_unprotect_sec_cmd;
|
||||
uint32_t fdt_protect_sec_cmd;
|
||||
uint32_t fdt_wrt_sts_reg_cmd;
|
||||
|
||||
uint32_t flt_region_flt;
|
||||
uint32_t flt_region_fdt;
|
||||
@ -3277,6 +3292,7 @@ struct qla_hw_data {
|
||||
|
||||
/* QLA83XX IDC specific fields */
|
||||
uint32_t idc_audit_ts;
|
||||
uint32_t idc_extend_tmo;
|
||||
|
||||
/* DPC low-priority workqueue */
|
||||
struct workqueue_struct *dpc_lp_wq;
|
||||
@ -3296,9 +3312,6 @@ struct qla_hw_data {
|
||||
struct mr_data_fx00 mr;
|
||||
|
||||
struct qlt_hw_data tgt;
|
||||
uint16_t thermal_support;
|
||||
#define THERMAL_SUPPORT_I2C BIT_0
|
||||
#define THERMAL_SUPPORT_ISP BIT_1
|
||||
};
|
||||
|
||||
/*
|
||||
@ -3364,6 +3377,7 @@ typedef struct scsi_qla_host {
|
||||
#define PORT_UPDATE_NEEDED 24
|
||||
#define FX00_RESET_RECOVERY 25
|
||||
#define FX00_TARGET_SCAN 26
|
||||
#define FX00_CRITEMP_RECOVERY 27
|
||||
|
||||
uint32_t device_flags;
|
||||
#define SWITCH_FOUND BIT_0
|
||||
@ -3402,7 +3416,7 @@ typedef struct scsi_qla_host {
|
||||
uint16_t fcoe_fcf_idx;
|
||||
uint8_t fcoe_vn_port_mac[6];
|
||||
|
||||
uint32_t vp_abort_cnt;
|
||||
uint32_t vp_abort_cnt;
|
||||
|
||||
struct fc_vport *fc_vport; /* holds fc_vport * for each vport */
|
||||
uint16_t vp_idx; /* vport ID */
|
||||
@ -3435,6 +3449,7 @@ typedef struct scsi_qla_host {
|
||||
struct bidi_statistics bidi_stats;
|
||||
|
||||
atomic_t vref_count;
|
||||
struct qla8044_reset_template reset_tmplt;
|
||||
} scsi_qla_host_t;
|
||||
|
||||
#define SET_VP_IDX 1
|
||||
|
@ -1387,6 +1387,8 @@ struct qla_flt_header {
|
||||
#define FLT_REG_GOLD_FW 0x2f
|
||||
#define FLT_REG_FCP_PRIO_0 0x87
|
||||
#define FLT_REG_FCP_PRIO_1 0x88
|
||||
#define FLT_REG_CNA_FW 0x97
|
||||
#define FLT_REG_BOOT_CODE_8044 0xA2
|
||||
#define FLT_REG_FCOE_FW 0xA4
|
||||
#define FLT_REG_FCOE_NVRAM_0 0xAA
|
||||
#define FLT_REG_FCOE_NVRAM_1 0xAC
|
||||
|
@ -356,6 +356,12 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *, dma_addr_t, uint16_t , uint16_t *,
|
||||
extern int
|
||||
qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
|
||||
|
||||
extern int
|
||||
qla82xx_set_driver_version(scsi_qla_host_t *, char *);
|
||||
|
||||
extern int
|
||||
qla25xx_set_driver_version(scsi_qla_host_t *, char *);
|
||||
|
||||
extern int
|
||||
qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *,
|
||||
uint16_t, uint16_t, uint16_t, uint16_t);
|
||||
@ -435,19 +441,19 @@ qla2x00_process_completed_request(struct scsi_qla_host *, struct req_que *,
|
||||
*/
|
||||
extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
|
||||
extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
|
||||
uint32_t, uint32_t);
|
||||
uint32_t, uint32_t);
|
||||
extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
|
||||
uint32_t);
|
||||
uint32_t);
|
||||
extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
|
||||
uint32_t);
|
||||
uint32_t);
|
||||
extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
|
||||
uint32_t);
|
||||
uint32_t);
|
||||
extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
|
||||
uint32_t);
|
||||
uint32_t);
|
||||
extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
|
||||
uint32_t);
|
||||
uint32_t);
|
||||
extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
|
||||
uint32_t);
|
||||
uint32_t);
|
||||
extern int qla2x00_is_a_vp_did(scsi_qla_host_t *, uint32_t);
|
||||
|
||||
extern int qla2x00_beacon_on(struct scsi_qla_host *);
|
||||
@ -463,21 +469,25 @@ extern int qla83xx_wr_reg(scsi_qla_host_t *, uint32_t, uint32_t);
|
||||
extern int qla83xx_rd_reg(scsi_qla_host_t *, uint32_t, uint32_t *);
|
||||
extern int qla83xx_restart_nic_firmware(scsi_qla_host_t *);
|
||||
extern int qla83xx_access_control(scsi_qla_host_t *, uint16_t, uint32_t,
|
||||
uint32_t, uint16_t *);
|
||||
uint32_t, uint16_t *);
|
||||
|
||||
extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
uint32_t, uint32_t);
|
||||
extern int qla2x00_write_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
uint32_t, uint32_t);
|
||||
extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
uint32_t, uint32_t);
|
||||
extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
uint32_t, uint32_t);
|
||||
extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
uint32_t, uint32_t);
|
||||
extern uint8_t *qla8044_read_optrom_data(struct scsi_qla_host *,
|
||||
uint8_t *, uint32_t, uint32_t);
|
||||
extern void qla8044_watchdog(struct scsi_qla_host *vha);
|
||||
|
||||
extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
|
||||
extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
|
||||
extern int qla82xx_get_flash_version(scsi_qla_host_t *, void *);
|
||||
|
||||
extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
|
||||
extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
|
||||
@ -498,7 +508,7 @@ extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
|
||||
extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
|
||||
extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t);
|
||||
extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t,
|
||||
uint8_t *, uint32_t);
|
||||
uint8_t *, uint32_t);
|
||||
extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int);
|
||||
|
||||
/*
|
||||
@ -584,6 +594,7 @@ extern int qlafx00_start_scsi(srb_t *);
|
||||
extern int qlafx00_abort_isp(scsi_qla_host_t *);
|
||||
extern int qlafx00_iospace_config(struct qla_hw_data *);
|
||||
extern int qlafx00_init_firmware(scsi_qla_host_t *, uint16_t);
|
||||
extern int qlafx00_driver_shutdown(scsi_qla_host_t *, int);
|
||||
extern int qlafx00_fw_ready(scsi_qla_host_t *);
|
||||
extern int qlafx00_configure_devices(scsi_qla_host_t *);
|
||||
extern int qlafx00_reset_initialize(scsi_qla_host_t *);
|
||||
@ -601,6 +612,7 @@ extern void qlafx00_abort_iocb(srb_t *, struct abort_iocb_entry_fx00 *);
|
||||
extern void qlafx00_fxdisc_iocb(srb_t *, struct fxdisc_entry_fx00 *);
|
||||
extern void qlafx00_timer_routine(scsi_qla_host_t *);
|
||||
extern int qlafx00_rescan_isp(scsi_qla_host_t *);
|
||||
extern int qlafx00_loop_reset(scsi_qla_host_t *vha);
|
||||
|
||||
/* qla82xx related functions */
|
||||
|
||||
@ -619,9 +631,9 @@ extern int qla82xx_start_firmware(scsi_qla_host_t *);
|
||||
/* Firmware and flash related functions */
|
||||
extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *);
|
||||
extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
uint32_t, uint32_t);
|
||||
extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
uint32_t, uint32_t);
|
||||
|
||||
/* Mailbox related functions */
|
||||
extern int qla82xx_abort_isp(scsi_qla_host_t *);
|
||||
@ -662,7 +674,7 @@ extern void qla8xxx_dev_failed_handler(scsi_qla_host_t *);
|
||||
extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *);
|
||||
|
||||
extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
|
||||
size_t, char *);
|
||||
size_t, char *);
|
||||
extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *);
|
||||
extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
|
||||
extern void qla82xx_start_iocbs(scsi_qla_host_t *);
|
||||
@ -674,6 +686,8 @@ extern int qla81xx_get_led_config(scsi_qla_host_t *, uint16_t *);
|
||||
extern int qla82xx_mbx_beacon_ctl(scsi_qla_host_t *, int);
|
||||
extern char *qdev_state(uint32_t);
|
||||
extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *);
|
||||
extern int qla82xx_read_temperature(scsi_qla_host_t *);
|
||||
extern int qla8044_read_temperature(scsi_qla_host_t *);
|
||||
|
||||
/* BSG related functions */
|
||||
extern int qla24xx_bsg_request(struct fc_bsg_job *);
|
||||
@ -695,5 +709,31 @@ extern void qla82xx_md_free(scsi_qla_host_t *);
|
||||
extern int qla82xx_md_collect(scsi_qla_host_t *);
|
||||
extern void qla82xx_md_prep(scsi_qla_host_t *);
|
||||
extern void qla82xx_set_reset_owner(scsi_qla_host_t *);
|
||||
extern int qla82xx_validate_template_chksum(scsi_qla_host_t *vha);
|
||||
|
||||
/* Function declarations for ISP8044 */
|
||||
extern int qla8044_idc_lock(struct qla_hw_data *ha);
|
||||
extern void qla8044_idc_unlock(struct qla_hw_data *ha);
|
||||
extern uint32_t qla8044_rd_reg(struct qla_hw_data *ha, ulong addr);
|
||||
extern void qla8044_wr_reg(struct qla_hw_data *ha, ulong addr, uint32_t val);
|
||||
extern void qla8044_read_reset_template(struct scsi_qla_host *ha);
|
||||
extern void qla8044_set_idc_dontreset(struct scsi_qla_host *ha);
|
||||
extern int qla8044_rd_direct(struct scsi_qla_host *vha, const uint32_t crb_reg);
|
||||
extern void qla8044_wr_direct(struct scsi_qla_host *vha,
|
||||
const uint32_t crb_reg, const uint32_t value);
|
||||
extern inline void qla8044_set_qsnt_ready(struct scsi_qla_host *vha);
|
||||
extern inline void qla8044_need_reset_handler(struct scsi_qla_host *vha);
|
||||
extern int qla8044_device_state_handler(struct scsi_qla_host *vha);
|
||||
extern void qla8044_clear_qsnt_ready(struct scsi_qla_host *vha);
|
||||
extern void qla8044_clear_drv_active(struct scsi_qla_host *vha);
|
||||
void qla8044_get_minidump(struct scsi_qla_host *vha);
|
||||
int qla8044_collect_md_data(struct scsi_qla_host *vha);
|
||||
extern int qla8044_md_get_template(scsi_qla_host_t *);
|
||||
extern int qla8044_write_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
extern irqreturn_t qla8044_intr_handler(int, void *);
|
||||
extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t);
|
||||
extern int qla8044_abort_isp(scsi_qla_host_t *);
|
||||
extern int qla8044_check_fw_alive(struct scsi_qla_host *);
|
||||
|
||||
#endif /* _QLA_GBL_H */
|
||||
|
@ -49,6 +49,8 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
|
||||
ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
|
||||
ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
|
||||
|
||||
vha->qla_stats.control_requests++;
|
||||
|
||||
return (ms_pkt);
|
||||
}
|
||||
|
||||
@ -87,6 +89,8 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
|
||||
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
|
||||
ct_pkt->vp_index = vha->vp_idx;
|
||||
|
||||
vha->qla_stats.control_requests++;
|
||||
|
||||
return (ct_pkt);
|
||||
}
|
||||
|
||||
@ -226,17 +230,9 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
|
||||
fcport->d_id.b.domain = 0xf0;
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x2063,
|
||||
"GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
|
||||
"pn %02x%02x%02x%02x%02x%02x%02x%02x "
|
||||
"GA_NXT entry - nn %8phN pn %8phN "
|
||||
"port_id=%02x%02x%02x.\n",
|
||||
fcport->node_name[0], fcport->node_name[1],
|
||||
fcport->node_name[2], fcport->node_name[3],
|
||||
fcport->node_name[4], fcport->node_name[5],
|
||||
fcport->node_name[6], fcport->node_name[7],
|
||||
fcport->port_name[0], fcport->port_name[1],
|
||||
fcport->port_name[2], fcport->port_name[3],
|
||||
fcport->port_name[4], fcport->port_name[5],
|
||||
fcport->port_name[6], fcport->port_name[7],
|
||||
fcport->node_name, fcport->port_name,
|
||||
fcport->d_id.b.domain, fcport->d_id.b.area,
|
||||
fcport->d_id.b.al_pa);
|
||||
}
|
||||
@ -447,17 +443,9 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
|
||||
ct_rsp->rsp.gnn_id.node_name, WWN_SIZE);
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x2058,
|
||||
"GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02X%02x "
|
||||
"pn %02x%02x%02x%02x%02x%02x%02X%02x "
|
||||
"GID_PT entry - nn %8phN pn %8phN "
|
||||
"portid=%02x%02x%02x.\n",
|
||||
list[i].node_name[0], list[i].node_name[1],
|
||||
list[i].node_name[2], list[i].node_name[3],
|
||||
list[i].node_name[4], list[i].node_name[5],
|
||||
list[i].node_name[6], list[i].node_name[7],
|
||||
list[i].port_name[0], list[i].port_name[1],
|
||||
list[i].port_name[2], list[i].port_name[3],
|
||||
list[i].port_name[4], list[i].port_name[5],
|
||||
list[i].port_name[6], list[i].port_name[7],
|
||||
list[i].node_name, list[i].port_name,
|
||||
list[i].d_id.b.domain, list[i].d_id.b.area,
|
||||
list[i].d_id.b.al_pa);
|
||||
}
|
||||
@ -739,6 +727,8 @@ qla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len,
|
||||
wc = (data_size - 16) / 4; /* Size in 32bit words. */
|
||||
sns_cmd->p.cmd.size = cpu_to_le16(wc);
|
||||
|
||||
vha->qla_stats.control_requests++;
|
||||
|
||||
return (sns_cmd);
|
||||
}
|
||||
|
||||
@ -796,17 +786,9 @@ qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
|
||||
fcport->d_id.b.domain = 0xf0;
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x2061,
|
||||
"GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
|
||||
"pn %02x%02x%02x%02x%02x%02x%02x%02x "
|
||||
"GA_NXT entry - nn %8phN pn %8phN "
|
||||
"port_id=%02x%02x%02x.\n",
|
||||
fcport->node_name[0], fcport->node_name[1],
|
||||
fcport->node_name[2], fcport->node_name[3],
|
||||
fcport->node_name[4], fcport->node_name[5],
|
||||
fcport->node_name[6], fcport->node_name[7],
|
||||
fcport->port_name[0], fcport->port_name[1],
|
||||
fcport->port_name[2], fcport->port_name[3],
|
||||
fcport->port_name[4], fcport->port_name[5],
|
||||
fcport->port_name[6], fcport->port_name[7],
|
||||
fcport->node_name, fcport->port_name,
|
||||
fcport->d_id.b.domain, fcport->d_id.b.area,
|
||||
fcport->d_id.b.al_pa);
|
||||
}
|
||||
@ -991,17 +973,9 @@ qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
|
||||
WWN_SIZE);
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x206e,
|
||||
"GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
|
||||
"pn %02x%02x%02x%02x%02x%02x%02x%02x "
|
||||
"GID_PT entry - nn %8phN pn %8phN "
|
||||
"port_id=%02x%02x%02x.\n",
|
||||
list[i].node_name[0], list[i].node_name[1],
|
||||
list[i].node_name[2], list[i].node_name[3],
|
||||
list[i].node_name[4], list[i].node_name[5],
|
||||
list[i].node_name[6], list[i].node_name[7],
|
||||
list[i].port_name[0], list[i].port_name[1],
|
||||
list[i].port_name[2], list[i].port_name[3],
|
||||
list[i].port_name[4], list[i].port_name[5],
|
||||
list[i].port_name[6], list[i].port_name[7],
|
||||
list[i].node_name, list[i].port_name,
|
||||
list[i].d_id.b.domain, list[i].d_id.b.area,
|
||||
list[i].d_id.b.al_pa);
|
||||
}
|
||||
@ -1321,11 +1295,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
|
||||
size += 4 + WWN_SIZE;
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x2025,
|
||||
"NodeName = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
|
||||
eiter->a.node_name[0], eiter->a.node_name[1],
|
||||
eiter->a.node_name[2], eiter->a.node_name[3],
|
||||
eiter->a.node_name[4], eiter->a.node_name[5],
|
||||
eiter->a.node_name[6], eiter->a.node_name[7]);
|
||||
"NodeName = %8phN.\n", eiter->a.node_name);
|
||||
|
||||
/* Manufacturer. */
|
||||
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
|
||||
@ -1428,16 +1398,8 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
|
||||
qla2x00_update_ms_fdmi_iocb(vha, size + 16);
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x202e,
|
||||
"RHBA identifier = "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n",
|
||||
ct_req->req.rhba.hba_identifier[0],
|
||||
ct_req->req.rhba.hba_identifier[1],
|
||||
ct_req->req.rhba.hba_identifier[2],
|
||||
ct_req->req.rhba.hba_identifier[3],
|
||||
ct_req->req.rhba.hba_identifier[4],
|
||||
ct_req->req.rhba.hba_identifier[5],
|
||||
ct_req->req.rhba.hba_identifier[6],
|
||||
ct_req->req.rhba.hba_identifier[7], size);
|
||||
"RHBA identifier = %8phN size=%d.\n",
|
||||
ct_req->req.rhba.hba_identifier, size);
|
||||
ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076,
|
||||
entries, size);
|
||||
|
||||
@ -1494,11 +1456,7 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *vha)
|
||||
memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE);
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x2036,
|
||||
"DHBA portname = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
|
||||
ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1],
|
||||
ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3],
|
||||
ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5],
|
||||
ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]);
|
||||
"DHBA portname = %8phN.\n", ct_req->req.dhba.port_name);
|
||||
|
||||
/* Execute MS IOCB */
|
||||
rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
|
||||
@ -1678,12 +1636,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
|
||||
qla2x00_update_ms_fdmi_iocb(vha, size + 16);
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x203e,
|
||||
"RPA portname= %02x%02x%02x%02x%02X%02x%02x%02x size=%d.\n",
|
||||
ct_req->req.rpa.port_name[0], ct_req->req.rpa.port_name[1],
|
||||
ct_req->req.rpa.port_name[2], ct_req->req.rpa.port_name[3],
|
||||
ct_req->req.rpa.port_name[4], ct_req->req.rpa.port_name[5],
|
||||
ct_req->req.rpa.port_name[6], ct_req->req.rpa.port_name[7],
|
||||
size);
|
||||
"RPA portname= %8phN size=%d.\n", ct_req->req.rpa.port_name, size);
|
||||
ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079,
|
||||
entries, size);
|
||||
|
||||
@ -1940,16 +1893,8 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
|
||||
|
||||
ql_dbg(ql_dbg_disc, vha, 0x205b,
|
||||
"GPSC ext entry - fpn "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
|
||||
"speed=%04x.\n",
|
||||
list[i].fabric_port_name[0],
|
||||
list[i].fabric_port_name[1],
|
||||
list[i].fabric_port_name[2],
|
||||
list[i].fabric_port_name[3],
|
||||
list[i].fabric_port_name[4],
|
||||
list[i].fabric_port_name[5],
|
||||
list[i].fabric_port_name[6],
|
||||
list[i].fabric_port_name[7],
|
||||
"%8phN speeds=%04x speed=%04x.\n",
|
||||
list[i].fabric_port_name,
|
||||
be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
|
||||
be16_to_cpu(ct_rsp->rsp.gpsc.speed));
|
||||
}
|
||||
|
@ -524,7 +524,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
vha->flags.reset_active = 0;
|
||||
ha->flags.pci_channel_io_perm_failure = 0;
|
||||
ha->flags.eeh_busy = 0;
|
||||
ha->thermal_support = THERMAL_SUPPORT_I2C|THERMAL_SUPPORT_ISP;
|
||||
vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
|
||||
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
|
||||
atomic_set(&vha->loop_state, LOOP_DOWN);
|
||||
vha->device_flags = DFLG_NO_CABLE;
|
||||
@ -552,7 +552,18 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x004f,
|
||||
"Unable to validate FLASH data.\n");
|
||||
return (rval);
|
||||
return rval;
|
||||
}
|
||||
|
||||
if (IS_QLA8044(ha)) {
|
||||
qla8044_read_reset_template(vha);
|
||||
|
||||
/* NOTE: If ql2xdontresethba==1, set IDC_CTRL DONTRESET_BIT0.
|
||||
* If DONRESET_BIT0 is set, drivers should not set dev_state
|
||||
* to NEED_RESET. But if NEED_RESET is set, drivers should
|
||||
* should honor the reset. */
|
||||
if (ql2xdontresethba == 1)
|
||||
qla8044_set_idc_dontreset(vha);
|
||||
}
|
||||
|
||||
ha->isp_ops->get_flash_version(vha, req->ring);
|
||||
@ -564,12 +575,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
if (ha->flags.disable_serdes) {
|
||||
/* Mask HBA via NVRAM settings? */
|
||||
ql_log(ql_log_info, vha, 0x0077,
|
||||
"Masking HBA WWPN "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
|
||||
vha->port_name[0], vha->port_name[1],
|
||||
vha->port_name[2], vha->port_name[3],
|
||||
vha->port_name[4], vha->port_name[5],
|
||||
vha->port_name[6], vha->port_name[7]);
|
||||
"Masking HBA WWPN %8phN (via NVRAM).\n", vha->port_name);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
@ -620,6 +626,11 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
|
||||
qla24xx_read_fcp_prio_cfg(vha);
|
||||
|
||||
if (IS_P3P_TYPE(ha))
|
||||
qla82xx_set_driver_version(vha, QLA2XXX_VERSION);
|
||||
else
|
||||
qla25xx_set_driver_version(vha, QLA2XXX_VERSION);
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
@ -1332,7 +1343,7 @@ qla24xx_chip_diag(scsi_qla_host_t *vha)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct req_que *req = ha->req_q_map[0];
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
return QLA_SUCCESS;
|
||||
|
||||
ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
|
||||
@ -1615,7 +1626,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
|
||||
unsigned long flags;
|
||||
uint16_t fw_major_version;
|
||||
|
||||
if (IS_QLA82XX(ha)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
rval = ha->isp_ops->load_risc(vha, &srisc_address);
|
||||
if (rval == QLA_SUCCESS) {
|
||||
qla2x00_stop_firmware(vha);
|
||||
@ -1651,7 +1662,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
|
||||
if (rval == QLA_SUCCESS) {
|
||||
enable_82xx_npiv:
|
||||
fw_major_version = ha->fw_major_version;
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
qla82xx_check_md_needed(vha);
|
||||
else
|
||||
rval = qla2x00_get_fw_version(vha);
|
||||
@ -1681,7 +1692,7 @@ enable_82xx_npiv:
|
||||
goto failed;
|
||||
|
||||
if (!fw_major_version && ql2xallocfwdump
|
||||
&& !IS_QLA82XX(ha))
|
||||
&& !(IS_P3P_TYPE(ha)))
|
||||
qla2x00_alloc_fw_dump(vha);
|
||||
}
|
||||
} else {
|
||||
@ -1849,7 +1860,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
|
||||
int rval;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
return;
|
||||
|
||||
/* Update Serial Link options. */
|
||||
@ -3061,22 +3072,13 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
|
||||
mb);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_disc, vha, 0x2004,
|
||||
"Unable to adjust iIDMA "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x "
|
||||
"%04x.\n", fcport->port_name[0], fcport->port_name[1],
|
||||
fcport->port_name[2], fcport->port_name[3],
|
||||
fcport->port_name[4], fcport->port_name[5],
|
||||
fcport->port_name[6], fcport->port_name[7], rval,
|
||||
fcport->fp_speed, mb[0], mb[1]);
|
||||
"Unable to adjust iIDMA %8phN -- %04x %x %04x %04x.\n",
|
||||
fcport->port_name, rval, fcport->fp_speed, mb[0], mb[1]);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_disc, vha, 0x2005,
|
||||
"iIDMA adjusted to %s GB/s "
|
||||
"on %02x%02x%02x%02x%02x%02x%02x%02x.\n",
|
||||
"iIDMA adjusted to %s GB/s on %8phN.\n",
|
||||
qla2x00_get_link_speed_str(ha, fcport->fp_speed),
|
||||
fcport->port_name[0], fcport->port_name[1],
|
||||
fcport->port_name[2], fcport->port_name[3],
|
||||
fcport->port_name[4], fcport->port_name[5],
|
||||
fcport->port_name[6], fcport->port_name[7]);
|
||||
fcport->port_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4007,10 +4009,18 @@ qla83xx_reset_ownership(scsi_qla_host_t *vha)
|
||||
uint32_t class_type_mask = 0x3;
|
||||
uint16_t fcoe_other_function = 0xffff, i;
|
||||
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
|
||||
|
||||
qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
|
||||
qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
|
||||
if (IS_QLA8044(ha)) {
|
||||
drv_presence = qla8044_rd_direct(vha,
|
||||
QLA8044_CRB_DRV_ACTIVE_INDEX);
|
||||
dev_part_info1 = qla8044_rd_direct(vha,
|
||||
QLA8044_CRB_DEV_PART_INFO_INDEX);
|
||||
dev_part_info2 = qla8044_rd_direct(vha,
|
||||
QLA8044_CRB_DEV_PART_INFO2);
|
||||
} else {
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
|
||||
qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
|
||||
qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
class_type = ((dev_part_info1 >> (i * 4)) & class_type_mask);
|
||||
if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
|
||||
@ -4347,7 +4357,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
|
||||
/* For ISP82XX, driver waits for completion of the commands.
|
||||
* online flag should be set.
|
||||
*/
|
||||
if (!IS_QLA82XX(ha))
|
||||
if (!(IS_P3P_TYPE(ha)))
|
||||
vha->flags.online = 0;
|
||||
ha->flags.chip_reset_done = 0;
|
||||
clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
@ -4360,7 +4370,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
|
||||
* Driver waits for the completion of the commands.
|
||||
* the interrupts need to be enabled.
|
||||
*/
|
||||
if (!IS_QLA82XX(ha))
|
||||
if (!(IS_P3P_TYPE(ha)))
|
||||
ha->isp_ops->reset_chip(vha);
|
||||
|
||||
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
|
||||
@ -4403,7 +4413,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
|
||||
|
||||
if (!ha->flags.eeh_busy) {
|
||||
/* Make sure for ISP 82XX IO DMA is complete */
|
||||
if (IS_QLA82XX(ha)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
qla82xx_chip_reset_cleanup(vha);
|
||||
ql_log(ql_log_info, vha, 0x00b4,
|
||||
"Done chip reset cleanup.\n");
|
||||
@ -4723,7 +4733,7 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
return;
|
||||
|
||||
vha->flags.online = 0;
|
||||
@ -4789,8 +4799,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
|
||||
}
|
||||
ha->nvram_size = sizeof(struct nvram_24xx);
|
||||
ha->vpd_size = FA_NVRAM_VPD_SIZE;
|
||||
if (IS_QLA82XX(ha))
|
||||
ha->vpd_size = FA_VPD_SIZE_82XX;
|
||||
|
||||
/* Get VPD data into cache */
|
||||
ha->vpd = ha->nvram + VPD_OFFSET;
|
||||
@ -5552,6 +5560,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
|
||||
/* Determine NVRAM starting address. */
|
||||
ha->nvram_size = sizeof(struct nvram_81xx);
|
||||
ha->vpd_size = FA_NVRAM_VPD_SIZE;
|
||||
if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
|
||||
ha->vpd_size = FA_VPD_SIZE_82XX;
|
||||
|
||||
/* Get VPD data into cache */
|
||||
ha->vpd = ha->nvram + VPD_OFFSET;
|
||||
@ -5734,7 +5744,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
|
||||
|
||||
/* Link Down Timeout = 0:
|
||||
*
|
||||
* When Port Down timer expires we will start returning
|
||||
* When Port Down timer expires we will start returning
|
||||
* I/O's to OS with "DID_NO_CONNECT".
|
||||
*
|
||||
* Link Down Timeout != 0:
|
||||
@ -6061,7 +6071,7 @@ qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
|
||||
if (priority < 0)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
if (IS_QLA82XX(vha->hw)) {
|
||||
if (IS_P3P_TYPE(vha->hw)) {
|
||||
fcport->fcp_prio = priority & 0xf;
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ qla2x00_poll(struct rsp_que *rsp)
|
||||
unsigned long flags;
|
||||
struct qla_hw_data *ha = rsp->hw;
|
||||
local_irq_save(flags);
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
qla82xx_poll(0, rsp);
|
||||
else
|
||||
ha->isp_ops->intr_handler(0, rsp);
|
||||
|
@ -32,9 +32,11 @@ qla2x00_get_cmd_direction(srb_t *sp)
|
||||
if (cmd->sc_data_direction == DMA_TO_DEVICE) {
|
||||
cflags = CF_WRITE;
|
||||
vha->qla_stats.output_bytes += scsi_bufflen(cmd);
|
||||
vha->qla_stats.output_requests++;
|
||||
} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
|
||||
cflags = CF_READ;
|
||||
vha->qla_stats.input_bytes += scsi_bufflen(cmd);
|
||||
vha->qla_stats.input_requests++;
|
||||
}
|
||||
return (cflags);
|
||||
}
|
||||
@ -474,7 +476,7 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
|
||||
|
||||
if (IS_QLA82XX(ha)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
qla82xx_start_iocbs(vha);
|
||||
} else {
|
||||
/* Adjust ring index. */
|
||||
@ -642,10 +644,12 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
|
||||
cmd_pkt->control_flags =
|
||||
__constant_cpu_to_le16(CF_WRITE_DATA);
|
||||
vha->qla_stats.output_bytes += scsi_bufflen(cmd);
|
||||
vha->qla_stats.output_requests++;
|
||||
} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
|
||||
cmd_pkt->control_flags =
|
||||
__constant_cpu_to_le16(CF_READ_DATA);
|
||||
vha->qla_stats.input_bytes += scsi_bufflen(cmd);
|
||||
vha->qla_stats.input_requests++;
|
||||
}
|
||||
|
||||
cur_seg = scsi_sglist(cmd);
|
||||
@ -758,10 +762,12 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
|
||||
cmd_pkt->task_mgmt_flags =
|
||||
__constant_cpu_to_le16(TMF_WRITE_DATA);
|
||||
vha->qla_stats.output_bytes += scsi_bufflen(cmd);
|
||||
vha->qla_stats.output_requests++;
|
||||
} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
|
||||
cmd_pkt->task_mgmt_flags =
|
||||
__constant_cpu_to_le16(TMF_READ_DATA);
|
||||
vha->qla_stats.input_bytes += scsi_bufflen(cmd);
|
||||
vha->qla_stats.input_requests++;
|
||||
}
|
||||
|
||||
/* One DSD is available in the Command Type 3 IOCB */
|
||||
@ -1844,7 +1850,7 @@ skip_cmd_array:
|
||||
if (req->cnt < req_cnt) {
|
||||
if (ha->mqenable || IS_QLA83XX(ha))
|
||||
cnt = RD_REG_DWORD(®->isp25mq.req_q_out);
|
||||
else if (IS_QLA82XX(ha))
|
||||
else if (IS_P3P_TYPE(ha))
|
||||
cnt = RD_REG_DWORD(®->isp82.req_q_out);
|
||||
else if (IS_FWI2_CAPABLE(ha))
|
||||
cnt = RD_REG_DWORD(®->isp24.req_q_out);
|
||||
@ -2056,6 +2062,8 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
|
||||
(bsg_job->reply_payload.sg_list)));
|
||||
els_iocb->rx_len = cpu_to_le32(sg_dma_len
|
||||
(bsg_job->reply_payload.sg_list));
|
||||
|
||||
sp->fcport->vha->qla_stats.control_requests++;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2133,6 +2141,8 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb)
|
||||
avail_dsds--;
|
||||
}
|
||||
ct_iocb->entry_count = entry_count;
|
||||
|
||||
sp->fcport->vha->qla_stats.control_requests++;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2685,6 +2695,9 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha,
|
||||
vha->bidi_stats.transfer_bytes += req_data_len;
|
||||
vha->bidi_stats.io_count++;
|
||||
|
||||
vha->qla_stats.output_bytes += req_data_len;
|
||||
vha->qla_stats.output_requests++;
|
||||
|
||||
/* Only one dsd is available for bidirectional IOCB, remaining dsds
|
||||
* are bundled in continuation iocb
|
||||
*/
|
||||
|
@ -282,25 +282,38 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
|
||||
"%04x %04x %04x %04x %04x %04x %04x.\n",
|
||||
event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
|
||||
mb[4], mb[5], mb[6]);
|
||||
if ((aen == MBA_IDC_COMPLETE && mb[1] >> 15)) {
|
||||
vha->hw->flags.idc_compl_status = 1;
|
||||
if (vha->hw->notify_dcbx_comp)
|
||||
complete(&vha->hw->dcbx_comp);
|
||||
switch (aen) {
|
||||
/* Handle IDC Error completion case. */
|
||||
case MBA_IDC_COMPLETE:
|
||||
if (mb[1] >> 15) {
|
||||
vha->hw->flags.idc_compl_status = 1;
|
||||
if (vha->hw->notify_dcbx_comp)
|
||||
complete(&vha->hw->dcbx_comp);
|
||||
}
|
||||
break;
|
||||
|
||||
case MBA_IDC_NOTIFY:
|
||||
/* Acknowledgement needed? [Notify && non-zero timeout]. */
|
||||
timeout = (descr >> 8) & 0xf;
|
||||
ql_dbg(ql_dbg_async, vha, 0x5022,
|
||||
"%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
|
||||
vha->host_no, event[aen & 0xff], timeout);
|
||||
|
||||
if (!timeout)
|
||||
return;
|
||||
rval = qla2x00_post_idc_ack_work(vha, mb);
|
||||
if (rval != QLA_SUCCESS)
|
||||
ql_log(ql_log_warn, vha, 0x5023,
|
||||
"IDC failed to post ACK.\n");
|
||||
break;
|
||||
case MBA_IDC_TIME_EXT:
|
||||
vha->hw->idc_extend_tmo = descr;
|
||||
ql_dbg(ql_dbg_async, vha, 0x5087,
|
||||
"%lu Inter-Driver Communication %s -- "
|
||||
"Extend timeout by=%d.\n",
|
||||
vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Acknowledgement needed? [Notify && non-zero timeout]. */
|
||||
timeout = (descr >> 8) & 0xf;
|
||||
if (aen != MBA_IDC_NOTIFY || !timeout)
|
||||
return;
|
||||
|
||||
ql_dbg(ql_dbg_async, vha, 0x5022,
|
||||
"%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
|
||||
vha->host_no, event[aen & 0xff], timeout);
|
||||
|
||||
rval = qla2x00_post_idc_ack_work(vha, mb);
|
||||
if (rval != QLA_SUCCESS)
|
||||
ql_log(ql_log_warn, vha, 0x5023,
|
||||
"IDC failed to post ACK.\n");
|
||||
}
|
||||
|
||||
#define LS_UNKNOWN 2
|
||||
@ -691,7 +704,8 @@ skip_rio:
|
||||
case MBA_LOOP_DOWN: /* Loop Down Event */
|
||||
mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
|
||||
? RD_REG_WORD(®24->mailbox4) : 0;
|
||||
mbx = IS_QLA82XX(ha) ? RD_REG_WORD(®82->mailbox_out[4]) : mbx;
|
||||
mbx = (IS_P3P_TYPE(ha)) ? RD_REG_WORD(®82->mailbox_out[4])
|
||||
: mbx;
|
||||
ql_dbg(ql_dbg_async, vha, 0x500b,
|
||||
"LOOP DOWN detected (%x %x %x %x).\n",
|
||||
mb[1], mb[2], mb[3], mbx);
|
||||
@ -740,7 +754,7 @@ skip_rio:
|
||||
if (IS_QLA2100(ha))
|
||||
break;
|
||||
|
||||
if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA8031(ha)) {
|
||||
if (IS_CNA_CAPABLE(ha)) {
|
||||
ql_dbg(ql_dbg_async, vha, 0x500d,
|
||||
"DCBX Completed -- %04x %04x %04x.\n",
|
||||
mb[1], mb[2], mb[3]);
|
||||
@ -1002,7 +1016,7 @@ skip_rio:
|
||||
mb[1], mb[2], mb[3]);
|
||||
break;
|
||||
case MBA_IDC_NOTIFY:
|
||||
if (IS_QLA8031(vha->hw)) {
|
||||
if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
|
||||
mb[4] = RD_REG_WORD(®24->mailbox4);
|
||||
if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
|
||||
(mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
|
||||
@ -1022,7 +1036,8 @@ skip_rio:
|
||||
complete(&ha->lb_portup_comp);
|
||||
/* Fallthru */
|
||||
case MBA_IDC_TIME_EXT:
|
||||
if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw))
|
||||
if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
|
||||
IS_QLA8044(ha))
|
||||
qla81xx_idc_event(vha, mb[0], mb[1]);
|
||||
break;
|
||||
|
||||
@ -1063,7 +1078,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
|
||||
ql_log(ql_log_warn, vha, 0x3014,
|
||||
"Invalid SCSI command index (%x).\n", index);
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
||||
else
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
@ -1080,7 +1095,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
|
||||
} else {
|
||||
ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
||||
else
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
@ -1100,7 +1115,7 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
|
||||
if (index >= req->num_outstanding_cmds) {
|
||||
ql_log(ql_log_warn, vha, 0x5031,
|
||||
"Invalid command index (%x).\n", index);
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
||||
else
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
@ -1805,6 +1820,9 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
|
||||
if (scsi_status == 0) {
|
||||
bsg_job->reply->reply_payload_rcv_len =
|
||||
bsg_job->reply_payload.payload_len;
|
||||
vha->qla_stats.input_bytes +=
|
||||
bsg_job->reply->reply_payload_rcv_len;
|
||||
vha->qla_stats.input_requests++;
|
||||
rval = EXT_STATUS_OK;
|
||||
}
|
||||
goto done;
|
||||
@ -1949,7 +1967,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
|
||||
ql_dbg(ql_dbg_io, vha, 0x3017,
|
||||
"Invalid status handle (0x%x).\n", sts->handle);
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
||||
else
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
@ -2176,8 +2194,10 @@ check_scsi_status:
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_io, fcport->vha, 0x3021,
|
||||
"Port down status: port-state=0x%x.\n",
|
||||
atomic_read(&fcport->state));
|
||||
"Port to be marked lost on fcport=%02x%02x%02x, current "
|
||||
"port state= %s.\n", fcport->d_id.b.domain,
|
||||
fcport->d_id.b.area, fcport->d_id.b.al_pa,
|
||||
port_state_str[atomic_read(&fcport->state)]);
|
||||
|
||||
if (atomic_read(&fcport->state) == FCS_ONLINE)
|
||||
qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
|
||||
@ -2212,16 +2232,13 @@ check_scsi_status:
|
||||
out:
|
||||
if (logit)
|
||||
ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
|
||||
"FCP command status: 0x%x-0x%x (0x%x) "
|
||||
"nexus=%ld:%d:%d portid=%02x%02x%02x oxid=0x%x "
|
||||
"cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
|
||||
"FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%d "
|
||||
"portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x "
|
||||
"rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n",
|
||||
comp_status, scsi_status, res, vha->host_no,
|
||||
cp->device->id, cp->device->lun, fcport->d_id.b.domain,
|
||||
fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
|
||||
cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
|
||||
cp->cmnd[4], cp->cmnd[5], cp->cmnd[6], cp->cmnd[7],
|
||||
cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp), rsp_info_len,
|
||||
cp->cmnd, scsi_bufflen(cp), rsp_info_len,
|
||||
resid_len, fw_resid_len);
|
||||
|
||||
if (!res)
|
||||
@ -2324,7 +2341,7 @@ fatal:
|
||||
ql_log(ql_log_warn, vha, 0x5030,
|
||||
"Error entry - invalid handle/queue.\n");
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
|
||||
else
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
@ -2452,7 +2469,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
|
||||
}
|
||||
|
||||
/* Adjust ring index */
|
||||
if (IS_QLA82XX(ha)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
|
||||
WRT_REG_DWORD(®->rsp_q_out[0], rsp->ring_index);
|
||||
} else
|
||||
@ -2865,7 +2882,7 @@ msix_failed:
|
||||
ret = request_irq(qentry->vector,
|
||||
qla83xx_msix_entries[i].handler,
|
||||
0, qla83xx_msix_entries[i].name, rsp);
|
||||
} else if (IS_QLA82XX(ha)) {
|
||||
} else if (IS_P3P_TYPE(ha)) {
|
||||
ret = request_irq(qentry->vector,
|
||||
qla82xx_msix_entries[i].handler,
|
||||
0, qla82xx_msix_entries[i].name, rsp);
|
||||
@ -2950,7 +2967,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
|
||||
skip_msix:
|
||||
|
||||
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
|
||||
!IS_QLA8001(ha) && !IS_QLA82XX(ha) && !IS_QLAFX00(ha))
|
||||
!IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha))
|
||||
goto skip_msi;
|
||||
|
||||
ret = pci_enable_msi(ha->pdev);
|
||||
|
@ -75,7 +75,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
return QLA_FUNCTION_TIMEOUT;
|
||||
}
|
||||
|
||||
if (IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung) {
|
||||
if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) {
|
||||
/* Setting Link-Down error */
|
||||
mcp->mb[0] = MBS_LINK_DOWN_ERROR;
|
||||
ql_log(ql_log_warn, vha, 0x1004,
|
||||
@ -106,9 +106,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
|
||||
/* Load mailbox registers. */
|
||||
if (IS_QLA82XX(ha))
|
||||
if (IS_P3P_TYPE(ha))
|
||||
optr = (uint16_t __iomem *)®->isp82.mailbox_in[0];
|
||||
else if (IS_FWI2_CAPABLE(ha) && !IS_QLA82XX(ha))
|
||||
else if (IS_FWI2_CAPABLE(ha) && !(IS_P3P_TYPE(ha)))
|
||||
optr = (uint16_t __iomem *)®->isp24.mailbox0;
|
||||
else
|
||||
optr = (uint16_t __iomem *)MAILBOX_REG(ha, ®->isp, 0);
|
||||
@ -117,33 +117,25 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
command = mcp->mb[0];
|
||||
mboxes = mcp->out_mb;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1111,
|
||||
"Mailbox registers (OUT):\n");
|
||||
for (cnt = 0; cnt < ha->mbx_count; cnt++) {
|
||||
if (IS_QLA2200(ha) && cnt == 8)
|
||||
optr =
|
||||
(uint16_t __iomem *)MAILBOX_REG(ha, ®->isp, 8);
|
||||
if (mboxes & BIT_0)
|
||||
if (mboxes & BIT_0) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1112,
|
||||
"mbox[%d]<-0x%04x\n", cnt, *iptr);
|
||||
WRT_REG_WORD(optr, *iptr);
|
||||
}
|
||||
|
||||
mboxes >>= 1;
|
||||
optr++;
|
||||
iptr++;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1111,
|
||||
"Loaded MBX registers (displayed in bytes) =.\n");
|
||||
ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1112,
|
||||
(uint8_t *)mcp->mb, 16);
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1113,
|
||||
".\n");
|
||||
ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1114,
|
||||
((uint8_t *)mcp->mb + 0x10), 16);
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1115,
|
||||
".\n");
|
||||
ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1116,
|
||||
((uint8_t *)mcp->mb + 0x20), 8);
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1117,
|
||||
"I/O Address = %p.\n", optr);
|
||||
ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x100e);
|
||||
|
||||
/* Issue set host interrupt command to send cmd out. */
|
||||
ha->flags.mbox_int = 0;
|
||||
@ -159,7 +151,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
|
||||
set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
|
||||
|
||||
if (IS_QLA82XX(ha)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
if (RD_REG_DWORD(®->isp82.hint) &
|
||||
HINT_MBX_INT_PENDING) {
|
||||
spin_unlock_irqrestore(&ha->hardware_lock,
|
||||
@ -189,7 +181,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1011,
|
||||
"Cmd=%x Polling Mode.\n", command);
|
||||
|
||||
if (IS_QLA82XX(ha)) {
|
||||
if (IS_P3P_TYPE(ha)) {
|
||||
if (RD_REG_DWORD(®->isp82.hint) &
|
||||
HINT_MBX_INT_PENDING) {
|
||||
spin_unlock_irqrestore(&ha->hardware_lock,
|
||||
@ -236,7 +228,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
ha->flags.mbox_int = 0;
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
|
||||
if ((IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung)) {
|
||||
if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) {
|
||||
ha->flags.mbox_busy = 0;
|
||||
/* Setting Link-Down error */
|
||||
mcp->mb[0] = MBS_LINK_DOWN_ERROR;
|
||||
@ -254,9 +246,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
iptr2 = mcp->mb;
|
||||
iptr = (uint16_t *)&ha->mailbox_out[0];
|
||||
mboxes = mcp->in_mb;
|
||||
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1113,
|
||||
"Mailbox registers (IN):\n");
|
||||
for (cnt = 0; cnt < ha->mbx_count; cnt++) {
|
||||
if (mboxes & BIT_0)
|
||||
if (mboxes & BIT_0) {
|
||||
*iptr2 = *iptr;
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1114,
|
||||
"mbox[%d]->0x%04x\n", cnt, *iptr2);
|
||||
}
|
||||
|
||||
mboxes >>= 1;
|
||||
iptr2++;
|
||||
@ -537,7 +535,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
|
||||
mcp->mb[0] = MBC_GET_FIRMWARE_VERSION;
|
||||
mcp->out_mb = MBX_0;
|
||||
mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
if (IS_QLA81XX(vha->hw) || IS_QLA8031(ha))
|
||||
if (IS_QLA81XX(vha->hw) || IS_QLA8031(ha) || IS_QLA8044(ha))
|
||||
mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8;
|
||||
if (IS_FWI2_CAPABLE(ha))
|
||||
mcp->in_mb |= MBX_17|MBX_16|MBX_15;
|
||||
@ -556,7 +554,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
|
||||
ha->fw_memory_size = 0x1FFFF; /* Defaults to 128KB. */
|
||||
else
|
||||
ha->fw_memory_size = (mcp->mb[5] << 16) | mcp->mb[4];
|
||||
if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw)) {
|
||||
if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
|
||||
ha->mpi_version[0] = mcp->mb[10] & 0xff;
|
||||
ha->mpi_version[1] = mcp->mb[11] >> 8;
|
||||
ha->mpi_version[2] = mcp->mb[11] & 0xff;
|
||||
@ -1201,7 +1199,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x104c,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
if (IS_QLA82XX(ha) && ql2xdbwr)
|
||||
if (IS_P3P_TYPE(ha) && ql2xdbwr)
|
||||
qla82xx_wr_32(ha, ha->nxdb_wr_ptr,
|
||||
(0x04 | (ha->portnum << 5) | (0 << 8) | (0 << 16)));
|
||||
|
||||
@ -1667,7 +1665,11 @@ qla24xx_link_initialize(scsi_qla_host_t *vha)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
mcp->mb[0] = MBC_LINK_INITIALIZATION;
|
||||
mcp->mb[1] = BIT_6|BIT_4;
|
||||
mcp->mb[1] = BIT_4;
|
||||
if (vha->hw->operating_mode == LOOP)
|
||||
mcp->mb[1] |= BIT_6;
|
||||
else
|
||||
mcp->mb[1] |= BIT_5;
|
||||
mcp->mb[2] = 0;
|
||||
mcp->mb[3] = 0;
|
||||
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
@ -3574,7 +3576,6 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
unsigned long flags;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
struct device_reg_25xxmq __iomem *reg;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d3,
|
||||
@ -3595,9 +3596,6 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
if (IS_QLA83XX(ha))
|
||||
mcp->mb[15] = 0;
|
||||
|
||||
reg = (struct device_reg_25xxmq __iomem *)((ha->mqiobase) +
|
||||
QLA_QUE_PAGE * req->id);
|
||||
|
||||
mcp->mb[4] = req->id;
|
||||
/* que in ptr index */
|
||||
mcp->mb[8] = 0;
|
||||
@ -3619,12 +3617,10 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
if (!(req->options & BIT_0)) {
|
||||
WRT_REG_DWORD(®->req_q_in, 0);
|
||||
WRT_REG_DWORD(req->req_q_in, 0);
|
||||
if (!IS_QLA83XX(ha))
|
||||
WRT_REG_DWORD(®->req_q_out, 0);
|
||||
WRT_REG_DWORD(req->req_q_out, 0);
|
||||
}
|
||||
req->req_q_in = ®->req_q_in;
|
||||
req->req_q_out = ®->req_q_out;
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
@ -3646,7 +3642,6 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
unsigned long flags;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
struct device_reg_25xxmq __iomem *reg;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d6,
|
||||
@ -3664,9 +3659,6 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
if (IS_QLA83XX(ha))
|
||||
mcp->mb[15] = 0;
|
||||
|
||||
reg = (struct device_reg_25xxmq __iomem *)((ha->mqiobase) +
|
||||
QLA_QUE_PAGE * rsp->id);
|
||||
|
||||
mcp->mb[4] = rsp->id;
|
||||
/* que in ptr index */
|
||||
mcp->mb[8] = 0;
|
||||
@ -3690,9 +3682,9 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
if (!(rsp->options & BIT_0)) {
|
||||
WRT_REG_DWORD(®->rsp_q_out, 0);
|
||||
WRT_REG_DWORD(rsp->rsp_q_out, 0);
|
||||
if (!IS_QLA83XX(ha))
|
||||
WRT_REG_DWORD(®->rsp_q_in, 0);
|
||||
WRT_REG_DWORD(rsp->rsp_q_in, 0);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
@ -3872,6 +3864,112 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla82xx_set_driver_version(scsi_qla_host_t *vha, char *version)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int i;
|
||||
int len;
|
||||
uint16_t *str;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_P3P_TYPE(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117b,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
str = (void *)version;
|
||||
len = strlen(version);
|
||||
|
||||
mcp->mb[0] = MBC_SET_RNID_PARAMS;
|
||||
mcp->mb[1] = RNID_TYPE_SET_VERSION << 8;
|
||||
mcp->out_mb = MBX_1|MBX_0;
|
||||
for (i = 4; i < 16 && len; i++, str++, len -= 2) {
|
||||
mcp->mb[i] = cpu_to_le16p(str);
|
||||
mcp->out_mb |= 1<<i;
|
||||
}
|
||||
for (; i < 16; i++) {
|
||||
mcp->mb[i] = 0;
|
||||
mcp->out_mb |= 1<<i;
|
||||
}
|
||||
mcp->in_mb = MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x117c,
|
||||
"Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117d,
|
||||
"Done %s.\n", __func__);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla25xx_set_driver_version(scsi_qla_host_t *vha, char *version)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int len;
|
||||
uint16_t dwlen;
|
||||
uint8_t *str;
|
||||
dma_addr_t str_dma;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_FWI2_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA81XX(ha) ||
|
||||
IS_P3P_TYPE(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117e,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
str = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &str_dma);
|
||||
if (!str) {
|
||||
ql_log(ql_log_warn, vha, 0x117f,
|
||||
"Failed to allocate driver version param.\n");
|
||||
return QLA_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
memcpy(str, "\x7\x3\x11\x0", 4);
|
||||
dwlen = str[0];
|
||||
len = dwlen * 4 - 4;
|
||||
memset(str + 4, 0, len);
|
||||
if (len > strlen(version))
|
||||
len = strlen(version);
|
||||
memcpy(str + 4, version, len);
|
||||
|
||||
mcp->mb[0] = MBC_SET_RNID_PARAMS;
|
||||
mcp->mb[1] = RNID_TYPE_SET_VERSION << 8 | dwlen;
|
||||
mcp->mb[2] = MSW(LSD(str_dma));
|
||||
mcp->mb[3] = LSW(LSD(str_dma));
|
||||
mcp->mb[6] = MSW(MSD(str_dma));
|
||||
mcp->mb[7] = LSW(MSD(str_dma));
|
||||
mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1180,
|
||||
"Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1181,
|
||||
"Done %s.\n", __func__);
|
||||
}
|
||||
|
||||
dma_pool_free(ha->s_dma_pool, str, str_dma);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp)
|
||||
{
|
||||
@ -4407,7 +4505,7 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1109,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA8044(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
mcp->mb[0] = MBC_GET_PORT_CONFIG;
|
||||
mcp->out_mb = MBX_0;
|
||||
@ -4512,40 +4610,43 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint8_t byte;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ca,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
if (ha->thermal_support & THERMAL_SUPPORT_I2C) {
|
||||
rval = qla2x00_read_sfp(vha, 0, &byte,
|
||||
0x98, 0x1, 1, BIT_13|BIT_12|BIT_0);
|
||||
*temp = byte;
|
||||
if (rval == QLA_SUCCESS)
|
||||
goto done;
|
||||
|
||||
ql_log(ql_log_warn, vha, 0x10c9,
|
||||
"Thermal not supported through I2C bus, trying alternate "
|
||||
"method (ISP access).\n");
|
||||
ha->thermal_support &= ~THERMAL_SUPPORT_I2C;
|
||||
if (!IS_FWI2_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA81XX(ha)) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1150,
|
||||
"Thermal not supported by this card.\n");
|
||||
return rval;
|
||||
}
|
||||
|
||||
if (ha->thermal_support & THERMAL_SUPPORT_ISP) {
|
||||
rval = qla2x00_read_asic_temperature(vha, temp);
|
||||
if (rval == QLA_SUCCESS)
|
||||
goto done;
|
||||
|
||||
ql_log(ql_log_warn, vha, 0x1019,
|
||||
"Thermal not supported through ISP.\n");
|
||||
ha->thermal_support &= ~THERMAL_SUPPORT_ISP;
|
||||
if (IS_QLA25XX(ha)) {
|
||||
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
||||
ha->pdev->subsystem_device == 0x0175) {
|
||||
rval = qla2x00_read_sfp(vha, 0, &byte,
|
||||
0x98, 0x1, 1, BIT_13|BIT_0);
|
||||
*temp = byte;
|
||||
return rval;
|
||||
}
|
||||
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
|
||||
ha->pdev->subsystem_device == 0x338e) {
|
||||
rval = qla2x00_read_sfp(vha, 0, &byte,
|
||||
0x98, 0x1, 1, BIT_15|BIT_14|BIT_0);
|
||||
*temp = byte;
|
||||
return rval;
|
||||
}
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x10c9,
|
||||
"Thermal not supported by this card.\n");
|
||||
return rval;
|
||||
}
|
||||
|
||||
ql_log(ql_log_warn, vha, 0x1150,
|
||||
"Thermal not supported by this card "
|
||||
"(ignoring further requests).\n");
|
||||
return rval;
|
||||
if (IS_QLA82XX(ha)) {
|
||||
*temp = qla82xx_read_temperature(vha);
|
||||
rval = QLA_SUCCESS;
|
||||
return rval;
|
||||
} else if (IS_QLA8044(ha)) {
|
||||
*temp = qla8044_read_temperature(vha);
|
||||
rval = QLA_SUCCESS;
|
||||
return rval;
|
||||
}
|
||||
|
||||
done:
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1018,
|
||||
"Done %s.\n", __func__);
|
||||
rval = qla2x00_read_asic_temperature(vha, temp);
|
||||
return rval;
|
||||
}
|
||||
|
||||
@ -4595,7 +4696,7 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha)
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x100d,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
if (!IS_QLA82XX(ha))
|
||||
if (!IS_P3P_TYPE(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
memset(mcp, 0, sizeof(mbx_cmd_t));
|
||||
@ -4712,6 +4813,60 @@ qla82xx_md_get_template(scsi_qla_host_t *vha)
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla8044_md_get_template(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int rval = QLA_FUNCTION_FAILED;
|
||||
int offset = 0, size = MINIDUMP_SIZE_36K;
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xb11f,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
ha->md_tmplt_hdr = dma_alloc_coherent(&ha->pdev->dev,
|
||||
ha->md_template_size, &ha->md_tmplt_hdr_dma, GFP_KERNEL);
|
||||
if (!ha->md_tmplt_hdr) {
|
||||
ql_log(ql_log_warn, vha, 0xb11b,
|
||||
"Unable to allocate memory for Minidump template.\n");
|
||||
return rval;
|
||||
}
|
||||
|
||||
memset(mcp->mb, 0 , sizeof(mcp->mb));
|
||||
while (offset < ha->md_template_size) {
|
||||
mcp->mb[0] = LSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE);
|
||||
mcp->mb[1] = MSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE);
|
||||
mcp->mb[2] = LSW(RQST_TMPLT);
|
||||
mcp->mb[3] = MSW(RQST_TMPLT);
|
||||
mcp->mb[4] = LSW(LSD(ha->md_tmplt_hdr_dma + offset));
|
||||
mcp->mb[5] = MSW(LSD(ha->md_tmplt_hdr_dma + offset));
|
||||
mcp->mb[6] = LSW(MSD(ha->md_tmplt_hdr_dma + offset));
|
||||
mcp->mb[7] = MSW(MSD(ha->md_tmplt_hdr_dma + offset));
|
||||
mcp->mb[8] = LSW(size);
|
||||
mcp->mb[9] = MSW(size);
|
||||
mcp->mb[10] = offset & 0x0000FFFF;
|
||||
mcp->mb[11] = offset & 0xFFFF0000;
|
||||
mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->out_mb = MBX_11|MBX_10|MBX_9|MBX_8|
|
||||
MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0xb11c,
|
||||
"mailbox command FAILED=0x%x, subcode=%x.\n",
|
||||
((mcp->mb[1] << 16) | mcp->mb[0]),
|
||||
((mcp->mb[3] << 16) | mcp->mb[2]));
|
||||
return rval;
|
||||
} else
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xb11d,
|
||||
"Done %s.\n", __func__);
|
||||
offset = offset + size;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla81xx_set_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg)
|
||||
{
|
||||
@ -4808,7 +4963,7 @@ qla82xx_mbx_beacon_ctl(scsi_qla_host_t *vha, int enable)
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA82XX(ha))
|
||||
if (!IS_P3P_TYPE(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1127,
|
||||
|
@ -699,6 +699,8 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
|
||||
req->cnt = req->length;
|
||||
req->id = que_id;
|
||||
reg = ISP_QUE_REG(ha, que_id);
|
||||
req->req_q_in = ®->isp25mq.req_q_in;
|
||||
req->req_q_out = ®->isp25mq.req_q_out;
|
||||
req->max_q_depth = ha->req_q_map[0]->max_q_depth;
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
|
||||
|
@ -294,7 +294,7 @@ premature_exit:
|
||||
* Context:
|
||||
* Kernel context.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
qlafx00_driver_shutdown(scsi_qla_host_t *vha, int tmo)
|
||||
{
|
||||
int rval;
|
||||
@ -775,6 +775,29 @@ qlafx00_lun_reset(fc_port_t *fcport, unsigned int l, int tag)
|
||||
return qlafx00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
|
||||
}
|
||||
|
||||
int
|
||||
qlafx00_loop_reset(scsi_qla_host_t *vha)
|
||||
{
|
||||
int ret;
|
||||
struct fc_port *fcport;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (ql2xtargetreset) {
|
||||
list_for_each_entry(fcport, &vha->vp_fcports, list) {
|
||||
if (fcport->port_type != FCT_TARGET)
|
||||
continue;
|
||||
|
||||
ret = ha->isp_ops->target_reset(fcport, 0, 0);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_taskm, vha, 0x803d,
|
||||
"Bus Reset failed: Reset=%d "
|
||||
"d_id=%x.\n", ret, fcport->d_id.b24);
|
||||
}
|
||||
}
|
||||
}
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
qlafx00_iospace_config(struct qla_hw_data *ha)
|
||||
{
|
||||
@ -918,12 +941,23 @@ qlafx00_init_fw_ready(scsi_qla_host_t *vha)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
|
||||
uint32_t aenmbx, aenmbx7 = 0;
|
||||
uint32_t pseudo_aen;
|
||||
uint32_t state[5];
|
||||
bool done = false;
|
||||
|
||||
/* 30 seconds wait - Adjust if required */
|
||||
wait_time = 30;
|
||||
|
||||
pseudo_aen = RD_REG_DWORD(®->pseudoaen);
|
||||
if (pseudo_aen == 1) {
|
||||
aenmbx7 = RD_REG_DWORD(®->initval7);
|
||||
ha->mbx_intr_code = MSW(aenmbx7);
|
||||
ha->rqstq_intr_code = LSW(aenmbx7);
|
||||
rval = qlafx00_driver_shutdown(vha, 10);
|
||||
if (rval != QLA_SUCCESS)
|
||||
qlafx00_soft_reset(vha);
|
||||
}
|
||||
|
||||
/* wait time before firmware ready */
|
||||
wtime = jiffies + (wait_time * HZ);
|
||||
do {
|
||||
@ -1349,21 +1383,22 @@ qlafx00_configure_devices(scsi_qla_host_t *vha)
|
||||
}
|
||||
|
||||
static void
|
||||
qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha)
|
||||
qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha, bool critemp)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
fc_port_t *fcport;
|
||||
|
||||
vha->flags.online = 0;
|
||||
ha->flags.chip_reset_done = 0;
|
||||
ha->mr.fw_hbt_en = 0;
|
||||
clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
vha->qla_stats.total_isp_aborts++;
|
||||
|
||||
ql_log(ql_log_info, vha, 0x013f,
|
||||
"Performing ISP error recovery - ha = %p.\n", ha);
|
||||
|
||||
ha->isp_ops->reset_chip(vha);
|
||||
if (!critemp) {
|
||||
ha->flags.chip_reset_done = 0;
|
||||
clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
vha->qla_stats.total_isp_aborts++;
|
||||
ql_log(ql_log_info, vha, 0x013f,
|
||||
"Performing ISP error recovery - ha = %p.\n", ha);
|
||||
ha->isp_ops->reset_chip(vha);
|
||||
}
|
||||
|
||||
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
||||
atomic_set(&vha->loop_state, LOOP_DOWN);
|
||||
@ -1383,12 +1418,19 @@ qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha)
|
||||
}
|
||||
|
||||
if (!ha->flags.eeh_busy) {
|
||||
/* Requeue all commands in outstanding command list. */
|
||||
qla2x00_abort_all_cmds(vha, DID_RESET << 16);
|
||||
if (critemp) {
|
||||
qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
|
||||
} else {
|
||||
/* Requeue all commands in outstanding command list. */
|
||||
qla2x00_abort_all_cmds(vha, DID_RESET << 16);
|
||||
}
|
||||
}
|
||||
|
||||
qla2x00_free_irqs(vha);
|
||||
set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
|
||||
if (critemp)
|
||||
set_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags);
|
||||
else
|
||||
set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
|
||||
|
||||
/* Clear the Interrupts */
|
||||
QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
|
||||
@ -1475,6 +1517,7 @@ qlafx00_timer_routine(scsi_qla_host_t *vha)
|
||||
uint32_t fw_heart_beat;
|
||||
uint32_t aenmbx0;
|
||||
struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
|
||||
uint32_t tempc;
|
||||
|
||||
/* Check firmware health */
|
||||
if (ha->mr.fw_hbt_cnt)
|
||||
@ -1539,10 +1582,36 @@ qlafx00_timer_routine(scsi_qla_host_t *vha)
|
||||
} else if ((aenmbx0 & 0xFF00) == MBA_FW_POLL_STATE) {
|
||||
ha->mr.fw_reset_timer_tick =
|
||||
QLAFX00_MAX_RESET_INTERVAL;
|
||||
} else if (aenmbx0 == MBA_FW_RESET_FCT) {
|
||||
ha->mr.fw_reset_timer_tick =
|
||||
QLAFX00_MAX_RESET_INTERVAL;
|
||||
}
|
||||
ha->mr.old_aenmbx0_state = aenmbx0;
|
||||
ha->mr.fw_reset_timer_tick--;
|
||||
}
|
||||
if (test_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags)) {
|
||||
/*
|
||||
* Critical temperature recovery to be
|
||||
* performed in timer routine
|
||||
*/
|
||||
if (ha->mr.fw_critemp_timer_tick == 0) {
|
||||
tempc = QLAFX00_GET_TEMPERATURE(ha);
|
||||
ql_dbg(ql_dbg_timer, vha, 0x6012,
|
||||
"ISPFx00(%s): Critical temp timer, "
|
||||
"current SOC temperature: %d\n",
|
||||
__func__, tempc);
|
||||
if (tempc < ha->mr.critical_temperature) {
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
clear_bit(FX00_CRITEMP_RECOVERY,
|
||||
&vha->dpc_flags);
|
||||
qla2xxx_wake_dpc(vha);
|
||||
}
|
||||
ha->mr.fw_critemp_timer_tick =
|
||||
QLAFX00_CRITEMP_INTERVAL;
|
||||
} else {
|
||||
ha->mr.fw_critemp_timer_tick--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1570,7 +1639,7 @@ qlafx00_reset_initialize(scsi_qla_host_t *vha)
|
||||
|
||||
if (vha->flags.online) {
|
||||
scsi_block_requests(vha->host);
|
||||
qlafx00_abort_isp_cleanup(vha);
|
||||
qlafx00_abort_isp_cleanup(vha, false);
|
||||
}
|
||||
|
||||
ql_log(ql_log_info, vha, 0x0143,
|
||||
@ -1602,7 +1671,15 @@ qlafx00_abort_isp(scsi_qla_host_t *vha)
|
||||
}
|
||||
|
||||
scsi_block_requests(vha->host);
|
||||
qlafx00_abort_isp_cleanup(vha);
|
||||
qlafx00_abort_isp_cleanup(vha, false);
|
||||
} else {
|
||||
scsi_block_requests(vha->host);
|
||||
clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
vha->qla_stats.total_isp_aborts++;
|
||||
ha->isp_ops->reset_chip(vha);
|
||||
set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
|
||||
/* Clear the Interrupts */
|
||||
QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
|
||||
}
|
||||
|
||||
ql_log(ql_log_info, vha, 0x0145,
|
||||
@ -1688,6 +1765,15 @@ qlafx00_process_aen(struct scsi_qla_host *vha, struct qla_work_evt *evt)
|
||||
aen_code = FCH_EVT_LINKDOWN;
|
||||
aen_data = 0;
|
||||
break;
|
||||
case QLAFX00_MBA_TEMP_CRIT: /* Critical temperature event */
|
||||
ql_log(ql_log_info, vha, 0x5082,
|
||||
"Process critical temperature event "
|
||||
"aenmb[0]: %x\n",
|
||||
evt->u.aenfx.evtcode);
|
||||
scsi_block_requests(vha->host);
|
||||
qlafx00_abort_isp_cleanup(vha, true);
|
||||
scsi_unblock_requests(vha->host);
|
||||
break;
|
||||
}
|
||||
|
||||
fc_host_post_event(vha->host, fc_get_event_number(),
|
||||
@ -1879,6 +1965,11 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
|
||||
sizeof(vha->hw->mr.uboot_version));
|
||||
memcpy(&vha->hw->mr.fru_serial_num, pinfo->fru_serial_num,
|
||||
sizeof(vha->hw->mr.fru_serial_num));
|
||||
vha->hw->mr.critical_temperature =
|
||||
(pinfo->nominal_temp_value) ?
|
||||
pinfo->nominal_temp_value : QLAFX00_CRITEMP_THRSHLD;
|
||||
ha->mr.extended_io_enabled = (pinfo->enabled_capabilities &
|
||||
QLAFX00_EXTENDED_IO_EN_MASK) != 0;
|
||||
} else if (fx_type == FXDISC_GET_PORT_INFO) {
|
||||
struct port_info_data *pinfo =
|
||||
(struct port_info_data *) fdisc->u.fxiocb.rsp_addr;
|
||||
@ -2021,6 +2112,7 @@ qlafx00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t tempc;
|
||||
|
||||
/* Clear adapter flags. */
|
||||
vha->flags.online = 0;
|
||||
@ -2028,7 +2120,6 @@ qlafx00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
vha->flags.reset_active = 0;
|
||||
ha->flags.pci_channel_io_perm_failure = 0;
|
||||
ha->flags.eeh_busy = 0;
|
||||
ha->thermal_support = 0;
|
||||
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
|
||||
atomic_set(&vha->loop_state, LOOP_DOWN);
|
||||
vha->device_flags = DFLG_NO_CABLE;
|
||||
@ -2072,6 +2163,11 @@ qlafx00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
rval = qla2x00_init_rings(vha);
|
||||
ha->flags.chip_reset_done = 1;
|
||||
|
||||
tempc = QLAFX00_GET_TEMPERATURE(ha);
|
||||
ql_dbg(ql_dbg_init, vha, 0x0152,
|
||||
"ISPFx00(%s): Critical temp timer, current SOC temperature: 0x%x\n",
|
||||
__func__, tempc);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
@ -2526,16 +2622,13 @@ check_scsi_status:
|
||||
|
||||
if (logit)
|
||||
ql_dbg(ql_dbg_io, fcport->vha, 0x3058,
|
||||
"FCP command status: 0x%x-0x%x (0x%x) "
|
||||
"nexus=%ld:%d:%d tgt_id: 0x%x lscsi_status: 0x%x"
|
||||
"cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
|
||||
"rsp_info=0x%x resid=0x%x fw_resid=0x%x "
|
||||
"sense_len=0x%x, par_sense_len=0x%x, rsp_info_len=0x%x\n",
|
||||
"FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%d "
|
||||
"tgt_id: 0x%x lscsi_status: 0x%x cdb=%10phN len=0x%x "
|
||||
"rsp_info=0x%x resid=0x%x fw_resid=0x%x sense_len=0x%x, "
|
||||
"par_sense_len=0x%x, rsp_info_len=0x%x\n",
|
||||
comp_status, scsi_status, res, vha->host_no,
|
||||
cp->device->id, cp->device->lun, fcport->tgt_id,
|
||||
lscsi_status, cp->cmnd[0], cp->cmnd[1], cp->cmnd[2],
|
||||
cp->cmnd[3], cp->cmnd[4], cp->cmnd[5], cp->cmnd[6],
|
||||
cp->cmnd[7], cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp),
|
||||
lscsi_status, cp->cmnd, scsi_bufflen(cp),
|
||||
rsp_info_len, resid_len, fw_resid_len, sense_len,
|
||||
par_sense_len, rsp_info_len);
|
||||
|
||||
@ -2720,9 +2813,6 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha,
|
||||
struct sts_entry_fx00 *pkt;
|
||||
response_t *lptr;
|
||||
|
||||
if (!vha->flags.online)
|
||||
return;
|
||||
|
||||
while (RD_REG_DWORD((void __iomem *)&(rsp->ring_ptr->signature)) !=
|
||||
RESPONSE_PROCESSED) {
|
||||
lptr = rsp->ring_ptr;
|
||||
@ -2824,6 +2914,28 @@ qlafx00_async_event(scsi_qla_host_t *vha)
|
||||
ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3]);
|
||||
data_size = 4;
|
||||
break;
|
||||
|
||||
case QLAFX00_MBA_TEMP_OVER: /* Over temperature event */
|
||||
ql_log(ql_log_info, vha, 0x5085,
|
||||
"Asynchronous over temperature event received "
|
||||
"aenmb[0]: %x\n",
|
||||
ha->aenmb[0]);
|
||||
break;
|
||||
|
||||
case QLAFX00_MBA_TEMP_NORM: /* Normal temperature event */
|
||||
ql_log(ql_log_info, vha, 0x5086,
|
||||
"Asynchronous normal temperature event received "
|
||||
"aenmb[0]: %x\n",
|
||||
ha->aenmb[0]);
|
||||
break;
|
||||
|
||||
case QLAFX00_MBA_TEMP_CRIT: /* Critical temperature event */
|
||||
ql_log(ql_log_info, vha, 0x5083,
|
||||
"Asynchronous critical temperature event received "
|
||||
"aenmb[0]: %x\n",
|
||||
ha->aenmb[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
ha->aenmb[1] = RD_REG_WORD(®->aenmailbox1);
|
||||
ha->aenmb[2] = RD_REG_WORD(®->aenmailbox2);
|
||||
|
@ -329,11 +329,13 @@ struct config_info_data {
|
||||
uint64_t adapter_id;
|
||||
|
||||
uint32_t cluster_key_len;
|
||||
uint8_t cluster_key[10];
|
||||
uint8_t cluster_key[16];
|
||||
|
||||
uint64_t cluster_master_id;
|
||||
uint64_t cluster_slave_id;
|
||||
uint8_t cluster_flags;
|
||||
uint32_t enabled_capabilities;
|
||||
uint32_t nominal_temp_value;
|
||||
} __packed;
|
||||
|
||||
#define FXDISC_GET_CONFIG_INFO 0x01
|
||||
@ -342,10 +344,11 @@ struct config_info_data {
|
||||
#define FXDISC_GET_TGT_NODE_LIST 0x81
|
||||
#define FXDISC_REG_HOST_INFO 0x99
|
||||
|
||||
#define QLAFX00_HBA_ICNTRL_REG 0x21B08
|
||||
#define QLAFX00_HBA_ICNTRL_REG 0x20B08
|
||||
#define QLAFX00_ICR_ENB_MASK 0x80000000
|
||||
#define QLAFX00_ICR_DIS_MASK 0x7fffffff
|
||||
#define QLAFX00_HST_RST_REG 0x18264
|
||||
#define QLAFX00_SOC_TEMP_REG 0x184C4
|
||||
#define QLAFX00_HST_TO_HBA_REG 0x20A04
|
||||
#define QLAFX00_HBA_TO_HOST_REG 0x21B70
|
||||
#define QLAFX00_HST_INT_STS_BITS 0x7
|
||||
@ -361,6 +364,9 @@ struct config_info_data {
|
||||
#define QLAFX00_INTR_ALL_CMPLT 0x7
|
||||
|
||||
#define QLAFX00_MBA_SYSTEM_ERR 0x8002
|
||||
#define QLAFX00_MBA_TEMP_OVER 0x8005
|
||||
#define QLAFX00_MBA_TEMP_NORM 0x8006
|
||||
#define QLAFX00_MBA_TEMP_CRIT 0x8007
|
||||
#define QLAFX00_MBA_LINK_UP 0x8011
|
||||
#define QLAFX00_MBA_LINK_DOWN 0x8012
|
||||
#define QLAFX00_MBA_PORT_UPDATE 0x8014
|
||||
@ -434,9 +440,11 @@ struct qla_mt_iocb_rqst_fx00 {
|
||||
|
||||
__le32 dataword_extra;
|
||||
|
||||
__le32 req_len;
|
||||
__le16 req_len;
|
||||
__le16 reserved_2;
|
||||
|
||||
__le32 rsp_len;
|
||||
__le16 rsp_len;
|
||||
__le16 reserved_3;
|
||||
};
|
||||
|
||||
struct qla_mt_iocb_rsp_fx00 {
|
||||
@ -499,12 +507,37 @@ struct mr_data_fx00 {
|
||||
uint32_t old_fw_hbt_cnt;
|
||||
uint16_t fw_reset_timer_tick;
|
||||
uint8_t fw_reset_timer_exp;
|
||||
uint16_t fw_critemp_timer_tick;
|
||||
uint32_t old_aenmbx0_state;
|
||||
uint32_t critical_temperature;
|
||||
bool extended_io_enabled;
|
||||
};
|
||||
|
||||
#define QLAFX00_EXTENDED_IO_EN_MASK 0x20
|
||||
|
||||
/*
|
||||
* SoC Junction Temperature is stored in
|
||||
* bits 9:1 of SoC Junction Temperature Register
|
||||
* in a firmware specific format format.
|
||||
* To get the temperature in Celsius degrees
|
||||
* the value from this bitfiled should be converted
|
||||
* using this formula:
|
||||
* Temperature (degrees C) = ((3,153,000 - (10,000 * X)) / 13,825)
|
||||
* where X is the bit field value
|
||||
* this macro reads the register, extracts the bitfield value,
|
||||
* performs the calcualtions and returns temperature in Celsius
|
||||
*/
|
||||
#define QLAFX00_GET_TEMPERATURE(ha) ((3153000 - (10000 * \
|
||||
((QLAFX00_RD_REG(ha, QLAFX00_SOC_TEMP_REG) & 0x3FE) >> 1))) / 13825)
|
||||
|
||||
|
||||
#define QLAFX00_LOOP_DOWN_TIME 615 /* 600 */
|
||||
#define QLAFX00_HEARTBEAT_INTERVAL 6 /* number of seconds */
|
||||
#define QLAFX00_HEARTBEAT_MISS_CNT 3 /* number of miss */
|
||||
#define QLAFX00_RESET_INTERVAL 120 /* number of seconds */
|
||||
#define QLAFX00_MAX_RESET_INTERVAL 600 /* number of seconds */
|
||||
#define QLAFX00_CRITEMP_INTERVAL 60 /* number of seconds */
|
||||
|
||||
#define QLAFX00_CRITEMP_THRSHLD 80 /* Celsius degrees */
|
||||
|
||||
#endif
|
||||
|
@ -848,7 +848,6 @@ qla82xx_rom_lock(struct qla_hw_data *ha)
|
||||
{
|
||||
int done = 0, timeout = 0;
|
||||
uint32_t lock_owner = 0;
|
||||
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
|
||||
|
||||
while (!done) {
|
||||
/* acquire semaphore2 from PCI HW block */
|
||||
@ -857,9 +856,6 @@ qla82xx_rom_lock(struct qla_hw_data *ha)
|
||||
break;
|
||||
if (timeout >= qla82xx_rom_lock_timeout) {
|
||||
lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb085,
|
||||
"Failed to acquire rom lock, acquired by %d.\n",
|
||||
lock_owner);
|
||||
return -1;
|
||||
}
|
||||
timeout++;
|
||||
@ -1666,8 +1662,14 @@ qla82xx_iospace_config(struct qla_hw_data *ha)
|
||||
}
|
||||
|
||||
/* Mapping of IO base pointer */
|
||||
ha->iobase = (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
|
||||
0xbc000 + (ha->pdev->devfn << 11));
|
||||
if (IS_QLA8044(ha)) {
|
||||
ha->iobase =
|
||||
(device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase);
|
||||
} else if (IS_QLA82XX(ha)) {
|
||||
ha->iobase =
|
||||
(device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
|
||||
0xbc000 + (ha->pdev->devfn << 11));
|
||||
}
|
||||
|
||||
if (!ql2xdbwr) {
|
||||
ha->nxdb_wr_ptr =
|
||||
@ -1967,7 +1969,7 @@ static struct qla82xx_legacy_intr_set legacy_intr[] = \
|
||||
* @ha: SCSI driver HA context
|
||||
* @mb0: Mailbox0 register
|
||||
*/
|
||||
static void
|
||||
void
|
||||
qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
|
||||
{
|
||||
uint16_t cnt;
|
||||
@ -2075,13 +2077,6 @@ qla82xx_intr_handler(int irq, void *dev_id)
|
||||
WRT_REG_DWORD(®->host_int, 0);
|
||||
}
|
||||
|
||||
#ifdef QL_DEBUG_LEVEL_17
|
||||
if (!irq && ha->flags.eeh_busy)
|
||||
ql_log(ql_log_warn, vha, 0x503d,
|
||||
"isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
|
||||
status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
|
||||
#endif
|
||||
|
||||
qla2x00_handle_mbx_completion(ha, status);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
@ -2147,13 +2142,6 @@ qla82xx_msix_default(int irq, void *dev_id)
|
||||
WRT_REG_DWORD(®->host_int, 0);
|
||||
} while (0);
|
||||
|
||||
#ifdef QL_DEBUG_LEVEL_17
|
||||
if (!irq && ha->flags.eeh_busy)
|
||||
ql_log(ql_log_warn, vha, 0x5044,
|
||||
"isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
|
||||
status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
|
||||
#endif
|
||||
|
||||
qla2x00_handle_mbx_completion(ha, status);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
@ -2247,7 +2235,10 @@ qla82xx_enable_intrs(struct qla_hw_data *ha)
|
||||
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
|
||||
qla82xx_mbx_intr_enable(vha);
|
||||
spin_lock_irq(&ha->hardware_lock);
|
||||
qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
|
||||
if (IS_QLA8044(ha))
|
||||
qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 0);
|
||||
else
|
||||
qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
|
||||
spin_unlock_irq(&ha->hardware_lock);
|
||||
ha->interrupts_on = 1;
|
||||
}
|
||||
@ -2258,7 +2249,10 @@ qla82xx_disable_intrs(struct qla_hw_data *ha)
|
||||
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
|
||||
qla82xx_mbx_intr_disable(vha);
|
||||
spin_lock_irq(&ha->hardware_lock);
|
||||
qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
|
||||
if (IS_QLA8044(ha))
|
||||
qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 1);
|
||||
else
|
||||
qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
|
||||
spin_unlock_irq(&ha->hardware_lock);
|
||||
ha->interrupts_on = 0;
|
||||
}
|
||||
@ -3008,6 +3002,9 @@ qla8xxx_dev_failed_handler(scsi_qla_host_t *vha)
|
||||
if (IS_QLA82XX(ha)) {
|
||||
qla82xx_clear_drv_active(ha);
|
||||
qla82xx_idc_unlock(ha);
|
||||
} else if (IS_QLA8044(ha)) {
|
||||
qla8044_clear_drv_active(vha);
|
||||
qla8044_idc_unlock(ha);
|
||||
}
|
||||
|
||||
/* Set DEV_FAILED flag to disable timer */
|
||||
@ -3134,7 +3131,7 @@ qla82xx_check_md_needed(scsi_qla_host_t *vha)
|
||||
if (fw_major_version != ha->fw_major_version ||
|
||||
fw_minor_version != ha->fw_minor_version ||
|
||||
fw_subminor_version != ha->fw_subminor_version) {
|
||||
ql_log(ql_log_info, vha, 0xb02d,
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb02d,
|
||||
"Firmware version differs "
|
||||
"Previous version: %d:%d:%d - "
|
||||
"New version: %d:%d:%d\n",
|
||||
@ -3330,6 +3327,14 @@ static int qla82xx_check_temp(scsi_qla_host_t *vha)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qla82xx_read_temperature(scsi_qla_host_t *vha)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = qla82xx_rd_32(vha->hw, CRB_TEMP_STATE);
|
||||
return qla82xx_get_temp_val(temp);
|
||||
}
|
||||
|
||||
void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
@ -3423,8 +3428,18 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
|
||||
|
||||
int qla82xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
||||
{
|
||||
int rval;
|
||||
rval = qla82xx_device_state_handler(vha);
|
||||
int rval = -1;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
rval = qla82xx_device_state_handler(vha);
|
||||
else if (IS_QLA8044(ha)) {
|
||||
qla8044_idc_lock(ha);
|
||||
/* Decide the reset ownership */
|
||||
qla83xx_reset_ownership(vha);
|
||||
qla8044_idc_unlock(ha);
|
||||
rval = qla8044_device_state_handler(vha);
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
@ -3432,17 +3447,25 @@ void
|
||||
qla82xx_set_reset_owner(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t dev_state;
|
||||
uint32_t dev_state = 0;
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
|
||||
else if (IS_QLA8044(ha))
|
||||
dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
|
||||
|
||||
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
|
||||
if (dev_state == QLA8XXX_DEV_READY) {
|
||||
ql_log(ql_log_info, vha, 0xb02f,
|
||||
"HW State: NEED RESET\n");
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA8XXX_DEV_NEED_RESET);
|
||||
ha->flags.nic_core_reset_owner = 1;
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb030,
|
||||
"reset_owner is 0x%x\n", ha->portnum);
|
||||
if (IS_QLA82XX(ha)) {
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA8XXX_DEV_NEED_RESET);
|
||||
ha->flags.nic_core_reset_owner = 1;
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb030,
|
||||
"reset_owner is 0x%x\n", ha->portnum);
|
||||
} else if (IS_QLA8044(ha))
|
||||
qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
|
||||
QLA8XXX_DEV_NEED_RESET);
|
||||
} else
|
||||
ql_log(ql_log_info, vha, 0xb031,
|
||||
"Device state is 0x%x = %s.\n",
|
||||
@ -3463,7 +3486,7 @@ qla82xx_set_reset_owner(scsi_qla_host_t *vha)
|
||||
int
|
||||
qla82xx_abort_isp(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval;
|
||||
int rval = -1;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (vha->device_flags & DFLG_DEV_FAILED) {
|
||||
@ -3477,7 +3500,15 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
|
||||
qla82xx_set_reset_owner(vha);
|
||||
qla82xx_idc_unlock(ha);
|
||||
|
||||
rval = qla82xx_device_state_handler(vha);
|
||||
if (IS_QLA82XX(ha))
|
||||
rval = qla82xx_device_state_handler(vha);
|
||||
else if (IS_QLA8044(ha)) {
|
||||
qla8044_idc_lock(ha);
|
||||
/* Decide the reset ownership */
|
||||
qla83xx_reset_ownership(vha);
|
||||
qla8044_idc_unlock(ha);
|
||||
rval = qla8044_device_state_handler(vha);
|
||||
}
|
||||
|
||||
qla82xx_idc_lock(ha);
|
||||
qla82xx_clear_rst_ready(ha);
|
||||
@ -3597,7 +3628,7 @@ int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha)
|
||||
void
|
||||
qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
|
||||
{
|
||||
int i;
|
||||
int i, fw_state = 0;
|
||||
unsigned long flags;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
@ -3608,7 +3639,11 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
|
||||
if (!ha->flags.isp82xx_fw_hung) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
msleep(1000);
|
||||
if (qla82xx_check_fw_alive(vha)) {
|
||||
if (IS_QLA82XX(ha))
|
||||
fw_state = qla82xx_check_fw_alive(vha);
|
||||
else if (IS_QLA8044(ha))
|
||||
fw_state = qla8044_check_fw_alive(vha);
|
||||
if (fw_state) {
|
||||
ha->flags.isp82xx_fw_hung = 1;
|
||||
qla82xx_clear_pending_mbx(vha);
|
||||
break;
|
||||
@ -4072,7 +4107,7 @@ qla82xx_minidump_process_rdmem(scsi_qla_host_t *vha,
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
qla82xx_validate_template_chksum(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
@ -4384,7 +4419,11 @@ qla82xx_md_prep(scsi_qla_host_t *vha)
|
||||
ha->md_template_size / 1024);
|
||||
|
||||
/* Get Minidump template */
|
||||
rval = qla82xx_md_get_template(vha);
|
||||
if (IS_QLA8044(ha))
|
||||
rval = qla8044_md_get_template(vha);
|
||||
else
|
||||
rval = qla82xx_md_get_template(vha);
|
||||
|
||||
if (rval == QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb04b,
|
||||
"MiniDump Template obtained\n");
|
||||
|
@ -589,6 +589,7 @@
|
||||
* The PCI VendorID and DeviceID for our board.
|
||||
*/
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP8021 0x8021
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP8044 0x8044
|
||||
|
||||
#define QLA82XX_MSIX_TBL_SPACE 8192
|
||||
#define QLA82XX_PCI_REG_MSIX_TBL 0x44
|
||||
@ -954,6 +955,11 @@ struct ct6_dsd {
|
||||
#define QLA82XX_CNTRL 98
|
||||
#define QLA82XX_TLHDR 99
|
||||
#define QLA82XX_RDEND 255
|
||||
#define QLA8044_POLLRD 35
|
||||
#define QLA8044_RDMUX2 36
|
||||
#define QLA8044_L1DTG 8
|
||||
#define QLA8044_L1ITG 9
|
||||
#define QLA8044_POLLRDMWR 37
|
||||
|
||||
/*
|
||||
* Opcodes for Control Entries.
|
||||
@ -1191,4 +1197,8 @@ enum {
|
||||
QLA82XX_TEMP_WARN, /* Sound alert, temperature getting high */
|
||||
QLA82XX_TEMP_PANIC /* Fatal error, hardware has shut down. */
|
||||
};
|
||||
|
||||
#define LEG_INTR_PTR_OFFSET 0x38C0
|
||||
#define LEG_INTR_TRIG_OFFSET 0x38C4
|
||||
#define LEG_INTR_MASK_OFFSET 0x38C8
|
||||
#endif
|
||||
|
3716
drivers/scsi/qla2xxx/qla_nx2.c
Normal file
3716
drivers/scsi/qla2xxx/qla_nx2.c
Normal file
File diff suppressed because it is too large
Load Diff
551
drivers/scsi/qla2xxx/qla_nx2.h
Normal file
551
drivers/scsi/qla2xxx/qla_nx2.h
Normal file
@ -0,0 +1,551 @@
|
||||
/*
|
||||
* QLogic Fibre Channel HBA Driver
|
||||
* Copyright (c) 2003-2013 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla2xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#ifndef __QLA_NX2_H
|
||||
#define __QLA_NX2_H
|
||||
|
||||
#define QSNT_ACK_TOV 30
|
||||
#define INTENT_TO_RECOVER 0x01
|
||||
#define PROCEED_TO_RECOVER 0x02
|
||||
#define IDC_LOCK_RECOVERY_OWNER_MASK 0x3C
|
||||
#define IDC_LOCK_RECOVERY_STATE_MASK 0x3
|
||||
#define IDC_LOCK_RECOVERY_STATE_SHIFT_BITS 2
|
||||
|
||||
#define QLA8044_DRV_LOCK_MSLEEP 200
|
||||
#define QLA8044_ADDR_DDR_NET (0x0000000000000000ULL)
|
||||
#define QLA8044_ADDR_DDR_NET_MAX (0x000000000fffffffULL)
|
||||
|
||||
#define MD_MIU_TEST_AGT_WRDATA_LO 0x410000A0
|
||||
#define MD_MIU_TEST_AGT_WRDATA_HI 0x410000A4
|
||||
#define MD_MIU_TEST_AGT_WRDATA_ULO 0x410000B0
|
||||
#define MD_MIU_TEST_AGT_WRDATA_UHI 0x410000B4
|
||||
#define MD_MIU_TEST_AGT_RDDATA_LO 0x410000A8
|
||||
#define MD_MIU_TEST_AGT_RDDATA_HI 0x410000AC
|
||||
#define MD_MIU_TEST_AGT_RDDATA_ULO 0x410000B8
|
||||
#define MD_MIU_TEST_AGT_RDDATA_UHI 0x410000BC
|
||||
|
||||
/* MIU_TEST_AGT_CTRL flags. work for SIU as well */
|
||||
#define MIU_TA_CTL_WRITE_ENABLE (MIU_TA_CTL_WRITE | MIU_TA_CTL_ENABLE)
|
||||
#define MIU_TA_CTL_WRITE_START (MIU_TA_CTL_WRITE | MIU_TA_CTL_ENABLE | \
|
||||
MIU_TA_CTL_START)
|
||||
#define MIU_TA_CTL_START_ENABLE (MIU_TA_CTL_START | MIU_TA_CTL_ENABLE)
|
||||
|
||||
/* Imbus address bit used to indicate a host address. This bit is
|
||||
* eliminated by the pcie bar and bar select before presentation
|
||||
* over pcie. */
|
||||
/* host memory via IMBUS */
|
||||
#define QLA8044_P2_ADDR_PCIE (0x0000000800000000ULL)
|
||||
#define QLA8044_P3_ADDR_PCIE (0x0000008000000000ULL)
|
||||
#define QLA8044_ADDR_PCIE_MAX (0x0000000FFFFFFFFFULL)
|
||||
#define QLA8044_ADDR_OCM0 (0x0000000200000000ULL)
|
||||
#define QLA8044_ADDR_OCM0_MAX (0x00000002000fffffULL)
|
||||
#define QLA8044_ADDR_OCM1 (0x0000000200400000ULL)
|
||||
#define QLA8044_ADDR_OCM1_MAX (0x00000002004fffffULL)
|
||||
#define QLA8044_ADDR_QDR_NET (0x0000000300000000ULL)
|
||||
#define QLA8044_P2_ADDR_QDR_NET_MAX (0x00000003001fffffULL)
|
||||
#define QLA8044_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL)
|
||||
#define QLA8044_ADDR_QDR_NET_MAX (0x0000000307ffffffULL)
|
||||
#define QLA8044_PCI_CRBSPACE ((unsigned long)0x06000000)
|
||||
#define QLA8044_PCI_DIRECT_CRB ((unsigned long)0x04400000)
|
||||
#define QLA8044_PCI_CAMQM ((unsigned long)0x04800000)
|
||||
#define QLA8044_PCI_CAMQM_MAX ((unsigned long)0x04ffffff)
|
||||
#define QLA8044_PCI_DDR_NET ((unsigned long)0x00000000)
|
||||
#define QLA8044_PCI_QDR_NET ((unsigned long)0x04000000)
|
||||
#define QLA8044_PCI_QDR_NET_MAX ((unsigned long)0x043fffff)
|
||||
|
||||
/* PCI Windowing for DDR regions. */
|
||||
#define QLA8044_ADDR_IN_RANGE(addr, low, high) \
|
||||
(((addr) <= (high)) && ((addr) >= (low)))
|
||||
|
||||
/* Indirectly Mapped Registers */
|
||||
#define QLA8044_FLASH_SPI_STATUS 0x2808E010
|
||||
#define QLA8044_FLASH_SPI_CONTROL 0x2808E014
|
||||
#define QLA8044_FLASH_STATUS 0x42100004
|
||||
#define QLA8044_FLASH_CONTROL 0x42110004
|
||||
#define QLA8044_FLASH_ADDR 0x42110008
|
||||
#define QLA8044_FLASH_WRDATA 0x4211000C
|
||||
#define QLA8044_FLASH_RDDATA 0x42110018
|
||||
#define QLA8044_FLASH_DIRECT_WINDOW 0x42110030
|
||||
#define QLA8044_FLASH_DIRECT_DATA(DATA) (0x42150000 | (0x0000FFFF&DATA))
|
||||
|
||||
/* Flash access regs */
|
||||
#define QLA8044_FLASH_LOCK 0x3850
|
||||
#define QLA8044_FLASH_UNLOCK 0x3854
|
||||
#define QLA8044_FLASH_LOCK_ID 0x3500
|
||||
|
||||
/* Driver Lock regs */
|
||||
#define QLA8044_DRV_LOCK 0x3868
|
||||
#define QLA8044_DRV_UNLOCK 0x386C
|
||||
#define QLA8044_DRV_LOCK_ID 0x3504
|
||||
#define QLA8044_DRV_LOCKRECOVERY 0x379C
|
||||
|
||||
/* IDC version */
|
||||
#define QLA8044_IDC_VER_MAJ_VALUE 0x1
|
||||
#define QLA8044_IDC_VER_MIN_VALUE 0x0
|
||||
|
||||
/* IDC Registers : Driver Coexistence Defines */
|
||||
#define QLA8044_CRB_IDC_VER_MAJOR 0x3780
|
||||
#define QLA8044_CRB_IDC_VER_MINOR 0x3798
|
||||
#define QLA8044_IDC_DRV_AUDIT 0x3794
|
||||
#define QLA8044_SRE_SHIM_CONTROL 0x0D200284
|
||||
#define QLA8044_PORT0_RXB_PAUSE_THRS 0x0B2003A4
|
||||
#define QLA8044_PORT1_RXB_PAUSE_THRS 0x0B2013A4
|
||||
#define QLA8044_PORT0_RXB_TC_MAX_CELL 0x0B200388
|
||||
#define QLA8044_PORT1_RXB_TC_MAX_CELL 0x0B201388
|
||||
#define QLA8044_PORT0_RXB_TC_STATS 0x0B20039C
|
||||
#define QLA8044_PORT1_RXB_TC_STATS 0x0B20139C
|
||||
#define QLA8044_PORT2_IFB_PAUSE_THRS 0x0B200704
|
||||
#define QLA8044_PORT3_IFB_PAUSE_THRS 0x0B201704
|
||||
|
||||
/* set value to pause threshold value */
|
||||
#define QLA8044_SET_PAUSE_VAL 0x0
|
||||
#define QLA8044_SET_TC_MAX_CELL_VAL 0x03FF03FF
|
||||
#define QLA8044_PEG_HALT_STATUS1 0x34A8
|
||||
#define QLA8044_PEG_HALT_STATUS2 0x34AC
|
||||
#define QLA8044_PEG_ALIVE_COUNTER 0x34B0 /* FW_HEARTBEAT */
|
||||
#define QLA8044_FW_CAPABILITIES 0x3528
|
||||
#define QLA8044_CRB_DRV_ACTIVE 0x3788 /* IDC_DRV_PRESENCE */
|
||||
#define QLA8044_CRB_DEV_STATE 0x3784 /* IDC_DEV_STATE */
|
||||
#define QLA8044_CRB_DRV_STATE 0x378C /* IDC_DRV_ACK */
|
||||
#define QLA8044_CRB_DRV_SCRATCH 0x3548
|
||||
#define QLA8044_CRB_DEV_PART_INFO1 0x37E0
|
||||
#define QLA8044_CRB_DEV_PART_INFO2 0x37E4
|
||||
#define QLA8044_FW_VER_MAJOR 0x3550
|
||||
#define QLA8044_FW_VER_MINOR 0x3554
|
||||
#define QLA8044_FW_VER_SUB 0x3558
|
||||
#define QLA8044_NPAR_STATE 0x359C
|
||||
#define QLA8044_FW_IMAGE_VALID 0x35FC
|
||||
#define QLA8044_CMDPEG_STATE 0x3650
|
||||
#define QLA8044_ASIC_TEMP 0x37B4
|
||||
#define QLA8044_FW_API 0x356C
|
||||
#define QLA8044_DRV_OP_MODE 0x3570
|
||||
#define QLA8044_CRB_WIN_BASE 0x3800
|
||||
#define QLA8044_CRB_WIN_FUNC(f) (QLA8044_CRB_WIN_BASE+((f)*4))
|
||||
#define QLA8044_SEM_LOCK_BASE 0x3840
|
||||
#define QLA8044_SEM_UNLOCK_BASE 0x3844
|
||||
#define QLA8044_SEM_LOCK_FUNC(f) (QLA8044_SEM_LOCK_BASE+((f)*8))
|
||||
#define QLA8044_SEM_UNLOCK_FUNC(f) (QLA8044_SEM_UNLOCK_BASE+((f)*8))
|
||||
#define QLA8044_LINK_STATE(f) (0x3698+((f) > 7 ? 4 : 0))
|
||||
#define QLA8044_LINK_SPEED(f) (0x36E0+(((f) >> 2) * 4))
|
||||
#define QLA8044_MAX_LINK_SPEED(f) (0x36F0+(((f) / 4) * 4))
|
||||
#define QLA8044_LINK_SPEED_FACTOR 10
|
||||
|
||||
/* FLASH API Defines */
|
||||
#define QLA8044_FLASH_MAX_WAIT_USEC 100
|
||||
#define QLA8044_FLASH_LOCK_TIMEOUT 10000
|
||||
#define QLA8044_FLASH_SECTOR_SIZE 65536
|
||||
#define QLA8044_DRV_LOCK_TIMEOUT 2000
|
||||
#define QLA8044_FLASH_SECTOR_ERASE_CMD 0xdeadbeef
|
||||
#define QLA8044_FLASH_WRITE_CMD 0xdacdacda
|
||||
#define QLA8044_FLASH_BUFFER_WRITE_CMD 0xcadcadca
|
||||
#define QLA8044_FLASH_READ_RETRY_COUNT 2000
|
||||
#define QLA8044_FLASH_STATUS_READY 0x6
|
||||
#define QLA8044_FLASH_BUFFER_WRITE_MIN 2
|
||||
#define QLA8044_FLASH_BUFFER_WRITE_MAX 64
|
||||
#define QLA8044_FLASH_STATUS_REG_POLL_DELAY 1
|
||||
#define QLA8044_ERASE_MODE 1
|
||||
#define QLA8044_WRITE_MODE 2
|
||||
#define QLA8044_DWORD_WRITE_MODE 3
|
||||
#define QLA8044_GLOBAL_RESET 0x38CC
|
||||
#define QLA8044_WILDCARD 0x38F0
|
||||
#define QLA8044_INFORMANT 0x38FC
|
||||
#define QLA8044_HOST_MBX_CTRL 0x3038
|
||||
#define QLA8044_FW_MBX_CTRL 0x303C
|
||||
#define QLA8044_BOOTLOADER_ADDR 0x355C
|
||||
#define QLA8044_BOOTLOADER_SIZE 0x3560
|
||||
#define QLA8044_FW_IMAGE_ADDR 0x3564
|
||||
#define QLA8044_MBX_INTR_ENABLE 0x1000
|
||||
#define QLA8044_MBX_INTR_MASK 0x1200
|
||||
|
||||
/* IDC Control Register bit defines */
|
||||
#define DONTRESET_BIT0 0x1
|
||||
#define GRACEFUL_RESET_BIT1 0x2
|
||||
|
||||
/* ISP8044 PEG_HALT_STATUS1 bits */
|
||||
#define QLA8044_HALT_STATUS_INFORMATIONAL (0x1 << 29)
|
||||
#define QLA8044_HALT_STATUS_FW_RESET (0x2 << 29)
|
||||
#define QLA8044_HALT_STATUS_UNRECOVERABLE (0x4 << 29)
|
||||
|
||||
/* Firmware image definitions */
|
||||
#define QLA8044_BOOTLOADER_FLASH_ADDR 0x10000
|
||||
#define QLA8044_BOOT_FROM_FLASH 0
|
||||
#define QLA8044_IDC_PARAM_ADDR 0x3e8020
|
||||
|
||||
/* FLASH related definitions */
|
||||
#define QLA8044_OPTROM_BURST_SIZE 0x100
|
||||
#define QLA8044_MAX_OPTROM_BURST_DWORDS (QLA8044_OPTROM_BURST_SIZE / 4)
|
||||
#define QLA8044_MIN_OPTROM_BURST_DWORDS 2
|
||||
#define QLA8044_SECTOR_SIZE (64 * 1024)
|
||||
|
||||
#define QLA8044_FLASH_SPI_CTL 0x4
|
||||
#define QLA8044_FLASH_FIRST_TEMP_VAL 0x00800000
|
||||
#define QLA8044_FLASH_SECOND_TEMP_VAL 0x00800001
|
||||
#define QLA8044_FLASH_FIRST_MS_PATTERN 0x43
|
||||
#define QLA8044_FLASH_SECOND_MS_PATTERN 0x7F
|
||||
#define QLA8044_FLASH_LAST_MS_PATTERN 0x7D
|
||||
#define QLA8044_FLASH_STATUS_WRITE_DEF_SIG 0xFD0100
|
||||
#define QLA8044_FLASH_SECOND_ERASE_MS_VAL 0x5
|
||||
#define QLA8044_FLASH_ERASE_SIG 0xFD0300
|
||||
#define QLA8044_FLASH_LAST_ERASE_MS_VAL 0x3D
|
||||
|
||||
/* Reset template definitions */
|
||||
#define QLA8044_MAX_RESET_SEQ_ENTRIES 16
|
||||
#define QLA8044_RESTART_TEMPLATE_SIZE 0x2000
|
||||
#define QLA8044_RESET_TEMPLATE_ADDR 0x4F0000
|
||||
#define QLA8044_RESET_SEQ_VERSION 0x0101
|
||||
|
||||
/* Reset template entry opcodes */
|
||||
#define OPCODE_NOP 0x0000
|
||||
#define OPCODE_WRITE_LIST 0x0001
|
||||
#define OPCODE_READ_WRITE_LIST 0x0002
|
||||
#define OPCODE_POLL_LIST 0x0004
|
||||
#define OPCODE_POLL_WRITE_LIST 0x0008
|
||||
#define OPCODE_READ_MODIFY_WRITE 0x0010
|
||||
#define OPCODE_SEQ_PAUSE 0x0020
|
||||
#define OPCODE_SEQ_END 0x0040
|
||||
#define OPCODE_TMPL_END 0x0080
|
||||
#define OPCODE_POLL_READ_LIST 0x0100
|
||||
|
||||
/* Template Header */
|
||||
#define RESET_TMPLT_HDR_SIGNATURE 0xCAFE
|
||||
#define QLA8044_IDC_DRV_CTRL 0x3790
|
||||
#define AF_8044_NO_FW_DUMP 27 /* 0x08000000 */
|
||||
|
||||
#define MINIDUMP_SIZE_36K 36864
|
||||
|
||||
struct qla8044_reset_template_hdr {
|
||||
uint16_t version;
|
||||
uint16_t signature;
|
||||
uint16_t size;
|
||||
uint16_t entries;
|
||||
uint16_t hdr_size;
|
||||
uint16_t checksum;
|
||||
uint16_t init_seq_offset;
|
||||
uint16_t start_seq_offset;
|
||||
} __packed;
|
||||
|
||||
/* Common Entry Header. */
|
||||
struct qla8044_reset_entry_hdr {
|
||||
uint16_t cmd;
|
||||
uint16_t size;
|
||||
uint16_t count;
|
||||
uint16_t delay;
|
||||
} __packed;
|
||||
|
||||
/* Generic poll entry type. */
|
||||
struct qla8044_poll {
|
||||
uint32_t test_mask;
|
||||
uint32_t test_value;
|
||||
} __packed;
|
||||
|
||||
/* Read modify write entry type. */
|
||||
struct qla8044_rmw {
|
||||
uint32_t test_mask;
|
||||
uint32_t xor_value;
|
||||
uint32_t or_value;
|
||||
uint8_t shl;
|
||||
uint8_t shr;
|
||||
uint8_t index_a;
|
||||
uint8_t rsvd;
|
||||
} __packed;
|
||||
|
||||
/* Generic Entry Item with 2 DWords. */
|
||||
struct qla8044_entry {
|
||||
uint32_t arg1;
|
||||
uint32_t arg2;
|
||||
} __packed;
|
||||
|
||||
/* Generic Entry Item with 4 DWords.*/
|
||||
struct qla8044_quad_entry {
|
||||
uint32_t dr_addr;
|
||||
uint32_t dr_value;
|
||||
uint32_t ar_addr;
|
||||
uint32_t ar_value;
|
||||
} __packed;
|
||||
|
||||
struct qla8044_reset_template {
|
||||
int seq_index;
|
||||
int seq_error;
|
||||
int array_index;
|
||||
uint32_t array[QLA8044_MAX_RESET_SEQ_ENTRIES];
|
||||
uint8_t *buff;
|
||||
uint8_t *stop_offset;
|
||||
uint8_t *start_offset;
|
||||
uint8_t *init_offset;
|
||||
struct qla8044_reset_template_hdr *hdr;
|
||||
uint8_t seq_end;
|
||||
uint8_t template_end;
|
||||
};
|
||||
|
||||
/* Driver_code is for driver to write some info about the entry
|
||||
* currently not used.
|
||||
*/
|
||||
struct qla8044_minidump_entry_hdr {
|
||||
uint32_t entry_type;
|
||||
uint32_t entry_size;
|
||||
uint32_t entry_capture_size;
|
||||
struct {
|
||||
uint8_t entry_capture_mask;
|
||||
uint8_t entry_code;
|
||||
uint8_t driver_code;
|
||||
uint8_t driver_flags;
|
||||
} d_ctrl;
|
||||
} __packed;
|
||||
|
||||
/* Read CRB entry header */
|
||||
struct qla8044_minidump_entry_crb {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t addr;
|
||||
struct {
|
||||
uint8_t addr_stride;
|
||||
uint8_t state_index_a;
|
||||
uint16_t poll_timeout;
|
||||
} crb_strd;
|
||||
uint32_t data_size;
|
||||
uint32_t op_count;
|
||||
|
||||
struct {
|
||||
uint8_t opcode;
|
||||
uint8_t state_index_v;
|
||||
uint8_t shl;
|
||||
uint8_t shr;
|
||||
} crb_ctrl;
|
||||
|
||||
uint32_t value_1;
|
||||
uint32_t value_2;
|
||||
uint32_t value_3;
|
||||
} __packed;
|
||||
|
||||
struct qla8044_minidump_entry_cache {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t tag_reg_addr;
|
||||
struct {
|
||||
uint16_t tag_value_stride;
|
||||
uint16_t init_tag_value;
|
||||
} addr_ctrl;
|
||||
uint32_t data_size;
|
||||
uint32_t op_count;
|
||||
uint32_t control_addr;
|
||||
struct {
|
||||
uint16_t write_value;
|
||||
uint8_t poll_mask;
|
||||
uint8_t poll_wait;
|
||||
} cache_ctrl;
|
||||
uint32_t read_addr;
|
||||
struct {
|
||||
uint8_t read_addr_stride;
|
||||
uint8_t read_addr_cnt;
|
||||
uint16_t rsvd_1;
|
||||
} read_ctrl;
|
||||
} __packed;
|
||||
|
||||
/* Read OCM */
|
||||
struct qla8044_minidump_entry_rdocm {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t rsvd_0;
|
||||
uint32_t rsvd_1;
|
||||
uint32_t data_size;
|
||||
uint32_t op_count;
|
||||
uint32_t rsvd_2;
|
||||
uint32_t rsvd_3;
|
||||
uint32_t read_addr;
|
||||
uint32_t read_addr_stride;
|
||||
} __packed;
|
||||
|
||||
/* Read Memory */
|
||||
struct qla8044_minidump_entry_rdmem {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t rsvd[6];
|
||||
uint32_t read_addr;
|
||||
uint32_t read_data_size;
|
||||
};
|
||||
|
||||
/* Read Memory: For Pex-DMA */
|
||||
struct qla8044_minidump_entry_rdmem_pex_dma {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t desc_card_addr;
|
||||
uint16_t dma_desc_cmd;
|
||||
uint8_t rsvd[2];
|
||||
uint32_t start_dma_cmd;
|
||||
uint8_t rsvd2[12];
|
||||
uint32_t read_addr;
|
||||
uint32_t read_data_size;
|
||||
} __packed;
|
||||
|
||||
/* Read ROM */
|
||||
struct qla8044_minidump_entry_rdrom {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t rsvd[6];
|
||||
uint32_t read_addr;
|
||||
uint32_t read_data_size;
|
||||
} __packed;
|
||||
|
||||
/* Mux entry */
|
||||
struct qla8044_minidump_entry_mux {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t select_addr;
|
||||
uint32_t rsvd_0;
|
||||
uint32_t data_size;
|
||||
uint32_t op_count;
|
||||
uint32_t select_value;
|
||||
uint32_t select_value_stride;
|
||||
uint32_t read_addr;
|
||||
uint32_t rsvd_1;
|
||||
} __packed;
|
||||
|
||||
/* Queue entry */
|
||||
struct qla8044_minidump_entry_queue {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t select_addr;
|
||||
struct {
|
||||
uint16_t queue_id_stride;
|
||||
uint16_t rsvd_0;
|
||||
} q_strd;
|
||||
uint32_t data_size;
|
||||
uint32_t op_count;
|
||||
uint32_t rsvd_1;
|
||||
uint32_t rsvd_2;
|
||||
uint32_t read_addr;
|
||||
struct {
|
||||
uint8_t read_addr_stride;
|
||||
uint8_t read_addr_cnt;
|
||||
uint16_t rsvd_3;
|
||||
} rd_strd;
|
||||
} __packed;
|
||||
|
||||
/* POLLRD Entry */
|
||||
struct qla8044_minidump_entry_pollrd {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t select_addr;
|
||||
uint32_t read_addr;
|
||||
uint32_t select_value;
|
||||
uint16_t select_value_stride;
|
||||
uint16_t op_count;
|
||||
uint32_t poll_wait;
|
||||
uint32_t poll_mask;
|
||||
uint32_t data_size;
|
||||
uint32_t rsvd_1;
|
||||
} __packed;
|
||||
|
||||
/* RDMUX2 Entry */
|
||||
struct qla8044_minidump_entry_rdmux2 {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t select_addr_1;
|
||||
uint32_t select_addr_2;
|
||||
uint32_t select_value_1;
|
||||
uint32_t select_value_2;
|
||||
uint32_t op_count;
|
||||
uint32_t select_value_mask;
|
||||
uint32_t read_addr;
|
||||
uint8_t select_value_stride;
|
||||
uint8_t data_size;
|
||||
uint8_t rsvd[2];
|
||||
} __packed;
|
||||
|
||||
/* POLLRDMWR Entry */
|
||||
struct qla8044_minidump_entry_pollrdmwr {
|
||||
struct qla8044_minidump_entry_hdr h;
|
||||
uint32_t addr_1;
|
||||
uint32_t addr_2;
|
||||
uint32_t value_1;
|
||||
uint32_t value_2;
|
||||
uint32_t poll_wait;
|
||||
uint32_t poll_mask;
|
||||
uint32_t modify_mask;
|
||||
uint32_t data_size;
|
||||
} __packed;
|
||||
|
||||
/* IDC additional information */
|
||||
struct qla8044_idc_information {
|
||||
uint32_t request_desc; /* IDC request descriptor */
|
||||
uint32_t info1; /* IDC additional info */
|
||||
uint32_t info2; /* IDC additional info */
|
||||
uint32_t info3; /* IDC additional info */
|
||||
} __packed;
|
||||
|
||||
enum qla_regs {
|
||||
QLA8044_PEG_HALT_STATUS1_INDEX = 0,
|
||||
QLA8044_PEG_HALT_STATUS2_INDEX,
|
||||
QLA8044_PEG_ALIVE_COUNTER_INDEX,
|
||||
QLA8044_CRB_DRV_ACTIVE_INDEX,
|
||||
QLA8044_CRB_DEV_STATE_INDEX,
|
||||
QLA8044_CRB_DRV_STATE_INDEX,
|
||||
QLA8044_CRB_DRV_SCRATCH_INDEX,
|
||||
QLA8044_CRB_DEV_PART_INFO_INDEX,
|
||||
QLA8044_CRB_DRV_IDC_VERSION_INDEX,
|
||||
QLA8044_FW_VERSION_MAJOR_INDEX,
|
||||
QLA8044_FW_VERSION_MINOR_INDEX,
|
||||
QLA8044_FW_VERSION_SUB_INDEX,
|
||||
QLA8044_CRB_CMDPEG_STATE_INDEX,
|
||||
QLA8044_CRB_TEMP_STATE_INDEX,
|
||||
} __packed;
|
||||
|
||||
#define CRB_REG_INDEX_MAX 14
|
||||
#define CRB_CMDPEG_CHECK_RETRY_COUNT 60
|
||||
#define CRB_CMDPEG_CHECK_DELAY 500
|
||||
|
||||
static const uint32_t qla8044_reg_tbl[] = {
|
||||
QLA8044_PEG_HALT_STATUS1,
|
||||
QLA8044_PEG_HALT_STATUS2,
|
||||
QLA8044_PEG_ALIVE_COUNTER,
|
||||
QLA8044_CRB_DRV_ACTIVE,
|
||||
QLA8044_CRB_DEV_STATE,
|
||||
QLA8044_CRB_DRV_STATE,
|
||||
QLA8044_CRB_DRV_SCRATCH,
|
||||
QLA8044_CRB_DEV_PART_INFO1,
|
||||
QLA8044_CRB_IDC_VER_MAJOR,
|
||||
QLA8044_FW_VER_MAJOR,
|
||||
QLA8044_FW_VER_MINOR,
|
||||
QLA8044_FW_VER_SUB,
|
||||
QLA8044_CMDPEG_STATE,
|
||||
QLA8044_ASIC_TEMP,
|
||||
};
|
||||
|
||||
/* MiniDump Structures */
|
||||
|
||||
/* Driver_code is for driver to write some info about the entry
|
||||
* currently not used.
|
||||
*/
|
||||
#define QLA8044_SS_OCM_WNDREG_INDEX 3
|
||||
#define QLA8044_DBG_STATE_ARRAY_LEN 16
|
||||
#define QLA8044_DBG_CAP_SIZE_ARRAY_LEN 8
|
||||
#define QLA8044_DBG_RSVD_ARRAY_LEN 8
|
||||
#define QLA8044_DBG_OCM_WNDREG_ARRAY_LEN 16
|
||||
#define QLA8044_SS_PCI_INDEX 0
|
||||
|
||||
struct qla8044_minidump_template_hdr {
|
||||
uint32_t entry_type;
|
||||
uint32_t first_entry_offset;
|
||||
uint32_t size_of_template;
|
||||
uint32_t capture_debug_level;
|
||||
uint32_t num_of_entries;
|
||||
uint32_t version;
|
||||
uint32_t driver_timestamp;
|
||||
uint32_t checksum;
|
||||
|
||||
uint32_t driver_capture_mask;
|
||||
uint32_t driver_info_word2;
|
||||
uint32_t driver_info_word3;
|
||||
uint32_t driver_info_word4;
|
||||
|
||||
uint32_t saved_state_array[QLA8044_DBG_STATE_ARRAY_LEN];
|
||||
uint32_t capture_size_array[QLA8044_DBG_CAP_SIZE_ARRAY_LEN];
|
||||
uint32_t ocm_window_reg[QLA8044_DBG_OCM_WNDREG_ARRAY_LEN];
|
||||
};
|
||||
|
||||
struct qla8044_pex_dma_descriptor {
|
||||
struct {
|
||||
uint32_t read_data_size; /* 0-23: size, 24-31: rsvd */
|
||||
uint8_t rsvd[2];
|
||||
uint16_t dma_desc_cmd;
|
||||
} cmd;
|
||||
uint64_t src_addr;
|
||||
uint64_t dma_bus_addr; /*0-3: desc-cmd, 4-7: pci-func, 8-15: desc-cmd*/
|
||||
uint8_t rsvd[24];
|
||||
} __packed;
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user