Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (209 commits)
  [SCSI] fix oops during scsi scanning
  [SCSI] libsrp: fix memory leak in srp_ring_free()
  [SCSI] libiscsi, bnx2i: make bound ep check common
  [SCSI] libiscsi: add completion function for drivers that do not need pdu processing
  [SCSI] scsi_dh_rdac: changes for rdac debug logging
  [SCSI] scsi_dh_rdac: changes to collect the rdac debug information during the initialization
  [SCSI] scsi_dh_rdac: move the init code from rdac_activate to rdac_bus_attach
  [SCSI] sg: fix oops in the error path in sg_build_indirect()
  [SCSI] mptsas : Bump version to 3.04.12
  [SCSI] mptsas : FW event thread and scsi mid layer deadlock in SYNCHRONIZE CACHE command
  [SCSI] mptsas : Send DID_NO_CONNECT for pending IOs of removed device
  [SCSI] mptsas : PAE Kernel more than 4 GB kernel panic
  [SCSI] mptsas : NULL pointer on big endian systems causing Expander not to tear off
  [SCSI] mptsas : Sanity check for phyinfo is added
  [SCSI] scsi_dh_rdac: Add support for Sun StorageTek ST2500, ST2510 and ST2530
  [SCSI] pmcraid: PMC-Sierra MaxRAID driver to support 6Gb/s SAS RAID controller
  [SCSI] qla2xxx: Update version number to 8.03.01-k6.
  [SCSI] qla2xxx: Properly delete rports attached to a vport.
  [SCSI] qla2xxx: Correct various NPIV issues.
  [SCSI] qla2xxx: Correct qla2x00_eh_wait_on_command() to wait correctly.
  ...
This commit is contained in:
Linus Torvalds 2009-09-14 17:53:36 -07:00
commit 39695224bd
112 changed files with 14377 additions and 4867 deletions

View file

@ -1811,6 +1811,12 @@ config ZFCP
called zfcp. If you want to compile it as a module, say M here
and read <file:Documentation/kbuild/modules.txt>.
config SCSI_PMCRAID
tristate "PMC SIERRA Linux MaxRAID adapter support"
depends on PCI && SCSI
---help---
This driver supports the PMC SIERRA MaxRAID adapters.
config SCSI_SRP
tristate "SCSI RDMA Protocol helper library"
depends on SCSI && PCI

View file

@ -130,6 +130,7 @@ obj-$(CONFIG_SCSI_MVSAS) += mvsas/
obj-$(CONFIG_PS3_ROM) += ps3rom.o
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
obj-$(CONFIG_ARM) += arm/

View file

@ -15,11 +15,10 @@
static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
static u32 adapter_count;
static int bnx2i_reg_device;
#define DRV_MODULE_NAME "bnx2i"
#define DRV_MODULE_VERSION "2.0.1d"
#define DRV_MODULE_RELDATE "Mar 25, 2009"
#define DRV_MODULE_VERSION "2.0.1e"
#define DRV_MODULE_RELDATE "June 22, 2009"
static char version[] __devinitdata =
"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@ -31,7 +30,7 @@ MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
static DEFINE_RWLOCK(bnx2i_dev_lock);
static DEFINE_MUTEX(bnx2i_dev_lock);
unsigned int event_coal_div = 1;
module_param(event_coal_div, int, 0664);
@ -100,14 +99,14 @@ struct bnx2i_hba *get_adapter_list_head(void)
if (!adapter_count)
goto hba_not_found;
read_lock(&bnx2i_dev_lock);
mutex_lock(&bnx2i_dev_lock);
list_for_each_entry(tmp_hba, &adapter_list, link) {
if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) {
hba = tmp_hba;
break;
}
}
read_unlock(&bnx2i_dev_lock);
mutex_unlock(&bnx2i_dev_lock);
hba_not_found:
return hba;
}
@ -122,14 +121,14 @@ struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic)
{
struct bnx2i_hba *hba, *temp;
read_lock(&bnx2i_dev_lock);
mutex_lock(&bnx2i_dev_lock);
list_for_each_entry_safe(hba, temp, &adapter_list, link) {
if (hba->cnic == cnic) {
read_unlock(&bnx2i_dev_lock);
mutex_unlock(&bnx2i_dev_lock);
return hba;
}
}
read_unlock(&bnx2i_dev_lock);
mutex_unlock(&bnx2i_dev_lock);
return NULL;
}
@ -186,18 +185,17 @@ void bnx2i_stop(void *handle)
*/
void bnx2i_register_device(struct bnx2i_hba *hba)
{
int rc;
if (test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) ||
test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
return;
}
hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
rc = hba->cnic->register_device(hba->cnic, CNIC_ULP_ISCSI, hba);
spin_lock(&hba->lock);
bnx2i_reg_device++;
spin_unlock(&hba->lock);
set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
if (!rc)
set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
}
@ -211,10 +209,10 @@ void bnx2i_reg_dev_all(void)
{
struct bnx2i_hba *hba, *temp;
read_lock(&bnx2i_dev_lock);
mutex_lock(&bnx2i_dev_lock);
list_for_each_entry_safe(hba, temp, &adapter_list, link)
bnx2i_register_device(hba);
read_unlock(&bnx2i_dev_lock);
mutex_unlock(&bnx2i_dev_lock);
}
@ -234,10 +232,6 @@ static void bnx2i_unreg_one_device(struct bnx2i_hba *hba)
hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
spin_lock(&hba->lock);
bnx2i_reg_device--;
spin_unlock(&hba->lock);
/* ep_disconnect could come before NETDEV_DOWN, driver won't
* see NETDEV_DOWN as it already unregistered itself.
*/
@ -255,10 +249,10 @@ void bnx2i_unreg_dev_all(void)
{
struct bnx2i_hba *hba, *temp;
read_lock(&bnx2i_dev_lock);
mutex_lock(&bnx2i_dev_lock);
list_for_each_entry_safe(hba, temp, &adapter_list, link)
bnx2i_unreg_one_device(hba);
read_unlock(&bnx2i_dev_lock);
mutex_unlock(&bnx2i_dev_lock);
}
@ -267,35 +261,34 @@ void bnx2i_unreg_dev_all(void)
* @hba: bnx2i adapter instance
* @cnic: cnic device handle
*
* Global resource lock and host adapter lock is held during critical sections
* below. This routine is called from cnic_register_driver() context and
* work horse thread which does majority of device specific initialization
* Global resource lock is held during critical sections below. This routine is
* called from either cnic_register_driver() or device hot plug context and
* and does majority of device specific initialization
*/
static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
{
int rc;
read_lock(&bnx2i_dev_lock);
if (bnx2i_reg_device &&
!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
if (rc) /* duplicate registration */
printk(KERN_ERR "bnx2i- dev reg failed\n");
spin_lock(&hba->lock);
bnx2i_reg_device++;
mutex_lock(&bnx2i_dev_lock);
rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
if (!rc) {
hba->age++;
spin_unlock(&hba->lock);
set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
}
read_unlock(&bnx2i_dev_lock);
list_add_tail(&hba->link, &adapter_list);
adapter_count++;
} else if (rc == -EBUSY) /* duplicate registration */
printk(KERN_ALERT "bnx2i, duplicate registration"
"hba=%p, cnic=%p\n", hba, cnic);
else if (rc == -EAGAIN)
printk(KERN_ERR "bnx2i, driver not registered\n");
else if (rc == -EINVAL)
printk(KERN_ERR "bnx2i, invalid type %d\n", CNIC_ULP_ISCSI);
else
printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc);
write_lock(&bnx2i_dev_lock);
list_add_tail(&hba->link, &adapter_list);
adapter_count++;
write_unlock(&bnx2i_dev_lock);
return 0;
mutex_unlock(&bnx2i_dev_lock);
return rc;
}
@ -343,19 +336,15 @@ void bnx2i_ulp_exit(struct cnic_dev *dev)
"found, dev 0x%p\n", dev);
return;
}
write_lock(&bnx2i_dev_lock);
mutex_lock(&bnx2i_dev_lock);
list_del_init(&hba->link);
adapter_count--;
if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
spin_lock(&hba->lock);
bnx2i_reg_device--;
spin_unlock(&hba->lock);
}
write_unlock(&bnx2i_dev_lock);
mutex_unlock(&bnx2i_dev_lock);
bnx2i_free_hba(hba);
}
@ -377,6 +366,8 @@ static int __init bnx2i_mod_init(void)
if (!is_power_of_2(sq_size))
sq_size = roundup_pow_of_two(sq_size);
mutex_init(&bnx2i_dev_lock);
bnx2i_scsi_xport_template =
iscsi_register_transport(&bnx2i_iscsi_transport);
if (!bnx2i_scsi_xport_template) {
@ -412,7 +403,7 @@ static void __exit bnx2i_mod_exit(void)
{
struct bnx2i_hba *hba;
write_lock(&bnx2i_dev_lock);
mutex_lock(&bnx2i_dev_lock);
while (!list_empty(&adapter_list)) {
hba = list_entry(adapter_list.next, struct bnx2i_hba, link);
list_del(&hba->link);
@ -421,14 +412,11 @@ static void __exit bnx2i_mod_exit(void)
if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
bnx2i_reg_device--;
}
write_unlock(&bnx2i_dev_lock);
bnx2i_free_hba(hba);
write_lock(&bnx2i_dev_lock);
}
write_unlock(&bnx2i_dev_lock);
mutex_unlock(&bnx2i_dev_lock);
iscsi_unregister_transport(&bnx2i_iscsi_transport);
cnic_unregister_driver(CNIC_ULP_ISCSI);

View file

@ -387,6 +387,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
bnx2i_ep = ep->dd_data;
INIT_LIST_HEAD(&bnx2i_ep->link);
bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->ep_iscsi_cid = (u16) -1;
bnx2i_ep->hba = hba;
bnx2i_ep->hba_age = hba->age;
hba->ofld_conns_active++;
@ -1160,9 +1161,6 @@ static int bnx2i_task_xmit(struct iscsi_task *task)
struct bnx2i_cmd *cmd = task->dd_data;
struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr;
if (test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state))
return -ENOTCONN;
if (!bnx2i_conn->is_bound)
return -ENOTCONN;
@ -1653,15 +1651,18 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
struct iscsi_endpoint *ep;
int rc = 0;
if (shost)
if (shost) {
/* driver is given scsi host to work with */
hba = iscsi_host_priv(shost);
else
/* Register the device with cnic if not already done so */
bnx2i_register_device(hba);
} else
/*
* check if the given destination can be reached through
* a iscsi capable NetXtreme2 device
*/
hba = bnx2i_check_route(dst_addr);
if (!hba) {
rc = -ENOMEM;
goto check_busy;
@ -1681,8 +1682,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
goto net_if_down;
}
bnx2i_ep->state = EP_STATE_IDLE;
bnx2i_ep->ep_iscsi_cid = (u16) -1;
bnx2i_ep->num_active_cmds = 0;
iscsi_cid = bnx2i_alloc_iscsi_cid(hba);
if (iscsi_cid == -1) {

View file

@ -353,6 +353,12 @@ ch_readconfig(scsi_changer *ch)
/* look up the devices of the data transfer elements */
ch->dt = kmalloc(ch->counts[CHET_DT]*sizeof(struct scsi_device),
GFP_KERNEL);
if (!ch->dt) {
kfree(buffer);
return -ENOMEM;
}
for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
id = -1;
lun = 0;

View file

@ -4,8 +4,7 @@
* Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422)
* Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
* by D. Gilbert and aeb (20020609)
* Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025
* Update to SPC-4 T10/1713-D Rev 5a, 14 June 2006, D. Gilbert 20060702
* Update to SPC-4 T10/1713-D Rev 20, 22 May 2009, D. Gilbert 20090624
*/
#include <linux/blkdev.h>
@ -56,9 +55,9 @@ static const char * cdb_byte0_names[] = {
"Read Buffer",
/* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)",
/* 40-41 */ "Change Definition", "Write Same(10)",
/* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support",
"Play audio(10)", "Get configuration", "Play audio msf",
"Play audio track/index",
/* 42-48 */ "Unmap/Read sub-channel", "Read TOC/PMA/ATIP",
"Read density support", "Play audio(10)", "Get configuration",
"Play audio msf", "Play audio track/index",
/* 49-4f */ "Play track relative(10)", "Get event status notification",
"Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
NULL,
@ -71,12 +70,13 @@ static const char * cdb_byte0_names[] = {
/* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length",
/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, "Extended CDB",
"Variable length",
/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy",
"Receive copy results",
/* 85-89 */ "ATA command pass through(16)", "Access control in",
"Access control out", "Read(16)", "Memory Export Out(16)",
/* 8a-8f */ "Write(16)", NULL, "Read attributes", "Write attributes",
/* 8a-8f */ "Write(16)", "ORWrite", "Read attributes", "Write attributes",
"Write and verify(16)", "Verify(16)",
/* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)",
"Lock/unlock cache(16)", "Write same(16)", NULL,
@ -107,22 +107,24 @@ struct value_name_pair {
};
static const struct value_name_pair maint_in_arr[] = {
{0x5, "Report device identifier"},
{0x5, "Report identifying information"},
{0xa, "Report target port groups"},
{0xb, "Report aliases"},
{0xc, "Report supported operation codes"},
{0xd, "Report supported task management functions"},
{0xe, "Report priority"},
{0xf, "Report timestamp"},
{0x10, "Management protocol in"},
};
#define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr)
static const struct value_name_pair maint_out_arr[] = {
{0x6, "Set device identifier"},
{0x6, "Set identifying information"},
{0xa, "Set target port groups"},
{0xb, "Change aliases"},
{0xe, "Set priority"},
{0xe, "Set timestamp"},
{0xf, "Set timestamp"},
{0x10, "Management protocol out"},
};
#define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr)
@ -412,6 +414,7 @@ static const struct error_info additional[] =
{0x0004, "Beginning-of-partition/medium detected"},
{0x0005, "End-of-data detected"},
{0x0006, "I/O process terminated"},
{0x0007, "Programmable early warning detected"},
{0x0011, "Audio play operation in progress"},
{0x0012, "Audio play operation paused"},
{0x0013, "Audio play operation successfully completed"},
@ -425,6 +428,7 @@ static const struct error_info additional[] =
{0x001B, "Set capacity operation in progress"},
{0x001C, "Verify operation in progress"},
{0x001D, "ATA pass through information available"},
{0x001E, "Conflicting SA creation request"},
{0x0100, "No index/sector signal"},
@ -449,9 +453,12 @@ static const struct error_info additional[] =
{0x040B, "Logical unit not accessible, target port in standby state"},
{0x040C, "Logical unit not accessible, target port in unavailable "
"state"},
{0x040D, "Logical unit not ready, structure check required"},
{0x0410, "Logical unit not ready, auxiliary memory not accessible"},
{0x0411, "Logical unit not ready, notify (enable spinup) required"},
{0x0412, "Logical unit not ready, offline"},
{0x0413, "Logical unit not ready, SA creation in progress"},
{0x0414, "Logical unit not ready, space allocation in progress"},
{0x0500, "Logical unit does not respond to selection"},
@ -479,6 +486,9 @@ static const struct error_info additional[] =
{0x0B03, "Warning - background self-test failed"},
{0x0B04, "Warning - background pre-scan detected medium error"},
{0x0B05, "Warning - background medium scan detected medium error"},
{0x0B06, "Warning - non-volatile cache now volatile"},
{0x0B07, "Warning - degraded power to non-volatile cache"},
{0x0B08, "Warning - power loss expected"},
{0x0C00, "Write error"},
{0x0C01, "Write error - recovered with auto reallocation"},
@ -593,6 +603,7 @@ static const struct error_info additional[] =
{0x1C02, "Grown defect list not found"},
{0x1D00, "Miscompare during verify operation"},
{0x1D01, "Miscompare verify of unmapped LBA"},
{0x1E00, "Recovered id with ECC correction"},
@ -626,6 +637,7 @@ static const struct error_info additional[] =
{0x2405, "Security working key frozen"},
{0x2406, "Nonce not unique"},
{0x2407, "Nonce timestamp out of range"},
{0x2408, "Invalid XCDB"},
{0x2500, "Logical unit not supported"},
@ -656,10 +668,12 @@ static const struct error_info additional[] =
{0x2704, "Persistent write protect"},
{0x2705, "Permanent write protect"},
{0x2706, "Conditional write protect"},
{0x2707, "Space allocation failed write protect"},
{0x2800, "Not ready to ready change, medium may have changed"},
{0x2801, "Import or export element accessed"},
{0x2802, "Format-layer may have changed"},
{0x2803, "Import/export element accessed, medium changed"},
{0x2900, "Power on, reset, or bus device reset occurred"},
{0x2901, "Power on occurred"},
@ -680,11 +694,16 @@ static const struct error_info additional[] =
{0x2A07, "Implicit asymmetric access state transition failed"},
{0x2A08, "Priority changed"},
{0x2A09, "Capacity data has changed"},
{0x2A0A, "Error history I_T nexus cleared"},
{0x2A0B, "Error history snapshot released"},
{0x2A0C, "Error recovery attributes have changed"},
{0x2A0D, "Data encryption capabilities changed"},
{0x2A10, "Timestamp changed"},
{0x2A11, "Data encryption parameters changed by another i_t nexus"},
{0x2A12, "Data encryption parameters changed by vendor specific "
"event"},
{0x2A13, "Data encryption key instance counter has changed"},
{0x2A14, "SA creation capabilities data has changed"},
{0x2B00, "Copy cannot execute since host cannot disconnect"},
@ -723,6 +742,8 @@ static const struct error_info additional[] =
{0x300C, "WORM medium - overwrite attempted"},
{0x300D, "WORM medium - integrity check"},
{0x3010, "Medium not formatted"},
{0x3011, "Incompatible volume type"},
{0x3012, "Incompatible volume qualifier"},
{0x3100, "Medium format corrupted"},
{0x3101, "Format command failed"},
@ -782,6 +803,10 @@ static const struct error_info additional[] =
{0x3B15, "Medium magazine unlocked"},
{0x3B16, "Mechanical positioning or changer error"},
{0x3B17, "Read past end of user object"},
{0x3B18, "Element disabled"},
{0x3B19, "Element enabled"},
{0x3B1A, "Data transfer device removed"},
{0x3B1B, "Data transfer device inserted"},
{0x3D00, "Invalid bits in identify message"},
@ -882,6 +907,8 @@ static const struct error_info additional[] =
{0x5506, "Auxiliary memory out of space"},
{0x5507, "Quota error"},
{0x5508, "Maximum number of supplemental decryption keys exceeded"},
{0x5509, "Medium auxiliary memory not accessible"},
{0x550A, "Data currently unavailable"},
{0x5700, "Unable to recover table-of-contents"},
@ -993,6 +1020,12 @@ static const struct error_info additional[] =
{0x5E02, "Standby condition activated by timer"},
{0x5E03, "Idle condition activated by command"},
{0x5E04, "Standby condition activated by command"},
{0x5E05, "Idle_b condition activated by timer"},
{0x5E06, "Idle_b condition activated by command"},
{0x5E07, "Idle_c condition activated by timer"},
{0x5E08, "Idle_c condition activated by command"},
{0x5E09, "Standby_y condition activated by timer"},
{0x5E0A, "Standby_y condition activated by command"},
{0x5E41, "Power state change to active"},
{0x5E42, "Power state change to idle"},
{0x5E43, "Power state change to standby"},
@ -1091,7 +1124,28 @@ static const struct error_info additional[] =
{0x7403, "Incorrect data encryption key"},
{0x7404, "Cryptographic integrity validation failed"},
{0x7405, "Error decrypting data"},
{0x7406, "Unknown signature verification key"},
{0x7407, "Encryption parameters not useable"},
{0x7408, "Digital signature validation failure"},
{0x7409, "Encryption mode mismatch on read"},
{0x740A, "Encrypted block not raw read enabled"},
{0x740B, "Incorrect Encryption parameters"},
{0x740C, "Unable to decrypt parameter list"},
{0x740D, "Encryption algorithm disabled"},
{0x7410, "SA creation parameter value invalid"},
{0x7411, "SA creation parameter value rejected"},
{0x7412, "Invalid SA usage"},
{0x7421, "Data Encryption configuration prevented"},
{0x7430, "SA creation parameter not supported"},
{0x7440, "Authentication failed"},
{0x7461, "External data encryption key manager access error"},
{0x7462, "External data encryption key manager error"},
{0x7463, "External data encryption key not found"},
{0x7464, "External data encryption request not authorized"},
{0x746E, "External data encryption control timeout"},
{0x746F, "External data encryption control error"},
{0x7471, "Logical unit access not authorized"},
{0x7479, "Security conflict in translated device"},
{0, NULL}
};
@ -1103,12 +1157,12 @@ struct error_info2 {
static const struct error_info2 additional2[] =
{
{0x40,0x00,0x7f,"Ram failure (%x)"},
{0x40,0x80,0xff,"Diagnostic failure on component (%x)"},
{0x41,0x00,0xff,"Data path failure (%x)"},
{0x42,0x00,0xff,"Power-on or self-test failure (%x)"},
{0x4D,0x00,0xff,"Tagged overlapped commands (queue tag %x)"},
{0x70,0x00,0xff,"Decompression exception short algorithm id of %x"},
{0x40, 0x00, 0x7f, "Ram failure (%x)"},
{0x40, 0x80, 0xff, "Diagnostic failure on component (%x)"},
{0x41, 0x00, 0xff, "Data path failure (%x)"},
{0x42, 0x00, 0xff, "Power-on or self-test failure (%x)"},
{0x4D, 0x00, 0xff, "Tagged overlapped commands (task tag %x)"},
{0x70, 0x00, 0xff, "Decompression exception short algorithm id of %x"},
{0, 0, 0, NULL}
};
@ -1157,14 +1211,15 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
int i;
unsigned short code = ((asc << 8) | ascq);
for (i=0; additional[i].text; i++)
for (i = 0; additional[i].text; i++)
if (additional[i].code12 == code)
return additional[i].text;
for (i=0; additional2[i].fmt; i++)
for (i = 0; additional2[i].fmt; i++) {
if (additional2[i].code1 == asc &&
additional2[i].code2_min >= ascq &&
additional2[i].code2_max <= ascq)
ascq >= additional2[i].code2_min &&
ascq <= additional2[i].code2_max)
return additional2[i].fmt;
}
#endif
return NULL;
}

View file

@ -153,12 +153,24 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev,
if (sdev->scsi_dh_data) {
if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
err = -EBUSY;
} else if (scsi_dh->attach)
else
kref_get(&sdev->scsi_dh_data->kref);
} else if (scsi_dh->attach) {
err = scsi_dh->attach(sdev);
if (!err) {
kref_init(&sdev->scsi_dh_data->kref);
sdev->scsi_dh_data->sdev = sdev;
}
}
return err;
}
static void __detach_handler (struct kref *kref)
{
struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref);
scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev);
}
/*
* scsi_dh_handler_detach - Detach a device handler from a device
* @sdev - SCSI device the device handler should be detached from
@ -180,7 +192,7 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev,
scsi_dh = sdev->scsi_dh_data->scsi_dh;
if (scsi_dh && scsi_dh->detach)
scsi_dh->detach(sdev);
kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
}
/*
@ -439,6 +451,39 @@ int scsi_dh_activate(struct request_queue *q)
}
EXPORT_SYMBOL_GPL(scsi_dh_activate);
/*
* scsi_dh_set_params - set the parameters for the device as per the
* string specified in params.
* @q - Request queue that is associated with the scsi_device for
* which the parameters to be set.
* @params - parameters in the following format
* "no_of_params\0param1\0param2\0param3\0...\0"
* for example, string for 2 parameters with value 10 and 21
* is specified as "2\010\021\0".
*/
int scsi_dh_set_params(struct request_queue *q, const char *params)
{
int err = -SCSI_DH_NOSYS;
unsigned long flags;
struct scsi_device *sdev;
struct scsi_device_handler *scsi_dh = NULL;
spin_lock_irqsave(q->queue_lock, flags);
sdev = q->queuedata;
if (sdev && sdev->scsi_dh_data)
scsi_dh = sdev->scsi_dh_data->scsi_dh;
if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev))
err = 0;
spin_unlock_irqrestore(q->queue_lock, flags);
if (err)
return err;
err = scsi_dh->set_params(sdev, params);
put_device(&sdev->sdev_gendev);
return err;
}
EXPORT_SYMBOL_GPL(scsi_dh_set_params);
/*
* scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for
* the given name. FALSE(0) otherwise.
@ -474,7 +519,6 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
if (!err) {
err = scsi_dh_handler_attach(sdev, scsi_dh);
put_device(&sdev->sdev_gendev);
}
return err;
@ -505,10 +549,8 @@ void scsi_dh_detach(struct request_queue *q)
return;
if (sdev->scsi_dh_data) {
/* if sdev is not on internal list, detach */
scsi_dh = sdev->scsi_dh_data->scsi_dh;
if (!device_handler_match(scsi_dh, sdev))
scsi_dh_handler_detach(sdev, scsi_dh);
scsi_dh_handler_detach(sdev, scsi_dh);
}
put_device(&sdev->sdev_gendev);
}

View file

@ -663,7 +663,7 @@ static int alua_activate(struct scsi_device *sdev)
goto out;
}
if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
if (h->tpgs & TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
out:

View file

@ -561,6 +561,61 @@ done:
return result;
}
/*
* params - parameters in the following format
* "no_of_params\0param1\0param2\0param3\0...\0"
* for example, string for 2 parameters with value 10 and 21
* is specified as "2\010\021\0".
*/
static int clariion_set_params(struct scsi_device *sdev, const char *params)
{
struct clariion_dh_data *csdev = get_clariion_data(sdev);
unsigned int hr = 0, st = 0, argc;
const char *p = params;
int result = SCSI_DH_OK;
if ((sscanf(params, "%u", &argc) != 1) || (argc != 2))
return -EINVAL;
while (*p++)
;
if ((sscanf(p, "%u", &st) != 1) || (st > 1))
return -EINVAL;
while (*p++)
;
if ((sscanf(p, "%u", &hr) != 1) || (hr > 1))
return -EINVAL;
if (st)
csdev->flags |= CLARIION_SHORT_TRESPASS;
else
csdev->flags &= ~CLARIION_SHORT_TRESPASS;
if (hr)
csdev->flags |= CLARIION_HONOR_RESERVATIONS;
else
csdev->flags &= ~CLARIION_HONOR_RESERVATIONS;
/*
* If this path is owned, we have to send a trespass command
* with the new parameters. If not, simply return. Next trespass
* command would use the parameters.
*/
if (csdev->lun_state != CLARIION_LUN_OWNED)
goto done;
csdev->lun_state = CLARIION_LUN_UNINITIALIZED;
result = send_trespass_cmd(sdev, csdev);
if (result != SCSI_DH_OK)
goto done;
/* Update status */
result = clariion_send_inquiry(sdev, csdev);
done:
return result;
}
static const struct scsi_dh_devlist clariion_dev_list[] = {
{"DGC", "RAID"},
@ -581,11 +636,9 @@ static struct scsi_device_handler clariion_dh = {
.check_sense = clariion_check_sense,
.activate = clariion_activate,
.prep_fn = clariion_prep_fn,
.set_params = clariion_set_params,
};
/*
* TODO: need some interface so we can set trespass values
*/
static int clariion_bus_attach(struct scsi_device *sdev)
{
struct scsi_dh_data *scsi_dh_data;

View file

@ -112,6 +112,7 @@ struct c9_inquiry {
#define SUBSYS_ID_LEN 16
#define SLOT_ID_LEN 2
#define ARRAY_LABEL_LEN 31
struct c4_inquiry {
u8 peripheral_info;
@ -135,6 +136,8 @@ struct rdac_controller {
struct rdac_pg_legacy legacy;
struct rdac_pg_expanded expanded;
} mode_select;
u8 index;
u8 array_name[ARRAY_LABEL_LEN];
};
struct c8_inquiry {
u8 peripheral_info;
@ -198,6 +201,31 @@ static const char *lun_state[] =
static LIST_HEAD(ctlr_list);
static DEFINE_SPINLOCK(list_lock);
/*
* module parameter to enable rdac debug logging.
* 2 bits for each type of logging, only two types defined for now
* Can be enhanced if required at later point
*/
static int rdac_logging = 1;
module_param(rdac_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(rdac_logging, "A bit mask of rdac logging levels, "
"Default is 1 - failover logging enabled, "
"set it to 0xF to enable all the logs");
#define RDAC_LOG_FAILOVER 0
#define RDAC_LOG_SENSE 2
#define RDAC_LOG_BITS 2
#define RDAC_LOG_LEVEL(SHIFT) \
((rdac_logging >> (SHIFT)) & ((1 << (RDAC_LOG_BITS)) - 1))
#define RDAC_LOG(SHIFT, sdev, f, arg...) \
do { \
if (unlikely(RDAC_LOG_LEVEL(SHIFT))) \
sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \
} while (0);
static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
{
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
@ -303,7 +331,8 @@ static void release_controller(struct kref *kref)
kfree(ctlr);
}
static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id)
static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id,
char *array_name)
{
struct rdac_controller *ctlr, *tmp;
@ -324,6 +353,14 @@ static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id)
/* initialize fields of controller */
memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN);
memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN);
memcpy(ctlr->array_name, array_name, ARRAY_LABEL_LEN);
/* update the controller index */
if (slot_id[1] == 0x31)
ctlr->index = 0;
else
ctlr->index = 1;
kref_init(&ctlr->kref);
ctlr->use_ms10 = -1;
list_add(&ctlr->node, &ctlr_list);
@ -363,9 +400,10 @@ done:
return err;
}
static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h)
static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h,
char *array_name)
{
int err;
int err, i;
struct c8_inquiry *inqp;
err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h);
@ -377,6 +415,11 @@ static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h)
inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd')
return SCSI_DH_NOSYS;
h->lun = inqp->lun[7]; /* Uses only the last byte */
for(i=0; i<ARRAY_LABEL_LEN-1; ++i)
*(array_name+i) = inqp->array_user_label[(2*i)+1];
*(array_name+ARRAY_LABEL_LEN-1) = '\0';
}
return err;
}
@ -410,7 +453,7 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
}
static int initialize_controller(struct scsi_device *sdev,
struct rdac_dh_data *h)
struct rdac_dh_data *h, char *array_name)
{
int err;
struct c4_inquiry *inqp;
@ -418,7 +461,8 @@ static int initialize_controller(struct scsi_device *sdev,
err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h);
if (err == SCSI_DH_OK) {
inqp = &h->inq.c4;
h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id,
array_name);
if (!h->ctlr)
err = SCSI_DH_RES_TEMP_UNAVAIL;
}
@ -450,6 +494,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
{
struct scsi_sense_hdr sense_hdr;
int err = SCSI_DH_IO, ret;
struct rdac_dh_data *h = get_rdac_data(sdev);
ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
if (!ret)
@ -478,11 +523,14 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
err = SCSI_DH_RETRY;
break;
default:
sdev_printk(KERN_INFO, sdev,
"MODE_SELECT failed with sense %02x/%02x/%02x.\n",
sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq);
break;
}
RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
"MODE_SELECT returned with sense %02x/%02x/%02x",
(char *) h->ctlr->array_name, h->ctlr->index,
sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq);
done:
return err;
}
@ -499,7 +547,9 @@ retry:
if (!rq)
goto done;
sdev_printk(KERN_INFO, sdev, "%s MODE_SELECT command.\n",
RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
"%s MODE_SELECT command",
(char *) h->ctlr->array_name, h->ctlr->index,
(retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying");
err = blk_execute_rq(q, NULL, rq, 1);
@ -509,8 +559,12 @@ retry:
if (err == SCSI_DH_RETRY && retry_cnt--)
goto retry;
}
if (err == SCSI_DH_OK)
if (err == SCSI_DH_OK) {
h->state = RDAC_STATE_ACTIVE;
RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, "
"MODE_SELECT completed",
(char *) h->ctlr->array_name, h->ctlr->index);
}
done:
return err;
@ -525,17 +579,6 @@ static int rdac_activate(struct scsi_device *sdev)
if (err != SCSI_DH_OK)
goto done;
if (!h->ctlr) {
err = initialize_controller(sdev, h);
if (err != SCSI_DH_OK)
goto done;
}
if (h->ctlr->use_ms10 == -1) {
err = set_mode_select(sdev, h);
if (err != SCSI_DH_OK)
goto done;
}
if (h->lun_state == RDAC_LUN_UNOWNED)
err = send_mode_select(sdev, h);
done:
@ -559,6 +602,12 @@ static int rdac_check_sense(struct scsi_device *sdev,
struct scsi_sense_hdr *sense_hdr)
{
struct rdac_dh_data *h = get_rdac_data(sdev);
RDAC_LOG(RDAC_LOG_SENSE, sdev, "array %s, ctlr %d, "
"I/O returned with sense %02x/%02x/%02x",
(char *) h->ctlr->array_name, h->ctlr->index,
sense_hdr->sense_key, sense_hdr->asc, sense_hdr->ascq);
switch (sense_hdr->sense_key) {
case NOT_READY:
if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01)
@ -628,11 +677,18 @@ static const struct scsi_dh_devlist rdac_dev_list[] = {
{"SGI", "IS"},
{"STK", "OPENstorage D280"},
{"SUN", "CSM200_R"},
{"SUN", "LCSM100_I"},
{"SUN", "LCSM100_S"},
{"SUN", "LCSM100_E"},
{"SUN", "LCSM100_F"},
{"DELL", "MD3000"},
{"DELL", "MD3000i"},
{"DELL", "MD32xx"},
{"DELL", "MD32xxi"},
{"LSI", "INF-01-00"},
{"ENGENIO", "INF-01-00"},
{"STK", "FLEXLINE 380"},
{"SUN", "CSM100_R_FC"},
{NULL, NULL},
};
@ -656,6 +712,7 @@ static int rdac_bus_attach(struct scsi_device *sdev)
struct rdac_dh_data *h;
unsigned long flags;
int err;
char array_name[ARRAY_LABEL_LEN];
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+ sizeof(*h) , GFP_KERNEL);
@ -670,16 +727,24 @@ static int rdac_bus_attach(struct scsi_device *sdev)
h->lun = UNINITIALIZED_LUN;
h->state = RDAC_STATE_ACTIVE;
err = get_lun(sdev, h);
err = get_lun_info(sdev, h, array_name);
if (err != SCSI_DH_OK)
goto failed;
err = initialize_controller(sdev, h, array_name);
if (err != SCSI_DH_OK)
goto failed;
err = check_ownership(sdev, h);
if (err != SCSI_DH_OK)
goto failed;
goto clean_ctlr;
err = set_mode_select(sdev, h);
if (err != SCSI_DH_OK)
goto clean_ctlr;
if (!try_module_get(THIS_MODULE))
goto failed;
goto clean_ctlr;
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
sdev->scsi_dh_data = scsi_dh_data;
@ -691,6 +756,9 @@ static int rdac_bus_attach(struct scsi_device *sdev)
return 0;
clean_ctlr:
kref_put(&h->ctlr->kref, release_controller);
failed:
kfree(scsi_dh_data);
sdev_printk(KERN_ERR, sdev, "%s: not attached\n",

File diff suppressed because it is too large Load diff

View file

@ -37,8 +37,8 @@
#define FCOE_MAX_OUTSTANDING_COMMANDS 1024
#define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */
#define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */
#define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */
#define FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */
unsigned int fcoe_debug_logging;
module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR);
@ -53,7 +53,7 @@ do { \
do { \
CMD; \
} while (0); \
} while (0);
} while (0)
#define FCOE_DBG(fmt, args...) \
FCOE_CHECK_LOGGING(FCOE_LOGGING, \
@ -61,7 +61,7 @@ do { \
#define FCOE_NETDEV_DBG(netdev, fmt, args...) \
FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING, \
printk(KERN_INFO "fcoe: %s" fmt, \
printk(KERN_INFO "fcoe: %s: " fmt, \
netdev->name, ##args);)
/*
@ -75,26 +75,36 @@ struct fcoe_percpu_s {
};
/*
* the fcoe sw transport private data
* an FCoE interface, 1:1 with netdev
*/
struct fcoe_softc {
struct fcoe_interface {
struct list_head list;
struct net_device *real_dev;
struct net_device *phys_dev; /* device with ethtool_ops */
struct net_device *netdev;
struct packet_type fcoe_packet_type;
struct packet_type fip_packet_type;
struct fcoe_ctlr ctlr;
struct fc_exch_mgr *oem; /* offload exchange manager */
struct kref kref;
};
/*
* the FCoE private structure that's allocated along with the
* Scsi_Host and libfc fc_lport structures
*/
struct fcoe_port {
struct fcoe_interface *fcoe;
struct fc_lport *lport;
struct sk_buff_head fcoe_pending_queue;
u8 fcoe_pending_queue_active;
struct timer_list timer; /* queue timer */
struct fcoe_ctlr ctlr;
struct work_struct destroy_work; /* to prevent rtnl deadlocks */
};
#define fcoe_from_ctlr(fc) container_of(fc, struct fcoe_softc, ctlr)
#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr)
static inline struct net_device *fcoe_netdev(
const struct fc_lport *lp)
static inline struct net_device *fcoe_netdev(const struct fc_lport *lp)
{
return ((struct fcoe_softc *)lport_priv(lp))->real_dev;
return ((struct fcoe_port *)lport_priv(lp))->fcoe->netdev;
}
#endif /* _FCOE_H_ */

View file

@ -69,7 +69,7 @@ do { \
do { \
CMD; \
} while (0); \
} while (0);
} while (0)
#define LIBFCOE_DBG(fmt, args...) \
LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
@ -148,13 +148,17 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)
*/
void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
{
flush_work(&fip->recv_work);
cancel_work_sync(&fip->recv_work);
spin_lock_bh(&fip->fip_recv_list.lock);
__skb_queue_purge(&fip->fip_recv_list);
spin_unlock_bh(&fip->fip_recv_list.lock);
spin_lock_bh(&fip->lock);
fip->state = FIP_ST_DISABLED;
fcoe_ctlr_reset_fcfs(fip);
spin_unlock_bh(&fip->lock);
del_timer_sync(&fip->timer);
flush_work(&fip->link_work);
cancel_work_sync(&fip->link_work);
}
EXPORT_SYMBOL(fcoe_ctlr_destroy);
@ -413,10 +417,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
struct fip_mac_desc *mac;
struct fcoe_fcf *fcf;
size_t dlen;
u16 fip_flags;
fcf = fip->sel_fcf;
if (!fcf)
return -ENODEV;
/* set flags according to both FCF and lport's capability on SPMA */
fip_flags = fcf->flags;
fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : FIP_FL_FPMA;
if (!fip_flags)
return -ENODEV;
dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */
cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap));
@ -429,9 +441,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,
cap->fip.fip_op = htons(FIP_OP_LS);
cap->fip.fip_subcode = FIP_SC_REQ;
cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW);
cap->fip.fip_flags = htons(FIP_FL_FPMA);
if (fip->spma)
cap->fip.fip_flags |= htons(FIP_FL_SPMA);
cap->fip.fip_flags = htons(fip_flags);
cap->encaps.fd_desc.fip_dtype = dtype;
cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
@ -879,7 +889,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
stats->RxFrames++;
stats->RxWords += skb->len / FIP_BPW;
fc_exch_recv(lp, lp->emp, fp);
fc_exch_recv(lp, fp);
return;
len_err:
@ -1104,7 +1114,6 @@ static void fcoe_ctlr_timeout(unsigned long arg)
struct fcoe_fcf *sel;
struct fcoe_fcf *fcf;
unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
DECLARE_MAC_BUF(buf);
u8 send_ctlr_ka;
u8 send_port_ka;
@ -1128,9 +1137,8 @@ static void fcoe_ctlr_timeout(unsigned long arg)
fcf = sel; /* the old FCF may have been freed */
if (sel) {
printk(KERN_INFO "libfcoe: host%d: FIP selected "
"Fibre-Channel Forwarder MAC %s\n",
fip->lp->host->host_no,
print_mac(buf, sel->fcf_mac));
"Fibre-Channel Forwarder MAC %pM\n",
fip->lp->host->host_no, sel->fcf_mac);
memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_KA_PERIOD);

