mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
SCSI updates on 20120319
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (GNU/Linux) iQEcBAABAgAGBQJPZxSnAAoJEDeqqVYsXL0M0Y4IAMX0vrTVZbg6psA5/gMcWGRP CkFXEQ8n0PL2SCaj6BoDqamJFe5Nc7dnqxM0fGawB4S9vr3rHhiOlwO+NbV9zFYC 2skBTpeL3sjgtN/jTBdfeeAa7xTYpu/XGyei0NS1A5c2AyMVXV0uYV2s4VNZxe44 tVIn1OEzM2giZ9EB1OZslDMrg5XXm3MBIUECP0LbWUhBm/35caSFKzMXRwhh7WiK +AVmc2AZYtdEwuknDyiH7KlsaoB3vGL9pPrAUJzIgEhy2pOo2A7W72HfA4Fj+y6a uF9HBS5zciMp1+sGWry62AjNbWgin9BRlozBEO/lJhIfMGDV1nXEIJsOkOgkdoE= =1TxB -----END PGP SIGNATURE----- Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6 SCSI updates from James Bottomley: "The update includes the usual assortment of driver updates (lpfc, qla2xxx, qla4xxx, bfa, bnx2fc, bnx2i, isci, fcoe, hpsa) plus a huge amount of infrastructure work in the SAS library and transport class as well as an iSCSI update. There's also a new SCSI based virtio driver." * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (177 commits) [SCSI] qla4xxx: Update driver version to 5.02.00-k15 [SCSI] qla4xxx: trivial cleanup [SCSI] qla4xxx: Fix sparse warning [SCSI] qla4xxx: Add support for multiple session per host. [SCSI] qla4xxx: Export CHAP index as sysfs attribute [SCSI] scsi_transport: Export CHAP index as sysfs attribute [SCSI] qla4xxx: Add support to display CHAP list and delete CHAP entry [SCSI] iscsi_transport: Add support to display CHAP list and delete CHAP entry [SCSI] pm8001: fix endian issue with code optimization. [SCSI] pm8001: Fix possible racing condition. [SCSI] pm8001: Fix bogus interrupt state flag issue. [SCSI] ipr: update PCI ID definitions for new adapters [SCSI] qla2xxx: handle default case in qla2x00_request_firmware() [SCSI] isci: improvements in driver unloading routine [SCSI] isci: improve phy event warnings [SCSI] isci: debug, provide state-enum-to-string conversions [SCSI] scsi_transport_sas: 'enable' phys on reset [SCSI] libsas: don't recover end devices attached to disabled phys [SCSI] libsas: fixup target_port_protocols for expanders that don't report sata [SCSI] libsas: set attached device type and target protocols for local phys ...
This commit is contained in:
commit
424a6f6ef9
@ -1,48 +1,11 @@
|
||||
Copyright (c) 2003-2011 QLogic Corporation
|
||||
QLogic Linux/ESX Fibre Channel HBA Driver
|
||||
QLogic Linux FC-FCoE Driver
|
||||
|
||||
This program includes a device driver for Linux 2.6/ESX that may be
|
||||
distributed with QLogic hardware specific firmware binary file.
|
||||
This program includes a device driver for Linux 3.x.
|
||||
You may modify and redistribute the device driver code under the
|
||||
GNU General Public License (a copy of which is attached hereto as
|
||||
Exhibit A) published by the Free Software Foundation (version 2).
|
||||
|
||||
You may redistribute the hardware specific firmware binary file
|
||||
under the following terms:
|
||||
|
||||
1. Redistribution of source code (only if applicable),
|
||||
must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistribution in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. The name of QLogic Corporation may not be used to
|
||||
endorse or promote products derived from this software
|
||||
without specific prior written permission
|
||||
|
||||
REGARDLESS OF WHAT LICENSING MECHANISM IS USED OR APPLICABLE,
|
||||
THIS PROGRAM IS PROVIDED BY QLOGIC CORPORATION "AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
USER ACKNOWLEDGES AND AGREES THAT USE OF THIS PROGRAM WILL NOT
|
||||
CREATE OR GIVE GROUNDS FOR A LICENSE BY IMPLICATION, ESTOPPEL, OR
|
||||
OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT,
|
||||
TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN
|
||||
ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN
|
||||
COMBINATION WITH THIS PROGRAM.
|
||||
|
||||
|
||||
EXHIBIT A
|
||||
|
82
Documentation/scsi/bfa.txt
Normal file
82
Documentation/scsi/bfa.txt
Normal file
@ -0,0 +1,82 @@
|
||||
Linux driver for Brocade FC/FCOE adapters
|
||||
|
||||
|
||||
Supported Hardware
|
||||
------------------
|
||||
|
||||
bfa 3.0.2.2 driver supports all Brocade FC/FCOE adapters. Below is a list of
|
||||
adapter models with corresponding PCIIDs.
|
||||
|
||||
PCIID Model
|
||||
|
||||
1657:0013:1657:0014 425 4Gbps dual port FC HBA
|
||||
1657:0013:1657:0014 825 8Gbps PCIe dual port FC HBA
|
||||
1657:0013:103c:1742 HP 82B 8Gbps PCIedual port FC HBA
|
||||
1657:0013:103c:1744 HP 42B 4Gbps dual port FC HBA
|
||||
1657:0017:1657:0014 415 4Gbps single port FC HBA
|
||||
1657:0017:1657:0014 815 8Gbps single port FC HBA
|
||||
1657:0017:103c:1741 HP 41B 4Gbps single port FC HBA
|
||||
1657:0017:103c 1743 HP 81B 8Gbps single port FC HBA
|
||||
1657:0021:103c:1779 804 8Gbps FC HBA for HP Bladesystem c-class
|
||||
|
||||
1657:0014:1657:0014 1010 10Gbps single port CNA - FCOE
|
||||
1657:0014:1657:0014 1020 10Gbps dual port CNA - FCOE
|
||||
1657:0014:1657:0014 1007 10Gbps dual port CNA - FCOE
|
||||
1657:0014:1657:0014 1741 10Gbps dual port CNA - FCOE
|
||||
|
||||
1657:0022:1657:0024 1860 16Gbps FC HBA
|
||||
1657:0022:1657:0022 1860 10Gbps CNA - FCOE
|
||||
|
||||
|
||||
Firmware download
|
||||
-----------------
|
||||
|
||||
The latest Firmware package for 3.0.2.2 bfa driver can be found at:
|
||||
|
||||
http://www.brocade.com/services-support/drivers-downloads/adapters/Linux.page
|
||||
|
||||
and then click following respective util package link:
|
||||
|
||||
Version Link
|
||||
|
||||
v3.0.0.0 Linux Adapter Firmware package for RHEL 6.2, SLES 11SP2
|
||||
|
||||
|
||||
Configuration & Management utility download
|
||||
-------------------------------------------
|
||||
|
||||
The latest driver configuration & management utility for 3.0.2.2 bfa driver can
|
||||
be found at:
|
||||
|
||||
http://www.brocade.com/services-support/drivers-downloads/adapters/Linux.page
|
||||
|
||||
and then click following respective util pacakge link
|
||||
|
||||
Version Link
|
||||
|
||||
v3.0.2.0 Linux Adapter Firmware package for RHEL 6.2, SLES 11SP2
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
The latest Administration's Guide, Installation and Reference Manual,
|
||||
Troubleshooting Guide, and Release Notes for the corresponding out-of-box
|
||||
driver can be found at:
|
||||
|
||||
http://www.brocade.com/services-support/drivers-downloads/adapters/Linux.page
|
||||
|
||||
and use the following inbox and out-of-box driver version mapping to find
|
||||
the corresponding documentation:
|
||||
|
||||
Inbox Version Out-of-box Version
|
||||
|
||||
v3.0.2.2 v3.0.0.0
|
||||
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
For general product and support info, go to the Brocade website at:
|
||||
|
||||
http://www.brocade.com/services-support/index.page
|
@ -398,21 +398,6 @@ struct sas_task {
|
||||
task_done -- callback when the task has finished execution
|
||||
};
|
||||
|
||||
When an external entity, entity other than the LLDD or the
|
||||
SAS Layer, wants to work with a struct domain_device, it
|
||||
_must_ call kobject_get() when getting a handle on the
|
||||
device and kobject_put() when it is done with the device.
|
||||
|
||||
This does two things:
|
||||
A) implements proper kfree() for the device;
|
||||
B) increments/decrements the kref for all players:
|
||||
domain_device
|
||||
all domain_device's ... (if past an expander)
|
||||
port
|
||||
host adapter
|
||||
pci device
|
||||
and up the ladder, etc.
|
||||
|
||||
DISCOVERY
|
||||
---------
|
||||
|
||||
|
@ -5936,29 +5936,31 @@ void ata_host_init(struct ata_host *host, struct device *dev,
|
||||
host->ops = ops;
|
||||
}
|
||||
|
||||
void __ata_port_probe(struct ata_port *ap)
|
||||
{
|
||||
struct ata_eh_info *ehi = &ap->link.eh_info;
|
||||
unsigned long flags;
|
||||
|
||||
/* kick EH for boot probing */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
ehi->probe_mask |= ATA_ALL_DEVICES;
|
||||
ehi->action |= ATA_EH_RESET;
|
||||
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
|
||||
|
||||
ap->pflags &= ~ATA_PFLAG_INITIALIZING;
|
||||
ap->pflags |= ATA_PFLAG_LOADING;
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
}
|
||||
|
||||
int ata_port_probe(struct ata_port *ap)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* probe */
|
||||
if (ap->ops->error_handler) {
|
||||
struct ata_eh_info *ehi = &ap->link.eh_info;
|
||||
unsigned long flags;
|
||||
|
||||
/* kick EH for boot probing */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
ehi->probe_mask |= ATA_ALL_DEVICES;
|
||||
ehi->action |= ATA_EH_RESET;
|
||||
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
|
||||
|
||||
ap->pflags &= ~ATA_PFLAG_INITIALIZING;
|
||||
ap->pflags |= ATA_PFLAG_LOADING;
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* wait for EH to finish */
|
||||
__ata_port_probe(ap);
|
||||
ata_port_wait_eh(ap);
|
||||
} else {
|
||||
DPRINTK("ata%u: bus probe begin\n", ap->print_id);
|
||||
|
@ -863,6 +863,7 @@ void ata_port_wait_eh(struct ata_port *ap)
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_port_wait_eh);
|
||||
|
||||
static int ata_eh_nr_in_flight(struct ata_port *ap)
|
||||
{
|
||||
|
@ -3838,6 +3838,19 @@ void ata_sas_port_stop(struct ata_port *ap)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_sas_port_stop);
|
||||
|
||||
int ata_sas_async_port_init(struct ata_port *ap)
|
||||
{
|
||||
int rc = ap->ops->port_start(ap);
|
||||
|
||||
if (!rc) {
|
||||
ap->print_id = ata_print_id++;
|
||||
__ata_port_probe(ap);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_sas_async_port_init);
|
||||
|
||||
/**
|
||||
* ata_sas_port_init - Initialize a SATA device
|
||||
* @ap: SATA port to initialize
|
||||
|
@ -105,6 +105,7 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
|
||||
extern struct ata_port *ata_port_alloc(struct ata_host *host);
|
||||
extern const char *sata_spd_string(unsigned int spd);
|
||||
extern int ata_port_probe(struct ata_port *ap);
|
||||
extern void __ata_port_probe(struct ata_port *ap);
|
||||
|
||||
/* libata-acpi.c */
|
||||
#ifdef CONFIG_ATA_ACPI
|
||||
@ -151,7 +152,6 @@ extern void ata_eh_acquire(struct ata_port *ap);
|
||||
extern void ata_eh_release(struct ata_port *ap);
|
||||
extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
|
||||
extern void ata_scsi_error(struct Scsi_Host *host);
|
||||
extern void ata_port_wait_eh(struct ata_port *ap);
|
||||
extern void ata_eh_fastdrain_timerfn(unsigned long arg);
|
||||
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
|
||||
extern void ata_dev_disable(struct ata_device *dev);
|
||||
|
@ -1903,6 +1903,14 @@ config SCSI_BFA_FC
|
||||
To compile this driver as a module, choose M here. The module will
|
||||
be called bfa.
|
||||
|
||||
config SCSI_VIRTIO
|
||||
tristate "virtio-scsi support (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && VIRTIO
|
||||
help
|
||||
This is the virtual HBA driver for virtio. If the kernel will
|
||||
be used in a virtual machine, say Y or M.
|
||||
|
||||
|
||||
endif # SCSI_LOWLEVEL
|
||||
|
||||
source "drivers/scsi/pcmcia/Kconfig"
|
||||
|
@ -141,6 +141,7 @@ obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/
|
||||
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
|
||||
obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
|
||||
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
|
||||
obj-$(CONFIG_SCSI_VIRTIO) += virtio_scsi.o
|
||||
obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
|
||||
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
|
||||
|
||||
|
@ -151,7 +151,11 @@ int aac_msi;
|
||||
int aac_commit = -1;
|
||||
int startup_timeout = 180;
|
||||
int aif_timeout = 120;
|
||||
int aac_sync_mode; /* Only Sync. transfer - disabled */
|
||||
|
||||
module_param(aac_sync_mode, int, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode"
|
||||
" 0=off, 1=on");
|
||||
module_param(nondasd, int, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices."
|
||||
" 0=off, 1=on");
|
||||
|
@ -12,7 +12,7 @@
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef AAC_DRIVER_BUILD
|
||||
# define AAC_DRIVER_BUILD 28000
|
||||
# define AAC_DRIVER_BUILD 28900
|
||||
# define AAC_DRIVER_BRANCH "-ms"
|
||||
#endif
|
||||
#define MAXIMUM_NUM_CONTAINERS 32
|
||||
@ -756,8 +756,16 @@ struct src_mu_registers {
|
||||
|
||||
struct src_registers {
|
||||
struct src_mu_registers MUnit; /* 00h - c7h */
|
||||
__le32 reserved1[130790]; /* c8h - 7fc5fh */
|
||||
struct src_inbound IndexRegs; /* 7fc60h */
|
||||
union {
|
||||
struct {
|
||||
__le32 reserved1[130790]; /* c8h - 7fc5fh */
|
||||
struct src_inbound IndexRegs; /* 7fc60h */
|
||||
} tupelo;
|
||||
struct {
|
||||
__le32 reserved1[974]; /* c8h - fffh */
|
||||
struct src_inbound IndexRegs; /* 1000h */
|
||||
} denali;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define src_readb(AEP, CSR) readb(&((AEP)->regs.src.bar0->CSR))
|
||||
@ -999,6 +1007,10 @@ struct aac_bus_info_response {
|
||||
#define AAC_OPT_NEW_COMM cpu_to_le32(1<<17)
|
||||
#define AAC_OPT_NEW_COMM_64 cpu_to_le32(1<<18)
|
||||
#define AAC_OPT_NEW_COMM_TYPE1 cpu_to_le32(1<<28)
|
||||
#define AAC_OPT_NEW_COMM_TYPE2 cpu_to_le32(1<<29)
|
||||
#define AAC_OPT_NEW_COMM_TYPE3 cpu_to_le32(1<<30)
|
||||
#define AAC_OPT_NEW_COMM_TYPE4 cpu_to_le32(1<<31)
|
||||
|
||||
|
||||
struct aac_dev
|
||||
{
|
||||
@ -1076,6 +1088,8 @@ struct aac_dev
|
||||
# define AAC_MIN_FOOTPRINT_SIZE 8192
|
||||
# define AAC_MIN_SRC_BAR0_SIZE 0x400000
|
||||
# define AAC_MIN_SRC_BAR1_SIZE 0x800
|
||||
# define AAC_MIN_SRCV_BAR0_SIZE 0x100000
|
||||
# define AAC_MIN_SRCV_BAR1_SIZE 0x400
|
||||
#endif
|
||||
union
|
||||
{
|
||||
@ -1116,7 +1130,10 @@ struct aac_dev
|
||||
u8 msi;
|
||||
int management_fib_count;
|
||||
spinlock_t manage_lock;
|
||||
|
||||
spinlock_t sync_lock;
|
||||
int sync_mode;
|
||||
struct fib *sync_fib;
|
||||
struct list_head sync_fib_list;
|
||||
};
|
||||
|
||||
#define aac_adapter_interrupt(dev) \
|
||||
@ -1163,6 +1180,7 @@ struct aac_dev
|
||||
|
||||
#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001)
|
||||
#define FIB_CONTEXT_FLAG (0x00000002)
|
||||
#define FIB_CONTEXT_FLAG_WAIT (0x00000004)
|
||||
|
||||
/*
|
||||
* Define the command values
|
||||
@ -1970,6 +1988,7 @@ int aac_rkt_init(struct aac_dev *dev);
|
||||
int aac_nark_init(struct aac_dev *dev);
|
||||
int aac_sa_init(struct aac_dev *dev);
|
||||
int aac_src_init(struct aac_dev *dev);
|
||||
int aac_srcv_init(struct aac_dev *dev);
|
||||
int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify);
|
||||
unsigned int aac_response_normal(struct aac_queue * q);
|
||||
unsigned int aac_command_normal(struct aac_queue * q);
|
||||
|
@ -325,12 +325,14 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
|
||||
{
|
||||
u32 status[5];
|
||||
struct Scsi_Host * host = dev->scsi_host_ptr;
|
||||
extern int aac_sync_mode;
|
||||
|
||||
/*
|
||||
* Check the preferred comm settings, defaults from template.
|
||||
*/
|
||||
dev->management_fib_count = 0;
|
||||
spin_lock_init(&dev->manage_lock);
|
||||
spin_lock_init(&dev->sync_lock);
|
||||
dev->max_fib_size = sizeof(struct hw_fib);
|
||||
dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
|
||||
- sizeof(struct aac_fibhdr)
|
||||
@ -344,13 +346,21 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
|
||||
(status[0] == 0x00000001)) {
|
||||
if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
|
||||
dev->raw_io_64 = 1;
|
||||
if (dev->a_ops.adapter_comm) {
|
||||
if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1)) {
|
||||
dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
|
||||
dev->raw_io_interface = 1;
|
||||
} else if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)) {
|
||||
dev->sync_mode = aac_sync_mode;
|
||||
if (dev->a_ops.adapter_comm &&
|
||||
(status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) {
|
||||
dev->comm_interface = AAC_COMM_MESSAGE;
|
||||
dev->raw_io_interface = 1;
|
||||
if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1))) {
|
||||
/* driver supports TYPE1 (Tupelo) */
|
||||
dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
|
||||
} else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE4)) ||
|
||||
(status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE3)) ||
|
||||
(status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE2))) {
|
||||
/* driver doesn't support TYPE2 (Series7), TYPE3 and TYPE4 */
|
||||
/* switch to sync. mode */
|
||||
dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
|
||||
dev->sync_mode = 1;
|
||||
}
|
||||
}
|
||||
if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
|
||||
@ -455,6 +465,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dev->fib_list);
|
||||
INIT_LIST_HEAD(&dev->sync_fib_list);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
@ -416,6 +416,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
|
||||
unsigned long flags = 0;
|
||||
unsigned long qflags;
|
||||
unsigned long mflags = 0;
|
||||
unsigned long sflags = 0;
|
||||
|
||||
|
||||
if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
|
||||
@ -512,6 +513,31 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
|
||||
spin_lock_irqsave(&fibptr->event_lock, flags);
|
||||
}
|
||||
|
||||
if (dev->sync_mode) {
|
||||
if (wait)
|
||||
spin_unlock_irqrestore(&fibptr->event_lock, flags);
|
||||
spin_lock_irqsave(&dev->sync_lock, sflags);
|
||||
if (dev->sync_fib) {
|
||||
list_add_tail(&fibptr->fiblink, &dev->sync_fib_list);
|
||||
spin_unlock_irqrestore(&dev->sync_lock, sflags);
|
||||
} else {
|
||||
dev->sync_fib = fibptr;
|
||||
spin_unlock_irqrestore(&dev->sync_lock, sflags);
|
||||
aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
|
||||
(u32)fibptr->hw_fib_pa, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
if (wait) {
|
||||
fibptr->flags |= FIB_CONTEXT_FLAG_WAIT;
|
||||
if (down_interruptible(&fibptr->event_wait)) {
|
||||
fibptr->flags &= ~FIB_CONTEXT_FLAG_WAIT;
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
if (aac_adapter_deliver(fibptr) != 0) {
|
||||
printk(KERN_ERR "aac_fib_send: returned -EBUSY\n");
|
||||
if (wait) {
|
||||
|
@ -56,7 +56,7 @@
|
||||
|
||||
#include "aacraid.h"
|
||||
|
||||
#define AAC_DRIVER_VERSION "1.1-7"
|
||||
#define AAC_DRIVER_VERSION "1.2-0"
|
||||
#ifndef AAC_DRIVER_BRANCH
|
||||
#define AAC_DRIVER_BRANCH ""
|
||||
#endif
|
||||
@ -162,7 +162,10 @@ static const struct pci_device_id aac_pci_tbl[] __devinitdata = {
|
||||
{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */
|
||||
{ 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */
|
||||
{ 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */
|
||||
{ 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Catch All */
|
||||
{ 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Series 6 (Tupelo) */
|
||||
{ 0x9005, 0x028c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 63 }, /* Adaptec PMC Series 7 (Denali) */
|
||||
{ 0x9005, 0x028d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 64 }, /* Adaptec PMC Series 8 */
|
||||
{ 0x9005, 0x028f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 65 }, /* Adaptec PMC Series 9 */
|
||||
{ 0,}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
|
||||
@ -238,7 +241,10 @@ static struct aac_driver_ident aac_drivers[] = {
|
||||
{ aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */
|
||||
{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */
|
||||
{ aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec NEMER/ARK Catch All */
|
||||
{ aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec PMC Catch All */
|
||||
{ aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 6 (Tupelo) */
|
||||
{ aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 7 (Denali) */
|
||||
{ aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 8 */
|
||||
{ aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec PMC Series 9 */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1102,6 +1108,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
|
||||
int error = -ENODEV;
|
||||
int unique_id = 0;
|
||||
u64 dmamask;
|
||||
extern int aac_sync_mode;
|
||||
|
||||
list_for_each_entry(aac, &aac_devices, entry) {
|
||||
if (aac->id > unique_id)
|
||||
@ -1162,6 +1169,21 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
|
||||
if ((*aac_drivers[index].init)(aac))
|
||||
goto out_unmap;
|
||||
|
||||
if (aac->sync_mode) {
|
||||
if (aac_sync_mode)
|
||||
printk(KERN_INFO "%s%d: Sync. mode enforced "
|
||||
"by driver parameter. This will cause "
|
||||
"a significant performance decrease!\n",
|
||||
aac->name,
|
||||
aac->id);
|
||||
else
|
||||
printk(KERN_INFO "%s%d: Async. mode not supported "
|
||||
"by current driver, sync. mode enforced."
|
||||
"\nPlease update driver to get full performance.\n",
|
||||
aac->name,
|
||||
aac->id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start any kernel threads needed
|
||||
*/
|
||||
|
@ -643,6 +643,7 @@ int _aac_rx_init(struct aac_dev *dev)
|
||||
if (aac_init_adapter(dev) == NULL)
|
||||
goto error_iounmap;
|
||||
aac_adapter_comm(dev, dev->comm_interface);
|
||||
dev->sync_mode = 0; /* sync. mode not supported */
|
||||
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
|
||||
|
@ -385,6 +385,7 @@ int aac_sa_init(struct aac_dev *dev)
|
||||
|
||||
if(aac_init_adapter(dev) == NULL)
|
||||
goto error_irq;
|
||||
dev->sync_mode = 0; /* sync. mode not supported */
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED|IRQF_DISABLED,
|
||||
"aacraid", (void *)dev ) < 0) {
|
||||
|
@ -96,6 +96,38 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
|
||||
our_interrupt = 1;
|
||||
/* handle AIF */
|
||||
aac_intr_normal(dev, 0, 2, 0, NULL);
|
||||
} else if (bellbits_shifted & OUTBOUNDDOORBELL_0) {
|
||||
unsigned long sflags;
|
||||
struct list_head *entry;
|
||||
int send_it = 0;
|
||||
|
||||
if (dev->sync_fib) {
|
||||
our_interrupt = 1;
|
||||
if (dev->sync_fib->callback)
|
||||
dev->sync_fib->callback(dev->sync_fib->callback_data,
|
||||
dev->sync_fib);
|
||||
spin_lock_irqsave(&dev->sync_fib->event_lock, sflags);
|
||||
if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) {
|
||||
dev->management_fib_count--;
|
||||
up(&dev->sync_fib->event_wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->sync_fib->event_lock, sflags);
|
||||
spin_lock_irqsave(&dev->sync_lock, sflags);
|
||||
if (!list_empty(&dev->sync_fib_list)) {
|
||||
entry = dev->sync_fib_list.next;
|
||||
dev->sync_fib = list_entry(entry, struct fib, fiblink);
|
||||
list_del(entry);
|
||||
send_it = 1;
|
||||
} else {
|
||||
dev->sync_fib = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->sync_lock, sflags);
|
||||
if (send_it) {
|
||||
aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
|
||||
(u32)dev->sync_fib->hw_fib_pa, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,56 +209,63 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command,
|
||||
*/
|
||||
src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT);
|
||||
|
||||
ok = 0;
|
||||
start = jiffies;
|
||||
if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) {
|
||||
ok = 0;
|
||||
start = jiffies;
|
||||
|
||||
/*
|
||||
* Wait up to 5 minutes
|
||||
*/
|
||||
while (time_before(jiffies, start+300*HZ)) {
|
||||
udelay(5); /* Delay 5 microseconds to let Mon960 get info. */
|
||||
/*
|
||||
* Mon960 will set doorbell0 bit when it has completed the command.
|
||||
*/
|
||||
if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
|
||||
/*
|
||||
* Clear the doorbell.
|
||||
*/
|
||||
src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Yield the processor in case we are slow
|
||||
*/
|
||||
msleep(1);
|
||||
}
|
||||
if (unlikely(ok != 1)) {
|
||||
/*
|
||||
* Restore interrupt mask even though we timed out
|
||||
*/
|
||||
aac_adapter_enable_int(dev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
/*
|
||||
* Pull the synch status from Mailbox 0.
|
||||
*/
|
||||
if (status)
|
||||
*status = readl(&dev->IndexRegs->Mailbox[0]);
|
||||
if (r1)
|
||||
*r1 = readl(&dev->IndexRegs->Mailbox[1]);
|
||||
if (r2)
|
||||
*r2 = readl(&dev->IndexRegs->Mailbox[2]);
|
||||
if (r3)
|
||||
*r3 = readl(&dev->IndexRegs->Mailbox[3]);
|
||||
if (r4)
|
||||
*r4 = readl(&dev->IndexRegs->Mailbox[4]);
|
||||
|
||||
/*
|
||||
* Clear the synch command doorbell.
|
||||
*/
|
||||
src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait up to 30 seconds
|
||||
* Restore interrupt mask
|
||||
*/
|
||||
while (time_before(jiffies, start+30*HZ)) {
|
||||
/* Delay 5 microseconds to let Mon960 get info. */
|
||||
udelay(5);
|
||||
|
||||
/* Mon960 will set doorbell0 bit
|
||||
* when it has completed the command
|
||||
*/
|
||||
if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
|
||||
/* Clear the doorbell */
|
||||
src_writel(dev,
|
||||
MUnit.ODR_C,
|
||||
OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Yield the processor in case we are slow */
|
||||
msleep(1);
|
||||
}
|
||||
if (unlikely(ok != 1)) {
|
||||
/* Restore interrupt mask even though we timed out */
|
||||
aac_adapter_enable_int(dev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Pull the synch status from Mailbox 0 */
|
||||
if (status)
|
||||
*status = readl(&dev->IndexRegs->Mailbox[0]);
|
||||
if (r1)
|
||||
*r1 = readl(&dev->IndexRegs->Mailbox[1]);
|
||||
if (r2)
|
||||
*r2 = readl(&dev->IndexRegs->Mailbox[2]);
|
||||
if (r3)
|
||||
*r3 = readl(&dev->IndexRegs->Mailbox[3]);
|
||||
if (r4)
|
||||
*r4 = readl(&dev->IndexRegs->Mailbox[4]);
|
||||
|
||||
/* Clear the synch command doorbell */
|
||||
src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
|
||||
/* Restore interrupt mask */
|
||||
aac_adapter_enable_int(dev);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -386,9 +425,7 @@ static int aac_src_ioremap(struct aac_dev *dev, u32 size)
|
||||
{
|
||||
if (!size) {
|
||||
iounmap(dev->regs.src.bar0);
|
||||
dev->regs.src.bar0 = NULL;
|
||||
iounmap(dev->base);
|
||||
dev->base = NULL;
|
||||
dev->base = dev->regs.src.bar0 = NULL;
|
||||
return 0;
|
||||
}
|
||||
dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2),
|
||||
@ -404,7 +441,27 @@ static int aac_src_ioremap(struct aac_dev *dev, u32 size)
|
||||
return -1;
|
||||
}
|
||||
dev->IndexRegs = &((struct src_registers __iomem *)
|
||||
dev->base)->IndexRegs;
|
||||
dev->base)->u.tupelo.IndexRegs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_srcv_ioremap
|
||||
* @size: mapping resize request
|
||||
*
|
||||
*/
|
||||
static int aac_srcv_ioremap(struct aac_dev *dev, u32 size)
|
||||
{
|
||||
if (!size) {
|
||||
iounmap(dev->regs.src.bar0);
|
||||
dev->base = dev->regs.src.bar0 = NULL;
|
||||
return 0;
|
||||
}
|
||||
dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base, size);
|
||||
if (dev->base == NULL)
|
||||
return -1;
|
||||
dev->IndexRegs = &((struct src_registers __iomem *)
|
||||
dev->base)->u.denali.IndexRegs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -419,7 +476,7 @@ static int aac_src_restart_adapter(struct aac_dev *dev, int bled)
|
||||
bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
|
||||
0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL);
|
||||
if (bled || (var != 0x00000001))
|
||||
bled = -EINVAL;
|
||||
return -EINVAL;
|
||||
if (dev->supplement_adapter_info.SupportedOptions2 &
|
||||
AAC_OPTION_DOORBELL_RESET) {
|
||||
src_writel(dev, MUnit.IDR, reset_mask);
|
||||
@ -579,15 +636,149 @@ int aac_src_init(struct aac_dev *dev)
|
||||
dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE;
|
||||
|
||||
aac_adapter_enable_int(dev);
|
||||
/*
|
||||
* Tell the adapter that all is configured, and it can
|
||||
* start accepting requests
|
||||
*/
|
||||
aac_src_start_adapter(dev);
|
||||
|
||||
if (!dev->sync_mode) {
|
||||
/*
|
||||
* Tell the adapter that all is configured, and it can
|
||||
* start accepting requests
|
||||
*/
|
||||
aac_src_start_adapter(dev);
|
||||
}
|
||||
return 0;
|
||||
|
||||
error_iounmap:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* aac_srcv_init - initialize an SRCv card
|
||||
* @dev: device to configure
|
||||
*
|
||||
*/
|
||||
|
||||
int aac_srcv_init(struct aac_dev *dev)
|
||||
{
|
||||
unsigned long start;
|
||||
unsigned long status;
|
||||
int restart = 0;
|
||||
int instance = dev->id;
|
||||
const char *name = dev->name;
|
||||
|
||||
dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
|
||||
dev->a_ops.adapter_comm = aac_src_select_comm;
|
||||
|
||||
dev->base_size = AAC_MIN_SRCV_BAR0_SIZE;
|
||||
if (aac_adapter_ioremap(dev, dev->base_size)) {
|
||||
printk(KERN_WARNING "%s: unable to map adapter.\n", name);
|
||||
goto error_iounmap;
|
||||
}
|
||||
|
||||
/* Failure to reset here is an option ... */
|
||||
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
|
||||
dev->a_ops.adapter_enable_int = aac_src_disable_interrupt;
|
||||
if ((aac_reset_devices || reset_devices) &&
|
||||
!aac_src_restart_adapter(dev, 0))
|
||||
++restart;
|
||||
/*
|
||||
* Check to see if the board panic'd while booting.
|
||||
*/
|
||||
status = src_readl(dev, MUnit.OMR);
|
||||
if (status & KERNEL_PANIC) {
|
||||
if (aac_src_restart_adapter(dev, aac_src_check_health(dev)))
|
||||
goto error_iounmap;
|
||||
++restart;
|
||||
}
|
||||
/*
|
||||
* Check to see if the board failed any self tests.
|
||||
*/
|
||||
status = src_readl(dev, MUnit.OMR);
|
||||
if (status & SELF_TEST_FAILED) {
|
||||
printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
/*
|
||||
* Check to see if the monitor panic'd while booting.
|
||||
*/
|
||||
if (status & MONITOR_PANIC) {
|
||||
printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
start = jiffies;
|
||||
/*
|
||||
* Wait for the adapter to be up and running. Wait up to 3 minutes
|
||||
*/
|
||||
while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)) {
|
||||
if ((restart &&
|
||||
(status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
|
||||
time_after(jiffies, start+HZ*startup_timeout)) {
|
||||
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
|
||||
dev->name, instance, status);
|
||||
goto error_iounmap;
|
||||
}
|
||||
if (!restart &&
|
||||
((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
|
||||
time_after(jiffies, start + HZ *
|
||||
((startup_timeout > 60)
|
||||
? (startup_timeout - 60)
|
||||
: (startup_timeout / 2))))) {
|
||||
if (likely(!aac_src_restart_adapter(dev, aac_src_check_health(dev))))
|
||||
start = jiffies;
|
||||
++restart;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
if (restart && aac_commit)
|
||||
aac_commit = 1;
|
||||
/*
|
||||
* Fill in the common function dispatch table.
|
||||
*/
|
||||
dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter;
|
||||
dev->a_ops.adapter_disable_int = aac_src_disable_interrupt;
|
||||
dev->a_ops.adapter_notify = aac_src_notify_adapter;
|
||||
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
|
||||
dev->a_ops.adapter_check_health = aac_src_check_health;
|
||||
dev->a_ops.adapter_restart = aac_src_restart_adapter;
|
||||
|
||||
/*
|
||||
* First clear out all interrupts. Then enable the one's that we
|
||||
* can handle.
|
||||
*/
|
||||
aac_adapter_comm(dev, AAC_COMM_MESSAGE);
|
||||
aac_adapter_disable_int(dev);
|
||||
src_writel(dev, MUnit.ODR_C, 0xffffffff);
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
if (aac_init_adapter(dev) == NULL)
|
||||
goto error_iounmap;
|
||||
if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1)
|
||||
goto error_iounmap;
|
||||
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
|
||||
name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
dev->dbg_base = dev->scsi_host_ptr->base;
|
||||
dev->dbg_base_mapped = dev->base;
|
||||
dev->dbg_size = dev->base_size;
|
||||
|
||||
aac_adapter_enable_int(dev);
|
||||
|
||||
if (!dev->sync_mode) {
|
||||
/*
|
||||
* Tell the adapter that all is configured, and it can
|
||||
* start accepting requests
|
||||
*/
|
||||
aac_src_start_adapter(dev);
|
||||
}
|
||||
return 0;
|
||||
|
||||
error_iounmap:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,8 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id);
|
||||
|
||||
int asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags);
|
||||
|
||||
void asd_set_dmamode(struct domain_device *dev);
|
||||
|
||||
/* ---------- TMFs ---------- */
|
||||
int asd_abort_task(struct sas_task *);
|
||||
int asd_abort_task_set(struct domain_device *, u8 *lun);
|
||||
|
@ -109,26 +109,37 @@ static int asd_init_sata_tag_ddb(struct domain_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asd_init_sata(struct domain_device *dev)
|
||||
void asd_set_dmamode(struct domain_device *dev)
|
||||
{
|
||||
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
|
||||
struct ata_device *ata_dev = sas_to_ata_dev(dev);
|
||||
int ddb = (int) (unsigned long) dev->lldd_dev;
|
||||
u32 qdepth = 0;
|
||||
int res = 0;
|
||||
|
||||
asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
|
||||
if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) &&
|
||||
dev->sata_dev.identify_device &&
|
||||
dev->sata_dev.identify_device[10] != 0) {
|
||||
u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]);
|
||||
u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]);
|
||||
|
||||
if (w76 & 0x100) /* NCQ? */
|
||||
qdepth = (w75 & 0x1F) + 1;
|
||||
if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) {
|
||||
if (ata_id_has_ncq(ata_dev->id))
|
||||
qdepth = ata_id_queue_depth(ata_dev->id);
|
||||
asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
|
||||
(1ULL<<qdepth)-1);
|
||||
asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
|
||||
}
|
||||
|
||||
if (qdepth > 0)
|
||||
if (asd_init_sata_tag_ddb(dev) != 0) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
|
||||
ata_dev->flags |= ATA_DFLAG_NCQ_OFF;
|
||||
spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static int asd_init_sata(struct domain_device *dev)
|
||||
{
|
||||
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
|
||||
int ddb = (int) (unsigned long) dev->lldd_dev;
|
||||
|
||||
asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
|
||||
if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
|
||||
dev->dev_type == SATA_PM_PORT) {
|
||||
struct dev_to_host_fis *fis = (struct dev_to_host_fis *)
|
||||
@ -136,9 +147,8 @@ static int asd_init_sata(struct domain_device *dev)
|
||||
asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status);
|
||||
}
|
||||
asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF);
|
||||
if (qdepth > 0)
|
||||
res = asd_init_sata_tag_ddb(dev);
|
||||
return res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asd_init_target_ddb(struct domain_device *dev)
|
||||
|
@ -68,7 +68,6 @@ static struct scsi_host_template aic94xx_sht = {
|
||||
.queuecommand = sas_queuecommand,
|
||||
.target_alloc = sas_target_alloc,
|
||||
.slave_configure = sas_slave_configure,
|
||||
.slave_destroy = sas_slave_destroy,
|
||||
.scan_finished = asd_scan_finished,
|
||||
.scan_start = asd_scan_start,
|
||||
.change_queue_depth = sas_change_queue_depth,
|
||||
@ -82,7 +81,6 @@ static struct scsi_host_template aic94xx_sht = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.eh_device_reset_handler = sas_eh_device_reset_handler,
|
||||
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
|
||||
.slave_alloc = sas_slave_alloc,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
};
|
||||
@ -972,7 +970,7 @@ static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time)
|
||||
if (time < HZ)
|
||||
return 0;
|
||||
/* Wait for discovery to finish */
|
||||
scsi_flush_work(shost);
|
||||
sas_drain_work(SHOST_TO_SAS_HA(shost));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1010,6 +1008,8 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
|
||||
.lldd_clear_nexus_ha = asd_clear_nexus_ha,
|
||||
|
||||
.lldd_control_phy = asd_control_phy,
|
||||
|
||||
.lldd_ata_set_dmamode = asd_set_dmamode,
|
||||
};
|
||||
|
||||
static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
|
||||
|
@ -181,7 +181,7 @@ static int asd_clear_nexus_I_T(struct domain_device *dev,
|
||||
int asd_I_T_nexus_reset(struct domain_device *dev)
|
||||
{
|
||||
int res, tmp_res, i;
|
||||
struct sas_phy *phy = sas_find_local_phy(dev);
|
||||
struct sas_phy *phy = sas_get_local_phy(dev);
|
||||
/* Standard mandates link reset for ATA (type 0) and
|
||||
* hard reset for SSP (type 1) */
|
||||
int reset_type = (dev->dev_type == SATA_DEV ||
|
||||
@ -192,7 +192,7 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
|
||||
ASD_DPRINTK("sending %s reset to %s\n",
|
||||
reset_type ? "hard" : "soft", dev_name(&phy->dev));
|
||||
res = sas_phy_reset(phy, reset_type);
|
||||
if (res == TMF_RESP_FUNC_COMPLETE) {
|
||||
if (res == TMF_RESP_FUNC_COMPLETE || res == -ENODEV) {
|
||||
/* wait for the maximum settle time */
|
||||
msleep(500);
|
||||
/* clear all outstanding commands (keep nexus suspended) */
|
||||
@ -201,7 +201,7 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
|
||||
for (i = 0 ; i < 3; i++) {
|
||||
tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME);
|
||||
if (tmp_res == TC_RESUME)
|
||||
return res;
|
||||
goto out;
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
@ -211,7 +211,10 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
|
||||
dev_printk(KERN_ERR, &phy->dev,
|
||||
"Failed to resume nexus after reset 0x%x\n", tmp_res);
|
||||
|
||||
return TMF_RESP_FUNC_FAILED;
|
||||
res = TMF_RESP_FUNC_FAILED;
|
||||
out:
|
||||
sas_put_local_phy(phy);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
|
||||
|
@ -3047,8 +3047,7 @@ bfad_im_bsg_els_ct_request(struct fc_bsg_job *job)
|
||||
* Allocate buffer for bsg_fcpt and do a copy_from_user op for payload
|
||||
* buffer of size bsg_data->payload_len
|
||||
*/
|
||||
bsg_fcpt = (struct bfa_bsg_fcpt_s *)
|
||||
kzalloc(bsg_data->payload_len, GFP_KERNEL);
|
||||
bsg_fcpt = kzalloc(bsg_data->payload_len, GFP_KERNEL);
|
||||
if (!bsg_fcpt)
|
||||
goto out;
|
||||
|
||||
@ -3060,6 +3059,7 @@ bfad_im_bsg_els_ct_request(struct fc_bsg_job *job)
|
||||
|
||||
drv_fcxp = kzalloc(sizeof(struct bfad_fcxp), GFP_KERNEL);
|
||||
if (drv_fcxp == NULL) {
|
||||
kfree(bsg_fcpt);
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@
|
||||
#include "bnx2fc_constants.h"
|
||||
|
||||
#define BNX2FC_NAME "bnx2fc"
|
||||
#define BNX2FC_VERSION "1.0.9"
|
||||
#define BNX2FC_VERSION "1.0.10"
|
||||
|
||||
#define PFX "bnx2fc: "
|
||||
|
||||
@ -114,6 +114,8 @@
|
||||
#define BNX2FC_HASH_TBL_CHUNK_SIZE (16 * 1024)
|
||||
|
||||
#define BNX2FC_MAX_SEQS 255
|
||||
#define BNX2FC_MAX_RETRY_CNT 3
|
||||
#define BNX2FC_MAX_RPORT_RETRY_CNT 255
|
||||
|
||||
#define BNX2FC_READ (1 << 1)
|
||||
#define BNX2FC_WRITE (1 << 0)
|
||||
@ -121,8 +123,10 @@
|
||||
#define BNX2FC_MIN_XID 0
|
||||
#define BNX2FC_MAX_XID \
|
||||
(BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS - 1)
|
||||
#define FCOE_MAX_NUM_XIDS 0x2000
|
||||
#define FCOE_MIN_XID (BNX2FC_MAX_XID + 1)
|
||||
#define FCOE_MAX_XID (FCOE_MIN_XID + 4095)
|
||||
#define FCOE_MAX_XID (FCOE_MIN_XID + FCOE_MAX_NUM_XIDS - 1)
|
||||
#define FCOE_XIDS_PER_CPU (FCOE_MIN_XID + (512 * nr_cpu_ids) - 1)
|
||||
#define BNX2FC_MAX_LUN 0xFFFF
|
||||
#define BNX2FC_MAX_FCP_TGT 256
|
||||
#define BNX2FC_MAX_CMD_LEN 16
|
||||
|
@ -22,7 +22,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
|
||||
|
||||
#define DRV_MODULE_NAME "bnx2fc"
|
||||
#define DRV_MODULE_VERSION BNX2FC_VERSION
|
||||
#define DRV_MODULE_RELDATE "Oct 21, 2011"
|
||||
#define DRV_MODULE_RELDATE "Jan 22, 2011"
|
||||
|
||||
|
||||
static char version[] __devinitdata =
|
||||
@ -939,8 +939,14 @@ static int bnx2fc_libfc_config(struct fc_lport *lport)
|
||||
|
||||
static int bnx2fc_em_config(struct fc_lport *lport)
|
||||
{
|
||||
int max_xid;
|
||||
|
||||
if (nr_cpu_ids <= 2)
|
||||
max_xid = FCOE_XIDS_PER_CPU;
|
||||
else
|
||||
max_xid = FCOE_MAX_XID;
|
||||
if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_MIN_XID,
|
||||
FCOE_MAX_XID, NULL)) {
|
||||
max_xid, NULL)) {
|
||||
printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -952,8 +958,8 @@ static int bnx2fc_lport_config(struct fc_lport *lport)
|
||||
{
|
||||
lport->link_up = 0;
|
||||
lport->qfull = 0;
|
||||
lport->max_retry_count = 3;
|
||||
lport->max_rport_retry_count = 3;
|
||||
lport->max_retry_count = BNX2FC_MAX_RETRY_CNT;
|
||||
lport->max_rport_retry_count = BNX2FC_MAX_RPORT_RETRY_CNT;
|
||||
lport->e_d_tov = 2 * 1000;
|
||||
lport->r_a_tov = 10 * 1000;
|
||||
|
||||
@ -1536,6 +1542,7 @@ static void __bnx2fc_destroy(struct bnx2fc_interface *interface)
|
||||
static int bnx2fc_destroy(struct net_device *netdev)
|
||||
{
|
||||
struct bnx2fc_interface *interface = NULL;
|
||||
struct workqueue_struct *timer_work_queue;
|
||||
int rc = 0;
|
||||
|
||||
rtnl_lock();
|
||||
@ -1548,9 +1555,9 @@ static int bnx2fc_destroy(struct net_device *netdev)
|
||||
goto netdev_err;
|
||||
}
|
||||
|
||||
|
||||
destroy_workqueue(interface->timer_work_queue);
|
||||
timer_work_queue = interface->timer_work_queue;
|
||||
__bnx2fc_destroy(interface);
|
||||
destroy_workqueue(timer_work_queue);
|
||||
|
||||
netdev_err:
|
||||
mutex_unlock(&bnx2fc_dev_lock);
|
||||
@ -2054,6 +2061,7 @@ if_create_err:
|
||||
ifput_err:
|
||||
bnx2fc_net_cleanup(interface);
|
||||
bnx2fc_interface_put(interface);
|
||||
goto mod_err;
|
||||
netdev_err:
|
||||
module_put(THIS_MODULE);
|
||||
mod_err:
|
||||
|
@ -1312,14 +1312,18 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
|
||||
ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) |
|
||||
/* EMC */
|
||||
(1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN));
|
||||
if (error_mask1)
|
||||
if (error_mask1) {
|
||||
iscsi_init2.error_bit_map[0] = error_mask1;
|
||||
else
|
||||
mask64 &= (u32)(~mask64);
|
||||
mask64 |= error_mask1;
|
||||
} else
|
||||
iscsi_init2.error_bit_map[0] = (u32) mask64;
|
||||
|
||||
if (error_mask2)
|
||||
if (error_mask2) {
|
||||
iscsi_init2.error_bit_map[1] = error_mask2;
|
||||
else
|
||||
mask64 &= 0xffffffff;
|
||||
mask64 |= ((u64)error_mask2 << 32);
|
||||
} else
|
||||
iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32);
|
||||
|
||||
iscsi_error_mask = mask64;
|
||||
|
@ -49,11 +49,11 @@ module_param(en_tcp_dack, int, 0664);
|
||||
MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK");
|
||||
|
||||
unsigned int error_mask1 = 0x00;
|
||||
module_param(error_mask1, int, 0664);
|
||||
module_param(error_mask1, uint, 0664);
|
||||
MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1");
|
||||
|
||||
unsigned int error_mask2 = 0x00;
|
||||
module_param(error_mask2, int, 0664);
|
||||
module_param(error_mask2, uint, 0664);
|
||||
MODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2");
|
||||
|
||||
unsigned int sq_size;
|
||||
@ -393,8 +393,9 @@ static void bnx2i_percpu_thread_create(unsigned int cpu)
|
||||
|
||||
p = &per_cpu(bnx2i_percpu, cpu);
|
||||
|
||||
thread = kthread_create(bnx2i_percpu_io_thread, (void *)p,
|
||||
"bnx2i_thread/%d", cpu);
|
||||
thread = kthread_create_on_node(bnx2i_percpu_io_thread, (void *)p,
|
||||
cpu_to_node(cpu),
|
||||
"bnx2i_thread/%d", cpu);
|
||||
/* bind thread to the cpu */
|
||||
if (likely(!IS_ERR(thread))) {
|
||||
kthread_bind(thread, cpu);
|
||||
|
@ -2147,11 +2147,10 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn,
|
||||
enum iscsi_param param, char *buf, int buflen)
|
||||
{
|
||||
struct iscsi_conn *conn = cls_conn->dd_data;
|
||||
struct iscsi_session *session = conn->session;
|
||||
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
|
||||
struct cxgbi_conn *cconn = tcp_conn->dd_data;
|
||||
struct cxgbi_sock *csk = cconn->cep->csk;
|
||||
int value, err = 0;
|
||||
int err;
|
||||
|
||||
log_debug(1 << CXGBI_DBG_ISCSI,
|
||||
"cls_conn 0x%p, param %d, buf(%d) %s.\n",
|
||||
@ -2173,15 +2172,7 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn,
|
||||
conn->datadgst_en, 0);
|
||||
break;
|
||||
case ISCSI_PARAM_MAX_R2T:
|
||||
sscanf(buf, "%d", &value);
|
||||
if (value <= 0 || !is_power_of_2(value))
|
||||
return -EINVAL;
|
||||
if (session->max_r2t == value)
|
||||
break;
|
||||
iscsi_tcp_r2tpool_free(session);
|
||||
err = iscsi_set_param(cls_conn, param, buf, buflen);
|
||||
if (!err && iscsi_tcp_r2tpool_alloc(session))
|
||||
return -ENOMEM;
|
||||
return iscsi_tcp_set_max_r2t(conn, buf);
|
||||
case ISCSI_PARAM_MAX_RECV_DLENGTH:
|
||||
err = iscsi_set_param(cls_conn, param, buf, buflen);
|
||||
if (!err)
|
||||
|
@ -168,6 +168,14 @@ static struct fc_function_template fcoe_nport_fc_functions = {
|
||||
.show_host_supported_fc4s = 1,
|
||||
.show_host_active_fc4s = 1,
|
||||
.show_host_maxframe_size = 1,
|
||||
.show_host_serial_number = 1,
|
||||
.show_host_manufacturer = 1,
|
||||
.show_host_model = 1,
|
||||
.show_host_model_description = 1,
|
||||
.show_host_hardware_version = 1,
|
||||
.show_host_driver_version = 1,
|
||||
.show_host_firmware_version = 1,
|
||||
.show_host_optionrom_version = 1,
|
||||
|
||||
.show_host_port_id = 1,
|
||||
.show_host_supported_speeds = 1,
|
||||
@ -208,6 +216,14 @@ static struct fc_function_template fcoe_vport_fc_functions = {
|
||||
.show_host_supported_fc4s = 1,
|
||||
.show_host_active_fc4s = 1,
|
||||
.show_host_maxframe_size = 1,
|
||||
.show_host_serial_number = 1,
|
||||
.show_host_manufacturer = 1,
|
||||
.show_host_model = 1,
|
||||
.show_host_model_description = 1,
|
||||
.show_host_hardware_version = 1,
|
||||
.show_host_driver_version = 1,
|
||||
.show_host_firmware_version = 1,
|
||||
.show_host_optionrom_version = 1,
|
||||
|
||||
.show_host_port_id = 1,
|
||||
.show_host_supported_speeds = 1,
|
||||
@ -364,11 +380,10 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
|
||||
if (!fcoe) {
|
||||
FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n");
|
||||
fcoe = ERR_PTR(-ENOMEM);
|
||||
goto out_nomod;
|
||||
goto out_putmod;
|
||||
}
|
||||
|
||||
dev_hold(netdev);
|
||||
kref_init(&fcoe->kref);
|
||||
|
||||
/*
|
||||
* Initialize FIP.
|
||||
@ -384,53 +399,17 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
|
||||
kfree(fcoe);
|
||||
dev_put(netdev);
|
||||
fcoe = ERR_PTR(err);
|
||||
goto out_nomod;
|
||||
goto out_putmod;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
out_nomod:
|
||||
out_putmod:
|
||||
module_put(THIS_MODULE);
|
||||
out:
|
||||
return fcoe;
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_interface_release() - fcoe_port kref release function
|
||||
* @kref: Embedded reference count in an fcoe_interface struct
|
||||
*/
|
||||
static void fcoe_interface_release(struct kref *kref)
|
||||
{
|
||||
struct fcoe_interface *fcoe;
|
||||
struct net_device *netdev;
|
||||
|
||||
fcoe = container_of(kref, struct fcoe_interface, kref);
|
||||
netdev = fcoe->netdev;
|
||||
/* tear-down the FCoE controller */
|
||||
fcoe_ctlr_destroy(&fcoe->ctlr);
|
||||
kfree(fcoe);
|
||||
dev_put(netdev);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_interface_get() - Get a reference to a FCoE interface
|
||||
* @fcoe: The FCoE interface to be held
|
||||
*/
|
||||
static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
|
||||
{
|
||||
kref_get(&fcoe->kref);
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_interface_put() - Put a reference to a FCoE interface
|
||||
* @fcoe: The FCoE interface to be released
|
||||
*/
|
||||
static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
|
||||
{
|
||||
kref_put(&fcoe->kref, fcoe_interface_release);
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_interface_cleanup() - Clean up a FCoE interface
|
||||
* @fcoe: The FCoE interface to be cleaned up
|
||||
@ -478,7 +457,11 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
|
||||
rtnl_unlock();
|
||||
|
||||
/* Release the self-reference taken during fcoe_interface_create() */
|
||||
fcoe_interface_put(fcoe);
|
||||
/* tear-down the FCoE controller */
|
||||
fcoe_ctlr_destroy(fip);
|
||||
kfree(fcoe);
|
||||
dev_put(netdev);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -734,6 +717,85 @@ static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fcoe_fdmi_info() - Get FDMI related info from net devive for SW FCoE
|
||||
* @lport: The local port that is associated with the net device
|
||||
* @netdev: The associated net device
|
||||
*
|
||||
* Must be called after fcoe_shost_config() as it will use local port mutex
|
||||
*
|
||||
*/
|
||||
static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev)
|
||||
{
|
||||
struct fcoe_interface *fcoe;
|
||||
struct fcoe_port *port;
|
||||
struct net_device *realdev;
|
||||
int rc;
|
||||
struct netdev_fcoe_hbainfo fdmi;
|
||||
|
||||
port = lport_priv(lport);
|
||||
fcoe = port->priv;
|
||||
realdev = fcoe->realdev;
|
||||
|
||||
if (!realdev)
|
||||
return;
|
||||
|
||||
/* No FDMI state m/c for NPIV ports */
|
||||
if (lport->vport)
|
||||
return;
|
||||
|
||||
if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) {
|
||||
memset(&fdmi, 0, sizeof(fdmi));
|
||||
rc = realdev->netdev_ops->ndo_fcoe_get_hbainfo(realdev,
|
||||
&fdmi);
|
||||
if (rc) {
|
||||
printk(KERN_INFO "fcoe: Failed to retrieve FDMI "
|
||||
"information from netdev.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(fc_host_serial_number(lport->host),
|
||||
FC_SERIAL_NUMBER_SIZE,
|
||||
"%s",
|
||||
fdmi.serial_number);
|
||||
snprintf(fc_host_manufacturer(lport->host),
|
||||
FC_SERIAL_NUMBER_SIZE,
|
||||
"%s",
|
||||
fdmi.manufacturer);
|
||||
snprintf(fc_host_model(lport->host),
|
||||
FC_SYMBOLIC_NAME_SIZE,
|
||||
"%s",
|
||||
fdmi.model);
|
||||
snprintf(fc_host_model_description(lport->host),
|
||||
FC_SYMBOLIC_NAME_SIZE,
|
||||
"%s",
|
||||
fdmi.model_description);
|
||||
snprintf(fc_host_hardware_version(lport->host),
|
||||
FC_VERSION_STRING_SIZE,
|
||||
"%s",
|
||||
fdmi.hardware_version);
|
||||
snprintf(fc_host_driver_version(lport->host),
|
||||
FC_VERSION_STRING_SIZE,
|
||||
"%s",
|
||||
fdmi.driver_version);
|
||||
snprintf(fc_host_optionrom_version(lport->host),
|
||||
FC_VERSION_STRING_SIZE,
|
||||
"%s",
|
||||
fdmi.optionrom_version);
|
||||
snprintf(fc_host_firmware_version(lport->host),
|
||||
FC_VERSION_STRING_SIZE,
|
||||
"%s",
|
||||
fdmi.firmware_version);
|
||||
|
||||
/* Enable FDMI lport states */
|
||||
lport->fdmi_enabled = 1;
|
||||
} else {
|
||||
lport->fdmi_enabled = 0;
|
||||
printk(KERN_INFO "fcoe: No FDMI support.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_oem_match() - The match routine for the offloaded exchange manager
|
||||
* @fp: The I/O frame
|
||||
@ -881,9 +943,6 @@ static void fcoe_if_destroy(struct fc_lport *lport)
|
||||
dev_uc_del(netdev, port->data_src_addr);
|
||||
rtnl_unlock();
|
||||
|
||||
/* Release reference held in fcoe_if_create() */
|
||||
fcoe_interface_put(fcoe);
|
||||
|
||||
/* Free queued packets for the per-CPU receive threads */
|
||||
fcoe_percpu_clean(lport);
|
||||
|
||||
@ -1047,6 +1106,9 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
|
||||
goto out_lp_destroy;
|
||||
}
|
||||
|
||||
/* Initialized FDMI information */
|
||||
fcoe_fdmi_info(lport, netdev);
|
||||
|
||||
/*
|
||||
* fcoe_em_alloc() and fcoe_hostlist_add() both
|
||||
* need to be atomic with respect to other changes to the
|
||||
@ -1070,7 +1132,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
|
||||
goto out_lp_destroy;
|
||||
}
|
||||
|
||||
fcoe_interface_get(fcoe);
|
||||
return lport;
|
||||
|
||||
out_lp_destroy:
|
||||
@ -2009,20 +2070,13 @@ static void fcoe_destroy_work(struct work_struct *work)
|
||||
{
|
||||
struct fcoe_port *port;
|
||||
struct fcoe_interface *fcoe;
|
||||
int npiv = 0;
|
||||
|
||||
port = container_of(work, struct fcoe_port, destroy_work);
|
||||
mutex_lock(&fcoe_config_mutex);
|
||||
|
||||
/* set if this is an NPIV port */
|
||||
npiv = port->lport->vport ? 1 : 0;
|
||||
|
||||
fcoe = port->priv;
|
||||
fcoe_if_destroy(port->lport);
|
||||
|
||||
/* Do not tear down the fcoe interface for NPIV port */
|
||||
if (!npiv)
|
||||
fcoe_interface_cleanup(fcoe);
|
||||
fcoe_interface_cleanup(fcoe);
|
||||
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
}
|
||||
@ -2593,12 +2647,15 @@ static int fcoe_vport_destroy(struct fc_vport *vport)
|
||||
struct Scsi_Host *shost = vport_to_shost(vport);
|
||||
struct fc_lport *n_port = shost_priv(shost);
|
||||
struct fc_lport *vn_port = vport->dd_data;
|
||||
struct fcoe_port *port = lport_priv(vn_port);
|
||||
|
||||
mutex_lock(&n_port->lp_mutex);
|
||||
list_del(&vn_port->list);
|
||||
mutex_unlock(&n_port->lp_mutex);
|
||||
queue_work(fcoe_wq, &port->destroy_work);
|
||||
|
||||
mutex_lock(&fcoe_config_mutex);
|
||||
fcoe_if_destroy(vn_port);
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -71,8 +71,6 @@ do { \
|
||||
* @ctlr: The FCoE controller (for FIP)
|
||||
* @oem: The offload exchange manager for all local port
|
||||
* instances associated with this port
|
||||
* @kref: The kernel reference
|
||||
*
|
||||
* This structure is 1:1 with a net devive.
|
||||
*/
|
||||
struct fcoe_interface {
|
||||
@ -83,7 +81,6 @@ struct fcoe_interface {
|
||||
struct packet_type fip_packet_type;
|
||||
struct fcoe_ctlr ctlr;
|
||||
struct fc_exch_mgr *oem;
|
||||
struct kref kref;
|
||||
};
|
||||
|
||||
#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr)
|
||||
|
@ -619,8 +619,8 @@ static int libfcoe_device_notification(struct notifier_block *notifier,
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_UNREGISTER:
|
||||
printk(KERN_ERR "libfcoe_device_notification: NETDEV_UNREGISTER %s\n",
|
||||
netdev->name);
|
||||
LIBFCOE_TRANSPORT_DBG("NETDEV_UNREGISTER %s\n",
|
||||
netdev->name);
|
||||
fcoe_del_netdev_mapping(netdev);
|
||||
break;
|
||||
}
|
||||
|
@ -56,6 +56,7 @@
|
||||
/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
|
||||
#define HPSA_DRIVER_VERSION "2.0.2-1"
|
||||
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
|
||||
#define HPSA "hpsa"
|
||||
|
||||
/* How long to wait (in milliseconds) for board to go into simple mode */
|
||||
#define MAX_CONFIG_WAIT 30000
|
||||
@ -202,30 +203,31 @@ static int check_for_unit_attention(struct ctlr_info *h,
|
||||
|
||||
switch (c->err_info->SenseInfo[12]) {
|
||||
case STATE_CHANGED:
|
||||
dev_warn(&h->pdev->dev, "hpsa%d: a state change "
|
||||
dev_warn(&h->pdev->dev, HPSA "%d: a state change "
|
||||
"detected, command retried\n", h->ctlr);
|
||||
break;
|
||||
case LUN_FAILED:
|
||||
dev_warn(&h->pdev->dev, "hpsa%d: LUN failure "
|
||||
dev_warn(&h->pdev->dev, HPSA "%d: LUN failure "
|
||||
"detected, action required\n", h->ctlr);
|
||||
break;
|
||||
case REPORT_LUNS_CHANGED:
|
||||
dev_warn(&h->pdev->dev, "hpsa%d: report LUN data "
|
||||
dev_warn(&h->pdev->dev, HPSA "%d: report LUN data "
|
||||
"changed, action required\n", h->ctlr);
|
||||
/*
|
||||
* Note: this REPORT_LUNS_CHANGED condition only occurs on the MSA2012.
|
||||
* Note: this REPORT_LUNS_CHANGED condition only occurs on the external
|
||||
* target (array) devices.
|
||||
*/
|
||||
break;
|
||||
case POWER_OR_RESET:
|
||||
dev_warn(&h->pdev->dev, "hpsa%d: a power on "
|
||||
dev_warn(&h->pdev->dev, HPSA "%d: a power on "
|
||||
"or device reset detected\n", h->ctlr);
|
||||
break;
|
||||
case UNIT_ATTENTION_CLEARED:
|
||||
dev_warn(&h->pdev->dev, "hpsa%d: unit attention "
|
||||
dev_warn(&h->pdev->dev, HPSA "%d: unit attention "
|
||||
"cleared by another initiator\n", h->ctlr);
|
||||
break;
|
||||
default:
|
||||
dev_warn(&h->pdev->dev, "hpsa%d: unknown "
|
||||
dev_warn(&h->pdev->dev, HPSA "%d: unknown "
|
||||
"unit attention detected\n", h->ctlr);
|
||||
break;
|
||||
}
|
||||
@ -296,11 +298,23 @@ static u32 unresettable_controller[] = {
|
||||
0x40800E11, /* Smart Array 5i */
|
||||
0x409C0E11, /* Smart Array 6400 */
|
||||
0x409D0E11, /* Smart Array 6400 EM */
|
||||
0x40700E11, /* Smart Array 5300 */
|
||||
0x40820E11, /* Smart Array 532 */
|
||||
0x40830E11, /* Smart Array 5312 */
|
||||
0x409A0E11, /* Smart Array 641 */
|
||||
0x409B0E11, /* Smart Array 642 */
|
||||
0x40910E11, /* Smart Array 6i */
|
||||
};
|
||||
|
||||
/* List of controllers which cannot even be soft reset */
|
||||
static u32 soft_unresettable_controller[] = {
|
||||
0x40800E11, /* Smart Array 5i */
|
||||
0x40700E11, /* Smart Array 5300 */
|
||||
0x40820E11, /* Smart Array 532 */
|
||||
0x40830E11, /* Smart Array 5312 */
|
||||
0x409A0E11, /* Smart Array 641 */
|
||||
0x409B0E11, /* Smart Array 642 */
|
||||
0x40910E11, /* Smart Array 6i */
|
||||
/* Exclude 640x boards. These are two pci devices in one slot
|
||||
* which share a battery backed cache module. One controls the
|
||||
* cache, the other accesses the cache through the one that controls
|
||||
@ -475,8 +489,8 @@ static struct device_attribute *hpsa_shost_attrs[] = {
|
||||
|
||||
static struct scsi_host_template hpsa_driver_template = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "hpsa",
|
||||
.proc_name = "hpsa",
|
||||
.name = HPSA,
|
||||
.proc_name = HPSA,
|
||||
.queuecommand = hpsa_scsi_queue_command,
|
||||
.scan_start = hpsa_scan_start,
|
||||
.scan_finished = hpsa_scan_finished,
|
||||
@ -577,21 +591,19 @@ static int hpsa_find_target_lun(struct ctlr_info *h,
|
||||
int i, found = 0;
|
||||
DECLARE_BITMAP(lun_taken, HPSA_MAX_DEVICES);
|
||||
|
||||
memset(&lun_taken[0], 0, HPSA_MAX_DEVICES >> 3);
|
||||
bitmap_zero(lun_taken, HPSA_MAX_DEVICES);
|
||||
|
||||
for (i = 0; i < h->ndevices; i++) {
|
||||
if (h->dev[i]->bus == bus && h->dev[i]->target != -1)
|
||||
set_bit(h->dev[i]->target, lun_taken);
|
||||
__set_bit(h->dev[i]->target, lun_taken);
|
||||
}
|
||||
|
||||
for (i = 0; i < HPSA_MAX_DEVICES; i++) {
|
||||
if (!test_bit(i, lun_taken)) {
|
||||
/* *bus = 1; */
|
||||
*target = i;
|
||||
*lun = 0;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
i = find_first_zero_bit(lun_taken, HPSA_MAX_DEVICES);
|
||||
if (i < HPSA_MAX_DEVICES) {
|
||||
/* *bus = 1; */
|
||||
*target = i;
|
||||
*lun = 0;
|
||||
found = 1;
|
||||
}
|
||||
return !found;
|
||||
}
|
||||
@ -675,6 +687,20 @@ lun_assigned:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update an entry in h->dev[] array. */
|
||||
static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
|
||||
int entry, struct hpsa_scsi_dev_t *new_entry)
|
||||
{
|
||||
/* assumes h->devlock is held */
|
||||
BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
|
||||
|
||||
/* Raid level changed. */
|
||||
h->dev[entry]->raid_level = new_entry->raid_level;
|
||||
dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n",
|
||||
scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
|
||||
new_entry->target, new_entry->lun);
|
||||
}
|
||||
|
||||
/* Replace an entry from h->dev[] array. */
|
||||
static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
|
||||
int entry, struct hpsa_scsi_dev_t *new_entry,
|
||||
@ -781,10 +807,25 @@ static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int device_updated(struct hpsa_scsi_dev_t *dev1,
|
||||
struct hpsa_scsi_dev_t *dev2)
|
||||
{
|
||||
/* Device attributes that can change, but don't mean
|
||||
* that the device is a different device, nor that the OS
|
||||
* needs to be told anything about the change.
|
||||
*/
|
||||
if (dev1->raid_level != dev2->raid_level)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find needle in haystack. If exact match found, return DEVICE_SAME,
|
||||
* and return needle location in *index. If scsi3addr matches, but not
|
||||
* vendor, model, serial num, etc. return DEVICE_CHANGED, and return needle
|
||||
* location in *index. If needle not found, return DEVICE_NOT_FOUND.
|
||||
* location in *index.
|
||||
* In the case of a minor device attribute change, such as RAID level, just
|
||||
* return DEVICE_UPDATED, along with the updated device's location in index.
|
||||
* If needle not found, return DEVICE_NOT_FOUND.
|
||||
*/
|
||||
static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
|
||||
struct hpsa_scsi_dev_t *haystack[], int haystack_size,
|
||||
@ -794,15 +835,19 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
|
||||
#define DEVICE_NOT_FOUND 0
|
||||
#define DEVICE_CHANGED 1
|
||||
#define DEVICE_SAME 2
|
||||
#define DEVICE_UPDATED 3
|
||||
for (i = 0; i < haystack_size; i++) {
|
||||
if (haystack[i] == NULL) /* previously removed. */
|
||||
continue;
|
||||
if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
|
||||
*index = i;
|
||||
if (device_is_the_same(needle, haystack[i]))
|
||||
if (device_is_the_same(needle, haystack[i])) {
|
||||
if (device_updated(needle, haystack[i]))
|
||||
return DEVICE_UPDATED;
|
||||
return DEVICE_SAME;
|
||||
else
|
||||
} else {
|
||||
return DEVICE_CHANGED;
|
||||
}
|
||||
}
|
||||
}
|
||||
*index = -1;
|
||||
@ -838,6 +883,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
|
||||
* sd[] and remove them from h->dev[], and for any
|
||||
* devices which have changed, remove the old device
|
||||
* info and add the new device info.
|
||||
* If minor device attributes change, just update
|
||||
* the existing device structure.
|
||||
*/
|
||||
i = 0;
|
||||
nremoved = 0;
|
||||
@ -858,6 +905,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
|
||||
* at the bottom of hpsa_update_scsi_devices()
|
||||
*/
|
||||
sd[entry] = NULL;
|
||||
} else if (device_change == DEVICE_UPDATED) {
|
||||
hpsa_scsi_update_entry(h, hostno, i, sd[entry]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -1257,46 +1306,6 @@ static void complete_scsi_command(struct CommandList *cp)
|
||||
cmd_free(h, cp);
|
||||
}
|
||||
|
||||
static int hpsa_scsi_detect(struct ctlr_info *h)
|
||||
{
|
||||
struct Scsi_Host *sh;
|
||||
int error;
|
||||
|
||||
sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
|
||||
if (sh == NULL)
|
||||
goto fail;
|
||||
|
||||
sh->io_port = 0;
|
||||
sh->n_io_port = 0;
|
||||
sh->this_id = -1;
|
||||
sh->max_channel = 3;
|
||||
sh->max_cmd_len = MAX_COMMAND_SIZE;
|
||||
sh->max_lun = HPSA_MAX_LUN;
|
||||
sh->max_id = HPSA_MAX_LUN;
|
||||
sh->can_queue = h->nr_cmds;
|
||||
sh->cmd_per_lun = h->nr_cmds;
|
||||
sh->sg_tablesize = h->maxsgentries;
|
||||
h->scsi_host = sh;
|
||||
sh->hostdata[0] = (unsigned long) h;
|
||||
sh->irq = h->intr[h->intr_mode];
|
||||
sh->unique_id = sh->irq;
|
||||
error = scsi_add_host(sh, &h->pdev->dev);
|
||||
if (error)
|
||||
goto fail_host_put;
|
||||
scsi_scan_host(sh);
|
||||
return 0;
|
||||
|
||||
fail_host_put:
|
||||
dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_add_host"
|
||||
" failed for controller %d\n", h->ctlr);
|
||||
scsi_host_put(sh);
|
||||
return error;
|
||||
fail:
|
||||
dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_host_alloc"
|
||||
" failed for controller %d\n", h->ctlr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void hpsa_pci_unmap(struct pci_dev *pdev,
|
||||
struct CommandList *c, int sg_used, int data_direction)
|
||||
{
|
||||
@ -1641,7 +1650,7 @@ bail_out:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned char *msa2xxx_model[] = {
|
||||
static unsigned char *ext_target_model[] = {
|
||||
"MSA2012",
|
||||
"MSA2024",
|
||||
"MSA2312",
|
||||
@ -1650,78 +1659,54 @@ static unsigned char *msa2xxx_model[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int is_msa2xxx(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
|
||||
static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; msa2xxx_model[i]; i++)
|
||||
if (strncmp(device->model, msa2xxx_model[i],
|
||||
strlen(msa2xxx_model[i])) == 0)
|
||||
for (i = 0; ext_target_model[i]; i++)
|
||||
if (strncmp(device->model, ext_target_model[i],
|
||||
strlen(ext_target_model[i])) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper function to assign bus, target, lun mapping of devices.
|
||||
* Puts non-msa2xxx logical volumes on bus 0, msa2xxx logical
|
||||
* Puts non-external target logical volumes on bus 0, external target logical
|
||||
* volumes on bus 1, physical devices on bus 2. and the hba on bus 3.
|
||||
* Logical drive target and lun are assigned at this time, but
|
||||
* physical device lun and target assignment are deferred (assigned
|
||||
* in hpsa_find_target_lun, called by hpsa_scsi_add_entry.)
|
||||
*/
|
||||
static void figure_bus_target_lun(struct ctlr_info *h,
|
||||
u8 *lunaddrbytes, int *bus, int *target, int *lun,
|
||||
struct hpsa_scsi_dev_t *device)
|
||||
u8 *lunaddrbytes, struct hpsa_scsi_dev_t *device)
|
||||
{
|
||||
u32 lunid;
|
||||
u32 lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
|
||||
|
||||
if (is_logical_dev_addr_mode(lunaddrbytes)) {
|
||||
/* logical device */
|
||||
if (unlikely(is_scsi_rev_5(h))) {
|
||||
/* p1210m, logical drives lun assignments
|
||||
* match SCSI REPORT LUNS data.
|
||||
*/
|
||||
lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
|
||||
*bus = 0;
|
||||
*target = 0;
|
||||
*lun = (lunid & 0x3fff) + 1;
|
||||
} else {
|
||||
/* not p1210m... */
|
||||
lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
|
||||
if (is_msa2xxx(h, device)) {
|
||||
/* msa2xxx way, put logicals on bus 1
|
||||
* and match target/lun numbers box
|
||||
* reports.
|
||||
*/
|
||||
*bus = 1;
|
||||
*target = (lunid >> 16) & 0x3fff;
|
||||
*lun = lunid & 0x00ff;
|
||||
} else {
|
||||
/* Traditional smart array way. */
|
||||
*bus = 0;
|
||||
*lun = 0;
|
||||
*target = lunid & 0x3fff;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* physical device */
|
||||
if (!is_logical_dev_addr_mode(lunaddrbytes)) {
|
||||
/* physical device, target and lun filled in later */
|
||||
if (is_hba_lunid(lunaddrbytes))
|
||||
if (unlikely(is_scsi_rev_5(h))) {
|
||||
*bus = 0; /* put p1210m ctlr at 0,0,0 */
|
||||
*target = 0;
|
||||
*lun = 0;
|
||||
return;
|
||||
} else
|
||||
*bus = 3; /* traditional smartarray */
|
||||
hpsa_set_bus_target_lun(device, 3, 0, lunid & 0x3fff);
|
||||
else
|
||||
*bus = 2; /* physical disk */
|
||||
*target = -1;
|
||||
*lun = -1; /* we will fill these in later. */
|
||||
/* defer target, lun assignment for physical devices */
|
||||
hpsa_set_bus_target_lun(device, 2, -1, -1);
|
||||
return;
|
||||
}
|
||||
/* It's a logical device */
|
||||
if (is_ext_target(h, device)) {
|
||||
/* external target way, put logicals on bus 1
|
||||
* and match target/lun numbers box
|
||||
* reports, other smart array, bus 0, target 0, match lunid
|
||||
*/
|
||||
hpsa_set_bus_target_lun(device,
|
||||
1, (lunid >> 16) & 0x3fff, lunid & 0x00ff);
|
||||
return;
|
||||
}
|
||||
hpsa_set_bus_target_lun(device, 0, 0, lunid & 0x3fff);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is no lun 0 on a target, linux won't find any devices.
|
||||
* For the MSA2xxx boxes, we have to manually detect the enclosure
|
||||
* For the external targets (arrays), we have to manually detect the enclosure
|
||||
* which is at lun zero, as CCISS_REPORT_PHYSICAL_LUNS doesn't report
|
||||
* it for some reason. *tmpdevice is the target we're adding,
|
||||
* this_device is a pointer into the current element of currentsd[]
|
||||
@ -1730,46 +1715,46 @@ static void figure_bus_target_lun(struct ctlr_info *h,
|
||||
* lun 0 assigned.
|
||||
* Returns 1 if an enclosure was added, 0 if not.
|
||||
*/
|
||||
static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
|
||||
static int add_ext_target_dev(struct ctlr_info *h,
|
||||
struct hpsa_scsi_dev_t *tmpdevice,
|
||||
struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes,
|
||||
int bus, int target, int lun, unsigned long lunzerobits[],
|
||||
int *nmsa2xxx_enclosures)
|
||||
unsigned long lunzerobits[], int *n_ext_target_devs)
|
||||
{
|
||||
unsigned char scsi3addr[8];
|
||||
|
||||
if (test_bit(target, lunzerobits))
|
||||
if (test_bit(tmpdevice->target, lunzerobits))
|
||||
return 0; /* There is already a lun 0 on this target. */
|
||||
|
||||
if (!is_logical_dev_addr_mode(lunaddrbytes))
|
||||
return 0; /* It's the logical targets that may lack lun 0. */
|
||||
|
||||
if (!is_msa2xxx(h, tmpdevice))
|
||||
return 0; /* It's only the MSA2xxx that have this problem. */
|
||||
if (!is_ext_target(h, tmpdevice))
|
||||
return 0; /* Only external target devices have this problem. */
|
||||
|
||||
if (lun == 0) /* if lun is 0, then obviously we have a lun 0. */
|
||||
if (tmpdevice->lun == 0) /* if lun is 0, then we have a lun 0. */
|
||||
return 0;
|
||||
|
||||
memset(scsi3addr, 0, 8);
|
||||
scsi3addr[3] = target;
|
||||
scsi3addr[3] = tmpdevice->target;
|
||||
if (is_hba_lunid(scsi3addr))
|
||||
return 0; /* Don't add the RAID controller here. */
|
||||
|
||||
if (is_scsi_rev_5(h))
|
||||
return 0; /* p1210m doesn't need to do this. */
|
||||
|
||||
if (*nmsa2xxx_enclosures >= MAX_MSA2XXX_ENCLOSURES) {
|
||||
dev_warn(&h->pdev->dev, "Maximum number of MSA2XXX "
|
||||
"enclosures exceeded. Check your hardware "
|
||||
if (*n_ext_target_devs >= MAX_EXT_TARGETS) {
|
||||
dev_warn(&h->pdev->dev, "Maximum number of external "
|
||||
"target devices exceeded. Check your hardware "
|
||||
"configuration.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hpsa_update_device_info(h, scsi3addr, this_device, NULL))
|
||||
return 0;
|
||||
(*nmsa2xxx_enclosures)++;
|
||||
hpsa_set_bus_target_lun(this_device, bus, target, 0);
|
||||
set_bit(target, lunzerobits);
|
||||
(*n_ext_target_devs)++;
|
||||
hpsa_set_bus_target_lun(this_device,
|
||||
tmpdevice->bus, tmpdevice->target, 0);
|
||||
set_bit(tmpdevice->target, lunzerobits);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1863,10 +1848,9 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
|
||||
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
|
||||
int ncurrent = 0;
|
||||
int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8;
|
||||
int i, nmsa2xxx_enclosures, ndevs_to_allocate;
|
||||
int bus, target, lun;
|
||||
int i, n_ext_target_devs, ndevs_to_allocate;
|
||||
int raid_ctlr_position;
|
||||
DECLARE_BITMAP(lunzerobits, HPSA_MAX_TARGETS_PER_CTLR);
|
||||
DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
|
||||
|
||||
currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL);
|
||||
physdev_list = kzalloc(reportlunsize, GFP_KERNEL);
|
||||
@ -1883,11 +1867,11 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
|
||||
logdev_list, &nlogicals))
|
||||
goto out;
|
||||
|
||||
/* We might see up to 32 MSA2xxx enclosures, actually 8 of them
|
||||
* but each of them 4 times through different paths. The plus 1
|
||||
* is for the RAID controller.
|
||||
/* We might see up to the maximum number of logical and physical disks
|
||||
* plus external target devices, and a device for the local RAID
|
||||
* controller.
|
||||
*/
|
||||
ndevs_to_allocate = nphysicals + nlogicals + MAX_MSA2XXX_ENCLOSURES + 1;
|
||||
ndevs_to_allocate = nphysicals + nlogicals + MAX_EXT_TARGETS + 1;
|
||||
|
||||
/* Allocate the per device structures */
|
||||
for (i = 0; i < ndevs_to_allocate; i++) {
|
||||
@ -1913,7 +1897,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
|
||||
raid_ctlr_position = nphysicals + nlogicals;
|
||||
|
||||
/* adjust our table of devices */
|
||||
nmsa2xxx_enclosures = 0;
|
||||
n_ext_target_devs = 0;
|
||||
for (i = 0; i < nphysicals + nlogicals + 1; i++) {
|
||||
u8 *lunaddrbytes, is_OBDR = 0;
|
||||
|
||||
@ -1929,26 +1913,24 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
|
||||
if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
|
||||
&is_OBDR))
|
||||
continue; /* skip it if we can't talk to it. */
|
||||
figure_bus_target_lun(h, lunaddrbytes, &bus, &target, &lun,
|
||||
tmpdevice);
|
||||
figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
|
||||
this_device = currentsd[ncurrent];
|
||||
|
||||
/*
|
||||
* For the msa2xxx boxes, we have to insert a LUN 0 which
|
||||
* For external target devices, we have to insert a LUN 0 which
|
||||
* doesn't show up in CCISS_REPORT_PHYSICAL data, but there
|
||||
* is nonetheless an enclosure device there. We have to
|
||||
* present that otherwise linux won't find anything if
|
||||
* there is no lun 0.
|
||||
*/
|
||||
if (add_msa2xxx_enclosure_device(h, tmpdevice, this_device,
|
||||
lunaddrbytes, bus, target, lun, lunzerobits,
|
||||
&nmsa2xxx_enclosures)) {
|
||||
if (add_ext_target_dev(h, tmpdevice, this_device,
|
||||
lunaddrbytes, lunzerobits,
|
||||
&n_ext_target_devs)) {
|
||||
ncurrent++;
|
||||
this_device = currentsd[ncurrent];
|
||||
}
|
||||
|
||||
*this_device = *tmpdevice;
|
||||
hpsa_set_bus_target_lun(this_device, bus, target, lun);
|
||||
|
||||
switch (this_device->devtype) {
|
||||
case TYPE_ROM:
|
||||
@ -2228,13 +2210,42 @@ static void hpsa_unregister_scsi(struct ctlr_info *h)
|
||||
|
||||
static int hpsa_register_scsi(struct ctlr_info *h)
|
||||
{
|
||||
int rc;
|
||||
struct Scsi_Host *sh;
|
||||
int error;
|
||||
|
||||
rc = hpsa_scsi_detect(h);
|
||||
if (rc != 0)
|
||||
dev_err(&h->pdev->dev, "hpsa_register_scsi: failed"
|
||||
" hpsa_scsi_detect(), rc is %d\n", rc);
|
||||
return rc;
|
||||
sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
|
||||
if (sh == NULL)
|
||||
goto fail;
|
||||
|
||||
sh->io_port = 0;
|
||||
sh->n_io_port = 0;
|
||||
sh->this_id = -1;
|
||||
sh->max_channel = 3;
|
||||
sh->max_cmd_len = MAX_COMMAND_SIZE;
|
||||
sh->max_lun = HPSA_MAX_LUN;
|
||||
sh->max_id = HPSA_MAX_LUN;
|
||||
sh->can_queue = h->nr_cmds;
|
||||
sh->cmd_per_lun = h->nr_cmds;
|
||||
sh->sg_tablesize = h->maxsgentries;
|
||||
h->scsi_host = sh;
|
||||
sh->hostdata[0] = (unsigned long) h;
|
||||
sh->irq = h->intr[h->intr_mode];
|
||||
sh->unique_id = sh->irq;
|
||||
error = scsi_add_host(sh, &h->pdev->dev);
|
||||
if (error)
|
||||
goto fail_host_put;
|
||||
scsi_scan_host(sh);
|
||||
return 0;
|
||||
|
||||
fail_host_put:
|
||||
dev_err(&h->pdev->dev, "%s: scsi_add_host"
|
||||
" failed for controller %d\n", __func__, h->ctlr);
|
||||
scsi_host_put(sh);
|
||||
return error;
|
||||
fail:
|
||||
dev_err(&h->pdev->dev, "%s: scsi_host_alloc"
|
||||
" failed for controller %d\n", __func__, h->ctlr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int wait_for_device_to_become_ready(struct ctlr_info *h,
|
||||
@ -2700,16 +2711,16 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
status = -EINVAL;
|
||||
goto cleanup1;
|
||||
}
|
||||
if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
|
||||
if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD) {
|
||||
status = -EINVAL;
|
||||
goto cleanup1;
|
||||
}
|
||||
buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
|
||||
buff = kzalloc(SG_ENTRIES_IN_CMD * sizeof(char *), GFP_KERNEL);
|
||||
if (!buff) {
|
||||
status = -ENOMEM;
|
||||
goto cleanup1;
|
||||
}
|
||||
buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL);
|
||||
buff_size = kmalloc(SG_ENTRIES_IN_CMD * sizeof(int), GFP_KERNEL);
|
||||
if (!buff_size) {
|
||||
status = -ENOMEM;
|
||||
goto cleanup1;
|
||||
@ -3354,7 +3365,7 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,
|
||||
static __devinit void init_driver_version(char *driver_version, int len)
|
||||
{
|
||||
memset(driver_version, 0, len);
|
||||
strncpy(driver_version, "hpsa " HPSA_DRIVER_VERSION, len - 1);
|
||||
strncpy(driver_version, HPSA " " HPSA_DRIVER_VERSION, len - 1);
|
||||
}
|
||||
|
||||
static __devinit int write_driver_ver_to_cfgtable(
|
||||
@ -3935,7 +3946,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = pci_request_regions(h->pdev, "hpsa");
|
||||
err = pci_request_regions(h->pdev, HPSA);
|
||||
if (err) {
|
||||
dev_err(&h->pdev->dev,
|
||||
"cannot obtain PCI resources, aborting\n");
|
||||
@ -4253,7 +4264,7 @@ static void start_controller_lockup_detector(struct ctlr_info *h)
|
||||
spin_lock_init(&lockup_detector_lock);
|
||||
hpsa_lockup_detector =
|
||||
kthread_run(detect_controller_lockup_thread,
|
||||
NULL, "hpsa");
|
||||
NULL, HPSA);
|
||||
}
|
||||
if (!hpsa_lockup_detector) {
|
||||
dev_warn(&h->pdev->dev,
|
||||
@ -4325,7 +4336,7 @@ reinit_after_soft_reset:
|
||||
if (rc != 0)
|
||||
goto clean1;
|
||||
|
||||
sprintf(h->devname, "hpsa%d", number_of_controllers);
|
||||
sprintf(h->devname, HPSA "%d", number_of_controllers);
|
||||
h->ctlr = number_of_controllers;
|
||||
number_of_controllers++;
|
||||
|
||||
@ -4482,6 +4493,14 @@ static void hpsa_shutdown(struct pci_dev *pdev)
|
||||
#endif /* CONFIG_PCI_MSI */
|
||||
}
|
||||
|
||||
static void __devexit hpsa_free_device_info(struct ctlr_info *h)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < h->ndevices; i++)
|
||||
kfree(h->dev[i]);
|
||||
}
|
||||
|
||||
static void __devexit hpsa_remove_one(struct pci_dev *pdev)
|
||||
{
|
||||
struct ctlr_info *h;
|
||||
@ -4497,6 +4516,7 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
|
||||
iounmap(h->vaddr);
|
||||
iounmap(h->transtable);
|
||||
iounmap(h->cfgtable);
|
||||
hpsa_free_device_info(h);
|
||||
hpsa_free_sg_chain_blocks(h);
|
||||
pci_free_consistent(h->pdev,
|
||||
h->nr_cmds * sizeof(struct CommandList),
|
||||
@ -4530,7 +4550,7 @@ static int hpsa_resume(__attribute__((unused)) struct pci_dev *pdev)
|
||||
}
|
||||
|
||||
static struct pci_driver hpsa_pci_driver = {
|
||||
.name = "hpsa",
|
||||
.name = HPSA,
|
||||
.probe = hpsa_init_one,
|
||||
.remove = __devexit_p(hpsa_remove_one),
|
||||
.id_table = hpsa_pci_device_id, /* id_table */
|
||||
@ -4592,15 +4612,15 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
|
||||
* Each SG entry requires 16 bytes. The eight registers are programmed
|
||||
* with the number of 16-byte blocks a command of that size requires.
|
||||
* The smallest command possible requires 5 such 16 byte blocks.
|
||||
* the largest command possible requires MAXSGENTRIES + 4 16-byte
|
||||
* the largest command possible requires SG_ENTRIES_IN_CMD + 4 16-byte
|
||||
* blocks. Note, this only extends to the SG entries contained
|
||||
* within the command block, and does not extend to chained blocks
|
||||
* of SG elements. bft[] contains the eight values we write to
|
||||
* the registers. They are not evenly distributed, but have more
|
||||
* sizes for small commands, and fewer sizes for larger commands.
|
||||
*/
|
||||
int bft[8] = {5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4};
|
||||
BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
|
||||
int bft[8] = {5, 6, 8, 10, 12, 20, 28, SG_ENTRIES_IN_CMD + 4};
|
||||
BUILD_BUG_ON(28 > SG_ENTRIES_IN_CMD + 4);
|
||||
/* 5 = 1 s/g entry or 4k
|
||||
* 6 = 2 s/g entry or 8k
|
||||
* 8 = 4 s/g entry or 16k
|
||||
@ -4613,8 +4633,9 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
|
||||
memset(h->reply_pool, 0, h->reply_pool_size);
|
||||
h->reply_pool_head = h->reply_pool;
|
||||
|
||||
bft[7] = h->max_sg_entries + 4;
|
||||
calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable);
|
||||
bft[7] = SG_ENTRIES_IN_CMD + 4;
|
||||
calc_bucket_map(bft, ARRAY_SIZE(bft),
|
||||
SG_ENTRIES_IN_CMD, h->blockFetchTable);
|
||||
for (i = 0; i < 8; i++)
|
||||
writel(bft[i], &h->transtable->BlockFetch[i]);
|
||||
|
||||
@ -4652,14 +4673,13 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
|
||||
return;
|
||||
|
||||
hpsa_get_max_perf_mode_cmds(h);
|
||||
h->max_sg_entries = 32;
|
||||
/* Performant mode ring buffer and supporting data structures */
|
||||
h->reply_pool_size = h->max_commands * sizeof(u64);
|
||||
h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
|
||||
&(h->reply_pool_dhandle));
|
||||
|
||||
/* Need a block fetch table for performant mode */
|
||||
h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
|
||||
h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) *
|
||||
sizeof(u32)), GFP_KERNEL);
|
||||
|
||||
if ((h->reply_pool == NULL)
|
||||
|
@ -58,7 +58,6 @@ struct ctlr_info {
|
||||
unsigned long paddr;
|
||||
int nr_cmds; /* Number of commands allowed on this controller */
|
||||
struct CfgTable __iomem *cfgtable;
|
||||
int max_sg_entries;
|
||||
int interrupts_enabled;
|
||||
int major;
|
||||
int max_commands;
|
||||
@ -317,7 +316,7 @@ static unsigned long SA5_completed(struct ctlr_info *h)
|
||||
dev_dbg(&h->pdev->dev, "Read %lx back from board\n",
|
||||
register_value);
|
||||
else
|
||||
dev_dbg(&h->pdev->dev, "hpsa: FIFO Empty read\n");
|
||||
dev_dbg(&h->pdev->dev, "FIFO Empty read\n");
|
||||
#endif
|
||||
|
||||
return register_value;
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/* general boundary defintions */
|
||||
#define SENSEINFOBYTES 32 /* may vary between hbas */
|
||||
#define MAXSGENTRIES 32
|
||||
#define SG_ENTRIES_IN_CMD 32 /* Max SG entries excluding chain blocks */
|
||||
#define HPSA_SG_CHAIN 0x80000000
|
||||
#define MAXREPLYQS 256
|
||||
|
||||
@ -122,12 +122,11 @@ union u64bit {
|
||||
};
|
||||
|
||||
/* FIXME this is a per controller value (barf!) */
|
||||
#define HPSA_MAX_TARGETS_PER_CTLR 16
|
||||
#define HPSA_MAX_LUN 1024
|
||||
#define HPSA_MAX_PHYS_LUN 1024
|
||||
#define MAX_MSA2XXX_ENCLOSURES 32
|
||||
#define MAX_EXT_TARGETS 32
|
||||
#define HPSA_MAX_DEVICES (HPSA_MAX_PHYS_LUN + HPSA_MAX_LUN + \
|
||||
MAX_MSA2XXX_ENCLOSURES + 1) /* + 1 is for the controller itself */
|
||||
MAX_EXT_TARGETS + 1) /* + 1 is for the controller itself */
|
||||
|
||||
/* SCSI-3 Commands */
|
||||
#pragma pack(1)
|
||||
@ -282,7 +281,7 @@ struct CommandList {
|
||||
struct CommandListHeader Header;
|
||||
struct RequestBlock Request;
|
||||
struct ErrDescriptor ErrDesc;
|
||||
struct SGDescriptor SG[MAXSGENTRIES];
|
||||
struct SGDescriptor SG[SG_ENTRIES_IN_CMD];
|
||||
/* information associated with the command */
|
||||
u32 busaddr; /* physical addr of this record */
|
||||
struct ErrorInfo *err_info; /* pointer to the allocated mem */
|
||||
|
@ -183,7 +183,7 @@ static const struct ipr_chip_t ipr_chip[] = {
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
|
||||
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
|
||||
};
|
||||
|
||||
static int ipr_max_bus_speeds [] = {
|
||||
@ -9191,15 +9191,15 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C3, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C4, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B4, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B1, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C6, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2,
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C8, 0, 0, 0 },
|
||||
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
|
||||
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57CE, 0, 0, 0 },
|
||||
{ }
|
||||
};
|
||||
|
@ -58,7 +58,7 @@
|
||||
#define PCI_DEVICE_ID_IBM_OBSIDIAN_E 0x0339
|
||||
|
||||
#define PCI_DEVICE_ID_IBM_CROC_FPGA_E2 0x033D
|
||||
#define PCI_DEVICE_ID_IBM_CROC_ASIC_E2 0x034A
|
||||
#define PCI_DEVICE_ID_IBM_CROCODILE 0x034A
|
||||
|
||||
#define IPR_SUBS_DEV_ID_2780 0x0264
|
||||
#define IPR_SUBS_DEV_ID_5702 0x0266
|
||||
@ -92,7 +92,7 @@
|
||||
#define IPR_SUBS_DEV_ID_57B1 0x0355
|
||||
|
||||
#define IPR_SUBS_DEV_ID_574D 0x0356
|
||||
#define IPR_SUBS_DEV_ID_575D 0x035D
|
||||
#define IPR_SUBS_DEV_ID_57C8 0x035D
|
||||
|
||||
#define IPR_NAME "ipr"
|
||||
|
||||
|
@ -649,15 +649,13 @@ static void isci_host_start_complete(struct isci_host *ihost, enum sci_status co
|
||||
|
||||
int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time)
|
||||
{
|
||||
struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha;
|
||||
struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
|
||||
struct isci_host *ihost = ha->lldd_ha;
|
||||
|
||||
if (test_bit(IHOST_START_PENDING, &ihost->flags))
|
||||
return 0;
|
||||
|
||||
/* todo: use sas_flush_discovery once it is upstream */
|
||||
scsi_flush_work(shost);
|
||||
|
||||
scsi_flush_work(shost);
|
||||
sas_drain_work(ha);
|
||||
|
||||
dev_dbg(&ihost->pdev->dev,
|
||||
"%s: ihost->status = %d, time = %ld\n",
|
||||
@ -1490,6 +1488,15 @@ sci_controller_set_interrupt_coalescence(struct isci_host *ihost,
|
||||
static void sci_controller_ready_state_enter(struct sci_base_state_machine *sm)
|
||||
{
|
||||
struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
|
||||
u32 val;
|
||||
|
||||
/* enable clock gating for power control of the scu unit */
|
||||
val = readl(&ihost->smu_registers->clock_gating_control);
|
||||
val &= ~(SMU_CGUCR_GEN_BIT(REGCLK_ENABLE) |
|
||||
SMU_CGUCR_GEN_BIT(TXCLK_ENABLE) |
|
||||
SMU_CGUCR_GEN_BIT(XCLK_ENABLE));
|
||||
val |= SMU_CGUCR_GEN_BIT(IDLE_ENABLE);
|
||||
writel(val, &ihost->smu_registers->clock_gating_control);
|
||||
|
||||
/* set the default interrupt coalescence number and timeout value. */
|
||||
sci_controller_set_interrupt_coalescence(ihost, 0, 0);
|
||||
|
@ -187,6 +187,7 @@ struct isci_host {
|
||||
int id; /* unique within a given pci device */
|
||||
struct isci_phy phys[SCI_MAX_PHYS];
|
||||
struct isci_port ports[SCI_MAX_PORTS + 1]; /* includes dummy port */
|
||||
struct asd_sas_port sas_ports[SCI_MAX_PORTS];
|
||||
struct sas_ha_struct sas_ha;
|
||||
|
||||
spinlock_t state_lock;
|
||||
@ -393,24 +394,6 @@ static inline int sci_remote_device_node_count(struct isci_remote_device *idev)
|
||||
#define sci_controller_clear_invalid_phy(controller, phy) \
|
||||
((controller)->invalid_phy_mask &= ~(1 << (phy)->phy_index))
|
||||
|
||||
static inline struct device *sciphy_to_dev(struct isci_phy *iphy)
|
||||
{
|
||||
|
||||
if (!iphy || !iphy->isci_port || !iphy->isci_port->isci_host)
|
||||
return NULL;
|
||||
|
||||
return &iphy->isci_port->isci_host->pdev->dev;
|
||||
}
|
||||
|
||||
static inline struct device *sciport_to_dev(struct isci_port *iport)
|
||||
{
|
||||
|
||||
if (!iport || !iport->isci_host)
|
||||
return NULL;
|
||||
|
||||
return &iport->isci_host->pdev->dev;
|
||||
}
|
||||
|
||||
static inline struct device *scirdev_to_dev(struct isci_remote_device *idev)
|
||||
{
|
||||
if (!idev || !idev->isci_port || !idev->isci_port->isci_host)
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include <linux/efi.h>
|
||||
#include <asm/string.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "host.h"
|
||||
#include "isci.h"
|
||||
#include "task.h"
|
||||
#include "probe_roms.h"
|
||||
@ -154,7 +155,6 @@ static struct scsi_host_template isci_sht = {
|
||||
.queuecommand = sas_queuecommand,
|
||||
.target_alloc = sas_target_alloc,
|
||||
.slave_configure = sas_slave_configure,
|
||||
.slave_destroy = sas_slave_destroy,
|
||||
.scan_finished = isci_host_scan_finished,
|
||||
.scan_start = isci_host_scan_start,
|
||||
.change_queue_depth = sas_change_queue_depth,
|
||||
@ -166,9 +166,6 @@ static struct scsi_host_template isci_sht = {
|
||||
.sg_tablesize = SG_ALL,
|
||||
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.eh_device_reset_handler = sas_eh_device_reset_handler,
|
||||
.eh_bus_reset_handler = isci_bus_reset_handler,
|
||||
.slave_alloc = sas_slave_alloc,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
.shost_attrs = isci_host_attrs,
|
||||
@ -194,6 +191,9 @@ static struct sas_domain_function_template isci_transport_ops = {
|
||||
.lldd_lu_reset = isci_task_lu_reset,
|
||||
.lldd_query_task = isci_task_query_task,
|
||||
|
||||
/* ata recovery called from ata-eh */
|
||||
.lldd_ata_check_ready = isci_ata_check_ready,
|
||||
|
||||
/* Port and Adapter management */
|
||||
.lldd_clear_nexus_port = isci_task_clear_nexus_port,
|
||||
.lldd_clear_nexus_ha = isci_task_clear_nexus_ha,
|
||||
@ -242,18 +242,13 @@ static int isci_register_sas_ha(struct isci_host *isci_host)
|
||||
if (!sas_ports)
|
||||
return -ENOMEM;
|
||||
|
||||
/*----------------- Libsas Initialization Stuff----------------------
|
||||
* Set various fields in the sas_ha struct:
|
||||
*/
|
||||
|
||||
sas_ha->sas_ha_name = DRV_NAME;
|
||||
sas_ha->lldd_module = THIS_MODULE;
|
||||
sas_ha->sas_addr = &isci_host->phys[0].sas_addr[0];
|
||||
|
||||
/* set the array of phy and port structs. */
|
||||
for (i = 0; i < SCI_MAX_PHYS; i++) {
|
||||
sas_phys[i] = &isci_host->phys[i].sas_phy;
|
||||
sas_ports[i] = &isci_host->ports[i].sas_port;
|
||||
sas_ports[i] = &isci_host->sas_ports[i];
|
||||
}
|
||||
|
||||
sas_ha->sas_phy = sas_phys;
|
||||
@ -528,6 +523,13 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
|
||||
goto err_host_alloc;
|
||||
}
|
||||
pci_info->hosts[i] = h;
|
||||
|
||||
/* turn on DIF support */
|
||||
scsi_host_set_prot(h->shost,
|
||||
SHOST_DIF_TYPE1_PROTECTION |
|
||||
SHOST_DIF_TYPE2_PROTECTION |
|
||||
SHOST_DIF_TYPE3_PROTECTION);
|
||||
scsi_host_set_guard(h->shost, SHOST_DIX_GUARD_CRC);
|
||||
}
|
||||
|
||||
err = isci_setup_interrupts(pdev);
|
||||
@ -551,9 +553,9 @@ static void __devexit isci_pci_remove(struct pci_dev *pdev)
|
||||
int i;
|
||||
|
||||
for_each_isci_host(i, ihost, pdev) {
|
||||
wait_for_start(ihost);
|
||||
isci_unregister(ihost);
|
||||
isci_host_deinit(ihost);
|
||||
sci_controller_disable_interrupts(ihost);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,16 @@
|
||||
#include "scu_event_codes.h"
|
||||
#include "probe_roms.h"
|
||||
|
||||
#undef C
|
||||
#define C(a) (#a)
|
||||
static const char *phy_state_name(enum sci_phy_states state)
|
||||
{
|
||||
static const char * const strings[] = PHY_STATES;
|
||||
|
||||
return strings[state];
|
||||
}
|
||||
#undef C
|
||||
|
||||
/* Maximum arbitration wait time in micro-seconds */
|
||||
#define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME (700)
|
||||
|
||||
@ -67,6 +77,19 @@ enum sas_linkrate sci_phy_linkrate(struct isci_phy *iphy)
|
||||
return iphy->max_negotiated_speed;
|
||||
}
|
||||
|
||||
static struct isci_host *phy_to_host(struct isci_phy *iphy)
|
||||
{
|
||||
struct isci_phy *table = iphy - iphy->phy_index;
|
||||
struct isci_host *ihost = container_of(table, typeof(*ihost), phys[0]);
|
||||
|
||||
return ihost;
|
||||
}
|
||||
|
||||
static struct device *sciphy_to_dev(struct isci_phy *iphy)
|
||||
{
|
||||
return &phy_to_host(iphy)->pdev->dev;
|
||||
}
|
||||
|
||||
static enum sci_status
|
||||
sci_phy_transport_layer_initialization(struct isci_phy *iphy,
|
||||
struct scu_transport_layer_registers __iomem *reg)
|
||||
@ -446,8 +469,8 @@ enum sci_status sci_phy_start(struct isci_phy *iphy)
|
||||
enum sci_phy_states state = iphy->sm.current_state_id;
|
||||
|
||||
if (state != SCI_PHY_STOPPED) {
|
||||
dev_dbg(sciphy_to_dev(iphy),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
|
||||
__func__, phy_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -472,8 +495,8 @@ enum sci_status sci_phy_stop(struct isci_phy *iphy)
|
||||
case SCI_PHY_READY:
|
||||
break;
|
||||
default:
|
||||
dev_dbg(sciphy_to_dev(iphy),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
|
||||
__func__, phy_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -486,8 +509,8 @@ enum sci_status sci_phy_reset(struct isci_phy *iphy)
|
||||
enum sci_phy_states state = iphy->sm.current_state_id;
|
||||
|
||||
if (state != SCI_PHY_READY) {
|
||||
dev_dbg(sciphy_to_dev(iphy),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
|
||||
__func__, phy_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -536,8 +559,8 @@ enum sci_status sci_phy_consume_power_handler(struct isci_phy *iphy)
|
||||
return SCI_SUCCESS;
|
||||
}
|
||||
default:
|
||||
dev_dbg(sciphy_to_dev(iphy),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
|
||||
__func__, phy_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -591,6 +614,60 @@ static void sci_phy_complete_link_training(struct isci_phy *iphy,
|
||||
sci_change_state(&iphy->sm, next_state);
|
||||
}
|
||||
|
||||
static const char *phy_event_name(u32 event_code)
|
||||
{
|
||||
switch (scu_get_event_code(event_code)) {
|
||||
case SCU_EVENT_PORT_SELECTOR_DETECTED:
|
||||
return "port selector";
|
||||
case SCU_EVENT_SENT_PORT_SELECTION:
|
||||
return "port selection";
|
||||
case SCU_EVENT_HARD_RESET_TRANSMITTED:
|
||||
return "tx hard reset";
|
||||
case SCU_EVENT_HARD_RESET_RECEIVED:
|
||||
return "rx hard reset";
|
||||
case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
|
||||
return "identify timeout";
|
||||
case SCU_EVENT_LINK_FAILURE:
|
||||
return "link fail";
|
||||
case SCU_EVENT_SATA_SPINUP_HOLD:
|
||||
return "sata spinup hold";
|
||||
case SCU_EVENT_SAS_15_SSC:
|
||||
case SCU_EVENT_SAS_15:
|
||||
return "sas 1.5";
|
||||
case SCU_EVENT_SAS_30_SSC:
|
||||
case SCU_EVENT_SAS_30:
|
||||
return "sas 3.0";
|
||||
case SCU_EVENT_SAS_60_SSC:
|
||||
case SCU_EVENT_SAS_60:
|
||||
return "sas 6.0";
|
||||
case SCU_EVENT_SATA_15_SSC:
|
||||
case SCU_EVENT_SATA_15:
|
||||
return "sata 1.5";
|
||||
case SCU_EVENT_SATA_30_SSC:
|
||||
case SCU_EVENT_SATA_30:
|
||||
return "sata 3.0";
|
||||
case SCU_EVENT_SATA_60_SSC:
|
||||
case SCU_EVENT_SATA_60:
|
||||
return "sata 6.0";
|
||||
case SCU_EVENT_SAS_PHY_DETECTED:
|
||||
return "sas detect";
|
||||
case SCU_EVENT_SATA_PHY_DETECTED:
|
||||
return "sata detect";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#define phy_event_dbg(iphy, state, code) \
|
||||
dev_dbg(sciphy_to_dev(iphy), "phy-%d:%d: %s event: %s (%x)\n", \
|
||||
phy_to_host(iphy)->id, iphy->phy_index, \
|
||||
phy_state_name(state), phy_event_name(code), code)
|
||||
|
||||
#define phy_event_warn(iphy, state, code) \
|
||||
dev_warn(sciphy_to_dev(iphy), "phy-%d:%d: %s event: %s (%x)\n", \
|
||||
phy_to_host(iphy)->id, iphy->phy_index, \
|
||||
phy_state_name(state), phy_event_name(code), code)
|
||||
|
||||
enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
{
|
||||
enum sci_phy_states state = iphy->sm.current_state_id;
|
||||
@ -607,11 +684,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
iphy->is_in_link_training = true;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(sciphy_to_dev(iphy),
|
||||
"%s: PHY starting substate machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__,
|
||||
event_code);
|
||||
phy_event_dbg(iphy, state, event_code);
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
return SCI_SUCCESS;
|
||||
@ -648,11 +721,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
|
||||
break;
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%s: PHY starting substate machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__, event_code);
|
||||
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE;
|
||||
break;
|
||||
}
|
||||
@ -677,10 +746,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
|
||||
break;
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%s: PHY starting substate machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__, event_code);
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
return SCI_SUCCESS;
|
||||
@ -691,11 +757,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
|
||||
break;
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%s: PHY starting substate machine received unexpected "
|
||||
"event_code %x\n",
|
||||
__func__,
|
||||
event_code);
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
return SCI_SUCCESS;
|
||||
@ -719,11 +781,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%s: PHY starting substate machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__, event_code);
|
||||
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
return SCI_SUCCESS;
|
||||
@ -751,12 +809,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
sci_phy_start_sas_link_training(iphy);
|
||||
break;
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%s: PHY starting substate machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__,
|
||||
event_code);
|
||||
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
return SCI_SUCCESS;
|
||||
@ -793,11 +846,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
sci_phy_start_sas_link_training(iphy);
|
||||
break;
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%s: PHY starting substate machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__, event_code);
|
||||
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
|
||||
@ -815,12 +864,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%s: PHY starting substate machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__,
|
||||
event_code);
|
||||
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
return SCI_SUCCESS;
|
||||
@ -838,10 +882,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
iphy->bcn_received_while_port_unassigned = true;
|
||||
break;
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%sP SCIC PHY 0x%p ready state machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__, iphy, event_code);
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
return SCI_SUCCESS;
|
||||
@ -852,18 +893,14 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
|
||||
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
|
||||
break;
|
||||
default:
|
||||
dev_warn(sciphy_to_dev(iphy),
|
||||
"%s: SCIC PHY 0x%p resetting state machine received "
|
||||
"unexpected event_code %x\n",
|
||||
__func__, iphy, event_code);
|
||||
|
||||
phy_event_warn(iphy, state, event_code);
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
break;
|
||||
}
|
||||
return SCI_SUCCESS;
|
||||
default:
|
||||
dev_dbg(sciphy_to_dev(iphy),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
|
||||
__func__, phy_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -956,8 +993,8 @@ enum sci_status sci_phy_frame_handler(struct isci_phy *iphy, u32 frame_index)
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
dev_dbg(sciphy_to_dev(iphy),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
|
||||
__func__, phy_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -1299,7 +1336,6 @@ void isci_phy_init(struct isci_phy *iphy, struct isci_host *ihost, int index)
|
||||
sas_addr = cpu_to_be64(sci_sas_addr);
|
||||
memcpy(iphy->sas_addr, &sas_addr, sizeof(sas_addr));
|
||||
|
||||
iphy->isci_port = NULL;
|
||||
iphy->sas_phy.enabled = 0;
|
||||
iphy->sas_phy.id = index;
|
||||
iphy->sas_phy.sas_addr = &iphy->sas_addr[0];
|
||||
@ -1333,13 +1369,13 @@ int isci_phy_control(struct asd_sas_phy *sas_phy,
|
||||
{
|
||||
int ret = 0;
|
||||
struct isci_phy *iphy = sas_phy->lldd_phy;
|
||||
struct isci_port *iport = iphy->isci_port;
|
||||
struct asd_sas_port *port = sas_phy->port;
|
||||
struct isci_host *ihost = sas_phy->ha->lldd_ha;
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(&ihost->pdev->dev,
|
||||
"%s: phy %p; func %d; buf %p; isci phy %p, port %p\n",
|
||||
__func__, sas_phy, func, buf, iphy, iport);
|
||||
__func__, sas_phy, func, buf, iphy, port);
|
||||
|
||||
switch (func) {
|
||||
case PHY_FUNC_DISABLE:
|
||||
@ -1356,11 +1392,10 @@ int isci_phy_control(struct asd_sas_phy *sas_phy,
|
||||
break;
|
||||
|
||||
case PHY_FUNC_HARD_RESET:
|
||||
if (!iport)
|
||||
if (!port)
|
||||
return -ENODEV;
|
||||
|
||||
/* Perform the port reset. */
|
||||
ret = isci_port_perform_hard_reset(ihost, iport, iphy);
|
||||
ret = isci_port_perform_hard_reset(ihost, port->lldd_port, iphy);
|
||||
|
||||
break;
|
||||
case PHY_FUNC_GET_EVENTS: {
|
||||
|
@ -103,7 +103,6 @@ struct isci_phy {
|
||||
struct scu_transport_layer_registers __iomem *transport_layer_registers;
|
||||
struct scu_link_layer_registers __iomem *link_layer_registers;
|
||||
struct asd_sas_phy sas_phy;
|
||||
struct isci_port *isci_port;
|
||||
u8 sas_addr[SAS_ADDR_SIZE];
|
||||
union {
|
||||
struct sas_identify_frame iaf;
|
||||
@ -344,101 +343,65 @@ enum sci_phy_counter_id {
|
||||
SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR
|
||||
};
|
||||
|
||||
enum sci_phy_states {
|
||||
/**
|
||||
* Simply the initial state for the base domain state machine.
|
||||
*/
|
||||
SCI_PHY_INITIAL,
|
||||
|
||||
/**
|
||||
* This state indicates that the phy has successfully been stopped.
|
||||
* In this state no new IO operations are permitted on this phy.
|
||||
* This state is entered from the INITIAL state.
|
||||
* This state is entered from the STARTING state.
|
||||
* This state is entered from the READY state.
|
||||
* This state is entered from the RESETTING state.
|
||||
*/
|
||||
SCI_PHY_STOPPED,
|
||||
|
||||
/**
|
||||
* This state indicates that the phy is in the process of becomming
|
||||
* ready. In this state no new IO operations are permitted on this phy.
|
||||
* This state is entered from the STOPPED state.
|
||||
* This state is entered from the READY state.
|
||||
* This state is entered from the RESETTING state.
|
||||
*/
|
||||
SCI_PHY_STARTING,
|
||||
|
||||
/**
|
||||
* Initial state
|
||||
*/
|
||||
SCI_PHY_SUB_INITIAL,
|
||||
|
||||
/**
|
||||
* Wait state for the hardware OSSP event type notification
|
||||
*/
|
||||
SCI_PHY_SUB_AWAIT_OSSP_EN,
|
||||
|
||||
/**
|
||||
* Wait state for the PHY speed notification
|
||||
*/
|
||||
SCI_PHY_SUB_AWAIT_SAS_SPEED_EN,
|
||||
|
||||
/**
|
||||
* Wait state for the IAF Unsolicited frame notification
|
||||
*/
|
||||
SCI_PHY_SUB_AWAIT_IAF_UF,
|
||||
|
||||
/**
|
||||
* Wait state for the request to consume power
|
||||
*/
|
||||
SCI_PHY_SUB_AWAIT_SAS_POWER,
|
||||
|
||||
/**
|
||||
* Wait state for request to consume power
|
||||
*/
|
||||
SCI_PHY_SUB_AWAIT_SATA_POWER,
|
||||
|
||||
/**
|
||||
* Wait state for the SATA PHY notification
|
||||
*/
|
||||
SCI_PHY_SUB_AWAIT_SATA_PHY_EN,
|
||||
|
||||
/**
|
||||
* Wait for the SATA PHY speed notification
|
||||
*/
|
||||
SCI_PHY_SUB_AWAIT_SATA_SPEED_EN,
|
||||
|
||||
/**
|
||||
* Wait state for the SIGNATURE FIS unsolicited frame notification
|
||||
*/
|
||||
SCI_PHY_SUB_AWAIT_SIG_FIS_UF,
|
||||
|
||||
/**
|
||||
* Exit state for this state machine
|
||||
*/
|
||||
SCI_PHY_SUB_FINAL,
|
||||
|
||||
/**
|
||||
* This state indicates the the phy is now ready. Thus, the user
|
||||
* is able to perform IO operations utilizing this phy as long as it
|
||||
* is currently part of a valid port.
|
||||
* This state is entered from the STARTING state.
|
||||
*/
|
||||
SCI_PHY_READY,
|
||||
|
||||
/**
|
||||
* This state indicates that the phy is in the process of being reset.
|
||||
* In this state no new IO operations are permitted on this phy.
|
||||
* This state is entered from the READY state.
|
||||
*/
|
||||
SCI_PHY_RESETTING,
|
||||
|
||||
/**
|
||||
* Simply the final state for the base phy state machine.
|
||||
*/
|
||||
SCI_PHY_FINAL,
|
||||
};
|
||||
/**
|
||||
* enum sci_phy_states - phy state machine states
|
||||
* @SCI_PHY_INITIAL: Simply the initial state for the base domain state
|
||||
* machine.
|
||||
* @SCI_PHY_STOPPED: phy has successfully been stopped. In this state
|
||||
* no new IO operations are permitted on this phy.
|
||||
* @SCI_PHY_STARTING: the phy is in the process of becomming ready. In
|
||||
* this state no new IO operations are permitted on
|
||||
* this phy.
|
||||
* @SCI_PHY_SUB_INITIAL: Initial state
|
||||
* @SCI_PHY_SUB_AWAIT_OSSP_EN: Wait state for the hardware OSSP event
|
||||
* type notification
|
||||
* @SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: Wait state for the PHY speed
|
||||
* notification
|
||||
* @SCI_PHY_SUB_AWAIT_IAF_UF: Wait state for the IAF Unsolicited frame
|
||||
* notification
|
||||
* @SCI_PHY_SUB_AWAIT_SAS_POWER: Wait state for the request to consume
|
||||
* power
|
||||
* @SCI_PHY_SUB_AWAIT_SATA_POWER: Wait state for request to consume
|
||||
* power
|
||||
* @SCI_PHY_SUB_AWAIT_SATA_PHY_EN: Wait state for the SATA PHY
|
||||
* notification
|
||||
* @SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: Wait for the SATA PHY speed
|
||||
* notification
|
||||
* @SCI_PHY_SUB_AWAIT_SIG_FIS_UF: Wait state for the SIGNATURE FIS
|
||||
* unsolicited frame notification
|
||||
* @SCI_PHY_SUB_FINAL: Exit state for this state machine
|
||||
* @SCI_PHY_READY: phy is now ready. Thus, the user is able to perform
|
||||
* IO operations utilizing this phy as long as it is
|
||||
* currently part of a valid port. This state is
|
||||
* entered from the STARTING state.
|
||||
* @SCI_PHY_RESETTING: phy is in the process of being reset. In this
|
||||
* state no new IO operations are permitted on this
|
||||
* phy. This state is entered from the READY state.
|
||||
* @SCI_PHY_FINAL: Simply the final state for the base phy state
|
||||
* machine.
|
||||
*/
|
||||
#define PHY_STATES {\
|
||||
C(PHY_INITIAL),\
|
||||
C(PHY_STOPPED),\
|
||||
C(PHY_STARTING),\
|
||||
C(PHY_SUB_INITIAL),\
|
||||
C(PHY_SUB_AWAIT_OSSP_EN),\
|
||||
C(PHY_SUB_AWAIT_SAS_SPEED_EN),\
|
||||
C(PHY_SUB_AWAIT_IAF_UF),\
|
||||
C(PHY_SUB_AWAIT_SAS_POWER),\
|
||||
C(PHY_SUB_AWAIT_SATA_POWER),\
|
||||
C(PHY_SUB_AWAIT_SATA_PHY_EN),\
|
||||
C(PHY_SUB_AWAIT_SATA_SPEED_EN),\
|
||||
C(PHY_SUB_AWAIT_SIG_FIS_UF),\
|
||||
C(PHY_SUB_FINAL),\
|
||||
C(PHY_READY),\
|
||||
C(PHY_RESETTING),\
|
||||
C(PHY_FINAL),\
|
||||
}
|
||||
#undef C
|
||||
#define C(a) SCI_##a
|
||||
enum sci_phy_states PHY_STATES;
|
||||
#undef C
|
||||
|
||||
void sci_phy_construct(
|
||||
struct isci_phy *iphy,
|
||||
|
@ -60,18 +60,29 @@
|
||||
#define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000)
|
||||
#define SCU_DUMMY_INDEX (0xFFFF)
|
||||
|
||||
static void isci_port_change_state(struct isci_port *iport, enum isci_status status)
|
||||
#undef C
|
||||
#define C(a) (#a)
|
||||
const char *port_state_name(enum sci_port_states state)
|
||||
{
|
||||
unsigned long flags;
|
||||
static const char * const strings[] = PORT_STATES;
|
||||
|
||||
dev_dbg(&iport->isci_host->pdev->dev,
|
||||
"%s: iport = %p, state = 0x%x\n",
|
||||
__func__, iport, status);
|
||||
return strings[state];
|
||||
}
|
||||
#undef C
|
||||
|
||||
/* XXX pointless lock */
|
||||
spin_lock_irqsave(&iport->state_lock, flags);
|
||||
iport->status = status;
|
||||
spin_unlock_irqrestore(&iport->state_lock, flags);
|
||||
static struct device *sciport_to_dev(struct isci_port *iport)
|
||||
{
|
||||
int i = iport->physical_port_index;
|
||||
struct isci_port *table;
|
||||
struct isci_host *ihost;
|
||||
|
||||
if (i == SCIC_SDS_DUMMY_PORT)
|
||||
i = SCI_MAX_PORTS+1;
|
||||
|
||||
table = iport - i;
|
||||
ihost = container_of(table, typeof(*ihost), ports[0]);
|
||||
|
||||
return &ihost->pdev->dev;
|
||||
}
|
||||
|
||||
static void sci_port_get_protocols(struct isci_port *iport, struct sci_phy_proto *proto)
|
||||
@ -165,18 +176,12 @@ static void isci_port_link_up(struct isci_host *isci_host,
|
||||
struct sci_port_properties properties;
|
||||
unsigned long success = true;
|
||||
|
||||
BUG_ON(iphy->isci_port != NULL);
|
||||
|
||||
iphy->isci_port = iport;
|
||||
|
||||
dev_dbg(&isci_host->pdev->dev,
|
||||
"%s: isci_port = %p\n",
|
||||
__func__, iport);
|
||||
|
||||
spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags);
|
||||
|
||||
isci_port_change_state(iphy->isci_port, isci_starting);
|
||||
|
||||
sci_port_get_properties(iport, &properties);
|
||||
|
||||
if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) {
|
||||
@ -258,7 +263,6 @@ static void isci_port_link_down(struct isci_host *isci_host,
|
||||
__func__, isci_device);
|
||||
set_bit(IDEV_GONE, &isci_device->flags);
|
||||
}
|
||||
isci_port_change_state(isci_port, isci_stopping);
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,52 +273,10 @@ static void isci_port_link_down(struct isci_host *isci_host,
|
||||
isci_host->sas_ha.notify_phy_event(&isci_phy->sas_phy,
|
||||
PHYE_LOSS_OF_SIGNAL);
|
||||
|
||||
isci_phy->isci_port = NULL;
|
||||
|
||||
dev_dbg(&isci_host->pdev->dev,
|
||||
"%s: isci_port = %p - Done\n", __func__, isci_port);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* isci_port_ready() - This function is called by the sci core when a link
|
||||
* becomes ready.
|
||||
* @isci_host: This parameter specifies the isci host object.
|
||||
* @port: This parameter specifies the sci port with the active link.
|
||||
*
|
||||
*/
|
||||
static void isci_port_ready(struct isci_host *isci_host, struct isci_port *isci_port)
|
||||
{
|
||||
dev_dbg(&isci_host->pdev->dev,
|
||||
"%s: isci_port = %p\n", __func__, isci_port);
|
||||
|
||||
complete_all(&isci_port->start_complete);
|
||||
isci_port_change_state(isci_port, isci_ready);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* isci_port_not_ready() - This function is called by the sci core when a link
|
||||
* is not ready. All remote devices on this link will be removed if they are
|
||||
* in the stopping state.
|
||||
* @isci_host: This parameter specifies the isci host object.
|
||||
* @port: This parameter specifies the sci port with the active link.
|
||||
*
|
||||
*/
|
||||
static void isci_port_not_ready(struct isci_host *isci_host, struct isci_port *isci_port)
|
||||
{
|
||||
dev_dbg(&isci_host->pdev->dev,
|
||||
"%s: isci_port = %p\n", __func__, isci_port);
|
||||
}
|
||||
|
||||
static void isci_port_stop_complete(struct isci_host *ihost,
|
||||
struct isci_port *iport,
|
||||
enum sci_status completion_status)
|
||||
{
|
||||
dev_dbg(&ihost->pdev->dev, "Port stop complete\n");
|
||||
}
|
||||
|
||||
|
||||
static bool is_port_ready_state(enum sci_port_states state)
|
||||
{
|
||||
switch (state) {
|
||||
@ -353,7 +315,9 @@ static void port_state_machine_change(struct isci_port *iport,
|
||||
static void isci_port_hard_reset_complete(struct isci_port *isci_port,
|
||||
enum sci_status completion_status)
|
||||
{
|
||||
dev_dbg(&isci_port->isci_host->pdev->dev,
|
||||
struct isci_host *ihost = isci_port->owning_controller;
|
||||
|
||||
dev_dbg(&ihost->pdev->dev,
|
||||
"%s: isci_port = %p, completion_status=%x\n",
|
||||
__func__, isci_port, completion_status);
|
||||
|
||||
@ -364,23 +328,24 @@ static void isci_port_hard_reset_complete(struct isci_port *isci_port,
|
||||
|
||||
/* The reset failed. The port state is now SCI_PORT_FAILED. */
|
||||
if (isci_port->active_phy_mask == 0) {
|
||||
int phy_idx = isci_port->last_active_phy;
|
||||
struct isci_phy *iphy = &ihost->phys[phy_idx];
|
||||
|
||||
/* Generate the link down now to the host, since it
|
||||
* was intercepted by the hard reset state machine when
|
||||
* it really happened.
|
||||
*/
|
||||
isci_port_link_down(isci_port->isci_host,
|
||||
&isci_port->isci_host->phys[
|
||||
isci_port->last_active_phy],
|
||||
isci_port);
|
||||
isci_port_link_down(ihost, iphy, isci_port);
|
||||
}
|
||||
/* Advance the port state so that link state changes will be
|
||||
* noticed.
|
||||
*/
|
||||
* noticed.
|
||||
*/
|
||||
port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING);
|
||||
|
||||
}
|
||||
complete_all(&isci_port->hard_reset_complete);
|
||||
clear_bit(IPORT_RESET_PENDING, &isci_port->state);
|
||||
wake_up(&ihost->eventq);
|
||||
|
||||
}
|
||||
|
||||
/* This method will return a true value if the specified phy can be assigned to
|
||||
@ -835,10 +800,9 @@ static void port_timeout(unsigned long data)
|
||||
__func__,
|
||||
iport);
|
||||
} else if (current_state == SCI_PORT_STOPPING) {
|
||||
/* if the port is still stopping then the stop has not completed */
|
||||
isci_port_stop_complete(iport->owning_controller,
|
||||
iport,
|
||||
SCI_FAILURE_TIMEOUT);
|
||||
dev_dbg(sciport_to_dev(iport),
|
||||
"%s: port%d: stop complete timeout\n",
|
||||
__func__, iport->physical_port_index);
|
||||
} else {
|
||||
/* The port is in the ready state and we have a timer
|
||||
* reporting a timeout this should not happen.
|
||||
@ -1003,7 +967,8 @@ static void sci_port_ready_substate_operational_enter(struct sci_base_state_mach
|
||||
struct isci_port *iport = container_of(sm, typeof(*iport), sm);
|
||||
struct isci_host *ihost = iport->owning_controller;
|
||||
|
||||
isci_port_ready(ihost, iport);
|
||||
dev_dbg(&ihost->pdev->dev, "%s: port%d ready\n",
|
||||
__func__, iport->physical_port_index);
|
||||
|
||||
for (index = 0; index < SCI_MAX_PHYS; index++) {
|
||||
if (iport->phy_table[index]) {
|
||||
@ -1069,7 +1034,8 @@ static void sci_port_ready_substate_operational_exit(struct sci_base_state_machi
|
||||
*/
|
||||
sci_port_abort_dummy_request(iport);
|
||||
|
||||
isci_port_not_ready(ihost, iport);
|
||||
dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n",
|
||||
__func__, iport->physical_port_index);
|
||||
|
||||
if (iport->ready_exit)
|
||||
sci_port_invalidate_dummy_remote_node(iport);
|
||||
@ -1081,7 +1047,8 @@ static void sci_port_ready_substate_configuring_enter(struct sci_base_state_mach
|
||||
struct isci_host *ihost = iport->owning_controller;
|
||||
|
||||
if (iport->active_phy_mask == 0) {
|
||||
isci_port_not_ready(ihost, iport);
|
||||
dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n",
|
||||
__func__, iport->physical_port_index);
|
||||
|
||||
port_state_machine_change(iport, SCI_PORT_SUB_WAITING);
|
||||
} else
|
||||
@ -1097,8 +1064,8 @@ enum sci_status sci_port_start(struct isci_port *iport)
|
||||
|
||||
state = iport->sm.current_state_id;
|
||||
if (state != SCI_PORT_STOPPED) {
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -1172,8 +1139,8 @@ enum sci_status sci_port_stop(struct isci_port *iport)
|
||||
SCI_PORT_STOPPING);
|
||||
return SCI_SUCCESS;
|
||||
default:
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -1187,8 +1154,8 @@ static enum sci_status sci_port_hard_reset(struct isci_port *iport, u32 timeout)
|
||||
|
||||
state = iport->sm.current_state_id;
|
||||
if (state != SCI_PORT_SUB_OPERATIONAL) {
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -1282,8 +1249,8 @@ enum sci_status sci_port_add_phy(struct isci_port *iport,
|
||||
SCI_PORT_SUB_CONFIGURING);
|
||||
return SCI_SUCCESS;
|
||||
default:
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -1332,8 +1299,8 @@ enum sci_status sci_port_remove_phy(struct isci_port *iport,
|
||||
SCI_PORT_SUB_CONFIGURING);
|
||||
return SCI_SUCCESS;
|
||||
default:
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -1375,8 +1342,8 @@ enum sci_status sci_port_link_up(struct isci_port *iport,
|
||||
sci_port_general_link_up_handler(iport, iphy, PF_RESUME);
|
||||
return SCI_SUCCESS;
|
||||
default:
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -1405,8 +1372,8 @@ enum sci_status sci_port_link_down(struct isci_port *iport,
|
||||
sci_port_deactivate_phy(iport, iphy, false);
|
||||
return SCI_SUCCESS;
|
||||
default:
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -1425,8 +1392,8 @@ enum sci_status sci_port_start_io(struct isci_port *iport,
|
||||
iport->started_request_count++;
|
||||
return SCI_SUCCESS;
|
||||
default:
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -1440,8 +1407,8 @@ enum sci_status sci_port_complete_io(struct isci_port *iport,
|
||||
state = iport->sm.current_state_id;
|
||||
switch (state) {
|
||||
case SCI_PORT_STOPPED:
|
||||
dev_warn(sciport_to_dev(iport),
|
||||
"%s: in wrong state: %d\n", __func__, state);
|
||||
dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n",
|
||||
__func__, port_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
case SCI_PORT_STOPPING:
|
||||
sci_port_decrement_request_count(iport);
|
||||
@ -1547,7 +1514,8 @@ static void sci_port_ready_state_enter(struct sci_base_state_machine *sm)
|
||||
if (prev_state == SCI_PORT_RESETTING)
|
||||
isci_port_hard_reset_complete(iport, SCI_SUCCESS);
|
||||
else
|
||||
isci_port_not_ready(ihost, iport);
|
||||
dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n",
|
||||
__func__, iport->physical_port_index);
|
||||
|
||||
/* Post and suspend the dummy remote node context for this port. */
|
||||
sci_port_post_dummy_remote_node(iport);
|
||||
@ -1644,22 +1612,7 @@ void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index)
|
||||
{
|
||||
INIT_LIST_HEAD(&iport->remote_dev_list);
|
||||
INIT_LIST_HEAD(&iport->domain_dev_list);
|
||||
spin_lock_init(&iport->state_lock);
|
||||
init_completion(&iport->start_complete);
|
||||
iport->isci_host = ihost;
|
||||
isci_port_change_state(iport, isci_freed);
|
||||
}
|
||||
|
||||
/**
|
||||
* isci_port_get_state() - This function gets the status of the port object.
|
||||
* @isci_port: This parameter points to the isci_port object
|
||||
*
|
||||
* status of the object as a isci_status enum.
|
||||
*/
|
||||
enum isci_status isci_port_get_state(
|
||||
struct isci_port *isci_port)
|
||||
{
|
||||
return isci_port->status;
|
||||
}
|
||||
|
||||
void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy)
|
||||
@ -1670,6 +1623,11 @@ void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy
|
||||
isci_port_bc_change_received(ihost, iport, iphy);
|
||||
}
|
||||
|
||||
static void wait_port_reset(struct isci_host *ihost, struct isci_port *iport)
|
||||
{
|
||||
wait_event(ihost->eventq, !test_bit(IPORT_RESET_PENDING, &iport->state));
|
||||
}
|
||||
|
||||
int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport,
|
||||
struct isci_phy *iphy)
|
||||
{
|
||||
@ -1680,9 +1638,8 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
|
||||
dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n",
|
||||
__func__, iport);
|
||||
|
||||
init_completion(&iport->hard_reset_complete);
|
||||
|
||||
spin_lock_irqsave(&ihost->scic_lock, flags);
|
||||
set_bit(IPORT_RESET_PENDING, &iport->state);
|
||||
|
||||
#define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT
|
||||
status = sci_port_hard_reset(iport, ISCI_PORT_RESET_TIMEOUT);
|
||||
@ -1690,7 +1647,7 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
|
||||
if (status == SCI_SUCCESS) {
|
||||
wait_for_completion(&iport->hard_reset_complete);
|
||||
wait_port_reset(ihost, iport);
|
||||
|
||||
dev_dbg(&ihost->pdev->dev,
|
||||
"%s: iport = %p; hard reset completion\n",
|
||||
@ -1704,6 +1661,8 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
|
||||
__func__, iport, iport->hard_reset_status);
|
||||
}
|
||||
} else {
|
||||
clear_bit(IPORT_RESET_PENDING, &iport->state);
|
||||
wake_up(&ihost->eventq);
|
||||
ret = TMF_RESP_FUNC_FAILED;
|
||||
|
||||
dev_err(&ihost->pdev->dev,
|
||||
@ -1726,24 +1685,80 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* isci_port_deformed() - This function is called by libsas when a port becomes
|
||||
* inactive.
|
||||
* @phy: This parameter specifies the libsas phy with the inactive port.
|
||||
*
|
||||
*/
|
||||
void isci_port_deformed(struct asd_sas_phy *phy)
|
||||
int isci_ata_check_ready(struct domain_device *dev)
|
||||
{
|
||||
pr_debug("%s: sas_phy = %p\n", __func__, phy);
|
||||
struct isci_port *iport = dev->port->lldd_port;
|
||||
struct isci_host *ihost = dev_to_ihost(dev);
|
||||
struct isci_remote_device *idev;
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
spin_lock_irqsave(&ihost->scic_lock, flags);
|
||||
idev = isci_lookup_device(dev);
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
|
||||
if (!idev)
|
||||
goto out;
|
||||
|
||||
if (test_bit(IPORT_RESET_PENDING, &iport->state))
|
||||
goto out;
|
||||
|
||||
rc = !!iport->active_phy_mask;
|
||||
out:
|
||||
isci_put_device(idev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void isci_port_deformed(struct asd_sas_phy *phy)
|
||||
{
|
||||
struct isci_host *ihost = phy->ha->lldd_ha;
|
||||
struct isci_port *iport = phy->port->lldd_port;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
/* we got a port notification on a port that was subsequently
|
||||
* torn down and libsas is just now catching up
|
||||
*/
|
||||
if (!iport)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ihost->scic_lock, flags);
|
||||
for (i = 0; i < SCI_MAX_PHYS; i++) {
|
||||
if (iport->active_phy_mask & 1 << i)
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
|
||||
if (i >= SCI_MAX_PHYS)
|
||||
dev_dbg(&ihost->pdev->dev, "%s: port: %ld\n",
|
||||
__func__, (long) (iport - &ihost->ports[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* isci_port_formed() - This function is called by libsas when a port becomes
|
||||
* active.
|
||||
* @phy: This parameter specifies the libsas phy with the active port.
|
||||
*
|
||||
*/
|
||||
void isci_port_formed(struct asd_sas_phy *phy)
|
||||
{
|
||||
pr_debug("%s: sas_phy = %p, sas_port = %p\n", __func__, phy, phy->port);
|
||||
struct isci_host *ihost = phy->ha->lldd_ha;
|
||||
struct isci_phy *iphy = to_iphy(phy);
|
||||
struct asd_sas_port *port = phy->port;
|
||||
struct isci_port *iport;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
/* initial ports are formed as the driver is still initializing,
|
||||
* wait for that process to complete
|
||||
*/
|
||||
wait_for_start(ihost);
|
||||
|
||||
spin_lock_irqsave(&ihost->scic_lock, flags);
|
||||
for (i = 0; i < SCI_MAX_PORTS; i++) {
|
||||
iport = &ihost->ports[i];
|
||||
if (iport->active_phy_mask & 1 << iphy->phy_index)
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
|
||||
if (i >= SCI_MAX_PORTS)
|
||||
iport = NULL;
|
||||
|
||||
port->lldd_port = iport;
|
||||
}
|
||||
|
@ -95,14 +95,11 @@ enum isci_status {
|
||||
* @timer: timeout start/stop operations
|
||||
*/
|
||||
struct isci_port {
|
||||
enum isci_status status;
|
||||
struct isci_host *isci_host;
|
||||
struct asd_sas_port sas_port;
|
||||
struct list_head remote_dev_list;
|
||||
spinlock_t state_lock;
|
||||
struct list_head domain_dev_list;
|
||||
struct completion start_complete;
|
||||
struct completion hard_reset_complete;
|
||||
#define IPORT_RESET_PENDING 0
|
||||
unsigned long state;
|
||||
enum sci_status hard_reset_status;
|
||||
struct sci_base_state_machine sm;
|
||||
bool ready_exit;
|
||||
@ -147,70 +144,47 @@ struct sci_port_properties {
|
||||
};
|
||||
|
||||
/**
|
||||
* enum sci_port_states - This enumeration depicts all the states for the
|
||||
* common port state machine.
|
||||
*
|
||||
*
|
||||
* enum sci_port_states - port state machine states
|
||||
* @SCI_PORT_STOPPED: port has successfully been stopped. In this state
|
||||
* no new IO operations are permitted. This state is
|
||||
* entered from the STOPPING state.
|
||||
* @SCI_PORT_STOPPING: port is in the process of stopping. In this
|
||||
* state no new IO operations are permitted, but
|
||||
* existing IO operations are allowed to complete.
|
||||
* This state is entered from the READY state.
|
||||
* @SCI_PORT_READY: port is now ready. Thus, the user is able to
|
||||
* perform IO operations on this port. This state is
|
||||
* entered from the STARTING state.
|
||||
* @SCI_PORT_SUB_WAITING: port is started and ready but has no active
|
||||
* phys.
|
||||
* @SCI_PORT_SUB_OPERATIONAL: port is started and ready and there is at
|
||||
* least one phy operational.
|
||||
* @SCI_PORT_SUB_CONFIGURING: port is started and there was an
|
||||
* add/remove phy event. This state is only
|
||||
* used in Automatic Port Configuration Mode
|
||||
* (APC)
|
||||
* @SCI_PORT_RESETTING: port is in the process of performing a hard
|
||||
* reset. Thus, the user is unable to perform IO
|
||||
* operations on this port. This state is entered
|
||||
* from the READY state.
|
||||
* @SCI_PORT_FAILED: port has failed a reset request. This state is
|
||||
* entered when a port reset request times out. This
|
||||
* state is entered from the RESETTING state.
|
||||
*/
|
||||
enum sci_port_states {
|
||||
/**
|
||||
* This state indicates that the port has successfully been stopped.
|
||||
* In this state no new IO operations are permitted.
|
||||
* This state is entered from the STOPPING state.
|
||||
*/
|
||||
SCI_PORT_STOPPED,
|
||||
|
||||
/**
|
||||
* This state indicates that the port is in the process of stopping.
|
||||
* In this state no new IO operations are permitted, but existing IO
|
||||
* operations are allowed to complete.
|
||||
* This state is entered from the READY state.
|
||||
*/
|
||||
SCI_PORT_STOPPING,
|
||||
|
||||
/**
|
||||
* This state indicates the port is now ready. Thus, the user is
|
||||
* able to perform IO operations on this port.
|
||||
* This state is entered from the STARTING state.
|
||||
*/
|
||||
SCI_PORT_READY,
|
||||
|
||||
/**
|
||||
* The substate where the port is started and ready but has no
|
||||
* active phys.
|
||||
*/
|
||||
SCI_PORT_SUB_WAITING,
|
||||
|
||||
/**
|
||||
* The substate where the port is started and ready and there is
|
||||
* at least one phy operational.
|
||||
*/
|
||||
SCI_PORT_SUB_OPERATIONAL,
|
||||
|
||||
/**
|
||||
* The substate where the port is started and there was an
|
||||
* add/remove phy event. This state is only used in Automatic
|
||||
* Port Configuration Mode (APC)
|
||||
*/
|
||||
SCI_PORT_SUB_CONFIGURING,
|
||||
|
||||
/**
|
||||
* This state indicates the port is in the process of performing a hard
|
||||
* reset. Thus, the user is unable to perform IO operations on this
|
||||
* port.
|
||||
* This state is entered from the READY state.
|
||||
*/
|
||||
SCI_PORT_RESETTING,
|
||||
|
||||
/**
|
||||
* This state indicates the port has failed a reset request. This state
|
||||
* is entered when a port reset request times out.
|
||||
* This state is entered from the RESETTING state.
|
||||
*/
|
||||
SCI_PORT_FAILED,
|
||||
|
||||
|
||||
};
|
||||
#define PORT_STATES {\
|
||||
C(PORT_STOPPED),\
|
||||
C(PORT_STOPPING),\
|
||||
C(PORT_READY),\
|
||||
C(PORT_SUB_WAITING),\
|
||||
C(PORT_SUB_OPERATIONAL),\
|
||||
C(PORT_SUB_CONFIGURING),\
|
||||
C(PORT_RESETTING),\
|
||||
C(PORT_FAILED),\
|
||||
}
|
||||
#undef C
|
||||
#define C(a) SCI_##a
|
||||
enum sci_port_states PORT_STATES;
|
||||
#undef C
|
||||
|
||||
static inline void sci_port_decrement_request_count(struct isci_port *iport)
|
||||
{
|
||||
@ -296,9 +270,6 @@ void sci_port_get_attached_sas_address(
|
||||
struct isci_port *iport,
|
||||
struct sci_sas_address *sas_address);
|
||||
|
||||
enum isci_status isci_port_get_state(
|
||||
struct isci_port *isci_port);
|
||||
|
||||
void isci_port_formed(struct asd_sas_phy *);
|
||||
void isci_port_deformed(struct asd_sas_phy *);
|
||||
|
||||
@ -309,4 +280,5 @@ void isci_port_init(
|
||||
|
||||
int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport,
|
||||
struct isci_phy *iphy);
|
||||
int isci_ata_check_ready(struct domain_device *dev);
|
||||
#endif /* !defined(_ISCI_PORT_H_) */
|
||||
|
@ -370,6 +370,27 @@ struct scu_iit_entry {
|
||||
>> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT \
|
||||
)
|
||||
|
||||
/* ***************************************************************************** */
|
||||
#define SMU_CLOCK_GATING_CONTROL_IDLE_ENABLE_SHIFT (0)
|
||||
#define SMU_CLOCK_GATING_CONTROL_IDLE_ENABLE_MASK (0x00000001)
|
||||
#define SMU_CLOCK_GATING_CONTROL_XCLK_ENABLE_SHIFT (1)
|
||||
#define SMU_CLOCK_GATING_CONTROL_XCLK_ENABLE_MASK (0x00000002)
|
||||
#define SMU_CLOCK_GATING_CONTROL_TXCLK_ENABLE_SHIFT (2)
|
||||
#define SMU_CLOCK_GATING_CONTROL_TXCLK_ENABLE_MASK (0x00000004)
|
||||
#define SMU_CLOCK_GATING_CONTROL_REGCLK_ENABLE_SHIFT (3)
|
||||
#define SMU_CLOCK_GATING_CONTROL_REGCLK_ENABLE_MASK (0x00000008)
|
||||
#define SMU_CLOCK_GATING_CONTROL_IDLE_TIMEOUT_SHIFT (16)
|
||||
#define SMU_CLOCK_GATING_CONTROL_IDLE_TIMEOUT_MASK (0x000F0000)
|
||||
#define SMU_CLOCK_GATING_CONTROL_FORCE_IDLE_SHIFT (31)
|
||||
#define SMU_CLOCK_GATING_CONTROL_FORCE_IDLE_MASK (0x80000000)
|
||||
#define SMU_CLOCK_GATING_CONTROL_RESERVED_MASK (0x7FF0FFF0)
|
||||
|
||||
#define SMU_CGUCR_GEN_VAL(name, value) \
|
||||
SCU_GEN_VALUE(SMU_CLOCK_GATING_CONTROL_##name, value)
|
||||
|
||||
#define SMU_CGUCR_GEN_BIT(name) \
|
||||
SCU_GEN_BIT(SMU_CLOCK_GATING_CONTROL_##name)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define SMU_CONTROL_STATUS_TASK_CONTEXT_RANGE_ENABLE_SHIFT (0)
|
||||
@ -992,8 +1013,10 @@ struct smu_registers {
|
||||
u32 mmr_address_window;
|
||||
/* 0x00A4 SMDW */
|
||||
u32 mmr_data_window;
|
||||
u32 reserved_A8;
|
||||
u32 reserved_AC;
|
||||
/* 0x00A8 CGUCR */
|
||||
u32 clock_gating_control;
|
||||
/* 0x00AC CGUPC */
|
||||
u32 clock_gating_performance;
|
||||
/* A whole bunch of reserved space */
|
||||
u32 reserved_Bx[4];
|
||||
u32 reserved_Cx[4];
|
||||
|
@ -62,6 +62,16 @@
|
||||
#include "scu_event_codes.h"
|
||||
#include "task.h"
|
||||
|
||||
#undef C
|
||||
#define C(a) (#a)
|
||||
const char *dev_state_name(enum sci_remote_device_states state)
|
||||
{
|
||||
static const char * const strings[] = REMOTE_DEV_STATES;
|
||||
|
||||
return strings[state];
|
||||
}
|
||||
#undef C
|
||||
|
||||
/**
|
||||
* isci_remote_device_not_ready() - This function is called by the ihost when
|
||||
* the remote device is not ready. We mark the isci device as ready (not
|
||||
@ -167,8 +177,8 @@ enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
|
||||
case SCI_DEV_FAILED:
|
||||
case SCI_DEV_FINAL:
|
||||
default:
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
case SCI_DEV_STOPPED:
|
||||
return SCI_SUCCESS;
|
||||
@ -226,8 +236,8 @@ enum sci_status sci_remote_device_reset(struct isci_remote_device *idev)
|
||||
case SCI_DEV_RESETTING:
|
||||
case SCI_DEV_FINAL:
|
||||
default:
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
case SCI_DEV_READY:
|
||||
case SCI_STP_DEV_IDLE:
|
||||
@ -246,8 +256,8 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev
|
||||
enum sci_remote_device_states state = sm->current_state_id;
|
||||
|
||||
if (state != SCI_DEV_RESETTING) {
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -262,8 +272,8 @@ enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
|
||||
enum sci_remote_device_states state = sm->current_state_id;
|
||||
|
||||
if (state != SCI_STP_DEV_CMD) {
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -287,8 +297,8 @@ enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev,
|
||||
case SCI_SMP_DEV_IDLE:
|
||||
case SCI_DEV_FINAL:
|
||||
default:
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
/* Return the frame back to the controller */
|
||||
sci_controller_release_frame(ihost, frame_index);
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
@ -502,8 +512,8 @@ enum sci_status sci_remote_device_start_io(struct isci_host *ihost,
|
||||
case SCI_DEV_RESETTING:
|
||||
case SCI_DEV_FINAL:
|
||||
default:
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
case SCI_DEV_READY:
|
||||
/* attempt to start an io request for this device object. The remote
|
||||
@ -637,8 +647,8 @@ enum sci_status sci_remote_device_complete_io(struct isci_host *ihost,
|
||||
case SCI_DEV_FAILED:
|
||||
case SCI_DEV_FINAL:
|
||||
default:
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
case SCI_DEV_READY:
|
||||
case SCI_STP_DEV_AWAIT_RESET:
|
||||
@ -721,8 +731,8 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
|
||||
case SCI_DEV_RESETTING:
|
||||
case SCI_DEV_FINAL:
|
||||
default:
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
case SCI_STP_DEV_IDLE:
|
||||
case SCI_STP_DEV_CMD:
|
||||
@ -853,8 +863,8 @@ static enum sci_status sci_remote_device_destruct(struct isci_remote_device *ide
|
||||
struct isci_host *ihost;
|
||||
|
||||
if (state != SCI_DEV_STOPPED) {
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -1204,8 +1214,8 @@ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev,
|
||||
enum sci_status status;
|
||||
|
||||
if (state != SCI_DEV_STOPPED) {
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %d\n",
|
||||
__func__, state);
|
||||
dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
|
||||
__func__, dev_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
|
||||
@ -1308,7 +1318,6 @@ void isci_remote_device_release(struct kref *kref)
|
||||
clear_bit(IDEV_STOP_PENDING, &idev->flags);
|
||||
clear_bit(IDEV_IO_READY, &idev->flags);
|
||||
clear_bit(IDEV_GONE, &idev->flags);
|
||||
clear_bit(IDEV_EH, &idev->flags);
|
||||
smp_mb__before_clear_bit();
|
||||
clear_bit(IDEV_ALLOCATED, &idev->flags);
|
||||
wake_up(&ihost->eventq);
|
||||
@ -1381,34 +1390,17 @@ void isci_remote_device_gone(struct domain_device *dev)
|
||||
*
|
||||
* status, zero indicates success.
|
||||
*/
|
||||
int isci_remote_device_found(struct domain_device *domain_dev)
|
||||
int isci_remote_device_found(struct domain_device *dev)
|
||||
{
|
||||
struct isci_host *isci_host = dev_to_ihost(domain_dev);
|
||||
struct isci_port *isci_port;
|
||||
struct isci_phy *isci_phy;
|
||||
struct asd_sas_port *sas_port;
|
||||
struct asd_sas_phy *sas_phy;
|
||||
struct isci_host *isci_host = dev_to_ihost(dev);
|
||||
struct isci_port *isci_port = dev->port->lldd_port;
|
||||
struct isci_remote_device *isci_device;
|
||||
enum sci_status status;
|
||||
|
||||
dev_dbg(&isci_host->pdev->dev,
|
||||
"%s: domain_device = %p\n", __func__, domain_dev);
|
||||
"%s: domain_device = %p\n", __func__, dev);
|
||||
|
||||
wait_for_start(isci_host);
|
||||
|
||||
sas_port = domain_dev->port;
|
||||
sas_phy = list_first_entry(&sas_port->phy_list, struct asd_sas_phy,
|
||||
port_phy_el);
|
||||
isci_phy = to_iphy(sas_phy);
|
||||
isci_port = isci_phy->isci_port;
|
||||
|
||||
/* we are being called for a device on this port,
|
||||
* so it has to come up eventually
|
||||
*/
|
||||
wait_for_completion(&isci_port->start_complete);
|
||||
|
||||
if ((isci_stopping == isci_port_get_state(isci_port)) ||
|
||||
(isci_stopped == isci_port_get_state(isci_port)))
|
||||
if (!isci_port)
|
||||
return -ENODEV;
|
||||
|
||||
isci_device = isci_remote_device_alloc(isci_host, isci_port);
|
||||
@ -1419,7 +1411,7 @@ int isci_remote_device_found(struct domain_device *domain_dev)
|
||||
INIT_LIST_HEAD(&isci_device->node);
|
||||
|
||||
spin_lock_irq(&isci_host->scic_lock);
|
||||
isci_device->domain_dev = domain_dev;
|
||||
isci_device->domain_dev = dev;
|
||||
isci_device->isci_port = isci_port;
|
||||
list_add_tail(&isci_device->node, &isci_port->remote_dev_list);
|
||||
|
||||
@ -1432,7 +1424,7 @@ int isci_remote_device_found(struct domain_device *domain_dev)
|
||||
|
||||
if (status == SCI_SUCCESS) {
|
||||
/* device came up, advertise it to the world */
|
||||
domain_dev->lldd_dev = isci_device;
|
||||
dev->lldd_dev = isci_device;
|
||||
} else
|
||||
isci_put_device(isci_device);
|
||||
spin_unlock_irq(&isci_host->scic_lock);
|
||||
|
@ -82,10 +82,9 @@ struct isci_remote_device {
|
||||
#define IDEV_START_PENDING 0
|
||||
#define IDEV_STOP_PENDING 1
|
||||
#define IDEV_ALLOCATED 2
|
||||
#define IDEV_EH 3
|
||||
#define IDEV_GONE 4
|
||||
#define IDEV_IO_READY 5
|
||||
#define IDEV_IO_NCQERROR 6
|
||||
#define IDEV_GONE 3
|
||||
#define IDEV_IO_READY 4
|
||||
#define IDEV_IO_NCQERROR 5
|
||||
unsigned long flags;
|
||||
struct kref kref;
|
||||
struct isci_port *isci_port;
|
||||
@ -180,122 +179,101 @@ enum sci_status sci_remote_device_reset_complete(
|
||||
/**
|
||||
* enum sci_remote_device_states - This enumeration depicts all the states
|
||||
* for the common remote device state machine.
|
||||
* @SCI_DEV_INITIAL: Simply the initial state for the base remote device
|
||||
* state machine.
|
||||
*
|
||||
* @SCI_DEV_STOPPED: This state indicates that the remote device has
|
||||
* successfully been stopped. In this state no new IO operations are
|
||||
* permitted. This state is entered from the INITIAL state. This state
|
||||
* is entered from the STOPPING state.
|
||||
*
|
||||
* @SCI_DEV_STARTING: This state indicates the the remote device is in
|
||||
* the process of becoming ready (i.e. starting). In this state no new
|
||||
* IO operations are permitted. This state is entered from the STOPPED
|
||||
* state.
|
||||
*
|
||||
* @SCI_DEV_READY: This state indicates the remote device is now ready.
|
||||
* Thus, the user is able to perform IO operations on the remote device.
|
||||
* This state is entered from the STARTING state.
|
||||
*
|
||||
* @SCI_STP_DEV_IDLE: This is the idle substate for the stp remote
|
||||
* device. When there are no active IO for the device it is is in this
|
||||
* state.
|
||||
*
|
||||
* @SCI_STP_DEV_CMD: This is the command state for for the STP remote
|
||||
* device. This state is entered when the device is processing a
|
||||
* non-NCQ command. The device object will fail any new start IO
|
||||
* requests until this command is complete.
|
||||
*
|
||||
* @SCI_STP_DEV_NCQ: This is the NCQ state for the STP remote device.
|
||||
* This state is entered when the device is processing an NCQ reuqest.
|
||||
* It will remain in this state so long as there is one or more NCQ
|
||||
* requests being processed.
|
||||
*
|
||||
* @SCI_STP_DEV_NCQ_ERROR: This is the NCQ error state for the STP
|
||||
* remote device. This state is entered when an SDB error FIS is
|
||||
* received by the device object while in the NCQ state. The device
|
||||
* object will only accept a READ LOG command while in this state.
|
||||
*
|
||||
* @SCI_STP_DEV_ATAPI_ERROR: This is the ATAPI error state for the STP
|
||||
* ATAPI remote device. This state is entered when ATAPI device sends
|
||||
* error status FIS without data while the device object is in CMD
|
||||
* state. A suspension event is expected in this state. The device
|
||||
* object will resume right away.
|
||||
*
|
||||
* @SCI_STP_DEV_AWAIT_RESET: This is the READY substate indicates the
|
||||
* device is waiting for the RESET task coming to be recovered from
|
||||
* certain hardware specific error.
|
||||
*
|
||||
* @SCI_SMP_DEV_IDLE: This is the ready operational substate for the
|
||||
* remote device. This is the normal operational state for a remote
|
||||
* device.
|
||||
*
|
||||
* @SCI_SMP_DEV_CMD: This is the suspended state for the remote device.
|
||||
* This is the state that the device is placed in when a RNC suspend is
|
||||
* received by the SCU hardware.
|
||||
*
|
||||
* @SCI_DEV_STOPPING: This state indicates that the remote device is in
|
||||
* the process of stopping. In this state no new IO operations are
|
||||
* permitted, but existing IO operations are allowed to complete. This
|
||||
* state is entered from the READY state. This state is entered from
|
||||
* the FAILED state.
|
||||
*
|
||||
* @SCI_DEV_FAILED: This state indicates that the remote device has
|
||||
* failed. In this state no new IO operations are permitted. This
|
||||
* state is entered from the INITIALIZING state. This state is entered
|
||||
* from the READY state.
|
||||
*
|
||||
* @SCI_DEV_RESETTING: This state indicates the device is being reset.
|
||||
* In this state no new IO operations are permitted. This state is
|
||||
* entered from the READY state.
|
||||
*
|
||||
* @SCI_DEV_FINAL: Simply the final state for the base remote device
|
||||
* state machine.
|
||||
*/
|
||||
enum sci_remote_device_states {
|
||||
/**
|
||||
* Simply the initial state for the base remote device state machine.
|
||||
*/
|
||||
SCI_DEV_INITIAL,
|
||||
|
||||
/**
|
||||
* This state indicates that the remote device has successfully been
|
||||
* stopped. In this state no new IO operations are permitted.
|
||||
* This state is entered from the INITIAL state.
|
||||
* This state is entered from the STOPPING state.
|
||||
*/
|
||||
SCI_DEV_STOPPED,
|
||||
|
||||
/**
|
||||
* This state indicates the the remote device is in the process of
|
||||
* becoming ready (i.e. starting). In this state no new IO operations
|
||||
* are permitted.
|
||||
* This state is entered from the STOPPED state.
|
||||
*/
|
||||
SCI_DEV_STARTING,
|
||||
|
||||
/**
|
||||
* This state indicates the remote device is now ready. Thus, the user
|
||||
* is able to perform IO operations on the remote device.
|
||||
* This state is entered from the STARTING state.
|
||||
*/
|
||||
SCI_DEV_READY,
|
||||
|
||||
/**
|
||||
* This is the idle substate for the stp remote device. When there are no
|
||||
* active IO for the device it is is in this state.
|
||||
*/
|
||||
SCI_STP_DEV_IDLE,
|
||||
|
||||
/**
|
||||
* This is the command state for for the STP remote device. This state is
|
||||
* entered when the device is processing a non-NCQ command. The device object
|
||||
* will fail any new start IO requests until this command is complete.
|
||||
*/
|
||||
SCI_STP_DEV_CMD,
|
||||
|
||||
/**
|
||||
* This is the NCQ state for the STP remote device. This state is entered
|
||||
* when the device is processing an NCQ reuqest. It will remain in this state
|
||||
* so long as there is one or more NCQ requests being processed.
|
||||
*/
|
||||
SCI_STP_DEV_NCQ,
|
||||
|
||||
/**
|
||||
* This is the NCQ error state for the STP remote device. This state is
|
||||
* entered when an SDB error FIS is received by the device object while in the
|
||||
* NCQ state. The device object will only accept a READ LOG command while in
|
||||
* this state.
|
||||
*/
|
||||
SCI_STP_DEV_NCQ_ERROR,
|
||||
|
||||
/**
|
||||
* This is the ATAPI error state for the STP ATAPI remote device.
|
||||
* This state is entered when ATAPI device sends error status FIS
|
||||
* without data while the device object is in CMD state.
|
||||
* A suspension event is expected in this state.
|
||||
* The device object will resume right away.
|
||||
*/
|
||||
SCI_STP_DEV_ATAPI_ERROR,
|
||||
|
||||
/**
|
||||
* This is the READY substate indicates the device is waiting for the RESET task
|
||||
* coming to be recovered from certain hardware specific error.
|
||||
*/
|
||||
SCI_STP_DEV_AWAIT_RESET,
|
||||
|
||||
/**
|
||||
* This is the ready operational substate for the remote device. This is the
|
||||
* normal operational state for a remote device.
|
||||
*/
|
||||
SCI_SMP_DEV_IDLE,
|
||||
|
||||
/**
|
||||
* This is the suspended state for the remote device. This is the state that
|
||||
* the device is placed in when a RNC suspend is received by the SCU hardware.
|
||||
*/
|
||||
SCI_SMP_DEV_CMD,
|
||||
|
||||
/**
|
||||
* This state indicates that the remote device is in the process of
|
||||
* stopping. In this state no new IO operations are permitted, but
|
||||
* existing IO operations are allowed to complete.
|
||||
* This state is entered from the READY state.
|
||||
* This state is entered from the FAILED state.
|
||||
*/
|
||||
SCI_DEV_STOPPING,
|
||||
|
||||
/**
|
||||
* This state indicates that the remote device has failed.
|
||||
* In this state no new IO operations are permitted.
|
||||
* This state is entered from the INITIALIZING state.
|
||||
* This state is entered from the READY state.
|
||||
*/
|
||||
SCI_DEV_FAILED,
|
||||
|
||||
/**
|
||||
* This state indicates the device is being reset.
|
||||
* In this state no new IO operations are permitted.
|
||||
* This state is entered from the READY state.
|
||||
*/
|
||||
SCI_DEV_RESETTING,
|
||||
|
||||
/**
|
||||
* Simply the final state for the base remote device state machine.
|
||||
*/
|
||||
SCI_DEV_FINAL,
|
||||
};
|
||||
#define REMOTE_DEV_STATES {\
|
||||
C(DEV_INITIAL),\
|
||||
C(DEV_STOPPED),\
|
||||
C(DEV_STARTING),\
|
||||
C(DEV_READY),\
|
||||
C(STP_DEV_IDLE),\
|
||||
C(STP_DEV_CMD),\
|
||||
C(STP_DEV_NCQ),\
|
||||
C(STP_DEV_NCQ_ERROR),\
|
||||
C(STP_DEV_ATAPI_ERROR),\
|
||||
C(STP_DEV_AWAIT_RESET),\
|
||||
C(SMP_DEV_IDLE),\
|
||||
C(SMP_DEV_CMD),\
|
||||
C(DEV_STOPPING),\
|
||||
C(DEV_FAILED),\
|
||||
C(DEV_RESETTING),\
|
||||
C(DEV_FINAL),\
|
||||
}
|
||||
#undef C
|
||||
#define C(a) SCI_##a
|
||||
enum sci_remote_device_states REMOTE_DEV_STATES;
|
||||
#undef C
|
||||
const char *dev_state_name(enum sci_remote_device_states state);
|
||||
|
||||
static inline struct isci_remote_device *rnc_to_dev(struct sci_remote_node_context *rnc)
|
||||
{
|
||||
|
@ -60,18 +60,15 @@
|
||||
#include "scu_event_codes.h"
|
||||
#include "scu_task_context.h"
|
||||
|
||||
#undef C
|
||||
#define C(a) (#a)
|
||||
const char *rnc_state_name(enum scis_sds_remote_node_context_states state)
|
||||
{
|
||||
static const char * const strings[] = RNC_STATES;
|
||||
|
||||
/**
|
||||
*
|
||||
* @sci_rnc: The RNC for which the is posted request is being made.
|
||||
*
|
||||
* This method will return true if the RNC is not in the initial state. In all
|
||||
* other states the RNC is considered active and this will return true. The
|
||||
* destroy request of the state machine drives the RNC back to the initial
|
||||
* state. If the state machine changes then this routine will also have to be
|
||||
* changed. bool true if the state machine is not in the initial state false if
|
||||
* the state machine is in the initial state
|
||||
*/
|
||||
return strings[state];
|
||||
}
|
||||
#undef C
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -85,61 +85,50 @@ struct sci_remote_node_context;
|
||||
typedef void (*scics_sds_remote_node_context_callback)(void *);
|
||||
|
||||
/**
|
||||
* This is the enumeration of the remote node context states.
|
||||
* enum sci_remote_node_context_states
|
||||
* @SCI_RNC_INITIAL initial state for a remote node context. On a resume
|
||||
* request the remote node context will transition to the posting state.
|
||||
*
|
||||
* @SCI_RNC_POSTING: transition state that posts the RNi to the hardware. Once
|
||||
* the RNC is posted the remote node context will be made ready.
|
||||
*
|
||||
* @SCI_RNC_INVALIDATING: transition state that will post an RNC invalidate to
|
||||
* the hardware. Once the invalidate is complete the remote node context will
|
||||
* transition to the posting state.
|
||||
*
|
||||
* @SCI_RNC_RESUMING: transition state that will post an RNC resume to the
|
||||
* hardare. Once the event notification of resume complete is received the
|
||||
* remote node context will transition to the ready state.
|
||||
*
|
||||
* @SCI_RNC_READY: state that the remote node context must be in to accept io
|
||||
* request operations.
|
||||
*
|
||||
* @SCI_RNC_TX_SUSPENDED: state that the remote node context transitions to when
|
||||
* it gets a TX suspend notification from the hardware.
|
||||
*
|
||||
* @SCI_RNC_TX_RX_SUSPENDED: state that the remote node context transitions to
|
||||
* when it gets a TX RX suspend notification from the hardware.
|
||||
*
|
||||
* @SCI_RNC_AWAIT_SUSPENSION: wait state for the remote node context that waits
|
||||
* for a suspend notification from the hardware. This state is entered when
|
||||
* either there is a request to supend the remote node context or when there is
|
||||
* a TC completion where the remote node will be suspended by the hardware.
|
||||
*/
|
||||
enum scis_sds_remote_node_context_states {
|
||||
/**
|
||||
* This state is the initial state for a remote node context. On a resume
|
||||
* request the remote node context will transition to the posting state.
|
||||
*/
|
||||
SCI_RNC_INITIAL,
|
||||
|
||||
/**
|
||||
* This is a transition state that posts the RNi to the hardware. Once the RNC
|
||||
* is posted the remote node context will be made ready.
|
||||
*/
|
||||
SCI_RNC_POSTING,
|
||||
|
||||
/**
|
||||
* This is a transition state that will post an RNC invalidate to the
|
||||
* hardware. Once the invalidate is complete the remote node context will
|
||||
* transition to the posting state.
|
||||
*/
|
||||
SCI_RNC_INVALIDATING,
|
||||
|
||||
/**
|
||||
* This is a transition state that will post an RNC resume to the hardare.
|
||||
* Once the event notification of resume complete is received the remote node
|
||||
* context will transition to the ready state.
|
||||
*/
|
||||
SCI_RNC_RESUMING,
|
||||
|
||||
/**
|
||||
* This is the state that the remote node context must be in to accept io
|
||||
* request operations.
|
||||
*/
|
||||
SCI_RNC_READY,
|
||||
|
||||
/**
|
||||
* This is the state that the remote node context transitions to when it gets
|
||||
* a TX suspend notification from the hardware.
|
||||
*/
|
||||
SCI_RNC_TX_SUSPENDED,
|
||||
|
||||
/**
|
||||
* This is the state that the remote node context transitions to when it gets
|
||||
* a TX RX suspend notification from the hardware.
|
||||
*/
|
||||
SCI_RNC_TX_RX_SUSPENDED,
|
||||
|
||||
/**
|
||||
* This state is a wait state for the remote node context that waits for a
|
||||
* suspend notification from the hardware. This state is entered when either
|
||||
* there is a request to supend the remote node context or when there is a TC
|
||||
* completion where the remote node will be suspended by the hardware.
|
||||
*/
|
||||
SCI_RNC_AWAIT_SUSPENSION
|
||||
};
|
||||
#define RNC_STATES {\
|
||||
C(RNC_INITIAL),\
|
||||
C(RNC_POSTING),\
|
||||
C(RNC_INVALIDATING),\
|
||||
C(RNC_RESUMING),\
|
||||
C(RNC_READY),\
|
||||
C(RNC_TX_SUSPENDED),\
|
||||
C(RNC_TX_RX_SUSPENDED),\
|
||||
C(RNC_AWAIT_SUSPENSION),\
|
||||
}
|
||||
#undef C
|
||||
#define C(a) SCI_##a
|
||||
enum scis_sds_remote_node_context_states RNC_STATES;
|
||||
#undef C
|
||||
const char *rnc_state_name(enum scis_sds_remote_node_context_states state);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -53,6 +53,7 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include "isci.h"
|
||||
#include "task.h"
|
||||
#include "request.h"
|
||||
@ -60,6 +61,16 @@
|
||||
#include "scu_event_codes.h"
|
||||
#include "sas.h"
|
||||
|
||||
#undef C
|
||||
#define C(a) (#a)
|
||||
const char *req_state_name(enum sci_base_request_states state)
|
||||
{
|
||||
static const char * const strings[] = REQUEST_STATES;
|
||||
|
||||
return strings[state];
|
||||
}
|
||||
#undef C
|
||||
|
||||
static struct scu_sgl_element_pair *to_sgl_element_pair(struct isci_request *ireq,
|
||||
int idx)
|
||||
{
|
||||
@ -264,6 +275,141 @@ static void scu_ssp_reqeust_construct_task_context(
|
||||
task_context->response_iu_lower = lower_32_bits(dma_addr);
|
||||
}
|
||||
|
||||
static u8 scu_bg_blk_size(struct scsi_device *sdp)
|
||||
{
|
||||
switch (sdp->sector_size) {
|
||||
case 512:
|
||||
return 0;
|
||||
case 1024:
|
||||
return 1;
|
||||
case 4096:
|
||||
return 3;
|
||||
default:
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 scu_dif_bytes(u32 len, u32 sector_size)
|
||||
{
|
||||
return (len >> ilog2(sector_size)) * 8;
|
||||
}
|
||||
|
||||
static void scu_ssp_ireq_dif_insert(struct isci_request *ireq, u8 type, u8 op)
|
||||
{
|
||||
struct scu_task_context *tc = ireq->tc;
|
||||
struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
|
||||
u8 blk_sz = scu_bg_blk_size(scmd->device);
|
||||
|
||||
tc->block_guard_enable = 1;
|
||||
tc->blk_prot_en = 1;
|
||||
tc->blk_sz = blk_sz;
|
||||
/* DIF write insert */
|
||||
tc->blk_prot_func = 0x2;
|
||||
|
||||
tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
|
||||
scmd->device->sector_size);
|
||||
|
||||
/* always init to 0, used by hw */
|
||||
tc->interm_crc_val = 0;
|
||||
|
||||
tc->init_crc_seed = 0;
|
||||
tc->app_tag_verify = 0;
|
||||
tc->app_tag_gen = 0;
|
||||
tc->ref_tag_seed_verify = 0;
|
||||
|
||||
/* always init to same as bg_blk_sz */
|
||||
tc->UD_bytes_immed_val = scmd->device->sector_size;
|
||||
|
||||
tc->reserved_DC_0 = 0;
|
||||
|
||||
/* always init to 8 */
|
||||
tc->DIF_bytes_immed_val = 8;
|
||||
|
||||
tc->reserved_DC_1 = 0;
|
||||
tc->bgc_blk_sz = scmd->device->sector_size;
|
||||
tc->reserved_E0_0 = 0;
|
||||
tc->app_tag_gen_mask = 0;
|
||||
|
||||
/** setup block guard control **/
|
||||
tc->bgctl = 0;
|
||||
|
||||
/* DIF write insert */
|
||||
tc->bgctl_f.op = 0x2;
|
||||
|
||||
tc->app_tag_verify_mask = 0;
|
||||
|
||||
/* must init to 0 for hw */
|
||||
tc->blk_guard_err = 0;
|
||||
|
||||
tc->reserved_E8_0 = 0;
|
||||
|
||||
if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
|
||||
tc->ref_tag_seed_gen = scsi_get_lba(scmd) & 0xffffffff;
|
||||
else if (type & SCSI_PROT_DIF_TYPE3)
|
||||
tc->ref_tag_seed_gen = 0;
|
||||
}
|
||||
|
||||
static void scu_ssp_ireq_dif_strip(struct isci_request *ireq, u8 type, u8 op)
|
||||
{
|
||||
struct scu_task_context *tc = ireq->tc;
|
||||
struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
|
||||
u8 blk_sz = scu_bg_blk_size(scmd->device);
|
||||
|
||||
tc->block_guard_enable = 1;
|
||||
tc->blk_prot_en = 1;
|
||||
tc->blk_sz = blk_sz;
|
||||
/* DIF read strip */
|
||||
tc->blk_prot_func = 0x1;
|
||||
|
||||
tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
|
||||
scmd->device->sector_size);
|
||||
|
||||
/* always init to 0, used by hw */
|
||||
tc->interm_crc_val = 0;
|
||||
|
||||
tc->init_crc_seed = 0;
|
||||
tc->app_tag_verify = 0;
|
||||
tc->app_tag_gen = 0;
|
||||
|
||||
if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
|
||||
tc->ref_tag_seed_verify = scsi_get_lba(scmd) & 0xffffffff;
|
||||
else if (type & SCSI_PROT_DIF_TYPE3)
|
||||
tc->ref_tag_seed_verify = 0;
|
||||
|
||||
/* always init to same as bg_blk_sz */
|
||||
tc->UD_bytes_immed_val = scmd->device->sector_size;
|
||||
|
||||
tc->reserved_DC_0 = 0;
|
||||
|
||||
/* always init to 8 */
|
||||
tc->DIF_bytes_immed_val = 8;
|
||||
|
||||
tc->reserved_DC_1 = 0;
|
||||
tc->bgc_blk_sz = scmd->device->sector_size;
|
||||
tc->reserved_E0_0 = 0;
|
||||
tc->app_tag_gen_mask = 0;
|
||||
|
||||
/** setup block guard control **/
|
||||
tc->bgctl = 0;
|
||||
|
||||
/* DIF read strip */
|
||||
tc->bgctl_f.crc_verify = 1;
|
||||
tc->bgctl_f.op = 0x1;
|
||||
if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) {
|
||||
tc->bgctl_f.ref_tag_chk = 1;
|
||||
tc->bgctl_f.app_f_detect = 1;
|
||||
} else if (type & SCSI_PROT_DIF_TYPE3)
|
||||
tc->bgctl_f.app_ref_f_detect = 1;
|
||||
|
||||
tc->app_tag_verify_mask = 0;
|
||||
|
||||
/* must init to 0 for hw */
|
||||
tc->blk_guard_err = 0;
|
||||
|
||||
tc->reserved_E8_0 = 0;
|
||||
tc->ref_tag_seed_gen = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is will fill in the SCU Task Context for a SSP IO request.
|
||||
* @sci_req:
|
||||
@ -274,6 +420,10 @@ static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
|
||||
u32 len)
|
||||
{
|
||||
struct scu_task_context *task_context = ireq->tc;
|
||||
struct sas_task *sas_task = ireq->ttype_ptr.io_task_ptr;
|
||||
struct scsi_cmnd *scmd = sas_task->uldd_task;
|
||||
u8 prot_type = scsi_get_prot_type(scmd);
|
||||
u8 prot_op = scsi_get_prot_op(scmd);
|
||||
|
||||
scu_ssp_reqeust_construct_task_context(ireq, task_context);
|
||||
|
||||
@ -296,6 +446,13 @@ static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
|
||||
|
||||
if (task_context->transfer_length_bytes > 0)
|
||||
sci_request_build_sgl(ireq);
|
||||
|
||||
if (prot_type != SCSI_PROT_DIF_TYPE0) {
|
||||
if (prot_op == SCSI_PROT_READ_STRIP)
|
||||
scu_ssp_ireq_dif_strip(ireq, prot_type, prot_op);
|
||||
else if (prot_op == SCSI_PROT_WRITE_INSERT)
|
||||
scu_ssp_ireq_dif_insert(ireq, prot_type, prot_op);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -519,18 +676,12 @@ sci_io_request_construct_sata(struct isci_request *ireq,
|
||||
if (test_bit(IREQ_TMF, &ireq->flags)) {
|
||||
struct isci_tmf *tmf = isci_request_access_tmf(ireq);
|
||||
|
||||
if (tmf->tmf_code == isci_tmf_sata_srst_high ||
|
||||
tmf->tmf_code == isci_tmf_sata_srst_low) {
|
||||
scu_stp_raw_request_construct_task_context(ireq);
|
||||
return SCI_SUCCESS;
|
||||
} else {
|
||||
dev_err(&ireq->owning_controller->pdev->dev,
|
||||
"%s: Request 0x%p received un-handled SAT "
|
||||
"management protocol 0x%x.\n",
|
||||
__func__, ireq, tmf->tmf_code);
|
||||
dev_err(&ireq->owning_controller->pdev->dev,
|
||||
"%s: Request 0x%p received un-handled SAT "
|
||||
"management protocol 0x%x.\n",
|
||||
__func__, ireq, tmf->tmf_code);
|
||||
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
|
||||
if (!sas_protocol_ata(task->task_proto)) {
|
||||
@ -627,34 +778,6 @@ static enum sci_status sci_io_request_construct_basic_sata(struct isci_request *
|
||||
return status;
|
||||
}
|
||||
|
||||
enum sci_status sci_task_request_construct_sata(struct isci_request *ireq)
|
||||
{
|
||||
enum sci_status status = SCI_SUCCESS;
|
||||
|
||||
/* check for management protocols */
|
||||
if (test_bit(IREQ_TMF, &ireq->flags)) {
|
||||
struct isci_tmf *tmf = isci_request_access_tmf(ireq);
|
||||
|
||||
if (tmf->tmf_code == isci_tmf_sata_srst_high ||
|
||||
tmf->tmf_code == isci_tmf_sata_srst_low) {
|
||||
scu_stp_raw_request_construct_task_context(ireq);
|
||||
} else {
|
||||
dev_err(&ireq->owning_controller->pdev->dev,
|
||||
"%s: Request 0x%p received un-handled SAT "
|
||||
"Protocol 0x%x.\n",
|
||||
__func__, ireq, tmf->tmf_code);
|
||||
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != SCI_SUCCESS)
|
||||
return status;
|
||||
sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* sci_req_tx_bytes - bytes transferred when reply underruns request
|
||||
* @ireq: request that was terminated early
|
||||
@ -756,9 +879,6 @@ sci_io_request_terminate(struct isci_request *ireq)
|
||||
case SCI_REQ_STP_PIO_WAIT_FRAME:
|
||||
case SCI_REQ_STP_PIO_DATA_IN:
|
||||
case SCI_REQ_STP_PIO_DATA_OUT:
|
||||
case SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED:
|
||||
case SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG:
|
||||
case SCI_REQ_STP_SOFT_RESET_WAIT_D2H:
|
||||
case SCI_REQ_ATAPI_WAIT_H2D:
|
||||
case SCI_REQ_ATAPI_WAIT_PIO_SETUP:
|
||||
case SCI_REQ_ATAPI_WAIT_D2H:
|
||||
@ -800,7 +920,8 @@ enum sci_status sci_request_complete(struct isci_request *ireq)
|
||||
|
||||
state = ireq->sm.current_state_id;
|
||||
if (WARN_ONCE(state != SCI_REQ_COMPLETED,
|
||||
"isci: request completion from wrong state (%d)\n", state))
|
||||
"isci: request completion from wrong state (%s)\n",
|
||||
req_state_name(state)))
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
|
||||
if (ireq->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX)
|
||||
@ -821,8 +942,8 @@ enum sci_status sci_io_request_event_handler(struct isci_request *ireq,
|
||||
state = ireq->sm.current_state_id;
|
||||
|
||||
if (state != SCI_REQ_STP_PIO_DATA_IN) {
|
||||
dev_warn(&ihost->pdev->dev, "%s: (%x) in wrong state %d\n",
|
||||
__func__, event_code, state);
|
||||
dev_warn(&ihost->pdev->dev, "%s: (%x) in wrong state %s\n",
|
||||
__func__, event_code, req_state_name(state));
|
||||
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
@ -1938,59 +2059,6 @@ sci_io_request_frame_handler(struct isci_request *ireq,
|
||||
return status;
|
||||
}
|
||||
|
||||
case SCI_REQ_STP_SOFT_RESET_WAIT_D2H: {
|
||||
struct dev_to_host_fis *frame_header;
|
||||
u32 *frame_buffer;
|
||||
|
||||
status = sci_unsolicited_frame_control_get_header(&ihost->uf_control,
|
||||
frame_index,
|
||||
(void **)&frame_header);
|
||||
if (status != SCI_SUCCESS) {
|
||||
dev_err(&ihost->pdev->dev,
|
||||
"%s: SCIC IO Request 0x%p could not get frame "
|
||||
"header for frame index %d, status %x\n",
|
||||
__func__,
|
||||
stp_req,
|
||||
frame_index,
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
switch (frame_header->fis_type) {
|
||||
case FIS_REGD2H:
|
||||
sci_unsolicited_frame_control_get_buffer(&ihost->uf_control,
|
||||
frame_index,
|
||||
(void **)&frame_buffer);
|
||||
|
||||
sci_controller_copy_sata_response(&ireq->stp.rsp,
|
||||
frame_header,
|
||||
frame_buffer);
|
||||
|
||||
/* The command has completed with error */
|
||||
ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
|
||||
ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(&ihost->pdev->dev,
|
||||
"%s: IO Request:0x%p Frame Id:%d protocol "
|
||||
"violation occurred\n",
|
||||
__func__,
|
||||
stp_req,
|
||||
frame_index);
|
||||
|
||||
ireq->scu_status = SCU_TASK_DONE_UNEXP_FIS;
|
||||
ireq->sci_status = SCI_FAILURE_PROTOCOL_VIOLATION;
|
||||
break;
|
||||
}
|
||||
|
||||
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
|
||||
|
||||
/* Frame has been decoded return it to the controller */
|
||||
sci_controller_release_frame(ihost, frame_index);
|
||||
|
||||
return status;
|
||||
}
|
||||
case SCI_REQ_ATAPI_WAIT_PIO_SETUP: {
|
||||
struct sas_task *task = isci_request_access_task(ireq);
|
||||
|
||||
@ -2088,57 +2156,6 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum sci_status
|
||||
stp_request_soft_reset_await_h2d_asserted_tc_event(struct isci_request *ireq,
|
||||
u32 completion_code)
|
||||
{
|
||||
switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
|
||||
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
|
||||
ireq->scu_status = SCU_TASK_DONE_GOOD;
|
||||
ireq->sci_status = SCI_SUCCESS;
|
||||
sci_change_state(&ireq->sm, SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG);
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* All other completion status cause the IO to be complete.
|
||||
* If a NAK was received, then it is up to the user to retry
|
||||
* the request.
|
||||
*/
|
||||
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
|
||||
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
|
||||
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
|
||||
break;
|
||||
}
|
||||
|
||||
return SCI_SUCCESS;
|
||||
}
|
||||
|
||||
static enum sci_status
|
||||
stp_request_soft_reset_await_h2d_diagnostic_tc_event(struct isci_request *ireq,
|
||||
u32 completion_code)
|
||||
{
|
||||
switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) {
|
||||
case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD):
|
||||
ireq->scu_status = SCU_TASK_DONE_GOOD;
|
||||
ireq->sci_status = SCI_SUCCESS;
|
||||
sci_change_state(&ireq->sm, SCI_REQ_STP_SOFT_RESET_WAIT_D2H);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* All other completion status cause the IO to be complete. If
|
||||
* a NAK was received, then it is up to the user to retry the
|
||||
* request.
|
||||
*/
|
||||
ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
|
||||
ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR;
|
||||
sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
|
||||
break;
|
||||
}
|
||||
|
||||
return SCI_SUCCESS;
|
||||
}
|
||||
|
||||
static enum sci_status atapi_raw_completion(struct isci_request *ireq, u32 completion_code,
|
||||
enum sci_base_request_states next)
|
||||
{
|
||||
@ -2284,14 +2301,6 @@ sci_io_request_tc_completion(struct isci_request *ireq,
|
||||
case SCI_REQ_STP_PIO_DATA_OUT:
|
||||
return pio_data_out_tx_done_tc_event(ireq, completion_code);
|
||||
|
||||
case SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED:
|
||||
return stp_request_soft_reset_await_h2d_asserted_tc_event(ireq,
|
||||
completion_code);
|
||||
|
||||
case SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG:
|
||||
return stp_request_soft_reset_await_h2d_diagnostic_tc_event(ireq,
|
||||
completion_code);
|
||||
|
||||
case SCI_REQ_ABORTING:
|
||||
return request_aborting_state_tc_event(ireq,
|
||||
completion_code);
|
||||
@ -2308,12 +2317,8 @@ sci_io_request_tc_completion(struct isci_request *ireq,
|
||||
return atapi_data_tc_completion_handler(ireq, completion_code);
|
||||
|
||||
default:
|
||||
dev_warn(&ihost->pdev->dev,
|
||||
"%s: SCIC IO Request given task completion "
|
||||
"notification %x while in wrong state %d\n",
|
||||
__func__,
|
||||
completion_code,
|
||||
state);
|
||||
dev_warn(&ihost->pdev->dev, "%s: %x in wrong state %s\n",
|
||||
__func__, completion_code, req_state_name(state));
|
||||
return SCI_FAILURE_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
@ -3065,10 +3070,6 @@ static void sci_request_started_state_enter(struct sci_base_state_machine *sm)
|
||||
*/
|
||||
if (!task && dev->dev_type == SAS_END_DEV) {
|
||||
state = SCI_REQ_TASK_WAIT_TC_COMP;
|
||||
} else if (!task &&
|
||||
(isci_request_access_tmf(ireq)->tmf_code == isci_tmf_sata_srst_high ||
|
||||
isci_request_access_tmf(ireq)->tmf_code == isci_tmf_sata_srst_low)) {
|
||||
state = SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED;
|
||||
} else if (task && task->task_proto == SAS_PROTOCOL_SMP) {
|
||||
state = SCI_REQ_SMP_WAIT_RESP;
|
||||
} else if (task && sas_protocol_ata(task->task_proto) &&
|
||||
@ -3125,31 +3126,6 @@ static void sci_stp_request_started_pio_await_h2d_completion_enter(struct sci_ba
|
||||
ireq->target_device->working_request = ireq;
|
||||
}
|
||||
|
||||
static void sci_stp_request_started_soft_reset_await_h2d_asserted_completion_enter(struct sci_base_state_machine *sm)
|
||||
{
|
||||
struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
|
||||
|
||||
ireq->target_device->working_request = ireq;
|
||||
}
|
||||
|
||||
static void sci_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter(struct sci_base_state_machine *sm)
|
||||
{
|
||||
struct isci_request *ireq = container_of(sm, typeof(*ireq), sm);
|
||||
struct scu_task_context *tc = ireq->tc;
|
||||
struct host_to_dev_fis *h2d_fis;
|
||||
enum sci_status status;
|
||||
|
||||
/* Clear the SRST bit */
|
||||
h2d_fis = &ireq->stp.cmd;
|
||||
h2d_fis->control = 0;
|
||||
|
||||
/* Clear the TC control bit */
|
||||
tc->control_frame = 0;
|
||||
|
||||
status = sci_controller_continue_io(ireq);
|
||||
WARN_ONCE(status != SCI_SUCCESS, "isci: continue io failure\n");
|
||||
}
|
||||
|
||||
static const struct sci_base_state sci_request_state_table[] = {
|
||||
[SCI_REQ_INIT] = { },
|
||||
[SCI_REQ_CONSTRUCTED] = { },
|
||||
@ -3168,13 +3144,6 @@ static const struct sci_base_state sci_request_state_table[] = {
|
||||
[SCI_REQ_STP_PIO_DATA_OUT] = { },
|
||||
[SCI_REQ_STP_UDMA_WAIT_TC_COMP] = { },
|
||||
[SCI_REQ_STP_UDMA_WAIT_D2H] = { },
|
||||
[SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED] = {
|
||||
.enter_state = sci_stp_request_started_soft_reset_await_h2d_asserted_completion_enter,
|
||||
},
|
||||
[SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG] = {
|
||||
.enter_state = sci_stp_request_started_soft_reset_await_h2d_diagnostic_completion_enter,
|
||||
},
|
||||
[SCI_REQ_STP_SOFT_RESET_WAIT_D2H] = { },
|
||||
[SCI_REQ_TASK_WAIT_TC_COMP] = { },
|
||||
[SCI_REQ_TASK_WAIT_TC_RESP] = { },
|
||||
[SCI_REQ_SMP_WAIT_RESP] = { },
|
||||
@ -3649,8 +3618,7 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
|
||||
/* Cause this task to be scheduled in the SCSI error
|
||||
* handler thread.
|
||||
*/
|
||||
isci_execpath_callback(ihost, task,
|
||||
sas_task_abort);
|
||||
sas_task_abort(task);
|
||||
|
||||
/* Change the status, since we are holding
|
||||
* the I/O until it is managed by the SCSI
|
||||
|
@ -182,138 +182,103 @@ static inline struct isci_request *to_ireq(struct isci_stp_request *stp_req)
|
||||
}
|
||||
|
||||
/**
|
||||
* enum sci_base_request_states - This enumeration depicts all the states for
|
||||
* the common request state machine.
|
||||
* enum sci_base_request_states - request state machine states
|
||||
*
|
||||
* @SCI_REQ_INIT: Simply the initial state for the base request state machine.
|
||||
*
|
||||
* @SCI_REQ_CONSTRUCTED: This state indicates that the request has been
|
||||
* constructed. This state is entered from the INITIAL state.
|
||||
*
|
||||
* @SCI_REQ_STARTED: This state indicates that the request has been started.
|
||||
* This state is entered from the CONSTRUCTED state.
|
||||
*
|
||||
* @SCI_REQ_STP_UDMA_WAIT_TC_COMP:
|
||||
* @SCI_REQ_STP_UDMA_WAIT_D2H:
|
||||
* @SCI_REQ_STP_NON_DATA_WAIT_H2D:
|
||||
* @SCI_REQ_STP_NON_DATA_WAIT_D2H:
|
||||
*
|
||||
* @SCI_REQ_STP_PIO_WAIT_H2D: While in this state the IO request object is
|
||||
* waiting for the TC completion notification for the H2D Register FIS
|
||||
*
|
||||
* @SCI_REQ_STP_PIO_WAIT_FRAME: While in this state the IO request object is
|
||||
* waiting for either a PIO Setup FIS or a D2H register FIS. The type of frame
|
||||
* received is based on the result of the prior frame and line conditions.
|
||||
*
|
||||
* @SCI_REQ_STP_PIO_DATA_IN: While in this state the IO request object is
|
||||
* waiting for a DATA frame from the device.
|
||||
*
|
||||
* @SCI_REQ_STP_PIO_DATA_OUT: While in this state the IO request object is
|
||||
* waiting to transmit the next data frame to the device.
|
||||
*
|
||||
* @SCI_REQ_ATAPI_WAIT_H2D: While in this state the IO request object is
|
||||
* waiting for the TC completion notification for the H2D Register FIS
|
||||
*
|
||||
* @SCI_REQ_ATAPI_WAIT_PIO_SETUP: While in this state the IO request object is
|
||||
* waiting for either a PIO Setup.
|
||||
*
|
||||
* @SCI_REQ_ATAPI_WAIT_D2H: The non-data IO transit to this state in this state
|
||||
* after receiving TC completion. While in this state IO request object is
|
||||
* waiting for D2H status frame as UF.
|
||||
*
|
||||
* @SCI_REQ_ATAPI_WAIT_TC_COMP: When transmitting raw frames hardware reports
|
||||
* task context completion after every frame submission, so in the
|
||||
* non-accelerated case we need to expect the completion for the "cdb" frame.
|
||||
*
|
||||
* @SCI_REQ_TASK_WAIT_TC_COMP: The AWAIT_TC_COMPLETION sub-state indicates that
|
||||
* the started raw task management request is waiting for the transmission of
|
||||
* the initial frame (i.e. command, task, etc.).
|
||||
*
|
||||
* @SCI_REQ_TASK_WAIT_TC_RESP: This sub-state indicates that the started task
|
||||
* management request is waiting for the reception of an unsolicited frame
|
||||
* (i.e. response IU).
|
||||
*
|
||||
* @SCI_REQ_SMP_WAIT_RESP: This sub-state indicates that the started task
|
||||
* management request is waiting for the reception of an unsolicited frame
|
||||
* (i.e. response IU).
|
||||
*
|
||||
* @SCI_REQ_SMP_WAIT_TC_COMP: The AWAIT_TC_COMPLETION sub-state indicates that
|
||||
* the started SMP request is waiting for the transmission of the initial frame
|
||||
* (i.e. command, task, etc.).
|
||||
*
|
||||
* @SCI_REQ_COMPLETED: This state indicates that the request has completed.
|
||||
* This state is entered from the STARTED state. This state is entered from the
|
||||
* ABORTING state.
|
||||
*
|
||||
* @SCI_REQ_ABORTING: This state indicates that the request is in the process
|
||||
* of being terminated/aborted. This state is entered from the CONSTRUCTED
|
||||
* state. This state is entered from the STARTED state.
|
||||
*
|
||||
* @SCI_REQ_FINAL: Simply the final state for the base request state machine.
|
||||
*/
|
||||
enum sci_base_request_states {
|
||||
/*
|
||||
* Simply the initial state for the base request state machine.
|
||||
*/
|
||||
SCI_REQ_INIT,
|
||||
|
||||
/*
|
||||
* This state indicates that the request has been constructed.
|
||||
* This state is entered from the INITIAL state.
|
||||
*/
|
||||
SCI_REQ_CONSTRUCTED,
|
||||
|
||||
/*
|
||||
* This state indicates that the request has been started. This state
|
||||
* is entered from the CONSTRUCTED state.
|
||||
*/
|
||||
SCI_REQ_STARTED,
|
||||
|
||||
SCI_REQ_STP_UDMA_WAIT_TC_COMP,
|
||||
SCI_REQ_STP_UDMA_WAIT_D2H,
|
||||
|
||||
SCI_REQ_STP_NON_DATA_WAIT_H2D,
|
||||
SCI_REQ_STP_NON_DATA_WAIT_D2H,
|
||||
|
||||
SCI_REQ_STP_SOFT_RESET_WAIT_H2D_ASSERTED,
|
||||
SCI_REQ_STP_SOFT_RESET_WAIT_H2D_DIAG,
|
||||
SCI_REQ_STP_SOFT_RESET_WAIT_D2H,
|
||||
|
||||
/*
|
||||
* While in this state the IO request object is waiting for the TC
|
||||
* completion notification for the H2D Register FIS
|
||||
*/
|
||||
SCI_REQ_STP_PIO_WAIT_H2D,
|
||||
|
||||
/*
|
||||
* While in this state the IO request object is waiting for either a
|
||||
* PIO Setup FIS or a D2H register FIS. The type of frame received is
|
||||
* based on the result of the prior frame and line conditions.
|
||||
*/
|
||||
SCI_REQ_STP_PIO_WAIT_FRAME,
|
||||
|
||||
/*
|
||||
* While in this state the IO request object is waiting for a DATA
|
||||
* frame from the device.
|
||||
*/
|
||||
SCI_REQ_STP_PIO_DATA_IN,
|
||||
|
||||
/*
|
||||
* While in this state the IO request object is waiting to transmit
|
||||
* the next data frame to the device.
|
||||
*/
|
||||
SCI_REQ_STP_PIO_DATA_OUT,
|
||||
|
||||
/*
|
||||
* While in this state the IO request object is waiting for the TC
|
||||
* completion notification for the H2D Register FIS
|
||||
*/
|
||||
SCI_REQ_ATAPI_WAIT_H2D,
|
||||
|
||||
/*
|
||||
* While in this state the IO request object is waiting for either a
|
||||
* PIO Setup.
|
||||
*/
|
||||
SCI_REQ_ATAPI_WAIT_PIO_SETUP,
|
||||
|
||||
/*
|
||||
* The non-data IO transit to this state in this state after receiving
|
||||
* TC completion. While in this state IO request object is waiting for
|
||||
* D2H status frame as UF.
|
||||
*/
|
||||
SCI_REQ_ATAPI_WAIT_D2H,
|
||||
|
||||
/*
|
||||
* When transmitting raw frames hardware reports task context completion
|
||||
* after every frame submission, so in the non-accelerated case we need
|
||||
* to expect the completion for the "cdb" frame.
|
||||
*/
|
||||
SCI_REQ_ATAPI_WAIT_TC_COMP,
|
||||
|
||||
/*
|
||||
* The AWAIT_TC_COMPLETION sub-state indicates that the started raw
|
||||
* task management request is waiting for the transmission of the
|
||||
* initial frame (i.e. command, task, etc.).
|
||||
*/
|
||||
SCI_REQ_TASK_WAIT_TC_COMP,
|
||||
|
||||
/*
|
||||
* This sub-state indicates that the started task management request
|
||||
* is waiting for the reception of an unsolicited frame
|
||||
* (i.e. response IU).
|
||||
*/
|
||||
SCI_REQ_TASK_WAIT_TC_RESP,
|
||||
|
||||
/*
|
||||
* This sub-state indicates that the started task management request
|
||||
* is waiting for the reception of an unsolicited frame
|
||||
* (i.e. response IU).
|
||||
*/
|
||||
SCI_REQ_SMP_WAIT_RESP,
|
||||
|
||||
/*
|
||||
* The AWAIT_TC_COMPLETION sub-state indicates that the started SMP
|
||||
* request is waiting for the transmission of the initial frame
|
||||
* (i.e. command, task, etc.).
|
||||
*/
|
||||
SCI_REQ_SMP_WAIT_TC_COMP,
|
||||
|
||||
/*
|
||||
* This state indicates that the request has completed.
|
||||
* This state is entered from the STARTED state. This state is entered
|
||||
* from the ABORTING state.
|
||||
*/
|
||||
SCI_REQ_COMPLETED,
|
||||
|
||||
/*
|
||||
* This state indicates that the request is in the process of being
|
||||
* terminated/aborted.
|
||||
* This state is entered from the CONSTRUCTED state.
|
||||
* This state is entered from the STARTED state.
|
||||
*/
|
||||
SCI_REQ_ABORTING,
|
||||
|
||||
/*
|
||||
* Simply the final state for the base request state machine.
|
||||
*/
|
||||
SCI_REQ_FINAL,
|
||||
};
|
||||
#define REQUEST_STATES {\
|
||||
C(REQ_INIT),\
|
||||
C(REQ_CONSTRUCTED),\
|
||||
C(REQ_STARTED),\
|
||||
C(REQ_STP_UDMA_WAIT_TC_COMP),\
|
||||
C(REQ_STP_UDMA_WAIT_D2H),\
|
||||
C(REQ_STP_NON_DATA_WAIT_H2D),\
|
||||
C(REQ_STP_NON_DATA_WAIT_D2H),\
|
||||
C(REQ_STP_PIO_WAIT_H2D),\
|
||||
C(REQ_STP_PIO_WAIT_FRAME),\
|
||||
C(REQ_STP_PIO_DATA_IN),\
|
||||
C(REQ_STP_PIO_DATA_OUT),\
|
||||
C(REQ_ATAPI_WAIT_H2D),\
|
||||
C(REQ_ATAPI_WAIT_PIO_SETUP),\
|
||||
C(REQ_ATAPI_WAIT_D2H),\
|
||||
C(REQ_ATAPI_WAIT_TC_COMP),\
|
||||
C(REQ_TASK_WAIT_TC_COMP),\
|
||||
C(REQ_TASK_WAIT_TC_RESP),\
|
||||
C(REQ_SMP_WAIT_RESP),\
|
||||
C(REQ_SMP_WAIT_TC_COMP),\
|
||||
C(REQ_COMPLETED),\
|
||||
C(REQ_ABORTING),\
|
||||
C(REQ_FINAL),\
|
||||
}
|
||||
#undef C
|
||||
#define C(a) SCI_##a
|
||||
enum sci_base_request_states REQUEST_STATES;
|
||||
#undef C
|
||||
const char *req_state_name(enum sci_base_request_states state);
|
||||
|
||||
enum sci_status sci_request_start(struct isci_request *ireq);
|
||||
enum sci_status sci_io_request_terminate(struct isci_request *ireq);
|
||||
@ -446,10 +411,7 @@ sci_task_request_construct(struct isci_host *ihost,
|
||||
struct isci_remote_device *idev,
|
||||
u16 io_tag,
|
||||
struct isci_request *ireq);
|
||||
enum sci_status
|
||||
sci_task_request_construct_ssp(struct isci_request *ireq);
|
||||
enum sci_status
|
||||
sci_task_request_construct_sata(struct isci_request *ireq);
|
||||
enum sci_status sci_task_request_construct_ssp(struct isci_request *ireq);
|
||||
void sci_smp_request_copy_response(struct isci_request *ireq);
|
||||
|
||||
static inline int isci_task_is_ncq_recovery(struct sas_task *task)
|
||||
|
@ -866,9 +866,9 @@ struct scu_task_context {
|
||||
struct transport_snapshot snapshot; /* read only set to 0 */
|
||||
|
||||
/* OFFSET 0x5C */
|
||||
u32 block_protection_enable:1;
|
||||
u32 block_size:2;
|
||||
u32 block_protection_function:2;
|
||||
u32 blk_prot_en:1;
|
||||
u32 blk_sz:2;
|
||||
u32 blk_prot_func:2;
|
||||
u32 reserved_5C_0:9;
|
||||
u32 active_sgl_element:2; /* read only set to 0 */
|
||||
u32 sgl_exhausted:1; /* read only set to 0 */
|
||||
@ -896,33 +896,56 @@ struct scu_task_context {
|
||||
u32 reserved_C4_CC[3];
|
||||
|
||||
/* OFFSET 0xD0 */
|
||||
u32 intermediate_crc_value:16;
|
||||
u32 initial_crc_seed:16;
|
||||
u32 interm_crc_val:16;
|
||||
u32 init_crc_seed:16;
|
||||
|
||||
/* OFFSET 0xD4 */
|
||||
u32 application_tag_for_verify:16;
|
||||
u32 application_tag_for_generate:16;
|
||||
u32 app_tag_verify:16;
|
||||
u32 app_tag_gen:16;
|
||||
|
||||
/* OFFSET 0xD8 */
|
||||
u32 reference_tag_seed_for_verify_function;
|
||||
u32 ref_tag_seed_verify;
|
||||
|
||||
/* OFFSET 0xDC */
|
||||
u32 reserved_DC;
|
||||
u32 UD_bytes_immed_val:13;
|
||||
u32 reserved_DC_0:3;
|
||||
u32 DIF_bytes_immed_val:4;
|
||||
u32 reserved_DC_1:12;
|
||||
|
||||
/* OFFSET 0xE0 */
|
||||
u32 reserved_E0_0:16;
|
||||
u32 application_tag_mask_for_generate:16;
|
||||
u32 bgc_blk_sz:13;
|
||||
u32 reserved_E0_0:3;
|
||||
u32 app_tag_gen_mask:16;
|
||||
|
||||
/* OFFSET 0xE4 */
|
||||
u32 block_protection_control:16;
|
||||
u32 application_tag_mask_for_verify:16;
|
||||
union {
|
||||
u16 bgctl;
|
||||
struct {
|
||||
u16 crc_verify:1;
|
||||
u16 app_tag_chk:1;
|
||||
u16 ref_tag_chk:1;
|
||||
u16 op:2;
|
||||
u16 legacy:1;
|
||||
u16 invert_crc_seed:1;
|
||||
u16 ref_tag_gen:1;
|
||||
u16 fixed_ref_tag:1;
|
||||
u16 invert_crc:1;
|
||||
u16 app_ref_f_detect:1;
|
||||
u16 uninit_dif_check_err:1;
|
||||
u16 uninit_dif_bypass:1;
|
||||
u16 app_f_detect:1;
|
||||
u16 reserved_0:2;
|
||||
} bgctl_f;
|
||||
};
|
||||
|
||||
u16 app_tag_verify_mask;
|
||||
|
||||
/* OFFSET 0xE8 */
|
||||
u32 block_protection_error:8;
|
||||
u32 blk_guard_err:8;
|
||||
u32 reserved_E8_0:24;
|
||||
|
||||
/* OFFSET 0xEC */
|
||||
u32 reference_tag_seed_for_verify;
|
||||
u32 ref_tag_seed_gen;
|
||||
|
||||
/* OFFSET 0xF0 */
|
||||
u32 intermediate_crc_valid_snapshot:16;
|
||||
@ -937,6 +960,6 @@ struct scu_task_context {
|
||||
/* OFFSET 0xFC */
|
||||
u32 reference_tag_seed_for_generate_function_snapshot;
|
||||
|
||||
};
|
||||
} __packed;
|
||||
|
||||
#endif /* _SCU_TASK_CONTEXT_H_ */
|
||||
|
@ -96,8 +96,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
|
||||
__func__, task, response, status);
|
||||
|
||||
task->lldd_task = NULL;
|
||||
|
||||
isci_execpath_callback(ihost, task, task->task_done);
|
||||
task->task_done(task);
|
||||
break;
|
||||
|
||||
case isci_perform_aborted_io_completion:
|
||||
@ -117,8 +116,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
|
||||
"%s: Error - task = %p, response=%d, "
|
||||
"status=%d\n",
|
||||
__func__, task, response, status);
|
||||
|
||||
isci_execpath_callback(ihost, task, sas_task_abort);
|
||||
sas_task_abort(task);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -249,46 +247,6 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum sci_status isci_sata_management_task_request_build(struct isci_request *ireq)
|
||||
{
|
||||
struct isci_tmf *isci_tmf;
|
||||
enum sci_status status;
|
||||
|
||||
if (!test_bit(IREQ_TMF, &ireq->flags))
|
||||
return SCI_FAILURE;
|
||||
|
||||
isci_tmf = isci_request_access_tmf(ireq);
|
||||
|
||||
switch (isci_tmf->tmf_code) {
|
||||
|
||||
case isci_tmf_sata_srst_high:
|
||||
case isci_tmf_sata_srst_low: {
|
||||
struct host_to_dev_fis *fis = &ireq->stp.cmd;
|
||||
|
||||
memset(fis, 0, sizeof(*fis));
|
||||
|
||||
fis->fis_type = 0x27;
|
||||
fis->flags &= ~0x80;
|
||||
fis->flags &= 0xF0;
|
||||
if (isci_tmf->tmf_code == isci_tmf_sata_srst_high)
|
||||
fis->control |= ATA_SRST;
|
||||
else
|
||||
fis->control &= ~ATA_SRST;
|
||||
break;
|
||||
}
|
||||
/* other management commnd go here... */
|
||||
default:
|
||||
return SCI_FAILURE;
|
||||
}
|
||||
|
||||
/* core builds the protocol specific request
|
||||
* based on the h2d fis.
|
||||
*/
|
||||
status = sci_task_request_construct_sata(ireq);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct isci_request *isci_task_request_build(struct isci_host *ihost,
|
||||
struct isci_remote_device *idev,
|
||||
u16 tag, struct isci_tmf *isci_tmf)
|
||||
@ -328,13 +286,6 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
|
||||
isci_tmf->proto = SAS_PROTOCOL_SATA;
|
||||
status = isci_sata_management_task_request_build(ireq);
|
||||
|
||||
if (status != SCI_SUCCESS)
|
||||
return NULL;
|
||||
}
|
||||
return ireq;
|
||||
}
|
||||
|
||||
@ -873,53 +824,20 @@ static int isci_task_send_lu_reset_sas(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isci_task_send_lu_reset_sata(struct isci_host *ihost,
|
||||
struct isci_remote_device *idev, u8 *lun)
|
||||
int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
|
||||
{
|
||||
int ret = TMF_RESP_FUNC_FAILED;
|
||||
struct isci_tmf tmf;
|
||||
|
||||
/* Send the soft reset to the target */
|
||||
#define ISCI_SRST_TIMEOUT_MS 25000 /* 25 second timeout. */
|
||||
isci_task_build_tmf(&tmf, isci_tmf_sata_srst_high, NULL, NULL);
|
||||
|
||||
ret = isci_task_execute_tmf(ihost, idev, &tmf, ISCI_SRST_TIMEOUT_MS);
|
||||
|
||||
if (ret != TMF_RESP_FUNC_COMPLETE) {
|
||||
dev_dbg(&ihost->pdev->dev,
|
||||
"%s: Assert SRST failed (%p) = %x",
|
||||
__func__, idev, ret);
|
||||
|
||||
/* Return the failure so that the LUN reset is escalated
|
||||
* to a target reset.
|
||||
*/
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* isci_task_lu_reset() - This function is one of the SAS Domain Template
|
||||
* functions. This is one of the Task Management functoins called by libsas,
|
||||
* to reset the given lun. Note the assumption that while this call is
|
||||
* executing, no I/O will be sent by the host to the device.
|
||||
* @lun: This parameter specifies the lun to be reset.
|
||||
*
|
||||
* status, zero indicates success.
|
||||
*/
|
||||
int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun)
|
||||
{
|
||||
struct isci_host *isci_host = dev_to_ihost(domain_device);
|
||||
struct isci_host *isci_host = dev_to_ihost(dev);
|
||||
struct isci_remote_device *isci_device;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&isci_host->scic_lock, flags);
|
||||
isci_device = isci_lookup_device(domain_device);
|
||||
isci_device = isci_lookup_device(dev);
|
||||
spin_unlock_irqrestore(&isci_host->scic_lock, flags);
|
||||
|
||||
dev_dbg(&isci_host->pdev->dev,
|
||||
"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
|
||||
__func__, domain_device, isci_host, isci_device);
|
||||
__func__, dev, isci_host, isci_device);
|
||||
|
||||
if (!isci_device) {
|
||||
/* If the device is gone, stop the escalations. */
|
||||
@ -928,11 +846,11 @@ int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun)
|
||||
ret = TMF_RESP_FUNC_COMPLETE;
|
||||
goto out;
|
||||
}
|
||||
set_bit(IDEV_EH, &isci_device->flags);
|
||||
|
||||
/* Send the task management part of the reset. */
|
||||
if (sas_protocol_ata(domain_device->tproto)) {
|
||||
ret = isci_task_send_lu_reset_sata(isci_host, isci_device, lun);
|
||||
if (dev_is_sata(dev)) {
|
||||
sas_ata_schedule_reset(dev);
|
||||
ret = TMF_RESP_FUNC_COMPLETE;
|
||||
} else
|
||||
ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);
|
||||
|
||||
@ -1062,9 +980,6 @@ int isci_task_abort_task(struct sas_task *task)
|
||||
"%s: dev = %p, task = %p, old_request == %p\n",
|
||||
__func__, isci_device, task, old_request);
|
||||
|
||||
if (isci_device)
|
||||
set_bit(IDEV_EH, &isci_device->flags);
|
||||
|
||||
/* Device reset conditions signalled in task_state_flags are the
|
||||
* responsbility of libsas to observe at the start of the error
|
||||
* handler thread.
|
||||
@ -1332,29 +1247,35 @@ isci_task_request_complete(struct isci_host *ihost,
|
||||
}
|
||||
|
||||
static int isci_reset_device(struct isci_host *ihost,
|
||||
struct domain_device *dev,
|
||||
struct isci_remote_device *idev)
|
||||
{
|
||||
struct sas_phy *phy = sas_find_local_phy(idev->domain_dev);
|
||||
enum sci_status status;
|
||||
unsigned long flags;
|
||||
int rc;
|
||||
unsigned long flags;
|
||||
enum sci_status status;
|
||||
struct sas_phy *phy = sas_get_local_phy(dev);
|
||||
struct isci_port *iport = dev->port->lldd_port;
|
||||
|
||||
dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
|
||||
|
||||
spin_lock_irqsave(&ihost->scic_lock, flags);
|
||||
status = sci_remote_device_reset(idev);
|
||||
if (status != SCI_SUCCESS) {
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
|
||||
if (status != SCI_SUCCESS) {
|
||||
dev_dbg(&ihost->pdev->dev,
|
||||
"%s: sci_remote_device_reset(%p) returned %d!\n",
|
||||
__func__, idev, status);
|
||||
|
||||
return TMF_RESP_FUNC_FAILED;
|
||||
rc = TMF_RESP_FUNC_FAILED;
|
||||
goto out;
|
||||
}
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
|
||||
rc = sas_phy_reset(phy, true);
|
||||
if (scsi_is_sas_phy_local(phy)) {
|
||||
struct isci_phy *iphy = &ihost->phys[phy->number];
|
||||
|
||||
rc = isci_port_perform_hard_reset(ihost, iport, iphy);
|
||||
} else
|
||||
rc = sas_phy_reset(phy, !dev_is_sata(dev));
|
||||
|
||||
/* Terminate in-progress I/O now. */
|
||||
isci_remote_device_nuke_requests(ihost, idev);
|
||||
@ -1371,7 +1292,8 @@ static int isci_reset_device(struct isci_host *ihost,
|
||||
}
|
||||
|
||||
dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
|
||||
|
||||
out:
|
||||
sas_put_local_phy(phy);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1386,35 +1308,15 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
|
||||
idev = isci_lookup_device(dev);
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
|
||||
if (!idev || !test_bit(IDEV_EH, &idev->flags)) {
|
||||
ret = TMF_RESP_FUNC_COMPLETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = isci_reset_device(ihost, idev);
|
||||
out:
|
||||
isci_put_device(idev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int isci_bus_reset_handler(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct domain_device *dev = sdev_to_domain_dev(cmd->device);
|
||||
struct isci_host *ihost = dev_to_ihost(dev);
|
||||
struct isci_remote_device *idev;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&ihost->scic_lock, flags);
|
||||
idev = isci_lookup_device(dev);
|
||||
spin_unlock_irqrestore(&ihost->scic_lock, flags);
|
||||
|
||||
if (!idev) {
|
||||
/* XXX: need to cleanup any ireqs targeting this
|
||||
* domain_device
|
||||
*/
|
||||
ret = TMF_RESP_FUNC_COMPLETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = isci_reset_device(ihost, idev);
|
||||
ret = isci_reset_device(ihost, dev, idev);
|
||||
out:
|
||||
isci_put_device(idev);
|
||||
return ret;
|
||||
|
@ -86,8 +86,6 @@ enum isci_tmf_function_codes {
|
||||
isci_tmf_func_none = 0,
|
||||
isci_tmf_ssp_task_abort = TMF_ABORT_TASK,
|
||||
isci_tmf_ssp_lun_reset = TMF_LU_RESET,
|
||||
isci_tmf_sata_srst_high = TMF_LU_RESET + 0x100, /* Non SCSI */
|
||||
isci_tmf_sata_srst_low = TMF_LU_RESET + 0x101 /* Non SCSI */
|
||||
};
|
||||
/**
|
||||
* struct isci_tmf - This class represents the task management object which
|
||||
@ -210,8 +208,6 @@ int isci_queuecommand(
|
||||
struct scsi_cmnd *scsi_cmd,
|
||||
void (*donefunc)(struct scsi_cmnd *));
|
||||
|
||||
int isci_bus_reset_handler(struct scsi_cmnd *cmd);
|
||||
|
||||
/**
|
||||
* enum isci_completion_selection - This enum defines the possible actions to
|
||||
* take with respect to a given request's notification back to libsas.
|
||||
@ -321,40 +317,4 @@ isci_task_set_completion_status(
|
||||
return task_notification_selection;
|
||||
|
||||
}
|
||||
/**
|
||||
* isci_execpath_callback() - This function is called from the task
|
||||
* execute path when the task needs to callback libsas about the submit-time
|
||||
* task failure. The callback occurs either through the task's done function
|
||||
* or through sas_task_abort. In the case of regular non-discovery SATA/STP I/O
|
||||
* requests, libsas takes the host lock before calling execute task. Therefore
|
||||
* in this situation the host lock must be managed before calling the func.
|
||||
*
|
||||
* @ihost: This parameter is the controller to which the I/O request was sent.
|
||||
* @task: This parameter is the I/O request.
|
||||
* @func: This parameter is the function to call in the correct context.
|
||||
* @status: This parameter is the status code for the completed task.
|
||||
*
|
||||
*/
|
||||
static inline void isci_execpath_callback(struct isci_host *ihost,
|
||||
struct sas_task *task,
|
||||
void (*func)(struct sas_task *))
|
||||
{
|
||||
struct domain_device *dev = task->dev;
|
||||
|
||||
if (dev_is_sata(dev) && task->uldd_task) {
|
||||
unsigned long flags;
|
||||
|
||||
/* Since we are still in the submit path, and since
|
||||
* libsas takes the host lock on behalf of SATA
|
||||
* devices before I/O starts (in the non-discovery case),
|
||||
* we need to unlock before we can call the callback function.
|
||||
*/
|
||||
raw_local_irq_save(flags);
|
||||
spin_unlock(dev->sata_dev.ap->lock);
|
||||
func(task);
|
||||
spin_lock(dev->sata_dev.ap->lock);
|
||||
raw_local_irq_restore(flags);
|
||||
} else
|
||||
func(task);
|
||||
}
|
||||
#endif /* !defined(_SCI_TASK_H_) */
|
||||
|
@ -684,10 +684,8 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn,
|
||||
int buflen)
|
||||
{
|
||||
struct iscsi_conn *conn = cls_conn->dd_data;
|
||||
struct iscsi_session *session = conn->session;
|
||||
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
|
||||
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
|
||||
int value;
|
||||
|
||||
switch(param) {
|
||||
case ISCSI_PARAM_HDRDGST_EN:
|
||||
@ -699,16 +697,7 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn,
|
||||
sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage;
|
||||
break;
|
||||
case ISCSI_PARAM_MAX_R2T:
|
||||
sscanf(buf, "%d", &value);
|
||||
if (value <= 0 || !is_power_of_2(value))
|
||||
return -EINVAL;
|
||||
if (session->max_r2t == value)
|
||||
break;
|
||||
iscsi_tcp_r2tpool_free(session);
|
||||
iscsi_set_param(cls_conn, param, buf, buflen);
|
||||
if (iscsi_tcp_r2tpool_alloc(session))
|
||||
return -ENOMEM;
|
||||
break;
|
||||
return iscsi_tcp_set_max_r2t(conn, buf);
|
||||
default:
|
||||
return iscsi_set_param(cls_conn, param, buf, buflen);
|
||||
}
|
||||
|
@ -337,6 +337,13 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
|
||||
schedule_delayed_work(&disc->disc_work, delay);
|
||||
} else
|
||||
fc_disc_done(disc, DISC_EV_FAILED);
|
||||
} else if (PTR_ERR(fp) == -FC_EX_CLOSED) {
|
||||
/*
|
||||
* if discovery fails due to lport reset, clear
|
||||
* pending flag so that subsequent discovery can
|
||||
* continue
|
||||
*/
|
||||
disc->pending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,8 +56,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,
|
||||
rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type);
|
||||
else {
|
||||
/* CT requests */
|
||||
rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type);
|
||||
did = FC_FID_DIR_SERV;
|
||||
rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type, &did);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
|
@ -1642,9 +1642,10 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp)
|
||||
case FC_RCTL_ACK_0:
|
||||
break;
|
||||
default:
|
||||
FC_EXCH_DBG(ep, "BLS rctl %x - %s received",
|
||||
fh->fh_r_ctl,
|
||||
fc_exch_rctl_name(fh->fh_r_ctl));
|
||||
if (ep)
|
||||
FC_EXCH_DBG(ep, "BLS rctl %x - %s received",
|
||||
fh->fh_r_ctl,
|
||||
fc_exch_rctl_name(fh->fh_r_ctl));
|
||||
break;
|
||||
}
|
||||
fc_frame_free(fp);
|
||||
|
@ -116,6 +116,8 @@ static void fc_lport_enter_ns(struct fc_lport *, enum fc_lport_state);
|
||||
static void fc_lport_enter_scr(struct fc_lport *);
|
||||
static void fc_lport_enter_ready(struct fc_lport *);
|
||||
static void fc_lport_enter_logo(struct fc_lport *);
|
||||
static void fc_lport_enter_fdmi(struct fc_lport *lport);
|
||||
static void fc_lport_enter_ms(struct fc_lport *, enum fc_lport_state);
|
||||
|
||||
static const char *fc_lport_state_names[] = {
|
||||
[LPORT_ST_DISABLED] = "disabled",
|
||||
@ -126,6 +128,11 @@ static const char *fc_lport_state_names[] = {
|
||||
[LPORT_ST_RSPN_ID] = "RSPN_ID",
|
||||
[LPORT_ST_RFT_ID] = "RFT_ID",
|
||||
[LPORT_ST_RFF_ID] = "RFF_ID",
|
||||
[LPORT_ST_FDMI] = "FDMI",
|
||||
[LPORT_ST_RHBA] = "RHBA",
|
||||
[LPORT_ST_RPA] = "RPA",
|
||||
[LPORT_ST_DHBA] = "DHBA",
|
||||
[LPORT_ST_DPRT] = "DPRT",
|
||||
[LPORT_ST_SCR] = "SCR",
|
||||
[LPORT_ST_READY] = "Ready",
|
||||
[LPORT_ST_LOGO] = "LOGO",
|
||||
@ -183,11 +190,14 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
|
||||
if (lport->state == LPORT_ST_DNS) {
|
||||
lport->dns_rdata = rdata;
|
||||
fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);
|
||||
} else if (lport->state == LPORT_ST_FDMI) {
|
||||
lport->ms_rdata = rdata;
|
||||
fc_lport_enter_ms(lport, LPORT_ST_DHBA);
|
||||
} else {
|
||||
FC_LPORT_DBG(lport, "Received an READY event "
|
||||
"on port (%6.6x) for the directory "
|
||||
"server, but the lport is not "
|
||||
"in the DNS state, it's in the "
|
||||
"in the DNS or FDMI state, it's in the "
|
||||
"%d state", rdata->ids.port_id,
|
||||
lport->state);
|
||||
lport->tt.rport_logoff(rdata);
|
||||
@ -196,7 +206,10 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
|
||||
case RPORT_EV_LOGO:
|
||||
case RPORT_EV_FAILED:
|
||||
case RPORT_EV_STOP:
|
||||
lport->dns_rdata = NULL;
|
||||
if (rdata->ids.port_id == FC_FID_DIR_SERV)
|
||||
lport->dns_rdata = NULL;
|
||||
else if (rdata->ids.port_id == FC_FID_MGMT_SERV)
|
||||
lport->ms_rdata = NULL;
|
||||
break;
|
||||
case RPORT_EV_NONE:
|
||||
break;
|
||||
@ -1148,7 +1161,10 @@ static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp,
|
||||
fc_lport_enter_ns(lport, LPORT_ST_RFF_ID);
|
||||
break;
|
||||
case LPORT_ST_RFF_ID:
|
||||
fc_lport_enter_scr(lport);
|
||||
if (lport->fdmi_enabled)
|
||||
fc_lport_enter_fdmi(lport);
|
||||
else
|
||||
fc_lport_enter_scr(lport);
|
||||
break;
|
||||
default:
|
||||
/* should have already been caught by state checks */
|
||||
@ -1162,6 +1178,85 @@ err:
|
||||
mutex_unlock(&lport->lp_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_lport_ms_resp() - Handle response to a management server
|
||||
* exchange
|
||||
* @sp: current sequence in exchange
|
||||
* @fp: response frame
|
||||
* @lp_arg: Fibre Channel host port instance
|
||||
*
|
||||
* Locking Note: This function will be called without the lport lock
|
||||
* held, but it will lock, call an _enter_* function or fc_lport_error()
|
||||
* and then unlock the lport.
|
||||
*/
|
||||
static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp,
|
||||
void *lp_arg)
|
||||
{
|
||||
struct fc_lport *lport = lp_arg;
|
||||
struct fc_frame_header *fh;
|
||||
struct fc_ct_hdr *ct;
|
||||
|
||||
FC_LPORT_DBG(lport, "Received a ms %s\n", fc_els_resp_type(fp));
|
||||
|
||||
if (fp == ERR_PTR(-FC_EX_CLOSED))
|
||||
return;
|
||||
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
|
||||
if (lport->state < LPORT_ST_RHBA || lport->state > LPORT_ST_DPRT) {
|
||||
FC_LPORT_DBG(lport, "Received a management server response, "
|
||||
"but in state %s\n", fc_lport_state(lport));
|
||||
if (IS_ERR(fp))
|
||||
goto err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (IS_ERR(fp)) {
|
||||
fc_lport_error(lport, fp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
fh = fc_frame_header_get(fp);
|
||||
ct = fc_frame_payload_get(fp, sizeof(*ct));
|
||||
|
||||
if (fh && ct && fh->fh_type == FC_TYPE_CT &&
|
||||
ct->ct_fs_type == FC_FST_MGMT &&
|
||||
ct->ct_fs_subtype == FC_FDMI_SUBTYPE) {
|
||||
FC_LPORT_DBG(lport, "Received a management server response, "
|
||||
"reason=%d explain=%d\n",
|
||||
ct->ct_reason,
|
||||
ct->ct_explan);
|
||||
|
||||
switch (lport->state) {
|
||||
case LPORT_ST_RHBA:
|
||||
if (ntohs(ct->ct_cmd) == FC_FS_ACC)
|
||||
fc_lport_enter_ms(lport, LPORT_ST_RPA);
|
||||
else /* Error Skip RPA */
|
||||
fc_lport_enter_scr(lport);
|
||||
break;
|
||||
case LPORT_ST_RPA:
|
||||
fc_lport_enter_scr(lport);
|
||||
break;
|
||||
case LPORT_ST_DPRT:
|
||||
fc_lport_enter_ms(lport, LPORT_ST_RHBA);
|
||||
break;
|
||||
case LPORT_ST_DHBA:
|
||||
fc_lport_enter_ms(lport, LPORT_ST_DPRT);
|
||||
break;
|
||||
default:
|
||||
/* should have already been caught by state checks */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Invalid Frame? */
|
||||
fc_lport_error(lport, fp);
|
||||
}
|
||||
out:
|
||||
fc_frame_free(fp);
|
||||
err:
|
||||
mutex_unlock(&lport->lp_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_lport_scr_resp() - Handle response to State Change Register (SCR) request
|
||||
* @sp: current sequence in SCR exchange
|
||||
@ -1338,6 +1433,123 @@ err:
|
||||
fc_lport_error(lport, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_lport_enter_ms() - management server commands
|
||||
* @lport: Fibre Channel local port to register
|
||||
*
|
||||
* Locking Note: The lport lock is expected to be held before calling
|
||||
* this routine.
|
||||
*/
|
||||
static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state)
|
||||
{
|
||||
struct fc_frame *fp;
|
||||
enum fc_fdmi_req cmd;
|
||||
int size = sizeof(struct fc_ct_hdr);
|
||||
size_t len;
|
||||
int numattrs;
|
||||
|
||||
FC_LPORT_DBG(lport, "Entered %s state from %s state\n",
|
||||
fc_lport_state_names[state],
|
||||
fc_lport_state(lport));
|
||||
|
||||
fc_lport_state_enter(lport, state);
|
||||
|
||||
switch (state) {
|
||||
case LPORT_ST_RHBA:
|
||||
cmd = FC_FDMI_RHBA;
|
||||
/* Number of HBA Attributes */
|
||||
numattrs = 10;
|
||||
len = sizeof(struct fc_fdmi_rhba);
|
||||
len -= sizeof(struct fc_fdmi_attr_entry);
|
||||
len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
|
||||
len += FC_FDMI_HBA_ATTR_NODENAME_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_MODEL_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN;
|
||||
len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN;
|
||||
|
||||
size += len;
|
||||
break;
|
||||
case LPORT_ST_RPA:
|
||||
cmd = FC_FDMI_RPA;
|
||||
/* Number of Port Attributes */
|
||||
numattrs = 6;
|
||||
len = sizeof(struct fc_fdmi_rpa);
|
||||
len -= sizeof(struct fc_fdmi_attr_entry);
|
||||
len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN);
|
||||
len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN;
|
||||
len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN;
|
||||
len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN;
|
||||
len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN;
|
||||
len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN;
|
||||
len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN;
|
||||
|
||||
size += len;
|
||||
break;
|
||||
case LPORT_ST_DPRT:
|
||||
cmd = FC_FDMI_DPRT;
|
||||
len = sizeof(struct fc_fdmi_dprt);
|
||||
size += len;
|
||||
break;
|
||||
case LPORT_ST_DHBA:
|
||||
cmd = FC_FDMI_DHBA;
|
||||
len = sizeof(struct fc_fdmi_dhba);
|
||||
size += len;
|
||||
break;
|
||||
default:
|
||||
fc_lport_error(lport, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
FC_LPORT_DBG(lport, "Cmd=0x%x Len %d size %d\n",
|
||||
cmd, (int)len, size);
|
||||
fp = fc_frame_alloc(lport, size);
|
||||
if (!fp) {
|
||||
fc_lport_error(lport, fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lport->tt.elsct_send(lport, FC_FID_MGMT_SERV, fp, cmd,
|
||||
fc_lport_ms_resp,
|
||||
lport, 3 * lport->r_a_tov))
|
||||
fc_lport_error(lport, fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_rport_enter_fdmi() - Create a fc_rport for the management server
|
||||
* @lport: The local port requesting a remote port for the management server
|
||||
*
|
||||
* Locking Note: The lport lock is expected to be held before calling
|
||||
* this routine.
|
||||
*/
|
||||
static void fc_lport_enter_fdmi(struct fc_lport *lport)
|
||||
{
|
||||
struct fc_rport_priv *rdata;
|
||||
|
||||
FC_LPORT_DBG(lport, "Entered FDMI state from %s state\n",
|
||||
fc_lport_state(lport));
|
||||
|
||||
fc_lport_state_enter(lport, LPORT_ST_FDMI);
|
||||
|
||||
mutex_lock(&lport->disc.disc_mutex);
|
||||
rdata = lport->tt.rport_create(lport, FC_FID_MGMT_SERV);
|
||||
mutex_unlock(&lport->disc.disc_mutex);
|
||||
if (!rdata)
|
||||
goto err;
|
||||
|
||||
rdata->ops = &fc_lport_rport_ops;
|
||||
lport->tt.rport_login(rdata);
|
||||
return;
|
||||
|
||||
err:
|
||||
fc_lport_error(lport, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_lport_timeout() - Handler for the retry_work timer
|
||||
* @work: The work struct of the local port
|
||||
@ -1371,6 +1583,15 @@ static void fc_lport_timeout(struct work_struct *work)
|
||||
case LPORT_ST_RFF_ID:
|
||||
fc_lport_enter_ns(lport, lport->state);
|
||||
break;
|
||||
case LPORT_ST_FDMI:
|
||||
fc_lport_enter_fdmi(lport);
|
||||
break;
|
||||
case LPORT_ST_RHBA:
|
||||
case LPORT_ST_RPA:
|
||||
case LPORT_ST_DHBA:
|
||||
case LPORT_ST_DPRT:
|
||||
fc_lport_enter_ms(lport, lport->state);
|
||||
break;
|
||||
case LPORT_ST_SCR:
|
||||
fc_lport_enter_scr(lport);
|
||||
break;
|
||||
|
@ -1909,6 +1909,16 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
|
||||
ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc);
|
||||
|
||||
spin_lock(&session->lock);
|
||||
task = (struct iscsi_task *)sc->SCp.ptr;
|
||||
if (!task) {
|
||||
/*
|
||||
* Raced with completion. Blk layer has taken ownership
|
||||
* so let timeout code complete it now.
|
||||
*/
|
||||
rc = BLK_EH_HANDLED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (session->state != ISCSI_STATE_LOGGED_IN) {
|
||||
/*
|
||||
* We are probably in the middle of iscsi recovery so let
|
||||
@ -1925,16 +1935,6 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
|
||||
goto done;
|
||||
}
|
||||
|
||||
task = (struct iscsi_task *)sc->SCp.ptr;
|
||||
if (!task) {
|
||||
/*
|
||||
* Raced with completion. Just reset timer, and let it
|
||||
* complete normally
|
||||
*/
|
||||
rc = BLK_EH_RESET_TIMER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have sent (at least queued to the network layer) a pdu or
|
||||
* recvd one for the task since the last timeout ask for
|
||||
@ -2807,6 +2807,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
|
||||
kfree(session->username);
|
||||
kfree(session->username_in);
|
||||
kfree(session->targetname);
|
||||
kfree(session->targetalias);
|
||||
kfree(session->initiatorname);
|
||||
kfree(session->ifacename);
|
||||
|
||||
@ -3200,7 +3201,7 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
||||
sscanf(buf, "%d", &session->initial_r2t_en);
|
||||
break;
|
||||
case ISCSI_PARAM_MAX_R2T:
|
||||
sscanf(buf, "%d", &session->max_r2t);
|
||||
sscanf(buf, "%hu", &session->max_r2t);
|
||||
break;
|
||||
case ISCSI_PARAM_IMM_DATA_EN:
|
||||
sscanf(buf, "%d", &session->imm_data_en);
|
||||
@ -3233,6 +3234,8 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
||||
return iscsi_switch_str_param(&session->password_in, buf);
|
||||
case ISCSI_PARAM_TARGET_NAME:
|
||||
return iscsi_switch_str_param(&session->targetname, buf);
|
||||
case ISCSI_PARAM_TARGET_ALIAS:
|
||||
return iscsi_switch_str_param(&session->targetalias, buf);
|
||||
case ISCSI_PARAM_TPGT:
|
||||
sscanf(buf, "%d", &session->tpgt);
|
||||
break;
|
||||
@ -3299,6 +3302,9 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
|
||||
case ISCSI_PARAM_TARGET_NAME:
|
||||
len = sprintf(buf, "%s\n", session->targetname);
|
||||
break;
|
||||
case ISCSI_PARAM_TARGET_ALIAS:
|
||||
len = sprintf(buf, "%s\n", session->targetalias);
|
||||
break;
|
||||
case ISCSI_PARAM_TPGT:
|
||||
len = sprintf(buf, "%d\n", session->tpgt);
|
||||
break;
|
||||
|
@ -1170,6 +1170,24 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free);
|
||||
|
||||
int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf)
|
||||
{
|
||||
struct iscsi_session *session = conn->session;
|
||||
unsigned short r2ts = 0;
|
||||
|
||||
sscanf(buf, "%hu", &r2ts);
|
||||
if (session->max_r2t == r2ts)
|
||||
return 0;
|
||||
|
||||
if (!r2ts || !is_power_of_2(r2ts))
|
||||
return -EINVAL;
|
||||
|
||||
session->max_r2t = r2ts;
|
||||
iscsi_tcp_r2tpool_free(session);
|
||||
return iscsi_tcp_r2tpool_alloc(session);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iscsi_tcp_set_max_r2t);
|
||||
|
||||
void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
|
||||
struct iscsi_stats *stats)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,29 +30,30 @@
|
||||
|
||||
#include <scsi/scsi_transport.h>
|
||||
#include <scsi/scsi_transport_sas.h>
|
||||
#include <scsi/sas_ata.h>
|
||||
#include "../scsi_sas_internal.h"
|
||||
|
||||
/* ---------- Basic task processing for discovery purposes ---------- */
|
||||
|
||||
void sas_init_dev(struct domain_device *dev)
|
||||
{
|
||||
INIT_LIST_HEAD(&dev->siblings);
|
||||
INIT_LIST_HEAD(&dev->dev_list_node);
|
||||
switch (dev->dev_type) {
|
||||
case SAS_END_DEV:
|
||||
break;
|
||||
case EDGE_DEV:
|
||||
case FANOUT_DEV:
|
||||
INIT_LIST_HEAD(&dev->ex_dev.children);
|
||||
break;
|
||||
case SATA_DEV:
|
||||
case SATA_PM:
|
||||
case SATA_PM_PORT:
|
||||
INIT_LIST_HEAD(&dev->sata_dev.children);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (dev->dev_type) {
|
||||
case SAS_END_DEV:
|
||||
break;
|
||||
case EDGE_DEV:
|
||||
case FANOUT_DEV:
|
||||
INIT_LIST_HEAD(&dev->ex_dev.children);
|
||||
mutex_init(&dev->ex_dev.cmd_mutex);
|
||||
break;
|
||||
case SATA_DEV:
|
||||
case SATA_PM:
|
||||
case SATA_PM_PORT:
|
||||
case SATA_PENDING:
|
||||
INIT_LIST_HEAD(&dev->sata_dev.children);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Domain device discovery ---------- */
|
||||
@ -68,19 +69,18 @@ void sas_init_dev(struct domain_device *dev)
|
||||
*/
|
||||
static int sas_get_port_device(struct asd_sas_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct asd_sas_phy *phy;
|
||||
struct sas_rphy *rphy;
|
||||
struct domain_device *dev;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
dev = sas_alloc_device();
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&port->phy_list_lock, flags);
|
||||
spin_lock_irq(&port->phy_list_lock);
|
||||
if (list_empty(&port->phy_list)) {
|
||||
spin_unlock_irqrestore(&port->phy_list_lock, flags);
|
||||
kfree(dev);
|
||||
spin_unlock_irq(&port->phy_list_lock);
|
||||
sas_put_device(dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el);
|
||||
@ -88,7 +88,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
|
||||
memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd),
|
||||
(size_t)phy->frame_rcvd_size));
|
||||
spin_unlock(&phy->frame_rcvd_lock);
|
||||
spin_unlock_irqrestore(&port->phy_list_lock, flags);
|
||||
spin_unlock_irq(&port->phy_list_lock);
|
||||
|
||||
if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) {
|
||||
struct dev_to_host_fis *fis =
|
||||
@ -130,9 +130,14 @@ static int sas_get_port_device(struct asd_sas_port *port)
|
||||
}
|
||||
|
||||
if (!rphy) {
|
||||
kfree(dev);
|
||||
sas_put_device(dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
spin_lock_irq(&port->phy_list_lock);
|
||||
list_for_each_entry(phy, &port->phy_list, port_phy_el)
|
||||
sas_phy_set_target(phy, dev);
|
||||
spin_unlock_irq(&port->phy_list_lock);
|
||||
rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
|
||||
memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);
|
||||
sas_fill_in_rphy(dev, rphy);
|
||||
@ -147,11 +152,17 @@ static int sas_get_port_device(struct asd_sas_port *port)
|
||||
memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
|
||||
memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
|
||||
port->disc.max_level = 0;
|
||||
sas_device_set_phy(dev, port->port);
|
||||
|
||||
dev->rphy = rphy;
|
||||
spin_lock_irq(&port->dev_list_lock);
|
||||
list_add_tail(&dev->dev_list_node, &port->dev_list);
|
||||
spin_unlock_irq(&port->dev_list_lock);
|
||||
|
||||
if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV)
|
||||
list_add_tail(&dev->disco_list_node, &port->disco_list);
|
||||
else {
|
||||
spin_lock_irq(&port->dev_list_lock);
|
||||
list_add_tail(&dev->dev_list_node, &port->dev_list);
|
||||
spin_unlock_irq(&port->dev_list_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -173,6 +184,7 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
|
||||
dev_name(sas_ha->dev),
|
||||
SAS_ADDR(dev->sas_addr), res);
|
||||
}
|
||||
kref_get(&dev->kref);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -184,12 +196,40 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
|
||||
struct Scsi_Host *shost = sas_ha->core.shost;
|
||||
struct sas_internal *i = to_sas_internal(shost->transportt);
|
||||
|
||||
if (i->dft->lldd_dev_gone)
|
||||
if (i->dft->lldd_dev_gone) {
|
||||
i->dft->lldd_dev_gone(dev);
|
||||
sas_put_device(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Common/dispatchers ---------- */
|
||||
static void sas_probe_devices(struct work_struct *work)
|
||||
{
|
||||
struct domain_device *dev, *n;
|
||||
struct sas_discovery_event *ev =
|
||||
container_of(work, struct sas_discovery_event, work);
|
||||
struct asd_sas_port *port = ev->port;
|
||||
|
||||
clear_bit(DISCE_PROBE, &port->disc.pending);
|
||||
|
||||
/* devices must be domain members before link recovery and probe */
|
||||
list_for_each_entry(dev, &port->disco_list, disco_list_node) {
|
||||
spin_lock_irq(&port->dev_list_lock);
|
||||
list_add_tail(&dev->dev_list_node, &port->dev_list);
|
||||
spin_unlock_irq(&port->dev_list_lock);
|
||||
}
|
||||
|
||||
sas_probe_sata(port);
|
||||
|
||||
list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
|
||||
int err;
|
||||
|
||||
err = sas_rphy_add(dev->rphy);
|
||||
if (err)
|
||||
sas_fail_probe(dev, __func__, err);
|
||||
else
|
||||
list_del_init(&dev->disco_list_node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sas_discover_end_dev -- discover an end device (SSP, etc)
|
||||
@ -203,22 +243,36 @@ int sas_discover_end_dev(struct domain_device *dev)
|
||||
|
||||
res = sas_notify_lldd_dev_found(dev);
|
||||
if (res)
|
||||
goto out_err2;
|
||||
|
||||
res = sas_rphy_add(dev->rphy);
|
||||
if (res)
|
||||
goto out_err;
|
||||
return res;
|
||||
sas_discover_event(dev->port, DISCE_PROBE);
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
sas_notify_lldd_dev_gone(dev);
|
||||
out_err2:
|
||||
return res;
|
||||
}
|
||||
|
||||
/* ---------- Device registration and unregistration ---------- */
|
||||
|
||||
void sas_free_device(struct kref *kref)
|
||||
{
|
||||
struct domain_device *dev = container_of(kref, typeof(*dev), kref);
|
||||
|
||||
if (dev->parent)
|
||||
sas_put_device(dev->parent);
|
||||
|
||||
sas_port_put_phy(dev->phy);
|
||||
dev->phy = NULL;
|
||||
|
||||
/* remove the phys and ports, everything else should be gone */
|
||||
if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV)
|
||||
kfree(dev->ex_dev.ex_phy);
|
||||
|
||||
if (dev_is_sata(dev) && dev->sata_dev.ap) {
|
||||
ata_sas_port_destroy(dev->sata_dev.ap);
|
||||
dev->sata_dev.ap = NULL;
|
||||
}
|
||||
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev)
|
||||
{
|
||||
sas_notify_lldd_dev_gone(dev);
|
||||
@ -230,34 +284,84 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d
|
||||
spin_lock_irq(&port->dev_list_lock);
|
||||
list_del_init(&dev->dev_list_node);
|
||||
spin_unlock_irq(&port->dev_list_lock);
|
||||
|
||||
sas_put_device(dev);
|
||||
}
|
||||
|
||||
static void sas_destruct_devices(struct work_struct *work)
|
||||
{
|
||||
struct domain_device *dev, *n;
|
||||
struct sas_discovery_event *ev =
|
||||
container_of(work, struct sas_discovery_event, work);
|
||||
struct asd_sas_port *port = ev->port;
|
||||
|
||||
clear_bit(DISCE_DESTRUCT, &port->disc.pending);
|
||||
|
||||
list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) {
|
||||
list_del_init(&dev->disco_list_node);
|
||||
|
||||
sas_remove_children(&dev->rphy->dev);
|
||||
sas_rphy_delete(dev->rphy);
|
||||
dev->rphy = NULL;
|
||||
sas_unregister_common_dev(port, dev);
|
||||
}
|
||||
}
|
||||
|
||||
void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
|
||||
{
|
||||
if (dev->rphy) {
|
||||
sas_remove_children(&dev->rphy->dev);
|
||||
sas_rphy_delete(dev->rphy);
|
||||
if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
|
||||
!list_empty(&dev->disco_list_node)) {
|
||||
/* this rphy never saw sas_rphy_add */
|
||||
list_del_init(&dev->disco_list_node);
|
||||
sas_rphy_free(dev->rphy);
|
||||
dev->rphy = NULL;
|
||||
sas_unregister_common_dev(port, dev);
|
||||
}
|
||||
if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
|
||||
/* remove the phys and ports, everything else should be gone */
|
||||
kfree(dev->ex_dev.ex_phy);
|
||||
dev->ex_dev.ex_phy = NULL;
|
||||
|
||||
if (dev->rphy && !test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
|
||||
sas_rphy_unlink(dev->rphy);
|
||||
list_move_tail(&dev->disco_list_node, &port->destroy_list);
|
||||
sas_discover_event(dev->port, DISCE_DESTRUCT);
|
||||
}
|
||||
sas_unregister_common_dev(port, dev);
|
||||
}
|
||||
|
||||
void sas_unregister_domain_devices(struct asd_sas_port *port)
|
||||
void sas_unregister_domain_devices(struct asd_sas_port *port, int gone)
|
||||
{
|
||||
struct domain_device *dev, *n;
|
||||
|
||||
list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node)
|
||||
list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) {
|
||||
if (gone)
|
||||
set_bit(SAS_DEV_GONE, &dev->state);
|
||||
sas_unregister_dev(port, dev);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node)
|
||||
sas_unregister_dev(port, dev);
|
||||
|
||||
port->port->rphy = NULL;
|
||||
|
||||
}
|
||||
|
||||
void sas_device_set_phy(struct domain_device *dev, struct sas_port *port)
|
||||
{
|
||||
struct sas_ha_struct *ha;
|
||||
struct sas_phy *new_phy;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
ha = dev->port->ha;
|
||||
new_phy = sas_port_get_phy(port);
|
||||
|
||||
/* pin and record last seen phy */
|
||||
spin_lock_irq(&ha->phy_port_lock);
|
||||
if (new_phy) {
|
||||
sas_port_put_phy(dev->phy);
|
||||
dev->phy = new_phy;
|
||||
}
|
||||
spin_unlock_irq(&ha->phy_port_lock);
|
||||
}
|
||||
|
||||
/* ---------- Discovery and Revalidation ---------- */
|
||||
|
||||
/**
|
||||
@ -277,8 +381,7 @@ static void sas_discover_domain(struct work_struct *work)
|
||||
container_of(work, struct sas_discovery_event, work);
|
||||
struct asd_sas_port *port = ev->port;
|
||||
|
||||
sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock,
|
||||
&port->disc.pending);
|
||||
clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending);
|
||||
|
||||
if (port->port_dev)
|
||||
return;
|
||||
@ -318,11 +421,12 @@ static void sas_discover_domain(struct work_struct *work)
|
||||
sas_rphy_free(dev->rphy);
|
||||
dev->rphy = NULL;
|
||||
|
||||
list_del_init(&dev->disco_list_node);
|
||||
spin_lock_irq(&port->dev_list_lock);
|
||||
list_del_init(&dev->dev_list_node);
|
||||
spin_unlock_irq(&port->dev_list_lock);
|
||||
|
||||
kfree(dev); /* not kobject_register-ed yet */
|
||||
sas_put_device(dev);
|
||||
port->port_dev = NULL;
|
||||
}
|
||||
|
||||
@ -336,21 +440,51 @@ static void sas_revalidate_domain(struct work_struct *work)
|
||||
struct sas_discovery_event *ev =
|
||||
container_of(work, struct sas_discovery_event, work);
|
||||
struct asd_sas_port *port = ev->port;
|
||||
struct sas_ha_struct *ha = port->ha;
|
||||
|
||||
sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock,
|
||||
&port->disc.pending);
|
||||
/* prevent revalidation from finding sata links in recovery */
|
||||
mutex_lock(&ha->disco_mutex);
|
||||
if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) {
|
||||
SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n",
|
||||
port->id, task_pid_nr(current));
|
||||
goto out;
|
||||
}
|
||||
|
||||
clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending);
|
||||
|
||||
SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
|
||||
task_pid_nr(current));
|
||||
|
||||
if (port->port_dev)
|
||||
res = sas_ex_revalidate_domain(port->port_dev);
|
||||
|
||||
SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
|
||||
port->id, task_pid_nr(current), res);
|
||||
out:
|
||||
mutex_unlock(&ha->disco_mutex);
|
||||
}
|
||||
|
||||
/* ---------- Events ---------- */
|
||||
|
||||
static void sas_chain_work(struct sas_ha_struct *ha, struct work_struct *work)
|
||||
{
|
||||
/* chained work is not subject to SA_HA_DRAINING or SAS_HA_REGISTERED */
|
||||
scsi_queue_work(ha->core.shost, work);
|
||||
}
|
||||
|
||||
static void sas_chain_event(int event, unsigned long *pending,
|
||||
struct work_struct *work,
|
||||
struct sas_ha_struct *ha)
|
||||
{
|
||||
if (!test_and_set_bit(event, pending)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ha->state_lock, flags);
|
||||
sas_chain_work(ha, work);
|
||||
spin_unlock_irqrestore(&ha->state_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
|
||||
{
|
||||
struct sas_discovery *disc;
|
||||
@ -361,8 +495,7 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
|
||||
|
||||
BUG_ON(ev >= DISC_NUM_EVENTS);
|
||||
|
||||
sas_queue_event(ev, &disc->disc_event_lock, &disc->pending,
|
||||
&disc->disc_work[ev].work, port->ha);
|
||||
sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -380,9 +513,10 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
|
||||
static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
|
||||
[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
|
||||
[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
|
||||
[DISCE_PROBE] = sas_probe_devices,
|
||||
[DISCE_DESTRUCT] = sas_destruct_devices,
|
||||
};
|
||||
|
||||
spin_lock_init(&disc->disc_event_lock);
|
||||
disc->pending = 0;
|
||||
for (i = 0; i < DISC_NUM_EVENTS; i++) {
|
||||
INIT_WORK(&disc->disc_work[i].work, sas_event_fns[i]);
|
||||
|
@ -22,15 +22,103 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "sas_internal.h"
|
||||
#include "sas_dump.h"
|
||||
|
||||
void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work)
|
||||
{
|
||||
if (!test_bit(SAS_HA_REGISTERED, &ha->state))
|
||||
return;
|
||||
|
||||
if (test_bit(SAS_HA_DRAINING, &ha->state))
|
||||
list_add(&work->entry, &ha->defer_q);
|
||||
else
|
||||
scsi_queue_work(ha->core.shost, work);
|
||||
}
|
||||
|
||||
static void sas_queue_event(int event, unsigned long *pending,
|
||||
struct work_struct *work,
|
||||
struct sas_ha_struct *ha)
|
||||
{
|
||||
if (!test_and_set_bit(event, pending)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ha->state_lock, flags);
|
||||
sas_queue_work(ha, work);
|
||||
spin_unlock_irqrestore(&ha->state_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void __sas_drain_work(struct sas_ha_struct *ha)
|
||||
{
|
||||
struct workqueue_struct *wq = ha->core.shost->work_q;
|
||||
struct work_struct *w, *_w;
|
||||
|
||||
set_bit(SAS_HA_DRAINING, &ha->state);
|
||||
/* flush submitters */
|
||||
spin_lock_irq(&ha->state_lock);
|
||||
spin_unlock_irq(&ha->state_lock);
|
||||
|
||||
drain_workqueue(wq);
|
||||
|
||||
spin_lock_irq(&ha->state_lock);
|
||||
clear_bit(SAS_HA_DRAINING, &ha->state);
|
||||
list_for_each_entry_safe(w, _w, &ha->defer_q, entry) {
|
||||
list_del_init(&w->entry);
|
||||
sas_queue_work(ha, w);
|
||||
}
|
||||
spin_unlock_irq(&ha->state_lock);
|
||||
}
|
||||
|
||||
int sas_drain_work(struct sas_ha_struct *ha)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&ha->drain_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
if (test_bit(SAS_HA_REGISTERED, &ha->state))
|
||||
__sas_drain_work(ha);
|
||||
mutex_unlock(&ha->drain_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sas_drain_work);
|
||||
|
||||
void sas_disable_revalidation(struct sas_ha_struct *ha)
|
||||
{
|
||||
mutex_lock(&ha->disco_mutex);
|
||||
set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
|
||||
mutex_unlock(&ha->disco_mutex);
|
||||
}
|
||||
|
||||
void sas_enable_revalidation(struct sas_ha_struct *ha)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&ha->disco_mutex);
|
||||
clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state);
|
||||
for (i = 0; i < ha->num_phys; i++) {
|
||||
struct asd_sas_port *port = ha->sas_port[i];
|
||||
const int ev = DISCE_REVALIDATE_DOMAIN;
|
||||
struct sas_discovery *d = &port->disc;
|
||||
|
||||
if (!test_and_clear_bit(ev, &d->pending))
|
||||
continue;
|
||||
|
||||
sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha);
|
||||
}
|
||||
mutex_unlock(&ha->disco_mutex);
|
||||
}
|
||||
|
||||
static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
|
||||
{
|
||||
BUG_ON(event >= HA_NUM_EVENTS);
|
||||
|
||||
sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending,
|
||||
sas_queue_event(event, &sas_ha->pending,
|
||||
&sas_ha->ha_events[event].work, sas_ha);
|
||||
}
|
||||
|
||||
@ -40,7 +128,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
|
||||
|
||||
BUG_ON(event >= PORT_NUM_EVENTS);
|
||||
|
||||
sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
|
||||
sas_queue_event(event, &phy->port_events_pending,
|
||||
&phy->port_events[event].work, ha);
|
||||
}
|
||||
|
||||
@ -50,7 +138,7 @@ static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
|
||||
|
||||
BUG_ON(event >= PHY_NUM_EVENTS);
|
||||
|
||||
sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
|
||||
sas_queue_event(event, &phy->phy_events_pending,
|
||||
&phy->phy_events[event].work, ha);
|
||||
}
|
||||
|
||||
@ -62,8 +150,6 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
|
||||
|
||||
int i;
|
||||
|
||||
spin_lock_init(&sas_ha->event_lock);
|
||||
|
||||
for (i = 0; i < HA_NUM_EVENTS; i++) {
|
||||
INIT_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]);
|
||||
sas_ha->ha_events[i].ha = sas_ha;
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "sas_internal.h"
|
||||
|
||||
#include <scsi/sas_ata.h>
|
||||
#include <scsi/scsi_transport.h>
|
||||
#include <scsi/scsi_transport_sas.h>
|
||||
#include "../scsi_sas_internal.h"
|
||||
@ -71,11 +72,18 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
|
||||
struct sas_internal *i =
|
||||
to_sas_internal(dev->port->ha->core.shost->transportt);
|
||||
|
||||
mutex_lock(&dev->ex_dev.cmd_mutex);
|
||||
for (retry = 0; retry < 3; retry++) {
|
||||
task = sas_alloc_task(GFP_KERNEL);
|
||||
if (!task)
|
||||
return -ENOMEM;
|
||||
if (test_bit(SAS_DEV_GONE, &dev->state)) {
|
||||
res = -ECOMM;
|
||||
break;
|
||||
}
|
||||
|
||||
task = sas_alloc_task(GFP_KERNEL);
|
||||
if (!task) {
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
task->dev = dev;
|
||||
task->task_proto = dev->tproto;
|
||||
sg_init_one(&task->smp_task.smp_req, req, req_size);
|
||||
@ -93,7 +101,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
|
||||
if (res) {
|
||||
del_timer(&task->timer);
|
||||
SAS_DPRINTK("executing SMP task failed:%d\n", res);
|
||||
goto ex_err;
|
||||
break;
|
||||
}
|
||||
|
||||
wait_for_completion(&task->completion);
|
||||
@ -103,24 +111,30 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
|
||||
i->dft->lldd_abort_task(task);
|
||||
if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
|
||||
SAS_DPRINTK("SMP task aborted and not done\n");
|
||||
goto ex_err;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
||||
task->task_status.stat == SAM_STAT_GOOD) {
|
||||
res = 0;
|
||||
break;
|
||||
} if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
||||
task->task_status.stat == SAS_DATA_UNDERRUN) {
|
||||
}
|
||||
if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
||||
task->task_status.stat == SAS_DATA_UNDERRUN) {
|
||||
/* no error, but return the number of bytes of
|
||||
* underrun */
|
||||
res = task->task_status.residual;
|
||||
break;
|
||||
} if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
||||
task->task_status.stat == SAS_DATA_OVERRUN) {
|
||||
}
|
||||
if (task->task_status.resp == SAS_TASK_COMPLETE &&
|
||||
task->task_status.stat == SAS_DATA_OVERRUN) {
|
||||
res = -EMSGSIZE;
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
if (task->task_status.resp == SAS_TASK_UNDELIVERED &&
|
||||
task->task_status.stat == SAS_DEVICE_UNKNOWN)
|
||||
break;
|
||||
else {
|
||||
SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
|
||||
"status 0x%x\n", __func__,
|
||||
SAS_ADDR(dev->sas_addr),
|
||||
@ -130,11 +144,10 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
|
||||
task = NULL;
|
||||
}
|
||||
}
|
||||
ex_err:
|
||||
mutex_unlock(&dev->ex_dev.cmd_mutex);
|
||||
|
||||
BUG_ON(retry == 3 && task != NULL);
|
||||
if (task != NULL) {
|
||||
sas_free_task(task);
|
||||
}
|
||||
sas_free_task(task);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -153,19 +166,49 @@ static inline void *alloc_smp_resp(int size)
|
||||
return kzalloc(size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/* ---------- Expander configuration ---------- */
|
||||
|
||||
static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
|
||||
void *disc_resp)
|
||||
static char sas_route_char(struct domain_device *dev, struct ex_phy *phy)
|
||||
{
|
||||
switch (phy->routing_attr) {
|
||||
case TABLE_ROUTING:
|
||||
if (dev->ex_dev.t2t_supp)
|
||||
return 'U';
|
||||
else
|
||||
return 'T';
|
||||
case DIRECT_ROUTING:
|
||||
return 'D';
|
||||
case SUBTRACTIVE_ROUTING:
|
||||
return 'S';
|
||||
default:
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
static enum sas_dev_type to_dev_type(struct discover_resp *dr)
|
||||
{
|
||||
/* This is detecting a failure to transmit initial dev to host
|
||||
* FIS as described in section J.5 of sas-2 r16
|
||||
*/
|
||||
if (dr->attached_dev_type == NO_DEVICE && dr->attached_sata_dev &&
|
||||
dr->linkrate >= SAS_LINK_RATE_1_5_GBPS)
|
||||
return SATA_PENDING;
|
||||
else
|
||||
return dr->attached_dev_type;
|
||||
}
|
||||
|
||||
static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
|
||||
{
|
||||
enum sas_dev_type dev_type;
|
||||
enum sas_linkrate linkrate;
|
||||
u8 sas_addr[SAS_ADDR_SIZE];
|
||||
struct smp_resp *resp = rsp;
|
||||
struct discover_resp *dr = &resp->disc;
|
||||
struct expander_device *ex = &dev->ex_dev;
|
||||
struct ex_phy *phy = &ex->ex_phy[phy_id];
|
||||
struct smp_resp *resp = disc_resp;
|
||||
struct discover_resp *dr = &resp->disc;
|
||||
struct sas_rphy *rphy = dev->rphy;
|
||||
int rediscover = (phy->phy != NULL);
|
||||
bool new_phy = !phy->phy;
|
||||
char *type;
|
||||
|
||||
if (!rediscover) {
|
||||
if (new_phy) {
|
||||
phy->phy = sas_phy_alloc(&rphy->dev, phy_id);
|
||||
|
||||
/* FIXME: error_handling */
|
||||
@ -184,8 +227,13 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
|
||||
break;
|
||||
}
|
||||
|
||||
/* check if anything important changed to squelch debug */
|
||||
dev_type = phy->attached_dev_type;
|
||||
linkrate = phy->linkrate;
|
||||
memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
|
||||
|
||||
phy->attached_dev_type = to_dev_type(dr);
|
||||
phy->phy_id = phy_id;
|
||||
phy->attached_dev_type = dr->attached_dev_type;
|
||||
phy->linkrate = dr->linkrate;
|
||||
phy->attached_sata_host = dr->attached_sata_host;
|
||||
phy->attached_sata_dev = dr->attached_sata_dev;
|
||||
@ -200,9 +248,11 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
|
||||
phy->last_da_index = -1;
|
||||
|
||||
phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr);
|
||||
phy->phy->identify.device_type = phy->attached_dev_type;
|
||||
phy->phy->identify.device_type = dr->attached_dev_type;
|
||||
phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
|
||||
phy->phy->identify.target_port_protocols = phy->attached_tproto;
|
||||
if (!phy->attached_tproto && dr->attached_sata_dev)
|
||||
phy->phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
|
||||
phy->phy->identify.phy_identifier = phy_id;
|
||||
phy->phy->minimum_linkrate_hw = dr->hmin_linkrate;
|
||||
phy->phy->maximum_linkrate_hw = dr->hmax_linkrate;
|
||||
@ -210,20 +260,76 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
|
||||
phy->phy->maximum_linkrate = dr->pmax_linkrate;
|
||||
phy->phy->negotiated_linkrate = phy->linkrate;
|
||||
|
||||
if (!rediscover)
|
||||
if (new_phy)
|
||||
if (sas_phy_add(phy->phy)) {
|
||||
sas_phy_free(phy->phy);
|
||||
return;
|
||||
}
|
||||
|
||||
SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n",
|
||||
SAS_ADDR(dev->sas_addr), phy->phy_id,
|
||||
phy->routing_attr == TABLE_ROUTING ? 'T' :
|
||||
phy->routing_attr == DIRECT_ROUTING ? 'D' :
|
||||
phy->routing_attr == SUBTRACTIVE_ROUTING ? 'S' : '?',
|
||||
SAS_ADDR(phy->attached_sas_addr));
|
||||
switch (phy->attached_dev_type) {
|
||||
case SATA_PENDING:
|
||||
type = "stp pending";
|
||||
break;
|
||||
case NO_DEVICE:
|
||||
type = "no device";
|
||||
break;
|
||||
case SAS_END_DEV:
|
||||
if (phy->attached_iproto) {
|
||||
if (phy->attached_tproto)
|
||||
type = "host+target";
|
||||
else
|
||||
type = "host";
|
||||
} else {
|
||||
if (dr->attached_sata_dev)
|
||||
type = "stp";
|
||||
else
|
||||
type = "ssp";
|
||||
}
|
||||
break;
|
||||
case EDGE_DEV:
|
||||
case FANOUT_DEV:
|
||||
type = "smp";
|
||||
break;
|
||||
default:
|
||||
type = "unknown";
|
||||
}
|
||||
|
||||
return;
|
||||
/* this routine is polled by libata error recovery so filter
|
||||
* unimportant messages
|
||||
*/
|
||||
if (new_phy || phy->attached_dev_type != dev_type ||
|
||||
phy->linkrate != linkrate ||
|
||||
SAS_ADDR(phy->attached_sas_addr) != SAS_ADDR(sas_addr))
|
||||
/* pass */;
|
||||
else
|
||||
return;
|
||||
|
||||
SAS_DPRINTK("ex %016llx phy%02d:%c:%X attached: %016llx (%s)\n",
|
||||
SAS_ADDR(dev->sas_addr), phy->phy_id,
|
||||
sas_route_char(dev, phy), phy->linkrate,
|
||||
SAS_ADDR(phy->attached_sas_addr), type);
|
||||
}
|
||||
|
||||
/* check if we have an existing attached ata device on this expander phy */
|
||||
struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
|
||||
{
|
||||
struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id];
|
||||
struct domain_device *dev;
|
||||
struct sas_rphy *rphy;
|
||||
|
||||
if (!ex_phy->port)
|
||||
return NULL;
|
||||
|
||||
rphy = ex_phy->port->rphy;
|
||||
if (!rphy)
|
||||
return NULL;
|
||||
|
||||
dev = sas_find_dev_by_rphy(rphy);
|
||||
|
||||
if (dev && dev_is_sata(dev))
|
||||
return dev;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define DISCOVER_REQ_SIZE 16
|
||||
@ -232,39 +338,25 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
|
||||
static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
|
||||
u8 *disc_resp, int single)
|
||||
{
|
||||
int i, res;
|
||||
struct discover_resp *dr;
|
||||
int res;
|
||||
|
||||
disc_req[9] = single;
|
||||
for (i = 1 ; i < 3; i++) {
|
||||
struct discover_resp *dr;
|
||||
|
||||
res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
|
||||
disc_resp, DISCOVER_RESP_SIZE);
|
||||
if (res)
|
||||
return res;
|
||||
/* This is detecting a failure to transmit initial
|
||||
* dev to host FIS as described in section G.5 of
|
||||
* sas-2 r 04b */
|
||||
dr = &((struct smp_resp *)disc_resp)->disc;
|
||||
if (memcmp(dev->sas_addr, dr->attached_sas_addr,
|
||||
SAS_ADDR_SIZE) == 0) {
|
||||
sas_printk("Found loopback topology, just ignore it!\n");
|
||||
return 0;
|
||||
}
|
||||
if (!(dr->attached_dev_type == 0 &&
|
||||
dr->attached_sata_dev))
|
||||
break;
|
||||
/* In order to generate the dev to host FIS, we
|
||||
* send a link reset to the expander port */
|
||||
sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL);
|
||||
/* Wait for the reset to trigger the negotiation */
|
||||
msleep(500);
|
||||
res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
|
||||
disc_resp, DISCOVER_RESP_SIZE);
|
||||
if (res)
|
||||
return res;
|
||||
dr = &((struct smp_resp *)disc_resp)->disc;
|
||||
if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) {
|
||||
sas_printk("Found loopback topology, just ignore it!\n");
|
||||
return 0;
|
||||
}
|
||||
sas_set_ex_phy(dev, single, disc_resp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sas_ex_phy_discover(struct domain_device *dev, int single)
|
||||
int sas_ex_phy_discover(struct domain_device *dev, int single)
|
||||
{
|
||||
struct expander_device *ex = &dev->ex_dev;
|
||||
int res = 0;
|
||||
@ -569,9 +661,8 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
|
||||
#define RPS_REQ_SIZE 16
|
||||
#define RPS_RESP_SIZE 60
|
||||
|
||||
static int sas_get_report_phy_sata(struct domain_device *dev,
|
||||
int phy_id,
|
||||
struct smp_resp *rps_resp)
|
||||
int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
|
||||
struct smp_resp *rps_resp)
|
||||
{
|
||||
int res;
|
||||
u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
|
||||
@ -657,10 +748,11 @@ static struct domain_device *sas_ex_discover_end_dev(
|
||||
if (phy->attached_sata_host || phy->attached_sata_ps)
|
||||
return NULL;
|
||||
|
||||
child = kzalloc(sizeof(*child), GFP_KERNEL);
|
||||
child = sas_alloc_device();
|
||||
if (!child)
|
||||
return NULL;
|
||||
|
||||
kref_get(&parent->kref);
|
||||
child->parent = parent;
|
||||
child->port = parent->port;
|
||||
child->iproto = phy->attached_iproto;
|
||||
@ -676,24 +768,13 @@ static struct domain_device *sas_ex_discover_end_dev(
|
||||
}
|
||||
}
|
||||
sas_ex_get_linkrate(parent, child, phy);
|
||||
sas_device_set_phy(child, phy->port);
|
||||
|
||||
#ifdef CONFIG_SCSI_SAS_ATA
|
||||
if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
|
||||
child->dev_type = SATA_DEV;
|
||||
if (phy->attached_tproto & SAS_PROTOCOL_STP)
|
||||
child->tproto = phy->attached_tproto;
|
||||
if (phy->attached_sata_dev)
|
||||
child->tproto |= SATA_DEV;
|
||||
res = sas_get_report_phy_sata(parent, phy_id,
|
||||
&child->sata_dev.rps_resp);
|
||||
if (res) {
|
||||
SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
|
||||
"0x%x\n", SAS_ADDR(parent->sas_addr),
|
||||
phy_id, res);
|
||||
res = sas_get_ata_info(child, phy);
|
||||
if (res)
|
||||
goto out_free;
|
||||
}
|
||||
memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
|
||||
sizeof(struct dev_to_host_fis));
|
||||
|
||||
rphy = sas_end_device_alloc(phy->port);
|
||||
if (unlikely(!rphy))
|
||||
@ -703,9 +784,7 @@ static struct domain_device *sas_ex_discover_end_dev(
|
||||
|
||||
child->rphy = rphy;
|
||||
|
||||
spin_lock_irq(&parent->port->dev_list_lock);
|
||||
list_add_tail(&child->dev_list_node, &parent->port->dev_list);
|
||||
spin_unlock_irq(&parent->port->dev_list_lock);
|
||||
list_add_tail(&child->disco_list_node, &parent->port->disco_list);
|
||||
|
||||
res = sas_discover_sata(child);
|
||||
if (res) {
|
||||
@ -729,9 +808,7 @@ static struct domain_device *sas_ex_discover_end_dev(
|
||||
child->rphy = rphy;
|
||||
sas_fill_in_rphy(child, rphy);
|
||||
|
||||
spin_lock_irq(&parent->port->dev_list_lock);
|
||||
list_add_tail(&child->dev_list_node, &parent->port->dev_list);
|
||||
spin_unlock_irq(&parent->port->dev_list_lock);
|
||||
list_add_tail(&child->disco_list_node, &parent->port->disco_list);
|
||||
|
||||
res = sas_discover_end_dev(child);
|
||||
if (res) {
|
||||
@ -755,6 +832,7 @@ static struct domain_device *sas_ex_discover_end_dev(
|
||||
sas_rphy_free(child->rphy);
|
||||
child->rphy = NULL;
|
||||
|
||||
list_del(&child->disco_list_node);
|
||||
spin_lock_irq(&parent->port->dev_list_lock);
|
||||
list_del(&child->dev_list_node);
|
||||
spin_unlock_irq(&parent->port->dev_list_lock);
|
||||
@ -762,7 +840,7 @@ static struct domain_device *sas_ex_discover_end_dev(
|
||||
sas_port_delete(phy->port);
|
||||
out_err:
|
||||
phy->port = NULL;
|
||||
kfree(child);
|
||||
sas_put_device(child);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -809,7 +887,7 @@ static struct domain_device *sas_ex_discover_expander(
|
||||
phy->attached_phy_id);
|
||||
return NULL;
|
||||
}
|
||||
child = kzalloc(sizeof(*child), GFP_KERNEL);
|
||||
child = sas_alloc_device();
|
||||
if (!child)
|
||||
return NULL;
|
||||
|
||||
@ -835,6 +913,7 @@ static struct domain_device *sas_ex_discover_expander(
|
||||
child->rphy = rphy;
|
||||
edev = rphy_to_expander_device(rphy);
|
||||
child->dev_type = phy->attached_dev_type;
|
||||
kref_get(&parent->kref);
|
||||
child->parent = parent;
|
||||
child->port = port;
|
||||
child->iproto = phy->attached_iproto;
|
||||
@ -858,7 +937,7 @@ static struct domain_device *sas_ex_discover_expander(
|
||||
spin_lock_irq(&parent->port->dev_list_lock);
|
||||
list_del(&child->dev_list_node);
|
||||
spin_unlock_irq(&parent->port->dev_list_lock);
|
||||
kfree(child);
|
||||
sas_put_device(child);
|
||||
return NULL;
|
||||
}
|
||||
list_add_tail(&child->siblings, &parent->ex_dev.children);
|
||||
@ -908,7 +987,8 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
|
||||
|
||||
if (ex_phy->attached_dev_type != SAS_END_DEV &&
|
||||
ex_phy->attached_dev_type != FANOUT_DEV &&
|
||||
ex_phy->attached_dev_type != EDGE_DEV) {
|
||||
ex_phy->attached_dev_type != EDGE_DEV &&
|
||||
ex_phy->attached_dev_type != SATA_PENDING) {
|
||||
SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx "
|
||||
"phy 0x%x\n", ex_phy->attached_dev_type,
|
||||
SAS_ADDR(dev->sas_addr),
|
||||
@ -934,6 +1014,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
|
||||
|
||||
switch (ex_phy->attached_dev_type) {
|
||||
case SAS_END_DEV:
|
||||
case SATA_PENDING:
|
||||
child = sas_ex_discover_end_dev(dev, phy_id);
|
||||
break;
|
||||
case FANOUT_DEV:
|
||||
@ -1128,32 +1209,25 @@ static void sas_print_parent_topology_bug(struct domain_device *child,
|
||||
struct ex_phy *parent_phy,
|
||||
struct ex_phy *child_phy)
|
||||
{
|
||||
static const char ra_char[] = {
|
||||
[DIRECT_ROUTING] = 'D',
|
||||
[SUBTRACTIVE_ROUTING] = 'S',
|
||||
[TABLE_ROUTING] = 'T',
|
||||
};
|
||||
static const char *ex_type[] = {
|
||||
[EDGE_DEV] = "edge",
|
||||
[FANOUT_DEV] = "fanout",
|
||||
};
|
||||
struct domain_device *parent = child->parent;
|
||||
|
||||
sas_printk("%s ex %016llx (T2T supp:%d) phy 0x%x <--> %s ex %016llx "
|
||||
"(T2T supp:%d) phy 0x%x has %c:%c routing link!\n",
|
||||
sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx "
|
||||
"phy 0x%x has %c:%c routing link!\n",
|
||||
|
||||
ex_type[parent->dev_type],
|
||||
SAS_ADDR(parent->sas_addr),
|
||||
parent->ex_dev.t2t_supp,
|
||||
parent_phy->phy_id,
|
||||
|
||||
ex_type[child->dev_type],
|
||||
SAS_ADDR(child->sas_addr),
|
||||
child->ex_dev.t2t_supp,
|
||||
child_phy->phy_id,
|
||||
|
||||
ra_char[parent_phy->routing_attr],
|
||||
ra_char[child_phy->routing_attr]);
|
||||
sas_route_char(parent, parent_phy),
|
||||
sas_route_char(child, child_phy));
|
||||
}
|
||||
|
||||
static int sas_check_eeds(struct domain_device *child,
|
||||
@ -1610,8 +1684,8 @@ static int sas_get_phy_change_count(struct domain_device *dev,
|
||||
return res;
|
||||
}
|
||||
|
||||
static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
|
||||
int phy_id, u8 *attached_sas_addr)
|
||||
static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
|
||||
u8 *sas_addr, enum sas_dev_type *type)
|
||||
{
|
||||
int res;
|
||||
struct smp_resp *disc_resp;
|
||||
@ -1623,10 +1697,11 @@ static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
|
||||
dr = &disc_resp->disc;
|
||||
|
||||
res = sas_get_phy_discover(dev, phy_id, disc_resp);
|
||||
if (!res) {
|
||||
memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8);
|
||||
if (dr->attached_dev_type == 0)
|
||||
memset(attached_sas_addr, 0, 8);
|
||||
if (res == 0) {
|
||||
memcpy(sas_addr, disc_resp->disc.attached_sas_addr, 8);
|
||||
*type = to_dev_type(dr);
|
||||
if (*type == 0)
|
||||
memset(sas_addr, 0, 8);
|
||||
}
|
||||
kfree(disc_resp);
|
||||
return res;
|
||||
@ -1748,7 +1823,7 @@ static void sas_unregister_ex_tree(struct asd_sas_port *port, struct domain_devi
|
||||
struct domain_device *child, *n;
|
||||
|
||||
list_for_each_entry_safe(child, n, &ex->children, siblings) {
|
||||
child->gone = 1;
|
||||
set_bit(SAS_DEV_GONE, &child->state);
|
||||
if (child->dev_type == EDGE_DEV ||
|
||||
child->dev_type == FANOUT_DEV)
|
||||
sas_unregister_ex_tree(port, child);
|
||||
@ -1763,27 +1838,28 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
|
||||
{
|
||||
struct expander_device *ex_dev = &parent->ex_dev;
|
||||
struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
|
||||
struct domain_device *child, *n;
|
||||
struct domain_device *child, *n, *found = NULL;
|
||||
if (last) {
|
||||
list_for_each_entry_safe(child, n,
|
||||
&ex_dev->children, siblings) {
|
||||
if (SAS_ADDR(child->sas_addr) ==
|
||||
SAS_ADDR(phy->attached_sas_addr)) {
|
||||
child->gone = 1;
|
||||
set_bit(SAS_DEV_GONE, &child->state);
|
||||
if (child->dev_type == EDGE_DEV ||
|
||||
child->dev_type == FANOUT_DEV)
|
||||
sas_unregister_ex_tree(parent->port, child);
|
||||
else
|
||||
sas_unregister_dev(parent->port, child);
|
||||
found = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parent->gone = 1;
|
||||
sas_disable_routing(parent, phy->attached_sas_addr);
|
||||
}
|
||||
memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
|
||||
if (phy->port) {
|
||||
sas_port_delete_phy(phy->port, phy->phy);
|
||||
sas_device_set_phy(found, phy->port);
|
||||
if (phy->port->num_phys == 0)
|
||||
sas_port_delete(phy->port);
|
||||
phy->port = NULL;
|
||||
@ -1874,39 +1950,71 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool dev_type_flutter(enum sas_dev_type new, enum sas_dev_type old)
|
||||
{
|
||||
if (old == new)
|
||||
return true;
|
||||
|
||||
/* treat device directed resets as flutter, if we went
|
||||
* SAS_END_DEV to SATA_PENDING the link needs recovery
|
||||
*/
|
||||
if ((old == SATA_PENDING && new == SAS_END_DEV) ||
|
||||
(old == SAS_END_DEV && new == SATA_PENDING))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
|
||||
{
|
||||
struct expander_device *ex = &dev->ex_dev;
|
||||
struct ex_phy *phy = &ex->ex_phy[phy_id];
|
||||
u8 attached_sas_addr[8];
|
||||
enum sas_dev_type type = NO_DEVICE;
|
||||
u8 sas_addr[8];
|
||||
int res;
|
||||
|
||||
res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr);
|
||||
res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type);
|
||||
switch (res) {
|
||||
case SMP_RESP_NO_PHY:
|
||||
phy->phy_state = PHY_NOT_PRESENT;
|
||||
sas_unregister_devs_sas_addr(dev, phy_id, last);
|
||||
goto out; break;
|
||||
return res;
|
||||
case SMP_RESP_PHY_VACANT:
|
||||
phy->phy_state = PHY_VACANT;
|
||||
sas_unregister_devs_sas_addr(dev, phy_id, last);
|
||||
goto out; break;
|
||||
return res;
|
||||
case SMP_RESP_FUNC_ACC:
|
||||
break;
|
||||
}
|
||||
|
||||
if (SAS_ADDR(attached_sas_addr) == 0) {
|
||||
if (SAS_ADDR(sas_addr) == 0) {
|
||||
phy->phy_state = PHY_EMPTY;
|
||||
sas_unregister_devs_sas_addr(dev, phy_id, last);
|
||||
} else if (SAS_ADDR(attached_sas_addr) ==
|
||||
SAS_ADDR(phy->attached_sas_addr)) {
|
||||
SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
|
||||
SAS_ADDR(dev->sas_addr), phy_id);
|
||||
return res;
|
||||
} else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) &&
|
||||
dev_type_flutter(type, phy->attached_dev_type)) {
|
||||
struct domain_device *ata_dev = sas_ex_to_ata(dev, phy_id);
|
||||
char *action = "";
|
||||
|
||||
sas_ex_phy_discover(dev, phy_id);
|
||||
} else
|
||||
res = sas_discover_new(dev, phy_id);
|
||||
out:
|
||||
return res;
|
||||
|
||||
if (ata_dev && phy->attached_dev_type == SATA_PENDING)
|
||||
action = ", needs recovery";
|
||||
SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter%s\n",
|
||||
SAS_ADDR(dev->sas_addr), phy_id, action);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* delete the old link */
|
||||
if (SAS_ADDR(phy->attached_sas_addr) &&
|
||||
SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr)) {
|
||||
SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n",
|
||||
SAS_ADDR(dev->sas_addr), phy_id,
|
||||
SAS_ADDR(phy->attached_sas_addr));
|
||||
sas_unregister_devs_sas_addr(dev, phy_id, last);
|
||||
}
|
||||
|
||||
return sas_discover_new(dev, phy_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,11 +187,14 @@ static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
|
||||
struct sas_internal *i =
|
||||
to_sas_internal(sas_ha->core.shost->transportt);
|
||||
struct sas_phy_linkrates rates;
|
||||
struct asd_sas_phy *asd_phy;
|
||||
|
||||
if (phy_id >= sas_ha->num_phys) {
|
||||
resp_data[2] = SMP_RESP_NO_PHY;
|
||||
return;
|
||||
}
|
||||
|
||||
asd_phy = sas_ha->sas_phy[phy_id];
|
||||
switch (phy_op) {
|
||||
case PHY_FUNC_NOP:
|
||||
case PHY_FUNC_LINK_RESET:
|
||||
@ -210,7 +213,13 @@ static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
|
||||
rates.minimum_linkrate = min;
|
||||
rates.maximum_linkrate = max;
|
||||
|
||||
if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates))
|
||||
/* filter reset requests through libata eh */
|
||||
if (phy_op == PHY_FUNC_LINK_RESET && sas_try_ata_reset(asd_phy) == 0) {
|
||||
resp_data[2] = SMP_RESP_FUNC_ACC;
|
||||
return;
|
||||
}
|
||||
|
||||
if (i->dft->lldd_control_phy(asd_phy, phy_op, &rates))
|
||||
resp_data[2] = SMP_RESP_FUNC_FAILED;
|
||||
else
|
||||
resp_data[2] = SMP_RESP_FUNC_ACC;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <scsi/sas_ata.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_transport.h>
|
||||
@ -97,14 +98,14 @@ void sas_hae_reset(struct work_struct *work)
|
||||
container_of(work, struct sas_ha_event, work);
|
||||
struct sas_ha_struct *ha = ev->ha;
|
||||
|
||||
sas_begin_event(HAE_RESET, &ha->event_lock,
|
||||
&ha->pending);
|
||||
clear_bit(HAE_RESET, &ha->pending);
|
||||
}
|
||||
|
||||
int sas_register_ha(struct sas_ha_struct *sas_ha)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
mutex_init(&sas_ha->disco_mutex);
|
||||
spin_lock_init(&sas_ha->phy_port_lock);
|
||||
sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr);
|
||||
|
||||
@ -113,8 +114,10 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
|
||||
else if (sas_ha->lldd_queue_size == -1)
|
||||
sas_ha->lldd_queue_size = 128; /* Sanity */
|
||||
|
||||
sas_ha->state = SAS_HA_REGISTERED;
|
||||
set_bit(SAS_HA_REGISTERED, &sas_ha->state);
|
||||
spin_lock_init(&sas_ha->state_lock);
|
||||
mutex_init(&sas_ha->drain_mutex);
|
||||
INIT_LIST_HEAD(&sas_ha->defer_q);
|
||||
|
||||
error = sas_register_phys(sas_ha);
|
||||
if (error) {
|
||||
@ -144,6 +147,7 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&sas_ha->eh_done_q);
|
||||
INIT_LIST_HEAD(&sas_ha->eh_ata_q);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -156,17 +160,23 @@ Undo_phys:
|
||||
|
||||
int sas_unregister_ha(struct sas_ha_struct *sas_ha)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* Set the state to unregistered to avoid further
|
||||
* events to be queued */
|
||||
spin_lock_irqsave(&sas_ha->state_lock, flags);
|
||||
sas_ha->state = SAS_HA_UNREGISTERED;
|
||||
spin_unlock_irqrestore(&sas_ha->state_lock, flags);
|
||||
scsi_flush_work(sas_ha->core.shost);
|
||||
/* Set the state to unregistered to avoid further unchained
|
||||
* events to be queued, and flush any in-progress drainers
|
||||
*/
|
||||
mutex_lock(&sas_ha->drain_mutex);
|
||||
spin_lock_irq(&sas_ha->state_lock);
|
||||
clear_bit(SAS_HA_REGISTERED, &sas_ha->state);
|
||||
spin_unlock_irq(&sas_ha->state_lock);
|
||||
__sas_drain_work(sas_ha);
|
||||
mutex_unlock(&sas_ha->drain_mutex);
|
||||
|
||||
sas_unregister_ports(sas_ha);
|
||||
|
||||
/* flush unregistration work */
|
||||
mutex_lock(&sas_ha->drain_mutex);
|
||||
__sas_drain_work(sas_ha);
|
||||
mutex_unlock(&sas_ha->drain_mutex);
|
||||
|
||||
if (sas_ha->lldd_max_execute_num > 1) {
|
||||
sas_shutdown_queue(sas_ha);
|
||||
sas_ha->lldd_max_execute_num = 1;
|
||||
@ -190,15 +200,41 @@ static int sas_get_linkerrors(struct sas_phy *phy)
|
||||
return sas_smp_get_phy_events(phy);
|
||||
}
|
||||
|
||||
int sas_phy_enable(struct sas_phy *phy, int enable)
|
||||
int sas_try_ata_reset(struct asd_sas_phy *asd_phy)
|
||||
{
|
||||
int ret;
|
||||
enum phy_func command;
|
||||
struct domain_device *dev = NULL;
|
||||
|
||||
if (enable)
|
||||
command = PHY_FUNC_LINK_RESET;
|
||||
/* try to route user requested link resets through libata */
|
||||
if (asd_phy->port)
|
||||
dev = asd_phy->port->port_dev;
|
||||
|
||||
/* validate that dev has been probed */
|
||||
if (dev)
|
||||
dev = sas_find_dev_by_rphy(dev->rphy);
|
||||
|
||||
if (dev && dev_is_sata(dev)) {
|
||||
sas_ata_schedule_reset(dev);
|
||||
sas_ata_wait_eh(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* transport_sas_phy_reset - reset a phy and permit libata to manage the link
|
||||
*
|
||||
* phy reset request via sysfs in host workqueue context so we know we
|
||||
* can block on eh and safely traverse the domain_device topology
|
||||
*/
|
||||
static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset)
|
||||
{
|
||||
enum phy_func reset_type;
|
||||
|
||||
if (hard_reset)
|
||||
reset_type = PHY_FUNC_HARD_RESET;
|
||||
else
|
||||
command = PHY_FUNC_DISABLE;
|
||||
reset_type = PHY_FUNC_LINK_RESET;
|
||||
|
||||
if (scsi_is_sas_phy_local(phy)) {
|
||||
struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
|
||||
@ -207,15 +243,52 @@ int sas_phy_enable(struct sas_phy *phy, int enable)
|
||||
struct sas_internal *i =
|
||||
to_sas_internal(sas_ha->core.shost->transportt);
|
||||
|
||||
if (!enable) {
|
||||
sas_phy_disconnected(asd_phy);
|
||||
sas_ha->notify_phy_event(asd_phy, PHYE_LOSS_OF_SIGNAL);
|
||||
}
|
||||
ret = i->dft->lldd_control_phy(asd_phy, command, NULL);
|
||||
if (!hard_reset && sas_try_ata_reset(asd_phy) == 0)
|
||||
return 0;
|
||||
return i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
|
||||
} else {
|
||||
struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
|
||||
struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
|
||||
ret = sas_smp_phy_control(ddev, phy->number, command, NULL);
|
||||
struct domain_device *ata_dev = sas_ex_to_ata(ddev, phy->number);
|
||||
|
||||
if (ata_dev && !hard_reset) {
|
||||
sas_ata_schedule_reset(ata_dev);
|
||||
sas_ata_wait_eh(ata_dev);
|
||||
return 0;
|
||||
} else
|
||||
return sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int sas_phy_enable(struct sas_phy *phy, int enable)
|
||||
{
|
||||
int ret;
|
||||
enum phy_func cmd;
|
||||
|
||||
if (enable)
|
||||
cmd = PHY_FUNC_LINK_RESET;
|
||||
else
|
||||
cmd = PHY_FUNC_DISABLE;
|
||||
|
||||
if (scsi_is_sas_phy_local(phy)) {
|
||||
struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
|
||||
struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
|
||||
struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
|
||||
struct sas_internal *i =
|
||||
to_sas_internal(sas_ha->core.shost->transportt);
|
||||
|
||||
if (enable)
|
||||
ret = transport_sas_phy_reset(phy, 0);
|
||||
else
|
||||
ret = i->dft->lldd_control_phy(asd_phy, cmd, NULL);
|
||||
} else {
|
||||
struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
|
||||
struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
|
||||
|
||||
if (enable)
|
||||
ret = transport_sas_phy_reset(phy, 0);
|
||||
else
|
||||
ret = sas_smp_phy_control(ddev, phy->number, cmd, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -225,6 +298,9 @@ int sas_phy_reset(struct sas_phy *phy, int hard_reset)
|
||||
int ret;
|
||||
enum phy_func reset_type;
|
||||
|
||||
if (!phy->enabled)
|
||||
return -ENODEV;
|
||||
|
||||
if (hard_reset)
|
||||
reset_type = PHY_FUNC_HARD_RESET;
|
||||
else
|
||||
@ -285,9 +361,101 @@ int sas_set_phy_speed(struct sas_phy *phy,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sas_phy_release(struct sas_phy *phy)
|
||||
{
|
||||
kfree(phy->hostdata);
|
||||
phy->hostdata = NULL;
|
||||
}
|
||||
|
||||
static void phy_reset_work(struct work_struct *work)
|
||||
{
|
||||
struct sas_phy_data *d = container_of(work, typeof(*d), reset_work);
|
||||
|
||||
d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset);
|
||||
}
|
||||
|
||||
static void phy_enable_work(struct work_struct *work)
|
||||
{
|
||||
struct sas_phy_data *d = container_of(work, typeof(*d), enable_work);
|
||||
|
||||
d->enable_result = sas_phy_enable(d->phy, d->enable);
|
||||
}
|
||||
|
||||
static int sas_phy_setup(struct sas_phy *phy)
|
||||
{
|
||||
struct sas_phy_data *d = kzalloc(sizeof(*d), GFP_KERNEL);
|
||||
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&d->event_lock);
|
||||
INIT_WORK(&d->reset_work, phy_reset_work);
|
||||
INIT_WORK(&d->enable_work, phy_enable_work);
|
||||
d->phy = phy;
|
||||
phy->hostdata = d;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int queue_phy_reset(struct sas_phy *phy, int hard_reset)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
|
||||
struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
|
||||
struct sas_phy_data *d = phy->hostdata;
|
||||
int rc;
|
||||
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
/* libsas workqueue coordinates ata-eh reset with discovery */
|
||||
mutex_lock(&d->event_lock);
|
||||
d->reset_result = 0;
|
||||
d->hard_reset = hard_reset;
|
||||
|
||||
spin_lock_irq(&ha->state_lock);
|
||||
sas_queue_work(ha, &d->reset_work);
|
||||
spin_unlock_irq(&ha->state_lock);
|
||||
|
||||
rc = sas_drain_work(ha);
|
||||
if (rc == 0)
|
||||
rc = d->reset_result;
|
||||
mutex_unlock(&d->event_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int queue_phy_enable(struct sas_phy *phy, int enable)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
|
||||
struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
|
||||
struct sas_phy_data *d = phy->hostdata;
|
||||
int rc;
|
||||
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
/* libsas workqueue coordinates ata-eh reset with discovery */
|
||||
mutex_lock(&d->event_lock);
|
||||
d->enable_result = 0;
|
||||
d->enable = enable;
|
||||
|
||||
spin_lock_irq(&ha->state_lock);
|
||||
sas_queue_work(ha, &d->enable_work);
|
||||
spin_unlock_irq(&ha->state_lock);
|
||||
|
||||
rc = sas_drain_work(ha);
|
||||
if (rc == 0)
|
||||
rc = d->enable_result;
|
||||
mutex_unlock(&d->event_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct sas_function_template sft = {
|
||||
.phy_enable = sas_phy_enable,
|
||||
.phy_reset = sas_phy_reset,
|
||||
.phy_enable = queue_phy_enable,
|
||||
.phy_reset = queue_phy_reset,
|
||||
.phy_setup = sas_phy_setup,
|
||||
.phy_release = sas_phy_release,
|
||||
.set_phy_speed = sas_set_phy_speed,
|
||||
.get_linkerrors = sas_get_linkerrors,
|
||||
.smp_handler = sas_smp_handler,
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_transport_sas.h>
|
||||
#include <scsi/libsas.h>
|
||||
#include <scsi/sas_ata.h>
|
||||
|
||||
#define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
|
||||
|
||||
@ -38,6 +39,18 @@
|
||||
#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
|
||||
#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
|
||||
|
||||
struct sas_phy_data {
|
||||
/* let reset be performed in sas_queue_work() context */
|
||||
struct sas_phy *phy;
|
||||
struct mutex event_lock;
|
||||
int hard_reset;
|
||||
int reset_result;
|
||||
struct work_struct reset_work;
|
||||
int enable;
|
||||
int enable_result;
|
||||
struct work_struct enable_work;
|
||||
};
|
||||
|
||||
void sas_scsi_recover_host(struct Scsi_Host *shost);
|
||||
|
||||
int sas_show_class(enum sas_class class, char *buf);
|
||||
@ -56,6 +69,9 @@ enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
|
||||
int sas_init_queue(struct sas_ha_struct *sas_ha);
|
||||
int sas_init_events(struct sas_ha_struct *sas_ha);
|
||||
void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
|
||||
void sas_disable_revalidation(struct sas_ha_struct *ha);
|
||||
void sas_enable_revalidation(struct sas_ha_struct *ha);
|
||||
void __sas_drain_work(struct sas_ha_struct *ha);
|
||||
|
||||
void sas_deform_port(struct asd_sas_phy *phy, int gone);
|
||||
|
||||
@ -64,6 +80,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work);
|
||||
void sas_porte_link_reset_err(struct work_struct *work);
|
||||
void sas_porte_timer_event(struct work_struct *work);
|
||||
void sas_porte_hard_reset(struct work_struct *work);
|
||||
void sas_queue_work(struct sas_ha_struct *ha, struct work_struct *work);
|
||||
|
||||
int sas_notify_lldd_dev_found(struct domain_device *);
|
||||
void sas_notify_lldd_dev_gone(struct domain_device *);
|
||||
@ -72,10 +89,17 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id,
|
||||
enum phy_func phy_func, struct sas_phy_linkrates *);
|
||||
int sas_smp_get_phy_events(struct sas_phy *phy);
|
||||
|
||||
void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
|
||||
struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
|
||||
|
||||
struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
|
||||
int sas_ex_phy_discover(struct domain_device *dev, int single);
|
||||
int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
|
||||
struct smp_resp *rps_resp);
|
||||
int sas_try_ata_reset(struct asd_sas_phy *phy);
|
||||
void sas_hae_reset(struct work_struct *work);
|
||||
|
||||
void sas_free_device(struct kref *kref);
|
||||
|
||||
#ifdef CONFIG_SCSI_SAS_HOST_SMP
|
||||
extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
|
||||
struct request *rsp);
|
||||
@ -90,36 +114,13 @@ static inline int sas_smp_host_handler(struct Scsi_Host *shost,
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void sas_queue_event(int event, spinlock_t *lock,
|
||||
unsigned long *pending,
|
||||
struct work_struct *work,
|
||||
struct sas_ha_struct *sas_ha)
|
||||
static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(lock, flags);
|
||||
if (test_bit(event, pending)) {
|
||||
spin_unlock_irqrestore(lock, flags);
|
||||
return;
|
||||
}
|
||||
__set_bit(event, pending);
|
||||
spin_unlock_irqrestore(lock, flags);
|
||||
|
||||
spin_lock_irqsave(&sas_ha->state_lock, flags);
|
||||
if (sas_ha->state != SAS_HA_UNREGISTERED) {
|
||||
scsi_queue_work(sas_ha->core.shost, work);
|
||||
}
|
||||
spin_unlock_irqrestore(&sas_ha->state_lock, flags);
|
||||
}
|
||||
|
||||
static inline void sas_begin_event(int event, spinlock_t *lock,
|
||||
unsigned long *pending)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(lock, flags);
|
||||
__clear_bit(event, pending);
|
||||
spin_unlock_irqrestore(lock, flags);
|
||||
SAS_DPRINTK("%s: for %s device %16llx returned %d\n",
|
||||
func, dev->parent ? "exp-attached" :
|
||||
"direct-attached",
|
||||
SAS_ADDR(dev->sas_addr), err);
|
||||
sas_unregister_dev(dev->port, dev);
|
||||
}
|
||||
|
||||
static inline void sas_fill_in_rphy(struct domain_device *dev,
|
||||
@ -132,6 +133,7 @@ static inline void sas_fill_in_rphy(struct domain_device *dev,
|
||||
case SATA_DEV:
|
||||
/* FIXME: need sata device type */
|
||||
case SAS_END_DEV:
|
||||
case SATA_PENDING:
|
||||
rphy->identify.device_type = SAS_END_DEVICE;
|
||||
break;
|
||||
case EDGE_DEV:
|
||||
@ -146,6 +148,22 @@ static inline void sas_fill_in_rphy(struct domain_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_device *dev)
|
||||
{
|
||||
struct sas_phy *phy = p->phy;
|
||||
|
||||
if (dev) {
|
||||
if (dev_is_sata(dev))
|
||||
phy->identify.device_type = SAS_END_DEVICE;
|
||||
else
|
||||
phy->identify.device_type = dev->dev_type;
|
||||
phy->identify.target_port_protocols = dev->tproto;
|
||||
} else {
|
||||
phy->identify.device_type = SAS_PHY_UNUSED;
|
||||
phy->identify.target_port_protocols = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sas_add_parent_port(struct domain_device *dev, int phy_id)
|
||||
{
|
||||
struct expander_device *ex = &dev->ex_dev;
|
||||
@ -161,4 +179,23 @@ static inline void sas_add_parent_port(struct domain_device *dev, int phy_id)
|
||||
sas_port_add_phy(ex->parent_port, ex_phy->phy);
|
||||
}
|
||||
|
||||
static inline struct domain_device *sas_alloc_device(void)
|
||||
{
|
||||
struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
|
||||
if (dev) {
|
||||
INIT_LIST_HEAD(&dev->siblings);
|
||||
INIT_LIST_HEAD(&dev->dev_list_node);
|
||||
INIT_LIST_HEAD(&dev->disco_list_node);
|
||||
kref_init(&dev->kref);
|
||||
spin_lock_init(&dev->done_lock);
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
static inline void sas_put_device(struct domain_device *dev)
|
||||
{
|
||||
kref_put(&dev->kref, sas_free_device);
|
||||
}
|
||||
|
||||
#endif /* _SAS_INTERNAL_H_ */
|
||||
|
@ -36,8 +36,7 @@ static void sas_phye_loss_of_signal(struct work_struct *work)
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock,
|
||||
&phy->phy_events_pending);
|
||||
clear_bit(PHYE_LOSS_OF_SIGNAL, &phy->phy_events_pending);
|
||||
phy->error = 0;
|
||||
sas_deform_port(phy, 1);
|
||||
}
|
||||
@ -48,8 +47,7 @@ static void sas_phye_oob_done(struct work_struct *work)
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock,
|
||||
&phy->phy_events_pending);
|
||||
clear_bit(PHYE_OOB_DONE, &phy->phy_events_pending);
|
||||
phy->error = 0;
|
||||
}
|
||||
|
||||
@ -63,8 +61,7 @@ static void sas_phye_oob_error(struct work_struct *work)
|
||||
struct sas_internal *i =
|
||||
to_sas_internal(sas_ha->core.shost->transportt);
|
||||
|
||||
sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock,
|
||||
&phy->phy_events_pending);
|
||||
clear_bit(PHYE_OOB_ERROR, &phy->phy_events_pending);
|
||||
|
||||
sas_deform_port(phy, 1);
|
||||
|
||||
@ -95,8 +92,7 @@ static void sas_phye_spinup_hold(struct work_struct *work)
|
||||
struct sas_internal *i =
|
||||
to_sas_internal(sas_ha->core.shost->transportt);
|
||||
|
||||
sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock,
|
||||
&phy->phy_events_pending);
|
||||
clear_bit(PHYE_SPINUP_HOLD, &phy->phy_events_pending);
|
||||
|
||||
phy->error = 0;
|
||||
i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
|
||||
|
@ -104,13 +104,11 @@ static void sas_form_port(struct asd_sas_phy *phy)
|
||||
|
||||
/* add the phy to the port */
|
||||
list_add_tail(&phy->port_phy_el, &port->phy_list);
|
||||
sas_phy_set_target(phy, port->port_dev);
|
||||
phy->port = port;
|
||||
port->num_phys++;
|
||||
port->phy_mask |= (1U << phy->id);
|
||||
|
||||
if (!port->phy)
|
||||
port->phy = phy->phy;
|
||||
|
||||
if (*(u64 *)port->attached_sas_addr == 0) {
|
||||
port->class = phy->class;
|
||||
memcpy(port->attached_sas_addr, phy->attached_sas_addr,
|
||||
@ -125,7 +123,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
|
||||
spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
|
||||
|
||||
if (!port->port) {
|
||||
port->port = sas_port_alloc(phy->phy->dev.parent, port->id);
|
||||
port->port = sas_port_alloc(phy->phy->dev.parent, phy->id);
|
||||
BUG_ON(!port->port);
|
||||
sas_port_add(port->port);
|
||||
}
|
||||
@ -170,13 +168,13 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
|
||||
dev->pathways--;
|
||||
|
||||
if (port->num_phys == 1) {
|
||||
if (dev && gone)
|
||||
dev->gone = 1;
|
||||
sas_unregister_domain_devices(port);
|
||||
sas_unregister_domain_devices(port, gone);
|
||||
sas_port_delete(port->port);
|
||||
port->port = NULL;
|
||||
} else
|
||||
} else {
|
||||
sas_port_delete_phy(port->port, phy->phy);
|
||||
sas_device_set_phy(dev, port->port);
|
||||
}
|
||||
|
||||
if (si->dft->lldd_port_deformed)
|
||||
si->dft->lldd_port_deformed(phy);
|
||||
@ -185,6 +183,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
|
||||
spin_lock(&port->phy_list_lock);
|
||||
|
||||
list_del_init(&phy->port_phy_el);
|
||||
sas_phy_set_target(phy, NULL);
|
||||
phy->port = NULL;
|
||||
port->num_phys--;
|
||||
port->phy_mask &= ~(1U << phy->id);
|
||||
@ -213,8 +212,7 @@ void sas_porte_bytes_dmaed(struct work_struct *work)
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock,
|
||||
&phy->port_events_pending);
|
||||
clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending);
|
||||
|
||||
sas_form_port(phy);
|
||||
}
|
||||
@ -227,8 +225,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work)
|
||||
unsigned long flags;
|
||||
u32 prim;
|
||||
|
||||
sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock,
|
||||
&phy->port_events_pending);
|
||||
clear_bit(PORTE_BROADCAST_RCVD, &phy->port_events_pending);
|
||||
|
||||
spin_lock_irqsave(&phy->sas_prim_lock, flags);
|
||||
prim = phy->sas_prim;
|
||||
@ -244,8 +241,7 @@ void sas_porte_link_reset_err(struct work_struct *work)
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,
|
||||
&phy->port_events_pending);
|
||||
clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending);
|
||||
|
||||
sas_deform_port(phy, 1);
|
||||
}
|
||||
@ -256,8 +252,7 @@ void sas_porte_timer_event(struct work_struct *work)
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,
|
||||
&phy->port_events_pending);
|
||||
clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending);
|
||||
|
||||
sas_deform_port(phy, 1);
|
||||
}
|
||||
@ -268,8 +263,7 @@ void sas_porte_hard_reset(struct work_struct *work)
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,
|
||||
&phy->port_events_pending);
|
||||
clear_bit(PORTE_HARD_RESET, &phy->port_events_pending);
|
||||
|
||||
sas_deform_port(phy, 1);
|
||||
}
|
||||
@ -282,6 +276,8 @@ static void sas_init_port(struct asd_sas_port *port,
|
||||
memset(port, 0, sizeof(*port));
|
||||
port->id = i;
|
||||
INIT_LIST_HEAD(&port->dev_list);
|
||||
INIT_LIST_HEAD(&port->disco_list);
|
||||
INIT_LIST_HEAD(&port->destroy_list);
|
||||
spin_lock_init(&port->phy_list_lock);
|
||||
INIT_LIST_HEAD(&port->phy_list);
|
||||
port->ha = sas_ha;
|
||||
|
@ -49,27 +49,12 @@
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/libata.h>
|
||||
|
||||
/* ---------- SCSI Host glue ---------- */
|
||||
|
||||
static void sas_scsi_task_done(struct sas_task *task)
|
||||
/* record final status and free the task */
|
||||
static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task)
|
||||
{
|
||||
struct task_status_struct *ts = &task->task_status;
|
||||
struct scsi_cmnd *sc = task->uldd_task;
|
||||
int hs = 0, stat = 0;
|
||||
|
||||
if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
|
||||
/* Aborted tasks will be completed by the error handler */
|
||||
SAS_DPRINTK("task done but aborted\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(!sc)) {
|
||||
SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
|
||||
list_del_init(&task->list);
|
||||
sas_free_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ts->resp == SAS_TASK_UNDELIVERED) {
|
||||
/* transport error */
|
||||
hs = DID_NO_CONNECT;
|
||||
@ -124,10 +109,41 @@ static void sas_scsi_task_done(struct sas_task *task)
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSIGN_SAS_TASK(sc, NULL);
|
||||
|
||||
sc->result = (hs << 16) | stat;
|
||||
ASSIGN_SAS_TASK(sc, NULL);
|
||||
list_del_init(&task->list);
|
||||
sas_free_task(task);
|
||||
}
|
||||
|
||||
static void sas_scsi_task_done(struct sas_task *task)
|
||||
{
|
||||
struct scsi_cmnd *sc = task->uldd_task;
|
||||
struct domain_device *dev = task->dev;
|
||||
struct sas_ha_struct *ha = dev->port->ha;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->done_lock, flags);
|
||||
if (test_bit(SAS_HA_FROZEN, &ha->state))
|
||||
task = NULL;
|
||||
else
|
||||
ASSIGN_SAS_TASK(sc, NULL);
|
||||
spin_unlock_irqrestore(&dev->done_lock, flags);
|
||||
|
||||
if (unlikely(!task)) {
|
||||
/* task will be completed by the error handler */
|
||||
SAS_DPRINTK("task done but aborted\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(!sc)) {
|
||||
SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
|
||||
list_del_init(&task->list);
|
||||
sas_free_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
sas_end_task(sc, task);
|
||||
sc->scsi_done(sc);
|
||||
}
|
||||
|
||||
@ -192,17 +208,15 @@ int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
|
||||
int res = 0;
|
||||
|
||||
/* If the device fell off, no sense in issuing commands */
|
||||
if (dev->gone) {
|
||||
if (test_bit(SAS_DEV_GONE, &dev->state)) {
|
||||
cmd->result = DID_BAD_TARGET << 16;
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
if (dev_is_sata(dev)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
|
||||
spin_lock_irq(dev->sata_dev.ap->lock);
|
||||
res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
|
||||
spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
|
||||
spin_unlock_irq(dev->sata_dev.ap->lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -235,24 +249,38 @@ out_done:
|
||||
|
||||
static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct sas_task *task = TO_SAS_TASK(cmd);
|
||||
struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host);
|
||||
struct sas_task *task = TO_SAS_TASK(cmd);
|
||||
|
||||
/* At this point, we only get called following an actual abort
|
||||
* of the task, so we should be guaranteed not to be racing with
|
||||
* any completions from the LLD. Task is freed after this.
|
||||
*/
|
||||
sas_end_task(cmd, task);
|
||||
|
||||
/* remove the aborted task flag to allow the task to be
|
||||
* completed now. At this point, we only get called following
|
||||
* an actual abort of the task, so we should be guaranteed not
|
||||
* to be racing with any completions from the LLD (hence we
|
||||
* don't need the task state lock to clear the flag) */
|
||||
task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
|
||||
/* Now call task_done. However, task will be free'd after
|
||||
* this */
|
||||
task->task_done(task);
|
||||
/* now finish the command and move it on to the error
|
||||
* handler done list, this also takes it off the
|
||||
* error handler pending list */
|
||||
* error handler pending list.
|
||||
*/
|
||||
scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q);
|
||||
}
|
||||
|
||||
static void sas_eh_defer_cmd(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct domain_device *dev = cmd_to_domain_dev(cmd);
|
||||
struct sas_ha_struct *ha = dev->port->ha;
|
||||
struct sas_task *task = TO_SAS_TASK(cmd);
|
||||
|
||||
if (!dev_is_sata(dev)) {
|
||||
sas_eh_finish_cmd(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* report the timeout to libata */
|
||||
sas_end_task(cmd, task);
|
||||
list_move_tail(&cmd->eh_entry, &ha->eh_ata_q);
|
||||
}
|
||||
|
||||
static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
|
||||
{
|
||||
struct scsi_cmnd *cmd, *n;
|
||||
@ -260,7 +288,7 @@ static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd
|
||||
list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
|
||||
if (cmd->device->sdev_target == my_cmd->device->sdev_target &&
|
||||
cmd->device->lun == my_cmd->device->lun)
|
||||
sas_eh_finish_cmd(cmd);
|
||||
sas_eh_defer_cmd(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,6 +323,7 @@ enum task_disposition {
|
||||
TASK_IS_DONE,
|
||||
TASK_IS_ABORTED,
|
||||
TASK_IS_AT_LU,
|
||||
TASK_IS_NOT_AT_HA,
|
||||
TASK_IS_NOT_AT_LU,
|
||||
TASK_ABORT_FAILED,
|
||||
};
|
||||
@ -311,19 +340,18 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
|
||||
struct scsi_core *core = &ha->core;
|
||||
struct sas_task *t, *n;
|
||||
|
||||
mutex_lock(&core->task_queue_flush);
|
||||
spin_lock_irqsave(&core->task_queue_lock, flags);
|
||||
list_for_each_entry_safe(t, n, &core->task_queue, list) {
|
||||
list_for_each_entry_safe(t, n, &core->task_queue, list)
|
||||
if (task == t) {
|
||||
list_del_init(&t->list);
|
||||
spin_unlock_irqrestore(&core->task_queue_lock,
|
||||
flags);
|
||||
SAS_DPRINTK("%s: task 0x%p aborted from "
|
||||
"task_queue\n",
|
||||
__func__, task);
|
||||
return TASK_IS_ABORTED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&core->task_queue_lock, flags);
|
||||
mutex_unlock(&core->task_queue_flush);
|
||||
|
||||
if (task == t)
|
||||
return TASK_IS_NOT_AT_HA;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
@ -411,30 +439,26 @@ static int sas_recover_I_T(struct domain_device *dev)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Find the sas_phy that's attached to this device */
|
||||
struct sas_phy *sas_find_local_phy(struct domain_device *dev)
|
||||
/* take a reference on the last known good phy for this device */
|
||||
struct sas_phy *sas_get_local_phy(struct domain_device *dev)
|
||||
{
|
||||
struct domain_device *pdev = dev->parent;
|
||||
struct ex_phy *exphy = NULL;
|
||||
int i;
|
||||
struct sas_ha_struct *ha = dev->port->ha;
|
||||
struct sas_phy *phy;
|
||||
unsigned long flags;
|
||||
|
||||
/* Directly attached device */
|
||||
if (!pdev)
|
||||
return dev->port->phy;
|
||||
/* a published domain device always has a valid phy, it may be
|
||||
* stale, but it is never NULL
|
||||
*/
|
||||
BUG_ON(!dev->phy);
|
||||
|
||||
/* Otherwise look in the expander */
|
||||
for (i = 0; i < pdev->ex_dev.num_phys; i++)
|
||||
if (!memcmp(dev->sas_addr,
|
||||
pdev->ex_dev.ex_phy[i].attached_sas_addr,
|
||||
SAS_ADDR_SIZE)) {
|
||||
exphy = &pdev->ex_dev.ex_phy[i];
|
||||
break;
|
||||
}
|
||||
spin_lock_irqsave(&ha->phy_port_lock, flags);
|
||||
phy = dev->phy;
|
||||
get_device(&phy->dev);
|
||||
spin_unlock_irqrestore(&ha->phy_port_lock, flags);
|
||||
|
||||
BUG_ON(!exphy);
|
||||
return exphy->phy;
|
||||
return phy;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sas_find_local_phy);
|
||||
EXPORT_SYMBOL_GPL(sas_get_local_phy);
|
||||
|
||||
/* Attempt to send a LUN reset message to a device */
|
||||
int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
|
||||
@ -461,7 +485,7 @@ int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
|
||||
int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct domain_device *dev = cmd_to_domain_dev(cmd);
|
||||
struct sas_phy *phy = sas_find_local_phy(dev);
|
||||
struct sas_phy *phy = sas_get_local_phy(dev);
|
||||
int res;
|
||||
|
||||
res = sas_phy_reset(phy, 1);
|
||||
@ -469,6 +493,8 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
|
||||
SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
|
||||
kobject_name(&phy->dev.kobj),
|
||||
res);
|
||||
sas_put_local_phy(phy);
|
||||
|
||||
if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
|
||||
return SUCCESS;
|
||||
|
||||
@ -495,9 +521,7 @@ try_bus_reset:
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
static int sas_eh_handle_sas_errors(struct Scsi_Host *shost,
|
||||
struct list_head *work_q,
|
||||
struct list_head *done_q)
|
||||
static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *work_q)
|
||||
{
|
||||
struct scsi_cmnd *cmd, *n;
|
||||
enum task_disposition res = TASK_IS_DONE;
|
||||
@ -505,13 +529,28 @@ static int sas_eh_handle_sas_errors(struct Scsi_Host *shost,
|
||||
struct sas_internal *i = to_sas_internal(shost->transportt);
|
||||
unsigned long flags;
|
||||
struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
|
||||
LIST_HEAD(done);
|
||||
|
||||
Again:
|
||||
/* clean out any commands that won the completion vs eh race */
|
||||
list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
|
||||
struct sas_task *task = TO_SAS_TASK(cmd);
|
||||
struct domain_device *dev = cmd_to_domain_dev(cmd);
|
||||
struct sas_task *task;
|
||||
|
||||
spin_lock_irqsave(&dev->done_lock, flags);
|
||||
/* by this point the lldd has either observed
|
||||
* SAS_HA_FROZEN and is leaving the task alone, or has
|
||||
* won the race with eh and decided to complete it
|
||||
*/
|
||||
task = TO_SAS_TASK(cmd);
|
||||
spin_unlock_irqrestore(&dev->done_lock, flags);
|
||||
|
||||
if (!task)
|
||||
continue;
|
||||
list_move_tail(&cmd->eh_entry, &done);
|
||||
}
|
||||
|
||||
Again:
|
||||
list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
|
||||
struct sas_task *task = TO_SAS_TASK(cmd);
|
||||
|
||||
list_del_init(&cmd->eh_entry);
|
||||
|
||||
@ -531,15 +570,23 @@ Again:
|
||||
cmd->eh_eflags = 0;
|
||||
|
||||
switch (res) {
|
||||
case TASK_IS_NOT_AT_HA:
|
||||
SAS_DPRINTK("%s: task 0x%p is not at ha: %s\n",
|
||||
__func__, task,
|
||||
cmd->retries ? "retry" : "aborted");
|
||||
if (cmd->retries)
|
||||
cmd->retries--;
|
||||
sas_eh_finish_cmd(cmd);
|
||||
continue;
|
||||
case TASK_IS_DONE:
|
||||
SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
|
||||
task);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
sas_eh_defer_cmd(cmd);
|
||||
continue;
|
||||
case TASK_IS_ABORTED:
|
||||
SAS_DPRINTK("%s: task 0x%p is aborted\n",
|
||||
__func__, task);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
sas_eh_defer_cmd(cmd);
|
||||
continue;
|
||||
case TASK_IS_AT_LU:
|
||||
SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
|
||||
@ -550,7 +597,7 @@ Again:
|
||||
"recovered\n",
|
||||
SAS_ADDR(task->dev),
|
||||
cmd->device->lun);
|
||||
sas_eh_finish_cmd(cmd);
|
||||
sas_eh_defer_cmd(cmd);
|
||||
sas_scsi_clear_queue_lu(work_q, cmd);
|
||||
goto Again;
|
||||
}
|
||||
@ -560,7 +607,8 @@ Again:
|
||||
SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n",
|
||||
task);
|
||||
tmf_resp = sas_recover_I_T(task->dev);
|
||||
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
|
||||
if (tmf_resp == TMF_RESP_FUNC_COMPLETE ||
|
||||
tmf_resp == -ENODEV) {
|
||||
struct domain_device *dev = task->dev;
|
||||
SAS_DPRINTK("I_T %016llx recovered\n",
|
||||
SAS_ADDR(task->dev->sas_addr));
|
||||
@ -607,13 +655,16 @@ Again:
|
||||
goto clear_q;
|
||||
}
|
||||
}
|
||||
return list_empty(work_q);
|
||||
clear_q:
|
||||
out:
|
||||
list_splice_tail(&done, work_q);
|
||||
list_splice_tail_init(&ha->eh_ata_q, work_q);
|
||||
return;
|
||||
|
||||
clear_q:
|
||||
SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__);
|
||||
list_for_each_entry_safe(cmd, n, work_q, eh_entry)
|
||||
sas_eh_finish_cmd(cmd);
|
||||
|
||||
return list_empty(work_q);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void sas_scsi_recover_host(struct Scsi_Host *shost)
|
||||
@ -627,12 +678,17 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
|
||||
shost->host_eh_scheduled = 0;
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
SAS_DPRINTK("Enter %s\n", __func__);
|
||||
SAS_DPRINTK("Enter %s busy: %d failed: %d\n",
|
||||
__func__, shost->host_busy, shost->host_failed);
|
||||
/*
|
||||
* Deal with commands that still have SAS tasks (i.e. they didn't
|
||||
* complete via the normal sas_task completion mechanism)
|
||||
* complete via the normal sas_task completion mechanism),
|
||||
* SAS_HA_FROZEN gives eh dominion over all sas_task completion.
|
||||
*/
|
||||
if (sas_eh_handle_sas_errors(shost, &eh_work_q, &ha->eh_done_q))
|
||||
set_bit(SAS_HA_FROZEN, &ha->state);
|
||||
sas_eh_handle_sas_errors(shost, &eh_work_q);
|
||||
clear_bit(SAS_HA_FROZEN, &ha->state);
|
||||
if (list_empty(&eh_work_q))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@ -641,59 +697,26 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
|
||||
* scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any
|
||||
* command we see here has no sas_task and is thus unknown to the HA.
|
||||
*/
|
||||
if (!sas_ata_eh(shost, &eh_work_q, &ha->eh_done_q))
|
||||
if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q))
|
||||
scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q);
|
||||
sas_ata_eh(shost, &eh_work_q, &ha->eh_done_q);
|
||||
if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q))
|
||||
scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q);
|
||||
|
||||
out:
|
||||
if (ha->lldd_max_execute_num > 1)
|
||||
wake_up_process(ha->core.queue_thread);
|
||||
|
||||
/* now link into libata eh --- if we have any ata devices */
|
||||
sas_ata_strategy_handler(shost);
|
||||
|
||||
scsi_eh_flush_done_q(&ha->eh_done_q);
|
||||
|
||||
SAS_DPRINTK("--- Exit %s\n", __func__);
|
||||
return;
|
||||
SAS_DPRINTK("--- Exit %s: busy: %d failed: %d\n",
|
||||
__func__, shost->host_busy, shost->host_failed);
|
||||
}
|
||||
|
||||
enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct sas_task *task = TO_SAS_TASK(cmd);
|
||||
unsigned long flags;
|
||||
enum blk_eh_timer_return rtn;
|
||||
|
||||
if (sas_ata_timed_out(cmd, task, &rtn))
|
||||
return rtn;
|
||||
|
||||
if (!task) {
|
||||
cmd->request->timeout /= 2;
|
||||
SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
|
||||
cmd, task, (cmd->request->timeout ?
|
||||
"BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
|
||||
if (!cmd->request->timeout)
|
||||
return BLK_EH_NOT_HANDLED;
|
||||
return BLK_EH_RESET_TIMER;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
|
||||
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
|
||||
"BLK_EH_HANDLED\n", cmd, task);
|
||||
return BLK_EH_HANDLED;
|
||||
}
|
||||
if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
|
||||
"BLK_EH_RESET_TIMER\n",
|
||||
cmd, task);
|
||||
return BLK_EH_RESET_TIMER;
|
||||
}
|
||||
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
|
||||
SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
|
||||
cmd, task);
|
||||
scmd_printk(KERN_DEBUG, cmd, "command %p timed out\n", cmd);
|
||||
|
||||
return BLK_EH_NOT_HANDLED;
|
||||
}
|
||||
@ -737,27 +760,15 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
|
||||
return found_dev;
|
||||
}
|
||||
|
||||
static inline struct domain_device *sas_find_target(struct scsi_target *starget)
|
||||
{
|
||||
struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
|
||||
|
||||
return sas_find_dev_by_rphy(rphy);
|
||||
}
|
||||
|
||||
int sas_target_alloc(struct scsi_target *starget)
|
||||
{
|
||||
struct domain_device *found_dev = sas_find_target(starget);
|
||||
int res;
|
||||
struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
|
||||
struct domain_device *found_dev = sas_find_dev_by_rphy(rphy);
|
||||
|
||||
if (!found_dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (dev_is_sata(found_dev)) {
|
||||
res = sas_ata_init_host_and_port(found_dev, starget);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
kref_get(&found_dev->kref);
|
||||
starget->hostdata = found_dev;
|
||||
return 0;
|
||||
}
|
||||
@ -797,14 +808,6 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sas_slave_destroy(struct scsi_device *scsi_dev)
|
||||
{
|
||||
struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
|
||||
|
||||
if (dev_is_sata(dev))
|
||||
sas_to_ata_dev(dev)->class = ATA_DEV_NONE;
|
||||
}
|
||||
|
||||
int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
|
||||
{
|
||||
struct domain_device *dev = sdev_to_domain_dev(sdev);
|
||||
@ -871,9 +874,11 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
|
||||
int res;
|
||||
struct sas_internal *i = to_sas_internal(core->shost->transportt);
|
||||
|
||||
mutex_lock(&core->task_queue_flush);
|
||||
spin_lock_irqsave(&core->task_queue_lock, flags);
|
||||
while (!kthread_should_stop() &&
|
||||
!list_empty(&core->task_queue)) {
|
||||
!list_empty(&core->task_queue) &&
|
||||
!test_bit(SAS_HA_FROZEN, &sas_ha->state)) {
|
||||
|
||||
can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
|
||||
if (can_queue >= 0) {
|
||||
@ -909,6 +914,7 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&core->task_queue_lock, flags);
|
||||
mutex_unlock(&core->task_queue_flush);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -935,6 +941,7 @@ int sas_init_queue(struct sas_ha_struct *sas_ha)
|
||||
struct scsi_core *core = &sas_ha->core;
|
||||
|
||||
spin_lock_init(&core->task_queue_lock);
|
||||
mutex_init(&core->task_queue_flush);
|
||||
core->task_queue_size = 0;
|
||||
INIT_LIST_HEAD(&core->task_queue);
|
||||
|
||||
@ -971,49 +978,6 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
|
||||
spin_unlock_irqrestore(&core->task_queue_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the LLDD task abort routine directly. This function is intended for
|
||||
* use by upper layers that need to tell the LLDD to abort a task.
|
||||
*/
|
||||
int __sas_task_abort(struct sas_task *task)
|
||||
{
|
||||
struct sas_internal *si =
|
||||
to_sas_internal(task->dev->port->ha->core.shost->transportt);
|
||||
unsigned long flags;
|
||||
int res;
|
||||
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
|
||||
task->task_state_flags & SAS_TASK_STATE_DONE) {
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
|
||||
task);
|
||||
return 0;
|
||||
}
|
||||
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
|
||||
if (!si->dft->lldd_abort_task)
|
||||
return -ENODEV;
|
||||
|
||||
res = si->dft->lldd_abort_task(task);
|
||||
|
||||
spin_lock_irqsave(&task->task_state_lock, flags);
|
||||
if ((task->task_state_flags & SAS_TASK_STATE_DONE) ||
|
||||
(res == TMF_RESP_FUNC_COMPLETE))
|
||||
{
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
task->task_done(task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
|
||||
task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
|
||||
spin_unlock_irqrestore(&task->task_state_lock, flags);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell an upper layer that it needs to initiate an abort for a given task.
|
||||
* This should only ever be called by an LLDD.
|
||||
@ -1043,27 +1007,15 @@ void sas_task_abort(struct sas_task *task)
|
||||
}
|
||||
}
|
||||
|
||||
int sas_slave_alloc(struct scsi_device *scsi_dev)
|
||||
{
|
||||
struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
|
||||
|
||||
if (dev_is_sata(dev))
|
||||
return ata_sas_port_init(dev->sata_dev.ap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sas_target_destroy(struct scsi_target *starget)
|
||||
{
|
||||
struct domain_device *found_dev = sas_find_target(starget);
|
||||
struct domain_device *found_dev = starget->hostdata;
|
||||
|
||||
if (!found_dev)
|
||||
return;
|
||||
|
||||
if (dev_is_sata(found_dev))
|
||||
ata_sas_port_destroy(found_dev->sata_dev.ap);
|
||||
|
||||
return;
|
||||
starget->hostdata = NULL;
|
||||
sas_put_device(found_dev);
|
||||
}
|
||||
|
||||
static void sas_parse_addr(u8 *sas_addr, const char *p)
|
||||
@ -1108,16 +1060,12 @@ EXPORT_SYMBOL_GPL(sas_request_addr);
|
||||
EXPORT_SYMBOL_GPL(sas_queuecommand);
|
||||
EXPORT_SYMBOL_GPL(sas_target_alloc);
|
||||
EXPORT_SYMBOL_GPL(sas_slave_configure);
|
||||
EXPORT_SYMBOL_GPL(sas_slave_destroy);
|
||||
EXPORT_SYMBOL_GPL(sas_change_queue_depth);
|
||||
EXPORT_SYMBOL_GPL(sas_change_queue_type);
|
||||
EXPORT_SYMBOL_GPL(sas_bios_param);
|
||||
EXPORT_SYMBOL_GPL(__sas_task_abort);
|
||||
EXPORT_SYMBOL_GPL(sas_task_abort);
|
||||
EXPORT_SYMBOL_GPL(sas_phy_reset);
|
||||
EXPORT_SYMBOL_GPL(sas_phy_enable);
|
||||
EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
|
||||
EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
|
||||
EXPORT_SYMBOL_GPL(sas_slave_alloc);
|
||||
EXPORT_SYMBOL_GPL(sas_target_destroy);
|
||||
EXPORT_SYMBOL_GPL(sas_ioctl);
|
||||
|
@ -534,6 +534,7 @@ struct lpfc_hba {
|
||||
void (*lpfc_scsi_prep_cmnd)
|
||||
(struct lpfc_vport *, struct lpfc_scsi_buf *,
|
||||
struct lpfc_nodelist *);
|
||||
|
||||
/* IOCB interface function jump table entries */
|
||||
int (*__lpfc_sli_issue_iocb)
|
||||
(struct lpfc_hba *, uint32_t,
|
||||
@ -541,8 +542,6 @@ struct lpfc_hba {
|
||||
void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *,
|
||||
struct lpfc_iocbq *);
|
||||
int (*lpfc_hba_down_post)(struct lpfc_hba *phba);
|
||||
|
||||
|
||||
IOCB_t * (*lpfc_get_iocb_from_iocbq)
|
||||
(struct lpfc_iocbq *);
|
||||
void (*lpfc_scsi_cmd_iocb_cmpl)
|
||||
@ -551,10 +550,12 @@ struct lpfc_hba {
|
||||
/* MBOX interface function jump table entries */
|
||||
int (*lpfc_sli_issue_mbox)
|
||||
(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
|
||||
|
||||
/* Slow-path IOCB process function jump table entries */
|
||||
void (*lpfc_sli_handle_slow_ring_event)
|
||||
(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||
uint32_t mask);
|
||||
|
||||
/* INIT device interface function jump table entries */
|
||||
int (*lpfc_sli_hbq_to_firmware)
|
||||
(struct lpfc_hba *, uint32_t, struct hbq_dmabuf *);
|
||||
@ -573,6 +574,10 @@ struct lpfc_hba {
|
||||
int (*lpfc_selective_reset)
|
||||
(struct lpfc_hba *);
|
||||
|
||||
int (*lpfc_bg_scsi_prep_dma_buf)
|
||||
(struct lpfc_hba *, struct lpfc_scsi_buf *);
|
||||
/* Add new entries here */
|
||||
|
||||
/* SLI4 specific HBA data structure */
|
||||
struct lpfc_sli4_hba sli4_hba;
|
||||
|
||||
@ -838,6 +843,7 @@ struct lpfc_hba {
|
||||
struct dentry *debug_writeGuard; /* inject write guard_tag errors */
|
||||
struct dentry *debug_writeApp; /* inject write app_tag errors */
|
||||
struct dentry *debug_writeRef; /* inject write ref_tag errors */
|
||||
struct dentry *debug_readGuard; /* inject read guard_tag errors */
|
||||
struct dentry *debug_readApp; /* inject read app_tag errors */
|
||||
struct dentry *debug_readRef; /* inject read ref_tag errors */
|
||||
|
||||
@ -845,10 +851,11 @@ struct lpfc_hba {
|
||||
uint32_t lpfc_injerr_wgrd_cnt;
|
||||
uint32_t lpfc_injerr_wapp_cnt;
|
||||
uint32_t lpfc_injerr_wref_cnt;
|
||||
uint32_t lpfc_injerr_rgrd_cnt;
|
||||
uint32_t lpfc_injerr_rapp_cnt;
|
||||
uint32_t lpfc_injerr_rref_cnt;
|
||||
sector_t lpfc_injerr_lba;
|
||||
#define LPFC_INJERR_LBA_OFF (sector_t)0xffffffffffffffff
|
||||
#define LPFC_INJERR_LBA_OFF (sector_t)(-1)
|
||||
|
||||
struct dentry *debug_slow_ring_trc;
|
||||
struct lpfc_debugfs_trc *slow_ring_trc;
|
||||
|
@ -353,7 +353,7 @@ lpfc_fwrev_show(struct device *dev, struct device_attribute *attr,
|
||||
struct lpfc_hba *phba = vport->phba;
|
||||
uint32_t if_type;
|
||||
uint8_t sli_family;
|
||||
char fwrev[32];
|
||||
char fwrev[FW_REV_STR_SIZE];
|
||||
int len;
|
||||
|
||||
lpfc_decode_firmware_rev(phba, fwrev, 1);
|
||||
@ -922,11 +922,15 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
|
||||
rc = lpfc_sli4_pdev_status_reg_wait(phba);
|
||||
|
||||
if (rc == -EPERM) {
|
||||
/* no privilage for reset, restore if needed */
|
||||
if (before_fc_flag & FC_OFFLINE_MODE)
|
||||
goto out;
|
||||
/* no privilage for reset */
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"3150 No privilage to perform the requested "
|
||||
"access: x%x\n", reg_val);
|
||||
} else if (rc == -EIO) {
|
||||
/* reset failed, there is nothing more we can do */
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"3153 Fail to perform the requested "
|
||||
"access: x%x\n", reg_val);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -589,7 +589,10 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
|
||||
}
|
||||
cmdiocbq->iocb.un.elsreq64.bdl.bdeSize =
|
||||
(request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
|
||||
cmdiocbq->iocb.ulpContext = rpi;
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi];
|
||||
else
|
||||
cmdiocbq->iocb.ulpContext = rpi;
|
||||
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
|
||||
cmdiocbq->context1 = NULL;
|
||||
cmdiocbq->context2 = NULL;
|
||||
@ -1768,7 +1771,7 @@ lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba)
|
||||
bf_set(lpfc_mbx_set_diag_state_link_type,
|
||||
&link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp);
|
||||
bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req,
|
||||
LPFC_DIAG_LOOPBACK_TYPE_SERDES);
|
||||
LPFC_DIAG_LOOPBACK_TYPE_INTERNAL);
|
||||
|
||||
mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO);
|
||||
if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) {
|
||||
@ -3977,7 +3980,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
||||
case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES:
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
||||
"3106 Handled SLI_CONFIG "
|
||||
"subsys_fcoe, opcode:x%x\n",
|
||||
"subsys_comn, opcode:x%x\n",
|
||||
opcode);
|
||||
rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
|
||||
nemb_mse, dmabuf);
|
||||
@ -3985,7 +3988,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
||||
default:
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
|
||||
"3107 Reject SLI_CONFIG "
|
||||
"subsys_fcoe, opcode:x%x\n",
|
||||
"subsys_comn, opcode:x%x\n",
|
||||
opcode);
|
||||
rc = -EPERM;
|
||||
break;
|
||||
@ -4556,7 +4559,12 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
|
||||
+ sizeof(MAILBOX_t));
|
||||
}
|
||||
} else if (phba->sli_rev == LPFC_SLI_REV4) {
|
||||
if (pmb->mbxCommand == MBX_DUMP_MEMORY) {
|
||||
/* Let type 4 (well known data) through because the data is
|
||||
* returned in varwords[4-8]
|
||||
* otherwise check the recieve length and fetch the buffer addr
|
||||
*/
|
||||
if ((pmb->mbxCommand == MBX_DUMP_MEMORY) &&
|
||||
(pmb->un.varDmp.type != DMP_WELL_KNOWN)) {
|
||||
/* rebuild the command for sli4 using our own buffers
|
||||
* like we do for biu diags
|
||||
*/
|
||||
|
@ -462,3 +462,4 @@ int lpfc_issue_unreg_vfi(struct lpfc_vport *);
|
||||
int lpfc_selective_reset(struct lpfc_hba *);
|
||||
int lpfc_sli4_read_config(struct lpfc_hba *phba);
|
||||
int lpfc_scsi_buf_update(struct lpfc_hba *phba);
|
||||
void lpfc_sli4_node_prep(struct lpfc_hba *phba);
|
||||
|
@ -1076,7 +1076,7 @@ int
|
||||
lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
|
||||
size_t size)
|
||||
{
|
||||
char fwrev[16];
|
||||
char fwrev[FW_REV_STR_SIZE];
|
||||
int n;
|
||||
|
||||
lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
|
||||
@ -1834,7 +1834,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
|
||||
uint8_t *fwname;
|
||||
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
sprintf(fwrevision, "%s", vp->rev.opFwName);
|
||||
snprintf(fwrevision, FW_REV_STR_SIZE, "%s", vp->rev.opFwName);
|
||||
else if (vp->rev.rBit) {
|
||||
if (psli->sli_flag & LPFC_SLI_ACTIVE)
|
||||
rev = vp->rev.sli2FwRev;
|
||||
|
@ -1019,6 +1019,8 @@ lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
|
||||
cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wapp_cnt);
|
||||
else if (dent == phba->debug_writeRef)
|
||||
cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wref_cnt);
|
||||
else if (dent == phba->debug_readGuard)
|
||||
cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rgrd_cnt);
|
||||
else if (dent == phba->debug_readApp)
|
||||
cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rapp_cnt);
|
||||
else if (dent == phba->debug_readRef)
|
||||
@ -1057,6 +1059,8 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
|
||||
phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp;
|
||||
else if (dent == phba->debug_writeRef)
|
||||
phba->lpfc_injerr_wref_cnt = (uint32_t)tmp;
|
||||
else if (dent == phba->debug_readGuard)
|
||||
phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp;
|
||||
else if (dent == phba->debug_readApp)
|
||||
phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp;
|
||||
else if (dent == phba->debug_readRef)
|
||||
@ -3978,6 +3982,17 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
|
||||
goto debug_failed;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "readGuardInjErr");
|
||||
phba->debug_readGuard =
|
||||
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
|
||||
phba->hba_debugfs_root,
|
||||
phba, &lpfc_debugfs_op_dif_err);
|
||||
if (!phba->debug_readGuard) {
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
|
||||
"0808 Cannot create debugfs readGuard\n");
|
||||
goto debug_failed;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "readAppInjErr");
|
||||
phba->debug_readApp =
|
||||
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
|
||||
@ -4318,6 +4333,10 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
|
||||
debugfs_remove(phba->debug_writeRef); /* writeRef */
|
||||
phba->debug_writeRef = NULL;
|
||||
}
|
||||
if (phba->debug_readGuard) {
|
||||
debugfs_remove(phba->debug_readGuard); /* readGuard */
|
||||
phba->debug_readGuard = NULL;
|
||||
}
|
||||
if (phba->debug_readApp) {
|
||||
debugfs_remove(phba->debug_readApp); /* readApp */
|
||||
phba->debug_readApp = NULL;
|
||||
|
@ -1526,7 +1526,6 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
|
||||
memcpy(&ndlp->active_rrqs.xri_bitmap,
|
||||
&rrq.xri_bitmap,
|
||||
sizeof(ndlp->active_rrqs.xri_bitmap));
|
||||
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
|
||||
/* Since we are swapping the ndlp passed in with the new one
|
||||
* and the did has already been swapped, copy over the
|
||||
* state and names.
|
||||
@ -1536,6 +1535,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
|
||||
memcpy(&new_ndlp->nlp_nodename, &ndlp->nlp_nodename,
|
||||
sizeof(struct lpfc_name));
|
||||
new_ndlp->nlp_state = ndlp->nlp_state;
|
||||
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
|
||||
/* Fix up the rport accordingly */
|
||||
rport = ndlp->rport;
|
||||
if (rport) {
|
||||
@ -7172,7 +7172,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
||||
goto out;
|
||||
/* FDISC failed */
|
||||
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
|
||||
"0126 FDISC failed. (%d/%d)\n",
|
||||
"0126 FDISC failed. (x%x/x%x)\n",
|
||||
irsp->ulpStatus, irsp->un.ulpWord[4]);
|
||||
goto fdisc_failed;
|
||||
}
|
||||
@ -7283,6 +7283,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
int rc;
|
||||
|
||||
vport->port_state = LPFC_FDISC;
|
||||
vport->fc_myDID = 0;
|
||||
cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
|
||||
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
|
||||
ELS_CMD_FDISC);
|
||||
|
@ -2977,9 +2977,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
|
||||
"topology\n");
|
||||
/* Get Loop Map information */
|
||||
if (bf_get(lpfc_mbx_read_top_il, la)) {
|
||||
spin_lock_irq(shost->host_lock);
|
||||
spin_lock(shost->host_lock);
|
||||
vport->fc_flag |= FC_LBIT;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
spin_unlock(shost->host_lock);
|
||||
}
|
||||
|
||||
vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
|
||||
@ -3029,9 +3029,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
|
||||
phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
|
||||
}
|
||||
vport->fc_myDID = phba->fc_pref_DID;
|
||||
spin_lock_irq(shost->host_lock);
|
||||
spin_lock(shost->host_lock);
|
||||
vport->fc_flag |= FC_LBIT;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
spin_unlock(shost->host_lock);
|
||||
}
|
||||
spin_unlock_irq(&phba->hbalock);
|
||||
|
||||
@ -5332,6 +5332,10 @@ lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param)
|
||||
{
|
||||
uint16_t *rpi = param;
|
||||
|
||||
/* check for active node */
|
||||
if (!NLP_CHK_NODE_ACT(ndlp))
|
||||
return 0;
|
||||
|
||||
return ndlp->nlp_rpi == *rpi;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*******************************************************************
|
||||
* This file is part of the Emulex Linux Device Driver for *
|
||||
* Fibre Channel Host Bus Adapters. *
|
||||
* Copyright (C) 2004-2010 Emulex. All rights reserved. *
|
||||
* Copyright (C) 2004-2011 Emulex. All rights reserved. *
|
||||
* EMULEX and SLI are trademarks of Emulex. *
|
||||
* www.emulex.com *
|
||||
* *
|
||||
@ -70,6 +70,7 @@
|
||||
/* vendor ID used in SCSI netlink calls */
|
||||
#define LPFC_NL_VENDOR_ID (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX)
|
||||
|
||||
#define FW_REV_STR_SIZE 32
|
||||
/* Common Transport structures and definitions */
|
||||
|
||||
union CtRevisionId {
|
||||
@ -2567,6 +2568,8 @@ typedef struct {
|
||||
|
||||
#define DMP_MEM_REG 0x1
|
||||
#define DMP_NV_PARAMS 0x2
|
||||
#define DMP_LMSD 0x3 /* Link Module Serial Data */
|
||||
#define DMP_WELL_KNOWN 0x4
|
||||
|
||||
#define DMP_REGION_VPD 0xe
|
||||
#define DMP_VPD_SIZE 0x400 /* maximum amount of VPD */
|
||||
|
@ -321,6 +321,10 @@ struct lpfc_cqe {
|
||||
#define CQE_STATUS_CMD_REJECT 0xb
|
||||
#define CQE_STATUS_FCP_TGT_LENCHECK 0xc
|
||||
#define CQE_STATUS_NEED_BUFF_ENTRY 0xf
|
||||
#define CQE_STATUS_DI_ERROR 0x16
|
||||
|
||||
/* Used when mapping CQE status to IOCB */
|
||||
#define LPFC_IOCB_STATUS_MASK 0xf
|
||||
|
||||
/* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */
|
||||
#define CQE_HW_STATUS_NO_ERR 0x0
|
||||
@ -348,6 +352,21 @@ struct lpfc_wcqe_complete {
|
||||
#define lpfc_wcqe_c_hw_status_WORD word0
|
||||
uint32_t total_data_placed;
|
||||
uint32_t parameter;
|
||||
#define lpfc_wcqe_c_bg_edir_SHIFT 5
|
||||
#define lpfc_wcqe_c_bg_edir_MASK 0x00000001
|
||||
#define lpfc_wcqe_c_bg_edir_WORD parameter
|
||||
#define lpfc_wcqe_c_bg_tdpv_SHIFT 3
|
||||
#define lpfc_wcqe_c_bg_tdpv_MASK 0x00000001
|
||||
#define lpfc_wcqe_c_bg_tdpv_WORD parameter
|
||||
#define lpfc_wcqe_c_bg_re_SHIFT 2
|
||||
#define lpfc_wcqe_c_bg_re_MASK 0x00000001
|
||||
#define lpfc_wcqe_c_bg_re_WORD parameter
|
||||
#define lpfc_wcqe_c_bg_ae_SHIFT 1
|
||||
#define lpfc_wcqe_c_bg_ae_MASK 0x00000001
|
||||
#define lpfc_wcqe_c_bg_ae_WORD parameter
|
||||
#define lpfc_wcqe_c_bg_ge_SHIFT 0
|
||||
#define lpfc_wcqe_c_bg_ge_MASK 0x00000001
|
||||
#define lpfc_wcqe_c_bg_ge_WORD parameter
|
||||
uint32_t word3;
|
||||
#define lpfc_wcqe_c_valid_SHIFT lpfc_cqe_valid_SHIFT
|
||||
#define lpfc_wcqe_c_valid_MASK lpfc_cqe_valid_MASK
|
||||
@ -359,8 +378,8 @@ struct lpfc_wcqe_complete {
|
||||
#define lpfc_wcqe_c_pv_MASK 0x00000001
|
||||
#define lpfc_wcqe_c_pv_WORD word3
|
||||
#define lpfc_wcqe_c_priority_SHIFT 24
|
||||
#define lpfc_wcqe_c_priority_MASK 0x00000007
|
||||
#define lpfc_wcqe_c_priority_WORD word3
|
||||
#define lpfc_wcqe_c_priority_MASK 0x00000007
|
||||
#define lpfc_wcqe_c_priority_WORD word3
|
||||
#define lpfc_wcqe_c_code_SHIFT lpfc_cqe_code_SHIFT
|
||||
#define lpfc_wcqe_c_code_MASK lpfc_cqe_code_MASK
|
||||
#define lpfc_wcqe_c_code_WORD lpfc_cqe_code_WORD
|
||||
@ -715,12 +734,20 @@ struct lpfc_register {
|
||||
#define lpfc_eqcq_doorbell_eqci_SHIFT 9
|
||||
#define lpfc_eqcq_doorbell_eqci_MASK 0x0001
|
||||
#define lpfc_eqcq_doorbell_eqci_WORD word0
|
||||
#define lpfc_eqcq_doorbell_cqid_SHIFT 0
|
||||
#define lpfc_eqcq_doorbell_cqid_MASK 0x03FF
|
||||
#define lpfc_eqcq_doorbell_cqid_WORD word0
|
||||
#define lpfc_eqcq_doorbell_eqid_SHIFT 0
|
||||
#define lpfc_eqcq_doorbell_eqid_MASK 0x01FF
|
||||
#define lpfc_eqcq_doorbell_eqid_WORD word0
|
||||
#define lpfc_eqcq_doorbell_cqid_lo_SHIFT 0
|
||||
#define lpfc_eqcq_doorbell_cqid_lo_MASK 0x03FF
|
||||
#define lpfc_eqcq_doorbell_cqid_lo_WORD word0
|
||||
#define lpfc_eqcq_doorbell_cqid_hi_SHIFT 11
|
||||
#define lpfc_eqcq_doorbell_cqid_hi_MASK 0x001F
|
||||
#define lpfc_eqcq_doorbell_cqid_hi_WORD word0
|
||||
#define lpfc_eqcq_doorbell_eqid_lo_SHIFT 0
|
||||
#define lpfc_eqcq_doorbell_eqid_lo_MASK 0x01FF
|
||||
#define lpfc_eqcq_doorbell_eqid_lo_WORD word0
|
||||
#define lpfc_eqcq_doorbell_eqid_hi_SHIFT 11
|
||||
#define lpfc_eqcq_doorbell_eqid_hi_MASK 0x001F
|
||||
#define lpfc_eqcq_doorbell_eqid_hi_WORD word0
|
||||
#define LPFC_CQID_HI_FIELD_SHIFT 10
|
||||
#define LPFC_EQID_HI_FIELD_SHIFT 9
|
||||
|
||||
#define LPFC_BMBX 0x0160
|
||||
#define lpfc_bmbx_addr_SHIFT 2
|
||||
@ -3313,7 +3340,11 @@ struct xmit_bls_rsp64_wqe {
|
||||
uint32_t rsrvd4;
|
||||
struct wqe_did wqe_dest;
|
||||
struct wqe_common wqe_com; /* words 6-11 */
|
||||
uint32_t rsvd_12_15[4];
|
||||
uint32_t word12;
|
||||
#define xmit_bls_rsp64_temprpi_SHIFT 0
|
||||
#define xmit_bls_rsp64_temprpi_MASK 0x0000ffff
|
||||
#define xmit_bls_rsp64_temprpi_WORD word12
|
||||
uint32_t rsvd_13_15[3];
|
||||
};
|
||||
|
||||
struct wqe_rctl_dfctl {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/aer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
@ -1474,8 +1475,12 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
|
||||
phba->sli4_hba.u.if_type2.STATUSregaddr,
|
||||
&portstat_reg.word0);
|
||||
/* consider PCI bus read error as pci_channel_offline */
|
||||
if (pci_rd_rc1 == -EIO)
|
||||
if (pci_rd_rc1 == -EIO) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
||||
"3151 PCI bus read access failure: x%x\n",
|
||||
readl(phba->sli4_hba.u.if_type2.STATUSregaddr));
|
||||
return;
|
||||
}
|
||||
reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
|
||||
reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr);
|
||||
if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) {
|
||||
@ -1525,6 +1530,9 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
|
||||
}
|
||||
/* fall through for not able to recover */
|
||||
}
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
||||
"3152 Unrecoverable error, bring the port "
|
||||
"offline\n");
|
||||
lpfc_sli4_offline_eratt(phba);
|
||||
break;
|
||||
case LPFC_SLI_INTF_IF_TYPE_1:
|
||||
@ -2333,13 +2341,20 @@ lpfc_cleanup(struct lpfc_vport *vport)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* take care of nodes in unused state before the state
|
||||
* machine taking action.
|
||||
*/
|
||||
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
|
||||
lpfc_nlp_put(ndlp);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ndlp->nlp_type & NLP_FABRIC)
|
||||
lpfc_disc_state_machine(vport, ndlp, NULL,
|
||||
NLP_EVT_DEVICE_RECOVERY);
|
||||
|
||||
lpfc_disc_state_machine(vport, ndlp, NULL,
|
||||
NLP_EVT_DEVICE_RM);
|
||||
|
||||
}
|
||||
|
||||
/* At this point, ALL ndlp's should be gone
|
||||
@ -2512,6 +2527,42 @@ lpfc_block_mgmt_io(struct lpfc_hba * phba)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_sli4_node_prep - Assign RPIs for active nodes.
|
||||
* @phba: pointer to lpfc hba data structure.
|
||||
*
|
||||
* Allocate RPIs for all active remote nodes. This is needed whenever
|
||||
* an SLI4 adapter is reset and the driver is not unloading. Its purpose
|
||||
* is to fixup the temporary rpi assignments.
|
||||
**/
|
||||
void
|
||||
lpfc_sli4_node_prep(struct lpfc_hba *phba)
|
||||
{
|
||||
struct lpfc_nodelist *ndlp, *next_ndlp;
|
||||
struct lpfc_vport **vports;
|
||||
int i;
|
||||
|
||||
if (phba->sli_rev != LPFC_SLI_REV4)
|
||||
return;
|
||||
|
||||
vports = lpfc_create_vport_work_array(phba);
|
||||
if (vports != NULL) {
|
||||
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
|
||||
if (vports[i]->load_flag & FC_UNLOADING)
|
||||
continue;
|
||||
|
||||
list_for_each_entry_safe(ndlp, next_ndlp,
|
||||
&vports[i]->fc_nodes,
|
||||
nlp_listp) {
|
||||
if (NLP_CHK_NODE_ACT(ndlp))
|
||||
ndlp->nlp_rpi =
|
||||
lpfc_sli4_alloc_rpi(phba);
|
||||
}
|
||||
}
|
||||
}
|
||||
lpfc_destroy_vport_work_array(phba, vports);
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_online - Initialize and bring a HBA online
|
||||
* @phba: pointer to lpfc hba data structure.
|
||||
@ -2653,6 +2704,15 @@ lpfc_offline_prep(struct lpfc_hba * phba)
|
||||
}
|
||||
spin_lock_irq(shost->host_lock);
|
||||
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
|
||||
|
||||
/*
|
||||
* Whenever an SLI4 port goes offline, free the
|
||||
* RPI. A new RPI when the adapter port comes
|
||||
* back online.
|
||||
*/
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi);
|
||||
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
lpfc_unreg_rpi(vports[i], ndlp);
|
||||
}
|
||||
@ -4327,6 +4387,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
||||
uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
|
||||
struct lpfc_mqe *mqe;
|
||||
int longs, sli_family;
|
||||
int sges_per_segment;
|
||||
|
||||
/* Before proceed, wait for POST done and device ready */
|
||||
rc = lpfc_sli4_post_status_check(phba);
|
||||
@ -4390,6 +4451,11 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
||||
phba->fc_map[1] = LPFC_FCOE_FCF_MAP1;
|
||||
phba->fc_map[2] = LPFC_FCOE_FCF_MAP2;
|
||||
|
||||
/* With BlockGuard we can have multiple SGEs per Data Segemnt */
|
||||
sges_per_segment = 1;
|
||||
if (phba->cfg_enable_bg)
|
||||
sges_per_segment = 2;
|
||||
|
||||
/*
|
||||
* Since the sg_tablesize is module parameter, the sg_dma_buf_size
|
||||
* used to create the sg_dma_buf_pool must be dynamically calculated.
|
||||
@ -4398,7 +4464,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
||||
* sgl sizes of must be a power of 2.
|
||||
*/
|
||||
buf_size = (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) +
|
||||
((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge)));
|
||||
(((phba->cfg_sg_seg_cnt * sges_per_segment) + 2) *
|
||||
sizeof(struct sli4_sge)));
|
||||
|
||||
sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf);
|
||||
max_buf_size = LPFC_SLI4_MAX_BUF_SIZE;
|
||||
@ -4415,6 +4482,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (dma_buf_size = LPFC_SLI4_MIN_BUF_SIZE;
|
||||
dma_buf_size < max_buf_size && buf_size > dma_buf_size;
|
||||
dma_buf_size = dma_buf_size << 1)
|
||||
@ -7223,19 +7291,17 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
if (bf_get(lpfc_sliport_status_rn, ®_data))
|
||||
reset_again++;
|
||||
if (bf_get(lpfc_sliport_status_rdy, ®_data))
|
||||
break;
|
||||
if (bf_get(lpfc_sliport_status_rn, ®_data)) {
|
||||
reset_again++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the port responds to the init request with
|
||||
* reset needed, delay for a bit and restart the loop.
|
||||
*/
|
||||
if (reset_again) {
|
||||
if (reset_again && (rdy_chk < 1000)) {
|
||||
msleep(10);
|
||||
reset_again = 0;
|
||||
continue;
|
||||
@ -8112,6 +8178,9 @@ lpfc_unset_hba(struct lpfc_hba *phba)
|
||||
vport->load_flag |= FC_UNLOADING;
|
||||
spin_unlock_irq(shost->host_lock);
|
||||
|
||||
kfree(phba->vpi_bmask);
|
||||
kfree(phba->vpi_ids);
|
||||
|
||||
lpfc_stop_hba_timers(phba);
|
||||
|
||||
phba->pport->work_port_events = 0;
|
||||
@ -8644,6 +8713,9 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)
|
||||
/* Final cleanup of txcmplq and reset the HBA */
|
||||
lpfc_sli_brdrestart(phba);
|
||||
|
||||
kfree(phba->vpi_bmask);
|
||||
kfree(phba->vpi_ids);
|
||||
|
||||
lpfc_stop_hba_timers(phba);
|
||||
spin_lock_irq(&phba->hbalock);
|
||||
list_del_init(&vport->listentry);
|
||||
@ -9058,7 +9130,7 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
|
||||
int
|
||||
lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
|
||||
{
|
||||
char fwrev[32];
|
||||
char fwrev[FW_REV_STR_SIZE];
|
||||
struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data;
|
||||
struct list_head dma_buffer_list;
|
||||
int i, rc = 0;
|
||||
@ -10012,6 +10084,36 @@ lpfc_io_resume(struct pci_dev *pdev)
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_mgmt_open - method called when 'lpfcmgmt' is opened from userspace
|
||||
* @inode: pointer to the inode representing the lpfcmgmt device
|
||||
* @filep: pointer to the file representing the open lpfcmgmt device
|
||||
*
|
||||
* This routine puts a reference count on the lpfc module whenever the
|
||||
* character device is opened
|
||||
**/
|
||||
static int
|
||||
lpfc_mgmt_open(struct inode *inode, struct file *filep)
|
||||
{
|
||||
try_module_get(THIS_MODULE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_mgmt_release - method called when 'lpfcmgmt' is closed in userspace
|
||||
* @inode: pointer to the inode representing the lpfcmgmt device
|
||||
* @filep: pointer to the file representing the open lpfcmgmt device
|
||||
*
|
||||
* This routine removes a reference count from the lpfc module when the
|
||||
* character device is closed
|
||||
**/
|
||||
static int
|
||||
lpfc_mgmt_release(struct inode *inode, struct file *filep)
|
||||
{
|
||||
module_put(THIS_MODULE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_device_id lpfc_id_table[] = {
|
||||
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
@ -10124,6 +10226,17 @@ static struct pci_driver lpfc_driver = {
|
||||
.err_handler = &lpfc_err_handler,
|
||||
};
|
||||
|
||||
static const struct file_operations lpfc_mgmt_fop = {
|
||||
.open = lpfc_mgmt_open,
|
||||
.release = lpfc_mgmt_release,
|
||||
};
|
||||
|
||||
static struct miscdevice lpfc_mgmt_dev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "lpfcmgmt",
|
||||
.fops = &lpfc_mgmt_fop,
|
||||
};
|
||||
|
||||
/**
|
||||
* lpfc_init - lpfc module initialization routine
|
||||
*
|
||||
@ -10144,6 +10257,11 @@ lpfc_init(void)
|
||||
printk(LPFC_MODULE_DESC "\n");
|
||||
printk(LPFC_COPYRIGHT "\n");
|
||||
|
||||
error = misc_register(&lpfc_mgmt_dev);
|
||||
if (error)
|
||||
printk(KERN_ERR "Could not register lpfcmgmt device, "
|
||||
"misc_register returned with status %d", error);
|
||||
|
||||
if (lpfc_enable_npiv) {
|
||||
lpfc_transport_functions.vport_create = lpfc_vport_create;
|
||||
lpfc_transport_functions.vport_delete = lpfc_vport_delete;
|
||||
@ -10180,6 +10298,7 @@ lpfc_init(void)
|
||||
static void __exit
|
||||
lpfc_exit(void)
|
||||
{
|
||||
misc_deregister(&lpfc_mgmt_dev);
|
||||
pci_unregister_driver(&lpfc_driver);
|
||||
fc_release_transport(lpfc_transport_template);
|
||||
if (lpfc_enable_npiv)
|
||||
|
@ -48,6 +48,10 @@ static int
|
||||
lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
struct lpfc_name *nn, struct lpfc_name *pn)
|
||||
{
|
||||
/* First, we MUST have a RPI registered */
|
||||
if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED))
|
||||
return 0;
|
||||
|
||||
/* Compare the ADISC rsp WWNN / WWPN matches our internal node
|
||||
* table entry for that node.
|
||||
*/
|
||||
@ -385,6 +389,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
if (!mbox)
|
||||
goto out;
|
||||
|
||||
/* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
|
||||
if (phba->sli_rev == LPFC_SLI_REV4)
|
||||
lpfc_unreg_rpi(vport, ndlp);
|
||||
|
||||
rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
|
||||
(uint8_t *) sp, mbox, ndlp->nlp_rpi);
|
||||
if (rc) {
|
||||
@ -445,11 +453,43 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_mbx_cmpl_resume_rpi - Resume RPI completion routine
|
||||
* @phba: pointer to lpfc hba data structure.
|
||||
* @mboxq: pointer to mailbox object
|
||||
*
|
||||
* This routine is invoked to issue a completion to a rcv'ed
|
||||
* ADISC or PDISC after the paused RPI has been resumed.
|
||||
**/
|
||||
static void
|
||||
lpfc_mbx_cmpl_resume_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
|
||||
{
|
||||
struct lpfc_vport *vport;
|
||||
struct lpfc_iocbq *elsiocb;
|
||||
struct lpfc_nodelist *ndlp;
|
||||
uint32_t cmd;
|
||||
|
||||
elsiocb = (struct lpfc_iocbq *)mboxq->context1;
|
||||
ndlp = (struct lpfc_nodelist *) mboxq->context2;
|
||||
vport = mboxq->vport;
|
||||
cmd = elsiocb->drvrTimeout;
|
||||
|
||||
if (cmd == ELS_CMD_ADISC) {
|
||||
lpfc_els_rsp_adisc_acc(vport, elsiocb, ndlp);
|
||||
} else {
|
||||
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, elsiocb,
|
||||
ndlp, NULL);
|
||||
}
|
||||
kfree(elsiocb);
|
||||
mempool_free(mboxq, phba->mbox_mem_pool);
|
||||
}
|
||||
|
||||
static int
|
||||
lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
struct lpfc_iocbq *cmdiocb)
|
||||
{
|
||||
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
||||
struct lpfc_iocbq *elsiocb;
|
||||
struct lpfc_dmabuf *pcmd;
|
||||
struct serv_parm *sp;
|
||||
struct lpfc_name *pnn, *ppn;
|
||||
@ -475,12 +515,43 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
|
||||
icmd = &cmdiocb->iocb;
|
||||
if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {
|
||||
|
||||
/*
|
||||
* As soon as we send ACC, the remote NPort can
|
||||
* start sending us data. Thus, for SLI4 we must
|
||||
* resume the RPI before the ACC goes out.
|
||||
*/
|
||||
if (vport->phba->sli_rev == LPFC_SLI_REV4) {
|
||||
elsiocb = kmalloc(sizeof(struct lpfc_iocbq),
|
||||
GFP_KERNEL);
|
||||
if (elsiocb) {
|
||||
|
||||
/* Save info from cmd IOCB used in rsp */
|
||||
memcpy((uint8_t *)elsiocb, (uint8_t *)cmdiocb,
|
||||
sizeof(struct lpfc_iocbq));
|
||||
|
||||
/* Save the ELS cmd */
|
||||
elsiocb->drvrTimeout = cmd;
|
||||
|
||||
lpfc_sli4_resume_rpi(ndlp,
|
||||
lpfc_mbx_cmpl_resume_rpi, elsiocb);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == ELS_CMD_ADISC) {
|
||||
lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
|
||||
} else {
|
||||
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
|
||||
NULL);
|
||||
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb,
|
||||
ndlp, NULL);
|
||||
}
|
||||
out:
|
||||
/* If we are authenticated, move to the proper state */
|
||||
if (ndlp->nlp_type & NLP_FCP_TARGET)
|
||||
lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
|
||||
else
|
||||
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/* Reject this request because invalid parameters */
|
||||
@ -1229,7 +1300,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
|
||||
}
|
||||
|
||||
if (phba->sli_rev == LPFC_SLI_REV4) {
|
||||
rc = lpfc_sli4_resume_rpi(ndlp);
|
||||
rc = lpfc_sli4_resume_rpi(ndlp, NULL, NULL);
|
||||
if (rc) {
|
||||
/* Stay in state and retry. */
|
||||
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -293,7 +293,9 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
|
||||
}
|
||||
bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released);
|
||||
bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT);
|
||||
bf_set(lpfc_eqcq_doorbell_eqid, &doorbell, q->queue_id);
|
||||
bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell,
|
||||
(q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT));
|
||||
bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id);
|
||||
writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
|
||||
/* PCI read to flush PCI pipeline on re-arming for INTx mode */
|
||||
if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM))
|
||||
@ -372,7 +374,9 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
|
||||
bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1);
|
||||
bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released);
|
||||
bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_COMPLETION);
|
||||
bf_set(lpfc_eqcq_doorbell_cqid, &doorbell, q->queue_id);
|
||||
bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell,
|
||||
(q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT));
|
||||
bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id);
|
||||
writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr);
|
||||
return released;
|
||||
}
|
||||
@ -553,81 +557,6 @@ __lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag)
|
||||
return sglq;
|
||||
}
|
||||
|
||||
/**
|
||||
* __lpfc_set_rrq_active - set RRQ active bit in the ndlp's xri_bitmap.
|
||||
* @phba: Pointer to HBA context object.
|
||||
* @ndlp: nodelist pointer for this target.
|
||||
* @xritag: xri used in this exchange.
|
||||
* @rxid: Remote Exchange ID.
|
||||
* @send_rrq: Flag used to determine if we should send rrq els cmd.
|
||||
*
|
||||
* This function is called with hbalock held.
|
||||
* The active bit is set in the ndlp's active rrq xri_bitmap. Allocates an
|
||||
* rrq struct and adds it to the active_rrq_list.
|
||||
*
|
||||
* returns 0 for rrq slot for this xri
|
||||
* < 0 Were not able to get rrq mem or invalid parameter.
|
||||
**/
|
||||
static int
|
||||
__lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
|
||||
uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
|
||||
{
|
||||
struct lpfc_node_rrq *rrq;
|
||||
int empty;
|
||||
uint32_t did = 0;
|
||||
|
||||
|
||||
if (!ndlp)
|
||||
return -EINVAL;
|
||||
|
||||
if (!phba->cfg_enable_rrq)
|
||||
return -EINVAL;
|
||||
|
||||
if (phba->pport->load_flag & FC_UNLOADING) {
|
||||
phba->hba_flag &= ~HBA_RRQ_ACTIVE;
|
||||
goto out;
|
||||
}
|
||||
did = ndlp->nlp_DID;
|
||||
|
||||
/*
|
||||
* set the active bit even if there is no mem available.
|
||||
*/
|
||||
if (NLP_CHK_FREE_REQ(ndlp))
|
||||
goto out;
|
||||
|
||||
if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
|
||||
goto out;
|
||||
|
||||
if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap))
|
||||
goto out;
|
||||
|
||||
rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
|
||||
if (rrq) {
|
||||
rrq->send_rrq = send_rrq;
|
||||
rrq->xritag = xritag;
|
||||
rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
|
||||
rrq->ndlp = ndlp;
|
||||
rrq->nlp_DID = ndlp->nlp_DID;
|
||||
rrq->vport = ndlp->vport;
|
||||
rrq->rxid = rxid;
|
||||
empty = list_empty(&phba->active_rrq_list);
|
||||
rrq->send_rrq = send_rrq;
|
||||
list_add_tail(&rrq->list, &phba->active_rrq_list);
|
||||
if (!(phba->hba_flag & HBA_RRQ_ACTIVE)) {
|
||||
phba->hba_flag |= HBA_RRQ_ACTIVE;
|
||||
if (empty)
|
||||
lpfc_worker_wake_up(phba);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
out:
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||
"2921 Can't set rrq active xri:0x%x rxid:0x%x"
|
||||
" DID:0x%x Send:%d\n",
|
||||
xritag, rxid, did, send_rrq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap.
|
||||
* @phba: Pointer to HBA context object.
|
||||
@ -856,15 +785,68 @@ lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
|
||||
**/
|
||||
int
|
||||
lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
|
||||
uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
|
||||
uint16_t xritag, uint16_t rxid, uint16_t send_rrq)
|
||||
{
|
||||
int ret;
|
||||
unsigned long iflags;
|
||||
struct lpfc_node_rrq *rrq;
|
||||
int empty;
|
||||
|
||||
if (!ndlp)
|
||||
return -EINVAL;
|
||||
|
||||
if (!phba->cfg_enable_rrq)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||
ret = __lpfc_set_rrq_active(phba, ndlp, xritag, rxid, send_rrq);
|
||||
if (phba->pport->load_flag & FC_UNLOADING) {
|
||||
phba->hba_flag &= ~HBA_RRQ_ACTIVE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* set the active bit even if there is no mem available.
|
||||
*/
|
||||
if (NLP_CHK_FREE_REQ(ndlp))
|
||||
goto out;
|
||||
|
||||
if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
|
||||
goto out;
|
||||
|
||||
if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap))
|
||||
goto out;
|
||||
|
||||
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||
return ret;
|
||||
rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);
|
||||
if (!rrq) {
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||
"3155 Unable to allocate RRQ xri:0x%x rxid:0x%x"
|
||||
" DID:0x%x Send:%d\n",
|
||||
xritag, rxid, ndlp->nlp_DID, send_rrq);
|
||||
return -EINVAL;
|
||||
}
|
||||
rrq->send_rrq = send_rrq;
|
||||
rrq->xritag = xritag;
|
||||
rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
|
||||
rrq->ndlp = ndlp;
|
||||
rrq->nlp_DID = ndlp->nlp_DID;
|
||||
rrq->vport = ndlp->vport;
|
||||
rrq->rxid = rxid;
|
||||
rrq->send_rrq = send_rrq;
|
||||
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||
empty = list_empty(&phba->active_rrq_list);
|
||||
list_add_tail(&rrq->list, &phba->active_rrq_list);
|
||||
phba->hba_flag |= HBA_RRQ_ACTIVE;
|
||||
if (empty)
|
||||
lpfc_worker_wake_up(phba);
|
||||
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||
return 0;
|
||||
out:
|
||||
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||
"2921 Can't set rrq active xri:0x%x rxid:0x%x"
|
||||
" DID:0x%x Send:%d\n",
|
||||
xritag, rxid, ndlp->nlp_DID, send_rrq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5596,6 +5578,8 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba)
|
||||
for (i = 0; i < count; i++)
|
||||
phba->sli4_hba.rpi_ids[i] = base + i;
|
||||
|
||||
lpfc_sli4_node_prep(phba);
|
||||
|
||||
/* VPIs. */
|
||||
count = phba->sli4_hba.max_cfg_param.max_vpi;
|
||||
base = phba->sli4_hba.max_cfg_param.vpi_base;
|
||||
@ -7555,6 +7539,8 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
|
||||
|
||||
sgl = (struct sli4_sge *)sglq->sgl;
|
||||
icmd = &piocbq->iocb;
|
||||
if (icmd->ulpCommand == CMD_XMIT_BLS_RSP64_CX)
|
||||
return sglq->sli4_xritag;
|
||||
if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) {
|
||||
numBdes = icmd->un.genreq64.bdl.bdeSize /
|
||||
sizeof(struct ulp_bde64);
|
||||
@ -7756,6 +7742,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
|
||||
if (if_type == LPFC_SLI_INTF_IF_TYPE_2) {
|
||||
if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
|
||||
*pcmd == ELS_CMD_SCR ||
|
||||
*pcmd == ELS_CMD_FDISC ||
|
||||
*pcmd == ELS_CMD_PLOGI)) {
|
||||
bf_set(els_req64_sp, &wqe->els_req, 1);
|
||||
bf_set(els_req64_sid, &wqe->els_req,
|
||||
@ -7763,7 +7750,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
|
||||
bf_set(wqe_ct, &wqe->els_req.wqe_com, 1);
|
||||
bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
|
||||
phba->vpi_ids[phba->pport->vpi]);
|
||||
} else if (iocbq->context1) {
|
||||
} else if (pcmd && iocbq->context1) {
|
||||
bf_set(wqe_ct, &wqe->els_req.wqe_com, 0);
|
||||
bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
|
||||
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
|
||||
@ -7830,12 +7817,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
|
||||
bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS);
|
||||
/* Always open the exchange */
|
||||
bf_set(wqe_xc, &wqe->fcp_iwrite.wqe_com, 0);
|
||||
bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
|
||||
bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE);
|
||||
bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com,
|
||||
LPFC_WQE_LENLOC_WORD4);
|
||||
bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
|
||||
bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
|
||||
if (iocbq->iocb_flag & LPFC_IO_DIF) {
|
||||
iocbq->iocb_flag &= ~LPFC_IO_DIF;
|
||||
bf_set(wqe_dif, &wqe->generic.wqe_com, 1);
|
||||
}
|
||||
bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
|
||||
break;
|
||||
case CMD_FCP_IREAD64_CR:
|
||||
/* word3 iocb=iotag wqe=payload_offset_len */
|
||||
@ -7849,12 +7840,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
|
||||
bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS);
|
||||
/* Always open the exchange */
|
||||
bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
|
||||
bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
|
||||
bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ);
|
||||
bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com,
|
||||
LPFC_WQE_LENLOC_WORD4);
|
||||
bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
|
||||
bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
|
||||
if (iocbq->iocb_flag & LPFC_IO_DIF) {
|
||||
iocbq->iocb_flag &= ~LPFC_IO_DIF;
|
||||
bf_set(wqe_dif, &wqe->generic.wqe_com, 1);
|
||||
}
|
||||
bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
|
||||
break;
|
||||
case CMD_FCP_ICMND64_CR:
|
||||
/* word3 iocb=IO_TAG wqe=reserved */
|
||||
@ -7982,6 +7977,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
|
||||
xritag = 0;
|
||||
break;
|
||||
case CMD_XMIT_BLS_RSP64_CX:
|
||||
ndlp = (struct lpfc_nodelist *)iocbq->context1;
|
||||
/* As BLS ABTS RSP WQE is very different from other WQEs,
|
||||
* we re-construct this WQE here based on information in
|
||||
* iocbq from scratch.
|
||||
@ -8008,8 +8004,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
|
||||
}
|
||||
bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff);
|
||||
bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1);
|
||||
|
||||
/* Use CT=VPI */
|
||||
bf_set(wqe_els_did, &wqe->xmit_bls_rsp.wqe_dest,
|
||||
ndlp->nlp_DID);
|
||||
bf_set(xmit_bls_rsp64_temprpi, &wqe->xmit_bls_rsp,
|
||||
iocbq->iocb.ulpContext);
|
||||
bf_set(wqe_ct, &wqe->xmit_bls_rsp.wqe_com, 1);
|
||||
bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com,
|
||||
iocbq->iocb.ulpContext);
|
||||
phba->vpi_ids[phba->pport->vpi]);
|
||||
bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1);
|
||||
bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com,
|
||||
LPFC_WQE_LENLOC_NONE);
|
||||
@ -8073,8 +8076,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
|
||||
|
||||
if (piocb->sli4_xritag == NO_XRI) {
|
||||
if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
|
||||
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN ||
|
||||
piocb->iocb.ulpCommand == CMD_XMIT_BLS_RSP64_CX)
|
||||
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
|
||||
sglq = NULL;
|
||||
else {
|
||||
if (pring->txq_cnt) {
|
||||
@ -8384,10 +8386,13 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba,
|
||||
{
|
||||
struct lpfc_vport *vport;
|
||||
|
||||
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
|
||||
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||
"3115 Node Context not found, driver "
|
||||
"ignoring abts err event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vport = ndlp->vport;
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
|
||||
"3116 Port generated FCP XRI ABORT event on "
|
||||
@ -10653,12 +10658,14 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba,
|
||||
struct lpfc_wcqe_complete *wcqe)
|
||||
{
|
||||
unsigned long iflags;
|
||||
uint32_t status;
|
||||
size_t offset = offsetof(struct lpfc_iocbq, iocb);
|
||||
|
||||
memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
|
||||
sizeof(struct lpfc_iocbq) - offset);
|
||||
/* Map WCQE parameters into irspiocb parameters */
|
||||
pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||
status = bf_get(lpfc_wcqe_c_status, wcqe);
|
||||
pIocbIn->iocb.ulpStatus = (status & LPFC_IOCB_STATUS_MASK);
|
||||
if (pIocbOut->iocb_flag & LPFC_IO_FCP)
|
||||
if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR)
|
||||
pIocbIn->iocb.un.fcpi.fcpi_parm =
|
||||
@ -10671,6 +10678,44 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba,
|
||||
pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed;
|
||||
}
|
||||
|
||||
/* Convert BG errors for completion status */
|
||||
if (status == CQE_STATUS_DI_ERROR) {
|
||||
pIocbIn->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
|
||||
|
||||
if (bf_get(lpfc_wcqe_c_bg_edir, wcqe))
|
||||
pIocbIn->iocb.un.ulpWord[4] = IOERR_RX_DMA_FAILED;
|
||||
else
|
||||
pIocbIn->iocb.un.ulpWord[4] = IOERR_TX_DMA_FAILED;
|
||||
|
||||
pIocbIn->iocb.unsli3.sli3_bg.bgstat = 0;
|
||||
if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) /* Guard Check failed */
|
||||
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
|
||||
BGS_GUARD_ERR_MASK;
|
||||
if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) /* App Tag Check failed */
|
||||
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
|
||||
BGS_APPTAG_ERR_MASK;
|
||||
if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) /* Ref Tag Check failed */
|
||||
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
|
||||
BGS_REFTAG_ERR_MASK;
|
||||
|
||||
/* Check to see if there was any good data before the error */
|
||||
if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) {
|
||||
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
|
||||
BGS_HI_WATER_MARK_PRESENT_MASK;
|
||||
pIocbIn->iocb.unsli3.sli3_bg.bghm =
|
||||
wcqe->total_data_placed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set ALL the error bits to indicate we don't know what
|
||||
* type of error it is.
|
||||
*/
|
||||
if (!pIocbIn->iocb.unsli3.sli3_bg.bgstat)
|
||||
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
|
||||
(BGS_REFTAG_ERR_MASK | BGS_APPTAG_ERR_MASK |
|
||||
BGS_GUARD_ERR_MASK);
|
||||
}
|
||||
|
||||
/* Pick up HBA exchange busy condition */
|
||||
if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
|
||||
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||
@ -14042,6 +14087,13 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba,
|
||||
{
|
||||
if (cmd_iocbq)
|
||||
lpfc_sli_release_iocbq(phba, cmd_iocbq);
|
||||
|
||||
/* Failure means BLS ABORT RSP did not get delivered to remote node*/
|
||||
if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus)
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
"3154 BLS ABORT RSP failed, data: x%x/x%x\n",
|
||||
rsp_iocbq->iocb.ulpStatus,
|
||||
rsp_iocbq->iocb.un.ulpWord[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -14748,7 +14800,8 @@ lpfc_sli4_remove_rpis(struct lpfc_hba *phba)
|
||||
* provided rpi via a bitmask.
|
||||
**/
|
||||
int
|
||||
lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp)
|
||||
lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp,
|
||||
void (*cmpl)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *arg)
|
||||
{
|
||||
LPFC_MBOXQ_t *mboxq;
|
||||
struct lpfc_hba *phba = ndlp->phba;
|
||||
@ -14761,6 +14814,13 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp)
|
||||
|
||||
/* Post all rpi memory regions to the port. */
|
||||
lpfc_resume_rpi(mboxq, ndlp);
|
||||
if (cmpl) {
|
||||
mboxq->mbox_cmpl = cmpl;
|
||||
mboxq->context1 = arg;
|
||||
mboxq->context2 = ndlp;
|
||||
} else
|
||||
mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
mboxq->vport = ndlp->vport;
|
||||
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
|
||||
if (rc == MBX_NOT_FINISHED) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
|
||||
|
@ -69,6 +69,7 @@ struct lpfc_iocbq {
|
||||
#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
|
||||
#define DSS_SECURITY_OP 0x100 /* security IO */
|
||||
#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */
|
||||
#define LPFC_IO_DIF 0x400 /* T10 DIF IO */
|
||||
|
||||
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
|
||||
#define LPFC_FIP_ELS_ID_SHIFT 14
|
||||
|
@ -633,7 +633,8 @@ void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
|
||||
void lpfc_sli4_remove_rpis(struct lpfc_hba *);
|
||||
void lpfc_sli4_async_event_proc(struct lpfc_hba *);
|
||||
void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *);
|
||||
int lpfc_sli4_resume_rpi(struct lpfc_nodelist *);
|
||||
int lpfc_sli4_resume_rpi(struct lpfc_nodelist *,
|
||||
void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *);
|
||||
void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *);
|
||||
void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *);
|
||||
void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *,
|
||||
|
@ -18,7 +18,7 @@
|
||||
* included with this package. *
|
||||
*******************************************************************/
|
||||
|
||||
#define LPFC_DRIVER_VERSION "8.3.28"
|
||||
#define LPFC_DRIVER_VERSION "8.3.29"
|
||||
#define LPFC_DRIVER_NAME "lpfc"
|
||||
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
|
||||
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
|
||||
|
@ -2575,6 +2575,11 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
||||
|
||||
ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
|
||||
GFP_KERNEL, ioc->chain_pages);
|
||||
if (!ioc->chain_lookup) {
|
||||
printk(MPT2SAS_ERR_FMT "chain_lookup: get_free_pages failed, "
|
||||
"sz(%d)\n", ioc->name, (int)sz);
|
||||
goto out;
|
||||
}
|
||||
ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
|
||||
ioc->request_sz, 16, 0);
|
||||
if (!ioc->chain_dma_pool) {
|
||||
|
@ -5744,7 +5744,7 @@ _scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
|
||||
}
|
||||
|
||||
/**
|
||||
* _scsih_sas_broadcast_primative_event - handle broadcast events
|
||||
* _scsih_sas_broadcast_primitive_event - handle broadcast events
|
||||
* @ioc: per adapter object
|
||||
* @fw_event: The fw_event_work object
|
||||
* Context: user.
|
||||
@ -5752,7 +5752,7 @@ _scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
|
||||
* Return nothing.
|
||||
*/
|
||||
static void
|
||||
_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
|
||||
_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc,
|
||||
struct fw_event_work *fw_event)
|
||||
{
|
||||
struct scsi_cmnd *scmd;
|
||||
@ -7263,7 +7263,7 @@ _firmware_event_work(struct work_struct *work)
|
||||
fw_event);
|
||||
break;
|
||||
case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
|
||||
_scsih_sas_broadcast_primative_event(ioc,
|
||||
_scsih_sas_broadcast_primitive_event(ioc,
|
||||
fw_event);
|
||||
break;
|
||||
case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
|
||||
|
@ -60,7 +60,6 @@ static struct scsi_host_template mvs_sht = {
|
||||
.queuecommand = sas_queuecommand,
|
||||
.target_alloc = sas_target_alloc,
|
||||
.slave_configure = sas_slave_configure,
|
||||
.slave_destroy = sas_slave_destroy,
|
||||
.scan_finished = mvs_scan_finished,
|
||||
.scan_start = mvs_scan_start,
|
||||
.change_queue_depth = sas_change_queue_depth,
|
||||
@ -74,7 +73,6 @@ static struct scsi_host_template mvs_sht = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.eh_device_reset_handler = sas_eh_device_reset_handler,
|
||||
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
|
||||
.slave_alloc = sas_slave_alloc,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
.shost_attrs = mvst_host_attrs,
|
||||
|
@ -308,7 +308,7 @@ int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
|
||||
if (mvs_prv->scan_finished == 0)
|
||||
return 0;
|
||||
|
||||
scsi_flush_work(shost);
|
||||
sas_drain_work(sha);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -893,9 +893,6 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
|
||||
|
||||
mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info;
|
||||
|
||||
if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
|
||||
spin_unlock_irq(dev->sata_dev.ap->lock);
|
||||
|
||||
spin_lock_irqsave(&mvi->lock, flags);
|
||||
rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass);
|
||||
if (rc)
|
||||
@ -906,9 +903,6 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
|
||||
(MVS_CHIP_SLOT_SZ - 1));
|
||||
spin_unlock_irqrestore(&mvi->lock, flags);
|
||||
|
||||
if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
|
||||
spin_lock_irq(dev->sata_dev.ap->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1480,10 +1474,11 @@ static int mvs_debug_issue_ssp_tmf(struct domain_device *dev,
|
||||
static int mvs_debug_I_T_nexus_reset(struct domain_device *dev)
|
||||
{
|
||||
int rc;
|
||||
struct sas_phy *phy = sas_find_local_phy(dev);
|
||||
struct sas_phy *phy = sas_get_local_phy(dev);
|
||||
int reset_type = (dev->dev_type == SATA_DEV ||
|
||||
(dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
|
||||
rc = sas_phy_reset(phy, reset_type);
|
||||
sas_put_local_phy(phy);
|
||||
msleep(2000);
|
||||
return rc;
|
||||
}
|
||||
|
@ -46,9 +46,9 @@ static inline u32 pm8001_read_32(void *virt_addr)
|
||||
return *((u32 *)virt_addr);
|
||||
}
|
||||
|
||||
static inline void pm8001_write_32(void *addr, u32 offset, u32 val)
|
||||
static inline void pm8001_write_32(void *addr, u32 offset, __le32 val)
|
||||
{
|
||||
*((u32 *)(addr + offset)) = val;
|
||||
*((__le32 *)(addr + offset)) = val;
|
||||
}
|
||||
|
||||
static inline u32 pm8001_cr32(struct pm8001_hba_info *pm8001_ha, u32 bar,
|
||||
|
@ -338,26 +338,25 @@ update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number)
|
||||
}
|
||||
|
||||
/**
|
||||
* bar4_shift - function is called to shift BAR base address
|
||||
* @pm8001_ha : our hba card information
|
||||
* pm8001_bar4_shift - function is called to shift BAR base address
|
||||
* @pm8001_ha : our hba card infomation
|
||||
* @shiftValue : shifting value in memory bar.
|
||||
*/
|
||||
static int bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
|
||||
int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
|
||||
{
|
||||
u32 regVal;
|
||||
u32 max_wait_count;
|
||||
unsigned long start;
|
||||
|
||||
/* program the inbound AXI translation Lower Address */
|
||||
pm8001_cw32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW, shiftValue);
|
||||
|
||||
/* confirm the setting is written */
|
||||
max_wait_count = 1 * 1000 * 1000; /* 1 sec */
|
||||
start = jiffies + HZ; /* 1 sec */
|
||||
do {
|
||||
udelay(1);
|
||||
regVal = pm8001_cr32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW);
|
||||
} while ((regVal != shiftValue) && (--max_wait_count));
|
||||
} while ((regVal != shiftValue) && time_before(jiffies, start));
|
||||
|
||||
if (!max_wait_count) {
|
||||
if (regVal != shiftValue) {
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
pm8001_printk("TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW"
|
||||
" = 0x%x\n", regVal));
|
||||
@ -375,6 +374,7 @@ static void __devinit
|
||||
mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
|
||||
{
|
||||
u32 value, offset, i;
|
||||
unsigned long flags;
|
||||
|
||||
#define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
|
||||
#define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
|
||||
@ -388,16 +388,23 @@ mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
|
||||
* Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
|
||||
* Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
|
||||
*/
|
||||
if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR))
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha,
|
||||
SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
offset = SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET + 0x4000 * i;
|
||||
pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
|
||||
}
|
||||
/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
|
||||
if (-1 == bar4_shift(pm8001_ha, SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR))
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha,
|
||||
SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return;
|
||||
}
|
||||
for (i = 4; i < 8; i++) {
|
||||
offset = SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
|
||||
pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
|
||||
@ -421,7 +428,8 @@ mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
|
||||
pm8001_cw32(pm8001_ha, 2, 0xd8, 0x8000C016);
|
||||
|
||||
/*set the shifted destination address to 0x0 to avoid error operation */
|
||||
bar4_shift(pm8001_ha, 0x0);
|
||||
pm8001_bar4_shift(pm8001_ha, 0x0);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -437,6 +445,7 @@ mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
|
||||
u32 offset;
|
||||
u32 value;
|
||||
u32 i;
|
||||
unsigned long flags;
|
||||
|
||||
#define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
|
||||
#define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
|
||||
@ -445,24 +454,30 @@ mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
|
||||
#define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
|
||||
|
||||
value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
/* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
|
||||
if (-1 == bar4_shift(pm8001_ha,
|
||||
OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR))
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha,
|
||||
OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
offset = OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET + 0x4000 * i;
|
||||
pm8001_cw32(pm8001_ha, 2, offset, value);
|
||||
}
|
||||
|
||||
if (-1 == bar4_shift(pm8001_ha,
|
||||
OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR))
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha,
|
||||
OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return;
|
||||
}
|
||||
for (i = 4; i < 8; i++) {
|
||||
offset = OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
|
||||
pm8001_cw32(pm8001_ha, 2, offset, value);
|
||||
}
|
||||
/*set the shifted destination address to 0x0 to avoid error operation */
|
||||
bar4_shift(pm8001_ha, 0x0);
|
||||
pm8001_bar4_shift(pm8001_ha, 0x0);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -607,7 +622,8 @@ static int __devinit pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
|
||||
update_inbnd_queue_table(pm8001_ha, 0);
|
||||
update_outbnd_queue_table(pm8001_ha, 0);
|
||||
mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
|
||||
mpi_set_open_retry_interval_reg(pm8001_ha, 7);
|
||||
/* 7->130ms, 34->500ms, 119->1.5s */
|
||||
mpi_set_open_retry_interval_reg(pm8001_ha, 119);
|
||||
/* notify firmware update finished and check initialization status */
|
||||
if (0 == mpi_init_check(pm8001_ha)) {
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
@ -688,8 +704,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
pm8001_printk("Firmware is ready for reset .\n"));
|
||||
} else {
|
||||
/* Trigger NMI twice via RB6 */
|
||||
if (-1 == bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
|
||||
unsigned long flags;
|
||||
/* Trigger NMI twice via RB6 */
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("Shift Bar4 to 0x%x failed\n",
|
||||
RB6_ACCESS_REG));
|
||||
@ -715,8 +734,10 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
|
||||
pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return -1;
|
||||
}
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -733,6 +754,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
u32 regVal, toggleVal;
|
||||
u32 max_wait_count;
|
||||
u32 regVal1, regVal2, regVal3;
|
||||
unsigned long flags;
|
||||
|
||||
/* step1: Check FW is ready for soft reset */
|
||||
if (soft_reset_ready_check(pm8001_ha) != 0) {
|
||||
@ -743,7 +765,9 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
/* step 2: clear NMI status register on AAP1 and IOP, write the same
|
||||
value to clear */
|
||||
/* map 0x60000 to BAR4(0x20), BAR2(win) */
|
||||
if (-1 == bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("Shift Bar4 to 0x%x failed\n",
|
||||
MBIC_AAP1_ADDR_BASE));
|
||||
@ -754,7 +778,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
pm8001_printk("MBIC - NMI Enable VPE0 (IOP)= 0x%x\n", regVal));
|
||||
pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
|
||||
/* map 0x70000 to BAR4(0x20), BAR2(win) */
|
||||
if (-1 == bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("Shift Bar4 to 0x%x failed\n",
|
||||
MBIC_IOP_ADDR_BASE));
|
||||
@ -796,7 +821,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
|
||||
/* read required registers for confirmming */
|
||||
/* map 0x0700000 to BAR4(0x20), BAR2(win) */
|
||||
if (-1 == bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("Shift Bar4 to 0x%x failed\n",
|
||||
GSM_ADDR_BASE));
|
||||
@ -862,7 +888,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
/* step 5: delay 10 usec */
|
||||
udelay(10);
|
||||
/* step 5-b: set GPIO-0 output control to tristate anyway */
|
||||
if (-1 == bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
pm8001_printk("Shift Bar4 to 0x%x failed\n",
|
||||
GPIO_ADDR_BASE));
|
||||
@ -878,7 +905,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
|
||||
/* Step 6: Reset the IOP and AAP1 */
|
||||
/* map 0x00000 to BAR4(0x20), BAR2(win) */
|
||||
if (-1 == bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
|
||||
SPC_TOP_LEVEL_ADDR_BASE));
|
||||
@ -915,7 +943,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
|
||||
/* step 11: reads and sets the GSM Configuration and Reset Register */
|
||||
/* map 0x0700000 to BAR4(0x20), BAR2(win) */
|
||||
if (-1 == bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
|
||||
GSM_ADDR_BASE));
|
||||
@ -968,7 +997,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
|
||||
/* step 13: bring the IOP and AAP1 out of reset */
|
||||
/* map 0x00000 to BAR4(0x20), BAR2(win) */
|
||||
if (-1 == bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("Shift Bar4 to 0x%x failed\n",
|
||||
SPC_TOP_LEVEL_ADDR_BASE));
|
||||
@ -1010,6 +1040,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
|
||||
pm8001_cr32(pm8001_ha, 0,
|
||||
MSGU_SCRATCH_PAD_3)));
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1039,9 +1070,12 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature)
|
||||
pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
|
||||
pm8001_cr32(pm8001_ha, 0,
|
||||
MSGU_SCRATCH_PAD_3)));
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
pm8001_bar4_shift(pm8001_ha, 0);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
pm8001_printk("SPC soft reset Complete\n"));
|
||||
@ -1157,8 +1191,8 @@ pm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha,
|
||||
msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
|
||||
msi_index += MSIX_TABLE_BASE;
|
||||
pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_DISABLE);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
|
||||
* @pm8001_ha: our hba card information
|
||||
@ -1212,7 +1246,7 @@ static int mpi_msg_free_get(struct inbound_queue_table *circularQ,
|
||||
consumer_index = pm8001_read_32(circularQ->ci_virt);
|
||||
circularQ->consumer_index = cpu_to_le32(consumer_index);
|
||||
if (((circularQ->producer_idx + bcCount) % 256) ==
|
||||
circularQ->consumer_index) {
|
||||
le32_to_cpu(circularQ->consumer_index)) {
|
||||
*messagePtr = NULL;
|
||||
return -1;
|
||||
}
|
||||
@ -1321,7 +1355,8 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
|
||||
u32 header_tmp;
|
||||
do {
|
||||
/* If there are not-yet-delivered messages ... */
|
||||
if (circularQ->producer_index != circularQ->consumer_idx) {
|
||||
if (le32_to_cpu(circularQ->producer_index)
|
||||
!= circularQ->consumer_idx) {
|
||||
/*Get the pointer to the circular queue buffer element*/
|
||||
msgHeader = (struct mpi_msg_hdr *)
|
||||
(circularQ->base_virt +
|
||||
@ -1329,14 +1364,14 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
|
||||
/* read header */
|
||||
header_tmp = pm8001_read_32(msgHeader);
|
||||
msgHeader_tmp = cpu_to_le32(header_tmp);
|
||||
if (0 != (msgHeader_tmp & 0x80000000)) {
|
||||
if (0 != (le32_to_cpu(msgHeader_tmp) & 0x80000000)) {
|
||||
if (OPC_OUB_SKIP_ENTRY !=
|
||||
(msgHeader_tmp & 0xfff)) {
|
||||
(le32_to_cpu(msgHeader_tmp) & 0xfff)) {
|
||||
*messagePtr1 =
|
||||
((u8 *)msgHeader) +
|
||||
sizeof(struct mpi_msg_hdr);
|
||||
*pBC = (u8)((msgHeader_tmp >> 24) &
|
||||
0x1f);
|
||||
*pBC = (u8)((le32_to_cpu(msgHeader_tmp)
|
||||
>> 24) & 0x1f);
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk(": CI=%d PI=%d "
|
||||
"msgHeader=%x\n",
|
||||
@ -1347,8 +1382,8 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
|
||||
} else {
|
||||
circularQ->consumer_idx =
|
||||
(circularQ->consumer_idx +
|
||||
((msgHeader_tmp >> 24) & 0x1f))
|
||||
% 256;
|
||||
((le32_to_cpu(msgHeader_tmp)
|
||||
>> 24) & 0x1f)) % 256;
|
||||
msgHeader_tmp = 0;
|
||||
pm8001_write_32(msgHeader, 0, 0);
|
||||
/* update the CI of outbound queue */
|
||||
@ -1360,7 +1395,8 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
|
||||
} else {
|
||||
circularQ->consumer_idx =
|
||||
(circularQ->consumer_idx +
|
||||
((msgHeader_tmp >> 24) & 0x1f)) % 256;
|
||||
((le32_to_cpu(msgHeader_tmp) >> 24) &
|
||||
0x1f)) % 256;
|
||||
msgHeader_tmp = 0;
|
||||
pm8001_write_32(msgHeader, 0, 0);
|
||||
/* update the CI of outbound queue */
|
||||
@ -1376,7 +1412,8 @@ static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
|
||||
producer_index = pm8001_read_32(pi_virt);
|
||||
circularQ->producer_index = cpu_to_le32(producer_index);
|
||||
}
|
||||
} while (circularQ->producer_index != circularQ->consumer_idx);
|
||||
} while (le32_to_cpu(circularQ->producer_index) !=
|
||||
circularQ->consumer_idx);
|
||||
/* while we don't have any more not-yet-delivered message */
|
||||
/* report empty */
|
||||
return MPI_IO_STATUS_BUSY;
|
||||
@ -1388,24 +1425,191 @@ static void pm8001_work_fn(struct work_struct *work)
|
||||
struct pm8001_device *pm8001_dev;
|
||||
struct domain_device *dev;
|
||||
|
||||
/*
|
||||
* So far, all users of this stash an associated structure here.
|
||||
* If we get here, and this pointer is null, then the action
|
||||
* was cancelled. This nullification happens when the device
|
||||
* goes away.
|
||||
*/
|
||||
pm8001_dev = pw->data; /* Most stash device structure */
|
||||
if ((pm8001_dev == NULL)
|
||||
|| ((pw->handler != IO_XFER_ERROR_BREAK)
|
||||
&& (pm8001_dev->dev_type == NO_DEVICE))) {
|
||||
kfree(pw);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pw->handler) {
|
||||
case IO_XFER_ERROR_BREAK:
|
||||
{ /* This one stashes the sas_task instead */
|
||||
struct sas_task *t = (struct sas_task *)pm8001_dev;
|
||||
u32 tag;
|
||||
struct pm8001_ccb_info *ccb;
|
||||
struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
|
||||
unsigned long flags, flags1;
|
||||
struct task_status_struct *ts;
|
||||
int i;
|
||||
|
||||
if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
|
||||
break; /* Task still on lu */
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
|
||||
spin_lock_irqsave(&t->task_state_lock, flags1);
|
||||
if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
break; /* Task got completed by another */
|
||||
}
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
||||
|
||||
/* Search for a possible ccb that matches the task */
|
||||
for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
|
||||
ccb = &pm8001_ha->ccb_info[i];
|
||||
tag = ccb->ccb_tag;
|
||||
if ((tag != 0xFFFFFFFF) && (ccb->task == t))
|
||||
break;
|
||||
}
|
||||
if (!ccb) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
break; /* Task got freed by another */
|
||||
}
|
||||
ts = &t->task_status;
|
||||
ts->resp = SAS_TASK_COMPLETE;
|
||||
/* Force the midlayer to retry */
|
||||
ts->stat = SAS_QUEUE_FULL;
|
||||
pm8001_dev = ccb->device;
|
||||
if (pm8001_dev)
|
||||
pm8001_dev->running_req--;
|
||||
spin_lock_irqsave(&t->task_state_lock, flags1);
|
||||
t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
|
||||
t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
|
||||
t->task_state_flags |= SAS_TASK_STATE_DONE;
|
||||
if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
||||
PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p"
|
||||
" done with event 0x%x resp 0x%x stat 0x%x but"
|
||||
" aborted by upper layer!\n",
|
||||
t, pw->handler, ts->resp, ts->stat));
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/* in order to force CPU ordering */
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
t->task_done(t);
|
||||
}
|
||||
} break;
|
||||
case IO_XFER_OPEN_RETRY_TIMEOUT:
|
||||
{ /* This one stashes the sas_task instead */
|
||||
struct sas_task *t = (struct sas_task *)pm8001_dev;
|
||||
u32 tag;
|
||||
struct pm8001_ccb_info *ccb;
|
||||
struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
|
||||
unsigned long flags, flags1;
|
||||
int i, ret = 0;
|
||||
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
|
||||
|
||||
ret = pm8001_query_task(t);
|
||||
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
switch (ret) {
|
||||
case TMF_RESP_FUNC_SUCC:
|
||||
pm8001_printk("...Task on lu\n");
|
||||
break;
|
||||
|
||||
case TMF_RESP_FUNC_COMPLETE:
|
||||
pm8001_printk("...Task NOT on lu\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
pm8001_printk("...query task failed!!!\n");
|
||||
break;
|
||||
});
|
||||
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
|
||||
spin_lock_irqsave(&t->task_state_lock, flags1);
|
||||
|
||||
if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
|
||||
(void)pm8001_abort_task(t);
|
||||
break; /* Task got completed by another */
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
||||
|
||||
/* Search for a possible ccb that matches the task */
|
||||
for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
|
||||
ccb = &pm8001_ha->ccb_info[i];
|
||||
tag = ccb->ccb_tag;
|
||||
if ((tag != 0xFFFFFFFF) && (ccb->task == t))
|
||||
break;
|
||||
}
|
||||
if (!ccb) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
|
||||
(void)pm8001_abort_task(t);
|
||||
break; /* Task got freed by another */
|
||||
}
|
||||
|
||||
pm8001_dev = ccb->device;
|
||||
dev = pm8001_dev->sas_device;
|
||||
|
||||
switch (ret) {
|
||||
case TMF_RESP_FUNC_SUCC: /* task on lu */
|
||||
ccb->open_retry = 1; /* Snub completion */
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
ret = pm8001_abort_task(t);
|
||||
ccb->open_retry = 0;
|
||||
switch (ret) {
|
||||
case TMF_RESP_FUNC_SUCC:
|
||||
case TMF_RESP_FUNC_COMPLETE:
|
||||
break;
|
||||
default: /* device misbehavior */
|
||||
ret = TMF_RESP_FUNC_FAILED;
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("...Reset phy\n"));
|
||||
pm8001_I_T_nexus_reset(dev);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
/* Do we need to abort the task locally? */
|
||||
break;
|
||||
|
||||
default: /* device misbehavior */
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
ret = TMF_RESP_FUNC_FAILED;
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("...Reset phy\n"));
|
||||
pm8001_I_T_nexus_reset(dev);
|
||||
}
|
||||
|
||||
if (ret == TMF_RESP_FUNC_FAILED)
|
||||
t = NULL;
|
||||
pm8001_open_reject_retry(pm8001_ha, t, pm8001_dev);
|
||||
PM8001_IO_DBG(pm8001_ha, pm8001_printk("...Complete\n"));
|
||||
} break;
|
||||
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
|
||||
pm8001_dev = pw->data;
|
||||
dev = pm8001_dev->sas_device;
|
||||
pm8001_I_T_nexus_reset(dev);
|
||||
break;
|
||||
case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
|
||||
pm8001_dev = pw->data;
|
||||
dev = pm8001_dev->sas_device;
|
||||
pm8001_I_T_nexus_reset(dev);
|
||||
break;
|
||||
case IO_DS_IN_ERROR:
|
||||
pm8001_dev = pw->data;
|
||||
dev = pm8001_dev->sas_device;
|
||||
pm8001_I_T_nexus_reset(dev);
|
||||
break;
|
||||
case IO_DS_NON_OPERATIONAL:
|
||||
pm8001_dev = pw->data;
|
||||
dev = pm8001_dev->sas_device;
|
||||
pm8001_I_T_nexus_reset(dev);
|
||||
break;
|
||||
@ -1460,6 +1664,11 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
|
||||
status = le32_to_cpu(psspPayload->status);
|
||||
tag = le32_to_cpu(psspPayload->tag);
|
||||
ccb = &pm8001_ha->ccb_info[tag];
|
||||
if ((status == IO_ABORTED) && ccb->open_retry) {
|
||||
/* Being completed by another */
|
||||
ccb->open_retry = 0;
|
||||
return;
|
||||
}
|
||||
pm8001_dev = ccb->device;
|
||||
param = le32_to_cpu(psspPayload->param);
|
||||
|
||||
@ -1515,6 +1724,8 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb)
|
||||
pm8001_printk("IO_XFER_ERROR_BREAK\n"));
|
||||
ts->resp = SAS_TASK_COMPLETE;
|
||||
ts->stat = SAS_OPEN_REJECT;
|
||||
/* Force the midlayer to retry */
|
||||
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
|
||||
break;
|
||||
case IO_XFER_ERROR_PHY_NOT_READY:
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
@ -1719,9 +1930,8 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
|
||||
case IO_XFER_ERROR_BREAK:
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("IO_XFER_ERROR_BREAK\n"));
|
||||
ts->resp = SAS_TASK_COMPLETE;
|
||||
ts->stat = SAS_INTERRUPTED;
|
||||
break;
|
||||
pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK);
|
||||
return;
|
||||
case IO_XFER_ERROR_PHY_NOT_READY:
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n"));
|
||||
@ -1800,10 +2010,8 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
|
||||
case IO_XFER_OPEN_RETRY_TIMEOUT:
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n"));
|
||||
ts->resp = SAS_TASK_COMPLETE;
|
||||
ts->stat = SAS_OPEN_REJECT;
|
||||
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
|
||||
break;
|
||||
pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT);
|
||||
return;
|
||||
case IO_XFER_ERROR_UNEXPECTED_PHASE:
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n"));
|
||||
@ -1877,7 +2085,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
{
|
||||
struct sas_task *t;
|
||||
struct pm8001_ccb_info *ccb;
|
||||
unsigned long flags = 0;
|
||||
u32 param;
|
||||
u32 status;
|
||||
u32 tag;
|
||||
@ -2016,9 +2223,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
ts->stat = SAS_QUEUE_FULL;
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/*in order to force CPU ordering*/
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -2036,9 +2243,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
ts->stat = SAS_QUEUE_FULL;
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/*ditto*/
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -2064,9 +2271,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
ts->stat = SAS_QUEUE_FULL;
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/* ditto*/
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -2131,9 +2338,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
ts->stat = SAS_QUEUE_FULL;
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/*ditto*/
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -2155,9 +2362,9 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
ts->stat = SAS_QUEUE_FULL;
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/*ditto*/
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -2175,31 +2382,31 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
ts->stat = SAS_DEV_NO_RESPONSE;
|
||||
break;
|
||||
}
|
||||
spin_lock_irqsave(&t->task_state_lock, flags);
|
||||
spin_lock_irq(&t->task_state_lock);
|
||||
t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
|
||||
t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
|
||||
t->task_state_flags |= SAS_TASK_STATE_DONE;
|
||||
if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags);
|
||||
spin_unlock_irq(&t->task_state_lock);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("task 0x%p done with io_status 0x%x"
|
||||
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
|
||||
t, status, ts->resp, ts->stat));
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
} else if (t->uldd_task) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags);
|
||||
spin_unlock_irq(&t->task_state_lock);
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/* ditto */
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
} else if (!t->uldd_task) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags);
|
||||
spin_unlock_irq(&t->task_state_lock);
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/*ditto*/
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2207,7 +2414,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
|
||||
{
|
||||
struct sas_task *t;
|
||||
unsigned long flags = 0;
|
||||
struct task_status_struct *ts;
|
||||
struct pm8001_ccb_info *ccb;
|
||||
struct pm8001_device *pm8001_dev;
|
||||
@ -2287,9 +2493,9 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
|
||||
ts->stat = SAS_QUEUE_FULL;
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/*ditto*/
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@ -2387,31 +2593,31 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
|
||||
ts->stat = SAS_OPEN_TO;
|
||||
break;
|
||||
}
|
||||
spin_lock_irqsave(&t->task_state_lock, flags);
|
||||
spin_lock_irq(&t->task_state_lock);
|
||||
t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
|
||||
t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
|
||||
t->task_state_flags |= SAS_TASK_STATE_DONE;
|
||||
if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags);
|
||||
spin_unlock_irq(&t->task_state_lock);
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("task 0x%p done with io_status 0x%x"
|
||||
" resp 0x%x stat 0x%x but aborted by upper layer!\n",
|
||||
t, event, ts->resp, ts->stat));
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
} else if (t->uldd_task) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags);
|
||||
spin_unlock_irq(&t->task_state_lock);
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/* ditto */
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
} else if (!t->uldd_task) {
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags);
|
||||
spin_unlock_irq(&t->task_state_lock);
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();/*ditto*/
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irq(&pm8001_ha->lock);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
spin_lock_irq(&pm8001_ha->lock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2857,7 +3063,7 @@ static void pm8001_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha,
|
||||
|
||||
memset((u8 *)&payload, 0, sizeof(payload));
|
||||
circularQ = &pm8001_ha->inbnd_q_tbl[Qnum];
|
||||
payload.tag = 1;
|
||||
payload.tag = cpu_to_le32(1);
|
||||
payload.sea_phyid_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) |
|
||||
((phyId & 0x0F) << 4) | (port_id & 0x0F));
|
||||
payload.param0 = cpu_to_le32(param0);
|
||||
@ -2929,9 +3135,9 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
phy->phy_type |= PORT_TYPE_SAS;
|
||||
phy->identify.device_type = deviceType;
|
||||
phy->phy_attached = 1;
|
||||
if (phy->identify.device_type == SAS_END_DEV)
|
||||
if (phy->identify.device_type == SAS_END_DEVICE)
|
||||
phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
|
||||
else if (phy->identify.device_type != NO_DEVICE)
|
||||
else if (phy->identify.device_type != SAS_PHY_UNUSED)
|
||||
phy->identify.target_port_protocols = SAS_PROTOCOL_SMP;
|
||||
phy->sas_phy.oob_mode = SAS_OOB_MODE;
|
||||
sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE);
|
||||
@ -3075,7 +3281,7 @@ static int mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
(struct dev_reg_resp *)(piomb + 4);
|
||||
|
||||
htag = le32_to_cpu(registerRespPayload->tag);
|
||||
ccb = &pm8001_ha->ccb_info[registerRespPayload->tag];
|
||||
ccb = &pm8001_ha->ccb_info[htag];
|
||||
pm8001_dev = ccb->device;
|
||||
status = le32_to_cpu(registerRespPayload->status);
|
||||
device_id = le32_to_cpu(registerRespPayload->device_id);
|
||||
@ -3149,7 +3355,7 @@ mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
struct fw_control_ex fw_control_context;
|
||||
struct fw_flash_Update_resp *ppayload =
|
||||
(struct fw_flash_Update_resp *)(piomb + 4);
|
||||
u32 tag = le32_to_cpu(ppayload->tag);
|
||||
u32 tag = ppayload->tag;
|
||||
struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
|
||||
status = le32_to_cpu(ppayload->status);
|
||||
memcpy(&fw_control_context,
|
||||
@ -3238,13 +3444,12 @@ mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
|
||||
struct task_abort_resp *pPayload =
|
||||
(struct task_abort_resp *)(piomb + 4);
|
||||
ccb = &pm8001_ha->ccb_info[pPayload->tag];
|
||||
t = ccb->task;
|
||||
|
||||
|
||||
status = le32_to_cpu(pPayload->status);
|
||||
tag = le32_to_cpu(pPayload->tag);
|
||||
scp = le32_to_cpu(pPayload->scp);
|
||||
ccb = &pm8001_ha->ccb_info[tag];
|
||||
t = ccb->task;
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk(" status = 0x%x\n", status));
|
||||
if (t == NULL)
|
||||
@ -3270,7 +3475,7 @@ mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
|
||||
t->task_state_flags |= SAS_TASK_STATE_DONE;
|
||||
spin_unlock_irqrestore(&t->task_state_lock, flags);
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, pPayload->tag);
|
||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
||||
mb();
|
||||
t->task_done(t);
|
||||
return 0;
|
||||
@ -3497,7 +3702,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb)
|
||||
static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||
{
|
||||
u32 pHeader = (u32)*(u32 *)piomb;
|
||||
u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
|
||||
u8 opc = (u8)(pHeader & 0xFFF);
|
||||
|
||||
PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:"));
|
||||
|
||||
@ -3664,9 +3869,11 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha)
|
||||
{
|
||||
struct outbound_queue_table *circularQ;
|
||||
void *pMsg1 = NULL;
|
||||
u8 bc = 0;
|
||||
u8 uninitialized_var(bc);
|
||||
u32 ret = MPI_IO_STATUS_FAIL;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
circularQ = &pm8001_ha->outbnd_q_tbl[0];
|
||||
do {
|
||||
ret = mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
|
||||
@ -3677,16 +3884,16 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha)
|
||||
mpi_msg_free_set(pm8001_ha, pMsg1, circularQ, bc);
|
||||
}
|
||||
if (MPI_IO_STATUS_BUSY == ret) {
|
||||
u32 producer_idx;
|
||||
/* Update the producer index from SPC */
|
||||
producer_idx = pm8001_read_32(circularQ->pi_virt);
|
||||
circularQ->producer_index = cpu_to_le32(producer_idx);
|
||||
if (circularQ->producer_index ==
|
||||
circularQ->producer_index =
|
||||
cpu_to_le32(pm8001_read_32(circularQ->pi_virt));
|
||||
if (le32_to_cpu(circularQ->producer_index) ==
|
||||
circularQ->consumer_idx)
|
||||
/* OQ is empty */
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3712,9 +3919,9 @@ pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd)
|
||||
}
|
||||
}
|
||||
|
||||
static void build_smp_cmd(u32 deviceID, u32 hTag, struct smp_req *psmp_cmd)
|
||||
static void build_smp_cmd(u32 deviceID, __le32 hTag, struct smp_req *psmp_cmd)
|
||||
{
|
||||
psmp_cmd->tag = cpu_to_le32(hTag);
|
||||
psmp_cmd->tag = hTag;
|
||||
psmp_cmd->device_id = cpu_to_le32(deviceID);
|
||||
psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1));
|
||||
}
|
||||
@ -3798,7 +4005,7 @@ static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
|
||||
struct ssp_ini_io_start_req ssp_cmd;
|
||||
u32 tag = ccb->ccb_tag;
|
||||
int ret;
|
||||
__le64 phys_addr;
|
||||
u64 phys_addr;
|
||||
struct inbound_queue_table *circularQ;
|
||||
u32 opc = OPC_INB_SSPINIIOSTART;
|
||||
memset(&ssp_cmd, 0, sizeof(ssp_cmd));
|
||||
@ -3819,15 +4026,15 @@ static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
|
||||
/* fill in PRD (scatter/gather) table, if any */
|
||||
if (task->num_scatter > 1) {
|
||||
pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
|
||||
phys_addr = cpu_to_le64(ccb->ccb_dma_handle +
|
||||
offsetof(struct pm8001_ccb_info, buf_prd[0]));
|
||||
ssp_cmd.addr_low = lower_32_bits(phys_addr);
|
||||
ssp_cmd.addr_high = upper_32_bits(phys_addr);
|
||||
phys_addr = ccb->ccb_dma_handle +
|
||||
offsetof(struct pm8001_ccb_info, buf_prd[0]);
|
||||
ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(phys_addr));
|
||||
ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(phys_addr));
|
||||
ssp_cmd.esgl = cpu_to_le32(1<<31);
|
||||
} else if (task->num_scatter == 1) {
|
||||
__le64 dma_addr = cpu_to_le64(sg_dma_address(task->scatter));
|
||||
ssp_cmd.addr_low = lower_32_bits(dma_addr);
|
||||
ssp_cmd.addr_high = upper_32_bits(dma_addr);
|
||||
u64 dma_addr = sg_dma_address(task->scatter);
|
||||
ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr));
|
||||
ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(dma_addr));
|
||||
ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
|
||||
ssp_cmd.esgl = 0;
|
||||
} else if (task->num_scatter == 0) {
|
||||
@ -3850,7 +4057,7 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
|
||||
int ret;
|
||||
struct sata_start_req sata_cmd;
|
||||
u32 hdr_tag, ncg_tag = 0;
|
||||
__le64 phys_addr;
|
||||
u64 phys_addr;
|
||||
u32 ATAP = 0x0;
|
||||
u32 dir;
|
||||
struct inbound_queue_table *circularQ;
|
||||
@ -3889,13 +4096,13 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
|
||||
/* fill in PRD (scatter/gather) table, if any */
|
||||
if (task->num_scatter > 1) {
|
||||
pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
|
||||
phys_addr = cpu_to_le64(ccb->ccb_dma_handle +
|
||||
offsetof(struct pm8001_ccb_info, buf_prd[0]));
|
||||
phys_addr = ccb->ccb_dma_handle +
|
||||
offsetof(struct pm8001_ccb_info, buf_prd[0]);
|
||||
sata_cmd.addr_low = lower_32_bits(phys_addr);
|
||||
sata_cmd.addr_high = upper_32_bits(phys_addr);
|
||||
sata_cmd.esgl = cpu_to_le32(1 << 31);
|
||||
} else if (task->num_scatter == 1) {
|
||||
__le64 dma_addr = cpu_to_le64(sg_dma_address(task->scatter));
|
||||
u64 dma_addr = sg_dma_address(task->scatter);
|
||||
sata_cmd.addr_low = lower_32_bits(dma_addr);
|
||||
sata_cmd.addr_high = upper_32_bits(dma_addr);
|
||||
sata_cmd.len = cpu_to_le32(task->total_xfer_len);
|
||||
@ -4039,7 +4246,7 @@ static int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha,
|
||||
|
||||
circularQ = &pm8001_ha->inbnd_q_tbl[0];
|
||||
memset(&payload, 0, sizeof(payload));
|
||||
payload.tag = 1;
|
||||
payload.tag = cpu_to_le32(1);
|
||||
payload.device_id = cpu_to_le32(device_id);
|
||||
PM8001_MSG_DBG(pm8001_ha,
|
||||
pm8001_printk("unregister device device_id = %d\n", device_id));
|
||||
@ -4063,7 +4270,7 @@ static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
|
||||
u32 opc = OPC_INB_LOCAL_PHY_CONTROL;
|
||||
memset(&payload, 0, sizeof(payload));
|
||||
circularQ = &pm8001_ha->inbnd_q_tbl[0];
|
||||
payload.tag = 1;
|
||||
payload.tag = cpu_to_le32(1);
|
||||
payload.phyop_phyid =
|
||||
cpu_to_le32(((phy_op & 0xff) << 8) | (phyId & 0x0F));
|
||||
ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
|
||||
@ -4092,12 +4299,9 @@ static u32 pm8001_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha)
|
||||
static irqreturn_t
|
||||
pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
pm8001_chip_interrupt_disable(pm8001_ha);
|
||||
process_oq(pm8001_ha);
|
||||
pm8001_chip_interrupt_enable(pm8001_ha);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -4360,8 +4564,10 @@ pm8001_chip_fw_flash_update_build(struct pm8001_hba_info *pm8001_ha,
|
||||
payload.cur_image_offset = cpu_to_le32(info->cur_image_offset);
|
||||
payload.total_image_len = cpu_to_le32(info->total_image_len);
|
||||
payload.len = info->sgl.im_len.len ;
|
||||
payload.sgl_addr_lo = lower_32_bits(info->sgl.addr);
|
||||
payload.sgl_addr_hi = upper_32_bits(info->sgl.addr);
|
||||
payload.sgl_addr_lo =
|
||||
cpu_to_le32(lower_32_bits(le64_to_cpu(info->sgl.addr)));
|
||||
payload.sgl_addr_hi =
|
||||
cpu_to_le32(upper_32_bits(le64_to_cpu(info->sgl.addr)));
|
||||
ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload);
|
||||
return ret;
|
||||
}
|
||||
|
@ -625,7 +625,7 @@ struct set_nvm_data_req {
|
||||
__le32 tag;
|
||||
__le32 len_ir_vpdd;
|
||||
__le32 vpd_offset;
|
||||
u32 reserved[8];
|
||||
__le32 reserved[8];
|
||||
__le32 resp_addr_lo;
|
||||
__le32 resp_addr_hi;
|
||||
__le32 resp_len;
|
||||
|
@ -62,7 +62,6 @@ static struct scsi_host_template pm8001_sht = {
|
||||
.queuecommand = sas_queuecommand,
|
||||
.target_alloc = sas_target_alloc,
|
||||
.slave_configure = sas_slave_configure,
|
||||
.slave_destroy = sas_slave_destroy,
|
||||
.scan_finished = pm8001_scan_finished,
|
||||
.scan_start = pm8001_scan_start,
|
||||
.change_queue_depth = sas_change_queue_depth,
|
||||
@ -76,7 +75,6 @@ static struct scsi_host_template pm8001_sht = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.eh_device_reset_handler = sas_eh_device_reset_handler,
|
||||
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
|
||||
.slave_alloc = sas_slave_alloc,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
.shost_attrs = pm8001_host_attrs,
|
||||
|
@ -166,6 +166,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
|
||||
struct pm8001_hba_info *pm8001_ha = NULL;
|
||||
struct sas_phy_linkrates *rates;
|
||||
DECLARE_COMPLETION_ONSTACK(completion);
|
||||
unsigned long flags;
|
||||
pm8001_ha = sas_phy->ha->lldd_ha;
|
||||
pm8001_ha->phy[phy_id].enable_completion = &completion;
|
||||
switch (func) {
|
||||
@ -209,8 +210,29 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
|
||||
case PHY_FUNC_DISABLE:
|
||||
PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
|
||||
break;
|
||||
case PHY_FUNC_GET_EVENTS:
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
if (-1 == pm8001_bar4_shift(pm8001_ha,
|
||||
(phy_id < 4) ? 0x30000 : 0x40000)) {
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
{
|
||||
struct sas_phy *phy = sas_phy->phy;
|
||||
uint32_t *qp = (uint32_t *)(((char *)
|
||||
pm8001_ha->io_mem[2].memvirtaddr)
|
||||
+ 0x1034 + (0x4000 * (phy_id & 3)));
|
||||
|
||||
phy->invalid_dword_count = qp[0];
|
||||
phy->running_disparity_error_count = qp[1];
|
||||
phy->loss_of_dword_sync_count = qp[3];
|
||||
phy->phy_reset_problem_count = qp[4];
|
||||
}
|
||||
pm8001_bar4_shift(pm8001_ha, 0);
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
return 0;
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
rc = -EOPNOTSUPP;
|
||||
}
|
||||
msleep(300);
|
||||
return rc;
|
||||
@ -234,12 +256,14 @@ void pm8001_scan_start(struct Scsi_Host *shost)
|
||||
|
||||
int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time)
|
||||
{
|
||||
struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
|
||||
|
||||
/* give the phy enabling interrupt event time to come in (1s
|
||||
* is empirically about all it takes) */
|
||||
if (time < HZ)
|
||||
return 0;
|
||||
/* Wait for discovery to finish */
|
||||
scsi_flush_work(shost);
|
||||
sas_drain_work(ha);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -340,7 +364,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
|
||||
struct pm8001_ccb_info *ccb;
|
||||
u32 tag = 0xdeadbeef, rc, n_elem = 0;
|
||||
u32 n = num;
|
||||
unsigned long flags = 0, flags_libsas = 0;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (!dev->port) {
|
||||
struct task_status_struct *tsm = &t->task_status;
|
||||
@ -364,11 +388,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
|
||||
ts->stat = SAS_PHY_DOWN;
|
||||
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
spin_unlock_irqrestore(dev->sata_dev.ap->lock,
|
||||
flags_libsas);
|
||||
t->task_done(t);
|
||||
spin_lock_irqsave(dev->sata_dev.ap->lock,
|
||||
flags_libsas);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
if (n > 1)
|
||||
t = list_entry(t->list.next,
|
||||
@ -516,6 +536,7 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
|
||||
task->lldd_task = NULL;
|
||||
ccb->task = NULL;
|
||||
ccb->ccb_tag = 0xFFFFFFFF;
|
||||
ccb->open_retry = 0;
|
||||
pm8001_ccb_free(pm8001_ha, ccb_idx);
|
||||
}
|
||||
|
||||
@ -615,7 +636,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
|
||||
wait_for_completion(&completion);
|
||||
if (dev->dev_type == SAS_END_DEV)
|
||||
msleep(50);
|
||||
pm8001_ha->flags |= PM8001F_RUN_TIME ;
|
||||
pm8001_ha->flags = PM8001F_RUN_TIME;
|
||||
return 0;
|
||||
found_out:
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
@ -860,6 +881,77 @@ static int pm8001_issue_ssp_tmf(struct domain_device *dev,
|
||||
tmf);
|
||||
}
|
||||
|
||||
/* retry commands by ha, by task and/or by device */
|
||||
void pm8001_open_reject_retry(
|
||||
struct pm8001_hba_info *pm8001_ha,
|
||||
struct sas_task *task_to_close,
|
||||
struct pm8001_device *device_to_close)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
if (pm8001_ha == NULL)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
|
||||
for (i = 0; i < PM8001_MAX_CCB; i++) {
|
||||
struct sas_task *task;
|
||||
struct task_status_struct *ts;
|
||||
struct pm8001_device *pm8001_dev;
|
||||
unsigned long flags1;
|
||||
u32 tag;
|
||||
struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[i];
|
||||
|
||||
pm8001_dev = ccb->device;
|
||||
if (!pm8001_dev || (pm8001_dev->dev_type == NO_DEVICE))
|
||||
continue;
|
||||
if (!device_to_close) {
|
||||
uintptr_t d = (uintptr_t)pm8001_dev
|
||||
- (uintptr_t)&pm8001_ha->devices;
|
||||
if (((d % sizeof(*pm8001_dev)) != 0)
|
||||
|| ((d / sizeof(*pm8001_dev)) >= PM8001_MAX_DEVICES))
|
||||
continue;
|
||||
} else if (pm8001_dev != device_to_close)
|
||||
continue;
|
||||
tag = ccb->ccb_tag;
|
||||
if (!tag || (tag == 0xFFFFFFFF))
|
||||
continue;
|
||||
task = ccb->task;
|
||||
if (!task || !task->task_done)
|
||||
continue;
|
||||
if (task_to_close && (task != task_to_close))
|
||||
continue;
|
||||
ts = &task->task_status;
|
||||
ts->resp = SAS_TASK_COMPLETE;
|
||||
/* Force the midlayer to retry */
|
||||
ts->stat = SAS_OPEN_REJECT;
|
||||
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
|
||||
if (pm8001_dev)
|
||||
pm8001_dev->running_req--;
|
||||
spin_lock_irqsave(&task->task_state_lock, flags1);
|
||||
task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
|
||||
task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
|
||||
task->task_state_flags |= SAS_TASK_STATE_DONE;
|
||||
if (unlikely((task->task_state_flags
|
||||
& SAS_TASK_STATE_ABORTED))) {
|
||||
spin_unlock_irqrestore(&task->task_state_lock,
|
||||
flags1);
|
||||
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&task->task_state_lock,
|
||||
flags1);
|
||||
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
|
||||
mb();/* in order to force CPU ordering */
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
task->task_done(task);
|
||||
spin_lock_irqsave(&pm8001_ha->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard mandates link reset for ATA (type 0) and hard reset for
|
||||
* SSP (type 1) , only for RECOVERY
|
||||
@ -875,12 +967,14 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev)
|
||||
|
||||
pm8001_dev = dev->lldd_dev;
|
||||
pm8001_ha = pm8001_find_ha_by_dev(dev);
|
||||
phy = sas_find_local_phy(dev);
|
||||
phy = sas_get_local_phy(dev);
|
||||
|
||||
if (dev_is_sata(dev)) {
|
||||
DECLARE_COMPLETION_ONSTACK(completion_setstate);
|
||||
if (scsi_is_sas_phy_local(phy))
|
||||
return 0;
|
||||
if (scsi_is_sas_phy_local(phy)) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
rc = sas_phy_reset(phy, 1);
|
||||
msleep(2000);
|
||||
rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
|
||||
@ -889,12 +983,14 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev)
|
||||
rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
|
||||
pm8001_dev, 0x01);
|
||||
wait_for_completion(&completion_setstate);
|
||||
} else{
|
||||
rc = sas_phy_reset(phy, 1);
|
||||
msleep(2000);
|
||||
} else {
|
||||
rc = sas_phy_reset(phy, 1);
|
||||
msleep(2000);
|
||||
}
|
||||
PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n",
|
||||
pm8001_dev->device_id, rc));
|
||||
out:
|
||||
sas_put_local_phy(phy);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -906,10 +1002,11 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun)
|
||||
struct pm8001_device *pm8001_dev = dev->lldd_dev;
|
||||
struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev);
|
||||
if (dev_is_sata(dev)) {
|
||||
struct sas_phy *phy = sas_find_local_phy(dev);
|
||||
struct sas_phy *phy = sas_get_local_phy(dev);
|
||||
rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
|
||||
dev, 1, 0);
|
||||
rc = sas_phy_reset(phy, 1);
|
||||
sas_put_local_phy(phy);
|
||||
rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha,
|
||||
pm8001_dev, 0x01);
|
||||
msleep(2000);
|
||||
|
@ -235,6 +235,7 @@ struct pm8001_ccb_info {
|
||||
struct pm8001_device *device;
|
||||
struct pm8001_prd buf_prd[PM8001_MAX_DMA_SG];
|
||||
struct fw_control_ex *fw_control_context;
|
||||
u8 open_retry;
|
||||
};
|
||||
|
||||
struct mpi_mem {
|
||||
@ -484,10 +485,15 @@ void pm8001_dev_gone(struct domain_device *dev);
|
||||
int pm8001_lu_reset(struct domain_device *dev, u8 *lun);
|
||||
int pm8001_I_T_nexus_reset(struct domain_device *dev);
|
||||
int pm8001_query_task(struct sas_task *task);
|
||||
void pm8001_open_reject_retry(
|
||||
struct pm8001_hba_info *pm8001_ha,
|
||||
struct sas_task *task_to_close,
|
||||
struct pm8001_device *device_to_close);
|
||||
int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr,
|
||||
dma_addr_t *pphys_addr, u32 *pphys_addr_hi, u32 *pphys_addr_lo,
|
||||
u32 mem_size, u32 align);
|
||||
|
||||
int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
|
||||
|
||||
/* ctl shared API */
|
||||
extern struct device_attribute *pm8001_host_attrs[];
|
||||
|
@ -356,7 +356,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
|
||||
else if (start == (ha->flt_region_boot * 4) ||
|
||||
start == (ha->flt_region_fw * 4))
|
||||
valid = 1;
|
||||
else if (IS_QLA25XX(ha) || IS_QLA8XXX_TYPE(ha))
|
||||
else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)
|
||||
|| IS_CNA_CAPABLE(ha) || IS_QLA2031(ha))
|
||||
valid = 1;
|
||||
if (!valid) {
|
||||
ql_log(ql_log_warn, vha, 0x7065,
|
||||
@ -626,144 +627,6 @@ static struct bin_attribute sysfs_reset_attr = {
|
||||
.write = qla2x00_sysfs_write_reset,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_edc(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint16_t dev, adr, opt, len;
|
||||
int rval;
|
||||
|
||||
ha->edc_data_len = 0;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ha->edc_data) {
|
||||
ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
|
||||
&ha->edc_data_dma);
|
||||
if (!ha->edc_data) {
|
||||
ql_log(ql_log_warn, vha, 0x7073,
|
||||
"Unable to allocate memory for EDC write.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
dev = le16_to_cpup((void *)&buf[0]);
|
||||
adr = le16_to_cpup((void *)&buf[2]);
|
||||
opt = le16_to_cpup((void *)&buf[4]);
|
||||
len = le16_to_cpup((void *)&buf[6]);
|
||||
|
||||
if (!(opt & BIT_0))
|
||||
if (len == 0 || len > DMA_POOL_SIZE || len > count - 8)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(ha->edc_data, &buf[8], len);
|
||||
|
||||
rval = qla2x00_write_sfp(vha, ha->edc_data_dma, ha->edc_data,
|
||||
dev, adr, len, opt);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x7074,
|
||||
"Unable to write EDC (%x) %02x:%04x:%02x:%02x:%02hhx\n",
|
||||
rval, dev, adr, opt, len, buf[8]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct bin_attribute sysfs_edc_attr = {
|
||||
.attr = {
|
||||
.name = "edc",
|
||||
.mode = S_IWUSR,
|
||||
},
|
||||
.size = 0,
|
||||
.write = qla2x00_sysfs_write_edc,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_write_edc_status(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint16_t dev, adr, opt, len;
|
||||
int rval;
|
||||
|
||||
ha->edc_data_len = 0;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ha->edc_data) {
|
||||
ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
|
||||
&ha->edc_data_dma);
|
||||
if (!ha->edc_data) {
|
||||
ql_log(ql_log_warn, vha, 0x708c,
|
||||
"Unable to allocate memory for EDC status.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
dev = le16_to_cpup((void *)&buf[0]);
|
||||
adr = le16_to_cpup((void *)&buf[2]);
|
||||
opt = le16_to_cpup((void *)&buf[4]);
|
||||
len = le16_to_cpup((void *)&buf[6]);
|
||||
|
||||
if (!(opt & BIT_0))
|
||||
if (len == 0 || len > DMA_POOL_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
memset(ha->edc_data, 0, len);
|
||||
rval = qla2x00_read_sfp(vha, ha->edc_data_dma, ha->edc_data,
|
||||
dev, adr, len, opt);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_info, vha, 0x7075,
|
||||
"Unable to write EDC status (%x) %02x:%04x:%02x:%02x.\n",
|
||||
rval, dev, adr, opt, len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ha->edc_data_len = len;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_edc_status(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
|
||||
struct device, kobj)));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) || off != 0 || count == 0)
|
||||
return 0;
|
||||
|
||||
if (!ha->edc_data || ha->edc_data_len == 0 || ha->edc_data_len > count)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(buf, ha->edc_data, ha->edc_data_len);
|
||||
|
||||
return ha->edc_data_len;
|
||||
}
|
||||
|
||||
static struct bin_attribute sysfs_edc_status_attr = {
|
||||
.attr = {
|
||||
.name = "edc_status",
|
||||
.mode = S_IRUSR | S_IWUSR,
|
||||
},
|
||||
.size = 0,
|
||||
.write = qla2x00_sysfs_write_edc_status,
|
||||
.read = qla2x00_sysfs_read_edc_status,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
@ -879,8 +742,6 @@ static struct sysfs_entry {
|
||||
{ "vpd", &sysfs_vpd_attr, 1 },
|
||||
{ "sfp", &sysfs_sfp_attr, 1 },
|
||||
{ "reset", &sysfs_reset_attr, },
|
||||
{ "edc", &sysfs_edc_attr, 2 },
|
||||
{ "edc_status", &sysfs_edc_status_attr, 2 },
|
||||
{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
|
||||
{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
|
||||
{ NULL },
|
||||
@ -898,7 +759,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
|
||||
continue;
|
||||
if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw))
|
||||
continue;
|
||||
if (iter->is4GBp_only == 3 && !(IS_QLA8XXX_TYPE(vha->hw)))
|
||||
if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
|
||||
continue;
|
||||
|
||||
ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
|
||||
@ -926,7 +787,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha)
|
||||
continue;
|
||||
if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
|
||||
continue;
|
||||
if (iter->is4GBp_only == 3 && !!(IS_QLA8XXX_TYPE(vha->hw)))
|
||||
if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw)))
|
||||
continue;
|
||||
|
||||
sysfs_remove_bin_file(&host->shost_gendev.kobj,
|
||||
@ -1231,7 +1092,7 @@ qla2x00_optrom_gold_fw_version_show(struct device *dev,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
|
||||
@ -1278,7 +1139,7 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
|
||||
@ -1293,7 +1154,7 @@ qla2x00_phy_version_show(struct device *dev, struct device_attribute *attr,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
|
||||
@ -1316,7 +1177,7 @@ qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
|
||||
if (!IS_QLA8XXX_TYPE(vha->hw))
|
||||
if (!IS_CNA_CAPABLE(vha->hw))
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id);
|
||||
@ -1328,7 +1189,7 @@ qla2x00_vn_port_mac_address_show(struct device *dev,
|
||||
{
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
|
||||
if (!IS_QLA8XXX_TYPE(vha->hw))
|
||||
if (!IS_CNA_CAPABLE(vha->hw))
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
@ -1364,7 +1225,7 @@ qla2x00_thermal_temp_show(struct device *dev,
|
||||
else if (!vha->hw->flags.eeh_busy)
|
||||
rval = qla2x00_get_thermal_temp(vha, &temp, &frac);
|
||||
if (rval != QLA_SUCCESS)
|
||||
temp = frac = 0;
|
||||
return snprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d.%02d\n", temp, frac);
|
||||
}
|
||||
@ -1493,6 +1354,9 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
|
||||
case PORT_SPEED_10GB:
|
||||
speed = FC_PORTSPEED_10GBIT;
|
||||
break;
|
||||
case PORT_SPEED_16GB:
|
||||
speed = FC_PORTSPEED_16GBIT;
|
||||
break;
|
||||
}
|
||||
fc_host_speed(shost) = speed;
|
||||
}
|
||||
@ -1643,10 +1507,14 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
|
||||
* final cleanup of firmware resources (PCBs and XCBs).
|
||||
*/
|
||||
if (fcport->loop_id != FC_NO_LOOP_ID &&
|
||||
!test_bit(UNLOADING, &fcport->vha->dpc_flags))
|
||||
fcport->vha->hw->isp_ops->fabric_logout(fcport->vha,
|
||||
fcport->loop_id, fcport->d_id.b.domain,
|
||||
fcport->d_id.b.area, fcport->d_id.b.al_pa);
|
||||
!test_bit(UNLOADING, &fcport->vha->dpc_flags)) {
|
||||
if (IS_FWI2_CAPABLE(fcport->vha->hw))
|
||||
fcport->vha->hw->isp_ops->fabric_logout(fcport->vha,
|
||||
fcport->loop_id, fcport->d_id.b.domain,
|
||||
fcport->d_id.b.area, fcport->d_id.b.al_pa);
|
||||
else
|
||||
qla2x00_port_logout(fcport->vha, fcport);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1889,6 +1757,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (qos) {
|
||||
ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0,
|
||||
qos);
|
||||
@ -2086,7 +1955,7 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
|
||||
fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports;
|
||||
fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count;
|
||||
|
||||
if (IS_QLA8XXX_TYPE(ha))
|
||||
if (IS_CNA_CAPABLE(ha))
|
||||
speed = FC_PORTSPEED_10GBIT;
|
||||
else if (IS_QLA25XX(ha))
|
||||
speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
|
||||
|
@ -11,29 +11,36 @@
|
||||
#include <linux/delay.h>
|
||||
|
||||
/* BSG support for ELS/CT pass through */
|
||||
inline srb_t *
|
||||
qla2x00_get_ctx_bsg_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size)
|
||||
void
|
||||
qla2x00_bsg_job_done(void *data, void *ptr, int res)
|
||||
{
|
||||
srb_t *sp;
|
||||
srb_t *sp = (srb_t *)ptr;
|
||||
struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
|
||||
struct fc_bsg_job *bsg_job = sp->u.bsg_job;
|
||||
|
||||
bsg_job->reply->result = res;
|
||||
bsg_job->job_done(bsg_job);
|
||||
sp->free(vha, sp);
|
||||
}
|
||||
|
||||
void
|
||||
qla2x00_bsg_sp_free(void *data, void *ptr)
|
||||
{
|
||||
srb_t *sp = (srb_t *)ptr;
|
||||
struct scsi_qla_host *vha = (scsi_qla_host_t *)data;
|
||||
struct fc_bsg_job *bsg_job = sp->u.bsg_job;
|
||||
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);
|
||||
sp = NULL;
|
||||
goto done;
|
||||
}
|
||||
dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
|
||||
bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
|
||||
|
||||
memset(sp, 0, sizeof(*sp));
|
||||
sp->fcport = fcport;
|
||||
sp->ctx = ctx;
|
||||
ctx->iocbs = 1;
|
||||
done:
|
||||
return sp;
|
||||
dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
|
||||
bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
|
||||
|
||||
if (sp->type == SRB_CT_CMD ||
|
||||
sp->type == SRB_ELS_CMD_HST)
|
||||
kfree(sp->fcport);
|
||||
mempool_free(sp, vha->hw->srb_mempool);
|
||||
}
|
||||
|
||||
int
|
||||
@ -101,8 +108,6 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job)
|
||||
uint32_t len;
|
||||
uint32_t oper;
|
||||
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
|
||||
if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA82XX(ha))) {
|
||||
ret = -EINVAL;
|
||||
goto exit_fcp_prio_cfg;
|
||||
@ -217,6 +222,7 @@ exit_fcp_prio_cfg:
|
||||
bsg_job->job_done(bsg_job);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qla2x00_process_els(struct fc_bsg_job *bsg_job)
|
||||
{
|
||||
@ -230,7 +236,6 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
|
||||
int req_sg_cnt, rsp_sg_cnt;
|
||||
int rval = (DRIVER_ERROR << 16);
|
||||
uint16_t nextlid = 0;
|
||||
struct srb_ctx *els;
|
||||
|
||||
if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
|
||||
rport = bsg_job->rport;
|
||||
@ -337,20 +342,21 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
|
||||
}
|
||||
|
||||
/* Alloc SRB structure */
|
||||
sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx));
|
||||
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
|
||||
if (!sp) {
|
||||
rval = -ENOMEM;
|
||||
goto done_unmap_sg;
|
||||
}
|
||||
|
||||
els = sp->ctx;
|
||||
els->type =
|
||||
sp->type =
|
||||
(bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
|
||||
SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST);
|
||||
els->name =
|
||||
sp->name =
|
||||
(bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
|
||||
"bsg_els_rpt" : "bsg_els_hst");
|
||||
els->u.bsg_job = bsg_job;
|
||||
sp->u.bsg_job = bsg_job;
|
||||
sp->free = qla2x00_bsg_sp_free;
|
||||
sp->done = qla2x00_bsg_job_done;
|
||||
|
||||
ql_dbg(ql_dbg_user, vha, 0x700a,
|
||||
"bsg rqst type: %s els type: %x - loop-id=%x "
|
||||
@ -362,7 +368,6 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x700e,
|
||||
"qla2x00_start_sp failed = %d\n", rval);
|
||||
kfree(sp->ctx);
|
||||
mempool_free(sp, ha->srb_mempool);
|
||||
rval = -EIO;
|
||||
goto done_unmap_sg;
|
||||
@ -409,7 +414,6 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
|
||||
uint16_t loop_id;
|
||||
struct fc_port *fcport;
|
||||
char *type = "FC_BSG_HST_CT";
|
||||
struct srb_ctx *ct;
|
||||
|
||||
req_sg_cnt =
|
||||
dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
|
||||
@ -486,19 +490,20 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
|
||||
fcport->loop_id = loop_id;
|
||||
|
||||
/* Alloc SRB structure */
|
||||
sp = qla2x00_get_ctx_bsg_sp(vha, fcport, sizeof(struct srb_ctx));
|
||||
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
|
||||
if (!sp) {
|
||||
ql_log(ql_log_warn, vha, 0x7015,
|
||||
"qla2x00_get_ctx_bsg_sp failed.\n");
|
||||
"qla2x00_get_sp failed.\n");
|
||||
rval = -ENOMEM;
|
||||
goto done_free_fcport;
|
||||
}
|
||||
|
||||
ct = sp->ctx;
|
||||
ct->type = SRB_CT_CMD;
|
||||
ct->name = "bsg_ct";
|
||||
ct->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);
|
||||
ct->u.bsg_job = bsg_job;
|
||||
sp->type = SRB_CT_CMD;
|
||||
sp->name = "bsg_ct";
|
||||
sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);
|
||||
sp->u.bsg_job = bsg_job;
|
||||
sp->free = qla2x00_bsg_sp_free;
|
||||
sp->done = qla2x00_bsg_job_done;
|
||||
|
||||
ql_dbg(ql_dbg_user, vha, 0x7016,
|
||||
"bsg rqst type: %s else type: %x - "
|
||||
@ -511,7 +516,6 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x7017,
|
||||
"qla2x00_start_sp failed=%d.\n", rval);
|
||||
kfree(sp->ctx);
|
||||
mempool_free(sp, ha->srb_mempool);
|
||||
rval = -EIO;
|
||||
goto done_free_fcport;
|
||||
@ -540,7 +544,7 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
|
||||
int rval = 0;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
|
||||
goto done_set_internal;
|
||||
|
||||
new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
|
||||
@ -582,7 +586,7 @@ qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
|
||||
uint16_t new_config[4];
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
|
||||
goto done_reset_internal;
|
||||
|
||||
memset(new_config, 0 , sizeof(new_config));
|
||||
@ -707,7 +711,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
|
||||
if ((ha->current_topology == ISP_CFG_F ||
|
||||
(atomic_read(&vha->loop_state) == LOOP_DOWN) ||
|
||||
(IS_QLA81XX(ha) &&
|
||||
((IS_QLA81XX(ha) || IS_QLA83XX(ha)) &&
|
||||
le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
|
||||
&& req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
|
||||
elreq.options == EXTERNAL_LOOPBACK) {
|
||||
@ -717,13 +721,12 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
command_sent = INT_DEF_LB_ECHO_CMD;
|
||||
rval = qla2x00_echo_test(vha, &elreq, response);
|
||||
} else {
|
||||
if (IS_QLA81XX(ha)) {
|
||||
if (IS_QLA81XX(ha) || IS_QLA8031(ha)) {
|
||||
memset(config, 0, sizeof(config));
|
||||
memset(new_config, 0, sizeof(new_config));
|
||||
if (qla81xx_get_port_config(vha, config)) {
|
||||
ql_log(ql_log_warn, vha, 0x701f,
|
||||
"Get port config failed.\n");
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
bsg_job->reply->result = (DID_ERROR << 16);
|
||||
rval = -EPERM;
|
||||
goto done_free_dma_req;
|
||||
@ -737,8 +740,6 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
new_config)) {
|
||||
ql_log(ql_log_warn, vha, 0x7024,
|
||||
"Internal loopback failed.\n");
|
||||
bsg_job->reply->reply_payload_rcv_len =
|
||||
0;
|
||||
bsg_job->reply->result =
|
||||
(DID_ERROR << 16);
|
||||
rval = -EPERM;
|
||||
@ -750,8 +751,6 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
*/
|
||||
if (qla81xx_reset_internal_loopback(vha,
|
||||
config, 1)) {
|
||||
bsg_job->reply->reply_payload_rcv_len =
|
||||
0;
|
||||
bsg_job->reply->result =
|
||||
(DID_ERROR << 16);
|
||||
rval = -EPERM;
|
||||
@ -788,7 +787,6 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
"MPI reset failed.\n");
|
||||
}
|
||||
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
bsg_job->reply->result = (DID_ERROR << 16);
|
||||
rval = -EIO;
|
||||
goto done_free_dma_req;
|
||||
@ -813,7 +811,6 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
fw_sts_ptr += sizeof(response);
|
||||
*fw_sts_ptr = command_sent;
|
||||
rval = 0;
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
bsg_job->reply->result = (DID_ERROR << 16);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_user, vha, 0x702d,
|
||||
@ -872,7 +869,7 @@ qla84xx_reset(struct fc_bsg_job *bsg_job)
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x7030,
|
||||
"Vendor request 84xx reset failed.\n");
|
||||
rval = bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
rval = 0;
|
||||
bsg_job->reply->result = (DID_ERROR << 16);
|
||||
|
||||
} else {
|
||||
@ -971,9 +968,8 @@ qla84xx_updatefw(struct fc_bsg_job *bsg_job)
|
||||
ql_log(ql_log_warn, vha, 0x7037,
|
||||
"Vendor request 84xx updatefw failed.\n");
|
||||
|
||||
rval = bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
rval = 0;
|
||||
bsg_job->reply->result = (DID_ERROR << 16);
|
||||
|
||||
} else {
|
||||
ql_dbg(ql_dbg_user, vha, 0x7038,
|
||||
"Vendor request 84xx updatefw completed.\n");
|
||||
@ -1159,7 +1155,7 @@ qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job)
|
||||
ql_log(ql_log_warn, vha, 0x7043,
|
||||
"Vendor request 84xx mgmt failed.\n");
|
||||
|
||||
rval = bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
rval = 0;
|
||||
bsg_job->reply->result = (DID_ERROR << 16);
|
||||
|
||||
} else {
|
||||
@ -1210,8 +1206,6 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
|
||||
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
||||
uint8_t *rsp_ptr = NULL;
|
||||
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
|
||||
if (!IS_IIDMA_CAPABLE(vha->hw)) {
|
||||
ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n");
|
||||
return -EINVAL;
|
||||
@ -1304,8 +1298,6 @@ qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
int valid = 0;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
|
||||
if (unlikely(pci_channel_offline(ha->pdev)))
|
||||
return -EINVAL;
|
||||
|
||||
@ -1331,7 +1323,7 @@ qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
start == (ha->flt_region_fw * 4))
|
||||
valid = 1;
|
||||
else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
|
||||
IS_QLA8XXX_TYPE(ha))
|
||||
IS_CNA_CAPABLE(ha) || IS_QLA2031(ha))
|
||||
valid = 1;
|
||||
if (!valid) {
|
||||
ql_log(ql_log_warn, vha, 0x7058,
|
||||
@ -1617,6 +1609,9 @@ qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
|
||||
struct Scsi_Host *host;
|
||||
scsi_qla_host_t *vha;
|
||||
|
||||
/* In case no data transferred. */
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
|
||||
if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) {
|
||||
rport = bsg_job->rport;
|
||||
fcport = *(fc_port_t **) rport->dd_data;
|
||||
@ -1655,6 +1650,7 @@ qla24xx_bsg_request(struct fc_bsg_job *bsg_job)
|
||||
case FC_BSG_RPT_CT:
|
||||
default:
|
||||
ql_log(ql_log_warn, vha, 0x705a, "Unsupported BSG request.\n");
|
||||
bsg_job->reply->result = ret;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
@ -1669,7 +1665,6 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
|
||||
int cnt, que;
|
||||
unsigned long flags;
|
||||
struct req_que *req;
|
||||
struct srb_ctx *sp_bsg;
|
||||
|
||||
/* find the bsg job from the active list of commands */
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
@ -1681,11 +1676,9 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
|
||||
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
|
||||
sp = req->outstanding_cmds[cnt];
|
||||
if (sp) {
|
||||
sp_bsg = sp->ctx;
|
||||
|
||||
if (((sp_bsg->type == SRB_CT_CMD) ||
|
||||
(sp_bsg->type == SRB_ELS_CMD_HST))
|
||||
&& (sp_bsg->u.bsg_job == bsg_job)) {
|
||||
if (((sp->type == SRB_CT_CMD) ||
|
||||
(sp->type == SRB_ELS_CMD_HST))
|
||||
&& (sp->u.bsg_job == bsg_job)) {
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
if (ha->isp_ops->abort_command(sp)) {
|
||||
ql_log(ql_log_warn, vha, 0x7089,
|
||||
@ -1715,7 +1708,6 @@ done:
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
if (bsg_job->request->msgcode == FC_BSG_HST_CT)
|
||||
kfree(sp->fcport);
|
||||
kfree(sp->ctx);
|
||||
mempool_free(sp, ha->srb_mempool);
|
||||
return 0;
|
||||
}
|
||||
|
@ -11,23 +11,27 @@
|
||||
* ----------------------------------------------------------------------
|
||||
* | Level | Last Value Used | Holes |
|
||||
* ----------------------------------------------------------------------
|
||||
* | Module Init and Probe | 0x0116 | 0xfa |
|
||||
* | Mailbox commands | 0x112b | |
|
||||
* | Device Discovery | 0x2084 | |
|
||||
* | Queue Command and IO tracing | 0x302f | 0x3008,0x302d, |
|
||||
* | | | 0x302e |
|
||||
* | Module Init and Probe | 0x0120 | 0x4b,0xba,0xfa |
|
||||
* | Mailbox commands | 0x113e | 0x112c-0x112e |
|
||||
* | | | 0x113a |
|
||||
* | Device Discovery | 0x2086 | 0x2020-0x2022 |
|
||||
* | Queue Command and IO tracing | 0x302f | 0x3006,0x3008 |
|
||||
* | | | 0x302d-0x302e |
|
||||
* | DPC Thread | 0x401c | |
|
||||
* | Async Events | 0x5057 | 0x5052 |
|
||||
* | Timer Routines | 0x6011 | 0x600e,0x600f |
|
||||
* | User Space Interactions | 0x709e | 0x7018,0x702e |
|
||||
* | | | 0x7039,0x7045 |
|
||||
* | Async Events | 0x505d | 0x502b-0x502f |
|
||||
* | | | 0x5047,0x5052 |
|
||||
* | Timer Routines | 0x6011 | 0x600e-0x600f |
|
||||
* | User Space Interactions | 0x709f | 0x7018,0x702e, |
|
||||
* | | | 0x7039,0x7045, |
|
||||
* | | | 0x7073-0x7075, |
|
||||
* | | | 0x708c |
|
||||
* | Task Management | 0x803c | 0x8025-0x8026 |
|
||||
* | | | 0x800b,0x8039 |
|
||||
* | AER/EEH | 0x900f | |
|
||||
* | Virtual Port | 0xa007 | |
|
||||
* | ISP82XX Specific | 0xb052 | |
|
||||
* | MultiQ | 0xc00b | |
|
||||
* | Misc | 0xd00b | |
|
||||
* | ISP82XX Specific | 0xb054 | 0xb053 |
|
||||
* | MultiQ | 0xc00c | |
|
||||
* | Misc | 0xd010 | |
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@ -85,7 +89,7 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
|
||||
WRT_REG_WORD(®->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED);
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
|
||||
dwords = GID_LIST_SIZE / 4;
|
||||
dwords = qla2x00_gid_list_size(ha) / 4;
|
||||
for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS;
|
||||
cnt += dwords, addr += dwords) {
|
||||
if (cnt + dwords > ram_dwords)
|
||||
@ -260,7 +264,7 @@ qla2xxx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint16_t *ram,
|
||||
WRT_MAILBOX_REG(ha, reg, 0, MBC_DUMP_RISC_RAM_EXTENDED);
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
|
||||
words = GID_LIST_SIZE / 2;
|
||||
words = qla2x00_gid_list_size(ha) / 2;
|
||||
for (cnt = 0; cnt < ram_words && rval == QLA_SUCCESS;
|
||||
cnt += words, addr += words) {
|
||||
if (cnt + words > ram_words)
|
||||
@ -374,6 +378,77 @@ qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
|
||||
return (char *)iter_reg + ntohl(fcec->size);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
|
||||
{
|
||||
struct qla2xxx_mqueue_chain *q;
|
||||
struct qla2xxx_mqueue_header *qh;
|
||||
struct req_que *req;
|
||||
struct rsp_que *rsp;
|
||||
int que;
|
||||
|
||||
if (!ha->mqenable)
|
||||
return ptr;
|
||||
|
||||
/* Request queues */
|
||||
for (que = 1; que < ha->max_req_queues; que++) {
|
||||
req = ha->req_q_map[que];
|
||||
if (!req)
|
||||
break;
|
||||
|
||||
/* Add chain. */
|
||||
q = ptr;
|
||||
*last_chain = &q->type;
|
||||
q->type = __constant_htonl(DUMP_CHAIN_QUEUE);
|
||||
q->chain_size = htonl(
|
||||
sizeof(struct qla2xxx_mqueue_chain) +
|
||||
sizeof(struct qla2xxx_mqueue_header) +
|
||||
(req->length * sizeof(request_t)));
|
||||
ptr += sizeof(struct qla2xxx_mqueue_chain);
|
||||
|
||||
/* Add header. */
|
||||
qh = ptr;
|
||||
qh->queue = __constant_htonl(TYPE_REQUEST_QUEUE);
|
||||
qh->number = htonl(que);
|
||||
qh->size = htonl(req->length * sizeof(request_t));
|
||||
ptr += sizeof(struct qla2xxx_mqueue_header);
|
||||
|
||||
/* Add data. */
|
||||
memcpy(ptr, req->ring, req->length * sizeof(request_t));
|
||||
ptr += req->length * sizeof(request_t);
|
||||
}
|
||||
|
||||
/* Response queues */
|
||||
for (que = 1; que < ha->max_rsp_queues; que++) {
|
||||
rsp = ha->rsp_q_map[que];
|
||||
if (!rsp)
|
||||
break;
|
||||
|
||||
/* Add chain. */
|
||||
q = ptr;
|
||||
*last_chain = &q->type;
|
||||
q->type = __constant_htonl(DUMP_CHAIN_QUEUE);
|
||||
q->chain_size = htonl(
|
||||
sizeof(struct qla2xxx_mqueue_chain) +
|
||||
sizeof(struct qla2xxx_mqueue_header) +
|
||||
(rsp->length * sizeof(response_t)));
|
||||
ptr += sizeof(struct qla2xxx_mqueue_chain);
|
||||
|
||||
/* Add header. */
|
||||
qh = ptr;
|
||||
qh->queue = __constant_htonl(TYPE_RESPONSE_QUEUE);
|
||||
qh->number = htonl(que);
|
||||
qh->size = htonl(rsp->length * sizeof(response_t));
|
||||
ptr += sizeof(struct qla2xxx_mqueue_header);
|
||||
|
||||
/* Add data. */
|
||||
memcpy(ptr, rsp->ring, rsp->length * sizeof(response_t));
|
||||
ptr += rsp->length * sizeof(response_t);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
|
||||
{
|
||||
@ -382,7 +457,7 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
|
||||
struct qla2xxx_mq_chain *mq = ptr;
|
||||
struct device_reg_25xxmq __iomem *reg;
|
||||
|
||||
if (!ha->mqenable)
|
||||
if (!ha->mqenable || IS_QLA83XX(ha))
|
||||
return ptr;
|
||||
|
||||
mq = ptr;
|
||||
@ -1322,12 +1397,16 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
|
||||
nxt = qla24xx_copy_eft(ha, nxt);
|
||||
|
||||
/* Chain entries -- started with MQ. */
|
||||
qla25xx_copy_fce(ha, nxt_chain, &last_chain);
|
||||
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
|
||||
nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
|
||||
if (last_chain) {
|
||||
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
|
||||
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
|
||||
}
|
||||
|
||||
/* Adjust valid length. */
|
||||
ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump);
|
||||
|
||||
qla25xx_fw_dump_failed_0:
|
||||
qla2xxx_dump_post_process(base_vha, rval);
|
||||
|
||||
@ -1636,12 +1715,16 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
|
||||
nxt = qla24xx_copy_eft(ha, nxt);
|
||||
|
||||
/* Chain entries -- started with MQ. */
|
||||
qla25xx_copy_fce(ha, nxt_chain, &last_chain);
|
||||
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
|
||||
nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
|
||||
if (last_chain) {
|
||||
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
|
||||
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
|
||||
}
|
||||
|
||||
/* Adjust valid length. */
|
||||
ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump);
|
||||
|
||||
qla81xx_fw_dump_failed_0:
|
||||
qla2xxx_dump_post_process(base_vha, rval);
|
||||
|
||||
@ -1650,6 +1733,507 @@ qla81xx_fw_dump_failed:
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
|
||||
{
|
||||
int rval;
|
||||
uint32_t cnt, reg_data;
|
||||
uint32_t risc_address;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
||||
uint32_t __iomem *dmp_reg;
|
||||
uint32_t *iter_reg;
|
||||
uint16_t __iomem *mbx_reg;
|
||||
unsigned long flags;
|
||||
struct qla83xx_fw_dump *fw;
|
||||
uint32_t ext_mem_cnt;
|
||||
void *nxt, *nxt_chain;
|
||||
uint32_t *last_chain = NULL;
|
||||
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
||||
|
||||
risc_address = ext_mem_cnt = 0;
|
||||
flags = 0;
|
||||
|
||||
if (!hardware_locked)
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
|
||||
if (!ha->fw_dump) {
|
||||
ql_log(ql_log_warn, vha, 0xd00c,
|
||||
"No buffer available for dump!!!\n");
|
||||
goto qla83xx_fw_dump_failed;
|
||||
}
|
||||
|
||||
if (ha->fw_dumped) {
|
||||
ql_log(ql_log_warn, vha, 0xd00d,
|
||||
"Firmware has been previously dumped (%p) -- ignoring "
|
||||
"request...\n", ha->fw_dump);
|
||||
goto qla83xx_fw_dump_failed;
|
||||
}
|
||||
fw = &ha->fw_dump->isp.isp83;
|
||||
qla2xxx_prep_dump(ha, ha->fw_dump);
|
||||
|
||||
fw->host_status = htonl(RD_REG_DWORD(®->host_status));
|
||||
|
||||
/* Pause RISC. */
|
||||
rval = qla24xx_pause_risc(reg);
|
||||
if (rval != QLA_SUCCESS)
|
||||
goto qla83xx_fw_dump_failed_0;
|
||||
|
||||
WRT_REG_DWORD(®->iobase_addr, 0x6000);
|
||||
dmp_reg = ®->iobase_window;
|
||||
reg_data = RD_REG_DWORD(dmp_reg);
|
||||
WRT_REG_DWORD(dmp_reg, 0);
|
||||
|
||||
dmp_reg = ®->unused_4_1[0];
|
||||
reg_data = RD_REG_DWORD(dmp_reg);
|
||||
WRT_REG_DWORD(dmp_reg, 0);
|
||||
|
||||
WRT_REG_DWORD(®->iobase_addr, 0x6010);
|
||||
dmp_reg = ®->unused_4_1[2];
|
||||
reg_data = RD_REG_DWORD(dmp_reg);
|
||||
WRT_REG_DWORD(dmp_reg, 0);
|
||||
|
||||
/* select PCR and disable ecc checking and correction */
|
||||
WRT_REG_DWORD(®->iobase_addr, 0x0F70);
|
||||
RD_REG_DWORD(®->iobase_addr);
|
||||
WRT_REG_DWORD(®->iobase_select, 0x60000000); /* write to F0h = PCR */
|
||||
|
||||
/* Host/Risc registers. */
|
||||
iter_reg = fw->host_risc_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x7010, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x7040, 16, iter_reg);
|
||||
|
||||
/* PCIe registers. */
|
||||
WRT_REG_DWORD(®->iobase_addr, 0x7C00);
|
||||
RD_REG_DWORD(®->iobase_addr);
|
||||
WRT_REG_DWORD(®->iobase_window, 0x01);
|
||||
dmp_reg = ®->iobase_c4;
|
||||
fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
|
||||
fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
|
||||
fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
|
||||
fw->pcie_regs[3] = htonl(RD_REG_DWORD(®->iobase_window));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_window, 0x00);
|
||||
RD_REG_DWORD(®->iobase_window);
|
||||
|
||||
/* Host interface registers. */
|
||||
dmp_reg = ®->flash_addr;
|
||||
for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
|
||||
fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
|
||||
|
||||
/* Disable interrupts. */
|
||||
WRT_REG_DWORD(®->ictrl, 0);
|
||||
RD_REG_DWORD(®->ictrl);
|
||||
|
||||
/* Shadow registers. */
|
||||
WRT_REG_DWORD(®->iobase_addr, 0x0F70);
|
||||
RD_REG_DWORD(®->iobase_addr);
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0000000);
|
||||
fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0100000);
|
||||
fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0200000);
|
||||
fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0300000);
|
||||
fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0400000);
|
||||
fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0500000);
|
||||
fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0600000);
|
||||
fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0700000);
|
||||
fw->shadow_reg[7] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0800000);
|
||||
fw->shadow_reg[8] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0900000);
|
||||
fw->shadow_reg[9] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
WRT_REG_DWORD(®->iobase_select, 0xB0A00000);
|
||||
fw->shadow_reg[10] = htonl(RD_REG_DWORD(®->iobase_sdata));
|
||||
|
||||
/* RISC I/O register. */
|
||||
WRT_REG_DWORD(®->iobase_addr, 0x0010);
|
||||
fw->risc_io_reg = htonl(RD_REG_DWORD(®->iobase_window));
|
||||
|
||||
/* Mailbox registers. */
|
||||
mbx_reg = ®->mailbox0;
|
||||
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
|
||||
fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
|
||||
|
||||
/* Transfer sequence registers. */
|
||||
iter_reg = fw->xseq_gp_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0xBE00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBE10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBE20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBE30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBE40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBE50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBE60, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBE70, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->xseq_0_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0xBFE0, 16, iter_reg);
|
||||
|
||||
qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
|
||||
|
||||
qla24xx_read_window(reg, 0xBEF0, 16, fw->xseq_2_reg);
|
||||
|
||||
/* Receive sequence registers. */
|
||||
iter_reg = fw->rseq_gp_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0xFE00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFE10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFE20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFE30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFE40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFE50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFE60, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFE70, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->rseq_0_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0xFFD0, 16, iter_reg);
|
||||
|
||||
qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
|
||||
qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
|
||||
qla24xx_read_window(reg, 0xFEF0, 16, fw->rseq_3_reg);
|
||||
|
||||
/* Auxiliary sequence registers. */
|
||||
iter_reg = fw->aseq_gp_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB070, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB100, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB110, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB120, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB130, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB140, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB150, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0xB160, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0xB170, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->aseq_0_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0xB0D0, 16, iter_reg);
|
||||
|
||||
qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg);
|
||||
qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg);
|
||||
qla24xx_read_window(reg, 0xB1F0, 16, fw->aseq_3_reg);
|
||||
|
||||
/* Command DMA registers. */
|
||||
iter_reg = fw->cmd_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7100, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x7120, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x7130, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x71F0, 16, iter_reg);
|
||||
|
||||
/* Queues. */
|
||||
iter_reg = fw->req0_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
|
||||
dmp_reg = ®->iobase_q;
|
||||
for (cnt = 0; cnt < 7; cnt++)
|
||||
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
|
||||
|
||||
iter_reg = fw->resp0_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
|
||||
dmp_reg = ®->iobase_q;
|
||||
for (cnt = 0; cnt < 7; cnt++)
|
||||
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
|
||||
|
||||
iter_reg = fw->req1_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
|
||||
dmp_reg = ®->iobase_q;
|
||||
for (cnt = 0; cnt < 7; cnt++)
|
||||
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
|
||||
|
||||
/* Transmit DMA registers. */
|
||||
iter_reg = fw->xmt0_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x7610, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->xmt1_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x7630, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->xmt2_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x7650, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->xmt3_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x7670, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->xmt4_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x7690, 16, iter_reg);
|
||||
|
||||
qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
|
||||
|
||||
/* Receive DMA registers. */
|
||||
iter_reg = fw->rcvt0_data_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x7710, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->rcvt1_data_dma_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x7730, 16, iter_reg);
|
||||
|
||||
/* RISC registers. */
|
||||
iter_reg = fw->risc_gp_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
|
||||
|
||||
/* Local memory controller registers. */
|
||||
iter_reg = fw->lmc_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x3070, 16, iter_reg);
|
||||
|
||||
/* Fibre Protocol Module registers. */
|
||||
iter_reg = fw->fpm_hdw_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x40C0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x40D0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x40E0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x40F0, 16, iter_reg);
|
||||
|
||||
/* RQ0 Array registers. */
|
||||
iter_reg = fw->rq0_array_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C60, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C70, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C80, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5C90, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5CA0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5CB0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5CC0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5CD0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5CE0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x5CF0, 16, iter_reg);
|
||||
|
||||
/* RQ1 Array registers. */
|
||||
iter_reg = fw->rq1_array_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D60, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D70, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D80, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5D90, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5DA0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5DB0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5DC0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5DD0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5DE0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x5DF0, 16, iter_reg);
|
||||
|
||||
/* RP0 Array registers. */
|
||||
iter_reg = fw->rp0_array_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E60, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E70, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E80, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5E90, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5EA0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5EB0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5EC0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5ED0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5EE0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x5EF0, 16, iter_reg);
|
||||
|
||||
/* RP1 Array registers. */
|
||||
iter_reg = fw->rp1_array_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F00, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F10, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F20, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F30, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F40, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F50, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F60, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F70, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F80, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5F90, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5FA0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5FB0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5FC0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5FD0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x5FE0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x5FF0, 16, iter_reg);
|
||||
|
||||
iter_reg = fw->at0_array_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x7080, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x7090, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x70A0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x70B0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x70C0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x70D0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x70E0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x70F0, 16, iter_reg);
|
||||
|
||||
/* I/O Queue Control registers. */
|
||||
qla24xx_read_window(reg, 0x7800, 16, fw->queue_control_reg);
|
||||
|
||||
/* Frame Buffer registers. */
|
||||
iter_reg = fw->fb_hdw_reg;
|
||||
iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6060, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6070, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x61C0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6530, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6540, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6550, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6560, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6570, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6580, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x6590, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x65A0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x65B0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x65C0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x65D0, 16, iter_reg);
|
||||
iter_reg = qla24xx_read_window(reg, 0x65E0, 16, iter_reg);
|
||||
qla24xx_read_window(reg, 0x6F00, 16, iter_reg);
|
||||
|
||||
/* Multi queue registers */
|
||||
nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset,
|
||||
&last_chain);
|
||||
|
||||
rval = qla24xx_soft_reset(ha);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0xd00e,
|
||||
"SOFT RESET FAILED, forcing continuation of dump!!!\n");
|
||||
rval = QLA_SUCCESS;
|
||||
|
||||
ql_log(ql_log_warn, vha, 0xd00f, "try a bigger hammer!!!\n");
|
||||
|
||||
WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET);
|
||||
RD_REG_DWORD(®->hccr);
|
||||
|
||||
WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE);
|
||||
RD_REG_DWORD(®->hccr);
|
||||
|
||||
WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET);
|
||||
RD_REG_DWORD(®->hccr);
|
||||
|
||||
for (cnt = 30000; cnt && (RD_REG_WORD(®->mailbox0)); cnt--)
|
||||
udelay(5);
|
||||
|
||||
if (!cnt) {
|
||||
nxt = fw->code_ram;
|
||||
nxt += sizeof(fw->code_ram),
|
||||
nxt += (ha->fw_memory_size - 0x100000 + 1);
|
||||
goto copy_queue;
|
||||
} else
|
||||
ql_log(ql_log_warn, vha, 0xd010,
|
||||
"bigger hammer success?\n");
|
||||
}
|
||||
|
||||
rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
|
||||
&nxt);
|
||||
if (rval != QLA_SUCCESS)
|
||||
goto qla83xx_fw_dump_failed_0;
|
||||
|
||||
copy_queue:
|
||||
nxt = qla2xxx_copy_queues(ha, nxt);
|
||||
|
||||
nxt = qla24xx_copy_eft(ha, nxt);
|
||||
|
||||
/* Chain entries -- started with MQ. */
|
||||
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
|
||||
nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
|
||||
if (last_chain) {
|
||||
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
|
||||
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
|
||||
}
|
||||
|
||||
/* Adjust valid length. */
|
||||
ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump);
|
||||
|
||||
qla83xx_fw_dump_failed_0:
|
||||
qla2xxx_dump_post_process(base_vha, rval);
|
||||
|
||||
qla83xx_fw_dump_failed:
|
||||
if (!hardware_locked)
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Driver Debug Functions. */
|
||||
/****************************************************************************/
|
||||
@ -1782,13 +2366,13 @@ ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...)
|
||||
vaf.va = &va;
|
||||
|
||||
switch (level) {
|
||||
case 0: /* FATAL LOG */
|
||||
case ql_log_fatal: /* FATAL LOG */
|
||||
pr_crit("%s%pV", pbuf, &vaf);
|
||||
break;
|
||||
case 1:
|
||||
case ql_log_warn:
|
||||
pr_err("%s%pV", pbuf, &vaf);
|
||||
break;
|
||||
case 2:
|
||||
case ql_log_info:
|
||||
pr_warn("%s%pV", pbuf, &vaf);
|
||||
break;
|
||||
default:
|
||||
@ -1837,13 +2421,13 @@ ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id,
|
||||
vaf.va = &va;
|
||||
|
||||
switch (level) {
|
||||
case 0: /* FATAL LOG */
|
||||
case ql_log_fatal: /* FATAL LOG */
|
||||
pr_crit("%s%pV", pbuf, &vaf);
|
||||
break;
|
||||
case 1:
|
||||
case ql_log_warn:
|
||||
pr_err("%s%pV", pbuf, &vaf);
|
||||
break;
|
||||
case 2:
|
||||
case ql_log_info:
|
||||
pr_warn("%s%pV", pbuf, &vaf);
|
||||
break;
|
||||
default:
|
||||
|
@ -165,6 +165,54 @@ struct qla81xx_fw_dump {
|
||||
uint32_t ext_mem[1];
|
||||
};
|
||||
|
||||
struct qla83xx_fw_dump {
|
||||
uint32_t host_status;
|
||||
uint32_t host_risc_reg[48];
|
||||
uint32_t pcie_regs[4];
|
||||
uint32_t host_reg[32];
|
||||
uint32_t shadow_reg[11];
|
||||
uint32_t risc_io_reg;
|
||||
uint16_t mailbox_reg[32];
|
||||
uint32_t xseq_gp_reg[256];
|
||||
uint32_t xseq_0_reg[48];
|
||||
uint32_t xseq_1_reg[16];
|
||||
uint32_t xseq_2_reg[16];
|
||||
uint32_t rseq_gp_reg[256];
|
||||
uint32_t rseq_0_reg[32];
|
||||
uint32_t rseq_1_reg[16];
|
||||
uint32_t rseq_2_reg[16];
|
||||
uint32_t rseq_3_reg[16];
|
||||
uint32_t aseq_gp_reg[256];
|
||||
uint32_t aseq_0_reg[32];
|
||||
uint32_t aseq_1_reg[16];
|
||||
uint32_t aseq_2_reg[16];
|
||||
uint32_t aseq_3_reg[16];
|
||||
uint32_t cmd_dma_reg[64];
|
||||
uint32_t req0_dma_reg[15];
|
||||
uint32_t resp0_dma_reg[15];
|
||||
uint32_t req1_dma_reg[15];
|
||||
uint32_t xmt0_dma_reg[32];
|
||||
uint32_t xmt1_dma_reg[32];
|
||||
uint32_t xmt2_dma_reg[32];
|
||||
uint32_t xmt3_dma_reg[32];
|
||||
uint32_t xmt4_dma_reg[32];
|
||||
uint32_t xmt_data_dma_reg[16];
|
||||
uint32_t rcvt0_data_dma_reg[32];
|
||||
uint32_t rcvt1_data_dma_reg[32];
|
||||
uint32_t risc_gp_reg[128];
|
||||
uint32_t lmc_reg[128];
|
||||
uint32_t fpm_hdw_reg[256];
|
||||
uint32_t rq0_array_reg[256];
|
||||
uint32_t rq1_array_reg[256];
|
||||
uint32_t rp0_array_reg[256];
|
||||
uint32_t rp1_array_reg[256];
|
||||
uint32_t queue_control_reg[16];
|
||||
uint32_t fb_hdw_reg[432];
|
||||
uint32_t at0_array_reg[128];
|
||||
uint32_t code_ram[0x2400];
|
||||
uint32_t ext_mem[1];
|
||||
};
|
||||
|
||||
#define EFT_NUM_BUFFERS 4
|
||||
#define EFT_BYTES_PER_BUFFER 0x4000
|
||||
#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
|
||||
@ -192,9 +240,23 @@ struct qla2xxx_mq_chain {
|
||||
uint32_t qregs[4 * QLA_MQ_SIZE];
|
||||
};
|
||||
|
||||
struct qla2xxx_mqueue_header {
|
||||
uint32_t queue;
|
||||
#define TYPE_REQUEST_QUEUE 0x1
|
||||
#define TYPE_RESPONSE_QUEUE 0x2
|
||||
uint32_t number;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct qla2xxx_mqueue_chain {
|
||||
uint32_t type;
|
||||
uint32_t chain_size;
|
||||
};
|
||||
|
||||
#define DUMP_CHAIN_VARIANT 0x80000000
|
||||
#define DUMP_CHAIN_FCE 0x7FFFFAF0
|
||||
#define DUMP_CHAIN_MQ 0x7FFFFAF1
|
||||
#define DUMP_CHAIN_QUEUE 0x7FFFFAF2
|
||||
#define DUMP_CHAIN_LAST 0x80000000
|
||||
|
||||
struct qla2xxx_fw_dump {
|
||||
@ -228,6 +290,7 @@ struct qla2xxx_fw_dump {
|
||||
struct qla24xx_fw_dump isp24;
|
||||
struct qla25xx_fw_dump isp25;
|
||||
struct qla81xx_fw_dump isp81;
|
||||
struct qla83xx_fw_dump isp83;
|
||||
} isp;
|
||||
};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user