aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc.h43
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c164
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h37
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c74
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h19
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c1012
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c575
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h65
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c265
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c33
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c391
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c25
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c470
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h6
16 files changed, 2076 insertions, 1113 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 38ffa8d6e62..087c44539a1 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -121,7 +121,9 @@ struct lpfc_stats {
uint32_t elsRcvLOGO;
uint32_t elsRcvPRLO;
uint32_t elsRcvPRLI;
- uint32_t elsRcvRRQ;
+ uint32_t elsRcvLIRR;
+ uint32_t elsRcvRPS;
+ uint32_t elsRcvRPL;
uint32_t elsXmitFLOGI;
uint32_t elsXmitPLOGI;
uint32_t elsXmitPRLI;
@@ -167,33 +169,35 @@ struct lpfc_sysfs_mbox {
};
struct lpfc_hba {
- struct list_head hba_list; /* List of hbas/ports */
struct lpfc_sli sli;
struct lpfc_sli2_slim *slim2p;
dma_addr_t slim2p_mapping;
uint16_t pci_cfg_value;
struct semaphore hba_can_block;
- uint32_t hba_state;
-
-#define LPFC_INIT_START 1 /* Initial state after board reset */
-#define LPFC_INIT_MBX_CMDS 2 /* Initialize HBA with mbox commands */
-#define LPFC_LINK_DOWN 3 /* HBA initialized, link is down */
-#define LPFC_LINK_UP 4 /* Link is up - issue READ_LA */
-#define LPFC_LOCAL_CFG_LINK 5 /* local NPORT Id configured */
-#define LPFC_FLOGI 6 /* FLOGI sent to Fabric */
-#define LPFC_FABRIC_CFG_LINK 7 /* Fabric assigned NPORT Id
+ int32_t hba_state;
+
+#define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */
+#define LPFC_WARM_START 1 /* HBA state after selective reset */
+#define LPFC_INIT_START 2 /* Initial state after board reset */
+#define LPFC_INIT_MBX_CMDS 3 /* Initialize HBA with mbox commands */
+#define LPFC_LINK_DOWN 4 /* HBA initialized, link is down */
+#define LPFC_LINK_UP 5 /* Link is up - issue READ_LA */
+#define LPFC_LOCAL_CFG_LINK 6 /* local NPORT Id configured */
+#define LPFC_FLOGI 7 /* FLOGI sent to Fabric */
+#define LPFC_FABRIC_CFG_LINK 8 /* Fabric assigned NPORT Id
configured */
-#define LPFC_NS_REG 8 /* Register with NameServer */
-#define LPFC_NS_QRY 9 /* Query NameServer for NPort ID list */
-#define LPFC_BUILD_DISC_LIST 10 /* Build ADISC and PLOGI lists for
+#define LPFC_NS_REG 9 /* Register with NameServer */
+#define LPFC_NS_QRY 10 /* Query NameServer for NPort ID list */
+#define LPFC_BUILD_DISC_LIST 11 /* Build ADISC and PLOGI lists for
* device authentication / discovery */
-#define LPFC_DISC_AUTH 11 /* Processing ADISC list */
-#define LPFC_CLEAR_LA 12 /* authentication cmplt - issue
+#define LPFC_DISC_AUTH 12 /* Processing ADISC list */
+#define LPFC_CLEAR_LA 13 /* authentication cmplt - issue
CLEAR_LA */
#define LPFC_HBA_READY 32
-#define LPFC_HBA_ERROR 0xff
+#define LPFC_HBA_ERROR -1
+ int32_t stopped; /* HBA has not been restarted since last ERATT */
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
uint32_t fc_eventTag; /* event tag for link attention */
@@ -245,6 +249,7 @@ struct lpfc_hba {
#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */
#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
+#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
uint32_t fc_topology; /* link topology, from LINK INIT */
@@ -289,8 +294,8 @@ struct lpfc_hba {
uint32_t cfg_link_speed;
uint32_t cfg_cr_delay;
uint32_t cfg_cr_count;
+ uint32_t cfg_multi_ring_support;
uint32_t cfg_fdmi_on;
- uint32_t cfg_fcp_bind_method;
uint32_t cfg_discovery_threads;
uint32_t cfg_max_luns;
uint32_t cfg_poll;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 5625a8c2a8f..b62a72dfab2 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -79,7 +79,7 @@ static ssize_t
lpfc_serialnum_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber);
}
@@ -87,7 +87,7 @@ static ssize_t
lpfc_modeldesc_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc);
}
@@ -95,7 +95,7 @@ static ssize_t
lpfc_modelname_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName);
}
@@ -103,7 +103,7 @@ static ssize_t
lpfc_programtype_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType);
}
@@ -111,7 +111,7 @@ static ssize_t
lpfc_portnum_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port);
}
@@ -119,7 +119,7 @@ static ssize_t
lpfc_fwrev_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
char fwrev[32];
lpfc_decode_firmware_rev(phba, fwrev, 1);
return snprintf(buf, PAGE_SIZE, "%s\n",fwrev);
@@ -130,7 +130,7 @@ lpfc_hdw_show(struct class_device *cdev, char *buf)
{
char hdw[9];
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
lpfc_vpd_t *vp = &phba->vpd;
lpfc_jedec_to_ascii(vp->rev.biuRev, hdw);
return snprintf(buf, PAGE_SIZE, "%s\n", hdw);
@@ -139,16 +139,18 @@ static ssize_t
lpfc_option_rom_version_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);
}
static ssize_t
lpfc_state_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
int len = 0;
switch (phba->hba_state) {
+ case LPFC_STATE_UNKNOWN:
+ case LPFC_WARM_START:
case LPFC_INIT_START:
case LPFC_INIT_MBX_CMDS:
case LPFC_LINK_DOWN:
@@ -194,7 +196,7 @@ static ssize_t
lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%d\n", phba->fc_map_cnt +
phba->fc_unmap_cnt);
}
@@ -203,7 +205,7 @@ lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf)
static int
lpfc_issue_lip(struct Scsi_Host *host)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata;
LPFC_MBOXQ_t *pmboxq;
int mbxstatus = MBXERR_ERROR;
@@ -235,7 +237,7 @@ static ssize_t
lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}
@@ -243,7 +245,7 @@ static ssize_t
lpfc_board_online_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
if (phba->fc_flag & FC_OFFLINE_MODE)
return snprintf(buf, PAGE_SIZE, "0\n");
@@ -256,7 +258,7 @@ lpfc_board_online_store(struct class_device *cdev, const char *buf,
size_t count)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
struct completion online_compl;
int val=0, status=0;
@@ -279,10 +281,62 @@ lpfc_board_online_store(struct class_device *cdev, const char *buf,
}
static ssize_t
+lpfc_board_mode_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ char * state;
+
+ if (phba->hba_state == LPFC_HBA_ERROR)
+ state = "error";
+ else if (phba->hba_state == LPFC_WARM_START)
+ state = "warm start";
+ else if (phba->hba_state == LPFC_INIT_START)
+ state = "offline";
+ else
+ state = "online";
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", state);
+}
+
+static ssize_t
+lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct completion online_compl;
+ int status=0;
+
+ init_completion(&online_compl);
+
+ if(strncmp(buf, "online", sizeof("online") - 1) == 0)
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_ONLINE);
+ else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_OFFLINE);
+ else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_WARM_START);
+ else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_KILL);
+ else
+ return -EINVAL;
+
+ wait_for_completion(&online_compl);
+
+ if (!status)
+ return strlen(buf);
+ else
+ return -EIO;
+}
+
+static ssize_t
lpfc_poll_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
return snprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll);
}
@@ -292,7 +346,7 @@ lpfc_poll_store(struct class_device *cdev, const char *buf,
size_t count)
{
struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
uint32_t creg_val;
uint32_t old_val;
int val=0;
@@ -349,7 +403,7 @@ static ssize_t \
lpfc_##attr##_show(struct class_device *cdev, char *buf) \
{ \
struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
int val = 0;\
val = phba->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%d\n",\
@@ -361,7 +415,7 @@ static ssize_t \
lpfc_##attr##_show(struct class_device *cdev, char *buf) \
{ \
struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
int val = 0;\
val = phba->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%#x\n",\
@@ -404,7 +458,7 @@ static ssize_t \
lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \
{ \
struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
int val=0;\
if (!isdigit(buf[0]))\
return -EINVAL;\
@@ -480,6 +534,8 @@ static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
NULL);
static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
lpfc_board_online_show, lpfc_board_online_store);
+static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
+ lpfc_board_mode_show, lpfc_board_mode_store);
static int lpfc_poll = 0;
module_param(lpfc_poll, int, 0);
@@ -520,6 +576,16 @@ LPFC_ATTR_R(lun_queue_depth, 30, 1, 128,
"Max number of FCP commands we can queue to a specific LUN");
/*
+# hba_queue_depth: This parameter is used to limit the number of outstanding
+# commands per lpfc HBA. Value range is [32,8192]. If this parameter
+# value is greater than the maximum number of exchanges supported by the HBA,
+# then maximum number of exchanges supported by the HBA is used to determine
+# the hba_queue_depth.
+*/
+LPFC_ATTR_R(hba_queue_depth, 8192, 32, 8192,
+ "Max number of FCP commands we can queue to a lpfc HBA");
+
+/*
# Some disk devices have a "select ID" or "select Target" capability.
# From a protocol standpoint "select ID" usually means select the
# Fibre channel "ALPA". In the FC-AL Profile there is an "informative
@@ -550,6 +616,7 @@ LPFC_ATTR_RW(nodev_tmo, 30, 0, 255,
/*
# lpfc_topology: link topology for init link
# 0x0 = attempt loop mode then point-to-point
+# 0x01 = internal loopback mode
# 0x02 = attempt point-to-point mode only
# 0x04 = attempt loop mode only
# 0x06 = attempt point-to-point mode then loop
@@ -557,7 +624,7 @@ LPFC_ATTR_RW(nodev_tmo, 30, 0, 255,
# Set loop mode if you want to run as an NL_Port. Value range is [0,0x6].
# Default value is 0.
*/
-LPFC_ATTR_R(topology, 0, 0, 6, "Select Fibre Channel topology");
+LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
/*
# lpfc_link_speed: Link speed selection for initializing the Fibre Channel
@@ -597,13 +664,21 @@ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support");
# is 0. Default value of cr_count is 1. The cr_count feature is disabled if
# cr_delay is set to 0.
*/
-LPFC_ATTR_RW(cr_delay, 0, 0, 63, "A count of milliseconds after which an"
+LPFC_ATTR_RW(cr_delay, 0, 0, 63, "A count of milliseconds after which an "
"interrupt response is generated");
-LPFC_ATTR_RW(cr_count, 1, 1, 255, "A count of I/O completions after which an"
+LPFC_ATTR_RW(cr_count, 1, 1, 255, "A count of I/O completions after which an "
"interrupt response is generated");
/*
+# lpfc_multi_ring_support: Determines how many rings to spread available
+# cmd/rsp IOCB entries across.
+# Value range is [1,2]. Default value is 1.
+*/
+LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary "
+ "SLI rings to spread IOCB entries across");
+
+/*
# lpfc_fdmi_on: controls FDMI support.
# 0 = no FDMI support
# 1 = support FDMI without attribute of hostname
@@ -616,7 +691,7 @@ LPFC_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support");
# Specifies the maximum number of ELS cmds we can have outstanding (for
# discovery). Value range is [1,64]. Default value = 32.
*/
-LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands"
+LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
"during discovery");
/*
@@ -649,6 +724,7 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_drvr_version,
&class_device_attr_lpfc_log_verbose,
&class_device_attr_lpfc_lun_queue_depth,
+ &class_device_attr_lpfc_hba_queue_depth,
&class_device_attr_lpfc_nodev_tmo,
&class_device_attr_lpfc_fcp_class,
&class_device_attr_lpfc_use_adisc,
@@ -658,11 +734,13 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_link_speed,
&class_device_attr_lpfc_cr_delay,
&class_device_attr_lpfc_cr_count,
+ &class_device_attr_lpfc_multi_ring_support,
&class_device_attr_lpfc_fdmi_on,
&class_device_attr_lpfc_max_luns,
&class_device_attr_nport_evt_cnt,
&class_device_attr_management_version,
&class_device_attr_board_online,
+ &class_device_attr_board_mode,
&class_device_attr_lpfc_poll,
&class_device_attr_lpfc_poll_tmo,
NULL,
@@ -674,7 +752,7 @@ sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
size_t buf_off;
struct Scsi_Host *host = class_to_shost(container_of(kobj,
struct class_device, kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
if ((off + count) > FF_REG_AREA_SIZE)
return -ERANGE;
@@ -707,7 +785,7 @@ sysfs_ctlreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
uint32_t * tmp_ptr;
struct Scsi_Host *host = class_to_shost(container_of(kobj,
struct class_device, kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
if (off > FF_REG_AREA_SIZE)
return -ERANGE;
@@ -762,7 +840,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct Scsi_Host * host =
class_to_shost(container_of(kobj, struct class_device, kobj));
- struct lpfc_hba * phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba * phba = (struct lpfc_hba*)host->hostdata;
struct lpfcMboxq * mbox = NULL;
if ((count + off) > MAILBOX_CMD_SIZE)
@@ -778,7 +856,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
return -ENOMEM;
-
+ memset(mbox, 0, sizeof (LPFC_MBOXQ_t));
}
spin_lock_irq(host->host_lock);
@@ -815,7 +893,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
struct Scsi_Host *host =
class_to_shost(container_of(kobj, struct class_device,
kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
int rc;
if (off > sizeof(MAILBOX_t))
@@ -872,8 +950,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
case MBX_DUMP_MEMORY:
case MBX_DOWN_LOAD:
case MBX_UPDATE_CFG:
+ case MBX_KILL_BOARD:
case MBX_LOAD_AREA:
case MBX_LOAD_EXP_ROM:
+ case MBX_BEACON:
+ case MBX_DEL_LD_ENTRY:
break;
case MBX_READ_SPARM64:
case MBX_READ_LA:
@@ -990,7 +1071,7 @@ lpfc_free_sysfs_attr(struct lpfc_hba *phba)
static void
lpfc_get_host_port_id(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
/* note: fc_myDID already in cpu endianness */
fc_host_port_id(shost) = phba->fc_myDID;
}
@@ -998,7 +1079,7 @@ lpfc_get_host_port_id(struct Scsi_Host *shost)
static void
lpfc_get_host_port_type(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
spin_lock_irq(shost->host_lock);
@@ -1023,7 +1104,7 @@ lpfc_get_host_port_type(struct Scsi_Host *shost)
static void
lpfc_get_host_port_state(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
spin_lock_irq(shost->host_lock);
@@ -1031,6 +1112,8 @@ lpfc_get_host_port_state(struct Scsi_Host *shost)
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
else {
switch (phba->hba_state) {
+ case LPFC_STATE_UNKNOWN:
+ case LPFC_WARM_START:
case LPFC_INIT_START:
case LPFC_INIT_MBX_CMDS:
case LPFC_LINK_DOWN:
@@ -1064,7 +1147,7 @@ lpfc_get_host_port_state(struct Scsi_Host *shost)
static void
lpfc_get_host_speed(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
spin_lock_irq(shost->host_lock);
@@ -1091,7 +1174,7 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
static void
lpfc_get_host_fabric_name (struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
u64 node_name;
spin_lock_irq(shost->host_lock);
@@ -1113,7 +1196,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
static struct fc_host_statistics *
lpfc_get_stats(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
struct lpfc_sli *psli = &phba->sli;
struct fc_host_statistics *hs = &phba->link_stats;
LPFC_MBOXQ_t *pmboxq;
@@ -1203,7 +1286,7 @@ static void
lpfc_get_starget_port_id(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
uint32_t did = -1;
struct lpfc_nodelist *ndlp = NULL;
@@ -1224,7 +1307,7 @@ static void
lpfc_get_starget_node_name(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
u64 node_name = 0;
struct lpfc_nodelist *ndlp = NULL;
@@ -1245,7 +1328,7 @@ static void
lpfc_get_starget_port_name(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0];
+ struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
u64 port_name = 0;
struct lpfc_nodelist *ndlp = NULL;
@@ -1366,6 +1449,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_log_verbose_init(phba, lpfc_log_verbose);
lpfc_cr_delay_init(phba, lpfc_cr_delay);
lpfc_cr_count_init(phba, lpfc_cr_count);
+ lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support);
lpfc_lun_queue_depth_init(phba, lpfc_lun_queue_depth);
lpfc_fcp_class_init(phba, lpfc_fcp_class);
lpfc_use_adisc_init(phba, lpfc_use_adisc);
@@ -1411,5 +1495,9 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
default:
phba->cfg_hba_queue_depth = LPFC_DFT_HBA_Q_DEPTH;
}
+
+ if (phba->cfg_hba_queue_depth > lpfc_hba_queue_depth)
+ lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index f1e708946e6..fad607b2e6f 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -26,6 +26,7 @@ void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_set_slim(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *,
uint32_t);
@@ -42,9 +43,6 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_nlp_plogi(struct lpfc_hba *, struct lpfc_nodelist *);
-int lpfc_nlp_adisc(struct lpfc_hba *, struct lpfc_nodelist *);
-int lpfc_nlp_unmapped(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int);
void lpfc_set_disctmo(struct lpfc_hba *);
int lpfc_can_disctmo(struct lpfc_hba *);
@@ -54,12 +52,10 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
-struct lpfc_nodelist *lpfc_setup_rscn_node(struct lpfc_hba *, uint32_t);
void lpfc_disc_list_loopmap(struct lpfc_hba *);
void lpfc_disc_start(struct lpfc_hba *);
void lpfc_disc_flush_list(struct lpfc_hba *);
void lpfc_disc_timeout(unsigned long);
-void lpfc_scan_timeout(unsigned long);
struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
@@ -68,19 +64,13 @@ int lpfc_do_work(void *);
int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
uint32_t);
-uint32_t lpfc_cmpl_prli_reglogin_issue(struct lpfc_hba *,
- struct lpfc_nodelist *, void *,
- uint32_t);
-uint32_t lpfc_cmpl_plogi_prli_issue(struct lpfc_hba *, struct lpfc_nodelist *,
- void *, uint32_t);
-
int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
struct serv_parm *, uint32_t);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp,
int);
int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_hba *);
-int lpfc_issue_els_plogi(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t);
int lpfc_issue_els_prli(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_adisc(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_logo(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
@@ -94,6 +84,7 @@ int lpfc_els_rsp_adisc_acc(struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_nodelist *);
int lpfc_els_rsp_prli_acc(struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_nodelist *);
+void lpfc_cancel_retry_delay_tmo(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_els_retry_delay(unsigned long);
void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
@@ -117,18 +108,15 @@ void lpfc_fdmi_tmo_handler(struct lpfc_hba *);
int lpfc_config_port_prep(struct lpfc_hba *);
int lpfc_config_port_post(struct lpfc_hba *);
int lpfc_hba_down_prep(struct lpfc_hba *);
+int lpfc_hba_down_post(struct lpfc_hba *);
void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
-uint8_t *lpfc_get_lpfchba_info(struct lpfc_hba *, uint8_t *);
-int lpfc_fcp_abort(struct lpfc_hba *, int, int, int);
int lpfc_online(struct lpfc_hba *);
int lpfc_offline(struct lpfc_hba *);
-
int lpfc_sli_setup(struct lpfc_hba *);
int lpfc_sli_queue_setup(struct lpfc_hba *);
-void lpfc_slim_access(struct lpfc_hba *);
void lpfc_handle_eratt(struct lpfc_hba *);
void lpfc_handle_latt(struct lpfc_hba *);
@@ -137,6 +125,7 @@ irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *);
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
@@ -149,6 +138,12 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
+
+void lpfc_reset_barrier(struct lpfc_hba * phba);
+int lpfc_sli_brdready(struct lpfc_hba *, uint32_t);
+int lpfc_sli_brdkill(struct lpfc_hba *);
+int lpfc_sli_brdreset(struct lpfc_hba *);
+int lpfc_sli_brdrestart(struct lpfc_hba *);
int lpfc_sli_hba_setup(struct lpfc_hba *);
int lpfc_sli_hba_down(struct lpfc_hba *);
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
@@ -174,12 +169,10 @@ int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
void lpfc_mbox_timeout(unsigned long);
void lpfc_mbox_timeout_handler(struct lpfc_hba *);
-void lpfc_map_fcp_cmnd_to_bpl(struct lpfc_hba *, struct lpfc_scsi_buf *);
-void lpfc_free_scsi_cmd(struct lpfc_scsi_buf *);
-uint32_t lpfc_os_timeout_transform(struct lpfc_hba *, uint32_t);
-struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order,
- uint32_t did);
+struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t, uint32_t);
+struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, uint32_t,
+ struct lpfc_name *);
int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
uint32_t timeout);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 7f427f9c468..b65ee57af53 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -260,8 +260,10 @@ lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp,
icmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL;
icmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP;
- if (!tmo)
- tmo = (2 * phba->fc_ratov) + 1;
+ if (!tmo) {
+ /* FC spec states we need 3 * ratov for CT requests */
+ tmo = (3 * phba->fc_ratov);
+ }
icmd->ulpTimeout = tmo;
icmd->ulpBdeCount = 1;
icmd->ulpLe = 1;
@@ -321,6 +323,7 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
struct lpfc_sli_ct_request *Response =
(struct lpfc_sli_ct_request *) mp->virt;
struct lpfc_nodelist *ndlp = NULL;
+ struct lpfc_nodelist *next_ndlp;
struct lpfc_dmabuf *mlast, *next_mp;
uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
uint32_t Did;
@@ -389,8 +392,36 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
nsout1:
list_del(&head);
- /* Here we are finished in the case RSCN */
+ /*
+ * The driver has cycled through all Nports in the RSCN payload.
+ * Complete the handling by cleaning up and marking the
+ * current driver state.
+ */
if (phba->hba_state == LPFC_HBA_READY) {
+
+ /*
+ * Switch ports that connect a loop of multiple targets need
+ * special consideration. The driver wants to unregister the
+ * rpi only on the target that was pulled from the loop. On
+ * RSCN, the driver wants to rediscover an NPort only if the
+ * driver flagged it as NLP_NPR_2B_DISC. Provided adisc is
+ * not enabled and the NPort is not capable of retransmissions
+ * (FC Tape) prevent timing races with the scsi error handler by
+ * unregistering the Nport's RPI. This action causes all
+ * outstanding IO to flush back to the midlayer.
+ */
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
+ nlp_listp) {
+ if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+ (lpfc_rscn_payload_check(phba, ndlp->nlp_DID))) {
+ if ((phba->cfg_use_adisc == 0) &&
+ !(ndlp->nlp_fcp_info &
+ NLP_FCP_2_DEVICE)) {
+ lpfc_unreg_rpi(phba, ndlp);
+ ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+ }
+ }
+ }
lpfc_els_flush_rscn(phba);
spin_lock_irq(phba->host->host_lock);
phba->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */
@@ -449,6 +480,11 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d:0239 NameServer Rsp "
+ "Data: x%x\n",
+ phba->brd_no,
+ phba->fc_flag);
lpfc_ns_rsp(phba, outp,
(uint32_t) (irsp->un.genreq64.bdl.bdeSize));
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
@@ -978,19 +1014,19 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_SPEED);
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
- if (FC_JEDEC_ID(vp->rev.biuRev) == VIPER_JEDEC_ID)
+
+ ae->un.SupportSpeed = 0;
+ if (phba->lmt & LMT_10Gb)
ae->un.SupportSpeed = HBA_PORTSPEED_10GBIT;
- else if (FC_JEDEC_ID(vp->rev.biuRev) == HELIOS_JEDEC_ID)
- ae->un.SupportSpe