View file

@ -115,7 +115,7 @@ void fnic_handle_frame(struct work_struct *work)
}
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
fc_exch_recv(lp, lp->emp, fp);
fc_exch_recv(lp, fp);
}
}

View file

@ -671,14 +671,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
lp->link_up = 0;
lp->tt = fnic_transport_template;
lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3,
FCPIO_HOST_EXCH_RANGE_START,
FCPIO_HOST_EXCH_RANGE_END);
if (!lp->emp) {
err = -ENOMEM;
goto err_out_remove_scsi_host;
}
lp->max_retry_count = fnic->config.flogi_retries;
lp->max_rport_retry_count = fnic->config.plogi_retries;
lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
@ -693,12 +685,18 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
fc_set_wwnn(lp, fnic->config.node_wwn);
fc_set_wwpn(lp, fnic->config.port_wwn);
fc_exch_init(lp);
fc_lport_init(lp);
fc_exch_init(lp);
fc_elsct_init(lp);
fc_rport_init(lp);
fc_disc_init(lp);
if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START,
FCPIO_HOST_EXCH_RANGE_END, NULL)) {
err = -ENOMEM;
goto err_out_remove_scsi_host;
}
fc_lport_config(lp);
if (fc_set_mfs(lp, fnic->config.maxdatafieldsize +
@ -738,7 +736,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
return 0;
err_out_free_exch_mgr:
fc_exch_mgr_free(lp->emp);
fc_exch_mgr_free(lp);
err_out_remove_scsi_host:
fc_remove_host(fnic->lport->host);
scsi_remove_host(fnic->lport->host);
@ -827,7 +825,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev)
fc_remove_host(fnic->lport->host);
scsi_remove_host(fnic->lport->host);
fc_exch_mgr_free(fnic->lport->emp);
fc_exch_mgr_free(fnic->lport);
vnic_dev_notify_unset(fnic->vdev);
fnic_free_vnic_resources(fnic);
fnic_free_intr(fnic);

View file

@ -4217,7 +4217,7 @@ static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost)
if (!vhost->trace)
goto free_disc_buffer;
vhost->tgt_pool = mempool_create_kzalloc_pool(IBMVFC_TGT_MEMPOOL_SZ,
vhost->tgt_pool = mempool_create_kmalloc_pool(IBMVFC_TGT_MEMPOOL_SZ,
sizeof(struct ibmvfc_target));
if (!vhost->tgt_pool) {

View file

@ -1199,7 +1199,7 @@ struct ipr_ioa_cfg {
struct ata_host ata_host;
char ipr_cmd_label[8];
#define IPR_CMD_LABEL "ipr_cmnd"
#define IPR_CMD_LABEL "ipr_cmd"
struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
u32 ipr_cmnd_list_dma[IPR_NUM_CMD_BLKS];
};

View file

@ -99,6 +99,27 @@ static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
return total_consumed;
}
/**
* iscsi_sw_sk_state_check - check socket state
* @sk: socket
*
* If the socket is in CLOSE or CLOSE_WAIT we should
* not close the connection if there is still some
* data pending.
*/
static inline int iscsi_sw_sk_state_check(struct sock *sk)
{
struct iscsi_conn *conn = (struct iscsi_conn*)sk->sk_user_data;
if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) &&
!atomic_read(&sk->sk_rmem_alloc)) {
ISCSI_SW_TCP_DBG(conn, "TCP_CLOSE|TCP_CLOSE_WAIT\n");
iscsi_conn_failure(conn, ISCSI_ERR_TCP_CONN_CLOSE);
return -ECONNRESET;
}
return 0;
}
static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag)
{
struct iscsi_conn *conn = sk->sk_user_data;
@ -117,6 +138,8 @@ static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag)
rd_desc.count = 1;
tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv);
iscsi_sw_sk_state_check(sk);
read_unlock(&sk->sk_callback_lock);
/* If we had to (atomically) map a highmem page,
@ -137,13 +160,7 @@ static void iscsi_sw_tcp_state_change(struct sock *sk)
conn = (struct iscsi_conn*)sk->sk_user_data;
session = conn->session;
if ((sk->sk_state == TCP_CLOSE_WAIT ||
sk->sk_state == TCP_CLOSE) &&
!atomic_read(&sk->sk_rmem_alloc)) {
ISCSI_SW_TCP_DBG(conn, "iscsi_tcp_state_change: "
"TCP_CLOSE|TCP_CLOSE_WAIT\n");
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
}
iscsi_sw_sk_state_check(sk);
tcp_conn = conn->dd_data;
tcp_sw_conn = tcp_conn->dd_data;

View file

@ -43,46 +43,13 @@
#define FC_DISC_RETRY_LIMIT 3 /* max retries */
#define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */
#define FC_DISC_DELAY 3
static void fc_disc_gpn_ft_req(struct fc_disc *);
static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *);
static int fc_disc_new_target(struct fc_disc *, struct fc_rport *,
struct fc_rport_identifiers *);
static void fc_disc_del_target(struct fc_disc *, struct fc_rport *);
static void fc_disc_done(struct fc_disc *);
static void fc_disc_done(struct fc_disc *, enum fc_disc_event);
static void fc_disc_timeout(struct work_struct *);
static void fc_disc_single(struct fc_disc *, struct fc_disc_port *);
static int fc_disc_single(struct fc_lport *, struct fc_disc_port *);
static void fc_disc_restart(struct fc_disc *);
/**
* fc_disc_lookup_rport() - lookup a remote port by port_id
* @lport: Fibre Channel host port instance
* @port_id: remote port port_id to match
*/
struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport,
u32 port_id)
{
const struct fc_disc *disc = &lport->disc;
struct fc_rport *rport, *found = NULL;
struct fc_rport_libfc_priv *rdata;
int disc_found = 0;
list_for_each_entry(rdata, &disc->rports, peers) {
rport = PRIV_TO_RPORT(rdata);
if (rport->port_id == port_id) {
disc_found = 1;
found = rport;
break;
}
}
if (!disc_found)
found = NULL;
return found;
}
/**
* fc_disc_stop_rports() - delete all the remote ports associated with the lport
* @disc: The discovery job to stop rports on
@ -93,69 +60,16 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport,
void fc_disc_stop_rports(struct fc_disc *disc)
{
struct fc_lport *lport;
struct fc_rport *rport;
struct fc_rport_libfc_priv *rdata, *next;
struct fc_rport_priv *rdata, *next;
lport = disc->lport;
mutex_lock(&disc->disc_mutex);
list_for_each_entry_safe(rdata, next, &disc->rports, peers) {
rport = PRIV_TO_RPORT(rdata);
list_del(&rdata->peers);
lport->tt.rport_logoff(rport);
}
list_for_each_entry_safe(rdata, next, &disc->rogue_rports, peers) {
rport = PRIV_TO_RPORT(rdata);
lport->tt.rport_logoff(rport);
}
list_for_each_entry_safe(rdata, next, &disc->rports, peers)
lport->tt.rport_logoff(rdata);
mutex_unlock(&disc->disc_mutex);
}
/**
* fc_disc_rport_callback() - Event handler for rport events
* @lport: The lport which is receiving the event
* @rport: The rport which the event has occured on
* @event: The event that occured
*
* Locking Note: The rport lock should not be held when calling
* this function.
*/
static void fc_disc_rport_callback(struct fc_lport *lport,
struct fc_rport *rport,
enum fc_rport_event event)
{
struct fc_rport_libfc_priv *rdata = rport->dd_data;
struct fc_disc *disc = &lport->disc;
FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event,
rport->port_id);
switch (event) {
case RPORT_EV_CREATED:
if (disc) {
mutex_lock(&disc->disc_mutex);
list_add_tail(&rdata->peers, &disc->rports);
mutex_unlock(&disc->disc_mutex);
}
break;
case RPORT_EV_LOGO:
case RPORT_EV_FAILED:
case RPORT_EV_STOP:
mutex_lock(&disc->disc_mutex);
mutex_lock(&rdata->rp_mutex);
if (rdata->trans_state == FC_PORTSTATE_ROGUE)
list_del(&rdata->peers);
mutex_unlock(&rdata->rp_mutex);
mutex_unlock(&disc->disc_mutex);
break;
default:
break;
}
}
/**
* fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
* @sp: Current sequence of the RSCN exchange
@ -169,8 +83,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
struct fc_disc *disc)
{
struct fc_lport *lport;
struct fc_rport *rport;
struct fc_rport_libfc_priv *rdata;
struct fc_els_rscn *rp;
struct fc_els_rscn_page *pp;
struct fc_seq_els_data rjt_data;
@ -224,10 +136,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
break;
}
dp->lp = lport;
dp->ids.port_id = ntoh24(pp->rscn_fid);
dp->ids.port_name = -1;
dp->ids.node_name = -1;
dp->ids.roles = FC_RPORT_ROLE_UNKNOWN;
dp->port_id = ntoh24(pp->rscn_fid);
list_add_tail(&dp->peers, &disc_ports);
break;
case ELS_ADDR_FMT_AREA:
@ -240,6 +149,19 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
}
}
lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
/*
* If not doing a complete rediscovery, do GPN_ID on
* the individual ports mentioned in the list.
* If any of these get an error, do a full rediscovery.
* In any case, go through the list and free the entries.
*/
list_for_each_entry_safe(dp, next, &disc_ports, peers) {
list_del(&dp->peers);
if (!redisc)
redisc = fc_disc_single(lport, dp);
kfree(dp);
}
if (redisc) {
FC_DISC_DBG(disc, "RSCN received: rediscovering\n");
fc_disc_restart(disc);
@ -247,16 +169,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
FC_DISC_DBG(disc, "RSCN received: not rediscovering. "
"redisc %d state %d in_prog %d\n",
redisc, lport->state, disc->pending);
list_for_each_entry_safe(dp, next, &disc_ports, peers) {
list_del(&dp->peers);
rport = lport->tt.rport_lookup(lport, dp->ids.port_id);
if (rport) {
rdata = rport->dd_data;
list_del(&rdata->peers);
lport->tt.rport_logoff(rport);
}
fc_disc_single(disc, dp);
}
}
fc_frame_free(fp);
return;
@ -308,35 +220,34 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
*/
static void fc_disc_restart(struct fc_disc *disc)
{
struct fc_rport *rport;
struct fc_rport_libfc_priv *rdata, *next;
struct fc_lport *lport = disc->lport;
if (!disc->disc_callback)
return;
FC_DISC_DBG(disc, "Restarting discovery\n");
list_for_each_entry_safe(rdata, next, &disc->rports, peers) {
rport = PRIV_TO_RPORT(rdata);
list_del(&rdata->peers);
lport->tt.rport_logoff(rport);
}
disc->requested = 1;
if (!disc->pending)
fc_disc_gpn_ft_req(disc);
if (disc->pending)
return;
/*
* Advance disc_id. This is an arbitrary non-zero number that will
* match the value in the fc_rport_priv after discovery for all
* freshly-discovered remote ports. Avoid wrapping to zero.
*/
disc->disc_id = (disc->disc_id + 2) | 1;
disc->retry_count = 0;
fc_disc_gpn_ft_req(disc);
}
/**
* fc_disc_start() - Fibre Channel Target discovery
* @lport: FC local port
*
* Returns non-zero if discovery cannot be started.
* @disc_callback: function to be called when discovery is complete
*/
static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
enum fc_disc_event),
struct fc_lport *lport)
{
struct fc_rport *rport;
struct fc_rport_identifiers ids;
struct fc_disc *disc = &lport->disc;
/*
@ -345,145 +256,47 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
* and send the GPN_FT request.
*/
mutex_lock(&disc->disc_mutex);
disc->disc_callback = disc_callback;
/*
* If not ready, or already running discovery, just set request flag.
*/
disc->requested = 1;
if (disc->pending) {
mutex_unlock(&disc->disc_mutex);
return;
}
/*
* Handle point-to-point mode as a simple discovery
* of the remote port. Yucky, yucky, yuck, yuck!
*/
rport = disc->lport->ptp_rp;
if (rport) {
ids.port_id = rport->port_id;
ids.port_name = rport->port_name;
ids.node_name = rport->node_name;
ids.roles = FC_RPORT_ROLE_UNKNOWN;
get_device(&rport->dev);
if (!fc_disc_new_target(disc, rport, &ids)) {
disc->event = DISC_EV_SUCCESS;
fc_disc_done(disc);
}
put_device(&rport->dev);
} else {
fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */
}
fc_disc_restart(disc);
mutex_unlock(&disc->disc_mutex);
}
static struct fc_rport_operations fc_disc_rport_ops = {
.event_callback = fc_disc_rport_callback,
};
/**
* fc_disc_new_target() - Handle new target found by discovery
* @lport: FC local port
* @rport: The previous FC remote port (NULL if new remote port)
* @ids: Identifiers for the new FC remote port
*
* Locking Note: This function expects that the disc_mutex is locked
* before it is called.
*/
static int fc_disc_new_target(struct fc_disc *disc,
struct fc_rport *rport,
struct fc_rport_identifiers *ids)
{
struct fc_lport *lport = disc->lport;
struct fc_rport_libfc_priv *rdata;
int error = 0;
if (rport && ids->port_name) {
if (rport->port_name == -1) {
/*
* Set WWN and fall through to notify of create.
*/
fc_rport_set_name(rport, ids->port_name,
rport->node_name);
} else if (rport->port_name != ids->port_name) {
/*
* This is a new port with the same FCID as
* a previously-discovered port. Presumably the old
* port logged out and a new port logged in and was
* assigned the same FCID. This should be rare.
* Delete the old one and fall thru to re-create.
*/
fc_disc_del_target(disc, rport);
rport = NULL;
}
}
if (((ids->port_name != -1) || (ids->port_id != -1)) &&
ids->port_id != fc_host_port_id(lport->host) &&
ids->port_name != lport->wwpn) {
if (!rport) {
rport = lport->tt.rport_lookup(lport, ids->port_id);
if (!rport) {
struct fc_disc_port dp;
dp.lp = lport;
dp.ids.port_id = ids->port_id;
dp.ids.port_name = ids->port_name;
dp.ids.node_name = ids->node_name;
dp.ids.roles = ids->roles;
rport = lport->tt.rport_create(&dp);
}
if (!rport)
error = -ENOMEM;
}
if (rport) {
rdata = rport->dd_data;
rdata->ops = &fc_disc_rport_ops;
rdata->rp_state = RPORT_ST_INIT;
list_add_tail(&rdata->peers, &disc->rogue_rports);
lport->tt.rport_login(rport);
}
}
return error;
}
/**
* fc_disc_del_target() - Delete a target
* @disc: FC discovery context
* @rport: The remote port to be removed
*/
static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport)
{
struct fc_lport *lport = disc->lport;
struct fc_rport_libfc_priv *rdata = rport->dd_data;
list_del(&rdata->peers);
lport->tt.rport_logoff(rport);
}
/**
* fc_disc_done() - Discovery has been completed
* @disc: FC discovery context
* @event: discovery completion status
*
* Locking Note: This function expects that the disc mutex is locked before
* it is called. The discovery callback is then made with the lock released,
* and the lock is re-taken before returning from this function
*/
static void fc_disc_done(struct fc_disc *disc)
static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
{
struct fc_lport *lport = disc->lport;
enum fc_disc_event event;
struct fc_rport_priv *rdata;
FC_DISC_DBG(disc, "Discovery complete\n");
event = disc->event;
disc->event = DISC_EV_NONE;
disc->pending = 0;
if (disc->requested) {
fc_disc_restart(disc);
return;
}
if (disc->requested)
fc_disc_gpn_ft_req(disc);
else
disc->pending = 0;
/*
* Go through all remote ports. If they were found in the latest
* discovery, reverify or log them in. Otherwise, log them out.
* Skip ports which were never discovered. These are the dNS port
* and ports which were created by PLOGI.
*/
list_for_each_entry(rdata, &disc->rports, peers) {
if (!rdata->disc_id)
continue;
if (rdata->disc_id == disc->disc_id)
lport->tt.rport_login(rdata);
else
lport->tt.rport_logoff(rdata);
}
mutex_unlock(&disc->disc_mutex);
disc->disc_callback(lport, event);
@ -522,11 +335,8 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
}
disc->retry_count++;
schedule_delayed_work(&disc->disc_work, delay);
} else {
/* exceeded retries */
disc->event = DISC_EV_FAILED;
fc_disc_done(disc);
}
} else
fc_disc_done(disc, DISC_EV_FAILED);
}
}
@ -555,7 +365,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *disc)
if (!fp)
goto err;
if (lport->tt.elsct_send(lport, NULL, fp,
if (lport->tt.elsct_send(lport, 0, fp,
FC_NS_GPN_FT,
fc_disc_gpn_ft_resp,
disc, lport->e_d_tov))
@ -565,10 +375,12 @@ err:
}
/**
* fc_disc_gpn_ft_parse() - Parse the list of IDs and names resulting from a request
* fc_disc_gpn_ft_parse() - Parse the body of the dNS GPN_FT response.
* @lport: Fibre Channel host port instance
* @buf: GPN_FT response buffer
* @len: size of response buffer
*
* Goes through the list of IDs and names resulting from a request.
*/
static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
{
@ -578,11 +390,11 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
size_t plen;
size_t tlen;
int error = 0;
struct fc_disc_port dp;
struct fc_rport *rport;
struct fc_rport_libfc_priv *rdata;
struct fc_rport_identifiers ids;
struct fc_rport_priv *rdata;
lport = disc->lport;
disc->seq_count++;
/*
* Handle partial name record left over from previous call.
@ -591,6 +403,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
plen = len;
np = (struct fc_gpn_ft_resp *)bp;
tlen = disc->buf_len;
disc->buf_len = 0;
if (tlen) {
WARN_ON(tlen >= sizeof(*np));
plen = sizeof(*np) - tlen;
@ -621,31 +434,25 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
* After the first time through the loop, things return to "normal".
*/
while (plen >= sizeof(*np)) {
dp.lp = lport;
dp.ids.port_id = ntoh24(np->fp_fid);
dp.ids.port_name = ntohll(np->fp_wwpn);
dp.ids.node_name = -1;
dp.ids.roles = FC_RPORT_ROLE_UNKNOWN;
ids.port_id = ntoh24(np->fp_fid);
ids.port_name = ntohll(np->fp_wwpn);
if ((dp.ids.port_id != fc_host_port_id(lport->host)) &&
(dp.ids.port_name != lport->wwpn)) {
rport = lport->tt.rport_create(&dp);
if (rport) {
rdata = rport->dd_data;
rdata->ops = &fc_disc_rport_ops;
rdata->local_port = lport;
list_add_tail(&rdata->peers,
&disc->rogue_rports);
lport->tt.rport_login(rport);
} else
if (ids.port_id != fc_host_port_id(lport->host) &&
ids.port_name != lport->wwpn) {
rdata = lport->tt.rport_create(lport, ids.port_id);
if (rdata) {
rdata->ids.port_name = ids.port_name;
rdata->disc_id = disc->disc_id;
} else {
printk(KERN_WARNING "libfc: Failed to allocate "
"memory for the newly discovered port "
"(%6x)\n", dp.ids.port_id);
"(%6x)\n", ids.port_id);
error = -ENOMEM;
}
}
if (np->fp_flags & FC_NS_FID_LAST) {
disc->event = DISC_EV_SUCCESS;
fc_disc_done(disc);
fc_disc_done(disc, DISC_EV_SUCCESS);
len = 0;
break;
}
@ -665,8 +472,6 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
memcpy(&disc->partial_buf, np, len);
}
disc->buf_len = (unsigned char) len;
} else {
disc->buf_len = 0;
}
return error;
}
@ -683,8 +488,7 @@ static void fc_disc_timeout(struct work_struct *work)
struct fc_disc,
disc_work.work);
mutex_lock(&disc->disc_mutex);
if (disc->requested && !disc->pending)
fc_disc_gpn_ft_req(disc);
fc_disc_gpn_ft_req(disc);
mutex_unlock(&disc->disc_mutex);
}
@ -703,10 +507,10 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_disc *disc = disc_arg;
struct fc_ct_hdr *cp;
struct fc_frame_header *fh;
enum fc_disc_event event = DISC_EV_NONE;
unsigned int seq_cnt;
void *buf = NULL;
unsigned int len;
int error;
int error = 0;
mutex_lock(&disc->disc_mutex);
FC_DISC_DBG(disc, "Received a GPN_FT response\n");
@ -721,77 +525,158 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,
fh = fc_frame_header_get(fp);
len = fr_len(fp) - sizeof(*fh);
seq_cnt = ntohs(fh->fh_seq_cnt);
if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 &&
disc->seq_count == 0) {
if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && disc->seq_count == 0) {
cp = fc_frame_payload_get(fp, sizeof(*cp));
if (!cp) {
FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n",
fr_len(fp));
event = DISC_EV_FAILED;
} else if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
/* Accepted, parse the response. */
buf = cp + 1;
len -= sizeof(*cp);
error = fc_disc_gpn_ft_parse(disc, cp + 1, len);
} else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x "
"(check zoning)\n", cp->ct_reason,
cp->ct_explan);
disc->event = DISC_EV_FAILED;
fc_disc_done(disc);
event = DISC_EV_FAILED;
if (cp->ct_reason == FC_FS_RJT_UNABL &&
cp->ct_explan == FC_FS_EXP_FTNR)
event = DISC_EV_SUCCESS;
} else {
FC_DISC_DBG(disc, "GPN_FT unexpected response code "
"%x\n", ntohs(cp->ct_cmd));
event = DISC_EV_FAILED;
}
} else if (fr_sof(fp) == FC_SOF_N3 &&
seq_cnt == disc->seq_count) {
buf = fh + 1;
} else if (fr_sof(fp) == FC_SOF_N3 && seq_cnt == disc->seq_count) {
error = fc_disc_gpn_ft_parse(disc, fh + 1, len);
} else {
FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? "
"seq_cnt %x expected %x sof %x eof %x\n",
seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp));
event = DISC_EV_FAILED;
}
if (buf) {
error = fc_disc_gpn_ft_parse(disc, buf, len);
if (error)
fc_disc_error(disc, fp);
else
disc->seq_count++;
}
if (error)
fc_disc_error(disc, fp);
else if (event != DISC_EV_NONE)
fc_disc_done(disc, event);
fc_frame_free(fp);
mutex_unlock(&disc->disc_mutex);
}
/**
* fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID)
* @sp: exchange sequence
* @fp: response frame
* @rdata_arg: remote port private data
*
* Locking Note: This function is called without disc mutex held.
*/
static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
void *rdata_arg)
{
struct fc_rport_priv *rdata = rdata_arg;
struct fc_rport_priv *new_rdata;
struct fc_lport *lport;
struct fc_disc *disc;
struct fc_ct_hdr *cp;
struct fc_ns_gid_pn *pn;
u64 port_name;
lport = rdata->local_port;
disc = &lport->disc;
mutex_lock(&disc->disc_mutex);
if (PTR_ERR(fp) == -FC_EX_CLOSED)
goto out;
if (IS_ERR(fp))
goto redisc;
cp = fc_frame_payload_get(fp, sizeof(*cp));
if (!cp)
goto redisc;
if (ntohs(cp->ct_cmd) == FC_FS_ACC) {
if (fr_len(fp) < sizeof(struct fc_frame_header) +
sizeof(*cp) + sizeof(*pn))
goto redisc;
pn = (struct fc_ns_gid_pn *)(cp + 1);
port_name = get_unaligned_be64(&pn->fn_wwpn);
if (rdata->ids.port_name == -1)
rdata->ids.port_name = port_name;
else if (rdata->ids.port_name != port_name) {
FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. "
"Port-id %x wwpn %llx\n",
rdata->ids.port_id, port_name);
lport->tt.rport_logoff(rdata);
new_rdata = lport->tt.rport_create(lport,
rdata->ids.port_id);
if (new_rdata) {
new_rdata->disc_id = disc->disc_id;
lport->tt.rport_login(new_rdata);
}
goto out;
}
rdata->disc_id = disc->disc_id;
lport->tt.rport_login(rdata);
} else if (ntohs(cp->ct_cmd) == FC_FS_RJT) {
FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n",
cp->ct_reason, cp->ct_explan);
lport->tt.rport_logoff(rdata);
} else {
FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n",
ntohs(cp->ct_cmd));
redisc:
fc_disc_restart(disc);
}
out:
mutex_unlock(&disc->disc_mutex);
kref_put(&rdata->kref, lport->tt.rport_destroy);
}
/**
* fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request
* @lport: local port
* @rdata: remote port private data
*
* Locking Note: This function expects that the disc_mutex is locked
* before it is called.
* On failure, an error code is returned.
*/
static int fc_disc_gpn_id_req(struct fc_lport *lport,
struct fc_rport_priv *rdata)
{
struct fc_frame *fp;
fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) +
sizeof(struct fc_ns_fid));
if (!fp)
return -ENOMEM;
if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID,
fc_disc_gpn_id_resp, rdata, lport->e_d_tov))
return -ENOMEM;
kref_get(&rdata->kref);
return 0;
}
/**
* fc_disc_single() - Discover the directory information for a single target
* @lport: FC local port
* @lport: local port
* @dp: The port to rediscover
*
* Locking Note: This function expects that the disc_mutex is locked
* before it is called.
*/
static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)
static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp)
{
struct fc_lport *lport;
struct fc_rport *new_rport;
struct fc_rport_libfc_priv *rdata;
struct fc_rport_priv *rdata;
lport = disc->lport;
if (dp->ids.port_id == fc_host_port_id(lport->host))
goto out;
new_rport = lport->tt.rport_create(dp);
if (new_rport) {
rdata = new_rport->dd_data;
rdata->ops = &fc_disc_rport_ops;
kfree(dp);
list_add_tail(&rdata->peers, &disc->rogue_rports);
lport->tt.rport_login(new_rport);
}
return;
out:
kfree(dp);
rdata = lport->tt.rport_create(lport, dp->port_id);
if (!rdata)
return -ENOMEM;
rdata->disc_id = 0;
return fc_disc_gpn_id_req(lport, rdata);
}
/**
@ -841,18 +726,12 @@ int fc_disc_init(struct fc_lport *lport)
if (!lport->tt.disc_recv_req)
lport->tt.disc_recv_req = fc_disc_recv_req;
if (!lport->tt.rport_lookup)
lport->tt.rport_lookup = fc_disc_lookup_rport;
disc = &lport->disc;
INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
mutex_init(&disc->disc_mutex);
INIT_LIST_HEAD(&disc->rports);
INIT_LIST_HEAD(&disc->rogue_rports);
disc->lport = lport;
disc->delay = FC_DISC_DELAY;
disc->event = DISC_EV_NONE;
return 0;
}

View file

@ -32,7 +32,7 @@
* fc_elsct_send - sends ELS/CT frame
*/
static struct fc_seq *fc_elsct_send(struct fc_lport *lport,
struct fc_rport *rport,
u32 did,
struct fc_frame *fp,
unsigned int op,
void (*resp)(struct fc_seq *,
@ -41,16 +41,17 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport,
void *arg, u32 timer_msec)
{
enum fc_rctl r_ctl;
u32 did = FC_FID_NONE;
enum fc_fh_type fh_type;
int rc;
/* ELS requests */
if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS))
rc = fc_els_fill(lport, rport, fp, op, &r_ctl, &did, &fh_type);
else
rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type);
else {
/* CT requests */
rc = fc_ct_fill(lport, fp, op, &r_ctl, &did, &fh_type);
rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type);
did = FC_FID_DIR_SERV;
}
if (rc)
return NULL;
@ -69,3 +70,41 @@ int fc_elsct_init(struct fc_lport *lport)
return 0;
}
EXPORT_SYMBOL(fc_elsct_init);
/**
* fc_els_resp_type() - return string describing ELS response for debug.
* @fp: frame pointer with possible error code.
*/
const char *fc_els_resp_type(struct fc_frame *fp)
{
const char *msg;
if (IS_ERR(fp)) {
switch (-PTR_ERR(fp)) {
case FC_NO_ERR:
msg = "response no error";
break;
case FC_EX_TIMEOUT:
msg = "response timeout";
break;
case FC_EX_CLOSED:
msg = "response closed";
break;
default:
msg = "response unknown error";
break;
}
} else {
switch (fc_frame_payload_op(fp)) {
case ELS_LS_ACC:
msg = "accept";
break;
case ELS_LS_RJT:
msg = "reject";
break;
default:
msg = "response unknown ELS";
break;
}
}
return msg;
}

View file

@ -32,6 +32,9 @@
#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
u16 fc_cpu_mask; /* cpu mask for possible cpus */
EXPORT_SYMBOL(fc_cpu_mask);
static u16 fc_cpu_order; /* 2's power to represent total possible cpus */
static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
/*
@ -47,6 +50,20 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
* fc_seq holds the state for an individual sequence.
*/
/*
* Per cpu exchange pool
*
* This structure manages per cpu exchanges in array of exchange pointers.
* This array is allocated followed by struct fc_exch_pool memory for
* assigned range of exchanges to per cpu pool.
*/
struct fc_exch_pool {
u16 next_index; /* next possible free exchange index */
u16 total_exches; /* total allocated exchanges */
spinlock_t lock; /* exch pool lock */
struct list_head ex_list; /* allocated exchanges list */
};
/*
* Exchange manager.
*
@ -55,17 +72,13 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */
*/
struct fc_exch_mgr {
enum fc_class class; /* default class for sequences */
spinlock_t em_lock; /* exchange manager lock,
must be taken before ex_lock */
u16 last_xid; /* last allocated exchange ID */
struct kref kref; /* exchange mgr reference count */
u16 min_xid; /* min exchange ID */
u16 max_xid; /* max exchange ID */
u16 max_read; /* max exchange ID for read */
u16 last_read; /* last xid allocated for read */
u32 total_exches; /* total allocated exchanges */
struct list_head ex_list; /* allocated exchanges list */
struct fc_lport *lp; /* fc device instance */
mempool_t *ep_pool; /* reserve ep's */
u16 pool_max_index; /* max exch array index in exch pool */
struct fc_exch_pool *pool; /* per cpu exch pool */
/*
* currently exchange mgr stats are updated but not used.
@ -80,10 +93,15 @@ struct fc_exch_mgr {
atomic_t seq_not_found;
atomic_t non_bls_resp;
} stats;
struct fc_exch **exches; /* for exch pointers indexed by xid */
};
#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq)
struct fc_exch_mgr_anchor {
struct list_head ema_list;
struct fc_exch_mgr *mp;
bool (*match)(struct fc_frame *);
};
static void fc_exch_rrq(struct fc_exch *);
static void fc_seq_ls_acc(struct fc_seq *);
static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason,
@ -167,8 +185,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp);
* sequence allocation and deallocation must be locked.
* - exchange refcnt can be done atomicly without locks.
* - sequence allocation must be locked by exch lock.
* - If the em_lock and ex_lock must be taken at the same time, then the
* em_lock must be taken before the ex_lock.
* - If the EM pool lock and ex_lock must be taken at the same time, then the
* EM pool lock must be taken before the ex_lock.
*/
/*
@ -268,8 +286,6 @@ static void fc_exch_release(struct fc_exch *ep)
mp = ep->em;
if (ep->destructor)
ep->destructor(&ep->seq, ep->arg);
if (ep->lp->tt.exch_put)
ep->lp->tt.exch_put(ep->lp, mp, ep->xid);
WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE));
mempool_free(ep, mp->ep_pool);
}
@ -299,17 +315,31 @@ static int fc_exch_done_locked(struct fc_exch *ep)
return rc;
}
static void fc_exch_mgr_delete_ep(struct fc_exch *ep)
static inline struct fc_exch *fc_exch_ptr_get(struct fc_exch_pool *pool,
u16 index)
{
struct fc_exch_mgr *mp;
struct fc_exch **exches = (struct fc_exch **)(pool + 1);
return exches[index];
}
mp = ep->em;
spin_lock_bh(&mp->em_lock);
WARN_ON(mp->total_exches <= 0);
mp->total_exches--;
mp->exches[ep->xid - mp->min_xid] = NULL;
static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index,
struct fc_exch *ep)
{
((struct fc_exch **)(pool + 1))[index] = ep;
}
static void fc_exch_delete(struct fc_exch *ep)
{
struct fc_exch_pool *pool;
pool = ep->pool;
spin_lock_bh(&pool->lock);
WARN_ON(pool->total_exches <= 0);
pool->total_exches--;
fc_exch_ptr_set(pool, (ep->xid - ep->em->min_xid) >> fc_cpu_order,
NULL);
list_del(&ep->ex_list);
spin_unlock_bh(&mp->em_lock);
spin_unlock_bh(&pool->lock);
fc_exch_release(ep); /* drop hold for exch in mp */
}
@ -322,7 +352,7 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep,
if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE))
return;
FC_EXCH_DBG(ep, "Exchange timed out, notifying the upper layer\n");
FC_EXCH_DBG(ep, "Exchange timer armed\n");
if (schedule_delayed_work(&ep->timeout_work,
msecs_to_jiffies(timer_msec)))
@ -408,6 +438,8 @@ static void fc_exch_timeout(struct work_struct *work)
u32 e_stat;
int rc = 1;
FC_EXCH_DBG(ep, "Exchange timed out\n");
spin_lock_bh(&ep->ex_lock);
if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE))
goto unlock;
@ -427,7 +459,7 @@ static void fc_exch_timeout(struct work_struct *work)
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
if (!rc)
fc_exch_mgr_delete_ep(ep);
fc_exch_delete(ep);
if (resp)
resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg);
fc_seq_exch_abort(sp, 2 * ep->r_a_tov);
@ -460,65 +492,20 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id)
return sp;
}
/*
* fc_em_alloc_xid - returns an xid based on request type
* @lp : ptr to associated lport
* @fp : ptr to the assocated frame
/**
* fc_exch_em_alloc() - allocate an exchange from a specified EM.
* @lport: ptr to the local port
* @mp: ptr to the exchange manager
*
* check the associated fc_fsp_pkt to get scsi command type and
* command direction to decide from which range this exch id
* will be allocated from.
*
* Returns : 0 or an valid xid
* Returns pointer to allocated fc_exch with exch lock held.
*/
static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp)
{
u16 xid, min, max;
u16 *plast;
struct fc_exch *ep = NULL;
if (mp->max_read) {
if (fc_fcp_is_read(fr_fsp(fp))) {
min = mp->min_xid;
max = mp->max_read;
plast = &mp->last_read;
} else {
min = mp->max_read + 1;
max = mp->max_xid;
plast = &mp->last_xid;
}
} else {
min = mp->min_xid;
max = mp->max_xid;
plast = &mp->last_xid;
}
xid = *plast;
do {
xid = (xid == max) ? min : xid + 1;
ep = mp->exches[xid - mp->min_xid];
} while ((ep != NULL) && (xid != *plast));
if (unlikely(ep))
xid = 0;
else
*plast = xid;
return xid;
}
/*
* fc_exch_alloc - allocate an exchange.
* @mp : ptr to the exchange manager
* @xid: input xid
*
* if xid is supplied zero then assign next free exchange ID
* from exchange manager, otherwise use supplied xid.
* Returns with exch lock held.
*/
struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
struct fc_frame *fp, u16 xid)
static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
struct fc_exch_mgr *mp)
{
struct fc_exch *ep;
unsigned int cpu;
u16 index;
struct fc_exch_pool *pool;
/* allocate memory for exchange */
ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC);
@ -528,16 +515,17 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
}
memset(ep, 0, sizeof(*ep));
spin_lock_bh(&mp->em_lock);
/* alloc xid if input xid 0 */
if (!xid) {
/* alloc a new xid */
xid = fc_em_alloc_xid(mp, fp);
if (!xid) {
printk(KERN_WARNING "libfc: Failed to allocate an exhange\n");
cpu = smp_processor_id();
pool = per_cpu_ptr(mp->pool, cpu);
spin_lock_bh(&pool->lock);
index = pool->next_index;
/* allocate new exch from pool */
while (fc_exch_ptr_get(pool, index)) {
index = index == mp->pool_max_index ? 0 : index + 1;
if (index == pool->next_index)
goto err;
}
}
pool->next_index = index == mp->pool_max_index ? 0 : index + 1;
fc_exch_hold(ep); /* hold for exch in mp */
spin_lock_init(&ep->ex_lock);
@ -548,18 +536,19 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
*/
spin_lock_bh(&ep->ex_lock);
mp->exches[xid - mp->min_xid] = ep;
list_add_tail(&ep->ex_list, &mp->ex_list);
fc_exch_ptr_set(pool, index, ep);
list_add_tail(&ep->ex_list, &pool->ex_list);
fc_seq_alloc(ep, ep->seq_id++);
mp->total_exches++;
spin_unlock_bh(&mp->em_lock);
pool->total_exches++;
spin_unlock_bh(&pool->lock);
/*
* update exchange
*/
ep->oxid = ep->xid = xid;
ep->oxid = ep->xid = (index << fc_cpu_order | cpu) + mp->min_xid;
ep->em = mp;
ep->lp = mp->lp;
ep->pool = pool;
ep->lp = lport;
ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */
ep->rxid = FC_XID_UNKNOWN;
ep->class = mp->class;
@ -567,11 +556,36 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
out:
return ep;
err:
spin_unlock_bh(&mp->em_lock);
spin_unlock_bh(&pool->lock);
atomic_inc(&mp->stats.no_free_exch_xid);
mempool_free(ep, mp->ep_pool);
return NULL;
}
/**
* fc_exch_alloc() - allocate an exchange.
* @lport: ptr to the local port
* @fp: ptr to the FC frame
*
* This function walks the list of the exchange manager(EM)
* anchors to select a EM for new exchange allocation. The
* EM is selected having either a NULL match function pointer
* or call to match function returning true.
*/
struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_exch_mgr_anchor *ema;
struct fc_exch *ep;
list_for_each_entry(ema, &lport->ema_list, ema_list) {
if (!ema->match || ema->match(fp)) {
ep = fc_exch_em_alloc(lport, ema->mp);
if (ep)
return ep;
}
}
return NULL;
}
EXPORT_SYMBOL(fc_exch_alloc);
/*
@ -579,16 +593,18 @@ EXPORT_SYMBOL(fc_exch_alloc);
*/
static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid)
{
struct fc_exch_pool *pool;
struct fc_exch *ep = NULL;
if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) {
spin_lock_bh(&mp->em_lock);
ep = mp->exches[xid - mp->min_xid];
pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask);
spin_lock_bh(&pool->lock);
ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order);
if (ep) {
fc_exch_hold(ep);
WARN_ON(ep->xid != xid);
}
spin_unlock_bh(&mp->em_lock);
spin_unlock_bh(&pool->lock);
}
return ep;
}
@ -602,7 +618,7 @@ void fc_exch_done(struct fc_seq *sp)
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
if (!rc)
fc_exch_mgr_delete_ep(ep);
fc_exch_delete(ep);
}
EXPORT_SYMBOL(fc_exch_done);
@ -610,12 +626,14 @@ EXPORT_SYMBOL(fc_exch_done);
* Allocate a new exchange as responder.
* Sets the responder ID in the frame header.
*/
static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
static struct fc_exch *fc_exch_resp(struct fc_lport *lport,
struct fc_exch_mgr *mp,
struct fc_frame *fp)
{
struct fc_exch *ep;
struct fc_frame_header *fh;
ep = mp->lp->tt.exch_get(mp->lp, fp);
ep = fc_exch_alloc(lport, fp);
if (ep) {
ep->class = fc_frame_class(fp);
@ -641,7 +659,7 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
ep->esb_stat &= ~ESB_ST_SEQ_INIT;
fc_exch_hold(ep); /* hold for caller */
spin_unlock_bh(&ep->ex_lock); /* lock from exch_get */
spin_unlock_bh(&ep->ex_lock); /* lock from fc_exch_alloc */
}
return ep;
}
@ -651,7 +669,8 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
* If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold
* on the ep that should be released by the caller.
*/
static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp,
static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport,
struct fc_exch_mgr *mp,
struct fc_frame *fp)
{
struct fc_frame_header *fh = fc_frame_header_get(fp);
@ -705,7 +724,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp,
reject = FC_RJT_RX_ID;
goto rel;
}
ep = fc_exch_resp(mp, fp);
ep = fc_exch_resp(lport, mp, fp);
if (!ep) {
reject = FC_RJT_EXCH_EST; /* XXX */
goto out;
@ -822,7 +841,6 @@ struct fc_seq *fc_seq_start_next(struct fc_seq *sp)
struct fc_exch *ep = fc_seq_exch(sp);
spin_lock_bh(&ep->ex_lock);
WARN_ON((ep->esb_stat & ESB_ST_COMPLETE) != 0);
sp = fc_seq_start_next_locked(sp);
spin_unlock_bh(&ep->ex_lock);
@ -999,8 +1017,8 @@ static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp,
*/
memcpy(fh->fh_s_id, rx_fh->fh_d_id, 3);
memcpy(fh->fh_d_id, rx_fh->fh_s_id, 3);
fh->fh_ox_id = rx_fh->fh_rx_id;
fh->fh_rx_id = rx_fh->fh_ox_id;
fh->fh_ox_id = rx_fh->fh_ox_id;
fh->fh_rx_id = rx_fh->fh_rx_id;
fh->fh_seq_cnt = rx_fh->fh_seq_cnt;
fh->fh_r_ctl = FC_RCTL_BA_RJT;
fh->fh_type = FC_TYPE_BLS;
@ -1097,7 +1115,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp,
enum fc_pf_rjt_reason reject;
fr_seq(fp) = NULL;
reject = fc_seq_lookup_recip(mp, fp);
reject = fc_seq_lookup_recip(lp, mp, fp);
if (reject == FC_RJT_NONE) {
sp = fr_seq(fp); /* sequence will be held */
ep = fc_seq_exch(sp);
@ -1123,7 +1141,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp,
lp->tt.lport_recv(lp, sp, fp);
fc_exch_release(ep); /* release from lookup */
} else {
FC_EM_DBG(mp, "exch/seq lookup failed: reject %x\n", reject);
FC_LPORT_DBG(lp, "exch/seq lookup failed: reject %x\n", reject);
fc_frame_free(fp);
}
}
@ -1193,7 +1211,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
WARN_ON(fc_seq_exch(sp) != ep);
spin_unlock_bh(&ep->ex_lock);
if (!rc)
fc_exch_mgr_delete_ep(ep);
fc_exch_delete(ep);
}
/*
@ -1229,13 +1247,12 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
struct fc_seq *sp;
sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */
if (!sp) {
if (!sp)
atomic_inc(&mp->stats.xid_not_found);
FC_EM_DBG(mp, "seq lookup failed\n");
} else {
else
atomic_inc(&mp->stats.non_bls_resp);
FC_EM_DBG(mp, "non-BLS response to sequence");
}
fc_frame_free(fp);
}
@ -1304,7 +1321,7 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp)
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
if (!rc)
fc_exch_mgr_delete_ep(ep);
fc_exch_delete(ep);
if (resp)
resp(sp, fp, ex_resp_arg);
@ -1447,44 +1464,77 @@ static void fc_exch_reset(struct fc_exch *ep)
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
if (!rc)
fc_exch_mgr_delete_ep(ep);
fc_exch_delete(ep);
if (resp)
resp(sp, ERR_PTR(-FC_EX_CLOSED), arg);
}
/*
* Reset an exchange manager, releasing all sequences and exchanges.
* If sid is non-zero, reset only exchanges we source from that FID.
* If did is non-zero, reset only exchanges destined to that FID.
/**
* fc_exch_pool_reset() - Resets an per cpu exches pool.
* @lport: ptr to the local port
* @pool: ptr to the per cpu exches pool
* @sid: source FC ID
* @did: destination FC ID
*
* Resets an per cpu exches pool, releasing its all sequences
* and exchanges. If sid is non-zero, then reset only exchanges
* we sourced from that FID. If did is non-zero, reset only
* exchanges destined to that FID.
*/
void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did)
static void fc_exch_pool_reset(struct fc_lport *lport,
struct fc_exch_pool *pool,
u32 sid, u32 did)
{
struct fc_exch *ep;
struct fc_exch *next;
struct fc_exch_mgr *mp = lp->emp;
spin_lock_bh(&mp->em_lock);
spin_lock_bh(&pool->lock);
restart:
list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) {
if ((sid == 0 || sid == ep->sid) &&
list_for_each_entry_safe(ep, next, &pool->ex_list, ex_list) {
if ((lport == ep->lp) &&
(sid == 0 || sid == ep->sid) &&
(did == 0 || did == ep->did)) {
fc_exch_hold(ep);
spin_unlock_bh(&mp->em_lock);
spin_unlock_bh(&pool->lock);
fc_exch_reset(ep);
fc_exch_release(ep);
spin_lock_bh(&mp->em_lock);
spin_lock_bh(&pool->lock);
/*
* must restart loop incase while lock was down
* multiple eps were released.
* must restart loop incase while lock
* was down multiple eps were released.
*/
goto restart;
}
}
spin_unlock_bh(&mp->em_lock);
spin_unlock_bh(&pool->lock);
}
/**
* fc_exch_mgr_reset() - Resets all EMs of a lport
* @lport: ptr to the local port
* @sid: source FC ID
* @did: destination FC ID
*
* Reset all EMs of a lport, releasing its all sequences and
* exchanges. If sid is non-zero, then reset only exchanges
* we sourced from that FID. If did is non-zero, reset only
* exchanges destined to that FID.
*/
void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did)
{
struct fc_exch_mgr_anchor *ema;
unsigned int cpu;
list_for_each_entry(ema, &lport->ema_list, ema_list) {
for_each_possible_cpu(cpu)
fc_exch_pool_reset(lport,
per_cpu_ptr(ema->mp->pool, cpu),
sid, did);
}
}
EXPORT_SYMBOL(fc_exch_mgr_reset);
@ -1730,85 +1780,129 @@ reject:
fc_frame_free(fp);
}
struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport,
struct fc_exch_mgr *mp,
bool (*match)(struct fc_frame *))
{
struct fc_exch_mgr_anchor *ema;
ema = kmalloc(sizeof(*ema), GFP_ATOMIC);
if (!ema)
return ema;
ema->mp = mp;
ema->match = match;
/* add EM anchor to EM anchors list */
list_add_tail(&ema->ema_list, &lport->ema_list);
kref_get(&mp->kref);
return ema;
}
EXPORT_SYMBOL(fc_exch_mgr_add);
static void fc_exch_mgr_destroy(struct kref *kref)
{
struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref);
mempool_destroy(mp->ep_pool);
free_percpu(mp->pool);
kfree(mp);
}
void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema)
{
/* remove EM anchor from EM anchors list */
list_del(&ema->ema_list);
kref_put(&ema->mp->kref, fc_exch_mgr_destroy);
kfree(ema);
}
EXPORT_SYMBOL(fc_exch_mgr_del);
struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
enum fc_class class,
u16 min_xid, u16 max_xid)
u16 min_xid, u16 max_xid,
bool (*match)(struct fc_frame *))
{
struct fc_exch_mgr *mp;
size_t len;
u16 pool_exch_range;
size_t pool_size;
unsigned int cpu;
struct fc_exch_pool *pool;
if (max_xid <= min_xid || min_xid == 0 || max_xid == FC_XID_UNKNOWN) {
if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN ||
(min_xid & fc_cpu_mask) != 0) {
FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n",
min_xid, max_xid);
return NULL;
}
/*
* Memory need for EM
* allocate memory for EM
*/
#define xid_ok(i, m1, m2) (((i) >= (m1)) && ((i) <= (m2)))
len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *));
len += sizeof(struct fc_exch_mgr);
mp = kzalloc(len, GFP_ATOMIC);
mp = kzalloc(sizeof(struct fc_exch_mgr), GFP_ATOMIC);
if (!mp)
return NULL;
mp->class = class;
mp->total_exches = 0;
mp->exches = (struct fc_exch **)(mp + 1);
mp->lp = lp;
/* adjust em exch xid range for offload */
mp->min_xid = min_xid;
mp->max_xid = max_xid;
mp->last_xid = min_xid - 1;
mp->max_read = 0;
mp->last_read = 0;
if (lp->lro_enabled && xid_ok(lp->lro_xid, min_xid, max_xid)) {
mp->max_read = lp->lro_xid;
mp->last_read = min_xid - 1;
mp->last_xid = mp->max_read;
} else {
/* disable lro if no xid control over read */
lp->lro_enabled = 0;
}
INIT_LIST_HEAD(&mp->ex_list);
spin_lock_init(&mp->em_lock);
mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep);
if (!mp->ep_pool)
goto free_mp;
/*
* Setup per cpu exch pool with entire exchange id range equally
* divided across all cpus. The exch pointers array memory is
* allocated for exch range per pool.
*/
pool_exch_range = (mp->max_xid - mp->min_xid + 1) / (fc_cpu_mask + 1);
mp->pool_max_index = pool_exch_range - 1;
/*
* Allocate and initialize per cpu exch pool
*/
pool_size = sizeof(*pool) + pool_exch_range * sizeof(struct fc_exch *);
mp->pool = __alloc_percpu(pool_size, __alignof__(struct fc_exch_pool));
if (!mp->pool)
goto free_mempool;
for_each_possible_cpu(cpu) {
pool = per_cpu_ptr(mp->pool, cpu);
spin_lock_init(&pool->lock);
INIT_LIST_HEAD(&pool->ex_list);
}
kref_init(&mp->kref);
if (!fc_exch_mgr_add(lp, mp, match)) {
free_percpu(mp->pool);
goto free_mempool;
}
/*
* Above kref_init() sets mp->kref to 1 and then
* call to fc_exch_mgr_add incremented mp->kref again,
* so adjust that extra increment.
*/
kref_put(&mp->kref, fc_exch_mgr_destroy);
return mp;
free_mempool:
mempool_destroy(mp->ep_pool);
free_mp:
kfree(mp);
return NULL;
}
EXPORT_SYMBOL(fc_exch_mgr_alloc);
void fc_exch_mgr_free(struct fc_exch_mgr *mp)
void fc_exch_mgr_free(struct fc_lport *lport)
{
WARN_ON(!mp);
/*
* The total exch count must be zero
* before freeing exchange manager.
*/
WARN_ON(mp->total_exches != 0);
mempool_destroy(mp->ep_pool);
kfree(mp);
struct fc_exch_mgr_anchor *ema, *next;
list_for_each_entry_safe(ema, next, &lport->ema_list, ema_list)
fc_exch_mgr_del(ema);
}
EXPORT_SYMBOL(fc_exch_mgr_free);
struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp)
{
if (!lp || !lp->emp)
return NULL;
return fc_exch_alloc(lp->emp, fp, 0);
}
EXPORT_SYMBOL(fc_exch_get);
struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
struct fc_frame *fp,
@ -1823,7 +1917,7 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
struct fc_frame_header *fh;
int rc = 1;
ep = lp->tt.exch_get(lp, fp);
ep = fc_exch_alloc(lp, fp);
if (!ep) {
fc_frame_free(fp);
return NULL;
@ -1843,7 +1937,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp,
fc_exch_setup_hdr(ep, fp, ep->f_ctl);
sp->cnt++;
fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
if (ep->xid <= lp->lro_xid)
fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
if (unlikely(lp->tt.frame_send(lp, fp)))
goto err;
@ -1860,7 +1955,7 @@ err:
rc = fc_exch_done_locked(ep);
spin_unlock_bh(&ep->ex_lock);
if (!rc)
fc_exch_mgr_delete_ep(ep);
fc_exch_delete(ep);
return NULL;
}
EXPORT_SYMBOL(fc_exch_seq_send);
@ -1868,24 +1963,44 @@ EXPORT_SYMBOL(fc_exch_seq_send);
/*
* Receive a frame
*/
void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,
struct fc_frame *fp)
void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp)
{
struct fc_frame_header *fh = fc_frame_header_get(fp);
u32 f_ctl;
struct fc_exch_mgr_anchor *ema;
u32 f_ctl, found = 0;
u16 oxid;
/* lport lock ? */
if (!lp || !mp || (lp->state == LPORT_ST_NONE)) {
if (!lp || lp->state == LPORT_ST_DISABLED) {
FC_LPORT_DBG(lp, "Receiving frames for an lport that "
"has not been initialized correctly\n");
fc_frame_free(fp);
return;
}
f_ctl = ntoh24(fh->fh_f_ctl);
oxid = ntohs(fh->fh_ox_id);
if (f_ctl & FC_FC_EX_CTX) {
list_for_each_entry(ema, &lp->ema_list, ema_list) {
if ((oxid >= ema->mp->min_xid) &&
(oxid <= ema->mp->max_xid)) {
found = 1;
break;
}
}
if (!found) {
FC_LPORT_DBG(lp, "Received response for out "
"of range oxid:%hx\n", oxid);
fc_frame_free(fp);
return;
}
} else
ema = list_entry(lp->ema_list.prev, typeof(*ema), ema_list);
/*
* If frame is marked invalid, just drop it.
*/
f_ctl = ntoh24(fh->fh_f_ctl);
switch (fr_eof(fp)) {
case FC_EOF_T:
if (f_ctl & FC_FC_END_SEQ)
@ -1893,34 +2008,24 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,
/* fall through */
case FC_EOF_N:
if (fh->fh_type == FC_TYPE_BLS)
fc_exch_recv_bls(mp, fp);
fc_exch_recv_bls(ema->mp, fp);
else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) ==
FC_FC_EX_CTX)
fc_exch_recv_seq_resp(mp, fp);
fc_exch_recv_seq_resp(ema->mp, fp);
else if (f_ctl & FC_FC_SEQ_CTX)
fc_exch_recv_resp(mp, fp);
fc_exch_recv_resp(ema->mp, fp);
else
fc_exch_recv_req(lp, mp, fp);
fc_exch_recv_req(lp, ema->mp, fp);
break;
default:
FC_EM_DBG(mp, "dropping invalid frame (eof %x)", fr_eof(fp));
FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp));
fc_frame_free(fp);
break;
}
}
EXPORT_SYMBOL(fc_exch_recv);
int fc_exch_init(struct fc_lport *lp)
{
if (!lp->tt.exch_get) {
/*
* exch_put() should be NULL if
* exch_get() is NULL
*/
WARN_ON(lp->tt.exch_put);
lp->tt.exch_get = fc_exch_get;
}
if (!lp->tt.seq_start_next)
lp->tt.seq_start_next = fc_seq_start_next;
@ -1942,6 +2047,28 @@ int fc_exch_init(struct fc_lport *lp)
if (!lp->tt.seq_exch_abort)
lp->tt.seq_exch_abort = fc_seq_exch_abort;
/*
* Initialize fc_cpu_mask and fc_cpu_order. The
* fc_cpu_mask is set for nr_cpu_ids rounded up
* to order of 2's * power and order is stored
* in fc_cpu_order as this is later required in
* mapping between an exch id and exch array index
* in per cpu exch pool.
*
* This round up is required to align fc_cpu_mask
* to exchange id's lower bits such that all incoming
* frames of an exchange gets delivered to the same
* cpu on which exchange originated by simple bitwise
* AND operation between fc_cpu_mask and exchange id.
*/
fc_cpu_mask = 1;
fc_cpu_order = 0;
while (fc_cpu_mask < nr_cpu_ids) {
fc_cpu_mask <<= 1;
fc_cpu_order++;
}
fc_cpu_mask--;
return 0;
}
EXPORT_SYMBOL(fc_exch_init);

View file

@ -507,33 +507,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
f_ctl = FC_FC_REL_OFF;
WARN_ON(!seq);
/*
* If a get_page()/put_page() will fail, don't use sg lists
* in the fc_frame structure.
*
* The put_page() may be long after the I/O has completed
* in the case of FCoE, since the network driver does it
* via free_skb(). See the test in free_pages_check().
*
* Test this case with 'dd </dev/zero >/dev/st0 bs=64k'.
*/
if (using_sg) {
for (sg = scsi_sglist(sc); sg; sg = sg_next(sg)) {
if (page_count(sg_page(sg)) == 0 ||
(sg_page(sg)->flags & (1 << PG_lru |
1 << PG_private |
1 << PG_locked |
1 << PG_active |
1 << PG_slab |
1 << PG_swapcache |
1 << PG_writeback |
1 << PG_reserved |
1 << PG_buddy))) {
using_sg = 0;
break;
}
}
}
sg = scsi_sglist(sc);
while (remaining > 0 && sg) {
@ -569,8 +542,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
}
sg_bytes = min(tlen, sg->length - offset);
if (using_sg) {
WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags >
FC_FRAME_SG_LEN);
get_page(sg_page(sg));
skb_fill_page_desc(fp_skb(fp),
skb_shinfo(fp_skb(fp))->nr_frags,
@ -1337,7 +1308,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id,
fc_host_port_id(rp->local_port->host), FC_TYPE_ELS,
FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
if (lp->tt.elsct_send(lp, rport, fp, ELS_REC, fc_fcp_rec_resp,
if (lp->tt.elsct_send(lp, rport->port_id, fp, ELS_REC, fc_fcp_rec_resp,
fsp, jiffies_to_msecs(FC_SCSI_REC_TOV))) {
fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */
return;

View file

@ -113,7 +113,7 @@ static void fc_lport_enter_ready(struct fc_lport *);
static void fc_lport_enter_logo(struct fc_lport *);
static const char *fc_lport_state_names[] = {
[LPORT_ST_NONE] = "none",
[LPORT_ST_DISABLED] = "disabled",
[LPORT_ST_FLOGI] = "FLOGI",
[LPORT_ST_DNS] = "dNS",
[LPORT_ST_RPN_ID] = "RPN_ID",
@ -133,57 +133,44 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp)
/**
* fc_lport_rport_callback() - Event handler for rport events
* @lport: The lport which is receiving the event
* @rport: The rport which the event has occured on
* @rdata: private remote port data
* @event: The event that occured
*
* Locking Note: The rport lock should not be held when calling
* this function.
*/
static void fc_lport_rport_callback(struct fc_lport *lport,
struct fc_rport *rport,
struct fc_rport_priv *rdata,
enum fc_rport_event event)
{
FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event,
rport->port_id);
rdata->ids.port_id);
mutex_lock(&lport->lp_mutex);
switch (event) {
case RPORT_EV_CREATED:
if (rport->port_id == FC_FID_DIR_SERV) {
mutex_lock(&lport->lp_mutex);
if (lport->state == LPORT_ST_DNS) {
lport->dns_rp = rport;
fc_lport_enter_rpn_id(lport);
} else {
FC_LPORT_DBG(lport, "Received an CREATED event "
"on port (%6x) for the directory "
"server, but the lport is not "
"in the DNS state, it's in the "
"%d state", rport->port_id,
lport->state);
lport->tt.rport_logoff(rport);
}
mutex_unlock(&lport->lp_mutex);
} else
FC_LPORT_DBG(lport, "Received an event for port (%6x) "
"which is not the directory server\n",
rport->port_id);
case RPORT_EV_READY:
if (lport->state == LPORT_ST_DNS) {
lport->dns_rp = rdata;
fc_lport_enter_rpn_id(lport);
} else {
FC_LPORT_DBG(lport, "Received an READY event "
"on port (%6x) for the directory "
"server, but the lport is not "
"in the DNS state, it's in the "
"%d state", rdata->ids.port_id,
lport->state);
lport->tt.rport_logoff(rdata);
}
break;
case RPORT_EV_LOGO:
case RPORT_EV_FAILED:
case RPORT_EV_STOP:
if (rport->port_id == FC_FID_DIR_SERV) {
mutex_lock(&lport->lp_mutex);
lport->dns_rp = NULL;
mutex_unlock(&lport->lp_mutex);
} else
FC_LPORT_DBG(lport, "Received an event for port (%6x) "
"which is not the directory server\n",
rport->port_id);
lport->dns_rp = NULL;
break;
case RPORT_EV_NONE:
break;
}
mutex_unlock(&lport->lp_mutex);
}
/**
@ -211,20 +198,13 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
u32 remote_fid, u64 remote_wwpn,
u64 remote_wwnn)
{
struct fc_disc_port dp;
dp.lp = lport;
dp.ids.port_id = remote_fid;
dp.ids.port_name = remote_wwpn;
dp.ids.node_name = remote_wwnn;
dp.ids.roles = FC_RPORT_ROLE_UNKNOWN;
if (lport->ptp_rp) {
mutex_lock(&lport->disc.disc_mutex);
if (lport->ptp_rp)
lport->tt.rport_logoff(lport->ptp_rp);
lport->ptp_rp = NULL;
}
lport->ptp_rp = lport->tt.rport_create(&dp);
lport->ptp_rp = lport->tt.rport_create(lport, remote_fid);
lport->ptp_rp->ids.port_name = remote_wwpn;
lport->ptp_rp->ids.node_name = remote_wwnn;
mutex_unlock(&lport->disc.disc_mutex);
lport->tt.rport_login(lport->ptp_rp);
@ -471,56 +451,6 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
fc_frame_free(in_fp);
}
/**
* fc_lport_recv_adisc_req() - Handle received Address Discovery Request
* @lport: Fibre Channel local port recieving the ADISC
* @sp: current sequence in the ADISC exchange
* @fp: ADISC request frame
*
* Locking Note: The lport lock is expected to be held before calling
* this function.
*/
static void fc_lport_recv_adisc_req(struct fc_seq *sp, struct fc_frame *in_fp,
struct fc_lport *lport)
{
struct fc_frame *fp;
struct fc_exch *ep = fc_seq_exch(sp);
struct fc_els_adisc *req, *rp;
struct fc_seq_els_data rjt_data;
size_t len;
u32 f_ctl;
FC_LPORT_DBG(lport, "Received ADISC request while in state %s\n",
fc_lport_state(lport));
req = fc_frame_payload_get(in_fp, sizeof(*req));
if (!req) {
rjt_data.fp = NULL;
rjt_data.reason = ELS_RJT_LOGIC;
rjt_data.explan = ELS_EXPL_NONE;
lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
} else {
len = sizeof(*rp);
fp = fc_frame_alloc(lport, len);
if (fp) {
rp = fc_frame_payload_get(fp, len);
memset(rp, 0, len);
rp->adisc_cmd = ELS_LS_ACC;
rp->adisc_wwpn = htonll(lport->wwpn);
rp->adisc_wwnn = htonll(lport->wwnn);
hton24(rp->adisc_port_id,
fc_host_port_id(lport->host));
sp = lport->tt.seq_start_next(sp);
f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
FC_TYPE_ELS, f_ctl, 0);
lport->tt.seq_send(lport, sp, fp);
}
}
fc_frame_free(in_fp);
}
/**
* fc_lport_recv_logo_req() - Handle received fabric LOGO request
* @lport: Fibre Channel local port recieving the LOGO
@ -550,7 +480,7 @@ int fc_fabric_login(struct fc_lport *lport)
int rc = -1;
mutex_lock(&lport->lp_mutex);
if (lport->state == LPORT_ST_NONE) {
if (lport->state == LPORT_ST_DISABLED) {
fc_lport_enter_reset(lport);
rc = 0;
}
@ -637,12 +567,13 @@ EXPORT_SYMBOL(fc_fabric_logoff);
int fc_lport_destroy(struct fc_lport *lport)
{
mutex_lock(&lport->lp_mutex);
lport->state = LPORT_ST_NONE;
lport->state = LPORT_ST_DISABLED;
lport->link_up = 0;
lport->tt.frame_send = fc_frame_drop;
mutex_unlock(&lport->lp_mutex);
lport->tt.fcp_abort_io(lport);
lport->tt.disc_stop_final(lport);
lport->tt.exch_mgr_reset(lport, 0, 0);
return 0;
}
@ -722,7 +653,8 @@ static void fc_lport_enter_ready(struct fc_lport *lport)
fc_lport_state_enter(lport, LPORT_ST_READY);
lport->tt.disc_start(fc_lport_disc_callback, lport);
if (!lport->ptp_rp)
lport->tt.disc_start(fc_lport_disc_callback, lport);
}
/**
@ -808,8 +740,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
fc_lport_ptp_setup(lport, remote_fid, remote_wwpn,
get_unaligned_be64(&flp->fl_wwnn));
lport->tt.disc_start(fc_lport_disc_callback, lport);
out:
sp = fr_seq(rx_fp);
fc_frame_free(rx_fp);
@ -832,10 +762,6 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
{
struct fc_frame_header *fh = fc_frame_header_get(fp);
void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *);
struct fc_rport *rport;
u32 s_id;
u32 d_id;
struct fc_seq_els_data rjt_data;
mutex_lock(&lport->lp_mutex);
@ -844,11 +770,14 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
* RSCN here. These don't require a session.
* Even if we had a session, it might not be ready.
*/
if (fh->fh_type == FC_TYPE_ELS && fh->fh_r_ctl == FC_RCTL_ELS_REQ) {
if (!lport->link_up)
fc_frame_free(fp);
else if (fh->fh_type == FC_TYPE_ELS &&
fh->fh_r_ctl == FC_RCTL_ELS_REQ) {
/*
* Check opcode.
*/
recv = NULL;
recv = lport->tt.rport_recv_req;
switch (fc_frame_payload_op(fp)) {
case ELS_FLOGI:
recv = fc_lport_recv_flogi_req;
@ -870,34 +799,9 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
case ELS_RNID:
recv = fc_lport_recv_rnid_req;
break;
case ELS_ADISC:
recv = fc_lport_recv_adisc_req;
break;
}
if (recv)
recv(sp, fp, lport);
else {
/*
* Find session.
* If this is a new incoming PLOGI, we won't find it.
*/
s_id = ntoh24(fh->fh_s_id);
d_id = ntoh24(fh->fh_d_id);
rport = lport->tt.rport_lookup(lport, s_id);
if (rport)
lport->tt.rport_recv_req(sp, fp, rport);
else {
rjt_data.fp = NULL;
rjt_data.reason = ELS_RJT_UNAB;
rjt_data.explan = ELS_EXPL_NONE;
lport->tt.seq_els_rsp_send(sp,
ELS_LS_RJT,
&rjt_data);
fc_frame_free(fp);
}
}
recv(sp, fp, lport);
} else {
FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n",
fr_eof(fp));
@ -930,7 +834,28 @@ int fc_lport_reset(struct fc_lport *lport)
EXPORT_SYMBOL(fc_lport_reset);
/**
* fc_rport_enter_reset() - Reset the local port
* fc_lport_reset_locked() - Reset the local port
* @lport: Fibre Channel local port to be reset
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
*/
static void fc_lport_reset_locked(struct fc_lport *lport)
{
if (lport->dns_rp)
lport->tt.rport_logoff(lport->dns_rp);
lport->ptp_rp = NULL;
lport->tt.disc_stop(lport);
lport->tt.exch_mgr_reset(lport, 0, 0);
fc_host_fabric_name(lport->host) = 0;
fc_host_port_id(lport->host) = 0;
}
/**
* fc_lport_enter_reset() - Reset the local port
* @lport: Fibre Channel local port to be reset
*
* Locking Note: The lport lock is expected to be held before calling
@ -942,25 +867,27 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
fc_lport_state(lport));
fc_lport_state_enter(lport, LPORT_ST_RESET);
if (lport->dns_rp)
lport->tt.rport_logoff(lport->dns_rp);
if (lport->ptp_rp) {
lport->tt.rport_logoff(lport->ptp_rp);
lport->ptp_rp = NULL;
}
lport->tt.disc_stop(lport);
lport->tt.exch_mgr_reset(lport, 0, 0);
fc_host_fabric_name(lport->host) = 0;
fc_host_port_id(lport->host) = 0;
fc_lport_reset_locked(lport);
if (lport->link_up)
fc_lport_enter_flogi(lport);
}
/**
* fc_lport_enter_disabled() - disable the local port
* @lport: Fibre Channel local port to be reset
*
* Locking Note: The lport lock is expected to be held before calling
* this routine.
*/
static void fc_lport_enter_disabled(struct fc_lport *lport)
{
FC_LPORT_DBG(lport, "Entered disabled state from %s state\n",
fc_lport_state(lport));
fc_lport_state_enter(lport, LPORT_ST_DISABLED);
fc_lport_reset_locked(lport);
}
/**
* fc_lport_error() - Handler for any errors
* @lport: The fc_lport object
@ -992,7 +919,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
schedule_delayed_work(&lport->retry_work, delay);
} else {
switch (lport->state) {
case LPORT_ST_NONE:
case LPORT_ST_DISABLED:
case LPORT_ST_READY:
case LPORT_ST_RESET:
case LPORT_ST_RPN_ID:
@ -1026,13 +953,13 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_frame_header *fh;
struct fc_ct_hdr *ct;
FC_LPORT_DBG(lport, "Received a RFT_ID %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
return;
mutex_lock(&lport->lp_mutex);
FC_LPORT_DBG(lport, "Received a RFT_ID response\n");
if (lport->state != LPORT_ST_RFT_ID) {
FC_LPORT_DBG(lport, "Received a RFT_ID response, but in state "
"%s\n", fc_lport_state(lport));
@ -1080,13 +1007,13 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_frame_header *fh;
struct fc_ct_hdr *ct;
FC_LPORT_DBG(lport, "Received a RPN_ID %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
return;
mutex_lock(&lport->lp_mutex);
FC_LPORT_DBG(lport, "Received a RPN_ID response\n");
if (lport->state != LPORT_ST_RPN_ID) {
FC_LPORT_DBG(lport, "Received a RPN_ID response, but in state "
"%s\n", fc_lport_state(lport));
@ -1132,13 +1059,13 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_lport *lport = lp_arg;
u8 op;
FC_LPORT_DBG(lport, "Received a SCR %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
return;
mutex_lock(&lport->lp_mutex);
FC_LPORT_DBG(lport, "Received a SCR response\n");
if (lport->state != LPORT_ST_SCR) {
FC_LPORT_DBG(lport, "Received a SCR response, but in state "
"%s\n", fc_lport_state(lport));
@ -1186,7 +1113,7 @@ static void fc_lport_enter_scr(struct fc_lport *lport)
return;
}
if (!lport->tt.elsct_send(lport, NULL, fp, ELS_SCR,
if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR,
fc_lport_scr_resp, lport, lport->e_d_tov))
fc_lport_error(lport, fp);
}
@ -1227,7 +1154,7 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport)
return;
}
if (!lport->tt.elsct_send(lport, NULL, fp, FC_NS_RFT_ID,
if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RFT_ID,
fc_lport_rft_id_resp,
lport, lport->e_d_tov))
fc_lport_error(lport, fp);
@ -1256,7 +1183,7 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport)
return;
}
if (!lport->tt.elsct_send(lport, NULL, fp, FC_NS_RPN_ID,
if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RPN_ID,
fc_lport_rpn_id_resp,
lport, lport->e_d_tov))
fc_lport_error(lport, fp);
@ -1275,28 +1202,21 @@ static struct fc_rport_operations fc_lport_rport_ops = {
*/
static void fc_lport_enter_dns(struct fc_lport *lport)
{
struct fc_rport *rport;
struct fc_rport_libfc_priv *rdata;
struct fc_disc_port dp;
dp.ids.port_id = FC_FID_DIR_SERV;
dp.ids.port_name = -1;
dp.ids.node_name = -1;
dp.ids.roles = FC_RPORT_ROLE_UNKNOWN;
dp.lp = lport;
struct fc_rport_priv *rdata;
FC_LPORT_DBG(lport, "Entered DNS state from %s state\n",
fc_lport_state(lport));
fc_lport_state_enter(lport, LPORT_ST_DNS);
rport = lport->tt.rport_create(&dp);
if (!rport)
mutex_lock(&lport->disc.disc_mutex);
rdata = lport->tt.rport_create(lport, FC_FID_DIR_SERV);
mutex_unlock(&lport->disc.disc_mutex);
if (!rdata)
goto err;
rdata = rport->dd_data;
rdata->ops = &fc_lport_rport_ops;
lport->tt.rport_login(rport);
lport->tt.rport_login(rdata);
return;
err:
@ -1316,7 +1236,7 @@ static void fc_lport_timeout(struct work_struct *work)
mutex_lock(&lport->lp_mutex);
switch (lport->state) {
case LPORT_ST_NONE:
case LPORT_ST_DISABLED:
case LPORT_ST_READY:
case LPORT_ST_RESET:
WARN_ON(1);
@ -1360,13 +1280,13 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
struct fc_lport *lport = lp_arg;
u8 op;
FC_LPORT_DBG(lport, "Received a LOGO %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
return;
mutex_lock(&lport->lp_mutex);
FC_LPORT_DBG(lport, "Received a LOGO response\n");
if (lport->state != LPORT_ST_LOGO) {
FC_LPORT_DBG(lport, "Received a LOGO response, but in state "
"%s\n", fc_lport_state(lport));
@ -1382,7 +1302,7 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
op = fc_frame_payload_op(fp);
if (op == ELS_LS_ACC)
fc_lport_enter_reset(lport);
fc_lport_enter_disabled(lport);
else
fc_lport_error(lport, fp);
@ -1415,8 +1335,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport)
return;
}
if (!lport->tt.elsct_send(lport, NULL, fp, ELS_LOGO, fc_lport_logo_resp,
lport, lport->e_d_tov))
if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO,
fc_lport_logo_resp, lport, lport->e_d_tov))
fc_lport_error(lport, fp);
}
@ -1442,13 +1362,13 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
unsigned int e_d_tov;
u16 mfs;
FC_LPORT_DBG(lport, "Received a FLOGI %s\n", fc_els_resp_type(fp));
if (fp == ERR_PTR(-FC_EX_CLOSED))
return;
mutex_lock(&lport->lp_mutex);
FC_LPORT_DBG(lport, "Received a FLOGI response\n");
if (lport->state != LPORT_ST_FLOGI) {
FC_LPORT_DBG(lport, "Received a FLOGI response, but in state "
"%s\n", fc_lport_state(lport));
@ -1501,14 +1421,6 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
fc_lport_enter_dns(lport);
}
}
if (flp) {
csp_flags = ntohs(flp->fl_csp.sp_features);
if ((csp_flags & FC_SP_FT_FPORT) == 0) {
lport->tt.disc_start(fc_lport_disc_callback,
lport);
}
}
} else {
FC_LPORT_DBG(lport, "Bad FLOGI response\n");
}
@ -1539,7 +1451,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
if (!fp)
return fc_lport_error(lport, fp);
if (!lport->tt.elsct_send(lport, NULL, fp, ELS_FLOGI,
if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_FLOGI,
fc_lport_flogi_resp, lport, lport->e_d_tov))
fc_lport_error(lport, fp);
}
@ -1550,7 +1462,7 @@ int fc_lport_config(struct fc_lport *lport)
INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout);
mutex_init(&lport->lp_mutex);
fc_lport_state_enter(lport, LPORT_ST_NONE);
fc_lport_state_enter(lport, LPORT_ST_DISABLED);
fc_lport_add_fc4_type(lport, FC_TYPE_FCP);
fc_lport_add_fc4_type(lport, FC_TYPE_CT);
@ -1588,6 +1500,7 @@ int fc_lport_init(struct fc_lport *lport)
if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;
INIT_LIST_HEAD(&lport->ema_list);
return 0;
}
EXPORT_SYMBOL(fc_lport_init);

File diff suppressed because it is too large Load diff

View file

@ -109,12 +109,9 @@ inline void iscsi_conn_queue_work(struct iscsi_conn *conn)
}
EXPORT_SYMBOL_GPL(iscsi_conn_queue_work);
void
iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
static void __iscsi_update_cmdsn(struct iscsi_session *session,
uint32_t exp_cmdsn, uint32_t max_cmdsn)
{
uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn);
uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn);
/*
* standard specifies this check for when to update expected and
* max sequence numbers
@ -138,6 +135,12 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
iscsi_conn_queue_work(session->leadconn);
}
}
void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
{
__iscsi_update_cmdsn(session, be32_to_cpu(hdr->exp_cmdsn),
be32_to_cpu(hdr->max_cmdsn));
}
EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
/**
@ -301,8 +304,6 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
memcpy(task->lun, hdr->lun, sizeof(task->lun));
hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
cmd_len = sc->cmd_len;
if (cmd_len < ISCSI_CDB_SIZE)
@ -388,6 +389,8 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
return -EIO;
task->state = ISCSI_TASK_RUNNING;
hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
conn->scsicmd_pdus_cnt++;
ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x "
@ -499,6 +502,31 @@ static void iscsi_complete_task(struct iscsi_task *task, int state)
__iscsi_put_task(task);
}
/**
* iscsi_complete_scsi_task - finish scsi task normally
* @task: iscsi task for scsi cmd
* @exp_cmdsn: expected cmd sn in cpu format
* @max_cmdsn: max cmd sn in cpu format
*
* This is used when drivers do not need or cannot perform
* lower level pdu processing.
*
* Called with session lock
*/
void iscsi_complete_scsi_task(struct iscsi_task *task,
uint32_t exp_cmdsn, uint32_t max_cmdsn)
{
struct iscsi_conn *conn = task->conn;
ISCSI_DBG_SESSION(conn->session, "[itt 0x%x]\n", task->itt);
conn->last_recv = jiffies;
__iscsi_update_cmdsn(conn->session, exp_cmdsn, max_cmdsn);
iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
}
EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task);
/*
* session lock must be held and if not called for a task that is
* still pending or from the xmit thread, then xmit thread must
@ -857,27 +885,102 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
}
}
static int iscsi_nop_out_rsp(struct iscsi_task *task,
struct iscsi_nopin *nop, char *data, int datalen)
{
struct iscsi_conn *conn = task->conn;
int rc = 0;
if (conn->ping_task != task) {
/*
* If this is not in response to one of our
* nops then it must be from userspace.
*/
if (iscsi_recv_pdu(conn->cls_conn, (struct iscsi_hdr *)nop,
data, datalen))
rc = ISCSI_ERR_CONN_FAILED;
} else
mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
return rc;
}
static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
char *data, int datalen)
{
struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
struct iscsi_hdr rejected_pdu;
int opcode, rc = 0;
conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) {
if (ntoh24(reject->dlength) > datalen)
return ISCSI_ERR_PROTO;
if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x) rejected "
"due to DataDigest error.\n",
rejected_pdu.opcode);
}
if (ntoh24(reject->dlength) > datalen ||
ntoh24(reject->dlength) < sizeof(struct iscsi_hdr)) {
iscsi_conn_printk(KERN_ERR, conn, "Cannot handle rejected "
"pdu. Invalid data length (pdu dlength "
"%u, datalen %d\n", ntoh24(reject->dlength),
datalen);
return ISCSI_ERR_PROTO;
}
return 0;
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
opcode = rejected_pdu.opcode & ISCSI_OPCODE_MASK;
switch (reject->reason) {
case ISCSI_REASON_DATA_DIGEST_ERROR:
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected "
"due to DataDigest error.\n",
rejected_pdu.itt, opcode);
break;
case ISCSI_REASON_IMM_CMD_REJECT:
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected. Too many "
"immediate commands.\n",
rejected_pdu.itt, opcode);
/*
* We only send one TMF at a time so if the target could not
* handle it, then it should get fixed (RFC mandates that
* a target can handle one immediate TMF per conn).
*
* For nops-outs, we could have sent more than one if
* the target is sending us lots of nop-ins
*/
if (opcode != ISCSI_OP_NOOP_OUT)
return 0;
if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG))
/*
* nop-out in response to target's nop-out rejected.
* Just resend.
*/
iscsi_send_nopout(conn,
(struct iscsi_nopin*)&rejected_pdu);
else {
struct iscsi_task *task;
/*
* Our nop as ping got dropped. We know the target
* and transport are ok so just clean up
*/
task = iscsi_itt_to_task(conn, rejected_pdu.itt);
if (!task) {
iscsi_conn_printk(KERN_ERR, conn,
"Invalid pdu reject. Could "
"not lookup rejected task.\n");
rc = ISCSI_ERR_BAD_ITT;
} else
rc = iscsi_nop_out_rsp(task,
(struct iscsi_nopin*)&rejected_pdu,
NULL, 0);
}
break;
default:
iscsi_conn_printk(KERN_ERR, conn,
"pdu (op 0x%x itt 0x%x) rejected. Reason "
"code 0x%x\n", rejected_pdu.itt,
rejected_pdu.opcode, reject->reason);
break;
}
return rc;
}
/**
@ -1038,15 +1141,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
}
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
if (conn->ping_task != task)
/*
* If this is not in response to one of our
* nops then it must be from userspace.
*/
goto recv_pdu;
mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
rc = iscsi_nop_out_rsp(task, (struct iscsi_nopin*)hdr,
data, datalen);
break;
default:
rc = ISCSI_ERR_BAD_OPCODE;
@ -1212,6 +1308,9 @@ static int iscsi_xmit_task(struct iscsi_conn *conn)
struct iscsi_task *task = conn->task;
int rc;
if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx))
return -ENODATA;
__iscsi_get_task(task);
spin_unlock_bh(&conn->session->lock);
rc = conn->session->tt->xmit_task(task);
@ -1261,7 +1360,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
int rc = 0;
spin_lock_bh(&conn->session->lock);
if (unlikely(conn->suspend_tx)) {
if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
spin_unlock_bh(&conn->session->lock);
return -ENODATA;
@ -1270,7 +1369,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
if (conn->task) {
rc = iscsi_xmit_task(conn);
if (rc)
goto again;
goto done;
}
/*
@ -1290,7 +1389,7 @@ check_mgmt:
}
rc = iscsi_xmit_task(conn);
if (rc)
goto again;
goto done;
}
/* process pending command queue */
@ -1311,14 +1410,14 @@ check_mgmt:
list_add_tail(&conn->task->running,
&conn->cmdqueue);
conn->task = NULL;
goto again;
goto done;
} else
fail_scsi_task(conn->task, DID_ABORT);
continue;
}
rc = iscsi_xmit_task(conn);
if (rc)
goto again;
goto done;
/*
* we could continuously get new task requests so
* we need to check the mgmt queue for nops that need to
@ -1344,16 +1443,14 @@ check_mgmt:
conn->task->state = ISCSI_TASK_RUNNING;
rc = iscsi_xmit_task(conn);
if (rc)
goto again;
goto done;
if (!list_empty(&conn->mgmtqueue))
goto check_mgmt;
}
spin_unlock_bh(&conn->session->lock);
return -ENODATA;
again:
if (unlikely(conn->suspend_tx))
rc = -ENODATA;
done:
spin_unlock_bh(&conn->session->lock);
return rc;
}
@ -1474,6 +1571,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
goto fault;
}
if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
reason = FAILURE_SESSION_IN_RECOVERY;
sc->result = DID_REQUEUE;
goto fault;
}
if (iscsi_check_cmdsn_window_closed(conn)) {
reason = FAILURE_WINDOW_CLOSED;
goto reject;
@ -1497,6 +1600,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
}
}
if (session->tt->xmit_task(task)) {
session->cmdsn--;
reason = FAILURE_SESSION_NOT_READY;
goto prepd_reject;
}
@ -1712,6 +1816,33 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun,
}
}
/**
* iscsi_suspend_queue - suspend iscsi_queuecommand
* @conn: iscsi conn to stop queueing IO on
*
* This grabs the session lock to make sure no one is in
* xmit_task/queuecommand, and then sets suspend to prevent
* new commands from being queued. This only needs to be called
* by offload drivers that need to sync a path like ep disconnect
* with the iscsi_queuecommand/xmit_task. To start IO again libiscsi
* will call iscsi_start_tx and iscsi_unblock_session when in FFP.
*/
void iscsi_suspend_queue(struct iscsi_conn *conn)
{
spin_lock_bh(&conn->session->lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
spin_unlock_bh(&conn->session->lock);
}
EXPORT_SYMBOL_GPL(iscsi_suspend_queue);
/**
* iscsi_suspend_tx - suspend iscsi_data_xmit
* @conn: iscsi conn tp stop processing IO on.
*
* This function sets the suspend bit to prevent iscsi_data_xmit
* from sending new IO, and if work is queued on the xmit thread
* it will wait for it to be completed.
*/
void iscsi_suspend_tx(struct iscsi_conn *conn)
{
struct Scsi_Host *shost = conn->session->host;

View file

@ -124,6 +124,7 @@ static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max,
dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
kfree(ring[i]);
}
kfree(ring);
}
int srp_target_alloc(struct srp_target *target, struct device *dev,

View file

@ -28,4 +28,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o
lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \
lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \
lpfc_vport.o lpfc_debugfs.o
lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o

View file

@ -312,6 +312,7 @@ struct lpfc_vport {
#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */
#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */
#define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */
uint32_t ct_flags;
#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */
@ -440,6 +441,12 @@ enum intr_type_t {
MSIX,
};
struct unsol_rcv_ct_ctx {
uint32_t ctxt_id;
uint32_t SID;
uint32_t oxid;
};
struct lpfc_hba {
/* SCSI interface function jump table entries */
int (*lpfc_new_scsi_buf)
@ -525,6 +532,8 @@ struct lpfc_hba {
#define FCP_XRI_ABORT_EVENT 0x20
#define ELS_XRI_ABORT_EVENT 0x40
#define ASYNC_EVENT 0x80
#define LINK_DISABLED 0x100 /* Link disabled by user */
#define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */
struct lpfc_dmabuf slim2p;
MAILBOX_t *mbox;
@ -616,6 +625,8 @@ struct lpfc_hba {
uint32_t hbq_count; /* Count of configured HBQs */
struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */
uint32_t fcp_qidx; /* next work queue to post work to */
unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */
unsigned long pci_bar1_map; /* Physical address for PCI BAR1 */
unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */
@ -682,6 +693,7 @@ struct lpfc_hba {
struct pci_pool *lpfc_mbuf_pool;
struct pci_pool *lpfc_hrb_pool; /* header receive buffer pool */
struct pci_pool *lpfc_drb_pool; /* data receive buffer pool */
struct pci_pool *lpfc_hbq_pool; /* SLI3 hbq buffer pool */
struct lpfc_dma_pool lpfc_mbuf_safety_pool;
mempool_t *mbox_mem_pool;
@ -763,11 +775,18 @@ struct lpfc_hba {
/* Maximum number of events that can be outstanding at any time*/
#define LPFC_MAX_EVT_COUNT 512
atomic_t fast_event_count;
uint32_t fcoe_eventtag;
uint32_t fcoe_eventtag_at_fcf_scan;
struct lpfc_fcf fcf;
uint8_t fc_map[3];
uint8_t valid_vlan;
uint16_t vlan_id;
struct list_head fcf_conn_rec_list;
struct mutex ct_event_mutex; /* synchronize access to ct_ev_waiters */
struct list_head ct_ev_waiters;
struct unsol_rcv_ct_ctx ct_ctx[64];
uint32_t ctx_idx;
};
static inline struct Scsi_Host *

View file

@ -394,7 +394,12 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
case LPFC_INIT_MBX_CMDS:
case LPFC_LINK_DOWN:
case LPFC_HBA_ERROR:
len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n");
if (phba->hba_flag & LINK_DISABLED)
len += snprintf(buf + len, PAGE_SIZE-len,
"Link Down - User disabled\n");
else
len += snprintf(buf + len, PAGE_SIZE-len,
"Link Down\n");
break;
case LPFC_LINK_UP:
case LPFC_CLEAR_LA:
@ -4127,6 +4132,9 @@ struct fc_function_template lpfc_transport_functions = {
.vport_disable = lpfc_vport_disable,
.set_vport_symbolic_name = lpfc_set_vport_symbolic_name,
.bsg_request = lpfc_bsg_request,
.bsg_timeout = lpfc_bsg_timeout,
};
struct fc_function_template lpfc_vport_transport_functions = {

View file

@ -0,0 +1,904 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2009 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of version 2 of the GNU General *
* Public License as published by the Free Software Foundation. *
* This program is distributed in the hope that it will be useful. *
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
* DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
* TO BE LEGALLY INVALID. See the GNU General Public License for *
* more details, a copy of which can be found in the file COPYING *
* included with this package. *
*******************************************************************/
#include <linux/interrupt.h>
#include <linux/mempool.h>
#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_bsg_fc.h>
#include "lpfc_hw4.h"
#include "lpfc_hw.h"
#include "lpfc_sli.h"
#include "lpfc_sli4.h"
#include "lpfc_nl.h"
#include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
#include "lpfc_vport.h"
#include "lpfc_version.h"
/**
* lpfc_bsg_rport_ct - send a CT command from a bsg request
* @job: fc_bsg_job to handle
*/
static int
lpfc_bsg_rport_ct(struct fc_bsg_job *job)
{
struct Scsi_Host *shost = job->shost;
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_rport_data *rdata = job->rport->dd_data;
struct lpfc_nodelist *ndlp = rdata->pnode;
struct ulp_bde64 *bpl = NULL;
uint32_t timeout;
struct lpfc_iocbq *cmdiocbq = NULL;
struct lpfc_iocbq *rspiocbq = NULL;
IOCB_t *cmd;
IOCB_t *rsp;
struct lpfc_dmabuf *bmp = NULL;
int request_nseg;
int reply_nseg;
struct scatterlist *sgel = NULL;
int numbde;
dma_addr_t busaddr;
int rc = 0;
/* in case no data is transferred */
job->reply->reply_payload_rcv_len = 0;
if (!lpfc_nlp_get(ndlp)) {
job->reply->result = -ENODEV;
return 0;
}
if (ndlp->nlp_flag & NLP_ELS_SND_MASK) {
rc = -ENODEV;
goto free_ndlp_exit;
}
spin_lock_irq(shost->host_lock);
cmdiocbq = lpfc_sli_get_iocbq(phba);
if (!cmdiocbq) {
rc = -ENOMEM;
spin_unlock_irq(shost->host_lock);
goto free_ndlp_exit;
}
cmd = &cmdiocbq->iocb;
rspiocbq = lpfc_sli_get_iocbq(phba);
if (!rspiocbq) {
rc = -ENOMEM;
goto free_cmdiocbq;
}
spin_unlock_irq(shost->host_lock);
rsp = &rspiocbq->iocb;
bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (!bmp) {
rc = -ENOMEM;
spin_lock_irq(shost->host_lock);
goto free_rspiocbq;
}
spin_lock_irq(shost->host_lock);
bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
if (!bmp->virt) {
rc = -ENOMEM;
goto free_bmp;
}
spin_unlock_irq(shost->host_lock);
INIT_LIST_HEAD(&bmp->list);
bpl = (struct ulp_bde64 *) bmp->virt;
request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
busaddr = sg_dma_address(sgel);
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
bpl->tus.f.bdeSize = sg_dma_len(sgel);
bpl->tus.w = cpu_to_le32(bpl->tus.w);
bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
bpl++;
}
reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
busaddr = sg_dma_address(sgel);
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
bpl->tus.f.bdeSize = sg_dma_len(sgel);
bpl->tus.w = cpu_to_le32(bpl->tus.w);
bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
bpl++;
}
cmd->un.genreq64.bdl.ulpIoTag32 = 0;
cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
cmd->un.genreq64.bdl.bdeSize =
(request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
cmd->un.genreq64.w5.hcsw.Dfctl = 0;
cmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL;
cmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP;
cmd->ulpBdeCount = 1;
cmd->ulpLe = 1;
cmd->ulpClass = CLASS3;
cmd->ulpContext = ndlp->nlp_rpi;
cmd->ulpOwner = OWN_CHIP;
cmdiocbq->vport = phba->pport;
cmdiocbq->context1 = NULL;
cmdiocbq->context2 = NULL;
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
timeout = phba->fc_ratov * 2;
job->dd_data = cmdiocbq;
rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq,
timeout + LPFC_DRVR_TIMEOUT);
if (rc != IOCB_TIMEDOUT) {
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
}
if (rc == IOCB_TIMEDOUT) {
lpfc_sli_release_iocbq(phba, rspiocbq);
rc = -EACCES;
goto free_ndlp_exit;
}
if (rc != IOCB_SUCCESS) {
rc = -EACCES;
goto free_outdmp;
}
if (rsp->ulpStatus) {
if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
switch (rsp->un.ulpWord[4] & 0xff) {
case IOERR_SEQUENCE_TIMEOUT:
rc = -ETIMEDOUT;
break;
case IOERR_INVALID_RPI:
rc = -EFAULT;
break;
default:
rc = -EACCES;
break;
}
goto free_outdmp;
}
} else
job->reply->reply_payload_rcv_len =
rsp->un.genreq64.bdl.bdeSize;
free_outdmp:
spin_lock_irq(shost->host_lock);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
free_bmp:
kfree(bmp);
free_rspiocbq:
lpfc_sli_release_iocbq(phba, rspiocbq);
free_cmdiocbq:
lpfc_sli_release_iocbq(phba, cmdiocbq);
spin_unlock_irq(shost->host_lock);
free_ndlp_exit:
lpfc_nlp_put(ndlp);
/* make error code available to userspace */
job->reply->result = rc;
/* complete the job back to userspace */
job->job_done(job);
return 0;
}
/**
* lpfc_bsg_rport_els - send an ELS command from a bsg request
* @job: fc_bsg_job to handle
*/
static int
lpfc_bsg_rport_els(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_rport_data *rdata = job->rport->dd_data;
struct lpfc_nodelist *ndlp = rdata->pnode;
uint32_t elscmd;
uint32_t cmdsize;
uint32_t rspsize;
struct lpfc_iocbq *rspiocbq;
struct lpfc_iocbq *cmdiocbq;
IOCB_t *rsp;
uint16_t rpi = 0;
struct lpfc_dmabuf *pcmd;
struct lpfc_dmabuf *prsp;
struct lpfc_dmabuf *pbuflist = NULL;
struct ulp_bde64 *bpl;
int iocb_status;
int request_nseg;
int reply_nseg;
struct scatterlist *sgel = NULL;
int numbde;
dma_addr_t busaddr;
int rc = 0;
/* in case no data is transferred */
job->reply->reply_payload_rcv_len = 0;
if (!lpfc_nlp_get(ndlp)) {
rc = -ENODEV;
goto out;
}
elscmd = job->request->rqst_data.r_els.els_code;
cmdsize = job->request_payload.payload_len;
rspsize = job->reply_payload.payload_len;
rspiocbq = lpfc_sli_get_iocbq(phba);
if (!rspiocbq) {
lpfc_nlp_put(ndlp);
rc = -ENOMEM;
goto out;
}
rsp = &rspiocbq->iocb;
rpi = ndlp->nlp_rpi;
cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, ndlp,
ndlp->nlp_DID, elscmd);
if (!cmdiocbq) {
lpfc_sli_release_iocbq(phba, rspiocbq);
return -EIO;
}
job->dd_data = cmdiocbq;
pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2;
prsp = (struct lpfc_dmabuf *) pcmd->list.next;
lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
kfree(pcmd);
lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
kfree(prsp);
cmdiocbq->context2 = NULL;
pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3;
bpl = (struct ulp_bde64 *) pbuflist->virt;
request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
busaddr = sg_dma_address(sgel);
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
bpl->tus.f.bdeSize = sg_dma_len(sgel);
bpl->tus.w = cpu_to_le32(bpl->tus.w);
bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
bpl++;
}
reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
busaddr = sg_dma_address(sgel);
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
bpl->tus.f.bdeSize = sg_dma_len(sgel);
bpl->tus.w = cpu_to_le32(bpl->tus.w);
bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
bpl++;
}
cmdiocbq->iocb.un.elsreq64.bdl.bdeSize =
(request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
cmdiocbq->iocb.ulpContext = rpi;
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
cmdiocbq->context1 = NULL;
cmdiocbq->context2 = NULL;
iocb_status = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
rspiocbq, (phba->fc_ratov * 2)
+ LPFC_DRVR_TIMEOUT);
/* release the new ndlp once the iocb completes */
lpfc_nlp_put(ndlp);
if (iocb_status != IOCB_TIMEDOUT) {
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
}
if (iocb_status == IOCB_SUCCESS) {
if (rsp->ulpStatus == IOSTAT_SUCCESS) {
job->reply->reply_payload_rcv_len =
rsp->un.elsreq64.bdl.bdeSize;
rc = 0;
} else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
struct fc_bsg_ctels_reply *els_reply;
/* LS_RJT data returned in word 4 */
uint8_t *rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
els_reply = &job->reply->reply_data.ctels_reply;
job->reply->result = 0;
els_reply->status = FC_CTELS_STATUS_REJECT;
els_reply->rjt_data.action = rjt_data[0];
els_reply->rjt_data.reason_code = rjt_data[1];
els_reply->rjt_data.reason_explanation = rjt_data[2];
els_reply->rjt_data.vendor_unique = rjt_data[3];
} else
rc = -EIO;
} else
rc = -EIO;
if (iocb_status != IOCB_TIMEDOUT)
lpfc_els_free_iocb(phba, cmdiocbq);
lpfc_sli_release_iocbq(phba, rspiocbq);
out:
/* make error code available to userspace */
job->reply->result = rc;
/* complete the job back to userspace */
job->job_done(job);
return 0;
}
struct lpfc_ct_event {
struct list_head node;
int ref;
wait_queue_head_t wq;
/* Event type and waiter identifiers */
uint32_t type_mask;
uint32_t req_id;
uint32_t reg_id;
/* next two flags are here for the auto-delete logic */
unsigned long wait_time_stamp;
int waiting;
/* seen and not seen events */
struct list_head events_to_get;
struct list_head events_to_see;
};
struct event_data {
struct list_head node;
uint32_t type;
uint32_t immed_dat;
void *data;
uint32_t len;
};
static struct lpfc_ct_event *
lpfc_ct_event_new(int ev_reg_id, uint32_t ev_req_id)
{
struct lpfc_ct_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL);
if (!evt)
return NULL;
INIT_LIST_HEAD(&evt->events_to_get);
INIT_LIST_HEAD(&evt->events_to_see);
evt->req_id = ev_req_id;
evt->reg_id = ev_reg_id;
evt->wait_time_stamp = jiffies;
init_waitqueue_head(&evt->wq);
return evt;
}
static void
lpfc_ct_event_free(struct lpfc_ct_event *evt)
{
struct event_data *ed;
list_del(&evt->node);
while (!list_empty(&evt->events_to_get)) {
ed = list_entry(evt->events_to_get.next, typeof(*ed), node);
list_del(&ed->node);
kfree(ed->data);
kfree(ed);
}
while (!list_empty(&evt->events_to_see)) {
ed = list_entry(evt->events_to_see.next, typeof(*ed), node);
list_del(&ed->node);
kfree(ed->data);
kfree(ed);
}
kfree(evt);
}
static inline void
lpfc_ct_event_ref(struct lpfc_ct_event *evt)
{
evt->ref++;
}
static inline void
lpfc_ct_event_unref(struct lpfc_ct_event *evt)
{
if (--evt->ref < 0)
lpfc_ct_event_free(evt);
}
#define SLI_CT_ELX_LOOPBACK 0x10
enum ELX_LOOPBACK_CMD {
ELX_LOOPBACK_XRI_SETUP,
ELX_LOOPBACK_DATA,
};
/**
* lpfc_bsg_ct_unsol_event - process an unsolicited CT command
* @phba:
* @pring:
* @piocbq:
*
* This function is called when an unsolicited CT command is received. It
* forwards the event to any processes registerd to receive CT events.
*/
void
lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocbq)
{
uint32_t evt_req_id = 0;
uint32_t cmd;
uint32_t len;
struct lpfc_dmabuf *dmabuf = NULL;
struct lpfc_ct_event *evt;
struct event_data *evt_dat = NULL;
struct lpfc_iocbq *iocbq;
size_t offset = 0;
struct list_head head;
struct ulp_bde64 *bde;
dma_addr_t dma_addr;
int i;
struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
struct lpfc_hbq_entry *hbqe;
struct lpfc_sli_ct_request *ct_req;
INIT_LIST_HEAD(&head);
list_add_tail(&head, &piocbq->list);
if (piocbq->iocb.ulpBdeCount == 0 ||
piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0)
goto error_ct_unsol_exit;
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
dmabuf = bdeBuf1;
else {
dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh,
piocbq->iocb.un.cont64[0].addrLow);
dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr);
}
ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt;
evt_req_id = ct_req->FsType;
cmd = ct_req->CommandResponse.bits.CmdRsp;
len = ct_req->CommandResponse.bits.Size;
if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
lpfc_sli_ringpostbuf_put(phba, pring, dmabuf);
mutex_lock(&phba->ct_event_mutex);
list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
if (evt->req_id != evt_req_id)
continue;
lpfc_ct_event_ref(evt);
evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL);
if (!evt_dat) {
lpfc_ct_event_unref(evt);
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2614 Memory allocation failed for "
"CT event\n");
break;
}
mutex_unlock(&phba->ct_event_mutex);
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
/* take accumulated byte count from the last iocbq */
iocbq = list_entry(head.prev, typeof(*iocbq), list);
evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len;
} else {
list_for_each_entry(iocbq, &head, list) {
for (i = 0; i < iocbq->iocb.ulpBdeCount; i++)
evt_dat->len +=
iocbq->iocb.un.cont64[i].tus.f.bdeSize;
}
}
evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL);
if (!evt_dat->data) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2615 Memory allocation failed for "
"CT event data, size %d\n",
evt_dat->len);
kfree(evt_dat);
mutex_lock(&phba->ct_event_mutex);
lpfc_ct_event_unref(evt);
mutex_unlock(&phba->ct_event_mutex);
goto error_ct_unsol_exit;
}
list_for_each_entry(iocbq, &head, list) {
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
bdeBuf1 = iocbq->context2;
bdeBuf2 = iocbq->context3;
}
for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) {
int size = 0;
if (phba->sli3_options &
LPFC_SLI3_HBQ_ENABLED) {
if (i == 0) {
hbqe = (struct lpfc_hbq_entry *)
&iocbq->iocb.un.ulpWord[0];
size = hbqe->bde.tus.f.bdeSize;
dmabuf = bdeBuf1;
} else if (i == 1) {
hbqe = (struct lpfc_hbq_entry *)
&iocbq->iocb.unsli3.
sli3Words[4];
size = hbqe->bde.tus.f.bdeSize;
dmabuf = bdeBuf2;
}
if ((offset + size) > evt_dat->len)
size = evt_dat->len - offset;
} else {
size = iocbq->iocb.un.cont64[i].
tus.f.bdeSize;
bde = &iocbq->iocb.un.cont64[i];
dma_addr = getPaddr(bde->addrHigh,
bde->addrLow);
dmabuf = lpfc_sli_ringpostbuf_get(phba,
pring, dma_addr);
}
if (!dmabuf) {
lpfc_printf_log(phba, KERN_ERR,
LOG_LIBDFC, "2616 No dmabuf "
"found for iocbq 0x%p\n",
iocbq);
kfree(evt_dat->data);
kfree(evt_dat);
mutex_lock(&phba->ct_event_mutex);
lpfc_ct_event_unref(evt);
mutex_unlock(&phba->ct_event_mutex);
goto error_ct_unsol_exit;
}
memcpy((char *)(evt_dat->data) + offset,
dmabuf->virt, size);
offset += size;
if (evt_req_id != SLI_CT_ELX_LOOPBACK &&
!(phba->sli3_options &
LPFC_SLI3_HBQ_ENABLED)) {
lpfc_sli_ringpostbuf_put(phba, pring,
dmabuf);
} else {
switch (cmd) {
case ELX_LOOPBACK_XRI_SETUP:
if (!(phba->sli3_options &
LPFC_SLI3_HBQ_ENABLED))
lpfc_post_buffer(phba,
pring,
1);
else
lpfc_in_buf_free(phba,
dmabuf);
break;
default:
if (!(phba->sli3_options &
LPFC_SLI3_HBQ_ENABLED))
lpfc_post_buffer(phba,
pring,
1);
break;
}
}
}
}
mutex_lock(&phba->ct_event_mutex);
if (phba->sli_rev == LPFC_SLI_REV4) {
evt_dat->immed_dat = phba->ctx_idx;
phba->ctx_idx = (phba->ctx_idx + 1) % 64;
phba->ct_ctx[evt_dat->immed_dat].oxid =
piocbq->iocb.ulpContext;
phba->ct_ctx[evt_dat->immed_dat].SID =
piocbq->iocb.un.rcvels.remoteID;
} else
evt_dat->immed_dat = piocbq->iocb.ulpContext;
evt_dat->type = FC_REG_CT_EVENT;
list_add(&evt_dat->node, &evt->events_to_see);
wake_up_interruptible(&evt->wq);
lpfc_ct_event_unref(evt);
if (evt_req_id == SLI_CT_ELX_LOOPBACK)
break;
}
mutex_unlock(&phba->ct_event_mutex);
error_ct_unsol_exit:
if (!list_empty(&head))
list_del(&head);
return;
}
/**
* lpfc_bsg_set_event - process a SET_EVENT bsg vendor command
* @job: SET_EVENT fc_bsg_job
*/
static int
lpfc_bsg_set_event(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct set_ct_event *event_req;
struct lpfc_ct_event *evt;
int rc = 0;
if (job->request_len <
sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2612 Received SET_CT_EVENT below minimum "
"size\n");
return -EINVAL;
}
event_req = (struct set_ct_event *)
job->request->rqst_data.h_vendor.vendor_cmd;
mutex_lock(&phba->ct_event_mutex);
list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
if (evt->reg_id == event_req->ev_reg_id) {
lpfc_ct_event_ref(evt);
evt->wait_time_stamp = jiffies;
break;
}
}
mutex_unlock(&phba->ct_event_mutex);
if (&evt->node == &phba->ct_ev_waiters) {
/* no event waiting struct yet - first call */
evt = lpfc_ct_event_new(event_req->ev_reg_id,
event_req->ev_req_id);
if (!evt) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2617 Failed allocation of event "
"waiter\n");
return -ENOMEM;
}
mutex_lock(&phba->ct_event_mutex);
list_add(&evt->node, &phba->ct_ev_waiters);
lpfc_ct_event_ref(evt);
mutex_unlock(&phba->ct_event_mutex);
}
evt->waiting = 1;
if (wait_event_interruptible(evt->wq,
!list_empty(&evt->events_to_see))) {
mutex_lock(&phba->ct_event_mutex);
lpfc_ct_event_unref(evt); /* release ref */
lpfc_ct_event_unref(evt); /* delete */
mutex_unlock(&phba->ct_event_mutex);
rc = -EINTR;
goto set_event_out;
}
evt->wait_time_stamp = jiffies;
evt->waiting = 0;
mutex_lock(&phba->ct_event_mutex);
list_move(evt->events_to_see.prev, &evt->events_to_get);
lpfc_ct_event_unref(evt); /* release ref */
mutex_unlock(&phba->ct_event_mutex);
set_event_out:
/* set_event carries no reply payload */
job->reply->reply_payload_rcv_len = 0;
/* make error code available to userspace */
job->reply->result = rc;
/* complete the job back to userspace */
job->job_done(job);
return 0;
}
/**
* lpfc_bsg_get_event - process a GET_EVENT bsg vendor command
* @job: GET_EVENT fc_bsg_job
*/
static int
lpfc_bsg_get_event(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct get_ct_event *event_req;
struct get_ct_event_reply *event_reply;
struct lpfc_ct_event *evt;
struct event_data *evt_dat = NULL;
int rc = 0;
if (job->request_len <
sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2613 Received GET_CT_EVENT request below "
"minimum size\n");
return -EINVAL;
}
event_req = (struct get_ct_event *)
job->request->rqst_data.h_vendor.vendor_cmd;
event_reply = (struct get_ct_event_reply *)
job->reply->reply_data.vendor_reply.vendor_rsp;
mutex_lock(&phba->ct_event_mutex);
list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
if (evt->reg_id == event_req->ev_reg_id) {
if (list_empty(&evt->events_to_get))
break;
lpfc_ct_event_ref(evt);
evt->wait_time_stamp = jiffies;
evt_dat = list_entry(evt->events_to_get.prev,
struct event_data, node);
list_del(&evt_dat->node);
break;
}
}
mutex_unlock(&phba->ct_event_mutex);
if (!evt_dat) {
job->reply->reply_payload_rcv_len = 0;
rc = -ENOENT;
goto error_get_event_exit;
}
if (evt_dat->len > job->reply_payload.payload_len) {
evt_dat->len = job->reply_payload.payload_len;
lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
"2618 Truncated event data at %d "
"bytes\n",
job->reply_payload.payload_len);
}
event_reply->immed_data = evt_dat->immed_dat;
if (evt_dat->len > 0)
job->reply->reply_payload_rcv_len =
sg_copy_from_buffer(job->reply_payload.sg_list,
job->reply_payload.sg_cnt,
evt_dat->data, evt_dat->len);
else
job->reply->reply_payload_rcv_len = 0;
rc = 0;
if (evt_dat)
kfree(evt_dat->data);
kfree(evt_dat);
mutex_lock(&phba->ct_event_mutex);
lpfc_ct_event_unref(evt);
mutex_unlock(&phba->ct_event_mutex);
error_get_event_exit:
/* make error code available to userspace */
job->reply->result = rc;
/* complete the job back to userspace */
job->job_done(job);
return rc;
}
/**
* lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job
* @job: fc_bsg_job to handle
*/
static int
lpfc_bsg_hst_vendor(struct fc_bsg_job *job)
{
int command = job->request->rqst_data.h_vendor.vendor_cmd[0];
switch (command) {
case LPFC_BSG_VENDOR_SET_CT_EVENT:
return lpfc_bsg_set_event(job);
break;
case LPFC_BSG_VENDOR_GET_CT_EVENT:
return lpfc_bsg_get_event(job);
break;
default:
return -EINVAL;
}
}
/**
* lpfc_bsg_request - handle a bsg request from the FC transport
* @job: fc_bsg_job to handle
*/
int
lpfc_bsg_request(struct fc_bsg_job *job)
{
uint32_t msgcode;
int rc = -EINVAL;
msgcode = job->request->msgcode;
switch (msgcode) {
case FC_BSG_HST_VENDOR:
rc = lpfc_bsg_hst_vendor(job);
break;
case FC_BSG_RPT_ELS:
rc = lpfc_bsg_rport_els(job);
break;
case FC_BSG_RPT_CT:
rc = lpfc_bsg_rport_ct(job);
break;
default:
break;
}
return rc;
}
/**
* lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport
* @job: fc_bsg_job that has timed out
*
* This function just aborts the job's IOCB. The aborted IOCB will return to
* the waiting function which will handle passing the error back to userspace
*/
int
lpfc_bsg_timeout(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)job->dd_data;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
if (cmdiocb)
lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
return 0;
}

View file

@ -21,9 +21,11 @@
typedef int (*node_filter)(struct lpfc_nodelist *, void *);
struct fc_rport;
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_sli_read_link_ste(struct lpfc_hba *);
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t);
void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
int lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
@ -135,6 +137,9 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
int lpfc_els_disc_plogi(struct lpfc_vport *);
void lpfc_els_timeout(unsigned long);
void lpfc_els_timeout_handler(struct lpfc_vport *);
struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t,
uint8_t, struct lpfc_nodelist *,
uint32_t, uint32_t);
void lpfc_hb_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
@ -182,11 +187,12 @@ int lpfc_mbox_dev_check(struct lpfc_hba *);
int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *);
void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t);
void lpfc_init_vpi(struct lpfcMboxq *, uint16_t);
void lpfc_init_vpi(struct lpfc_hba *, struct lpfcMboxq *, uint16_t);
void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t);
void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t);
void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *);
int lpfc_check_pending_fcoe_event(struct lpfc_hba *, uint8_t);
void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
uint32_t , LPFC_MBOXQ_t *);
@ -234,6 +240,7 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
struct lpfc_iocbq *, uint32_t);
void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
void lpfc_sli_bemem_bcopy(void *, void *, uint32_t);
void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
void lpfc_sli_flush_fcp_rings(struct lpfc_hba *);
int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
@ -360,3 +367,8 @@ void lpfc_start_fdiscs(struct lpfc_hba *phba);
#define HBA_EVENT_LINK_UP 2
#define HBA_EVENT_LINK_DOWN 3
/* functions to support SGIOv4/bsg interface */
int lpfc_bsg_request(struct fc_bsg_job *);
int lpfc_bsg_timeout(struct fc_bsg_job *);
void lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);

View file

@ -97,6 +97,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct list_head head;
struct lpfc_dmabuf *bdeBuf;
lpfc_bsg_ct_unsol_event(phba, pring, piocbq);
if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
} else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&

View file

@ -146,7 +146,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
* Pointer to the newly allocated/prepared els iocb data structure
* NULL - when els iocb data structure allocation/preparation failed
**/
static struct lpfc_iocbq *
struct lpfc_iocbq *
lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
uint16_t cmdSize, uint8_t retry,
struct lpfc_nodelist *ndlp, uint32_t did,

View file

@ -61,6 +61,7 @@ static uint8_t lpfcAlpaArray[] = {
static void lpfc_disc_timeout_handler(struct lpfc_vport *);
static void lpfc_disc_flush_list(struct lpfc_vport *vport);
static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
void
lpfc_terminate_rport_io(struct fc_rport *rport)
@ -1009,9 +1010,15 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
spin_lock_irqsave(&phba->hbalock, flags);
phba->fcf.fcf_flag |= FCF_REGISTERED;
spin_unlock_irqrestore(&phba->hbalock, flags);
/* If there is a pending FCoE event, restart FCF table scan. */
if (lpfc_check_pending_fcoe_event(phba, 1)) {
mempool_free(mboxq, phba->mbox_mem_pool);
return;
}
if (vport->port_state != LPFC_FLOGI) {
spin_lock_irqsave(&phba->hbalock, flags);
phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
spin_unlock_irqrestore(&phba->hbalock, flags);
lpfc_initial_flogi(vport);
}
@ -1053,6 +1060,39 @@ lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record)
return 0;
}
/**
* lpfc_sw_name_match - Check if the fcf switch name match.
* @fab_name: pointer to fabric name.
* @new_fcf_record: pointer to fcf record.
*
* This routine compare the fcf record's switch name with provided
* switch name. If the switch name are identical this function
* returns 1 else return 0.
**/
static uint32_t
lpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record)
{
if ((sw_name[0] ==
bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record)) &&
(sw_name[1] ==
bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record)) &&
(sw_name[2] ==
bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record)) &&
(sw_name[3] ==
bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record)) &&
(sw_name[4] ==
bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record)) &&
(sw_name[5] ==
bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record)) &&
(sw_name[6] ==
bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record)) &&
(sw_name[7] ==
bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record)))
return 1;
else
return 0;
}
/**
* lpfc_mac_addr_match - Check if the fcf mac address match.
* @phba: pointer to lpfc hba data structure.
@ -1123,6 +1163,22 @@ lpfc_copy_fcf_record(struct lpfc_hba *phba, struct fcf_record *new_fcf_record)
bf_get(lpfc_fcf_record_mac_5, new_fcf_record);
phba->fcf.fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
phba->fcf.priority = new_fcf_record->fip_priority;
phba->fcf.switch_name[0] =
bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record);
phba->fcf.switch_name[1] =
bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record);
phba->fcf.switch_name[2] =
bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record);
phba->fcf.switch_name[3] =
bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record);
phba->fcf.switch_name[4] =
bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record);
phba->fcf.switch_name[5] =
bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record);
phba->fcf.switch_name[6] =
bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record);
phba->fcf.switch_name[7] =
bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record);
}
/**
@ -1150,6 +1206,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
/* The FCF is already registered, start discovery */
if (phba->fcf.fcf_flag & FCF_REGISTERED) {
phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
spin_unlock_irqrestore(&phba->hbalock, flags);
if (phba->pport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(phba->pport);
@ -1239,9 +1296,12 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) &&
!lpfc_fab_name_match(conn_entry->conn_rec.fabric_name,
new_fcf_record))
new_fcf_record))
continue;
if ((conn_entry->conn_rec.flags & FCFCNCT_SWNM_VALID) &&
!lpfc_sw_name_match(conn_entry->conn_rec.switch_name,
new_fcf_record))
continue;
if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) {
/*
* If the vlan bit map does not have the bit set for the
@ -1335,6 +1395,60 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
return 0;
}
/**
* lpfc_check_pending_fcoe_event - Check if there is pending fcoe event.
* @phba: pointer to lpfc hba data structure.
* @unreg_fcf: Unregister FCF if FCF table need to be re-scaned.
*
* This function check if there is any fcoe event pending while driver
* scan FCF entries. If there is any pending event, it will restart the
* FCF saning and return 1 else return 0.
*/
int
lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
{
LPFC_MBOXQ_t *mbox;
int rc;
/*
* If the Link is up and no FCoE events while in the
* FCF discovery, no need to restart FCF discovery.
*/
if ((phba->link_state >= LPFC_LINK_UP) &&
(phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
return 0;
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_AVAILABLE;
spin_unlock_irq(&phba->hbalock);
if (phba->link_state >= LPFC_LINK_UP)
lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
if (unreg_fcf) {
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_REGISTERED;
spin_unlock_irq(&phba->hbalock);
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) {
lpfc_printf_log(phba, KERN_ERR,
LOG_DISCOVERY|LOG_MBOX,
"2610 UNREG_FCFI mbox allocation failed\n");
return 1;
}
lpfc_unreg_fcfi(mbox, phba->fcf.fcfi);
mbox->vport = phba->pport;
mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX,
"2611 UNREG_FCFI issue mbox failed\n");
mempool_free(mbox, phba->mbox_mem_pool);
}
}
return 1;
}
/**
* lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
* @phba: pointer to lpfc hba data structure.
@ -1367,6 +1481,12 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
unsigned long flags;
uint16_t vlan_id;
/* If there is pending FCoE event restart FCF table scan */
if (lpfc_check_pending_fcoe_event(phba, 0)) {
lpfc_sli4_mbox_cmd_free(phba, mboxq);
return;
}
/* Get the first SGE entry from the non-embedded DMA memory. This
* routine only uses a single SGE.
*/
@ -1424,7 +1544,9 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
spin_lock_irqsave(&phba->hbalock, flags);
if (phba->fcf.fcf_flag & FCF_IN_USE) {
if (lpfc_fab_name_match(phba->fcf.fabric_name,
new_fcf_record) &&
new_fcf_record) &&
lpfc_sw_name_match(phba->fcf.switch_name,
new_fcf_record) &&
lpfc_mac_addr_match(phba, new_fcf_record)) {
phba->fcf.fcf_flag |= FCF_AVAILABLE;
spin_unlock_irqrestore(&phba->hbalock, flags);
@ -1464,9 +1586,9 @@ lpfc_mbx_cmpl_read_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
* If there is a record with lower priority value for
* the current FCF, use that record.
*/
if (lpfc_fab_name_match(phba->fcf.fabric_name, new_fcf_record)
&& (new_fcf_record->fip_priority <
phba->fcf.priority)) {
if (lpfc_fab_name_match(phba->fcf.fabric_name,
new_fcf_record) &&
(new_fcf_record->fip_priority < phba->fcf.priority)) {
/* Use this FCF record */
lpfc_copy_fcf_record(phba, new_fcf_record);
phba->fcf.addr_mode = addr_mode;
@ -1511,6 +1633,39 @@ out:
return;
}
/**
* lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox data structure.
*
* This function handles completion of init vpi mailbox command.
*/
static void
lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
struct lpfc_vport *vport = mboxq->vport;
if (mboxq->u.mb.mbxStatus) {
lpfc_printf_vlog(vport, KERN_ERR,
LOG_MBOX,
"2609 Init VPI mailbox failed 0x%x\n",
mboxq->u.mb.mbxStatus);
mempool_free(mboxq, phba->mbox_mem_pool);
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
return;
}
vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
lpfc_initial_fdisc(vport);
else {
lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
lpfc_printf_vlog(vport, KERN_ERR,
LOG_ELS,
"2606 No NPIV Fabric support\n");
}
return;
}
/**
* lpfc_start_fdiscs - send fdiscs for each vports on this port.
* @phba: pointer to lpfc hba data structure.
@ -1523,6 +1678,8 @@ lpfc_start_fdiscs(struct lpfc_hba *phba)
{
struct lpfc_vport **vports;
int i;
LPFC_MBOXQ_t *mboxq;
int rc;
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL) {
@ -1540,6 +1697,29 @@ lpfc_start_fdiscs(struct lpfc_hba *phba)
FC_VPORT_LINKDOWN);
continue;
}
if (vports[i]->fc_flag & FC_VPORT_NEEDS_INIT_VPI) {
mboxq = mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL);
if (!mboxq) {
lpfc_printf_vlog(vports[i], KERN_ERR,
LOG_MBOX, "2607 Failed to allocate "
"init_vpi mailbox\n");
continue;
}
lpfc_init_vpi(phba, mboxq, vports[i]->vpi);
mboxq->vport = vports[i];
mboxq->mbox_cmpl = lpfc_init_vpi_cmpl;
rc = lpfc_sli_issue_mbox(phba, mboxq,
MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
lpfc_printf_vlog(vports[i], KERN_ERR,
LOG_MBOX, "2608 Failed to issue "
"init_vpi mailbox\n");
mempool_free(mboxq,
phba->mbox_mem_pool);
}
continue;
}
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
lpfc_initial_fdisc(vports[i]);
else {
@ -1769,6 +1949,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
goto out;
}
} else {
vport->port_state = LPFC_VPORT_UNKNOWN;
/*
* Add the driver's default FCF record at FCF index 0 now. This
* is phase 1 implementation that support FCF index 0 and driver
@ -1804,6 +1985,12 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
* The driver is expected to do FIP/FCF. Call the port
* and get the FCF Table.
*/
spin_lock_irq(&phba->hbalock);
if (phba->hba_flag & FCF_DISC_INPROGRESS) {
spin_unlock_irq(&phba->hbalock);
return;
}
spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli4_read_fcf_record(phba,
LPFC_FCOE_FCF_GET_FIRST);
if (rc)
@ -2113,13 +2300,15 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
LPFC_MBOXQ_t *pmb = NULL;
MAILBOX_t *mb;
struct static_vport_info *vport_info;
int rc, i;
int rc = 0, i;
struct fc_vport_identifiers vport_id;
struct fc_vport *new_fc_vport;
struct Scsi_Host *shost;
struct lpfc_vport *vport;
uint16_t offset = 0;
uint8_t *vport_buff;
struct lpfc_dmabuf *mp;
uint32_t byte_count = 0;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
@ -2142,7 +2331,9 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
vport_buff = (uint8_t *) vport_info;
do {
lpfc_dump_static_vport(phba, pmb, offset);
if (lpfc_dump_static_vport(phba, pmb, offset))
goto out;
pmb->vport = phba->pport;
rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO);
@ -2155,17 +2346,30 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
goto out;
}
if (mb->un.varDmp.word_cnt >
sizeof(struct static_vport_info) - offset)
mb->un.varDmp.word_cnt =
sizeof(struct static_vport_info) - offset;
if (phba->sli_rev == LPFC_SLI_REV4) {
byte_count = pmb->u.mqe.un.mb_words[5];
mp = (struct lpfc_dmabuf *) pmb->context2;
if (byte_count > sizeof(struct static_vport_info) -
offset)
byte_count = sizeof(struct static_vport_info)
- offset;
memcpy(vport_buff + offset, mp->virt, byte_count);
offset += byte_count;
} else {
if (mb->un.varDmp.word_cnt >
sizeof(struct static_vport_info) - offset)
mb->un.varDmp.word_cnt =
sizeof(struct static_vport_info)
- offset;
byte_count = mb->un.varDmp.word_cnt;
lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
vport_buff + offset,
byte_count);
lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
vport_buff + offset,
mb->un.varDmp.word_cnt);
offset += mb->un.varDmp.word_cnt;
offset += byte_count;
}
} while (mb->un.varDmp.word_cnt &&
} while (byte_count &&
offset < sizeof(struct static_vport_info));
@ -2198,7 +2402,7 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
if (!new_fc_vport) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"0546 lpfc_create_static_vport failed to"
" create vport \n");
" create vport\n");
continue;
}
@ -2207,16 +2411,15 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
}
out:
/*
* If this is timed out command, setting NULL to context2 tell SLI
* layer not to use this buffer.
*/
spin_lock_irq(&phba->hbalock);
pmb->context2 = NULL;
spin_unlock_irq(&phba->hbalock);
kfree(vport_info);
if (rc != MBX_TIMEOUT)
if (rc != MBX_TIMEOUT) {
if (pmb->context2) {
mp = (struct lpfc_dmabuf *) pmb->context2;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
mempool_free(pmb, phba->mbox_mem_pool);
}
return;
}
@ -4360,7 +4563,7 @@ lpfc_read_fcoe_param(struct lpfc_hba *phba,
fcoe_param_hdr = (struct lpfc_fip_param_hdr *)
buff;
fcoe_param = (struct lpfc_fcoe_params *)
buff + sizeof(struct lpfc_fip_param_hdr);
(buff + sizeof(struct lpfc_fip_param_hdr));
if ((fcoe_param_hdr->parm_version != FIPP_VERSION) ||
(fcoe_param_hdr->length != FCOE_PARAM_LENGTH))

View file

@ -2496,8 +2496,8 @@ typedef struct {
#define DMP_VPORT_REGION_SIZE 0x200
#define DMP_MBOX_OFFSET_WORD 0x5
#define DMP_REGION_FCOEPARAM 0x17 /* fcoe param region */
#define DMP_FCOEPARAM_RGN_SIZE 0x400
#define DMP_REGION_23 0x17 /* fcoe param and port state region */
#define DMP_RGN23_SIZE 0x400
#define WAKE_UP_PARMS_REGION_ID 4
#define WAKE_UP_PARMS_WORD_SIZE 15

View file

@ -52,6 +52,31 @@ struct dma_address {
uint32_t addr_hi;
};
#define LPFC_SLIREV_CONF_WORD 0x58
struct lpfc_sli_intf {
uint32_t word0;
#define lpfc_sli_intf_iftype_MASK 0x00000007
#define lpfc_sli_intf_iftype_SHIFT 0
#define lpfc_sli_intf_iftype_WORD word0
#define lpfc_sli_intf_rev_MASK 0x0000000f
#define lpfc_sli_intf_rev_SHIFT 4
#define lpfc_sli_intf_rev_WORD word0
#define LPFC_SLIREV_CONF_SLI4 4
#define lpfc_sli_intf_family_MASK 0x000000ff
#define lpfc_sli_intf_family_SHIFT 8
#define lpfc_sli_intf_family_WORD word0
#define lpfc_sli_intf_feat1_MASK 0x000000ff
#define lpfc_sli_intf_feat1_SHIFT 16
#define lpfc_sli_intf_feat1_WORD word0
#define lpfc_sli_intf_feat2_MASK 0x0000001f
#define lpfc_sli_intf_feat2_SHIFT 24
#define lpfc_sli_intf_feat2_WORD word0
#define lpfc_sli_intf_valid_MASK 0x00000007
#define lpfc_sli_intf_valid_SHIFT 29
#define lpfc_sli_intf_valid_WORD word0
#define LPFC_SLI_INTF_VALID 6
};
#define LPFC_SLI4_BAR0 1
#define LPFC_SLI4_BAR1 2
#define LPFC_SLI4_BAR2 4
@ -1181,6 +1206,32 @@ struct fcf_record {
#define lpfc_fcf_record_fcf_state_MASK 0x0000FFFF
#define lpfc_fcf_record_fcf_state_WORD word8
uint8_t vlan_bitmap[512];
uint32_t word137;
#define lpfc_fcf_record_switch_name_0_SHIFT 0
#define lpfc_fcf_record_switch_name_0_MASK 0x000000FF
#define lpfc_fcf_record_switch_name_0_WORD word137
#define lpfc_fcf_record_switch_name_1_SHIFT 8
#define lpfc_fcf_record_switch_name_1_MASK 0x000000FF
#define lpfc_fcf_record_switch_name_1_WORD word137
#define lpfc_fcf_record_switch_name_2_SHIFT 16
#define lpfc_fcf_record_switch_name_2_MASK 0x000000FF
#define lpfc_fcf_record_switch_name_2_WORD word137
#define lpfc_fcf_record_switch_name_3_SHIFT 24
#define lpfc_fcf_record_switch_name_3_MASK 0x000000FF
#define lpfc_fcf_record_switch_name_3_WORD word137
uint32_t word138;
#define lpfc_fcf_record_switch_name_4_SHIFT 0
#define lpfc_fcf_record_switch_name_4_MASK 0x000000FF
#define lpfc_fcf_record_switch_name_4_WORD word138
#define lpfc_fcf_record_switch_name_5_SHIFT 8
#define lpfc_fcf_record_switch_name_5_MASK 0x000000FF
#define lpfc_fcf_record_switch_name_5_WORD word138
#define lpfc_fcf_record_switch_name_6_SHIFT 16
#define lpfc_fcf_record_switch_name_6_MASK 0x000000FF
#define lpfc_fcf_record_switch_name_6_WORD word138
#define lpfc_fcf_record_switch_name_7_SHIFT 24
#define lpfc_fcf_record_switch_name_7_MASK 0x000000FF
#define lpfc_fcf_record_switch_name_7_WORD word138
};
struct lpfc_mbx_read_fcf_tbl {
@ -1385,20 +1436,17 @@ struct lpfc_mbx_unreg_vfi {
struct lpfc_mbx_resume_rpi {
uint32_t word1;
#define lpfc_resume_rpi_rpi_SHIFT 0
#define lpfc_resume_rpi_rpi_MASK 0x0000FFFF
#define lpfc_resume_rpi_rpi_WORD word1
#define lpfc_resume_rpi_index_SHIFT 0
#define lpfc_resume_rpi_index_MASK 0x0000FFFF
#define lpfc_resume_rpi_index_WORD word1
#define lpfc_resume_rpi_ii_SHIFT 30
#define lpfc_resume_rpi_ii_MASK 0x00000003
#define lpfc_resume_rpi_ii_WORD word1
#define RESUME_INDEX_RPI 0
#define RESUME_INDEX_VPI 1
#define RESUME_INDEX_VFI 2
#define RESUME_INDEX_FCFI 3
uint32_t event_tag;
uint32_t word3_rsvd;
uint32_t word4_rsvd;
uint32_t word5_rsvd;
uint32_t word6;
#define lpfc_resume_rpi_vpi_SHIFT 0
#define lpfc_resume_rpi_vpi_MASK 0x0000FFFF
#define lpfc_resume_rpi_vpi_WORD word6
#define lpfc_resume_rpi_vfi_SHIFT 16
#define lpfc_resume_rpi_vfi_MASK 0x0000FFFF
#define lpfc_resume_rpi_vfi_WORD word6
};
#define REG_FCF_INVALID_QID 0xFFFF

View file

@ -211,7 +211,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba)
goto out_free_mbox;
do {
lpfc_dump_mem(phba, pmb, offset);
lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
@ -425,6 +425,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
return -EIO;
}
/* Check if the port is disabled */
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 =
@ -524,27 +527,46 @@ lpfc_config_port_post(struct lpfc_hba *phba)
/* Set up error attention (ERATT) polling timer */
mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
lpfc_set_loopback_flag(phba);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
if (phba->hba_flag & LINK_DISABLED) {
lpfc_printf_log(phba,
KERN_ERR, LOG_INIT,
"2598 Adapter Link is disabled.\n");
lpfc_down_link(phba, pmb);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
lpfc_printf_log(phba,
KERN_ERR, LOG_INIT,
"2599 Adapter failed to issue DOWN_LINK"
" mbox command rc 0x%x\n", rc);
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
} else {
lpfc_init_link(phba, pmb, phba->cfg_topology,
phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
lpfc_set_loopback_flag(phba);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0454 Adapter failed to init, mbxCmd x%x "
"INIT_LINK, mbxStatus x%x\n",
mb->mbxCommand, mb->mbxStatus);
/* Clear all interrupt enable conditions */
writel(0, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
/* Clear all pending interrupts */
writel(0xffffffff, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
/* Clear all interrupt enable conditions */
writel(0, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
/* Clear all pending interrupts */
writel(0xffffffff, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
phba->link_state = LPFC_HBA_ERROR;
if (rc != MBX_BUSY)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
phba->link_state = LPFC_HBA_ERROR;
if (rc != MBX_BUSY)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
}
/* MBOX buffer will be freed in mbox compl */
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@ -558,7 +580,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
KERN_ERR,
LOG_INIT,
"0456 Adapter failed to issue "
"ASYNCEVT_ENABLE mbox status x%x \n.",
"ASYNCEVT_ENABLE mbox status x%x\n",
rc);
mempool_free(pmb, phba->mbox_mem_pool);
}
@ -572,7 +594,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed "
"to get Option ROM version status x%x\n.", rc);
"to get Option ROM version status x%x\n", rc);
mempool_free(pmb, phba->mbox_mem_pool);
}
@ -2133,6 +2155,8 @@ lpfc_online(struct lpfc_hba *phba)
vports[i]->fc_flag &= ~FC_OFFLINE_MODE;
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
if (phba->sli_rev == LPFC_SLI_REV4)
vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
}
lpfc_destroy_vport_work_array(phba, vports);
@ -2807,6 +2831,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
att_type = lpfc_sli4_parse_latt_type(phba, acqe_link);
if (att_type != AT_LINK_DOWN && att_type != AT_LINK_UP)
return;
phba->fcoe_eventtag = acqe_link->event_tag;
pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
@ -2894,18 +2919,20 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe);
int rc;
phba->fcoe_eventtag = acqe_fcoe->event_tag;
switch (event_type) {
case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
"2546 New FCF found index 0x%x tag 0x%x \n",
"2546 New FCF found index 0x%x tag 0x%x\n",
acqe_fcoe->fcf_index,
acqe_fcoe->event_tag);
/*
* If the current FCF is in discovered state,
* do nothing.
* If the current FCF is in discovered state, or
* FCF discovery is in progress do nothing.
*/
spin_lock_irq(&phba->hbalock);
if (phba->fcf.fcf_flag & FCF_DISCOVERED) {
if ((phba->fcf.fcf_flag & FCF_DISCOVERED) ||
(phba->hba_flag & FCF_DISC_INPROGRESS)) {
spin_unlock_irq(&phba->hbalock);
break;
}
@ -2922,7 +2949,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL:
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2548 FCF Table full count 0x%x tag 0x%x \n",
"2548 FCF Table full count 0x%x tag 0x%x\n",
bf_get(lpfc_acqe_fcoe_fcf_count, acqe_fcoe),
acqe_fcoe->event_tag);
break;
@ -2930,7 +2957,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
case LPFC_FCOE_EVENT_TYPE_FCF_DEAD:
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
"2549 FCF disconnected fron network index 0x%x"
" tag 0x%x \n", acqe_fcoe->fcf_index,
" tag 0x%x\n", acqe_fcoe->fcf_index,
acqe_fcoe->event_tag);
/* If the event is not for currently used fcf do nothing */
if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index)
@ -4130,8 +4157,7 @@ lpfc_hba_alloc(struct pci_dev *pdev)
/* Allocate memory for HBA structure */
phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL);
if (!phba) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"1417 Failed to allocate hba struct.\n");
dev_err(&pdev->dev, "failed to allocate hba struct\n");
return NULL;
}
@ -4145,6 +4171,9 @@ lpfc_hba_alloc(struct pci_dev *pdev)
return NULL;
}
mutex_init(&phba->ct_event_mutex);
INIT_LIST_HEAD(&phba->ct_ev_waiters);
return phba;
}
@ -4489,23 +4518,6 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
if (!phba->sli4_hba.STAregaddr)
return -ENODEV;
/* With uncoverable error, log the error message and return error */
onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
if (uerrlo_reg.word0 || uerrhi_reg.word0) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"1422 HBA Unrecoverable error: "
"uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
"online0_reg=0x%x, online1_reg=0x%x\n",
uerrlo_reg.word0, uerrhi_reg.word0,
onlnreg0, onlnreg1);
}
return -ENODEV;
}
/* Wait up to 30 seconds for the SLI Port POST done and ready */
for (i = 0; i < 3000; i++) {
sta_reg.word0 = readl(phba->sli4_hba.STAregaddr);
@ -4545,6 +4557,23 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba)
bf_get(lpfc_scratchpad_featurelevel1, &scratchpad),
bf_get(lpfc_scratchpad_featurelevel2, &scratchpad));
/* With uncoverable error, log the error message and return error */
onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr);
onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr);
if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) {
uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr);
uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr);
if (uerrlo_reg.word0 || uerrhi_reg.word0) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"1422 HBA Unrecoverable error: "
"uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, "
"online0_reg=0x%x, online1_reg=0x%x\n",
uerrlo_reg.word0, uerrhi_reg.word0,
onlnreg0, onlnreg1);
}
return -ENODEV;
}
return port_error;
}
@ -7347,6 +7376,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Perform post initialization setup */
lpfc_post_init_setup(phba);
/* Check if there are static vports to be created. */
lpfc_create_static_vport(phba);
return 0;
out_disable_intr:
@ -7636,19 +7668,17 @@ static int __devinit
lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
{
int rc;
uint16_t dev_id;
struct lpfc_sli_intf intf;
if (pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id))
if (pci_read_config_dword(pdev, LPFC_SLIREV_CONF_WORD, &intf.word0))
return -ENODEV;
switch (dev_id) {
case PCI_DEVICE_ID_TIGERSHARK:
if ((bf_get(lpfc_sli_intf_valid, &intf) == LPFC_SLI_INTF_VALID) &&
(bf_get(lpfc_sli_intf_rev, &intf) == LPFC_SLIREV_CONF_SLI4))
rc = lpfc_pci_probe_one_s4(pdev, pid);
break;
default:
else
rc = lpfc_pci_probe_one_s3(pdev, pid);
break;
}
return rc;
}

View file

@ -52,48 +52,85 @@
* This routine prepares the mailbox command for dumping list of static
* vports to be created.
**/
void
int
lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
uint16_t offset)
{
MAILBOX_t *mb;
void *ctx;
struct lpfc_dmabuf *mp;
mb = &pmb->u.mb;
ctx = pmb->context2;
/* Setup to dump vport info region */
memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
mb->mbxCommand = MBX_DUMP_MEMORY;
mb->un.varDmp.cv = 1;
mb->un.varDmp.type = DMP_NV_PARAMS;
mb->un.varDmp.entry_index = offset;
mb->un.varDmp.region_id = DMP_REGION_VPORT;
mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t);
mb->un.varDmp.co = 0;
mb->un.varDmp.resp_offset = 0;
pmb->context2 = ctx;
mb->mbxOwner = OWN_HOST;
return;
/* For SLI3 HBAs data is embedded in mailbox */
if (phba->sli_rev != LPFC_SLI_REV4) {
mb->un.varDmp.cv = 1;
mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t);
return 0;
}
/* For SLI4 HBAs driver need to allocate memory */
mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (mp)
mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
if (!mp || !mp->virt) {
kfree(mp);
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
"2605 lpfc_dump_static_vport: memory"
" allocation failed\n");
return 1;
}
memset(mp->virt, 0, LPFC_BPL_SIZE);
INIT_LIST_HEAD(&mp->list);
/* save address for completion */
pmb->context2 = (uint8_t *) mp;
mb->un.varWords[3] = putPaddrLow(mp->phys);
mb->un.varWords[4] = putPaddrHigh(mp->phys);
mb->un.varDmp.sli4_length = sizeof(struct static_vport_info);
return 0;
}
/**
* lpfc_dump_mem - Prepare a mailbox command for retrieving HBA's VPD memory
* lpfc_down_link - Bring down HBAs link.
* @phba: pointer to lpfc hba data structure.
* @pmb: pointer to the driver internal queue element for mailbox command.
* @offset: offset for dumping VPD memory mailbox command.
*
* This routine prepares a mailbox command to bring down HBA link.
**/
void
lpfc_down_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
MAILBOX_t *mb;
memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
mb = &pmb->u.mb;
mb->mbxCommand = MBX_DOWN_LINK;
mb->mbxOwner = OWN_HOST;
}
/**
* lpfc_dump_mem - Prepare a mailbox command for reading a region.
* @phba: pointer to lpfc hba data structure.
* @pmb: pointer to the driver internal queue element for mailbox command.
* @offset: offset into the region.
* @region_id: config region id.
*
* The dump mailbox command provides a method for the device driver to obtain
* various types of information from the HBA device.
*
* This routine prepares the mailbox command for dumping HBA Vital Product
* Data (VPD) memory. This mailbox command is to be used for retrieving a
* portion (DMP_RSP_SIZE bytes) of a HBA's VPD from the HBA at an address
* offset specified by the offset parameter.
* This routine prepares the mailbox command for dumping HBA's config region.
**/
void
lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset)
lpfc_dump_mem(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint16_t offset,
uint16_t region_id)
{
MAILBOX_t *mb;
void *ctx;
@ -107,7 +144,7 @@ lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset)
mb->un.varDmp.cv = 1;
mb->un.varDmp.type = DMP_NV_PARAMS;
mb->un.varDmp.entry_index = offset;
mb->un.varDmp.region_id = DMP_REGION_VPD;
mb->un.varDmp.region_id = region_id;
mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t));
mb->un.varDmp.co = 0;
mb->un.varDmp.resp_offset = 0;
@ -1789,6 +1826,7 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
/**
* lpfc_init_vpi - Initialize the INIT_VPI mailbox command
* @phba: pointer to the hba structure to init the VPI for.
* @mbox: pointer to lpfc mbox command to initialize.
* @vpi: VPI to be initialized.
*
@ -1799,11 +1837,14 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
* successful virtual NPort login.
**/
void
lpfc_init_vpi(struct lpfcMboxq *mbox, uint16_t vpi)
lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi)
{
memset(mbox, 0, sizeof(*mbox));
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VPI);
bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi, vpi);
bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi,
vpi + phba->vpi_base);
bf_set(lpfc_init_vpi_vfi, &mbox->u.mqe.un.init_vpi,
phba->pport->vfi + phba->vfi_base);
}
/**
@ -1852,7 +1893,7 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba,
/* dump_fcoe_param failed to allocate memory */
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
"2569 lpfc_dump_fcoe_param: memory"
" allocation failed \n");
" allocation failed\n");
return 1;
}
@ -1864,8 +1905,8 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba,
mb->mbxCommand = MBX_DUMP_MEMORY;
mb->un.varDmp.type = DMP_NV_PARAMS;
mb->un.varDmp.region_id = DMP_REGION_FCOEPARAM;
mb->un.varDmp.sli4_length = DMP_FCOEPARAM_RGN_SIZE;
mb->un.varDmp.region_id = DMP_REGION_23;
mb->un.varDmp.sli4_length = DMP_RGN23_SIZE;
mb->un.varWords[3] = putPaddrLow(mp->phys);
mb->un.varWords[4] = putPaddrHigh(mp->phys);
return 0;
@ -1938,9 +1979,7 @@ lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp)
memset(mbox, 0, sizeof(*mbox));
resume_rpi = &mbox->u.mqe.un.resume_rpi;
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI);
bf_set(lpfc_resume_rpi_rpi, resume_rpi, ndlp->nlp_rpi);
bf_set(lpfc_resume_rpi_vpi, resume_rpi,
ndlp->vport->vpi + ndlp->vport->phba->vpi_base);
bf_set(lpfc_resume_rpi_vfi, resume_rpi,
ndlp->vport->vfi + ndlp->vport->phba->vfi_base);
bf_set(lpfc_resume_rpi_index, resume_rpi, ndlp->nlp_rpi);
bf_set(lpfc_resume_rpi_ii, resume_rpi, RESUME_INDEX_RPI);
resume_rpi->event_tag = ndlp->phba->fc_eventTag;
}

View file

@ -110,17 +110,28 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
sizeof(struct lpfc_nodelist));
if (!phba->nlp_mem_pool)
goto fail_free_mbox_pool;
phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
if (phba->sli_rev == LPFC_SLI_REV4) {
phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool",
phba->pcidev,
LPFC_HDR_BUF_SIZE, align, 0);
if (!phba->lpfc_hrb_pool)
goto fail_free_nlp_mem_pool;
phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
if (!phba->lpfc_hrb_pool)
goto fail_free_nlp_mem_pool;
phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool",
phba->pcidev,
LPFC_DATA_BUF_SIZE, align, 0);
if (!phba->lpfc_drb_pool)
goto fail_free_hbq_pool;
if (!phba->lpfc_drb_pool)
goto fail_free_hrb_pool;
phba->lpfc_hbq_pool = NULL;
} else {
phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",
phba->pcidev, LPFC_BPL_SIZE, align, 0);
if (!phba->lpfc_hbq_pool)
goto fail_free_nlp_mem_pool;
phba->lpfc_hrb_pool = NULL;
phba->lpfc_drb_pool = NULL;
}
/* vpi zero is reserved for the physical port so add 1 to max */
longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
@ -132,7 +143,7 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align)
fail_free_dbq_pool:
pci_pool_destroy(phba->lpfc_drb_pool);
phba->lpfc_drb_pool = NULL;
fail_free_hbq_pool:
fail_free_hrb_pool:
pci_pool_destroy(phba->lpfc_hrb_pool);
phba->lpfc_hrb_pool = NULL;
fail_free_nlp_mem_pool:
@ -176,11 +187,17 @@ lpfc_mem_free(struct lpfc_hba *phba)
/* Free HBQ pools */
lpfc_sli_hbqbuf_free_all(phba);
pci_pool_destroy(phba->lpfc_drb_pool);
if (phba->lpfc_drb_pool)
pci_pool_destroy(phba->lpfc_drb_pool);
phba->lpfc_drb_pool = NULL;
pci_pool_destroy(phba->lpfc_hrb_pool);
if (phba->lpfc_hrb_pool)
pci_pool_destroy(phba->lpfc_hrb_pool);
phba->lpfc_hrb_pool = NULL;
if (phba->lpfc_hbq_pool)
pci_pool_destroy(phba->lpfc_hbq_pool);
phba->lpfc_hbq_pool = NULL;
/* Free NLP memory pool */
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
@ -380,7 +397,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba)
if (!hbqbp)
return NULL;
hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL,
hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL,
&hbqbp->dbuf.phys);
if (!hbqbp->dbuf.virt) {
kfree(hbqbp);
@ -405,7 +422,7 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba)
void
lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp)
{
pci_pool_free(phba->lpfc_hrb_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
kfree(hbqbp);
return;
}

View file

@ -177,3 +177,23 @@ struct temp_event {
uint32_t data;
};
/* bsg definitions */
#define LPFC_BSG_VENDOR_SET_CT_EVENT 1
#define LPFC_BSG_VENDOR_GET_CT_EVENT 2
struct set_ct_event {
uint32_t command;
uint32_t ev_req_id;
uint32_t ev_reg_id;
};
struct get_ct_event {
uint32_t command;
uint32_t ev_reg_id;
uint32_t ev_req_id;
};
struct get_ct_event_reply {
uint32_t immed_data;
uint32_t type;
};

View file

@ -2142,7 +2142,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
} else if (resp_info & RESID_OVER) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"9028 FCP command x%x residual overrun error. "
"Data: x%x x%x \n", cmnd->cmnd[0],
"Data: x%x x%x\n", cmnd->cmnd[0],
scsi_bufflen(cmnd), scsi_get_resid(cmnd));
host_status = DID_ERROR;
@ -2843,7 +2843,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
dif_op_str[scsi_get_prot_op(cmnd)]);
lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9034 BLKGRD: CDB: %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x \n",
"%02x %02x %02x %02x %02x\n",
cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2],
cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5],
cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8],
@ -2871,7 +2871,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
dif_op_str[scsi_get_prot_op(cmnd)]);
lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG,
"9039 BLKGRD: CDB: %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x \n",
"%02x %02x %02x %02x %02x\n",
cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2],
cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5],
cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8],
@ -3584,6 +3584,7 @@ struct scsi_host_template lpfc_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = lpfc_hba_attrs,
.max_sectors = 0xFFFF,
.vendor_id = LPFC_NL_VENDOR_ID,
};
struct scsi_host_template lpfc_vport_template = {

View file

@ -4139,7 +4139,7 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba,
return -EIO;
}
data_length = mqe->un.mb_words[5];
if (data_length > DMP_FCOEPARAM_RGN_SIZE) {
if (data_length > DMP_RGN23_SIZE) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
return -EIO;
@ -4304,7 +4304,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
*/
if (lpfc_sli4_read_fcoe_params(phba, mboxq))
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT,
"2570 Failed to read FCoE parameters \n");
"2570 Failed to read FCoE parameters\n");
/* Issue READ_REV to collect vpd and FW information. */
vpd_size = PAGE_SIZE;
@ -4522,12 +4522,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
lpfc_sli4_rb_setup(phba);
/* Start the ELS watchdog timer */
/*
* The driver for SLI4 is not yet ready to process timeouts
* or interrupts. Once it is, the comment bars can be removed.
*/
/* mod_timer(&vport->els_tmofunc,
* jiffies + HZ * (phba->fc_ratov*2)); */
mod_timer(&vport->els_tmofunc,
jiffies + HZ * (phba->fc_ratov * 2));
/* Start heart beat timer */
mod_timer(&phba->hb_tmofunc,
@ -4706,13 +4702,13 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
spin_lock_irqsave(&phba->hbalock, drvr_flag);
if (!pmbox) {
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
/* processing mbox queue from intr_handler */
if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
return MBX_SUCCESS;
}
processing_queue = 1;
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
pmbox = lpfc_mbox_get(phba);
if (!pmbox) {
spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
@ -5279,6 +5275,18 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
unsigned long iflags;
int rc;
rc = lpfc_mbox_dev_check(phba);
if (unlikely(rc)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
"(%d):2544 Mailbox command x%x (x%x) "
"cannot issue Data: x%x x%x\n",
mboxq->vport ? mboxq->vport->vpi : 0,
mboxq->u.mb.mbxCommand,
lpfc_sli4_mbox_opcode_get(phba, mboxq),
psli->sli_flag, flag);
goto out_not_finished;
}
/* Detect polling mode and jump to a handler */
if (!phba->sli4_hba.intr_enable) {
if (flag == MBX_POLL)
@ -5338,17 +5346,6 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
psli->sli_flag, flag);
goto out_not_finished;
}
rc = lpfc_mbox_dev_check(phba);
if (unlikely(rc)) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
"(%d):2544 Mailbox command x%x (x%x) "
"cannot issue Data: x%x x%x\n",
mboxq->vport ? mboxq->vport->vpi : 0,
mboxq->u.mb.mbxCommand,
lpfc_sli4_mbox_opcode_get(phba, mboxq),
psli->sli_flag, flag);
goto out_not_finished;
}
/* Put the mailbox command to the driver internal FIFO */
psli->slistat.mbox_busy++;
@ -5817,19 +5814,21 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
/**
* lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution
* @phba: Pointer to HBA context object.
* @piocb: Pointer to command iocb.
*
* This routine performs a round robin SCSI command to SLI4 FCP WQ index
* distribution.
* distribution. This is called by __lpfc_sli_issue_iocb_s4() with the hbalock
* held.
*
* Return: index into SLI4 fast-path FCP queue index.
**/
static uint32_t
lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba)
{
static uint32_t fcp_qidx;
++phba->fcp_qidx;
if (phba->fcp_qidx >= phba->cfg_fcp_wq_count)
phba->fcp_qidx = 0;
return fcp_qidx++ % phba->cfg_fcp_wq_count;
return phba->fcp_qidx;
}
/**
@ -6156,7 +6155,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
return IOCB_ERROR;
if (piocb->iocb_flag & LPFC_IO_FCP) {
fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba, piocb);
fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba);
if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe))
return IOCB_ERROR;
} else {
@ -6327,7 +6326,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
KERN_ERR,
LOG_SLI,
"0346 Ring %d handler: unexpected ASYNC_STATUS"
" evt_code 0x%x \n"
" evt_code 0x%x\n"
"W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n"
"W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n"
"W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n"
@ -6789,6 +6788,33 @@ lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
}
/**
* lpfc_sli_bemem_bcopy - SLI memory copy function
* @srcp: Source memory pointer.
* @destp: Destination memory pointer.
* @cnt: Number of words required to be copied.
*
* This function is used for copying data between a data structure
* with big endian representation to local endianness.
* This function can be called with or without lock.
**/
void
lpfc_sli_bemem_bcopy(void *srcp, void *destp, uint32_t cnt)
{
uint32_t *src = srcp;
uint32_t *dest = destp;
uint32_t ldata;
int i;
for (i = 0; i < (int)cnt; i += sizeof(uint32_t)) {
ldata = *src;
ldata = be32_to_cpu(ldata);
*dest = ldata;
src++;
dest++;
}
}
/**
* lpfc_sli_ringpostbuf_put - Function to add a buffer to postbufq
* @phba: Pointer to HBA context object.
@ -7678,12 +7704,6 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
"online0_reg=0x%x, online1_reg=0x%x\n",
uerr_sta_lo, uerr_sta_hi,
onlnreg0, onlnreg1);
/* TEMP: as the driver error recover logic is not
* fully developed, we just log the error message
* and the device error attention action is now
* temporarily disabled.
*/
return 0;
phba->work_status[0] = uerr_sta_lo;
phba->work_status[1] = uerr_sta_hi;
/* Set the driver HA work bitmap */
@ -9499,8 +9519,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
eq->host_index = 0;
eq->hba_index = 0;
if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@ -9604,10 +9623,9 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response);
cq->host_index = 0;
cq->hba_index = 0;
out:
if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
out:
mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@ -9712,8 +9730,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
/* link the mq onto the parent cq child list */
list_add_tail(&mq->list, &cq->child_list);
out:
if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@ -9795,8 +9812,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
/* link the wq onto the parent cq child list */
list_add_tail(&wq->list, &cq->child_list);
out:
if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@ -9970,8 +9986,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
list_add_tail(&drq->list, &cq->child_list);
out:
if (rc != MBX_TIMEOUT)
mempool_free(mbox, phba->mbox_mem_pool);
mempool_free(mbox, phba->mbox_mem_pool);
return status;
}
@ -10026,8 +10041,7 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq)
/* Remove eq from any list */
list_del_init(&eq->list);
if (rc != MBX_TIMEOUT)
mempool_free(mbox, eq->phba->mbox_mem_pool);
mempool_free(mbox, eq->phba->mbox_mem_pool);
return status;
}
@ -10080,8 +10094,7 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq)
}
/* Remove cq from any list */
list_del_init(&cq->list);
if (rc != MBX_TIMEOUT)
mempool_free(mbox, cq->phba->mbox_mem_pool);
mempool_free(mbox, cq->phba->mbox_mem_pool);
return status;
}
@ -10134,8 +10147,7 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq)
}
/* Remove mq from any list */
list_del_init(&mq->list);
if (rc != MBX_TIMEOUT)
mempool_free(mbox, mq->phba->mbox_mem_pool);
mempool_free(mbox, mq->phba->mbox_mem_pool);
return status;
}
@ -10187,8 +10199,7 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq)
}
/* Remove wq from any list */
list_del_init(&wq->list);
if (rc != MBX_TIMEOUT)
mempool_free(mbox, wq->phba->mbox_mem_pool);
mempool_free(mbox, wq->phba->mbox_mem_pool);
return status;
}
@ -10258,8 +10269,7 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq,
}
list_del_init(&hrq->list);
list_del_init(&drq->list);
if (rc != MBX_TIMEOUT)
mempool_free(mbox, hrq->phba->mbox_mem_pool);
mempool_free(mbox, hrq->phba->mbox_mem_pool);
return status;
}
@ -10933,6 +10943,7 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
first_iocbq = lpfc_sli_get_iocbq(vport->phba);
if (first_iocbq) {
/* Initialize the first IOCB. */
first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0;
first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;
first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX;
first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id);
@ -10945,6 +10956,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
first_iocbq->iocb.un.rcvels.remoteID = sid;
first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
}
iocbq = first_iocbq;
/*
@ -10961,6 +10974,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
iocbq->iocb.ulpBdeCount++;
iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
} else {
iocbq = lpfc_sli_get_iocbq(vport->phba);
if (!iocbq) {
@ -10978,6 +10993,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
iocbq->iocb.ulpBdeCount = 1;
iocbq->iocb.un.cont64[0].tus.f.bdeSize =
LPFC_DATA_BUF_SIZE;
first_iocbq->iocb.unsli3.rcvsli3.acc_len +=
bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe);
iocbq->iocb.un.rcvels.remoteID = sid;
list_add_tail(&iocbq->list, &first_iocbq->list);
}
@ -11324,7 +11341,7 @@ lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi)
mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mboxq)
return -ENOMEM;
lpfc_init_vpi(mboxq, vpi);
lpfc_init_vpi(phba, mboxq, vpi);
mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI);
rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo);
if (rc != MBX_TIMEOUT)
@ -11519,6 +11536,7 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
uint32_t alloc_len, req_len;
struct lpfc_mbx_read_fcf_tbl *read_fcf;
phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag;
mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mboxq) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@ -11570,7 +11588,140 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
if (rc == MBX_NOT_FINISHED) {
lpfc_sli4_mbox_cmd_free(phba, mboxq);
error = -EIO;
} else
} else {
spin_lock_irq(&phba->hbalock);
phba->hba_flag |= FCF_DISC_INPROGRESS;
spin_unlock_irq(&phba->hbalock);
error = 0;
}
return error;
}
/**
* lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled.
* @phba: pointer to lpfc hba data structure.
*
* This function read region 23 and parse TLV for port status to
* decide if the user disaled the port. If the TLV indicates the
* port is disabled, the hba_flag is set accordingly.
**/
void
lpfc_sli_read_link_ste(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *pmb = NULL;
MAILBOX_t *mb;
uint8_t *rgn23_data = NULL;
uint32_t offset = 0, data_size, sub_tlv_len, tlv_offset;
int rc;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2600 lpfc_sli_read_serdes_param failed to"
" allocate mailbox memory\n");
goto out;
}
mb = &pmb->u.mb;
/* Get adapter Region 23 data */
rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL);
if (!rgn23_data)
goto out;
do {
lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"2601 lpfc_sli_read_link_ste failed to"
" read config region 23 rc 0x%x Status 0x%x\n",
rc, mb->mbxStatus);
mb->un.varDmp.word_cnt = 0;
}
/*
* dump mem may return a zero when finished or we got a
* mailbox error, either way we are done.
*/
if (mb->un.varDmp.word_cnt == 0)
break;
if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset)
mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset;
lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
rgn23_data + offset,
mb->un.varDmp.word_cnt);
offset += mb->un.varDmp.word_cnt;
} while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE);
data_size = offset;
offset = 0;
if (!data_size)
goto out;
/* Check the region signature first */
if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2619 Config region 23 has bad signature\n");
goto out;
}
offset += 4;
/* Check the data structure version */
if (rgn23_data[offset] != LPFC_REGION23_VERSION) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2620 Config region 23 has bad version\n");
goto out;
}
offset += 4;
/* Parse TLV entries in the region */
while (offset < data_size) {
if (rgn23_data[offset] == LPFC_REGION23_LAST_REC)
break;
/*
* If the TLV is not driver specific TLV or driver id is
* not linux driver id, skip the record.
*/
if ((rgn23_data[offset] != DRIVER_SPECIFIC_TYPE) ||
(rgn23_data[offset + 2] != LINUX_DRIVER_ID) ||
(rgn23_data[offset + 3] != 0)) {
offset += rgn23_data[offset + 1] * 4 + 4;
continue;
}
/* Driver found a driver specific TLV in the config region */
sub_tlv_len = rgn23_data[offset + 1] * 4;
offset += 4;
tlv_offset = 0;
/*
* Search for configured port state sub-TLV.
*/
while ((offset < data_size) &&
(tlv_offset < sub_tlv_len)) {
if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) {
offset += 4;
tlv_offset += 4;
break;
}
if (rgn23_data[offset] != PORT_STE_TYPE) {
offset += rgn23_data[offset + 1] * 4 + 4;
tlv_offset += rgn23_data[offset + 1] * 4 + 4;
continue;
}
/* This HBA contains PORT_STE configured */
if (!rgn23_data[offset + 2])
phba->hba_flag |= LINK_DISABLED;
goto out;
}
}
out:
if (pmb)
mempool_free(pmb, phba->mbox_mem_pool);
kfree(rgn23_data);
return;
}

View file

@ -132,6 +132,7 @@ struct lpfc_sli4_link {
struct lpfc_fcf {
uint8_t fabric_name[8];
uint8_t switch_name[8];
uint8_t mac_addr[6];
uint16_t fcf_indx;
uint16_t fcfi;
@ -150,6 +151,10 @@ struct lpfc_fcf {
#define LPFC_REGION23_SIGNATURE "RG23"
#define LPFC_REGION23_VERSION 1
#define LPFC_REGION23_LAST_REC 0xff
#define DRIVER_SPECIFIC_TYPE 0xA2
#define LINUX_DRIVER_ID 0x20
#define PORT_STE_TYPE 0x1
struct lpfc_fip_param_hdr {
uint8_t type;
#define FCOE_PARAM_TYPE 0xA0

View file

@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
#define LPFC_DRIVER_VERSION "8.3.3"
#define LPFC_DRIVER_VERSION "8.3.4"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"

View file

@ -313,22 +313,6 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
goto error_out;
}
/*
* In SLI4, the vpi must be activated before it can be used
* by the port.
*/
if (phba->sli_rev == LPFC_SLI_REV4) {
rc = lpfc_sli4_init_vpi(phba, vpi);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"1838 Failed to INIT_VPI on vpi %d "
"status %d\n", vpi, rc);
rc = VPORT_NORESOURCES;
lpfc_free_vpi(phba, vpi);
goto error_out;
}
}
/* Assign an unused board number */
if ((instance = lpfc_get_instance()) < 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
@ -367,12 +351,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
goto error_out;
}
memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8);
memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8);
if (fc_vport->node_name != 0)
u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn);
if (fc_vport->port_name != 0)
u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn);
u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn);
u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn);
memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8);
memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8);
@ -404,7 +384,34 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
*(struct lpfc_vport **)fc_vport->dd_data = vport;
vport->fc_vport = fc_vport;
/*
* In SLI4, the vpi must be activated before it can be used
* by the port.
*/
if ((phba->sli_rev == LPFC_SLI_REV4) &&
(pport->vfi_state & LPFC_VFI_REGISTERED)) {
rc = lpfc_sli4_init_vpi(phba, vpi);
if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
"1838 Failed to INIT_VPI on vpi %d "
"status %d\n", vpi, rc);
rc = VPORT_NORESOURCES;
lpfc_free_vpi(phba, vpi);
goto error_out;
}
} else if (phba->sli_rev == LPFC_SLI_REV4) {
/*
* Driver cannot INIT_VPI now. Set the flags to
* init_vpi when reg_vfi complete.
*/
vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
rc = VPORT_OK;
goto out;
}
if ((phba->link_state < LPFC_LINK_UP) ||
(pport->port_state < LPFC_FABRIC_CFG_LINK) ||
(phba->fc_topology == TOPOLOGY_LOOP)) {
lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
rc = VPORT_OK;
@ -661,7 +668,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
lpfc_printf_log(vport->phba, KERN_WARNING,
LOG_VPORT,
"1829 CT command failed to "
"delete objects on fabric. \n");
"delete objects on fabric\n");
}
/* First look for the Fabric ndlp */
ndlp = lpfc_findnode_did(vport, Fabric_DID);

View file

@ -94,7 +94,7 @@ _base_fault_reset_work(struct work_struct *work)
int rc;
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->ioc_reset_in_progress)
if (ioc->shost_recovery)
goto rearm_timer;
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
@ -687,6 +687,14 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
ioc->mask_interrupts = 0;
}
union reply_descriptor {
u64 word;
struct {
u32 low;
u32 high;
} u;
};
/**
* _base_interrupt - MPT adapter (IOC) specific interrupt handler.
* @irq: irq number (not used)
@ -698,47 +706,38 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
static irqreturn_t
_base_interrupt(int irq, void *bus_id)
{
union reply_descriptor {
u64 word;
struct {
u32 low;
u32 high;
} u;
};
union reply_descriptor rd;
u32 post_index, post_index_next, completed_cmds;
u32 completed_cmds;
u8 request_desript_type;
u16 smid;
u8 cb_idx;
u32 reply;
u8 VF_ID;
int i;
struct MPT2SAS_ADAPTER *ioc = bus_id;
Mpi2ReplyDescriptorsUnion_t *rpf;
if (ioc->mask_interrupts)
return IRQ_NONE;
post_index = ioc->reply_post_host_index;
request_desript_type = ioc->reply_post_free[post_index].
Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
rpf = &ioc->reply_post_free[ioc->reply_post_host_index];
request_desript_type = rpf->Default.ReplyFlags
& MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
return IRQ_NONE;
completed_cmds = 0;
do {
rd.word = ioc->reply_post_free[post_index].Words;
rd.word = rpf->Words;
if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
goto out;
reply = 0;
cb_idx = 0xFF;
smid = le16_to_cpu(ioc->reply_post_free[post_index].
Default.DescriptorTypeDependent1);
VF_ID = ioc->reply_post_free[post_index].
Default.VF_ID;
smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
VF_ID = rpf->Default.VF_ID;
if (request_desript_type ==
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
reply = le32_to_cpu(ioc->reply_post_free[post_index].
AddressReply.ReplyFrameAddress);
reply = le32_to_cpu
(rpf->AddressReply.ReplyFrameAddress);
} else if (request_desript_type ==
MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER)
goto next;
@ -765,21 +764,27 @@ _base_interrupt(int irq, void *bus_id)
0 : ioc->reply_free_host_index + 1;
ioc->reply_free[ioc->reply_free_host_index] =
cpu_to_le32(reply);
wmb();
writel(ioc->reply_free_host_index,
&ioc->chip->ReplyFreeHostIndex);
wmb();
}
next:
post_index_next = (post_index == (ioc->reply_post_queue_depth -
1)) ? 0 : post_index + 1;
rpf->Words = ULLONG_MAX;
ioc->reply_post_host_index = (ioc->reply_post_host_index ==
(ioc->reply_post_queue_depth - 1)) ? 0 :
ioc->reply_post_host_index + 1;
request_desript_type =
ioc->reply_post_free[post_index_next].Default.ReplyFlags
& MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
ioc->reply_post_free[ioc->reply_post_host_index].Default.
ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
completed_cmds++;
if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
goto out;
post_index = post_index_next;
if (!ioc->reply_post_host_index)
rpf = ioc->reply_post_free;
else
rpf++;
} while (1);
out:
@ -787,19 +792,8 @@ _base_interrupt(int irq, void *bus_id)
if (!completed_cmds)
return IRQ_NONE;
/* reply post descriptor handling */
post_index_next = ioc->reply_post_host_index;
for (i = 0 ; i < completed_cmds; i++) {
post_index = post_index_next;
/* poison the reply post descriptor */
ioc->reply_post_free[post_index_next].Words = ULLONG_MAX;
post_index_next = (post_index ==
(ioc->reply_post_queue_depth - 1))
? 0 : post_index + 1;
}
ioc->reply_post_host_index = post_index_next;
writel(post_index_next, &ioc->chip->ReplyPostHostIndex);
wmb();
writel(ioc->reply_post_host_index, &ioc->chip->ReplyPostHostIndex);
return IRQ_HANDLED;
}
@ -1542,6 +1536,8 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
(ioc->bios_pg3.BiosVersion & 0x0000FF00) >> 8,
ioc->bios_pg3.BiosVersion & 0x000000FF);
_base_display_dell_branding(ioc);
printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name);
if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
@ -1554,8 +1550,6 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
i++;
}
_base_display_dell_branding(ioc);
i = 0;
printk("), ");
printk("Capabilities=(");
@ -1627,6 +1621,9 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
u32 iounit_pg1_flags;
mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
if (ioc->ir_firmware)
mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply,
&ioc->manu_pg10);
mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
@ -1647,7 +1644,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
iounit_pg1_flags |=
MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, ioc->iounit_pg1);
mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
}
/**
@ -3303,13 +3300,11 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
mutex_init(&ioc->tm_cmds.mutex);
init_completion(&ioc->tm_cmds.done);
/* config page internal command bits */
ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->config_cmds.status = MPT2_CMD_NOT_USED;
mutex_init(&ioc->config_cmds.mutex);
init_completion(&ioc->config_cmds.done);
/* ctl module internal command bits */
ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
@ -3433,6 +3428,7 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
if (ioc->config_cmds.status & MPT2_CMD_PENDING) {
ioc->config_cmds.status |= MPT2_CMD_RESET;
mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid);
ioc->config_cmds.smid = USHORT_MAX;
complete(&ioc->config_cmds.done);
}
break;
@ -3501,20 +3497,13 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
__func__));
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->ioc_reset_in_progress) {
if (ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
printk(MPT2SAS_ERR_FMT "%s: busy\n",
ioc->name, __func__);
return -EBUSY;
}
ioc->ioc_reset_in_progress = 1;
ioc->shost_recovery = 1;
if (ioc->shost->shost_state == SHOST_RUNNING) {
/* set back to SHOST_RUNNING in mpt2sas_scsih.c */
scsi_host_set_state(ioc->shost, SHOST_RECOVERY);
printk(MPT2SAS_INFO_FMT "putting controller into "
"SHOST_RECOVERY\n", ioc->name);
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
_base_reset_handler(ioc, MPT2_IOC_PRE_RESET);
@ -3534,7 +3523,10 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
ioc->ioc_reset_in_progress = 0;
ioc->shost_recovery = 0;
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
if (!r)
_base_reset_handler(ioc, MPT2_IOC_RUNNING);
return r;
}

View file

@ -69,10 +69,10 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <[email protected]>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
#define MPT2SAS_DRIVER_VERSION "01.100.04.00"
#define MPT2SAS_DRIVER_VERSION "01.100.06.00"
#define MPT2SAS_MAJOR_VERSION 01
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 04
#define MPT2SAS_BUILD_VERSION 06
#define MPT2SAS_RELEASE_VERSION 00
/*
@ -119,6 +119,7 @@
#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */
#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */
#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */
#define MPT2_IOC_RUNNING 4 /* shost running */
/*
* logging format
@ -196,6 +197,38 @@ struct MPT2SAS_TARGET {
* @block: device is in SDEV_BLOCK state
* @tlr_snoop_check: flag used in determining whether to disable TLR
*/
/* OEM Identifiers */
#define MFG10_OEM_ID_INVALID (0x00000000)
#define MFG10_OEM_ID_DELL (0x00000001)
#define MFG10_OEM_ID_FSC (0x00000002)
#define MFG10_OEM_ID_SUN (0x00000003)
#define MFG10_OEM_ID_IBM (0x00000004)
/* GENERIC Flags 0*/
#define MFG10_GF0_OCE_DISABLED (0x00000001)
#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002)
#define MFG10_GF0_R10_DISPLAY (0x00000004)
#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008)
#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010)
/* OEM Specific Flags will come from OEM specific header files */
typedef struct _MPI2_CONFIG_PAGE_MAN_10 {
MPI2_CONFIG_PAGE_HEADER Header; /* 00h */
U8 OEMIdentifier; /* 04h */
U8 Reserved1; /* 05h */
U16 Reserved2; /* 08h */
U32 Reserved3; /* 0Ch */
U32 GenericFlags0; /* 10h */
U32 GenericFlags1; /* 14h */
U32 Reserved4; /* 18h */
U32 OEMSpecificFlags0; /* 1Ch */
U32 OEMSpecificFlags1; /* 20h */
U32 Reserved5[18]; /* 24h-60h*/
} MPI2_CONFIG_PAGE_MAN_10,
MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10,
Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t;
struct MPT2SAS_DEVICE {
struct MPT2SAS_TARGET *sas_target;
unsigned int lun;
@ -431,7 +464,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @fw_event_list: list of fw events
* @aen_event_read_flag: event log was read
* @broadcast_aen_busy: broadcast aen waiting to be serviced
* @ioc_reset_in_progress: host reset in progress
* @shost_recovery: host reset in progress
* @ioc_reset_in_progress_lock:
* @ioc_link_reset_in_progress: phy/hard reset in progress
* @ignore_loginfos: ignore loginfos during task managment
@ -460,6 +493,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @facts: static facts data
* @pfacts: static port facts data
* @manu_pg0: static manufacturing page 0
* @manu_pg10: static manufacturing page 10
* @bios_pg2: static bios page 2
* @bios_pg3: static bios page 3
* @ioc_pg8: static ioc page 8
@ -544,7 +578,6 @@ struct MPT2SAS_ADAPTER {
/* misc flags */
int aen_event_read_flag;
u8 broadcast_aen_busy;
u8 ioc_reset_in_progress;
u8 shost_recovery;
spinlock_t ioc_reset_in_progress_lock;
u8 ioc_link_reset_in_progress;
@ -663,6 +696,7 @@ struct MPT2SAS_ADAPTER {
dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT];
u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT];
u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT];
Mpi2ManufacturingPage10_t manu_pg10;
u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23];
u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
};
@ -734,6 +768,8 @@ void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 re
int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys);
int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page);
int mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page);
int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2BiosPage2_t *config_page);
int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
@ -749,7 +785,7 @@ int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRep
int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t config_page);
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
@ -776,7 +812,6 @@ int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
u16 *volume_handle);
int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
u64 *wwid);
/* ctl shared API */
extern struct device_attribute *mpt2sas_host_attrs[];
extern struct device_attribute *mpt2sas_dev_attrs[];
@ -798,9 +833,11 @@ int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev);
int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
*mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev);
void mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle,
void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle,
u16 attached_handle, u8 phy_number, u8 link_rate);
extern struct sas_function_template mpt2sas_transport_functions;
extern struct scsi_transport_template *mpt2sas_transport_template;
extern int scsi_internal_device_block(struct scsi_device *sdev);
extern int scsi_internal_device_unblock(struct scsi_device *sdev);
#endif /* MPT2SAS_BASE_H_INCLUDED */

File diff suppressed because it is too large Load diff

View file

@ -1963,7 +1963,6 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
{
enum block_state state;
long ret = -EINVAL;
unsigned long flags;
state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING :
BLOCKING;
@ -1989,13 +1988,8 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
!ioc)
return -ENODEV;
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
flags);
if (ioc->shost_recovery)
return -EAGAIN;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
uarg = arg;
@ -2098,7 +2092,6 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
struct mpt2_ioctl_command karg;
struct MPT2SAS_ADAPTER *ioc;
enum block_state state;
unsigned long flags;
if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
return -EINVAL;
@ -2113,13 +2106,8 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg)
if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
flags);
if (ioc->shost_recovery)
return -EAGAIN;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
karg.hdr.ioc_number = karg32.hdr.ioc_number;

View file

@ -103,7 +103,6 @@ struct sense_info {
};
#define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF)
/**
* struct fw_event_work - firmware event struct
* @list: link list framework
@ -1502,7 +1501,13 @@ _scsih_slave_configure(struct scsi_device *sdev)
break;
case MPI2_RAID_VOL_TYPE_RAID1E:
qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
r_level = "RAID1E";
if (ioc->manu_pg10.OEMIdentifier &&
(ioc->manu_pg10.GenericFlags0 &
MFG10_GF0_R10_DISPLAY) &&
!(raid_device->num_pds % 2))
r_level = "RAID10";
else
r_level = "RAID1E";
break;
case MPI2_RAID_VOL_TYPE_RAID1:
qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
@ -1786,17 +1791,18 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
u32 ioc_state;
unsigned long timeleft;
u8 VF_ID = 0;
unsigned long flags;
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED ||
ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
__func__, ioc->name);
return;
}
if (ioc->shost_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
if (ioc_state & MPI2_DOORBELL_USED) {
@ -1830,6 +1836,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
mpi_request->TaskMID = cpu_to_le16(smid_task);
int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
mpt2sas_scsih_set_tm_flag(ioc, handle);
init_completion(&ioc->tm_cmds.done);
mpt2sas_base_put_smid_hi_priority(ioc, smid, VF_ID);
timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
mpt2sas_scsih_clear_tm_flag(ioc, handle);
@ -2222,7 +2229,7 @@ _scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
MPT2SAS_INFO_FMT "SDEV_RUNNING: "
"handle(0x%04x)\n", ioc->name, handle));
sas_device_priv_data->block = 0;
scsi_device_set_state(sdev, SDEV_RUNNING);
scsi_internal_device_unblock(sdev);
}
}
}
@ -2251,7 +2258,7 @@ _scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
MPT2SAS_INFO_FMT "SDEV_BLOCK: "
"handle(0x%04x)\n", ioc->name, handle));
sas_device_priv_data->block = 1;
scsi_device_set_state(sdev, SDEV_BLOCK);
scsi_internal_device_block(sdev);
}
}
}
@ -2327,6 +2334,7 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
u16 handle;
u16 reason_code;
u8 phy_number;
u8 link_rate;
for (i = 0; i < event_data->NumEntries; i++) {
handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
@ -2337,6 +2345,11 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_RC_MASK;
if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
_scsih_block_io_device(ioc, handle);
if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
link_rate = event_data->PHY[i].LinkRate >> 4;
if (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)
_scsih_ublock_io_device(ioc, handle);
}
}
}
@ -2404,27 +2417,6 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
/**
* _scsih_queue_rescan - queue a topology rescan from user context
* @ioc: per adapter object
*
* Return nothing.
*/
static void
_scsih_queue_rescan(struct MPT2SAS_ADAPTER *ioc)
{
struct fw_event_work *fw_event;
if (ioc->wait_for_port_enable_to_complete)
return;
fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
if (!fw_event)
return;
fw_event->event = MPT2SAS_RESCAN_AFTER_HOST_RESET;
fw_event->ioc = ioc;
_scsih_fw_event_add(ioc, fw_event);
}
/**
* _scsih_flush_running_cmds - completing outstanding commands.
* @ioc: per adapter object
@ -2455,46 +2447,6 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
ioc->name, count));
}
/**
* mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
* @ioc: per adapter object
* @reset_phase: phase
*
* The handler for doing any required cleanup or initialization.
*
* The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
* MPT2_IOC_DONE_RESET
*
* Return nothing.
*/
void
mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
{
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
_scsih_fw_event_off(ioc);
break;
case MPT2_IOC_AFTER_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
ioc->tm_cmds.status |= MPT2_CMD_RESET;
mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
complete(&ioc->tm_cmds.done);
}
_scsih_fw_event_on(ioc);
_scsih_flush_running_cmds(ioc);
break;
case MPT2_IOC_DONE_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
_scsih_queue_rescan(ioc);
break;
}
}
/**
* _scsih_setup_eedp - setup MPI request for EEDP transfer
* @scmd: pointer to scsi command object
@ -2615,7 +2567,6 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
Mpi2SCSIIORequest_t *mpi_request;
u32 mpi_control;
u16 smid;
unsigned long flags;
scmd->scsi_done = done;
sas_device_priv_data = scmd->device->hostdata;
@ -2634,13 +2585,10 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
}
/* see if we are busy with task managment stuff */
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (sas_target_priv_data->tm_busy ||
ioc->shost_recovery || ioc->ioc_link_reset_in_progress) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
if (sas_target_priv_data->tm_busy)
return SCSI_MLQUEUE_DEVICE_BUSY;
else if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
return SCSI_MLQUEUE_HOST_BUSY;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
if (scmd->sc_data_direction == DMA_FROM_DEVICE)
mpi_control = MPI2_SCSIIO_CONTROL_READ;
@ -3188,25 +3136,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
scmd->scsi_done(scmd);
}
/**
* _scsih_link_change - process phy link changes
* @ioc: per adapter object
* @handle: phy handle
* @attached_handle: valid for devices attached to link
* @phy_number: phy number
* @link_rate: new link rate
* Context: user.
*
* Return nothing.
*/
static void
_scsih_link_change(struct MPT2SAS_ADAPTER *ioc, u16 handle, u16 attached_handle,
u8 phy_number, u8 link_rate)
{
mpt2sas_transport_update_phy_link_change(ioc, handle, attached_handle,
phy_number, link_rate);
}
/**
* _scsih_sas_host_refresh - refreshing sas host object contents
* @ioc: per adapter object
@ -3251,7 +3180,8 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc, u8 update)
le16_to_cpu(sas_iounit_pg0->PhyData[i].
ControllerDevHandle);
if (update)
_scsih_link_change(ioc,
mpt2sas_transport_update_links(
ioc,
ioc->sas_hba.phy[i].handle,
le16_to_cpu(sas_iounit_pg0->PhyData[i].
AttachedDevHandle), i,
@ -3436,6 +3366,9 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
if (!handle)
return -1;
if (ioc->shost_recovery)
return -1;
if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@ -3572,6 +3505,9 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u16 handle)
struct _sas_node *sas_expander;
unsigned long flags;
if (ioc->shost_recovery)
return;
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
@ -3743,6 +3679,8 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
mutex_unlock(&ioc->tm_cmds.mutex);
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
"done: handle(0x%04x)\n", ioc->name, device_handle));
if (ioc->shost_recovery)
goto out;
}
/* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
@ -3765,6 +3703,9 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
le32_to_cpu(mpi_reply.IOCLogInfo)));
out:
_scsih_ublock_io_device(ioc, handle);
mpt2sas_transport_port_remove(ioc, sas_device->sas_address,
sas_device->parent_handle);
@ -3908,6 +3849,8 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
"expander event\n", ioc->name));
return;
}
if (ioc->shost_recovery)
return;
if (event_data->PHY[i].PhyStatus &
MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
continue;
@ -3923,9 +3866,10 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
if (!parent_handle) {
if (phy_number < ioc->sas_hba.num_phys)
_scsih_link_change(ioc,
ioc->sas_hba.phy[phy_number].handle,
handle, phy_number, link_rate_);
mpt2sas_transport_update_links(
ioc,
ioc->sas_hba.phy[phy_number].handle,
handle, phy_number, link_rate_);
} else {
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_expander =
@ -3935,17 +3879,14 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
flags);
if (sas_expander) {
if (phy_number < sas_expander->num_phys)
_scsih_link_change(ioc,
sas_expander->
phy[phy_number].handle,
handle, phy_number,
link_rate_);
mpt2sas_transport_update_links(
ioc,
sas_expander->
phy[phy_number].handle,
handle, phy_number,
link_rate_);
}
}
if (reason_code == MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED) {
if (link_rate_ >= MPI2_SAS_NEG_LINK_RATE_1_5)
_scsih_ublock_io_device(ioc, handle);
}
if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) {
if (link_rate_ < MPI2_SAS_NEG_LINK_RATE_1_5)
break;
@ -4455,7 +4396,7 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
return;
}
_scsih_link_change(ioc,
mpt2sas_transport_update_links(ioc,
le16_to_cpu(sas_device_pg0.ParentDevHandle),
handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
@ -4744,7 +4685,7 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
return;
}
_scsih_link_change(ioc,
mpt2sas_transport_update_links(ioc,
le16_to_cpu(sas_device_pg0.ParentDevHandle),
handle, sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
@ -5156,22 +5097,9 @@ static void
_scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
{
struct _sas_device *sas_device, *sas_device_next;
struct _sas_node *sas_expander, *sas_expander_next;
struct _sas_node *sas_expander;
struct _raid_device *raid_device, *raid_device_next;
unsigned long flags;
_scsih_search_responding_sas_devices(ioc);
_scsih_search_responding_raid_devices(ioc);
_scsih_search_responding_expanders(ioc);
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
ioc->shost_recovery = 0;
if (ioc->shost->shost_state == SHOST_RECOVERY) {
printk(MPT2SAS_INFO_FMT "putting controller into "
"SHOST_RUNNING\n", ioc->name);
scsi_host_set_state(ioc->shost, SHOST_RUNNING);
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
list_for_each_entry_safe(sas_device, sas_device_next,
&ioc->sas_device_list, list) {
@ -5207,16 +5135,63 @@ _scsih_remove_unresponding_devices(struct MPT2SAS_ADAPTER *ioc)
_scsih_raid_device_remove(ioc, raid_device);
}
list_for_each_entry_safe(sas_expander, sas_expander_next,
&ioc->sas_expander_list, list) {
retry_expander_search:
sas_expander = NULL;
list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
if (sas_expander->responding) {
sas_expander->responding = 0;
continue;
}
printk("\tremoving expander: handle(0x%04x), "
" sas_addr(0x%016llx)\n", sas_expander->handle,
(unsigned long long)sas_expander->sas_address);
_scsih_expander_remove(ioc, sas_expander->handle);
goto retry_expander_search;
}
}
/**
* mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
* @ioc: per adapter object
* @reset_phase: phase
*
* The handler for doing any required cleanup or initialization.
*
* The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
* MPT2_IOC_DONE_RESET
*
* Return nothing.
*/
void
mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
{
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
_scsih_fw_event_off(ioc);
break;
case MPT2_IOC_AFTER_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
ioc->tm_cmds.status |= MPT2_CMD_RESET;
mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
complete(&ioc->tm_cmds.done);
}
_scsih_fw_event_on(ioc);
_scsih_flush_running_cmds(ioc);
break;
case MPT2_IOC_DONE_RESET:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
_scsih_sas_host_refresh(ioc, 0);
_scsih_search_responding_sas_devices(ioc);
_scsih_search_responding_raid_devices(ioc);
_scsih_search_responding_expanders(ioc);
break;
case MPT2_IOC_RUNNING:
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
"MPT2_IOC_RUNNING\n", ioc->name, __func__));
_scsih_remove_unresponding_devices(ioc);
break;
}
}
@ -5236,14 +5211,6 @@ _firmware_event_work(struct work_struct *work)
unsigned long flags;
struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
/* This is invoked by calling _scsih_queue_rescan(). */
if (fw_event->event == MPT2SAS_RESCAN_AFTER_HOST_RESET) {
_scsih_fw_event_free(ioc, fw_event);
_scsih_sas_host_refresh(ioc, 1);
_scsih_remove_unresponding_devices(ioc);
return;
}
/* the queue is being flushed so ignore this event */
spin_lock_irqsave(&ioc->fw_event_lock, flags);
if (ioc->fw_events_off || ioc->remove_host) {
@ -5253,13 +5220,10 @@ _firmware_event_work(struct work_struct *work)
}
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
_scsih_fw_event_requeue(ioc, fw_event, 1000);
return;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
switch (fw_event->event) {
case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
@ -5461,6 +5425,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
if (!sas_device)
continue;
_scsih_remove_device(ioc, sas_device->handle);
if (ioc->shost_recovery)
return;
goto retry_device_search;
}
}
@ -5482,6 +5448,8 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
if (!expander_sibling)
continue;
_scsih_expander_remove(ioc, expander_sibling->handle);
if (ioc->shost_recovery)
return;
goto retry_expander_search;
}
}

View file

@ -140,11 +140,18 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
u32 device_info;
u32 ioc_status;
if (ioc->shost_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
}
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -1;
return -ENXIO;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
@ -153,7 +160,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
"\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
__FILE__, __LINE__, __func__);
return -1;
return -EIO;
}
memset(identify, 0, sizeof(identify));
@ -288,21 +295,17 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
void *psge;
u32 sgl_flags;
u8 issue_reset = 0;
unsigned long flags;
void *data_out = NULL;
dma_addr_t data_out_dma;
u32 sz;
u64 *sas_address_le;
u16 wait_state_count;
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->ioc_reset_in_progress) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
mutex_lock(&ioc->transport_cmds.mutex);
@ -789,7 +792,7 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
}
/**
* mpt2sas_transport_update_phy_link_change - refreshing phy link changes and attached devices
* mpt2sas_transport_update_links - refreshing phy link changes
* @ioc: per adapter object
* @handle: handle to sas_host or expander
* @attached_handle: attached device handle
@ -799,13 +802,19 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
* Returns nothing.
*/
void
mpt2sas_transport_update_phy_link_change(struct MPT2SAS_ADAPTER *ioc,
mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate)
{
unsigned long flags;
struct _sas_node *sas_node;
struct _sas_phy *mpt2sas_phy;
if (ioc->shost_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return;
}
spin_lock_irqsave(&ioc->sas_node_lock, flags);
sas_node = _transport_sas_node_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
@ -1025,7 +1034,6 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
void *psge;
u32 sgl_flags;
u8 issue_reset = 0;
unsigned long flags;
dma_addr_t dma_addr_in = 0;
dma_addr_t dma_addr_out = 0;
u16 wait_state_count;
@ -1045,14 +1053,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
return -EINVAL;
}
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->ioc_reset_in_progress) {
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
if (ioc->shost_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
}
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
if (rc)

View file

@ -1713,7 +1713,7 @@ static int nsp_cs_config(struct pcmcia_device *link)
nsp_dbg(NSP_DEBUG_INIT, "in");
cfg_mem = kzalloc(sizeof(cfg_mem), GFP_KERNEL);
cfg_mem = kzalloc(sizeof(*cfg_mem), GFP_KERNEL);
if (!cfg_mem)
return -ENOMEM;
cfg_mem->data = data;

5604
drivers/scsi/pmcraid.c Normal file

File diff suppressed because it is too large Load diff

1029
drivers/scsi/pmcraid.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -1670,7 +1670,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
qla24xx_vport_disable(fc_vport, disable);
if (ql2xmultique_tag) {
if (ha->flags.cpu_affinity_enabled) {
req = ha->req_q_map[1];
goto vport_queue;
} else if (ql2xmaxqueues == 1 || !ha->npiv_info)
@ -1736,6 +1736,11 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
qla24xx_deallocate_vp_id(vha);
mutex_lock(&ha->vport_lock);
ha->cur_vport_count--;
clear_bit(vha->vp_idx, ha->vp_idx_map);
mutex_unlock(&ha->vport_lock);
if (vha->timer_active) {
qla2x00_vp_stop_timer(vha);
DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p "
@ -1743,7 +1748,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
vha->host_no, vha->vp_idx, vha));
}
if (vha->req->id && !ql2xmultique_tag) {
if (vha->req->id && !ha->flags.cpu_affinity_enabled) {
if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS)
qla_printk(KERN_WARNING, ha,
"Queue delete failed.\n");

View file

@ -189,6 +189,7 @@ struct req_que;
*/
typedef struct srb {
struct fc_port *fcport;
uint32_t handle;
struct scsi_cmnd *cmd; /* Linux SCSI command pkt */
@ -196,6 +197,8 @@ typedef struct srb {
uint32_t request_sense_length;
uint8_t *request_sense_ptr;
void *ctx;
} srb_t;
/*
@ -203,6 +206,28 @@ typedef struct srb {
*/
#define SRB_DMA_VALID BIT_0 /* Command sent to ISP */
/*
* SRB extensions.
*/
struct srb_ctx {
#define SRB_LOGIN_CMD 1
#define SRB_LOGOUT_CMD 2
uint16_t type;
struct timer_list timer;
void (*free)(srb_t *sp);
void (*timeout)(srb_t *sp);
};
struct srb_logio {
struct srb_ctx ctx;
#define SRB_LOGIN_RETRIED BIT_0
#define SRB_LOGIN_COND_PLOGI BIT_1
#define SRB_LOGIN_SKIP_PRLI BIT_2
uint16_t flags;
};
/*
* ISP I/O Register Set structure definitions.
*/
@ -1482,7 +1507,7 @@ typedef union {
uint8_t domain;
uint8_t area;
uint8_t al_pa;
#elif __LITTLE_ENDIAN
#elif defined(__LITTLE_ENDIAN)
uint8_t al_pa;
uint8_t area;
uint8_t domain;
@ -1565,6 +1590,7 @@ typedef struct fc_port {
#define FCF_FABRIC_DEVICE BIT_0
#define FCF_LOGIN_NEEDED BIT_1
#define FCF_TAPE_PRESENT BIT_2
#define FCF_FCP2_DEVICE BIT_3
/* No loop ID flag. */
#define FC_NO_LOOP_ID 0x1000
@ -2093,6 +2119,10 @@ struct qla_msix_entry {
enum qla_work_type {
QLA_EVT_AEN,
QLA_EVT_IDC_ACK,
QLA_EVT_ASYNC_LOGIN,
QLA_EVT_ASYNC_LOGIN_DONE,
QLA_EVT_ASYNC_LOGOUT,
QLA_EVT_ASYNC_LOGOUT_DONE,
};
@ -2111,6 +2141,11 @@ struct qla_work_evt {
#define QLA_IDC_ACK_REGS 7
uint16_t mb[QLA_IDC_ACK_REGS];
} idc_ack;
struct {
struct fc_port *fcport;
#define QLA_LOGIO_LOGIN_RETRIED BIT_0
u16 data[2];
} logio;
} u;
};
@ -2224,6 +2259,7 @@ struct qla_hw_data {
uint32_t chip_reset_done :1;
uint32_t port0 :1;
uint32_t running_gold_fw :1;
uint32_t cpu_affinity_enabled :1;
} flags;
/* This spinlock is used to protect "io transactions", you must
@ -2350,6 +2386,7 @@ struct qla_hw_data {
(ha)->flags.msix_enabled)
#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha))
#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha))
#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA)
#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2)

View file

@ -1126,7 +1126,7 @@ struct vp_config_entry_24xx {
uint16_t id;
uint16_t reserved_4;
uint16_t hopct;
uint8_t reserved_5;
uint8_t reserved_5[2];
};
#define VP_RPT_ID_IOCB_TYPE 0x32 /* Report ID Acquisition entry. */

View file

@ -52,6 +52,14 @@ extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
extern void qla84xx_put_chip(struct scsi_qla_host *);
extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
/*
* Global Data in qla_os.c source file.
*/
@ -76,6 +84,15 @@ extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
fc_host_event_code, u32);
extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *);
extern int qla2x00_post_async_login_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_login_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
extern void qla2x00_abort_fcport_cmds(fc_port_t *);
@ -83,6 +100,8 @@ extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *,
struct qla_hw_data *);
extern void qla2x00_free_host(struct scsi_qla_host *);
extern void qla2x00_relogin(struct scsi_qla_host *);
extern void qla2x00_do_work(struct scsi_qla_host *);
/*
* Global Functions in qla_mid.c source file.
*/
@ -135,6 +154,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
extern int qla2x00_start_sp(srb_t *);
/*
* Global Function Prototypes in qla_mbx.c source file.

View file

@ -1674,6 +1674,10 @@ int
qla2x00_fdmi_register(scsi_qla_host_t *vha)
{
int rval;
struct qla_hw_data *ha = vha->hw;
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return QLA_FUNCTION_FAILED;
rval = qla2x00_mgmt_svr_login(vha);
if (rval)

View file

@ -40,6 +40,210 @@ static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
static int qla84xx_init_chip(scsi_qla_host_t *);
static int qla25xx_init_queues(struct qla_hw_data *);
/* SRB Extensions ---------------------------------------------------------- */
static void
qla2x00_ctx_sp_timeout(unsigned long __data)
{
srb_t *sp = (srb_t *)__data;
struct srb_ctx *ctx;
fc_port_t *fcport = sp->fcport;
struct qla_hw_data *ha = fcport->vha->hw;
struct req_que *req;
unsigned long flags;
spin_lock_irqsave(&ha->hardware_lock, flags);
req = ha->req_q_map[0];
req->outstanding_cmds[sp->handle] = NULL;
ctx = sp->ctx;
ctx->timeout(sp);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
ctx->free(sp);
}
static void
qla2x00_ctx_sp_free(srb_t *sp)
{
struct srb_ctx *ctx = sp->ctx;
kfree(ctx);
mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
}
inline srb_t *
qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
unsigned long tmo)
{
srb_t *sp;
struct qla_hw_data *ha = vha->hw;
struct srb_ctx *ctx;
sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
if (!sp)
goto done;
ctx = kzalloc(size, GFP_KERNEL);
if (!ctx) {
mempool_free(sp, ha->srb_mempool);
goto done;
}
memset(sp, 0, sizeof(*sp));
sp->fcport = fcport;
sp->ctx = ctx;
ctx->free = qla2x00_ctx_sp_free;
init_timer(&ctx->timer);
if (!tmo)
goto done;
ctx->timer.expires = jiffies + tmo * HZ;
ctx->timer.data = (unsigned long)sp;
ctx->timer.function = qla2x00_ctx_sp_timeout;
add_timer(&ctx->timer);
done:
return sp;
}
/* Asynchronous Login/Logout Routines -------------------------------------- */
#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
static void
qla2x00_async_logio_timeout(srb_t *sp)
{
fc_port_t *fcport = sp->fcport;
struct srb_logio *lio = sp->ctx;
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s timeout.\n",
fcport->vha->host_no, sp->handle,
lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout"));
if (lio->ctx.type == SRB_LOGIN_CMD)
qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
}
int
qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_logio *lio;
int rval;
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
ELS_TMO_2_RATOV(ha) + 2);
if (!sp)
goto done;
lio = sp->ctx;
lio->ctx.type = SRB_LOGIN_CMD;
lio->ctx.timeout = qla2x00_async_logio_timeout;
lio->flags |= SRB_LOGIN_COND_PLOGI;
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
lio->flags |= SRB_LOGIN_RETRIED;
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
DEBUG2(printk(KERN_DEBUG
"scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x "
"retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
fcport->login_retry));
return rval;
done_free_sp:
del_timer_sync(&lio->ctx.timer);
lio->ctx.free(sp);
done:
return rval;
}
int
qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_logio *lio;
int rval;
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
ELS_TMO_2_RATOV(ha) + 2);
if (!sp)
goto done;
lio = sp->ctx;
lio->ctx.type = SRB_LOGOUT_CMD;
lio->ctx.timeout = qla2x00_async_logio_timeout;
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
DEBUG2(printk(KERN_DEBUG
"scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
fcport->vha->host_no, sp->handle, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
return rval;
done_free_sp:
del_timer_sync(&lio->ctx.timer);
lio->ctx.free(sp);
done:
return rval;
}
int
qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
int rval;
uint8_t opts = 0;
switch (data[0]) {
case MBS_COMMAND_COMPLETE:
if (fcport->flags & FCF_TAPE_PRESENT)
opts |= BIT_1;
rval = qla2x00_get_port_database(vha, fcport, opts);
if (rval != QLA_SUCCESS)
qla2x00_mark_device_lost(vha, fcport, 1, 0);
else
qla2x00_update_fcport(vha, fcport);
break;
case MBS_COMMAND_ERROR:
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
else
qla2x00_mark_device_lost(vha, fcport, 1, 0);
break;
case MBS_PORT_ID_USED:
fcport->loop_id = data[1];
qla2x00_post_async_login_work(vha, fcport, NULL);
break;
case MBS_LOOP_ID_USED:
fcport->loop_id++;
rval = qla2x00_find_new_loop_id(vha, fcport);
if (rval != QLA_SUCCESS) {
qla2x00_mark_device_lost(vha, fcport, 1, 0);
break;
}
qla2x00_post_async_login_work(vha, fcport, NULL);
break;
}
return QLA_SUCCESS;
}
int
qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
qla2x00_mark_device_lost(vha, fcport, 1, 0);
return QLA_SUCCESS;
}
/****************************************************************************/
/* QLogic ISP2x00 Hardware Support Functions. */
/****************************************************************************/
@ -987,7 +1191,6 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
ha->phy_version);
if (rval != QLA_SUCCESS)
goto failed;
ha->flags.npiv_supported = 0;
if (IS_QLA2XXX_MIDTYPE(ha) &&
(ha->fw_attributes & BIT_2)) {
@ -1591,7 +1794,8 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
char *st, *en;
uint16_t index;
struct qla_hw_data *ha = vha->hw;
int use_tbl = !IS_QLA25XX(ha) && !IS_QLA81XX(ha);
int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
!IS_QLA81XX(ha);
if (memcmp(model, BINZERO, len) != 0) {
strncpy(ha->model_number, model, len);
@ -1978,7 +2182,7 @@ qla2x00_rport_del(void *data)
struct fc_rport *rport;
spin_lock_irq(fcport->vha->host->host_lock);
rport = fcport->drport;
rport = fcport->drport ? fcport->drport: fcport->rport;
fcport->drport = NULL;
spin_unlock_irq(fcport->vha->host->host_lock);
if (rport)
@ -2345,8 +2549,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
struct fc_rport *rport;
struct qla_hw_data *ha = vha->hw;
if (fcport->drport)
qla2x00_rport_del(fcport);
qla2x00_rport_del(fcport);
rport_ids.node_name = wwn_to_u64(fcport->node_name);
rport_ids.port_name = wwn_to_u64(fcport->port_name);
@ -3039,6 +3242,12 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
rval = QLA_SUCCESS;
retry = 0;
if (IS_ALOGIO_CAPABLE(ha)) {
rval = qla2x00_post_async_login_work(vha, fcport, NULL);
if (!rval)
return rval;
}
rval = qla2x00_fabric_login(vha, fcport, next_loopid);
if (rval == QLA_SUCCESS) {
/* Send an ADISC to tape devices.*/
@ -3133,7 +3342,7 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
} else {
fcport->port_type = FCT_TARGET;
if (mb[1] & BIT_1) {
fcport->flags |= FCF_TAPE_PRESENT;
fcport->flags |= FCF_FCP2_DEVICE;
}
}
@ -3244,7 +3453,7 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
struct req_que *req;
struct rsp_que *rsp;
if (ql2xmultique_tag)
if (vha->hw->flags.cpu_affinity_enabled)
req = vha->hw->req_q_map[0];
else
req = vha->req;
@ -3286,15 +3495,17 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
}
void
qla2x00_update_fcports(scsi_qla_host_t *vha)
qla2x00_update_fcports(scsi_qla_host_t *base_vha)
{
fc_port_t *fcport;
struct scsi_qla_host *tvp, *vha;
/* Go with deferred removal of rport references. */
list_for_each_entry(fcport, &vha->vp_fcports, list)
if (fcport && fcport->drport &&
atomic_read(&fcport->state) != FCS_UNCONFIGURED)
qla2x00_rport_del(fcport);
list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list)
list_for_each_entry(fcport, &vha->vp_fcports, list)
if (fcport && fcport->drport &&
atomic_read(&fcport->state) != FCS_UNCONFIGURED)
qla2x00_rport_del(fcport);
}
/*
@ -3331,8 +3542,6 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
qla2x00_mark_all_devices_lost(vha, 0);
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list)
qla2x00_mark_all_devices_lost(vp, 0);
} else {
if (!atomic_read(&vha->loop_down_timer))
atomic_set(&vha->loop_down_timer,
@ -4264,7 +4473,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha)
return -EINVAL;
rval = qla2x00_fw_ready(base_vha);
if (ql2xmultique_tag)
if (ha->flags.cpu_affinity_enabled)
req = ha->req_q_map[0];
else
req = vha->req;

View file

@ -350,6 +350,7 @@ qla2x00_start_scsi(srb_t *sp)
/* Build command packet */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
sp->handle = handle;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
req->cnt -= req_cnt;
@ -778,6 +779,7 @@ qla24xx_start_scsi(srb_t *sp)
/* Build command packet. */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
sp->handle = handle;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
req->cnt -= req_cnt;
@ -852,9 +854,211 @@ static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp)
struct qla_hw_data *ha = sp->fcport->vha->hw;
int affinity = cmd->request->cpu;
if (ql2xmultique_tag && affinity >= 0 &&
if (ha->flags.cpu_affinity_enabled && affinity >= 0 &&
affinity < ha->max_rsp_queues - 1)
*rsp = ha->rsp_q_map[affinity + 1];
else
*rsp = ha->rsp_q_map[0];
}
/* Generic Control-SRB manipulation functions. */
static void *
qla2x00_alloc_iocbs(srb_t *sp)
{
scsi_qla_host_t *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
uint32_t index, handle;
request_t *pkt;
uint16_t cnt, req_cnt;
pkt = NULL;
req_cnt = 1;
/* Check for room in outstanding command list. */
handle = req->current_outstanding_cmd;
for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
if (!req->outstanding_cmds[handle])
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
goto queuing_error;
/* Check for room on request queue. */
if (req->cnt < req_cnt) {
if (ha->mqenable)
cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
else if (IS_FWI2_CAPABLE(ha))
cnt = RD_REG_DWORD(&reg->isp24.req_q_out);
else
cnt = qla2x00_debounce_register(
ISP_REQ_Q_OUT(ha, &reg->isp));
if (req->ring_index < cnt)
req->cnt = cnt - req->ring_index;
else
req->cnt = req->length -
(req->ring_index - cnt);
}
if (req->cnt < req_cnt)
goto queuing_error;
/* Prep packet */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
req->cnt -= req_cnt;
pkt = req->ring_ptr;
memset(pkt, 0, REQUEST_ENTRY_SIZE);
pkt->entry_count = req_cnt;
pkt->handle = handle;
sp->handle = handle;
queuing_error:
return pkt;
}
static void
qla2x00_start_iocbs(srb_t *sp)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
struct req_que *req = ha->req_q_map[0];
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
/* Adjust ring index. */
req->ring_index++;
if (req->ring_index == req->length) {
req->ring_index = 0;
req->ring_ptr = req->ring;
} else
req->ring_ptr++;
/* Set chip new ring index. */
if (ha->mqenable) {
WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
RD_REG_DWORD(&ioreg->hccr);
} else if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
} else {
WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp), req->ring_index);
RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
}
}
static void
qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
{
struct srb_logio *lio = sp->ctx;
logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);
if (lio->flags & SRB_LOGIN_COND_PLOGI)
logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI);
if (lio->flags & SRB_LOGIN_SKIP_PRLI)
logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI);
logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
logio->port_id[0] = sp->fcport->d_id.b.al_pa;
logio->port_id[1] = sp->fcport->d_id.b.area;
logio->port_id[2] = sp->fcport->d_id.b.domain;
logio->vp_index = sp->fcport->vp_idx;
}
static void
qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
struct srb_logio *lio = sp->ctx;
uint16_t opts;
mbx->entry_type = MBX_IOCB_TYPE;;
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
opts = lio->flags & SRB_LOGIN_COND_PLOGI ? BIT_0: 0;
opts |= lio->flags & SRB_LOGIN_SKIP_PRLI ? BIT_1: 0;
if (HAS_EXTENDED_IDS(ha)) {
mbx->mb1 = cpu_to_le16(sp->fcport->loop_id);
mbx->mb10 = cpu_to_le16(opts);
} else {
mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | opts);
}
mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain);
mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 |
sp->fcport->d_id.b.al_pa);
mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx);
}
static void
qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio)
{
logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
logio->control_flags =
cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO);
logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
logio->port_id[0] = sp->fcport->d_id.b.al_pa;
logio->port_id[1] = sp->fcport->d_id.b.area;
logio->port_id[2] = sp->fcport->d_id.b.domain;
logio->vp_index = sp->fcport->vp_idx;
}
static void
qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
mbx->entry_type = MBX_IOCB_TYPE;;
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
mbx->mb1 = HAS_EXTENDED_IDS(ha) ?
cpu_to_le16(sp->fcport->loop_id):
cpu_to_le16(sp->fcport->loop_id << 8);
mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain);
mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 |
sp->fcport->d_id.b.al_pa);
mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx);
/* Implicit: mbx->mbx10 = 0. */
}
int
qla2x00_start_sp(srb_t *sp)
{
int rval;
struct qla_hw_data *ha = sp->fcport->vha->hw;
void *pkt;
struct srb_ctx *ctx = sp->ctx;
unsigned long flags;
rval = QLA_FUNCTION_FAILED;
spin_lock_irqsave(&ha->hardware_lock, flags);
pkt = qla2x00_alloc_iocbs(sp);
if (!pkt)
goto done;
rval = QLA_SUCCESS;
switch (ctx->type) {
case SRB_LOGIN_CMD:
IS_FWI2_CAPABLE(ha) ?
qla24xx_login_iocb(sp, pkt):
qla2x00_login_iocb(sp, pkt);
break;
case SRB_LOGOUT_CMD:
IS_FWI2_CAPABLE(ha) ?
qla24xx_logout_iocb(sp, pkt):
qla2x00_logout_iocb(sp, pkt);
break;
default:
break;
}
wmb();
qla2x00_start_iocbs(sp);
done:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return rval;
}

View file

@ -598,9 +598,54 @@ skip_rio:
break;
case MBA_PORT_UPDATE: /* Port database update */
/* Only handle SCNs for our Vport index. */
if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff))
/*
* Handle only global and vn-port update events
*
* Relevant inputs:
* mb[1] = N_Port handle of changed port
* OR 0xffff for global event
* mb[2] = New login state
* 7 = Port logged out
* mb[3] = LSB is vp_idx, 0xff = all vps
*
* Skip processing if:
* Event is global, vp_idx is NOT all vps,
* vp_idx does not match
* Event is not global, vp_idx does not match
*/
if ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff)
|| (mb[1] != 0xffff)) {
if (vha->vp_idx != (mb[3] & 0xff))
break;
}
/* Global event -- port logout or port unavailable. */
if (mb[1] == 0xffff && mb[2] == 0x7) {
DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
vha->host_no));
DEBUG(printk(KERN_INFO
"scsi(%ld): Port unavailable %04x %04x %04x.\n",
vha->host_no, mb[1], mb[2], mb[3]));
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer,
LOOP_DOWN_TIME);
vha->device_flags |= DFLG_NO_CABLE;
qla2x00_mark_all_devices_lost(vha, 1);
}
if (vha->vp_idx) {
atomic_set(&vha->vp_state, VP_FAILED);
fc_vport_set_state(vha->fc_vport,
FC_VPORT_FAILED);
qla2x00_mark_all_devices_lost(vha, 1);
}
vha->flags.management_server_logged_in = 0;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
break;
}
/*
* If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
@ -640,8 +685,9 @@ skip_rio:
if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
break;
/* Only handle SCNs for our Vport index. */
if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff))
if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
break;
DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
vha->host_no));
DEBUG(printk(KERN_INFO
@ -874,6 +920,249 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
}
}
static srb_t *
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
struct req_que *req, void *iocb)
{
struct qla_hw_data *ha = vha->hw;
sts_entry_t *pkt = iocb;
srb_t *sp = NULL;
uint16_t index;
index = LSW(pkt->handle);
if (index >= MAX_OUTSTANDING_COMMANDS) {
qla_printk(KERN_WARNING, ha,
"%s: Invalid completion handle (%x).\n", func, index);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
goto done;
}
sp = req->outstanding_cmds[index];
if (!sp) {
qla_printk(KERN_WARNING, ha,
"%s: Invalid completion handle (%x) -- timed-out.\n", func,
index);
return sp;
}
if (sp->handle != index) {
qla_printk(KERN_WARNING, ha,
"%s: SRB handle (%x) mismatch %x.\n", func, sp->handle,
index);
return NULL;
}
req->outstanding_cmds[index] = NULL;
done:
return sp;
}
static void
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
struct mbx_entry *mbx)
{
const char func[] = "MBX-IOCB";
const char *type;
struct qla_hw_data *ha = vha->hw;
fc_port_t *fcport;
srb_t *sp;
struct srb_logio *lio;
uint16_t data[2];
sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
if (!sp)
return;
type = NULL;
lio = sp->ctx;
switch (lio->ctx.type) {
case SRB_LOGIN_CMD:
type = "login";
break;
case SRB_LOGOUT_CMD:
type = "logout";
break;
default:
qla_printk(KERN_WARNING, ha,
"%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
lio->ctx.type);
return;
}
del_timer(&lio->ctx.timer);
fcport = sp->fcport;
data[0] = data[1] = 0;
if (mbx->entry_status) {
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s error entry - entry-status=%x "
"status=%x state-flag=%x status-flags=%x.\n",
fcport->vha->host_no, sp->handle, type,
mbx->entry_status, le16_to_cpu(mbx->status),
le16_to_cpu(mbx->state_flags),
le16_to_cpu(mbx->status_flags)));
DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
data[0] = MBS_COMMAND_ERROR;
data[1] = lio->flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED: 0;
goto done_post_logio_done_work;
}
if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
DEBUG2(printk(KERN_DEBUG
"scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",
fcport->vha->host_no, sp->handle, type,
le16_to_cpu(mbx->mb1)));
data[0] = MBS_COMMAND_COMPLETE;
if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1)
fcport->flags |= FCF_FCP2_DEVICE;
goto done_post_logio_done_work;
}
data[0] = le16_to_cpu(mbx->mb0);
switch (data[0]) {
case MBS_PORT_ID_USED:
data[1] = le16_to_cpu(mbx->mb1);
break;
case MBS_LOOP_ID_USED:
break;
default:
data[0] = MBS_COMMAND_ERROR;
data[1] = lio->flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED: 0;
break;
}
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "
"mb6=%x mb7=%x.\n",
fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status),
le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
le16_to_cpu(mbx->mb7)));
done_post_logio_done_work:
lio->ctx.type == SRB_LOGIN_CMD ?
qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
lio->ctx.free(sp);
}
static void
qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
struct logio_entry_24xx *logio)
{
const char func[] = "LOGIO-IOCB";
const char *type;
struct qla_hw_data *ha = vha->hw;
fc_port_t *fcport;
srb_t *sp;
struct srb_logio *lio;
uint16_t data[2];
uint32_t iop[2];
sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
if (!sp)
return;
type = NULL;
lio = sp->ctx;
switch (lio->ctx.type) {
case SRB_LOGIN_CMD:
type = "login";
break;
case SRB_LOGOUT_CMD:
type = "logout";
break;
default:
qla_printk(KERN_WARNING, ha,
"%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
lio->ctx.type);
return;
}
del_timer(&lio->ctx.timer);
fcport = sp->fcport;
data[0] = data[1] = 0;
if (logio->entry_status) {
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
fcport->vha->host_no, sp->handle, type,
logio->entry_status));
DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
data[0] = MBS_COMMAND_ERROR;
data[1] = lio->flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED: 0;
goto done_post_logio_done_work;
}
if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
DEBUG2(printk(KERN_DEBUG
"scsi(%ld:%x): Async-%s complete - iop0=%x.\n",
fcport->vha->host_no, sp->handle, type,
le32_to_cpu(logio->io_parameter[0])));
data[0] = MBS_COMMAND_COMPLETE;
if (lio->ctx.type == SRB_LOGOUT_CMD)
goto done_post_logio_done_work;
iop[0] = le32_to_cpu(logio->io_parameter[0]);
if (iop[0] & BIT_4) {
fcport->port_type = FCT_TARGET;
if (iop[0] & BIT_8)
fcport->flags |= FCF_FCP2_DEVICE;
}
if (iop[0] & BIT_5)
fcport->port_type = FCT_INITIATOR;
if (logio->io_parameter[7] || logio->io_parameter[8])
fcport->supported_classes |= FC_COS_CLASS2;
if (logio->io_parameter[9] || logio->io_parameter[10])
fcport->supported_classes |= FC_COS_CLASS3;
goto done_post_logio_done_work;
}
iop[0] = le32_to_cpu(logio->io_parameter[0]);
iop[1] = le32_to_cpu(logio->io_parameter[1]);
switch (iop[0]) {
case LSC_SCODE_PORTID_USED:
data[0] = MBS_PORT_ID_USED;
data[1] = LSW(iop[1]);
break;
case LSC_SCODE_NPORT_USED:
data[0] = MBS_LOOP_ID_USED;
break;
case LSC_SCODE_CMD_FAILED:
if ((iop[1] & 0xff) == 0x05) {
data[0] = MBS_NOT_LOGGED_IN;
break;
}
/* Fall through. */
default:
data[0] = MBS_COMMAND_ERROR;
data[1] = lio->flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED: 0;
break;
}
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n",
fcport->vha->host_no, sp->handle, type,
le16_to_cpu(logio->comp_status),
le32_to_cpu(logio->io_parameter[0]),
le32_to_cpu(logio->io_parameter[1])));
done_post_logio_done_work:
lio->ctx.type == SRB_LOGIN_CMD ?
qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
lio->ctx.free(sp);
}
/**
* qla2x00_process_response_queue() - Process response queue entries.
* @ha: SCSI driver HA context
@ -935,6 +1224,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
case STATUS_CONT_TYPE:
qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
break;
case MBX_IOCB_TYPE:
qla2x00_mbx_iocb_entry(vha, rsp->req,
(struct mbx_entry *)pkt);
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
@ -1223,6 +1515,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
cp->device->id, cp->device->lun, resid,
scsi_bufflen(cp)));
scsi_set_resid(cp, resid);
cp->result = DID_ERROR << 16;
break;
}
@ -1544,6 +1837,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
qla24xx_report_id_acquisition(vha,
(struct vp_rpt_id_entry_24xx *)pkt);
break;
case LOGINOUT_PORT_IOCB_TYPE:
qla24xx_logio_entry(vha, rsp->req,
(struct logio_entry_24xx *)pkt);
break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
@ -1723,8 +2020,10 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
vha = qla25xx_get_host(rsp);
qla24xx_process_response_queue(vha, rsp);
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
if (!ha->mqenable) {
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
RD_REG_DWORD_RELAXED(&reg->hccr);
}
spin_unlock_irq(&ha->hardware_lock);
return IRQ_HANDLED;

View file

@ -1507,7 +1507,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
if (ql2xmultique_tag)
if (ha->flags.cpu_affinity_enabled)
req = ha->req_q_map[0];
else
req = vha->req;
@ -2324,7 +2324,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
vha = fcport->vha;
ha = vha->hw;
req = vha->req;
if (ql2xmultique_tag)
if (ha->flags.cpu_affinity_enabled)
rsp = ha->rsp_q_map[tag + 1];
else
rsp = req->rsp;
@ -2746,7 +2746,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
if (rptid_entry->format == 0) {
DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs setup %d,"
" number of VPs acquired %d\n", __func__, vha->host_no,
MSB(rptid_entry->vp_count), LSB(rptid_entry->vp_count)));
MSB(le16_to_cpu(rptid_entry->vp_count)),
LSB(le16_to_cpu(rptid_entry->vp_count))));
DEBUG15(printk("%s primary port id %02x%02x%02x\n", __func__,
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]));

View file

@ -42,7 +42,6 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
set_bit(vp_id, ha->vp_idx_map);
ha->num_vhosts++;
ha->cur_vport_count++;
vha->vp_idx = vp_id;
list_add_tail(&vha->list, &ha->vp_list);
mutex_unlock(&ha->vport_lock);
@ -58,7 +57,6 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
mutex_lock(&ha->vport_lock);
vp_id = vha->vp_idx;
ha->num_vhosts--;
ha->cur_vport_count--;
clear_bit(vp_id, ha->vp_idx_map);
list_del(&vha->list);
mutex_unlock(&ha->vport_lock);
@ -235,7 +233,11 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
}
/* To exclusively reset vport, we need to log it out first.*/
/*
* To exclusively reset vport, we need to log it out first. Note: this
* control_vp can fail if ISP reset is already issued, this is
* expected, as the vp would be already logged out due to ISP reset.
*/
if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
@ -247,18 +249,11 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
static int
qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
qla2x00_do_work(vha);
if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
/* VP acquired. complete port configuration */
if (atomic_read(&base_vha->loop_state) == LOOP_READY) {
qla24xx_configure_vp(vha);
} else {
set_bit(VP_IDX_ACQUIRED, &vha->vp_flags);
set_bit(VP_DPC_NEEDED, &base_vha->dpc_flags);
}
qla24xx_configure_vp(vha);
return 0;
}
@ -309,6 +304,9 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha)
clear_bit(VP_DPC_NEEDED, &vha->dpc_flags);
if (!(ha->current_topology & ISP_CFG_F))
return;
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
if (vp->vp_idx)
ret = qla2x00_do_dpc_vp(vp);
@ -413,6 +411,11 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
vha->flags.init_done = 1;
mutex_lock(&ha->vport_lock);
set_bit(vha->vp_idx, ha->vp_idx_map);
ha->cur_vport_count++;
mutex_unlock(&ha->vport_lock);
return vha;
create_vhost_failed:

View file

@ -287,9 +287,12 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
int ques, req, ret;
struct qla_hw_data *ha = vha->hw;
if (!(ha->fw_attributes & BIT_6)) {
qla_printk(KERN_INFO, ha,
"Firmware is not multi-queue capable\n");
goto fail;
}
if (ql2xmultique_tag) {
/* CPU affinity mode */
ha->wq = create_workqueue("qla2xxx_wq");
/* create a request queue for IO */
options |= BIT_7;
req = qla25xx_create_req_que(ha, options, 0, 0, -1,
@ -299,6 +302,7 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
"Can't create request queue\n");
goto fail;
}
ha->wq = create_workqueue("qla2xxx_wq");
vha->req = ha->req_q_map[req];
options |= BIT_1;
for (ques = 1; ques < ha->max_rsp_queues; ques++) {
@ -309,6 +313,8 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
goto fail2;
}
}
ha->flags.cpu_affinity_enabled = 1;
DEBUG2(qla_printk(KERN_INFO, ha,
"CPU affinity mode enabled, no. of response"
" queues:%d, no. of request queues:%d\n",
@ -317,8 +323,13 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha)
return 0;
fail2:
qla25xx_delete_queues(vha);
destroy_workqueue(ha->wq);
ha->wq = NULL;
fail:
ha->mqenable = 0;
kfree(ha->req_q_map);
kfree(ha->rsp_q_map);
ha->max_req_queues = ha->max_rsp_queues = 1;
return 1;
}
@ -462,6 +473,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
sp->flags = 0;
CMD_SP(cmd) = (void *)sp;
cmd->scsi_done = done;
sp->ctx = NULL;
return sp;
}
@ -556,11 +568,8 @@ qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd)
unsigned long wait_iter = ABORT_WAIT_ITER;
int ret = QLA_SUCCESS;
while (CMD_SP(cmd)) {
while (CMD_SP(cmd) && wait_iter--) {
msleep(ABORT_POLLING_PERIOD);
if (--wait_iter)
break;
}
if (CMD_SP(cmd))
ret = QLA_FUNCTION_FAILED;
@ -698,6 +707,8 @@ qla2x00_abort_fcport_cmds(fc_port_t *fcport)
continue;
if (sp->fcport != fcport)
continue;
if (sp->ctx)
continue;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops->abort_command(sp)) {
@ -783,7 +794,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
if (sp == NULL)
continue;
if (sp->ctx)
continue;
if (sp->cmd != cmd)
continue;
@ -848,7 +860,8 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t,
sp = req->outstanding_cmds[cnt];
if (!sp)
continue;
if (sp->ctx)
continue;
if (vha->vp_idx != sp->fcport->vha->vp_idx)
continue;
match = 0;
@ -1106,8 +1119,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
struct fc_port *fcport;
struct qla_hw_data *ha = vha->hw;
if (ha->flags.enable_lip_full_login && !vha->vp_idx &&
!IS_QLA81XX(ha)) {
if (ha->flags.enable_lip_full_login && !IS_QLA81XX(ha)) {
ret = qla2x00_full_login_lip(vha);
if (ret != QLA_SUCCESS) {
DEBUG2_3(printk("%s(%ld): failed: "
@ -1120,7 +1132,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
qla2x00_wait_for_loop_ready(vha);
}
if (ha->flags.enable_lip_reset && !vha->vp_idx) {
if (ha->flags.enable_lip_reset) {
ret = qla2x00_lip_reset(vha);
if (ret != QLA_SUCCESS) {
DEBUG2_3(printk("%s(%ld): failed: "
@ -1154,6 +1166,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
int que, cnt;
unsigned long flags;
srb_t *sp;
struct srb_ctx *ctx;
struct qla_hw_data *ha = vha->hw;
struct req_que *req;
@ -1166,8 +1179,14 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
sp = req->outstanding_cmds[cnt];
if (sp) {
req->outstanding_cmds[cnt] = NULL;
sp->cmd->result = res;
qla2x00_sp_compl(ha, sp);
if (!sp->ctx) {
sp->cmd->result = res;
qla2x00_sp_compl(ha, sp);
} else {
ctx = sp->ctx;
del_timer_sync(&ctx->timer);
ctx->free(sp);
}
}
}
}
@ -1193,6 +1212,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
scsi_qla_host_t *vha = shost_priv(sdev->host);
struct qla_hw_data *ha = vha->hw;
struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
struct req_que *req = vha->req;
if (sdev->tagged_supported)
@ -1201,6 +1221,8 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
scsi_deactivate_tcq(sdev, req->max_q_depth);
rport->dev_loss_tmo = ha->port_down_retry_count;
if (sdev->type == TYPE_TAPE)
fcport->flags |= FCF_TAPE_PRESENT;
return 0;
}
@ -1923,6 +1945,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto probe_init_failed;
/* Alloc arrays of request and response ring ptrs */
que_init:
if (!qla2x00_alloc_queues(ha)) {
qla_printk(KERN_WARNING, ha,
"[ERROR] Failed to allocate memory for queue"
@ -1959,11 +1982,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto probe_failed;
}
if (ha->mqenable)
if (qla25xx_setup_mode(base_vha))
if (ha->mqenable) {
if (qla25xx_setup_mode(base_vha)) {
qla_printk(KERN_WARNING, ha,
"Can't create queues, falling back to single"
" queue mode\n");
goto que_init;
}
}
if (ha->flags.running_gold_fw)
goto skip_dpc;
@ -2155,17 +2181,19 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
int defer)
{
struct fc_rport *rport;
scsi_qla_host_t *base_vha;
if (!fcport->rport)
return;
rport = fcport->rport;
if (defer) {
base_vha = pci_get_drvdata(vha->hw->pdev);
spin_lock_irq(vha->host->host_lock);
fcport->drport = rport;
spin_unlock_irq(vha->host->host_lock);
set_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
qla2xxx_wake_dpc(base_vha);
} else
fc_remote_port_delete(rport);
}
@ -2237,8 +2265,9 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer)
fc_port_t *fcport;
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (vha->vp_idx != fcport->vp_idx)
if (vha->vp_idx != 0 && vha->vp_idx != fcport->vp_idx)
continue;
/*
* No point in marking the device as lost, if the device is
* already DEAD.
@ -2246,10 +2275,12 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer)
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
continue;
if (atomic_read(&fcport->state) == FCS_ONLINE) {
atomic_set(&fcport->state, FCS_DEVICE_LOST);
qla2x00_schedule_rport_del(vha, fcport, defer);
} else
atomic_set(&fcport->state, FCS_DEVICE_LOST);
if (defer)
qla2x00_schedule_rport_del(vha, fcport, defer);
else if (vha->vp_idx == fcport->vp_idx)
qla2x00_schedule_rport_del(vha, fcport, defer);
}
atomic_set(&fcport->state, FCS_DEVICE_LOST);
}
}
@ -2598,7 +2629,31 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb)
return qla2x00_post_work(vha, e);
}
static void
#define qla2x00_post_async_work(name, type) \
int qla2x00_post_async_##name##_work( \
struct scsi_qla_host *vha, \
fc_port_t *fcport, uint16_t *data) \
{ \
struct qla_work_evt *e; \
\
e = qla2x00_alloc_work(vha, type); \
if (!e) \
return QLA_FUNCTION_FAILED; \
\
e->u.logio.fcport = fcport; \
if (data) { \
e->u.logio.data[0] = data[0]; \
e->u.logio.data[1] = data[1]; \
} \
return qla2x00_post_work(vha, e); \
}
qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN);
qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE);
qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT);
qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE);
void
qla2x00_do_work(struct scsi_qla_host *vha)
{
struct qla_work_evt *e, *tmp;
@ -2620,6 +2675,21 @@ qla2x00_do_work(struct scsi_qla_host *vha)
case QLA_EVT_IDC_ACK:
qla81xx_idc_ack(vha, e->u.idc_ack.mb);
break;
case QLA_EVT_ASYNC_LOGIN:
qla2x00_async_login(vha, e->u.logio.fcport,
e->u.logio.data);
break;
case QLA_EVT_ASYNC_LOGIN_DONE:
qla2x00_async_login_done(vha, e->u.logio.fcport,
e->u.logio.data);
break;
case QLA_EVT_ASYNC_LOGOUT:
qla2x00_async_logout(vha, e->u.logio.fcport);
break;
case QLA_EVT_ASYNC_LOGOUT_DONE:
qla2x00_async_logout_done(vha, e->u.logio.fcport,
e->u.logio.data);
break;
}
if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e);
@ -2635,6 +2705,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
int status;
uint16_t next_loopid = 0;
struct qla_hw_data *ha = vha->hw;
uint16_t data[2];
list_for_each_entry(fcport, &vha->vp_fcports, list) {
/*
@ -2644,6 +2715,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
if (atomic_read(&fcport->state) !=
FCS_ONLINE && fcport->login_retry) {
fcport->login_retry--;
if (fcport->flags & FCF_FABRIC_DEVICE) {
if (fcport->flags & FCF_TAPE_PRESENT)
ha->isp_ops->fabric_logout(vha,
@ -2652,13 +2724,22 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
fcport->d_id.b.area,
fcport->d_id.b.al_pa);
status = qla2x00_fabric_login(vha, fcport,
&next_loopid);
if (IS_ALOGIO_CAPABLE(ha)) {
data[0] = 0;
data[1] = QLA_LOGIO_LOGIN_RETRIED;
status = qla2x00_post_async_login_work(
vha, fcport, data);
if (status == QLA_SUCCESS)
continue;
/* Attempt a retry. */
status = 1;
} else
status = qla2x00_fabric_login(vha,
fcport, &next_loopid);
} else
status = qla2x00_local_device_login(vha,
fcport);
fcport->login_retry--;
if (status == QLA_SUCCESS) {
fcport->old_loop_id = fcport->loop_id;
@ -2831,6 +2912,9 @@ qla2x00_do_dpc(void *data)
*/
ha->dpc_active = 0;
/* Cleanup any residual CTX SRBs. */
qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
return 0;
}
@ -2971,6 +3055,8 @@ qla2x00_timer(scsi_qla_host_t *vha)
sp = req->outstanding_cmds[index];
if (!sp)
continue;
if (sp->ctx)
continue;
sfcp = sp->fcport;
if (!(sfcp->flags & FCF_TAPE_PRESENT))
continue;
@ -2987,8 +3073,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
/* if the loop has been down for 4 minutes, reinit adapter */
if (atomic_dec_and_test(&vha->loop_down_timer) != 0) {
if (!(vha->device_flags & DFLG_NO_CABLE) &&
!vha->vp_idx) {
if (!(vha->device_flags & DFLG_NO_CABLE)) {
DEBUG(printk("scsi(%ld): Loop down - "
"aborting ISP.\n",
vha->host_no));

View file

@ -7,7 +7,7 @@
/*
* Driver version
*/
#define QLA2XXX_VERSION "8.03.01-k4"
#define QLA2XXX_VERSION "8.03.01-k6"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3

View file

@ -227,11 +227,11 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
case SCS_DATA_UNDERRUN:
case SCS_DATA_OVERRUN:
if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) ||
(sts_entry->completionStatus == SCS_DATA_OVERRUN)) {
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "
"residual = 0x%x\n", ha->host_no,
(sts_entry->completionStatus == SCS_DATA_OVERRUN)) {
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun\n",
ha->host_no,
cmd->device->channel, cmd->device->id,
cmd->device->lun, __func__, residual));
cmd->device->lun, __func__));
cmd->result = DID_ERROR << 16;
break;

View file

@ -994,7 +994,7 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
* all the existing users tried this hard.
*/
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
len + 4, NULL, 30 * HZ, 3, NULL);
len, NULL, 30 * HZ, 3, NULL);
if (result)
return result;
@ -1021,13 +1021,14 @@ unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
{
int i, result;
unsigned int len;
unsigned char *buf = kmalloc(259, GFP_KERNEL);
const unsigned int init_vpd_len = 255;
unsigned char *buf = kmalloc(init_vpd_len, GFP_KERNEL);
if (!buf)
return NULL;
/* Ask for all the pages supported by this device */
result = scsi_vpd_inquiry(sdev, buf, 0, 255);
result = scsi_vpd_inquiry(sdev, buf, 0, init_vpd_len);
if (result)
goto fail;
@ -1050,12 +1051,12 @@ unsigned char *scsi_get_vpd_page(struct scsi_device *sdev, u8 page)
* Some pages are longer than 255 bytes. The actual length of
* the page is returned in the header.
*/
len = (buf[2] << 8) | buf[3];
if (len <= 255)
len = ((buf[2] << 8) | buf[3]) + 4;
if (len <= init_vpd_len)
return buf;
kfree(buf);
buf = kmalloc(len + 4, GFP_KERNEL);
buf = kmalloc(len, GFP_KERNEL);
result = scsi_vpd_inquiry(sdev, buf, page, len);
if (result)
goto fail;

View file

@ -382,9 +382,13 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
* who knows? FIXME(eric)
*/
return SUCCESS;
case RESERVATION_CONFLICT:
/*
* let issuer deal with this, it could be just fine
*/
return SUCCESS;
case BUSY:
case QUEUE_FULL:
case RESERVATION_CONFLICT:
default:
return FAILED;
}

View file

@ -896,6 +896,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
scsi_print_result(cmd);
if (driver_byte(result) & DRIVER_SENSE)
scsi_print_sense("", cmd);
scsi_print_command(cmd);
}
blk_end_request_all(req, -EIO);
scsi_next_command(cmd);

View file

@ -291,7 +291,7 @@ static void fc_scsi_scan_rport(struct work_struct *work);
#define FC_STARGET_NUM_ATTRS 3
#define FC_RPORT_NUM_ATTRS 10
#define FC_VPORT_NUM_ATTRS 9
#define FC_HOST_NUM_ATTRS 21
#define FC_HOST_NUM_ATTRS 22
struct fc_internal {
struct scsi_transport_template t;
@ -3432,7 +3432,7 @@ fc_bsg_jobdone(struct fc_bsg_job *job)
/**
* fc_bsg_softirq_done - softirq done routine for destroying the bsg requests
* @req: BSG request that holds the job to be destroyed
* @rq: BSG request that holds the job to be destroyed
*/
static void fc_bsg_softirq_done(struct request *rq)
{

View file

@ -36,6 +36,38 @@
#define ISCSI_TRANSPORT_VERSION "2.0-870"
static int dbg_session;
module_param_named(debug_session, dbg_session, int,
S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug_session,
"Turn on debugging for sessions in scsi_transport_iscsi "
"module. Set to 1 to turn on, and zero to turn off. Default "
"is off.");
static int dbg_conn;
module_param_named(debug_conn, dbg_conn, int,
S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug_conn,
"Turn on debugging for connections in scsi_transport_iscsi "
"module. Set to 1 to turn on, and zero to turn off. Default "
"is off.");
#define ISCSI_DBG_TRANS_SESSION(_session, dbg_fmt, arg...) \
do { \
if (dbg_session) \
iscsi_cls_session_printk(KERN_INFO, _session, \
"%s: " dbg_fmt, \
__func__, ##arg); \
} while (0);
#define ISCSI_DBG_TRANS_CONN(_conn, dbg_fmt, arg...) \
do { \
if (dbg_conn) \
iscsi_cls_conn_printk(KERN_INFO, _conn, \
"%s: " dbg_fmt, \
__func__, ##arg); \
} while (0);
struct iscsi_internal {
struct scsi_transport_template t;
struct iscsi_transport *iscsi_transport;
@ -377,6 +409,7 @@ static void iscsi_session_release(struct device *dev)
shost = iscsi_session_to_shost(session);
scsi_host_put(shost);
ISCSI_DBG_TRANS_SESSION(session, "Completing session release\n");
kfree(session);
}
@ -441,6 +474,9 @@ static int iscsi_user_scan_session(struct device *dev, void *data)
return 0;
session = iscsi_dev_to_session(dev);
ISCSI_DBG_TRANS_SESSION(session, "Scanning session\n");
shost = iscsi_session_to_shost(session);
ihost = shost->shost_data;
@ -448,8 +484,7 @@ static int iscsi_user_scan_session(struct device *dev, void *data)
spin_lock_irqsave(&session->lock, flags);
if (session->state != ISCSI_SESSION_LOGGED_IN) {
spin_unlock_irqrestore(&session->lock, flags);
mutex_unlock(&ihost->mutex);
return 0;
goto user_scan_exit;
}
id = session->target_id;
spin_unlock_irqrestore(&session->lock, flags);
@ -462,7 +497,10 @@ static int iscsi_user_scan_session(struct device *dev, void *data)
scsi_scan_target(&session->dev, 0, id,
scan_data->lun, 1);
}
user_scan_exit:
mutex_unlock(&ihost->mutex);
ISCSI_DBG_TRANS_SESSION(session, "Completed session scan\n");
return 0;
}
@ -522,7 +560,9 @@ static void session_recovery_timedout(struct work_struct *work)
if (session->transport->session_recovery_timedout)
session->transport->session_recovery_timedout(session);
ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n");
scsi_target_unblock(&session->dev);
ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n");
}
static void __iscsi_unblock_session(struct work_struct *work)
@ -534,6 +574,7 @@ static void __iscsi_unblock_session(struct work_struct *work)
struct iscsi_cls_host *ihost = shost->shost_data;
unsigned long flags;
ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n");
/*
* The recovery and unblock work get run from the same workqueue,
* so try to cancel it if it was going to run after this unblock.
@ -553,6 +594,7 @@ static void __iscsi_unblock_session(struct work_struct *work)
if (scsi_queue_work(shost, &session->scan_work))
atomic_inc(&ihost->nr_scans);
}
ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n");
}
/**
@ -579,10 +621,12 @@ static void __iscsi_block_session(struct work_struct *work)
block_work);
unsigned long flags;
ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n");
spin_lock_irqsave(&session->lock, flags);
session->state = ISCSI_SESSION_FAILED;
spin_unlock_irqrestore(&session->lock, flags);
scsi_target_block(&session->dev);
ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n");
queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
session->recovery_tmo * HZ);
}
@ -602,6 +646,8 @@ static void __iscsi_unbind_session(struct work_struct *work)
struct iscsi_cls_host *ihost = shost->shost_data;
unsigned long flags;
ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n");
/* Prevent new scans and make sure scanning is not in progress */
mutex_lock(&ihost->mutex);
spin_lock_irqsave(&session->lock, flags);
@ -616,6 +662,7 @@ static void __iscsi_unbind_session(struct work_struct *work)
scsi_remove_target(&session->dev);
iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
}
struct iscsi_cls_session *
@ -647,6 +694,8 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
device_initialize(&session->dev);
if (dd_size)
session->dd_data = &session[1];
ISCSI_DBG_TRANS_SESSION(session, "Completed session allocation\n");
return session;
}
EXPORT_SYMBOL_GPL(iscsi_alloc_session);
@ -712,6 +761,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
spin_unlock_irqrestore(&sesslock, flags);
iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n");
return 0;
release_host:
@ -752,6 +802,7 @@ static void iscsi_conn_release(struct device *dev)
struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
struct device *parent = conn->dev.parent;
ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n");
kfree(conn);
put_device(parent);
}
@ -774,6 +825,8 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
unsigned long flags;
int err;
ISCSI_DBG_TRANS_SESSION(session, "Removing session\n");
spin_lock_irqsave(&sesslock, flags);
list_del(&session->sess_list);
spin_unlock_irqrestore(&sesslock, flags);
@ -807,12 +860,15 @@ void iscsi_remove_session(struct iscsi_cls_session *session)
"for session. Error %d.\n", err);
transport_unregister_device(&session->dev);
ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n");
device_del(&session->dev);
}
EXPORT_SYMBOL_GPL(iscsi_remove_session);
void iscsi_free_session(struct iscsi_cls_session *session)
{
ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n");
iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
put_device(&session->dev);
}
@ -828,6 +884,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session);
int iscsi_destroy_session(struct iscsi_cls_session *session)
{
iscsi_remove_session(session);
ISCSI_DBG_TRANS_SESSION(session, "Completing session destruction\n");
iscsi_free_session(session);
return 0;
}
@ -885,6 +942,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
list_add(&conn->conn_list, &connlist);
conn->active = 1;
spin_unlock_irqrestore(&connlock, flags);
ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n");
return conn;
release_parent_ref:
@ -912,6 +971,7 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
spin_unlock_irqrestore(&connlock, flags);
transport_unregister_device(&conn->dev);
ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n");
device_unregister(&conn->dev);
return 0;
}
@ -1200,6 +1260,9 @@ int iscsi_session_event(struct iscsi_cls_session *session,
"Cannot notify userspace of session "
"event %u. Check iscsi daemon\n",
event);
ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n",
event, rc);
return rc;
}
EXPORT_SYMBOL_GPL(iscsi_session_event);
@ -1221,6 +1284,8 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
shost = iscsi_session_to_shost(session);
ev->r.c_session_ret.host_no = shost->host_no;
ev->r.c_session_ret.sid = session->sid;
ISCSI_DBG_TRANS_SESSION(session,
"Completed creating transport session\n");
return 0;
}
@ -1246,6 +1311,8 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
ev->r.c_conn_ret.sid = session->sid;
ev->r.c_conn_ret.cid = conn->cid;
ISCSI_DBG_TRANS_CONN(conn, "Completed creating transport conn\n");
return 0;
}
@ -1258,8 +1325,10 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev
if (!conn)
return -EINVAL;
ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n");
if (transport->destroy_conn)
transport->destroy_conn(conn);
return 0;
}

View file

@ -1691,10 +1691,6 @@ sas_attach_transport(struct sas_function_template *ft)
i->f = ft;
count = 0;
SETUP_PORT_ATTRIBUTE(num_phys);
i->host_attrs[count] = NULL;
count = 0;
SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
SETUP_PHY_ATTRIBUTE(target_port_protocols);

View file

@ -2021,6 +2021,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
sdp->removable ? "removable " : "");
put_device(&sdkp->dev);
}
/**
@ -2106,6 +2107,7 @@ static int sd_probe(struct device *dev)
get_device(&sdp->sdev_gendev);
get_device(&sdkp->dev); /* prevent release before async_schedule */
async_schedule(sd_probe_async, sdkp);
return 0;

View file

@ -347,6 +347,97 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev,
return 0;
}
#define INIT_ALLOC_SIZE 32
static void ses_enclosure_data_process(struct enclosure_device *edev,
struct scsi_device *sdev,
int create)
{
u32 result;
unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL;
int i, j, page7_len, len, components;
struct ses_device *ses_dev = edev->scratch;
int types = ses_dev->page1[10];
unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
if (!hdr_buf)
goto simple_populate;
/* re-read page 10 */
if (ses_dev->page10)
ses_recv_diag(sdev, 10, ses_dev->page10, ses_dev->page10_len);
/* Page 7 for the descriptors is optional */
result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE);
if (result)
goto simple_populate;
page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
/* add 1 for trailing '\0' we'll use */
buf = kzalloc(len + 1, GFP_KERNEL);
if (!buf)
goto simple_populate;
result = ses_recv_diag(sdev, 7, buf, len);
if (result) {
simple_populate:
kfree(buf);
buf = NULL;
desc_ptr = NULL;
len = 0;
page7_len = 0;
} else {
desc_ptr = buf + 8;
len = (desc_ptr[2] << 8) + desc_ptr[3];
/* skip past overall descriptor */
desc_ptr += len + 4;
if (ses_dev->page10)
addl_desc_ptr = ses_dev->page10 + 8;
}
type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
components = 0;
for (i = 0; i < types; i++, type_ptr += 4) {
for (j = 0; j < type_ptr[1]; j++) {
char *name = NULL;
struct enclosure_component *ecomp;
if (desc_ptr) {
if (desc_ptr >= buf + page7_len) {
desc_ptr = NULL;
} else {
len = (desc_ptr[2] << 8) + desc_ptr[3];
desc_ptr += 4;
/* Add trailing zero - pushes into
* reserved space */
desc_ptr[len] = '\0';
name = desc_ptr;
}
}
if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {
if (create)
ecomp = enclosure_component_register(edev,
components++,
type_ptr[0],
name);
else
ecomp = &edev->component[components++];
if (!IS_ERR(ecomp) && addl_desc_ptr)
ses_process_descriptor(ecomp,
addl_desc_ptr);
}
if (desc_ptr)
desc_ptr += len;
if (addl_desc_ptr)
addl_desc_ptr += addl_desc_ptr[1] + 2;
}
}
kfree(buf);
kfree(hdr_buf);
}
static void ses_match_to_enclosure(struct enclosure_device *edev,
struct scsi_device *sdev)
{
@ -361,6 +452,8 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
if (!buf)
return;
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
vpd_len = ((buf[2] << 8) | buf[3]) + 4;
desc = buf + 4;
@ -395,28 +488,26 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
kfree(buf);
}
#define INIT_ALLOC_SIZE 32
static int ses_intf_add(struct device *cdev,
struct class_interface *intf)
{
struct scsi_device *sdev = to_scsi_device(cdev->parent);
struct scsi_device *tmp_sdev;
unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr = NULL,
*addl_desc_ptr = NULL;
unsigned char *buf = NULL, *hdr_buf, *type_ptr;
struct ses_device *ses_dev;
u32 result;
int i, j, types, len, page7_len = 0, components = 0;
int i, types, len, components = 0;
int err = -ENOMEM;
struct enclosure_device *edev;
struct ses_component *scomp = NULL;
if (!scsi_device_enclosure(sdev)) {
/* not an enclosure, but might be in one */
edev = enclosure_find(&sdev->host->shost_gendev);
if (edev) {
struct enclosure_device *prev = NULL;
while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) {
ses_match_to_enclosure(edev, sdev);
put_device(&edev->edev);
prev = edev;
}
return -ENODEV;
}
@ -500,6 +591,7 @@ static int ses_intf_add(struct device *cdev,
ses_dev->page10_len = len;
buf = NULL;
}
kfree(hdr_buf);
scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL);
if (!scomp)
@ -516,72 +608,7 @@ static int ses_intf_add(struct device *cdev,
for (i = 0; i < components; i++)
edev->component[i].scratch = scomp + i;
/* Page 7 for the descriptors is optional */
result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE);
if (result)
goto simple_populate;
page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
/* add 1 for trailing '\0' we'll use */
buf = kzalloc(len + 1, GFP_KERNEL);
if (!buf)
goto simple_populate;
result = ses_recv_diag(sdev, 7, buf, len);
if (result) {
simple_populate:
kfree(buf);
buf = NULL;
desc_ptr = NULL;
addl_desc_ptr = NULL;
} else {
desc_ptr = buf + 8;
len = (desc_ptr[2] << 8) + desc_ptr[3];
/* skip past overall descriptor */
desc_ptr += len + 4;
if (ses_dev->page10)
addl_desc_ptr = ses_dev->page10 + 8;
}
type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
components = 0;
for (i = 0; i < types; i++, type_ptr += 4) {
for (j = 0; j < type_ptr[1]; j++) {
char *name = NULL;
struct enclosure_component *ecomp;
if (desc_ptr) {
if (desc_ptr >= buf + page7_len) {
desc_ptr = NULL;
} else {
len = (desc_ptr[2] << 8) + desc_ptr[3];
desc_ptr += 4;
/* Add trailing zero - pushes into
* reserved space */
desc_ptr[len] = '\0';
name = desc_ptr;
}
}
if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {
ecomp = enclosure_component_register(edev,
components++,
type_ptr[0],
name);
if (!IS_ERR(ecomp) && addl_desc_ptr)
ses_process_descriptor(ecomp,
addl_desc_ptr);
}
if (desc_ptr)
desc_ptr += len;
if (addl_desc_ptr)
addl_desc_ptr += addl_desc_ptr[1] + 2;
}
}
kfree(buf);
kfree(hdr_buf);
ses_enclosure_data_process(edev, sdev, 1);
/* see if there are any devices matching before
* we found the enclosure */
@ -615,17 +642,26 @@ static int ses_remove(struct device *dev)
return 0;
}
static void ses_intf_remove(struct device *cdev,
struct class_interface *intf)
static void ses_intf_remove_component(struct scsi_device *sdev)
{
struct enclosure_device *edev, *prev = NULL;
while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) {
prev = edev;
if (!enclosure_remove_device(edev, &sdev->sdev_gendev))
break;
}
if (edev)
put_device(&edev->edev);
}
static void ses_intf_remove_enclosure(struct scsi_device *sdev)
{
struct scsi_device *sdev = to_scsi_device(cdev->parent);
struct enclosure_device *edev;
struct ses_device *ses_dev;
if (!scsi_device_enclosure(sdev))
return;
edev = enclosure_find(cdev->parent);
/* exact match to this enclosure */
edev = enclosure_find(&sdev->sdev_gendev, NULL);
if (!edev)
return;
@ -643,6 +679,17 @@ static void ses_intf_remove(struct device *cdev,
enclosure_unregister(edev);
}
static void ses_intf_remove(struct device *cdev,
struct class_interface *intf)
{
struct scsi_device *sdev = to_scsi_device(cdev->parent);
if (!scsi_device_enclosure(sdev))
ses_intf_remove_component(sdev);
else
ses_intf_remove_enclosure(sdev);
}
static struct class_interface ses_interface = {
.add_dev = ses_intf_add,
.remove_dev = ses_intf_remove,

View file

@ -1811,7 +1811,7 @@ retry:
return 0;
out:
for (i = 0; i < k; i++)
__free_pages(schp->pages[k], order);
__free_pages(schp->pages[i], order);
if (--order >= 0)
goto retry;

View file

@ -55,6 +55,7 @@ enum {
OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */
OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */
YIOA_STATUS = 0x00,
YH2I_INT = 0x20,
YINT_EN = 0x34,
YI2H_INT = 0x9c,
@ -108,6 +109,10 @@ enum {
SS_HEAD_HANDSHAKE = 0x80,
SS_H2I_INT_RESET = 0x100,
SS_MU_OPERATIONAL = 0x80000000,
STEX_CDB_LENGTH = 16,
STATUS_VAR_LEN = 128,
@ -884,7 +889,7 @@ static void stex_ss_mu_intr(struct st_hba *hba)
tag = (u16)value;
if (unlikely(tag >= hba->host->can_queue)) {
printk(KERN_WARNING DRV_NAME
"(%s): invalid tag\n", pci_name(hba->pdev));
"(%s): invalid tag\n", pci_name(hba->pdev));
continue;
}
@ -1040,16 +1045,27 @@ static int stex_ss_handshake(struct st_hba *hba)
void __iomem *base = hba->mmio_base;
struct st_msg_header *msg_h;
struct handshake_frame *h;
__le32 *scratch = hba->scratch;
__le32 *scratch;
u32 data;
unsigned long before;
int ret = 0;
h = (struct handshake_frame *)(hba->alloc_rq(hba));
msg_h = (struct st_msg_header *)h - 1;
before = jiffies;
while ((readl(base + YIOA_STATUS) & SS_MU_OPERATIONAL) == 0) {
if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
printk(KERN_ERR DRV_NAME
"(%s): firmware not operational\n",
pci_name(hba->pdev));
return -1;
}
msleep(1);
}
msg_h = (struct st_msg_header *)hba->dma_mem;
msg_h->handle = cpu_to_le64(hba->dma_handle);
msg_h->flag = SS_HEAD_HANDSHAKE;
h = (struct handshake_frame *)(msg_h + 1);
h->rb_phy = cpu_to_le64(hba->dma_handle);
h->req_sz = cpu_to_le16(hba->rq_size);
h->req_cnt = cpu_to_le16(hba->rq_count+1);
@ -1205,6 +1221,13 @@ static void stex_hard_reset(struct st_hba *hba)
hba->pdev->saved_config_space[i]);
}
static void stex_ss_reset(struct st_hba *hba)
{
writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT);
readl(hba->mmio_base + YH2I_INT);
ssleep(5);
}
static int stex_reset(struct scsi_cmnd *cmd)
{
struct st_hba *hba;
@ -1221,6 +1244,8 @@ static int stex_reset(struct scsi_cmnd *cmd)
if (hba->cardtype == st_shasta)
stex_hard_reset(hba);
else if (hba->cardtype == st_yel)
stex_ss_reset(hba);
if (hba->cardtype != st_yosemite) {
if (stex_handshake(hba)) {