Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (54 commits) [SCSI] Initial Commit of qla4xxx [SCSI] raid class: handle component-add errors [SCSI] SCSI megaraid_sas: handle thrown errors [SCSI] SCSI aic94xx: handle sysfs errors [SCSI] SCSI st: fix error handling in module init, sysfs [SCSI] SCSI sd: fix module init/exit error handling [SCSI] SCSI osst: add error handling to module init, sysfs [SCSI] scsi: remove hosts.h [SCSI] scsi: Scsi_Cmnd convertion in aic7xxx_old.c [SCSI] megaraid_sas: sets ioctl timeout and updates version,changelog [SCSI] megaraid_sas: adds tasklet for cmd completion [SCSI] megaraid_sas: prints pending cmds before setting hw_crit_error [SCSI] megaraid_sas: function pointer for disable interrupt [SCSI] megaraid_sas: frame count optimization [SCSI] megaraid_sas: FW transition and q size changes [SCSI] qla2xxx: Update version number to 8.01.07-k2. [SCSI] qla2xxx: Stall mid-layer error handlers while rport is blocked. [SCSI] qla2xxx: Add MODULE_FIRMWARE tags. [SCSI] qla2xxx: Add support for host port state FC transport attribute. [SCSI] qla2xxx: Add support for fabric name FC transport attribute. ...
This commit is contained in:
commit
97d41e90fe
|
@ -1,4 +1,49 @@
|
|||
|
||||
1 Release Date : Mon Oct 02 11:21:32 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
|
||||
2 Current Version : 00.00.03.05
|
||||
3 Older Version : 00.00.03.04
|
||||
|
||||
i. PCI_DEVICE macro used
|
||||
|
||||
Convert the pci_device_id-table of the megaraid_sas-driver to the PCI_DEVICE-macro, to safe some lines.
|
||||
|
||||
- Henrik Kretzschmar <henne@nachtwindheim.de>
|
||||
ii. All compiler warnings removed
|
||||
iii. megasas_ctrl_info struct reverted to 3.02 release
|
||||
iv. Default value of megasas_dbg_lvl set to 0
|
||||
v. Removing in megasas_exit the sysfs entry created for megasas_dbg_lvl
|
||||
vi. In megasas_teardown_frame_pool(), cmd->frame was passed instead of
|
||||
cmd->sense to pci_pool_free. Fixed. Bug was pointed out by
|
||||
Eric Sesterhenn
|
||||
|
||||
1 Release Date : Wed Sep 13 14:22:51 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
|
||||
2 Current Version : 00.00.03.04
|
||||
3 Older Version : 00.00.03.03
|
||||
|
||||
i. Added Reboot notify
|
||||
ii. Reduced by 1 max cmds sent to FW from Driver to make the reply_q_sz same
|
||||
as Max Cmds FW can support
|
||||
|
||||
1 Release Date : Tue Aug 22 16:33:14 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
|
||||
2 Current Version : 00.00.03.03
|
||||
3 Older Version : 00.00.03.02
|
||||
|
||||
i. Send stop adapter to FW & Dump pending FW cmds before declaring adapter dead.
|
||||
New varible added to set dbg level.
|
||||
ii. Disable interrupt made as fn pointer as they are different for 1068 / 1078
|
||||
iii. Frame count optimization. Main frame can contain 2 SGE for 64 bit SGLs and
|
||||
3 SGE for 32 bit SGL
|
||||
iv. Tasklet added for cmd completion
|
||||
v. If FW in operational state before firing INIT, now we send RESET Flag to FW instead of just READY. This is used to do soft reset.
|
||||
vi. megasas_ctrl_prop structure updated (based on FW struct)
|
||||
vii. Added print : FW now in Ready State during initialization
|
||||
|
||||
1 Release Date : Sun Aug 06 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
|
||||
2 Current Version : 00.00.03.02
|
||||
3 Older Version : 00.00.03.01
|
||||
|
||||
i. Added FW tranistion state for Hotplug scenario
|
||||
|
||||
1 Release Date : Sun May 14 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
|
||||
2 Current Version : 00.00.03.01
|
||||
3 Older Version : 00.00.02.04
|
||||
|
|
|
@ -6,13 +6,4 @@
|
|||
#include <linux/version.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6))
|
||||
static int inline scsi_device_online(struct scsi_device *sdev)
|
||||
{
|
||||
return sdev->online;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
#endif /* _LINUX_COMPAT_H */
|
||||
|
|
|
@ -2211,7 +2211,7 @@ static int __init twa_init(void)
|
|||
{
|
||||
printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
|
||||
|
||||
return pci_module_init(&twa_driver);
|
||||
return pci_register_driver(&twa_driver);
|
||||
} /* End twa_init() */
|
||||
|
||||
/* This function is called on driver exit */
|
||||
|
|
|
@ -2486,7 +2486,7 @@ static int __init tw_init(void)
|
|||
{
|
||||
printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
|
||||
|
||||
return pci_module_init(&tw_driver);
|
||||
return pci_register_driver(&tw_driver);
|
||||
} /* End tw_init() */
|
||||
|
||||
/* This function is called on driver exit */
|
||||
|
|
|
@ -74,7 +74,7 @@ static char *tw_aen_string[] = {
|
|||
[0x00D] = "ERROR: Logical unit deleted: Unit #",
|
||||
[0x00F] = "WARNING: SMART threshold exceeded: Port #",
|
||||
[0x021] = "WARNING: ATA UDMA downgrade: Port #",
|
||||
[0x021] = "WARNING: ATA UDMA upgrade: Port #",
|
||||
[0x022] = "WARNING: ATA UDMA upgrade: Port #",
|
||||
[0x023] = "WARNING: Sector repair occurred: Port #",
|
||||
[0x024] = "ERROR: SBUF integrity check failure",
|
||||
[0x025] = "ERROR: Lost cached write: Port #",
|
||||
|
|
|
@ -1016,7 +1016,7 @@ config SCSI_SYM53C8XX_MMIO
|
|||
|
||||
config SCSI_IPR
|
||||
tristate "IBM Power Linux RAID adapter support"
|
||||
depends on PCI && SCSI
|
||||
depends on PCI && SCSI && ATA
|
||||
select FW_LOADER
|
||||
---help---
|
||||
This driver supports the IBM Power Linux family RAID adapters.
|
||||
|
@ -1246,6 +1246,7 @@ config SCSI_QLOGICPTI
|
|||
module will be called qlogicpti.
|
||||
|
||||
source "drivers/scsi/qla2xxx/Kconfig"
|
||||
source "drivers/scsi/qla4xxx/Kconfig"
|
||||
|
||||
config SCSI_LPFC
|
||||
tristate "Emulex LightPulse Fibre Channel Support"
|
||||
|
@ -1262,8 +1263,8 @@ config SCSI_SEAGATE
|
|||
These are 8-bit SCSI controllers; the ST-01 is also supported by
|
||||
this driver. It is explained in section 3.9 of the SCSI-HOWTO,
|
||||
available from <http://www.tldp.org/docs.html#howto>. If it
|
||||
doesn't work out of the box, you may have to change some settings in
|
||||
<file:drivers/scsi/seagate.h>.
|
||||
doesn't work out of the box, you may have to change some macros at
|
||||
compiletime, which are described in <file:drivers/scsi/seagate.c>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called seagate.
|
||||
|
|
|
@ -84,6 +84,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o
|
|||
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
|
||||
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
|
||||
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
|
||||
obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
|
||||
obj-$(CONFIG_SCSI_LPFC) += lpfc/
|
||||
obj-$(CONFIG_SCSI_PAS16) += pas16.o
|
||||
obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
|
||||
|
|
|
@ -1187,7 +1187,7 @@ static struct pci_driver inia100_pci_driver = {
|
|||
|
||||
static int __init inia100_init(void)
|
||||
{
|
||||
return pci_module_init(&inia100_pci_driver);
|
||||
return pci_register_driver(&inia100_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit inia100_exit(void)
|
||||
|
|
|
@ -527,7 +527,8 @@ ahd_inw(struct ahd_softc *ahd, u_int port)
|
|||
* or have other side effects when the low byte is
|
||||
* read.
|
||||
*/
|
||||
return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
|
||||
uint16_t r = ahd_inb(ahd, port+1) << 8;
|
||||
return r | ahd_inb(ahd, port);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
|
|
|
@ -198,7 +198,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
int
|
||||
ahd_linux_pci_init(void)
|
||||
{
|
||||
return (pci_module_init(&aic79xx_pci_driver));
|
||||
return pci_register_driver(&aic79xx_pci_driver);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -300,7 +300,8 @@ ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
|
|||
static __inline uint16_t
|
||||
ahc_inw(struct ahc_softc *ahc, u_int port)
|
||||
{
|
||||
return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
|
||||
uint16_t r = ahc_inb(ahc, port+1) << 8;
|
||||
return r | ahc_inb(ahc, port);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
|
|
|
@ -246,8 +246,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
int
|
||||
ahc_linux_pci_init(void)
|
||||
{
|
||||
/* Translate error or zero return into zero or one */
|
||||
return pci_module_init(&aic7xxx_pci_driver) ? 0 : 1;
|
||||
return pci_register_driver(&aic7xxx_pci_driver);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -780,24 +780,26 @@ typedef enum {
|
|||
} ahc_bugs;
|
||||
|
||||
struct aic7xxx_scb {
|
||||
struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
|
||||
Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
|
||||
struct aic7xxx_scb *q_next; /* next scb in queue */
|
||||
volatile scb_flag_type flags; /* current state of scb */
|
||||
struct hw_scatterlist *sg_list; /* SG list in adapter format */
|
||||
unsigned char tag_action;
|
||||
unsigned char sg_count;
|
||||
unsigned char *sense_cmd; /*
|
||||
* Allocate 6 characters for
|
||||
* sense command.
|
||||
*/
|
||||
unsigned char *cmnd;
|
||||
unsigned int sg_length; /* We init this during buildscb so we
|
||||
* don't have to calculate anything
|
||||
* during underflow/overflow/stat code
|
||||
*/
|
||||
void *kmalloc_ptr;
|
||||
struct aic7xxx_scb_dma *scb_dma;
|
||||
struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
|
||||
struct scsi_cmnd *cmd; /* scsi_cmnd for this scb */
|
||||
struct aic7xxx_scb *q_next; /* next scb in queue */
|
||||
volatile scb_flag_type flags; /* current state of scb */
|
||||
struct hw_scatterlist *sg_list; /* SG list in adapter format */
|
||||
unsigned char tag_action;
|
||||
unsigned char sg_count;
|
||||
unsigned char *sense_cmd; /*
|
||||
* Allocate 6 characters for
|
||||
* sense command.
|
||||
*/
|
||||
unsigned char *cmnd;
|
||||
unsigned int sg_length; /*
|
||||
* We init this during
|
||||
* buildscb so we don't have
|
||||
* to calculate anything during
|
||||
* underflow/overflow/stat code
|
||||
*/
|
||||
void *kmalloc_ptr;
|
||||
struct aic7xxx_scb_dma *scb_dma;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -918,79 +920,77 @@ struct aic7xxx_host {
|
|||
* We are grouping things here....first, items that get either read or
|
||||
* written with nearly every interrupt
|
||||
*/
|
||||
volatile long flags;
|
||||
ahc_feature features; /* chip features */
|
||||
unsigned long base; /* card base address */
|
||||
volatile unsigned char __iomem *maddr; /* memory mapped address */
|
||||
unsigned long isr_count; /* Interrupt count */
|
||||
unsigned long spurious_int;
|
||||
scb_data_type *scb_data;
|
||||
struct aic7xxx_cmd_queue {
|
||||
Scsi_Cmnd *head;
|
||||
Scsi_Cmnd *tail;
|
||||
} completeq;
|
||||
volatile long flags;
|
||||
ahc_feature features; /* chip features */
|
||||
unsigned long base; /* card base address */
|
||||
volatile unsigned char __iomem *maddr; /* memory mapped address */
|
||||
unsigned long isr_count; /* Interrupt count */
|
||||
unsigned long spurious_int;
|
||||
scb_data_type *scb_data;
|
||||
struct aic7xxx_cmd_queue {
|
||||
struct scsi_cmnd *head;
|
||||
struct scsi_cmnd *tail;
|
||||
} completeq;
|
||||
|
||||
/*
|
||||
* Things read/written on nearly every entry into aic7xxx_queue()
|
||||
*/
|
||||
volatile scb_queue_type waiting_scbs;
|
||||
unsigned char unpause; /* unpause value for HCNTRL */
|
||||
unsigned char pause; /* pause value for HCNTRL */
|
||||
volatile unsigned char qoutfifonext;
|
||||
volatile unsigned char activescbs; /* active scbs */
|
||||
volatile unsigned char max_activescbs;
|
||||
volatile unsigned char qinfifonext;
|
||||
volatile unsigned char *untagged_scbs;
|
||||
volatile unsigned char *qoutfifo;
|
||||
volatile unsigned char *qinfifo;
|
||||
/*
|
||||
* Things read/written on nearly every entry into aic7xxx_queue()
|
||||
*/
|
||||
volatile scb_queue_type waiting_scbs;
|
||||
unsigned char unpause; /* unpause value for HCNTRL */
|
||||
unsigned char pause; /* pause value for HCNTRL */
|
||||
volatile unsigned char qoutfifonext;
|
||||
volatile unsigned char activescbs; /* active scbs */
|
||||
volatile unsigned char max_activescbs;
|
||||
volatile unsigned char qinfifonext;
|
||||
volatile unsigned char *untagged_scbs;
|
||||
volatile unsigned char *qoutfifo;
|
||||
volatile unsigned char *qinfifo;
|
||||
|
||||
unsigned char dev_last_queue_full[MAX_TARGETS];
|
||||
unsigned char dev_last_queue_full_count[MAX_TARGETS];
|
||||
unsigned short ultraenb; /* Gets downloaded to card as a
|
||||
bitmap */
|
||||
unsigned short discenable; /* Gets downloaded to card as a
|
||||
bitmap */
|
||||
transinfo_type user[MAX_TARGETS];
|
||||
unsigned char dev_last_queue_full[MAX_TARGETS];
|
||||
unsigned char dev_last_queue_full_count[MAX_TARGETS];
|
||||
unsigned short ultraenb; /* Gets downloaded to card as a bitmap */
|
||||
unsigned short discenable; /* Gets downloaded to card as a bitmap */
|
||||
transinfo_type user[MAX_TARGETS];
|
||||
|
||||
unsigned char msg_buf[13]; /* The message for the target */
|
||||
unsigned char msg_type;
|
||||
unsigned char msg_buf[13]; /* The message for the target */
|
||||
unsigned char msg_type;
|
||||
#define MSG_TYPE_NONE 0x00
|
||||
#define MSG_TYPE_INITIATOR_MSGOUT 0x01
|
||||
#define MSG_TYPE_INITIATOR_MSGIN 0x02
|
||||
unsigned char msg_len; /* Length of message */
|
||||
unsigned char msg_index; /* Index into msg_buf array */
|
||||
unsigned char msg_len; /* Length of message */
|
||||
unsigned char msg_index; /* Index into msg_buf array */
|
||||
|
||||
|
||||
/*
|
||||
* We put the less frequently used host structure items after the more
|
||||
* frequently used items to try and ease the burden on the cache subsystem.
|
||||
* These entries are not *commonly* accessed, whereas the preceding entries
|
||||
* are accessed very often.
|
||||
*/
|
||||
|
||||
unsigned int irq; /* IRQ for this adapter */
|
||||
int instance; /* aic7xxx instance number */
|
||||
int scsi_id; /* host adapter SCSI ID */
|
||||
int scsi_id_b; /* channel B for twin adapters */
|
||||
unsigned int bios_address;
|
||||
int board_name_index;
|
||||
unsigned short bios_control; /* bios control - SEEPROM */
|
||||
unsigned short adapter_control; /* adapter control - SEEPROM */
|
||||
struct pci_dev *pdev;
|
||||
unsigned char pci_bus;
|
||||
unsigned char pci_device_fn;
|
||||
struct seeprom_config sc;
|
||||
unsigned short sc_type;
|
||||
unsigned short sc_size;
|
||||
struct aic7xxx_host *next; /* allow for multiple IRQs */
|
||||
struct Scsi_Host *host; /* pointer to scsi host */
|
||||
struct list_head aic_devs; /* all aic_dev structs on host */
|
||||
int host_no; /* SCSI host number */
|
||||
unsigned long mbase; /* I/O memory address */
|
||||
ahc_chip chip; /* chip type */
|
||||
ahc_bugs bugs;
|
||||
dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
|
||||
/*
|
||||
* We put the less frequently used host structure items
|
||||
* after the more frequently used items to try and ease
|
||||
* the burden on the cache subsystem.
|
||||
* These entries are not *commonly* accessed, whereas
|
||||
* the preceding entries are accessed very often.
|
||||
*/
|
||||
|
||||
unsigned int irq; /* IRQ for this adapter */
|
||||
int instance; /* aic7xxx instance number */
|
||||
int scsi_id; /* host adapter SCSI ID */
|
||||
int scsi_id_b; /* channel B for twin adapters */
|
||||
unsigned int bios_address;
|
||||
int board_name_index;
|
||||
unsigned short bios_control; /* bios control - SEEPROM */
|
||||
unsigned short adapter_control; /* adapter control - SEEPROM */
|
||||
struct pci_dev *pdev;
|
||||
unsigned char pci_bus;
|
||||
unsigned char pci_device_fn;
|
||||
struct seeprom_config sc;
|
||||
unsigned short sc_type;
|
||||
unsigned short sc_size;
|
||||
struct aic7xxx_host *next; /* allow for multiple IRQs */
|
||||
struct Scsi_Host *host; /* pointer to scsi host */
|
||||
struct list_head aic_devs; /* all aic_dev structs on host */
|
||||
int host_no; /* SCSI host number */
|
||||
unsigned long mbase; /* I/O memory address */
|
||||
ahc_chip chip; /* chip type */
|
||||
ahc_bugs bugs;
|
||||
dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1271,7 +1271,7 @@ static void aic7xxx_set_syncrate(struct aic7xxx_host *p,
|
|||
static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel,
|
||||
int lun, unsigned int width, unsigned int type,
|
||||
struct aic_dev_data *aic_dev);
|
||||
static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
|
||||
static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd);
|
||||
static void aic7xxx_print_card(struct aic7xxx_host *p);
|
||||
static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
|
||||
static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded);
|
||||
|
@ -2626,7 +2626,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
|
|||
* we're finished. This function queues the completed commands.
|
||||
*-F*************************************************************************/
|
||||
static void
|
||||
aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
|
||||
aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, struct scsi_cmnd *cmd)
|
||||
{
|
||||
aic7xxx_position(cmd) = SCB_LIST_NULL;
|
||||
cmd->host_scribble = (char *)p->completeq.head;
|
||||
|
@ -2640,18 +2640,16 @@ aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
|
|||
* Description:
|
||||
* Process the completed command queue.
|
||||
*-F*************************************************************************/
|
||||
static void
|
||||
aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
|
||||
static void aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
|
||||
{
|
||||
Scsi_Cmnd *cmd;
|
||||
|
||||
while (p->completeq.head != NULL)
|
||||
{
|
||||
cmd = p->completeq.head;
|
||||
p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
|
||||
cmd->host_scribble = NULL;
|
||||
cmd->scsi_done(cmd);
|
||||
}
|
||||
struct scsi_cmnd *cmd;
|
||||
|
||||
while (p->completeq.head != NULL) {
|
||||
cmd = p->completeq.head;
|
||||
p->completeq.head = (struct scsi_Cmnd *) cmd->host_scribble;
|
||||
cmd->host_scribble = NULL;
|
||||
cmd->scsi_done(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/*+F*************************************************************************
|
||||
|
@ -2687,11 +2685,11 @@ aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
|
|||
static void
|
||||
aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
|
||||
{
|
||||
Scsi_Cmnd *cmd = scb->cmd;
|
||||
struct aic_dev_data *aic_dev = cmd->device->hostdata;
|
||||
int tindex = TARGET_INDEX(cmd);
|
||||
struct aic7xxx_scb *scbp;
|
||||
unsigned char queue_depth;
|
||||
struct scsi_cmnd *cmd = scb->cmd;
|
||||
struct aic_dev_data *aic_dev = cmd->device->hostdata;
|
||||
int tindex = TARGET_INDEX(cmd);
|
||||
struct aic7xxx_scb *scbp;
|
||||
unsigned char queue_depth;
|
||||
|
||||
if (cmd->use_sg > 1)
|
||||
{
|
||||
|
@ -2891,7 +2889,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
|
|||
* aic7xxx_run_done_queue
|
||||
*
|
||||
* Description:
|
||||
* Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
|
||||
* Calls the aic7xxx_done() for the scsi_cmnd of each scb in the
|
||||
* aborted list, and adds each scb to the free list. If complete
|
||||
* is TRUE, we also process the commands complete list.
|
||||
*-F*************************************************************************/
|
||||
|
@ -3826,9 +3824,9 @@ aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
|
|||
static void
|
||||
aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
|
||||
{
|
||||
struct aic7xxx_hwscb *hscb;
|
||||
Scsi_Cmnd *cmd;
|
||||
int actual, i;
|
||||
struct aic7xxx_hwscb *hscb;
|
||||
struct scsi_cmnd *cmd;
|
||||
int actual, i;
|
||||
|
||||
cmd = scb->cmd;
|
||||
hscb = scb->hscb;
|
||||
|
@ -4219,20 +4217,20 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
|
|||
|
||||
case BAD_STATUS:
|
||||
{
|
||||
unsigned char scb_index;
|
||||
struct aic7xxx_hwscb *hscb;
|
||||
Scsi_Cmnd *cmd;
|
||||
unsigned char scb_index;
|
||||
struct aic7xxx_hwscb *hscb;
|
||||
struct scsi_cmnd *cmd;
|
||||
|
||||
/* The sequencer will notify us when a command has an error that
|
||||
* would be of interest to the kernel. This allows us to leave
|
||||
* the sequencer running in the common case of command completes
|
||||
* without error. The sequencer will have DMA'd the SCB back
|
||||
* up to us, so we can reference the drivers SCB array.
|
||||
*
|
||||
* Set the default return value to 0 indicating not to send
|
||||
* sense. The sense code will change this if needed and this
|
||||
* reduces code duplication.
|
||||
*/
|
||||
/* The sequencer will notify us when a command has an error that
|
||||
* would be of interest to the kernel. This allows us to leave
|
||||
* the sequencer running in the common case of command completes
|
||||
* without error. The sequencer will have DMA'd the SCB back
|
||||
* up to us, so we can reference the drivers SCB array.
|
||||
*
|
||||
* Set the default return value to 0 indicating not to send
|
||||
* sense. The sense code will change this if needed and this
|
||||
* reduces code duplication.
|
||||
*/
|
||||
aic_outb(p, 0, RETURN_1);
|
||||
scb_index = aic_inb(p, SCB_TAG);
|
||||
if (scb_index > p->scb_data->numscbs)
|
||||
|
@ -5800,9 +5798,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
|
|||
}
|
||||
else if ((status & SELTO) != 0)
|
||||
{
|
||||
unsigned char scbptr;
|
||||
unsigned char nextscb;
|
||||
Scsi_Cmnd *cmd;
|
||||
unsigned char scbptr;
|
||||
unsigned char nextscb;
|
||||
struct scsi_cmnd *cmd;
|
||||
|
||||
scbptr = aic_inb(p, WAITING_SCBH);
|
||||
if (scbptr > p->scb_data->maxhscbs)
|
||||
|
@ -5941,11 +5939,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
|
|||
/*
|
||||
* Determine the bus phase and queue an appropriate message.
|
||||
*/
|
||||
char *phase;
|
||||
Scsi_Cmnd *cmd;
|
||||
unsigned char mesg_out = MSG_NOOP;
|
||||
unsigned char lastphase = aic_inb(p, LASTPHASE);
|
||||
unsigned char sstat2 = aic_inb(p, SSTAT2);
|
||||
char *phase;
|
||||
struct scsi_cmnd *cmd;
|
||||
unsigned char mesg_out = MSG_NOOP;
|
||||
unsigned char lastphase = aic_inb(p, LASTPHASE);
|
||||
unsigned char sstat2 = aic_inb(p, SSTAT2);
|
||||
|
||||
cmd = scb->cmd;
|
||||
switch (lastphase)
|
||||
|
@ -6248,10 +6246,10 @@ aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
|
|||
static void
|
||||
aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
|
||||
{
|
||||
struct aic7xxx_scb *scb = NULL;
|
||||
struct aic_dev_data *aic_dev;
|
||||
Scsi_Cmnd *cmd;
|
||||
unsigned char scb_index, tindex;
|
||||
struct aic7xxx_scb *scb = NULL;
|
||||
struct aic_dev_data *aic_dev;
|
||||
struct scsi_cmnd *cmd;
|
||||
unsigned char scb_index, tindex;
|
||||
|
||||
#ifdef AIC7XXX_VERBOSE_DEBUGGING
|
||||
if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
|
||||
|
@ -10131,9 +10129,8 @@ skip_pci_controller:
|
|||
* Description:
|
||||
* Build a SCB.
|
||||
*-F*************************************************************************/
|
||||
static void
|
||||
aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
|
||||
struct aic7xxx_scb *scb)
|
||||
static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
|
||||
struct aic7xxx_scb *scb)
|
||||
{
|
||||
unsigned short mask;
|
||||
struct aic7xxx_hwscb *hscb;
|
||||
|
@ -10285,8 +10282,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
|
|||
* Description:
|
||||
* Queue a SCB to the controller.
|
||||
*-F*************************************************************************/
|
||||
static int
|
||||
aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
|
||||
static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
|
||||
{
|
||||
struct aic7xxx_host *p;
|
||||
struct aic7xxx_scb *scb;
|
||||
|
@ -10319,11 +10315,11 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
|
|||
}
|
||||
scb->cmd = cmd;
|
||||
|
||||
/*
|
||||
* Make sure the Scsi_Cmnd pointer is saved, the struct it points to
|
||||
* is set up properly, and the parity error flag is reset, then send
|
||||
* the SCB to the sequencer and watch the fun begin.
|
||||
*/
|
||||
/*
|
||||
* Make sure the scsi_cmnd pointer is saved, the struct it points to
|
||||
* is set up properly, and the parity error flag is reset, then send
|
||||
* the SCB to the sequencer and watch the fun begin.
|
||||
*/
|
||||
aic7xxx_position(cmd) = scb->hscb->tag;
|
||||
cmd->scsi_done = fn;
|
||||
cmd->result = DID_OK;
|
||||
|
@ -10356,8 +10352,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
|
|||
* aborted, then we will reset the channel and have all devices renegotiate.
|
||||
* Returns an enumerated type that indicates the status of the operation.
|
||||
*-F*************************************************************************/
|
||||
static int
|
||||
__aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
|
||||
static int __aic7xxx_bus_device_reset(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct aic7xxx_host *p;
|
||||
struct aic7xxx_scb *scb;
|
||||
|
@ -10550,8 +10545,7 @@ __aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
|
||||
static int aic7xxx_bus_device_reset(struct scsi_cmnd *cmd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -10570,8 +10564,7 @@ aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
|
|||
* Description:
|
||||
* Abort the current SCSI command(s).
|
||||
*-F*************************************************************************/
|
||||
static void
|
||||
aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
|
||||
static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd)
|
||||
{
|
||||
|
||||
printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
|
||||
|
@ -10595,8 +10588,7 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
|
|||
* Description:
|
||||
* Abort the current SCSI command(s).
|
||||
*-F*************************************************************************/
|
||||
static int
|
||||
__aic7xxx_abort(Scsi_Cmnd *cmd)
|
||||
static int __aic7xxx_abort(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct aic7xxx_scb *scb = NULL;
|
||||
struct aic7xxx_host *p;
|
||||
|
@ -10813,8 +10805,7 @@ success:
|
|||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
aic7xxx_abort(Scsi_Cmnd *cmd)
|
||||
static int aic7xxx_abort(struct scsi_cmnd *cmd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -10836,8 +10827,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
|
|||
* DEVICE RESET message - on the offending target before pulling
|
||||
* the SCSI bus reset line.
|
||||
*-F*************************************************************************/
|
||||
static int
|
||||
aic7xxx_reset(Scsi_Cmnd *cmd)
|
||||
static int aic7xxx_reset(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct aic7xxx_scb *scb;
|
||||
struct aic7xxx_host *p;
|
||||
|
|
|
@ -28,6 +28,7 @@ config SCSI_AIC94XX
|
|||
tristate "Adaptec AIC94xx SAS/SATA support"
|
||||
depends on PCI
|
||||
select SCSI_SAS_LIBSAS
|
||||
select FW_LOADER
|
||||
help
|
||||
This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
|
||||
AIC94xx chip based host adapters.
|
||||
|
|
|
@ -309,11 +309,29 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
|
||||
|
||||
static void asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
|
||||
static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
|
||||
{
|
||||
device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
|
||||
device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
|
||||
device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
|
||||
int err;
|
||||
|
||||
err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
|
||||
if (err)
|
||||
goto err_rev;
|
||||
|
||||
err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
|
||||
if (err)
|
||||
goto err_biosb;
|
||||
|
||||
return 0;
|
||||
|
||||
err_biosb:
|
||||
device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
|
||||
err_rev:
|
||||
device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
|
||||
|
@ -645,7 +663,9 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
|
|||
}
|
||||
ASD_DPRINTK("escbs posted\n");
|
||||
|
||||
asd_create_dev_attrs(asd_ha);
|
||||
err = asd_create_dev_attrs(asd_ha);
|
||||
if (err)
|
||||
goto Err_dev_attrs;
|
||||
|
||||
err = asd_register_sas_ha(asd_ha);
|
||||
if (err)
|
||||
|
@ -668,6 +688,7 @@ Err_en_phys:
|
|||
asd_unregister_sas_ha(asd_ha);
|
||||
Err_reg_sas:
|
||||
asd_remove_dev_attrs(asd_ha);
|
||||
Err_dev_attrs:
|
||||
Err_escbs:
|
||||
asd_disable_ints(asd_ha);
|
||||
free_irq(dev->irq, asd_ha);
|
||||
|
@ -754,9 +775,9 @@ static ssize_t asd_version_show(struct device_driver *driver, char *buf)
|
|||
}
|
||||
static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);
|
||||
|
||||
static void asd_create_driver_attrs(struct device_driver *driver)
|
||||
static int asd_create_driver_attrs(struct device_driver *driver)
|
||||
{
|
||||
driver_create_file(driver, &driver_attr_version);
|
||||
return driver_create_file(driver, &driver_attr_version);
|
||||
}
|
||||
|
||||
static void asd_remove_driver_attrs(struct device_driver *driver)
|
||||
|
@ -834,10 +855,14 @@ static int __init aic94xx_init(void)
|
|||
if (err)
|
||||
goto out_release_transport;
|
||||
|
||||
asd_create_driver_attrs(&aic94xx_pci_driver.driver);
|
||||
err = asd_create_driver_attrs(&aic94xx_pci_driver.driver);
|
||||
if (err)
|
||||
goto out_unregister_pcidrv;
|
||||
|
||||
return err;
|
||||
|
||||
out_unregister_pcidrv:
|
||||
pci_unregister_driver(&aic94xx_pci_driver);
|
||||
out_release_transport:
|
||||
sas_release_transport(aic94xx_transport_template);
|
||||
out_destroy_caches:
|
||||
|
|
|
@ -194,7 +194,8 @@
|
|||
unsigned int sdtr_period = SDTR_PERIOD;
|
||||
unsigned int sdtr_size = SDTR_SIZE;
|
||||
|
||||
static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
|
||||
static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
|
||||
unsigned int result);
|
||||
static int acornscsi_reconnect_finish(AS_Host *host);
|
||||
static void acornscsi_dma_cleanup(AS_Host *host);
|
||||
static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
|
||||
|
@ -712,7 +713,7 @@ static
|
|||
intr_ret_t acornscsi_kick(AS_Host *host)
|
||||
{
|
||||
int from_queue = 0;
|
||||
Scsi_Cmnd *SCpnt;
|
||||
struct scsi_cmnd *SCpnt;
|
||||
|
||||
/* first check to see if a command is waiting to be executed */
|
||||
SCpnt = host->origSCpnt;
|
||||
|
@ -796,15 +797,15 @@ intr_ret_t acornscsi_kick(AS_Host *host)
|
|||
}
|
||||
|
||||
/*
|
||||
* Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
|
||||
* Function: void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, unsigned int result)
|
||||
* Purpose : complete processing for command
|
||||
* Params : host - interface that completed
|
||||
* result - driver byte of result
|
||||
*/
|
||||
static
|
||||
void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
|
||||
static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
|
||||
unsigned int result)
|
||||
{
|
||||
Scsi_Cmnd *SCpnt = *SCpntp;
|
||||
struct scsi_cmnd *SCpnt = *SCpntp;
|
||||
|
||||
/* clean up */
|
||||
sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);
|
||||
|
@ -1318,7 +1319,7 @@ acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int
|
|||
static void
|
||||
acornscsi_sendcommand(AS_Host *host)
|
||||
{
|
||||
Scsi_Cmnd *SCpnt = host->SCpnt;
|
||||
struct scsi_cmnd *SCpnt = host->SCpnt;
|
||||
|
||||
sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0);
|
||||
sbic_arm_writenext(host->scsi.io_port, 0);
|
||||
|
@ -1693,7 +1694,7 @@ void acornscsi_message(AS_Host *host)
|
|||
acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
|
||||
msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
|
||||
} else {
|
||||
Scsi_Cmnd *SCpnt = host->SCpnt;
|
||||
struct scsi_cmnd *SCpnt = host->SCpnt;
|
||||
|
||||
acornscsi_dma_cleanup(host);
|
||||
|
||||
|
@ -2509,13 +2510,14 @@ acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
|
|||
*/
|
||||
|
||||
/*
|
||||
* Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
|
||||
* Function : acornscsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
||||
* Purpose : queues a SCSI command
|
||||
* Params : cmd - SCSI command
|
||||
* done - function called on completion, with pointer to command descriptor
|
||||
* Returns : 0, or < 0 on error.
|
||||
*/
|
||||
int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
|
||||
int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
|
||||
void (*done)(struct scsi_cmnd *))
|
||||
{
|
||||
AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
|
||||
|
||||
|
@ -2565,17 +2567,18 @@ int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
|
|||
}
|
||||
|
||||
/*
|
||||
* Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
|
||||
* Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result)
|
||||
* Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
|
||||
* Params : SCpntp1 - pointer to command to return
|
||||
* SCpntp2 - pointer to command to check
|
||||
* result - result to pass back to mid-level done function
|
||||
* Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
|
||||
*/
|
||||
static inline
|
||||
void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
|
||||
static inline void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1,
|
||||
struct scsi_cmnd **SCpntp2,
|
||||
int result)
|
||||
{
|
||||
Scsi_Cmnd *SCpnt = *SCpntp1;
|
||||
struct scsi_cmnd *SCpnt = *SCpntp1;
|
||||
|
||||
if (SCpnt) {
|
||||
*SCpntp1 = NULL;
|
||||
|
@ -2591,13 +2594,12 @@ void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result
|
|||
enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
|
||||
|
||||
/*
|
||||
* Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
|
||||
* Prototype: enum res acornscsi_do_abort(struct scsi_cmnd *SCpnt)
|
||||
* Purpose : abort a command on this host
|
||||
* Params : SCpnt - command to abort
|
||||
* Returns : our abort status
|
||||
*/
|
||||
static enum res_abort
|
||||
acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
|
||||
static enum res_abort acornscsi_do_abort(AS_Host *host, struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
enum res_abort res = res_not_running;
|
||||
|
||||
|
@ -2684,12 +2686,12 @@ acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
|
|||
}
|
||||
|
||||
/*
|
||||
* Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
|
||||
* Prototype: int acornscsi_abort(struct scsi_cmnd *SCpnt)
|
||||
* Purpose : abort a command on this host
|
||||
* Params : SCpnt - command to abort
|
||||
* Returns : one of SCSI_ABORT_ macros
|
||||
*/
|
||||
int acornscsi_abort(Scsi_Cmnd *SCpnt)
|
||||
int acornscsi_abort(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata;
|
||||
int result;
|
||||
|
@ -2770,16 +2772,16 @@ int acornscsi_abort(Scsi_Cmnd *SCpnt)
|
|||
}
|
||||
|
||||
/*
|
||||
* Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
|
||||
* Prototype: int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags)
|
||||
* Purpose : reset a command on this host/reset this host
|
||||
* Params : SCpnt - command causing reset
|
||||
* result - what type of reset to perform
|
||||
* Returns : one of SCSI_RESET_ macros
|
||||
*/
|
||||
int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
|
||||
int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags)
|
||||
{
|
||||
AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
|
||||
Scsi_Cmnd *SCptr;
|
||||
AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
|
||||
struct scsi_cmnd *SCptr;
|
||||
|
||||
host->stats.resets += 1;
|
||||
|
||||
|
|
|
@ -277,8 +277,8 @@ struct status_entry {
|
|||
typedef struct acornscsi_hostdata {
|
||||
/* miscellaneous */
|
||||
struct Scsi_Host *host; /* host */
|
||||
Scsi_Cmnd *SCpnt; /* currently processing command */
|
||||
Scsi_Cmnd *origSCpnt; /* original connecting command */
|
||||
struct scsi_cmnd *SCpnt; /* currently processing command */
|
||||
struct scsi_cmnd *origSCpnt; /* original connecting command */
|
||||
|
||||
/* driver information */
|
||||
struct {
|
||||
|
|
|
@ -297,8 +297,8 @@ fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap)
|
|||
printk("scsi%d.%c: %s", info->host->host_no, target, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...)
|
||||
static void fas216_log_command(FAS216_Info *info, int level,
|
||||
struct scsi_cmnd *SCpnt, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
|
@ -1662,7 +1662,7 @@ irqreturn_t fas216_intr(FAS216_Info *info)
|
|||
return handled;
|
||||
}
|
||||
|
||||
static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
||||
static void __fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
int tot_msglen;
|
||||
|
||||
|
@ -1754,7 +1754,7 @@ static int parity_test(FAS216_Info *info, int target)
|
|||
return info->device[target].parity_check;
|
||||
}
|
||||
|
||||
static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
||||
static void fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
int disconnect_ok;
|
||||
|
||||
|
@ -1808,7 +1808,7 @@ static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
|||
__fas216_start_command(info, SCpnt);
|
||||
}
|
||||
|
||||
static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
||||
static void fas216_allocate_tag(FAS216_Info *info, struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
#ifdef SCSI2_TAG
|
||||
/*
|
||||
|
@ -1842,7 +1842,8 @@ static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
|||
}
|
||||
}
|
||||
|
||||
static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
||||
static void fas216_do_bus_device_reset(FAS216_Info *info,
|
||||
struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
struct message *msg;
|
||||
|
||||
|
@ -1890,7 +1891,7 @@ static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
|||
*/
|
||||
static void fas216_kick(FAS216_Info *info)
|
||||
{
|
||||
Scsi_Cmnd *SCpnt = NULL;
|
||||
struct scsi_cmnd *SCpnt = NULL;
|
||||
#define TYPE_OTHER 0
|
||||
#define TYPE_RESET 1
|
||||
#define TYPE_QUEUE 2
|
||||
|
@ -1978,8 +1979,8 @@ static void fas216_kick(FAS216_Info *info)
|
|||
/*
|
||||
* Clean up from issuing a BUS DEVICE RESET message to a device.
|
||||
*/
|
||||
static void
|
||||
fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
|
||||
static void fas216_devicereset_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
|
||||
unsigned int result)
|
||||
{
|
||||
fas216_log(info, LOG_ERROR, "fas216 device reset complete");
|
||||
|
||||
|
@ -1996,8 +1997,8 @@ fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result
|
|||
*
|
||||
* Finish processing automatic request sense command
|
||||
*/
|
||||
static void
|
||||
fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
|
||||
static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
|
||||
unsigned int result)
|
||||
{
|
||||
fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
|
||||
"request sense complete, result=0x%04x%02x%02x",
|
||||
|
@ -2030,7 +2031,7 @@ fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
|
|||
* Finish processing of standard command
|
||||
*/
|
||||
static void
|
||||
fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
|
||||
fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result)
|
||||
{
|
||||
info->stats.fins += 1;
|
||||
|
||||
|
@ -2142,8 +2143,8 @@ request_sense:
|
|||
*/
|
||||
static void fas216_done(FAS216_Info *info, unsigned int result)
|
||||
{
|
||||
void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
|
||||
Scsi_Cmnd *SCpnt;
|
||||
void (*fn)(FAS216_Info *, struct scsi_cmnd *, unsigned int);
|
||||
struct scsi_cmnd *SCpnt;
|
||||
unsigned long flags;
|
||||
|
||||
fas216_checkmagic(info);
|
||||
|
@ -2182,7 +2183,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
|
|||
info->device[SCpnt->device->id].parity_check = 0;
|
||||
clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
|
||||
|
||||
fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
|
||||
fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble;
|
||||
fn(info, SCpnt, result);
|
||||
|
||||
if (info->scsi.irq != NO_IRQ) {
|
||||
|
@ -2207,7 +2208,8 @@ no_command:
|
|||
* Returns: 0 on success, else error.
|
||||
* Notes: io_request_lock is held, interrupts are disabled.
|
||||
*/
|
||||
int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
|
||||
int fas216_queue_command(struct scsi_cmnd *SCpnt,
|
||||
void (*done)(struct scsi_cmnd *))
|
||||
{
|
||||
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
|
||||
int result;
|
||||
|
@ -2254,7 +2256,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
|
|||
*
|
||||
* Trigger restart of a waiting thread in fas216_command
|
||||
*/
|
||||
static void fas216_internal_done(Scsi_Cmnd *SCpnt)
|
||||
static void fas216_internal_done(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
|
||||
|
||||
|
@ -2271,7 +2273,8 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt)
|
|||
* Returns: scsi result code.
|
||||
* Notes: io_request_lock is held, interrupts are disabled.
|
||||
*/
|
||||
int fas216_noqueue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
|
||||
int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
|
||||
void (*done)(struct scsi_cmnd *))
|
||||
{
|
||||
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
|
||||
|
||||
|
@ -2350,7 +2353,8 @@ enum res_find {
|
|||
* Decide how to abort a command.
|
||||
* Returns: abort status
|
||||
*/
|
||||
static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
||||
static enum res_find fas216_find_command(FAS216_Info *info,
|
||||
struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
enum res_find res = res_failed;
|
||||
|
||||
|
@ -2417,7 +2421,7 @@ static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
|
|||
* Returns: FAILED if unable to abort
|
||||
* Notes: io_request_lock is taken, and irqs are disabled
|
||||
*/
|
||||
int fas216_eh_abort(Scsi_Cmnd *SCpnt)
|
||||
int fas216_eh_abort(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
|
||||
int result = FAILED;
|
||||
|
@ -2474,7 +2478,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt)
|
|||
* Notes: We won't be re-entered, so we'll only have one device
|
||||
* reset on the go at one time.
|
||||
*/
|
||||
int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
|
||||
int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
|
||||
unsigned long flags;
|
||||
|
@ -2555,7 +2559,7 @@ int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
|
|||
* Returns: FAILED if unable to reset.
|
||||
* Notes: Further commands are blocked.
|
||||
*/
|
||||
int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
|
||||
int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
|
||||
unsigned long flags;
|
||||
|
@ -2655,7 +2659,7 @@ static void fas216_init_chip(FAS216_Info *info)
|
|||
* Returns: FAILED if unable to reset.
|
||||
* Notes: io_request_lock is taken, and irqs are disabled
|
||||
*/
|
||||
int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
|
||||
int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
|
||||
|
||||
|
|
|
@ -218,11 +218,11 @@ typedef struct {
|
|||
unsigned long magic_start;
|
||||
spinlock_t host_lock;
|
||||
struct Scsi_Host *host; /* host */
|
||||
Scsi_Cmnd *SCpnt; /* currently processing command */
|
||||
Scsi_Cmnd *origSCpnt; /* original connecting command */
|
||||
Scsi_Cmnd *reqSCpnt; /* request sense command */
|
||||
Scsi_Cmnd *rstSCpnt; /* reset command */
|
||||
Scsi_Cmnd *pending_SCpnt[8]; /* per-device pending commands */
|
||||
struct scsi_cmnd *SCpnt; /* currently processing command */
|
||||
struct scsi_cmnd *origSCpnt; /* original connecting command */
|
||||
struct scsi_cmnd *reqSCpnt; /* request sense command */
|
||||
struct scsi_cmnd *rstSCpnt; /* reset command */
|
||||
struct scsi_cmnd *pending_SCpnt[8]; /* per-device pending commands */
|
||||
int next_pending; /* next pending device */
|
||||
|
||||
/*
|
||||
|
@ -328,21 +328,23 @@ extern int fas216_init (struct Scsi_Host *instance);
|
|||
*/
|
||||
extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
|
||||
|
||||
/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
|
||||
/* Function: int fas216_queue_command(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||
* Purpose : queue a command for adapter to process.
|
||||
* Params : SCpnt - Command to queue
|
||||
* done - done function to call once command is complete
|
||||
* Returns : 0 - success, else error
|
||||
*/
|
||||
extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
|
||||
extern int fas216_queue_command(struct scsi_cmnd *,
|
||||
void (*done)(struct scsi_cmnd *));
|
||||
|
||||
/* Function: int fas216_noqueue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
|
||||
/* Function: int fas216_noqueue_command(istruct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||
* Purpose : queue a command for adapter to process, and process it to completion.
|
||||
* Params : SCpnt - Command to queue
|
||||
* done - done function to call once command is complete
|
||||
* Returns : 0 - success, else error
|
||||
*/
|
||||
extern int fas216_noqueue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
|
||||
extern int fas216_noqueue_command(struct scsi_cmnd *,
|
||||
void (*done)(struct scsi_cmnd *));
|
||||
|
||||
/* Function: irqreturn_t fas216_intr (FAS216_Info *info)
|
||||
* Purpose : handle interrupts from the interface to progress a command
|
||||
|
@ -363,32 +365,32 @@ extern int fas216_print_host(FAS216_Info *info, char *buffer);
|
|||
extern int fas216_print_stats(FAS216_Info *info, char *buffer);
|
||||
extern int fas216_print_devices(FAS216_Info *info, char *buffer);
|
||||
|
||||
/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
|
||||
/* Function: int fas216_eh_abort(struct scsi_cmnd *SCpnt)
|
||||
* Purpose : abort this command
|
||||
* Params : SCpnt - command to abort
|
||||
* Returns : FAILED if unable to abort
|
||||
*/
|
||||
extern int fas216_eh_abort(Scsi_Cmnd *SCpnt);
|
||||
extern int fas216_eh_abort(struct scsi_cmnd *SCpnt);
|
||||
|
||||
/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
|
||||
/* Function: int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
|
||||
* Purpose : Reset the device associated with this command
|
||||
* Params : SCpnt - command specifing device to reset
|
||||
* Returns : FAILED if unable to reset
|
||||
*/
|
||||
extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt);
|
||||
extern int fas216_eh_device_reset(struct scsi_cmnd *SCpnt);
|
||||
|
||||
/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
|
||||
/* Function: int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt)
|
||||
* Purpose : Reset the complete bus associated with this command
|
||||
* Params : SCpnt - command specifing bus to reset
|
||||
* Returns : FAILED if unable to reset
|
||||
*/
|
||||
extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt);
|
||||
extern int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt);
|
||||
|
||||
/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
|
||||
/* Function: int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
|
||||
* Purpose : Reset the host associated with this command
|
||||
* Params : SCpnt - command specifing host to reset
|
||||
* Returns : FAILED if unable to reset
|
||||
*/
|
||||
extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt);
|
||||
extern int fas216_eh_host_reset(struct scsi_cmnd *SCpnt);
|
||||
|
||||
#endif /* FAS216_H */
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
typedef struct queue_entry {
|
||||
struct list_head list;
|
||||
Scsi_Cmnd *SCpnt;
|
||||
struct scsi_cmnd *SCpnt;
|
||||
#ifdef DEBUG
|
||||
unsigned long magic;
|
||||
#endif
|
||||
|
@ -96,14 +96,14 @@ void queue_free (Queue_t *queue)
|
|||
|
||||
|
||||
/*
|
||||
* Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
|
||||
* Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
|
||||
* Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head.
|
||||
* Params : queue - destination queue
|
||||
* SCpnt - command to add
|
||||
* head - add command to head of queue
|
||||
* Returns : 0 on error, !0 on success
|
||||
*/
|
||||
int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
|
||||
int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct list_head *l;
|
||||
|
@ -134,7 +134,7 @@ empty:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
|
||||
static struct scsi_cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
|
||||
{
|
||||
QE_t *q;
|
||||
|
||||
|
@ -152,17 +152,17 @@ static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
|
|||
}
|
||||
|
||||
/*
|
||||
* Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude)
|
||||
* Function: struct scsi_cmnd *queue_remove_exclude (queue, exclude)
|
||||
* Purpose : remove a SCSI command from a queue
|
||||
* Params : queue - queue to remove command from
|
||||
* exclude - bit array of target&lun which is busy
|
||||
* Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
|
||||
* Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
|
||||
*/
|
||||
Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
|
||||
struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct list_head *l;
|
||||
Scsi_Cmnd *SCpnt = NULL;
|
||||
struct scsi_cmnd *SCpnt = NULL;
|
||||
|
||||
spin_lock_irqsave(&queue->queue_lock, flags);
|
||||
list_for_each(l, &queue->head) {
|
||||
|
@ -178,15 +178,15 @@ Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
|
|||
}
|
||||
|
||||
/*
|
||||
* Function: Scsi_Cmnd *queue_remove (queue)
|
||||
* Function: struct scsi_cmnd *queue_remove (queue)
|
||||
* Purpose : removes first SCSI command from a queue
|
||||
* Params : queue - queue to remove command from
|
||||
* Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
|
||||
* Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
|
||||
*/
|
||||
Scsi_Cmnd *queue_remove(Queue_t *queue)
|
||||
struct scsi_cmnd *queue_remove(Queue_t *queue)
|
||||
{
|
||||
unsigned long flags;
|
||||
Scsi_Cmnd *SCpnt = NULL;
|
||||
struct scsi_cmnd *SCpnt = NULL;
|
||||
|
||||
spin_lock_irqsave(&queue->queue_lock, flags);
|
||||
if (!list_empty(&queue->head))
|
||||
|
@ -197,19 +197,20 @@ Scsi_Cmnd *queue_remove(Queue_t *queue)
|
|||
}
|
||||
|
||||
/*
|
||||
* Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
|
||||
* Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
|
||||
* Purpose : remove a SCSI command from the queue for a specified target/lun/tag
|
||||
* Params : queue - queue to remove command from
|
||||
* target - target that we want
|
||||
* lun - lun on device
|
||||
* tag - tag on device
|
||||
* Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
|
||||
* Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements
|
||||
*/
|
||||
Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag)
|
||||
struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, int lun,
|
||||
int tag)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct list_head *l;
|
||||
Scsi_Cmnd *SCpnt = NULL;
|
||||
struct scsi_cmnd *SCpnt = NULL;
|
||||
|
||||
spin_lock_irqsave(&queue->queue_lock, flags);
|
||||
list_for_each(l, &queue->head) {
|
||||
|
@ -275,13 +276,13 @@ int queue_probetgtlun (Queue_t *queue, int target, int lun)
|
|||
}
|
||||
|
||||
/*
|
||||
* Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
|
||||
* Function: int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
|
||||
* Purpose : remove a specific command from the queues
|
||||
* Params : queue - queue to look in
|
||||
* SCpnt - command to find
|
||||
* Returns : 0 if not found
|
||||
*/
|
||||
int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
|
||||
int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct list_head *l;
|
||||
|
|
|
@ -32,46 +32,48 @@ extern int queue_initialise (Queue_t *queue);
|
|||
extern void queue_free (Queue_t *queue);
|
||||
|
||||
/*
|
||||
* Function: Scsi_Cmnd *queue_remove (queue)
|
||||
* Function: struct scsi_cmnd *queue_remove (queue)
|
||||
* Purpose : removes first SCSI command from a queue
|
||||
* Params : queue - queue to remove command from
|
||||
* Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
|
||||
* Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
|
||||
*/
|
||||
extern Scsi_Cmnd *queue_remove (Queue_t *queue);
|
||||
extern struct scsi_cmnd *queue_remove (Queue_t *queue);
|
||||
|
||||
/*
|
||||
* Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude)
|
||||
* Function: struct scsi_cmnd *queue_remove_exclude_ref (queue, exclude)
|
||||
* Purpose : remove a SCSI command from a queue
|
||||
* Params : queue - queue to remove command from
|
||||
* exclude - array of busy LUNs
|
||||
* Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
|
||||
* Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
|
||||
*/
|
||||
extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude);
|
||||
extern struct scsi_cmnd *queue_remove_exclude(Queue_t *queue,
|
||||
unsigned long *exclude);
|
||||
|
||||
#define queue_add_cmd_ordered(queue,SCpnt) \
|
||||
__queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE)
|
||||
#define queue_add_cmd_tail(queue,SCpnt) \
|
||||
__queue_add(queue,SCpnt,0)
|
||||
/*
|
||||
* Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
|
||||
* Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
|
||||
* Purpose : Add a new command onto a queue
|
||||
* Params : queue - destination queue
|
||||
* SCpnt - command to add
|
||||
* head - add command to head of queue
|
||||
* Returns : 0 on error, !0 on success
|
||||
*/
|
||||
extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head);
|
||||
extern int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head);
|
||||
|
||||
/*
|
||||
* Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
|
||||
* Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
|
||||
* Purpose : remove a SCSI command from the queue for a specified target/lun/tag
|
||||
* Params : queue - queue to remove command from
|
||||
* target - target that we want
|
||||
* lun - lun on device
|
||||
* tag - tag on device
|
||||
* Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
|
||||
* Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements
|
||||
*/
|
||||
extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag);
|
||||
extern struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target,
|
||||
int lun, int tag);
|
||||
|
||||
/*
|
||||
* Function: queue_remove_all_target(queue, target)
|
||||
|
@ -94,12 +96,12 @@ extern void queue_remove_all_target(Queue_t *queue, int target);
|
|||
extern int queue_probetgtlun (Queue_t *queue, int target, int lun);
|
||||
|
||||
/*
|
||||
* Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt)
|
||||
* Function: int queue_remove_cmd (Queue_t *queue, struct scsi_cmnd *SCpnt)
|
||||
* Purpose : remove a specific command from the queues
|
||||
* Params : queue - queue to look in
|
||||
* SCpnt - command to find
|
||||
* Returns : 0 if not found
|
||||
*/
|
||||
int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt);
|
||||
int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt);
|
||||
|
||||
#endif /* QUEUE_H */
|
||||
|
|
|
@ -66,7 +66,7 @@ static inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c)
|
|||
SCp->this_residual -= 1;
|
||||
}
|
||||
|
||||
static inline void init_SCp(Scsi_Cmnd *SCpnt)
|
||||
static inline void init_SCp(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
|
||||
|
||||
|
|
|
@ -1219,7 +1219,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb,
|
|||
srb, srb->cmd, srb->cmd->pid,
|
||||
srb->cmd->cmnd[0], srb->cmd->device->id,
|
||||
srb->cmd->device->lun);
|
||||
printk(" sglist=%p cnt=%i idx=%i len=%i\n",
|
||||
printk(" sglist=%p cnt=%i idx=%i len=%Zd\n",
|
||||
srb->segment_x, srb->sg_count, srb->sg_index,
|
||||
srb->total_xfer_length);
|
||||
printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
|
||||
|
@ -4949,7 +4949,7 @@ static struct pci_driver dc395x_driver = {
|
|||
**/
|
||||
static int __init dc395x_module_init(void)
|
||||
{
|
||||
return pci_module_init(&dc395x_driver);
|
||||
return pci_register_driver(&dc395x_driver);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ static struct pci_driver dmx3191d_pci_driver = {
|
|||
|
||||
static int __init dmx3191d_init(void)
|
||||
{
|
||||
return pci_module_init(&dmx3191d_pci_driver);
|
||||
return pci_register_driver(&dmx3191d_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit dmx3191d_exit(void)
|
||||
|
|
|
@ -47,21 +47,11 @@
|
|||
* I2O Interface Objects
|
||||
*/
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
|
||||
|
||||
#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
|
||||
|
||||
typedef struct wait_queue *adpt_wait_queue_head_t;
|
||||
#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) adpt_wait_queue_head_t wait = NULL
|
||||
typedef struct wait_queue adpt_wait_queue_t;
|
||||
#else
|
||||
|
||||
#include <linux/wait.h>
|
||||
typedef wait_queue_head_t adpt_wait_queue_head_t;
|
||||
#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait)
|
||||
typedef wait_queue_t adpt_wait_queue_t;
|
||||
|
||||
#endif
|
||||
/*
|
||||
* message structures
|
||||
*/
|
||||
|
|
|
@ -2212,7 +2212,7 @@ static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
|
|||
*/
|
||||
host->io_port = 0;
|
||||
host->n_io_port = 0;
|
||||
/* see comments in hosts.h */
|
||||
/* see comments in scsi_host.h */
|
||||
host->max_id = 16;
|
||||
host->max_lun = 256;
|
||||
host->max_channel = pHba->top_scsi_channel + 1;
|
||||
|
|
|
@ -44,7 +44,7 @@ static int adpt_device_reset(struct scsi_cmnd* cmd);
|
|||
|
||||
|
||||
/*
|
||||
* struct scsi_host_template (see hosts.h)
|
||||
* struct scsi_host_template (see scsi/scsi_host.h)
|
||||
*/
|
||||
|
||||
#define DPT_DRIVER_NAME "Adaptec I2O RAID"
|
||||
|
|
|
@ -936,18 +936,12 @@ typedef struct {
|
|||
gdth_binfo_str binfo; /* controller info */
|
||||
gdth_evt_data dvr; /* event structure */
|
||||
spinlock_t smp_lock;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
struct pci_dev *pdev;
|
||||
#endif
|
||||
char oem_name[8];
|
||||
#ifdef GDTH_DMA_STATISTICS
|
||||
ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
struct scsi_device *sdev;
|
||||
#else
|
||||
struct scsi_device sdev;
|
||||
#endif
|
||||
} gdth_ha_str;
|
||||
|
||||
/* structure for scsi_register(), SCSI bus != 0 */
|
||||
|
@ -1029,10 +1023,6 @@ typedef struct {
|
|||
|
||||
/* function prototyping */
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
|
||||
#else
|
||||
int gdth_proc_info(char *,char **,off_t,int,int,int);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
#warning "This file is obsolete, please use <scsi/scsi_host.h> instead"
|
||||
#include <scsi/scsi_host.h>
|
|
@ -70,6 +70,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/libata.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/processor.h>
|
||||
|
@ -78,6 +79,7 @@
|
|||
#include <scsi/scsi_tcq.h>
|
||||
#include <scsi/scsi_eh.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_transport.h>
|
||||
#include "ipr.h"
|
||||
|
||||
/*
|
||||
|
@ -199,6 +201,8 @@ struct ipr_error_table_t ipr_error_table[] = {
|
|||
"FFFA: Undefined device response recovered by the IOA"},
|
||||
{0x014A0000, 1, 1,
|
||||
"FFF6: Device bus error, message or command phase"},
|
||||
{0x014A8000, 0, 1,
|
||||
"FFFE: Task Management Function failed"},
|
||||
{0x015D0000, 0, 1,
|
||||
"FFF6: Failure prediction threshold exceeded"},
|
||||
{0x015D9200, 0, 1,
|
||||
|
@ -261,6 +265,8 @@ struct ipr_error_table_t ipr_error_table[] = {
|
|||
"Device bus status error"},
|
||||
{0x04448600, 0, 1,
|
||||
"8157: IOA error requiring IOA reset to recover"},
|
||||
{0x04448700, 0, 0,
|
||||
"ATA device status error"},
|
||||
{0x04490000, 0, 0,
|
||||
"Message reject received from the device"},
|
||||
{0x04449200, 0, 1,
|
||||
|
@ -273,6 +279,8 @@ struct ipr_error_table_t ipr_error_table[] = {
|
|||
"9082: IOA detected device error"},
|
||||
{0x044A0000, 1, 1,
|
||||
"3110: Device bus error, message or command phase"},
|
||||
{0x044A8000, 1, 1,
|
||||
"3110: SAS Command / Task Management Function failed"},
|
||||
{0x04670400, 0, 1,
|
||||
"9091: Incorrect hardware configuration change has been detected"},
|
||||
{0x04678000, 0, 1,
|
||||
|
@ -453,7 +461,8 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
|
|||
trace_entry->time = jiffies;
|
||||
trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
|
||||
trace_entry->type = type;
|
||||
trace_entry->cmd_index = ipr_cmd->cmd_index;
|
||||
trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command;
|
||||
trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff;
|
||||
trace_entry->res_handle = ipr_cmd->ioarcb.res_handle;
|
||||
trace_entry->u.add_data = add_data;
|
||||
}
|
||||
|
@ -480,8 +489,10 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
|
|||
ioarcb->read_ioadl_len = 0;
|
||||
ioasa->ioasc = 0;
|
||||
ioasa->residual_data_len = 0;
|
||||
ioasa->u.gata.status = 0;
|
||||
|
||||
ipr_cmd->scsi_cmd = NULL;
|
||||
ipr_cmd->qc = NULL;
|
||||
ipr_cmd->sense_buffer[0] = 0;
|
||||
ipr_cmd->dma_use_sg = 0;
|
||||
}
|
||||
|
@ -625,6 +636,28 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_sata_eh_done - done function for aborted SATA commands
|
||||
* @ipr_cmd: ipr command struct
|
||||
*
|
||||
* This function is invoked for ops generated to SATA
|
||||
* devices which are being aborted.
|
||||
*
|
||||
* Return value:
|
||||
* none
|
||||
**/
|
||||
static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
|
||||
{
|
||||
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
|
||||
struct ata_queued_cmd *qc = ipr_cmd->qc;
|
||||
struct ipr_sata_port *sata_port = qc->ap->private_data;
|
||||
|
||||
qc->err_mask |= AC_ERR_OTHER;
|
||||
sata_port->ioasa.status |= ATA_BUSY;
|
||||
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
|
||||
ata_qc_complete(qc);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_scsi_eh_done - mid-layer done function for aborted ops
|
||||
* @ipr_cmd: ipr command struct
|
||||
|
@ -669,6 +702,8 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg)
|
|||
|
||||
if (ipr_cmd->scsi_cmd)
|
||||
ipr_cmd->done = ipr_scsi_eh_done;
|
||||
else if (ipr_cmd->qc)
|
||||
ipr_cmd->done = ipr_sata_eh_done;
|
||||
|
||||
ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET);
|
||||
del_timer(&ipr_cmd->timer);
|
||||
|
@ -825,6 +860,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res)
|
|||
res->del_from_ml = 0;
|
||||
res->resetting_device = 0;
|
||||
res->sdev = NULL;
|
||||
res->sata_port = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1316,7 +1352,7 @@ static u32 ipr_get_error(u32 ioasc)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++)
|
||||
if (ipr_error_table[i].ioasc == ioasc)
|
||||
if (ipr_error_table[i].ioasc == (ioasc & IPR_IOASC_IOASC_MASK))
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
|
@ -3051,6 +3087,17 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; };
|
|||
**/
|
||||
static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
|
||||
{
|
||||
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
|
||||
struct ipr_resource_entry *res;
|
||||
unsigned long lock_flags = 0;
|
||||
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||
res = (struct ipr_resource_entry *)sdev->hostdata;
|
||||
|
||||
if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN)
|
||||
qdepth = IPR_MAX_CMD_PER_ATA_LUN;
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
|
||||
return sdev->queue_depth;
|
||||
}
|
||||
|
@ -3165,6 +3212,122 @@ static int ipr_biosparam(struct scsi_device *sdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_find_starget - Find target based on bus/target.
|
||||
* @starget: scsi target struct
|
||||
*
|
||||
* Return value:
|
||||
* resource entry pointer if found / NULL if not found
|
||||
**/
|
||||
static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
|
||||
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
|
||||
struct ipr_resource_entry *res;
|
||||
|
||||
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
|
||||
if ((res->cfgte.res_addr.bus == starget->channel) &&
|
||||
(res->cfgte.res_addr.target == starget->id) &&
|
||||
(res->cfgte.res_addr.lun == 0)) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ata_port_info sata_port_info;
|
||||
|
||||
/**
|
||||
* ipr_target_alloc - Prepare for commands to a SCSI target
|
||||
* @starget: scsi target struct
|
||||
*
|
||||
* If the device is a SATA device, this function allocates an
|
||||
* ATA port with libata, else it does nothing.
|
||||
*
|
||||
* Return value:
|
||||
* 0 on success / non-0 on failure
|
||||
**/
|
||||
static int ipr_target_alloc(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
|
||||
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
|
||||
struct ipr_sata_port *sata_port;
|
||||
struct ata_port *ap;
|
||||
struct ipr_resource_entry *res;
|
||||
unsigned long lock_flags;
|
||||
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||
res = ipr_find_starget(starget);
|
||||
starget->hostdata = NULL;
|
||||
|
||||
if (res && ipr_is_gata(res)) {
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||
sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL);
|
||||
if (!sata_port)
|
||||
return -ENOMEM;
|
||||
|
||||
ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost);
|
||||
if (ap) {
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||
sata_port->ioa_cfg = ioa_cfg;
|
||||
sata_port->ap = ap;
|
||||
sata_port->res = res;
|
||||
|
||||
res->sata_port = sata_port;
|
||||
ap->private_data = sata_port;
|
||||
starget->hostdata = sata_port;
|
||||
} else {
|
||||
kfree(sata_port);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_target_destroy - Destroy a SCSI target
|
||||
* @starget: scsi target struct
|
||||
*
|
||||
* If the device was a SATA device, this function frees the libata
|
||||
* ATA port, else it does nothing.
|
||||
*
|
||||
**/
|
||||
static void ipr_target_destroy(struct scsi_target *starget)
|
||||
{
|
||||
struct ipr_sata_port *sata_port = starget->hostdata;
|
||||
|
||||
if (sata_port) {
|
||||
starget->hostdata = NULL;
|
||||
ata_sas_port_destroy(sata_port->ap);
|
||||
kfree(sata_port);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_find_sdev - Find device based on bus/target/lun.
|
||||
* @sdev: scsi device struct
|
||||
*
|
||||
* Return value:
|
||||
* resource entry pointer if found / NULL if not found
|
||||
**/
|
||||
static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev)
|
||||
{
|
||||
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
|
||||
struct ipr_resource_entry *res;
|
||||
|
||||
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
|
||||
if ((res->cfgte.res_addr.bus == sdev->channel) &&
|
||||
(res->cfgte.res_addr.target == sdev->id) &&
|
||||
(res->cfgte.res_addr.lun == sdev->lun))
|
||||
return res;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_slave_destroy - Unconfigure a SCSI device
|
||||
* @sdev: scsi device struct
|
||||
|
@ -3183,8 +3346,11 @@ static void ipr_slave_destroy(struct scsi_device *sdev)
|
|||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||
res = (struct ipr_resource_entry *) sdev->hostdata;
|
||||
if (res) {
|
||||
if (res->sata_port)
|
||||
ata_port_disable(res->sata_port->ap);
|
||||
sdev->hostdata = NULL;
|
||||
res->sdev = NULL;
|
||||
res->sata_port = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||
}
|
||||
|
@ -3219,12 +3385,44 @@ static int ipr_slave_configure(struct scsi_device *sdev)
|
|||
}
|
||||
if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
|
||||
sdev->allow_restart = 1;
|
||||
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
|
||||
if (ipr_is_gata(res) && res->sata_port) {
|
||||
scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN);
|
||||
ata_sas_slave_configure(sdev, res->sata_port->ap);
|
||||
} else {
|
||||
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_ata_slave_alloc - Prepare for commands to a SATA device
|
||||
* @sdev: scsi device struct
|
||||
*
|
||||
* This function initializes an ATA port so that future commands
|
||||
* sent through queuecommand will work.
|
||||
*
|
||||
* Return value:
|
||||
* 0 on success
|
||||
**/
|
||||
static int ipr_ata_slave_alloc(struct scsi_device *sdev)
|
||||
{
|
||||
struct ipr_sata_port *sata_port = NULL;
|
||||
int rc = -ENXIO;
|
||||
|
||||
ENTER;
|
||||
if (sdev->sdev_target)
|
||||
sata_port = sdev->sdev_target->hostdata;
|
||||
if (sata_port)
|
||||
rc = ata_sas_port_init(sata_port->ap);
|
||||
if (rc)
|
||||
ipr_slave_destroy(sdev);
|
||||
|
||||
LEAVE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_slave_alloc - Prepare for commands to a device.
|
||||
* @sdev: scsi device struct
|
||||
|
@ -3248,18 +3446,18 @@ static int ipr_slave_alloc(struct scsi_device *sdev)
|
|||
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||
|
||||
list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
|
||||
if ((res->cfgte.res_addr.bus == sdev->channel) &&
|
||||
(res->cfgte.res_addr.target == sdev->id) &&
|
||||
(res->cfgte.res_addr.lun == sdev->lun)) {
|
||||
res->sdev = sdev;
|
||||
res->add_to_ml = 0;
|
||||
res->in_erp = 0;
|
||||
sdev->hostdata = res;
|
||||
if (!ipr_is_naca_model(res))
|
||||
res->needs_sync_complete = 1;
|
||||
rc = 0;
|
||||
break;
|
||||
res = ipr_find_sdev(sdev);
|
||||
if (res) {
|
||||
res->sdev = sdev;
|
||||
res->add_to_ml = 0;
|
||||
res->in_erp = 0;
|
||||
sdev->hostdata = res;
|
||||
if (!ipr_is_naca_model(res))
|
||||
res->needs_sync_complete = 1;
|
||||
rc = 0;
|
||||
if (ipr_is_gata(res)) {
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||
return ipr_ata_slave_alloc(sdev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3314,7 +3512,8 @@ static int ipr_eh_host_reset(struct scsi_cmnd * cmd)
|
|||
* This function issues a device reset to the affected device.
|
||||
* If the device is a SCSI device, a LUN reset will be sent
|
||||
* to the device first. If that does not work, a target reset
|
||||
* will be sent.
|
||||
* will be sent. If the device is a SATA device, a PHY reset will
|
||||
* be sent.
|
||||
*
|
||||
* Return value:
|
||||
* 0 on success / non-zero on failure
|
||||
|
@ -3325,25 +3524,78 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
|
|||
struct ipr_cmnd *ipr_cmd;
|
||||
struct ipr_ioarcb *ioarcb;
|
||||
struct ipr_cmd_pkt *cmd_pkt;
|
||||
struct ipr_ioarcb_ata_regs *regs;
|
||||
u32 ioasc;
|
||||
|
||||
ENTER;
|
||||
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
|
||||
ioarcb = &ipr_cmd->ioarcb;
|
||||
cmd_pkt = &ioarcb->cmd_pkt;
|
||||
regs = &ioarcb->add_data.u.regs;
|
||||
|
||||
ioarcb->res_handle = res->cfgte.res_handle;
|
||||
cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
|
||||
cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
|
||||
if (ipr_is_gata(res)) {
|
||||
cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET;
|
||||
ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(regs->flags));
|
||||
regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
|
||||
}
|
||||
|
||||
ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
|
||||
ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
|
||||
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
|
||||
if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET)
|
||||
memcpy(&res->sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
|
||||
sizeof(struct ipr_ioasa_gata));
|
||||
|
||||
LEAVE;
|
||||
return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_sata_reset - Reset the SATA port
|
||||
* @ap: SATA port to reset
|
||||
* @classes: class of the attached device
|
||||
*
|
||||
* This function issues a SATA phy reset to the affected ATA port.
|
||||
*
|
||||
* Return value:
|
||||
* 0 on success / non-zero on failure
|
||||
**/
|
||||
static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
|
||||
{
|
||||
struct ipr_sata_port *sata_port = ap->private_data;
|
||||
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
|
||||
struct ipr_resource_entry *res;
|
||||
unsigned long lock_flags = 0;
|
||||
int rc = -ENXIO;
|
||||
|
||||
ENTER;
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||
res = sata_port->res;
|
||||
if (res) {
|
||||
rc = ipr_device_reset(ioa_cfg, res);
|
||||
switch(res->cfgte.proto) {
|
||||
case IPR_PROTO_SATA:
|
||||
case IPR_PROTO_SAS_STP:
|
||||
*classes = ATA_DEV_ATA;
|
||||
break;
|
||||
case IPR_PROTO_SATA_ATAPI:
|
||||
case IPR_PROTO_SAS_STP_ATAPI:
|
||||
*classes = ATA_DEV_ATAPI;
|
||||
break;
|
||||
default:
|
||||
*classes = ATA_DEV_UNKNOWN;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||
LEAVE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_eh_dev_reset - Reset the device
|
||||
* @scsi_cmd: scsi command struct
|
||||
|
@ -3360,7 +3612,8 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
|
|||
struct ipr_cmnd *ipr_cmd;
|
||||
struct ipr_ioa_cfg *ioa_cfg;
|
||||
struct ipr_resource_entry *res;
|
||||
int rc;
|
||||
struct ata_port *ap;
|
||||
int rc = 0;
|
||||
|
||||
ENTER;
|
||||
ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
|
||||
|
@ -3388,7 +3641,14 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
|
|||
|
||||
res->resetting_device = 1;
|
||||
scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n");
|
||||
rc = ipr_device_reset(ioa_cfg, res);
|
||||
|
||||
if (ipr_is_gata(res) && res->sata_port) {
|
||||
ap = res->sata_port->ap;
|
||||
spin_unlock_irq(scsi_cmd->device->host->host_lock);
|
||||
ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL);
|
||||
spin_lock_irq(scsi_cmd->device->host->host_lock);
|
||||
} else
|
||||
rc = ipr_device_reset(ioa_cfg, res);
|
||||
res->resetting_device = 0;
|
||||
|
||||
LEAVE;
|
||||
|
@ -4300,6 +4560,9 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (ipr_is_gata(res) && res->sata_port)
|
||||
return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap);
|
||||
|
||||
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
|
||||
ioarcb = &ipr_cmd->ioarcb;
|
||||
list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
|
||||
|
@ -4344,6 +4607,26 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_ioctl - IOCTL handler
|
||||
* @sdev: scsi device struct
|
||||
* @cmd: IOCTL cmd
|
||||
* @arg: IOCTL arg
|
||||
*
|
||||
* Return value:
|
||||
* 0 on success / other on failure
|
||||
**/
|
||||
int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
|
||||
{
|
||||
struct ipr_resource_entry *res;
|
||||
|
||||
res = (struct ipr_resource_entry *)sdev->hostdata;
|
||||
if (res && ipr_is_gata(res))
|
||||
return ata_scsi_ioctl(sdev, cmd, arg);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_info - Get information about the card/driver
|
||||
* @scsi_host: scsi host struct
|
||||
|
@ -4366,10 +4649,45 @@ static const char * ipr_ioa_info(struct Scsi_Host *host)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_scsi_timed_out - Handle scsi command timeout
|
||||
* @scsi_cmd: scsi command struct
|
||||
*
|
||||
* Return value:
|
||||
* EH_NOT_HANDLED
|
||||
**/
|
||||
enum scsi_eh_timer_return ipr_scsi_timed_out(struct scsi_cmnd *scsi_cmd)
|
||||
{
|
||||
struct ipr_ioa_cfg *ioa_cfg;
|
||||
struct ipr_cmnd *ipr_cmd;
|
||||
unsigned long flags;
|
||||
|
||||
ENTER;
|
||||
spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags);
|
||||
ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
|
||||
|
||||
list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
|
||||
if (ipr_cmd->qc && ipr_cmd->qc->scsicmd == scsi_cmd) {
|
||||
ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
|
||||
ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags);
|
||||
LEAVE;
|
||||
return EH_NOT_HANDLED;
|
||||
}
|
||||
|
||||
static struct scsi_transport_template ipr_transport_template = {
|
||||
.eh_timed_out = ipr_scsi_timed_out
|
||||
};
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "IPR",
|
||||
.info = ipr_ioa_info,
|
||||
.ioctl = ipr_ioctl,
|
||||
.queuecommand = ipr_queuecommand,
|
||||
.eh_abort_handler = ipr_eh_abort,
|
||||
.eh_device_reset_handler = ipr_eh_dev_reset,
|
||||
|
@ -4377,6 +4695,8 @@ static struct scsi_host_template driver_template = {
|
|||
.slave_alloc = ipr_slave_alloc,
|
||||
.slave_configure = ipr_slave_configure,
|
||||
.slave_destroy = ipr_slave_destroy,
|
||||
.target_alloc = ipr_target_alloc,
|
||||
.target_destroy = ipr_target_destroy,
|
||||
.change_queue_depth = ipr_change_queue_depth,
|
||||
.change_queue_type = ipr_change_queue_type,
|
||||
.bios_param = ipr_biosparam,
|
||||
|
@ -4391,6 +4711,330 @@ static struct scsi_host_template driver_template = {
|
|||
.proc_name = IPR_NAME
|
||||
};
|
||||
|
||||
/**
|
||||
* ipr_ata_phy_reset - libata phy_reset handler
|
||||
* @ap: ata port to reset
|
||||
*
|
||||
**/
|
||||
static void ipr_ata_phy_reset(struct ata_port *ap)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct ipr_sata_port *sata_port = ap->private_data;
|
||||
struct ipr_resource_entry *res = sata_port->res;
|
||||
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
|
||||
int rc;
|
||||
|
||||
ENTER;
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
|
||||
while(ioa_cfg->in_reset_reload) {
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
|
||||
wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
|
||||
}
|
||||
|
||||
if (!ioa_cfg->allow_cmds)
|
||||
goto out_unlock;
|
||||
|
||||
rc = ipr_device_reset(ioa_cfg, res);
|
||||
|
||||
if (rc) {
|
||||
ap->ops->port_disable(ap);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
switch(res->cfgte.proto) {
|
||||
case IPR_PROTO_SATA:
|
||||
case IPR_PROTO_SAS_STP:
|
||||
ap->device[0].class = ATA_DEV_ATA;
|
||||
break;
|
||||
case IPR_PROTO_SATA_ATAPI:
|
||||
case IPR_PROTO_SAS_STP_ATAPI:
|
||||
ap->device[0].class = ATA_DEV_ATAPI;
|
||||
break;
|
||||
default:
|
||||
ap->device[0].class = ATA_DEV_UNKNOWN;
|
||||
ap->ops->port_disable(ap);
|
||||
break;
|
||||
};
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
|
||||
LEAVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_ata_post_internal - Cleanup after an internal command
|
||||
* @qc: ATA queued command
|
||||
*
|
||||
* Return value:
|
||||
* none
|
||||
**/
|
||||
static void ipr_ata_post_internal(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ipr_sata_port *sata_port = qc->ap->private_data;
|
||||
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
|
||||
struct ipr_cmnd *ipr_cmd;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
|
||||
list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
|
||||
if (ipr_cmd->qc == qc) {
|
||||
ipr_device_reset(ioa_cfg, sata_port->res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_tf_read - Read the current ATA taskfile for the ATA port
|
||||
* @ap: ATA port
|
||||
* @tf: destination ATA taskfile
|
||||
*
|
||||
* Return value:
|
||||
* none
|
||||
**/
|
||||
static void ipr_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
|
||||
{
|
||||
struct ipr_sata_port *sata_port = ap->private_data;
|
||||
struct ipr_ioasa_gata *g = &sata_port->ioasa;
|
||||
|
||||
tf->feature = g->error;
|
||||
tf->nsect = g->nsect;
|
||||
tf->lbal = g->lbal;
|
||||
tf->lbam = g->lbam;
|
||||
tf->lbah = g->lbah;
|
||||
tf->device = g->device;
|
||||
tf->command = g->status;
|
||||
tf->hob_nsect = g->hob_nsect;
|
||||
tf->hob_lbal = g->hob_lbal;
|
||||
tf->hob_lbam = g->hob_lbam;
|
||||
tf->hob_lbah = g->hob_lbah;
|
||||
tf->ctl = g->alt_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure
|
||||
* @regs: destination
|
||||
* @tf: source ATA taskfile
|
||||
*
|
||||
* Return value:
|
||||
* none
|
||||
**/
|
||||
static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs,
|
||||
struct ata_taskfile *tf)
|
||||
{
|
||||
regs->feature = tf->feature;
|
||||
regs->nsect = tf->nsect;
|
||||
regs->lbal = tf->lbal;
|
||||
regs->lbam = tf->lbam;
|
||||
regs->lbah = tf->lbah;
|
||||
regs->device = tf->device;
|
||||
regs->command = tf->command;
|
||||
regs->hob_feature = tf->hob_feature;
|
||||
regs->hob_nsect = tf->hob_nsect;
|
||||
regs->hob_lbal = tf->hob_lbal;
|
||||
regs->hob_lbam = tf->hob_lbam;
|
||||
regs->hob_lbah = tf->hob_lbah;
|
||||
regs->ctl = tf->ctl;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_sata_done - done function for SATA commands
|
||||
* @ipr_cmd: ipr command struct
|
||||
*
|
||||
* This function is invoked by the interrupt handler for
|
||||
* ops generated by the SCSI mid-layer to SATA devices
|
||||
*
|
||||
* Return value:
|
||||
* none
|
||||
**/
|
||||
static void ipr_sata_done(struct ipr_cmnd *ipr_cmd)
|
||||
{
|
||||
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
|
||||
struct ata_queued_cmd *qc = ipr_cmd->qc;
|
||||
struct ipr_sata_port *sata_port = qc->ap->private_data;
|
||||
struct ipr_resource_entry *res = sata_port->res;
|
||||
u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
|
||||
|
||||
memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
|
||||
sizeof(struct ipr_ioasa_gata));
|
||||
ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
|
||||
|
||||
if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET)
|
||||
scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus,
|
||||
res->cfgte.res_addr.target);
|
||||
|
||||
if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
|
||||
qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status);
|
||||
else
|
||||
qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status);
|
||||
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
|
||||
ata_qc_complete(qc);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_build_ata_ioadl - Build an ATA scatter/gather list
|
||||
* @ipr_cmd: ipr command struct
|
||||
* @qc: ATA queued command
|
||||
*
|
||||
**/
|
||||
static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
|
||||
struct ata_queued_cmd *qc)
|
||||
{
|
||||
u32 ioadl_flags = 0;
|
||||
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
|
||||
struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
|
||||
int len = qc->nbytes + qc->pad_len;
|
||||
struct scatterlist *sg;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
if (qc->dma_dir == DMA_TO_DEVICE) {
|
||||
ioadl_flags = IPR_IOADL_FLAGS_WRITE;
|
||||
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
|
||||
ioarcb->write_data_transfer_length = cpu_to_be32(len);
|
||||
ioarcb->write_ioadl_len =
|
||||
cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
|
||||
} else if (qc->dma_dir == DMA_FROM_DEVICE) {
|
||||
ioadl_flags = IPR_IOADL_FLAGS_READ;
|
||||
ioarcb->read_data_transfer_length = cpu_to_be32(len);
|
||||
ioarcb->read_ioadl_len =
|
||||
cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
|
||||
}
|
||||
|
||||
ata_for_each_sg(sg, qc) {
|
||||
ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
|
||||
ioadl->address = cpu_to_be32(sg_dma_address(sg));
|
||||
if (ata_sg_is_last(sg, qc))
|
||||
ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
|
||||
else
|
||||
ioadl++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_qc_issue - Issue a SATA qc to a device
|
||||
* @qc: queued command
|
||||
*
|
||||
* Return value:
|
||||
* 0 if success
|
||||
**/
|
||||
static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
struct ipr_sata_port *sata_port = ap->private_data;
|
||||
struct ipr_resource_entry *res = sata_port->res;
|
||||
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
|
||||
struct ipr_cmnd *ipr_cmd;
|
||||
struct ipr_ioarcb *ioarcb;
|
||||
struct ipr_ioarcb_ata_regs *regs;
|
||||
|
||||
if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead))
|
||||
return -EIO;
|
||||
|
||||
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
|
||||
ioarcb = &ipr_cmd->ioarcb;
|
||||
regs = &ioarcb->add_data.u.regs;
|
||||
|
||||
memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data));
|
||||
ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs));
|
||||
|
||||
list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
|
||||
ipr_cmd->qc = qc;
|
||||
ipr_cmd->done = ipr_sata_done;
|
||||
ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
|
||||
ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU;
|
||||
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
|
||||
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
|
||||
ipr_cmd->dma_use_sg = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
|
||||
|
||||
ipr_build_ata_ioadl(ipr_cmd, qc);
|
||||
regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
|
||||
ipr_copy_sata_tf(regs, &qc->tf);
|
||||
memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN);
|
||||
ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr));
|
||||
|
||||
switch (qc->tf.protocol) {
|
||||
case ATA_PROT_NODATA:
|
||||
case ATA_PROT_PIO:
|
||||
break;
|
||||
|
||||
case ATA_PROT_DMA:
|
||||
regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
|
||||
break;
|
||||
|
||||
case ATA_PROT_ATAPI:
|
||||
case ATA_PROT_ATAPI_NODATA:
|
||||
regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
|
||||
break;
|
||||
|
||||
case ATA_PROT_ATAPI_DMA:
|
||||
regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
|
||||
regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mb();
|
||||
writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr),
|
||||
ioa_cfg->regs.ioarrin_reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_ata_check_status - Return last ATA status
|
||||
* @ap: ATA port
|
||||
*
|
||||
* Return value:
|
||||
* ATA status
|
||||
**/
|
||||
static u8 ipr_ata_check_status(struct ata_port *ap)
|
||||
{
|
||||
struct ipr_sata_port *sata_port = ap->private_data;
|
||||
return sata_port->ioasa.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipr_ata_check_altstatus - Return last ATA altstatus
|
||||
* @ap: ATA port
|
||||
*
|
||||
* Return value:
|
||||
* Alt ATA status
|
||||
**/
|
||||
static u8 ipr_ata_check_altstatus(struct ata_port *ap)
|
||||
{
|
||||
struct ipr_sata_port *sata_port = ap->private_data;
|
||||
return sata_port->ioasa.alt_status;
|
||||
}
|
||||
|
||||
static struct ata_port_operations ipr_sata_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
.check_status = ipr_ata_check_status,
|
||||
.check_altstatus = ipr_ata_check_altstatus,
|
||||
.dev_select = ata_noop_dev_select,
|
||||
.phy_reset = ipr_ata_phy_reset,
|
||||
.post_internal_cmd = ipr_ata_post_internal,
|
||||
.tf_read = ipr_tf_read,
|
||||
.qc_prep = ata_noop_qc_prep,
|
||||
.qc_issue = ipr_qc_issue,
|
||||
.port_start = ata_sas_port_start,
|
||||
.port_stop = ata_sas_port_stop
|
||||
};
|
||||
|
||||
static struct ata_port_info sata_port_info = {
|
||||
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET |
|
||||
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
|
||||
.pio_mask = 0x10, /* pio4 */
|
||||
.mwdma_mask = 0x07,
|
||||
.udma_mask = 0x7f, /* udma0-6 */
|
||||
.port_ops = &ipr_sata_ops
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PPC_PSERIES
|
||||
static const u16 ipr_blocked_processors[] = {
|
||||
PV_NORTHSTAR,
|
||||
|
@ -6352,7 +6996,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
|
|||
struct Scsi_Host *host;
|
||||
unsigned long ipr_regs_pci;
|
||||
void __iomem *ipr_regs;
|
||||
u32 rc = PCIBIOS_SUCCESSFUL;
|
||||
int rc = PCIBIOS_SUCCESSFUL;
|
||||
volatile u32 mask, uproc;
|
||||
|
||||
ENTER;
|
||||
|
@ -6374,6 +7018,9 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
|
|||
|
||||
ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
|
||||
memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
|
||||
host->transportt = &ipr_transport_template;
|
||||
ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
|
||||
sata_port_info.flags, &ipr_sata_ops);
|
||||
|
||||
ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id);
|
||||
|
||||
|
@ -6749,7 +7396,7 @@ static int __init ipr_init(void)
|
|||
ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n",
|
||||
IPR_DRIVER_VERSION, IPR_DRIVER_DATE);
|
||||
|
||||
return pci_module_init(&ipr_driver);
|
||||
return pci_register_driver(&ipr_driver);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/kref.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
@ -36,8 +37,8 @@
|
|||
/*
|
||||
* Literals
|
||||
*/
|
||||
#define IPR_DRIVER_VERSION "2.1.4"
|
||||
#define IPR_DRIVER_DATE "(August 2, 2006)"
|
||||
#define IPR_DRIVER_VERSION "2.2.0"
|
||||
#define IPR_DRIVER_DATE "(September 25, 2006)"
|
||||
|
||||
/*
|
||||
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
|
||||
|
@ -849,6 +850,13 @@ struct ipr_bus_attributes {
|
|||
u32 max_xfer_rate;
|
||||
};
|
||||
|
||||
struct ipr_sata_port {
|
||||
struct ipr_ioa_cfg *ioa_cfg;
|
||||
struct ata_port *ap;
|
||||
struct ipr_resource_entry *res;
|
||||
struct ipr_ioasa_gata ioasa;
|
||||
};
|
||||
|
||||
struct ipr_resource_entry {
|
||||
struct ipr_config_table_entry cfgte;
|
||||
u8 needs_sync_complete:1;
|
||||
|
@ -858,6 +866,7 @@ struct ipr_resource_entry {
|
|||
u8 resetting_device:1;
|
||||
|
||||
struct scsi_device *sdev;
|
||||
struct ipr_sata_port *sata_port;
|
||||
struct list_head queue;
|
||||
};
|
||||
|
||||
|
@ -928,10 +937,11 @@ struct ipr_trace_entry {
|
|||
u32 time;
|
||||
|
||||
u8 op_code;
|
||||
u8 ata_op_code;
|
||||
u8 type;
|
||||
#define IPR_TRACE_START 0x00
|
||||
#define IPR_TRACE_FINISH 0xff
|
||||
u16 cmd_index;
|
||||
u8 cmd_index;
|
||||
|
||||
__be32 res_handle;
|
||||
union {
|
||||
|
@ -1073,6 +1083,7 @@ struct ipr_ioa_cfg {
|
|||
|
||||
struct ipr_cmnd *reset_cmd;
|
||||
|
||||
struct ata_host ata_host;
|
||||
char ipr_cmd_label[8];
|
||||
#define IPR_CMD_LABEL "ipr_cmnd"
|
||||
struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
|
||||
|
@ -1085,6 +1096,7 @@ struct ipr_cmnd {
|
|||
struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES];
|
||||
struct list_head queue;
|
||||
struct scsi_cmnd *scsi_cmd;
|
||||
struct ata_queued_cmd *qc;
|
||||
struct completion completion;
|
||||
struct timer_list timer;
|
||||
void (*done) (struct ipr_cmnd *);
|
||||
|
|
|
@ -182,14 +182,8 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <scsi/sg.h>
|
||||
|
||||
#include "scsi.h"
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
|
||||
#include "hosts.h"
|
||||
#else
|
||||
#include <scsi/scsi_host.h>
|
||||
#endif
|
||||
|
||||
#include "ips.h"
|
||||
|
||||
|
@ -250,9 +244,9 @@ module_param(ips, charp, 0);
|
|||
*/
|
||||
static int ips_detect(struct scsi_host_template *);
|
||||
static int ips_release(struct Scsi_Host *);
|
||||
static int ips_eh_abort(Scsi_Cmnd *);
|
||||
static int ips_eh_reset(Scsi_Cmnd *);
|
||||
static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
|
||||
static int ips_eh_abort(struct scsi_cmnd *);
|
||||
static int ips_eh_reset(struct scsi_cmnd *);
|
||||
static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *));
|
||||
static const char *ips_info(struct Scsi_Host *);
|
||||
static irqreturn_t do_ipsintr(int, void *, struct pt_regs *);
|
||||
static int ips_hainit(ips_ha_t *);
|
||||
|
@ -325,24 +319,26 @@ static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
|
|||
static uint32_t ips_statupd_morpheus(ips_ha_t *);
|
||||
static ips_scb_t *ips_getscb(ips_ha_t *);
|
||||
static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
|
||||
static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
|
||||
static void ips_putq_wait_tail(ips_wait_queue_t *, struct scsi_cmnd *);
|
||||
static void ips_putq_copp_tail(ips_copp_queue_t *,
|
||||
ips_copp_wait_item_t *);
|
||||
static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
|
||||
static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
|
||||
static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
|
||||
static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
|
||||
static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
|
||||
static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *,
|
||||
struct scsi_cmnd *);
|
||||
static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
|
||||
ips_copp_wait_item_t *);
|
||||
static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
|
||||
|
||||
static int ips_is_passthru(Scsi_Cmnd *);
|
||||
static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
|
||||
static int ips_is_passthru(struct scsi_cmnd *);
|
||||
static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int);
|
||||
static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
|
||||
static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
|
||||
static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
|
||||
static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data,
|
||||
unsigned int count);
|
||||
static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
|
||||
static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data,
|
||||
unsigned int count);
|
||||
|
||||
static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
|
||||
static int ips_host_info(ips_ha_t *, char *, off_t, int);
|
||||
|
@ -812,8 +808,7 @@ ips_halt(struct notifier_block *nb, ulong event, void *buf)
|
|||
/* Abort a command (using the new error code stuff) */
|
||||
/* Note: this routine is called under the io_request_lock */
|
||||
/****************************************************************************/
|
||||
int
|
||||
ips_eh_abort(Scsi_Cmnd * SC)
|
||||
int ips_eh_abort(struct scsi_cmnd *SC)
|
||||
{
|
||||
ips_ha_t *ha;
|
||||
ips_copp_wait_item_t *item;
|
||||
|
@ -871,8 +866,7 @@ ips_eh_abort(Scsi_Cmnd * SC)
|
|||
/* NOTE: this routine is called under the io_request_lock spinlock */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
static int
|
||||
__ips_eh_reset(Scsi_Cmnd * SC)
|
||||
static int __ips_eh_reset(struct scsi_cmnd *SC)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
@ -968,7 +962,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
|
|||
ret = (*ha->func.reset) (ha);
|
||||
|
||||
if (!ret) {
|
||||
Scsi_Cmnd *scsi_cmd;
|
||||
struct scsi_cmnd *scsi_cmd;
|
||||
|
||||
IPS_PRINTK(KERN_NOTICE, ha->pcidev,
|
||||
"Controller reset failed - controller now offline.\n");
|
||||
|
@ -997,7 +991,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
|
|||
}
|
||||
|
||||
if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
|
||||
Scsi_Cmnd *scsi_cmd;
|
||||
struct scsi_cmnd *scsi_cmd;
|
||||
|
||||
IPS_PRINTK(KERN_NOTICE, ha->pcidev,
|
||||
"Controller reset failed - controller now offline.\n");
|
||||
|
@ -1059,8 +1053,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
|
|||
|
||||
}
|
||||
|
||||
static int
|
||||
ips_eh_reset(Scsi_Cmnd * SC)
|
||||
static int ips_eh_reset(struct scsi_cmnd *SC)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -1083,8 +1076,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
|
|||
/* Linux obtains io_request_lock before calling this function */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
static int
|
||||
ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
|
||||
static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
|
||||
{
|
||||
ips_ha_t *ha;
|
||||
ips_passthru_t *pt;
|
||||
|
@ -1602,8 +1594,7 @@ ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
|
|||
/* Determine if the specified SCSI command is really a passthru command */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
static int
|
||||
ips_is_passthru(Scsi_Cmnd * SC)
|
||||
static int ips_is_passthru(struct scsi_cmnd *SC)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -1685,7 +1676,7 @@ ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
|
|||
/* */
|
||||
/****************************************************************************/
|
||||
static int
|
||||
ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
|
||||
ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
|
||||
{
|
||||
ips_passthru_t *pt;
|
||||
int length = 0;
|
||||
|
@ -2734,9 +2725,9 @@ static void
|
|||
ips_next(ips_ha_t * ha, int intr)
|
||||
{
|
||||
ips_scb_t *scb;
|
||||
Scsi_Cmnd *SC;
|
||||
Scsi_Cmnd *p;
|
||||
Scsi_Cmnd *q;
|
||||
struct scsi_cmnd *SC;
|
||||
struct scsi_cmnd *p;
|
||||
struct scsi_cmnd *q;
|
||||
ips_copp_wait_item_t *item;
|
||||
int ret;
|
||||
unsigned long cpu_flags = 0;
|
||||
|
@ -2847,7 +2838,7 @@ ips_next(ips_ha_t * ha, int intr)
|
|||
dcdb_active[scmd_channel(p) -
|
||||
1] & (1 << scmd_id(p)))) {
|
||||
ips_freescb(ha, scb);
|
||||
p = (Scsi_Cmnd *) p->host_scribble;
|
||||
p = (struct scsi_cmnd *) p->host_scribble;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2962,7 +2953,7 @@ ips_next(ips_ha_t * ha, int intr)
|
|||
break;
|
||||
} /* end case */
|
||||
|
||||
p = (Scsi_Cmnd *) p->host_scribble;
|
||||
p = (struct scsi_cmnd *) p->host_scribble;
|
||||
|
||||
} /* end while */
|
||||
|
||||
|
@ -3090,8 +3081,7 @@ ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
|
|||
/* ASSUMED to be called from within the HA lock */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
static void
|
||||
ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
|
||||
static void ips_putq_wait_tail(ips_wait_queue_t *queue, struct scsi_cmnd *item)
|
||||
{
|
||||
METHOD_TRACE("ips_putq_wait_tail", 1);
|
||||
|
||||
|
@ -3122,10 +3112,9 @@ ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
|
|||
/* ASSUMED to be called from within the HA lock */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
static Scsi_Cmnd *
|
||||
ips_removeq_wait_head(ips_wait_queue_t * queue)
|
||||
static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *queue)
|
||||
{
|
||||
Scsi_Cmnd *item;
|
||||
struct scsi_cmnd *item;
|
||||
|
||||
METHOD_TRACE("ips_removeq_wait_head", 1);
|
||||
|
||||
|
@ -3135,7 +3124,7 @@ ips_removeq_wait_head(ips_wait_queue_t * queue)
|
|||
return (NULL);
|
||||
}
|
||||
|
||||
queue->head = (Scsi_Cmnd *) item->host_scribble;
|
||||
queue->head = (struct scsi_cmnd *) item->host_scribble;
|
||||
item->host_scribble = NULL;
|
||||
|
||||
if (queue->tail == item)
|
||||
|
@ -3157,10 +3146,10 @@ ips_removeq_wait_head(ips_wait_queue_t * queue)
|
|||
/* ASSUMED to be called from within the HA lock */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
static Scsi_Cmnd *
|
||||
ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
|
||||
static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *queue,
|
||||
struct scsi_cmnd *item)
|
||||
{
|
||||
Scsi_Cmnd *p;
|
||||
struct scsi_cmnd *p;
|
||||
|
||||
METHOD_TRACE("ips_removeq_wait", 1);
|
||||
|
||||
|
@ -3173,8 +3162,8 @@ ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
|
|||
|
||||
p = queue->head;
|
||||
|
||||
while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
|
||||
p = (Scsi_Cmnd *) p->host_scribble;
|
||||
while ((p) && (item != (struct scsi_cmnd *) p->host_scribble))
|
||||
p = (struct scsi_cmnd *) p->host_scribble;
|
||||
|
||||
if (p) {
|
||||
/* found a match */
|
||||
|
@ -3659,11 +3648,10 @@ ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
|
|||
/* Routine Name: ips_scmd_buf_write */
|
||||
/* */
|
||||
/* Routine Description: */
|
||||
/* Write data to Scsi_Cmnd request_buffer at proper offsets */
|
||||
/* Write data to struct scsi_cmnd request_buffer at proper offsets */
|
||||
/****************************************************************************/
|
||||
static void
|
||||
ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
|
||||
int count)
|
||||
ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
|
||||
{
|
||||
if (scmd->use_sg) {
|
||||
int i;
|
||||
|
@ -3698,11 +3686,10 @@ ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
|
|||
/* Routine Name: ips_scmd_buf_read */
|
||||
/* */
|
||||
/* Routine Description: */
|
||||
/* Copy data from a Scsi_Cmnd to a new, linear buffer */
|
||||
/* Copy data from a struct scsi_cmnd to a new, linear buffer */
|
||||
/****************************************************************************/
|
||||
static void
|
||||
ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
|
||||
int count)
|
||||
ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
|
||||
{
|
||||
if (scmd->use_sg) {
|
||||
int i;
|
||||
|
@ -7078,7 +7065,7 @@ ips_remove_device(struct pci_dev *pci_dev)
|
|||
static int __init
|
||||
ips_module_init(void)
|
||||
{
|
||||
if (pci_module_init(&ips_pci_driver) < 0)
|
||||
if (pci_register_driver(&ips_pci_driver) < 0)
|
||||
return -ENODEV;
|
||||
ips_driver_template.module = THIS_MODULE;
|
||||
ips_order_controllers();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/* David Jeffery, Adaptec, Inc. */
|
||||
/* */
|
||||
/* Copyright (C) 1999 IBM Corporation */
|
||||
/* Copyright (C) 2003 Adaptec, Inc. */
|
||||
/* Copyright (C) 2003 Adaptec, Inc. */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify */
|
||||
/* it under the terms of the GNU General Public License as published by */
|
||||
|
@ -1033,14 +1033,14 @@ typedef struct ips_scb_queue {
|
|||
* Wait queue_format
|
||||
*/
|
||||
typedef struct ips_wait_queue {
|
||||
Scsi_Cmnd *head;
|
||||
Scsi_Cmnd *tail;
|
||||
int count;
|
||||
struct scsi_cmnd *head;
|
||||
struct scsi_cmnd *tail;
|
||||
int count;
|
||||
} ips_wait_queue_t;
|
||||
|
||||
typedef struct ips_copp_wait_item {
|
||||
Scsi_Cmnd *scsi_cmd;
|
||||
struct ips_copp_wait_item *next;
|
||||
struct scsi_cmnd *scsi_cmd;
|
||||
struct ips_copp_wait_item *next;
|
||||
} ips_copp_wait_item_t;
|
||||
|
||||
typedef struct ips_copp_queue {
|
||||
|
@ -1149,7 +1149,7 @@ typedef struct ips_scb {
|
|||
uint32_t flags;
|
||||
uint32_t op_code;
|
||||
IPS_SG_LIST sg_list;
|
||||
Scsi_Cmnd *scsi_cmd;
|
||||
struct scsi_cmnd *scsi_cmd;
|
||||
struct ips_scb *q_next;
|
||||
ips_scb_callback callback;
|
||||
uint32_t sg_busaddr;
|
||||
|
@ -1175,7 +1175,7 @@ typedef struct ips_scb_pt {
|
|||
uint32_t flags;
|
||||
uint32_t op_code;
|
||||
IPS_SG_LIST *sg_list;
|
||||
Scsi_Cmnd *scsi_cmd;
|
||||
struct scsi_cmnd *scsi_cmd;
|
||||
struct ips_scb *q_next;
|
||||
ips_scb_callback callback;
|
||||
} ips_scb_pt_t;
|
||||
|
|
|
@ -389,7 +389,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
|
|||
|
||||
lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
|
||||
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
|
||||
if (lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT) != MBX_SUCCESS) {
|
||||
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
|
||||
if (rc != MBX_SUCCESS) {
|
||||
lpfc_printf_log(phba,
|
||||
KERN_ERR,
|
||||
LOG_INIT,
|
||||
|
@ -406,7 +407,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
|
|||
readl(phba->HAregaddr); /* flush */
|
||||
|
||||
phba->hba_state = LPFC_HBA_ERROR;
|
||||
mempool_free(pmb, phba->mbox_mem_pool);
|
||||
if (rc != MBX_BUSY)
|
||||
mempool_free(pmb, phba->mbox_mem_pool);
|
||||
return -EIO;
|
||||
}
|
||||
/* MBOX buffer will be freed in mbox compl */
|
||||
|
|
|
@ -175,7 +175,7 @@ typedef struct {
|
|||
uint8_t max_lun;
|
||||
|
||||
uint32_t unique_id;
|
||||
uint8_t irq;
|
||||
int irq;
|
||||
uint8_t ito;
|
||||
caddr_t ibuf;
|
||||
dma_addr_t ibuf_dma_h;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FILE : megaraid_sas.c
|
||||
* Version : v00.00.03.01
|
||||
* Version : v00.00.03.05
|
||||
*
|
||||
* Authors:
|
||||
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
|
||||
|
@ -71,6 +71,8 @@ static struct megasas_mgmt_info megasas_mgmt_info;
|
|||
static struct fasync_struct *megasas_async_queue;
|
||||
static DEFINE_MUTEX(megasas_async_queue_mutex);
|
||||
|
||||
static u32 megasas_dbg_lvl;
|
||||
|
||||
/**
|
||||
* megasas_get_cmd - Get a command from the free pool
|
||||
* @instance: Adapter soft state
|
||||
|
@ -134,6 +136,19 @@ megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
|
|||
readl(®s->outbound_intr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_disable_intr_xscale -Disables interrupt
|
||||
* @regs: MFI register set
|
||||
*/
|
||||
static inline void
|
||||
megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
|
||||
{
|
||||
u32 mask = 0x1f;
|
||||
writel(mask, ®s->outbound_intr_mask);
|
||||
/* Dummy readl to force pci flush */
|
||||
readl(®s->outbound_intr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_read_fw_status_reg_xscale - returns the current FW status value
|
||||
* @regs: MFI register set
|
||||
|
@ -185,6 +200,7 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
|
|||
|
||||
.fire_cmd = megasas_fire_cmd_xscale,
|
||||
.enable_intr = megasas_enable_intr_xscale,
|
||||
.disable_intr = megasas_disable_intr_xscale,
|
||||
.clear_intr = megasas_clear_intr_xscale,
|
||||
.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
|
||||
};
|
||||
|
@ -214,6 +230,19 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
|
|||
readl(®s->outbound_intr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_disable_intr_ppc - Disable interrupt
|
||||
* @regs: MFI register set
|
||||
*/
|
||||
static inline void
|
||||
megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
|
||||
{
|
||||
u32 mask = 0xFFFFFFFF;
|
||||
writel(mask, ®s->outbound_intr_mask);
|
||||
/* Dummy readl to force pci flush */
|
||||
readl(®s->outbound_intr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_read_fw_status_reg_ppc - returns the current FW status value
|
||||
* @regs: MFI register set
|
||||
|
@ -265,6 +294,7 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
|
|||
|
||||
.fire_cmd = megasas_fire_cmd_ppc,
|
||||
.enable_intr = megasas_enable_intr_ppc,
|
||||
.disable_intr = megasas_disable_intr_ppc,
|
||||
.clear_intr = megasas_clear_intr_ppc,
|
||||
.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
|
||||
};
|
||||
|
@ -274,25 +304,6 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
|
|||
* specific to ppc (deviceid : 0x60) controllers
|
||||
*/
|
||||
|
||||
/**
|
||||
* megasas_disable_intr - Disables interrupts
|
||||
* @regs: MFI register set
|
||||
*/
|
||||
static inline void
|
||||
megasas_disable_intr(struct megasas_instance *instance)
|
||||
{
|
||||
u32 mask = 0x1f;
|
||||
struct megasas_register_set __iomem *regs = instance->reg_set;
|
||||
|
||||
if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R)
|
||||
mask = 0xffffffff;
|
||||
|
||||
writel(mask, ®s->outbound_intr_mask);
|
||||
|
||||
/* Dummy readl to force pci flush */
|
||||
readl(®s->outbound_intr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_issue_polled - Issues a polling command
|
||||
* @instance: Adapter soft state
|
||||
|
@ -336,6 +347,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
|
|||
* @cmd: Command to be issued
|
||||
*
|
||||
* This function waits on an event for the command to be returned from ISR.
|
||||
* Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
|
||||
* Used to issue ioctl commands.
|
||||
*/
|
||||
static int
|
||||
|
@ -346,7 +358,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
|
|||
|
||||
instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
|
||||
|
||||
wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
|
||||
wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
|
||||
MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -358,7 +371,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
|
|||
*
|
||||
* MFI firmware can abort previously issued AEN comamnd (automatic event
|
||||
* notification). The megasas_issue_blocked_abort_cmd() issues such abort
|
||||
* cmd and blocks till it is completed.
|
||||
* cmd and waits for return status.
|
||||
* Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
|
||||
*/
|
||||
static int
|
||||
megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
|
||||
|
@ -392,7 +406,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
|
|||
/*
|
||||
* Wait for this cmd to complete
|
||||
*/
|
||||
wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));
|
||||
wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
|
||||
MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
|
||||
|
||||
megasas_return_cmd(instance, cmd);
|
||||
return 0;
|
||||
|
@ -495,6 +510,46 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
|
|||
return sge_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_get_frame_count - Computes the number of frames
|
||||
* @sge_count : number of sg elements
|
||||
*
|
||||
* Returns the number of frames required for numnber of sge's (sge_count)
|
||||
*/
|
||||
|
||||
u32 megasas_get_frame_count(u8 sge_count)
|
||||
{
|
||||
int num_cnt;
|
||||
int sge_bytes;
|
||||
u32 sge_sz;
|
||||
u32 frame_count=0;
|
||||
|
||||
sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
|
||||
sizeof(struct megasas_sge32);
|
||||
|
||||
/*
|
||||
* Main frame can contain 2 SGEs for 64-bit SGLs and
|
||||
* 3 SGEs for 32-bit SGLs
|
||||
*/
|
||||
if (IS_DMA64)
|
||||
num_cnt = sge_count - 2;
|
||||
else
|
||||
num_cnt = sge_count - 3;
|
||||
|
||||
if(num_cnt>0){
|
||||
sge_bytes = sge_sz * num_cnt;
|
||||
|
||||
frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
|
||||
((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
|
||||
}
|
||||
/* Main frame */
|
||||
frame_count +=1;
|
||||
|
||||
if (frame_count > 7)
|
||||
frame_count = 8;
|
||||
return frame_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_build_dcdb - Prepares a direct cdb (DCDB) command
|
||||
* @instance: Adapter soft state
|
||||
|
@ -508,8 +563,6 @@ static int
|
|||
megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
|
||||
struct megasas_cmd *cmd)
|
||||
{
|
||||
u32 sge_sz;
|
||||
int sge_bytes;
|
||||
u32 is_logical;
|
||||
u32 device_id;
|
||||
u16 flags = 0;
|
||||
|
@ -544,9 +597,6 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
|
|||
/*
|
||||
* Construct SGL
|
||||
*/
|
||||
sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
|
||||
sizeof(struct megasas_sge32);
|
||||
|
||||
if (IS_DMA64) {
|
||||
pthru->flags |= MFI_FRAME_SGL64;
|
||||
pthru->sge_count = megasas_make_sgl64(instance, scp,
|
||||
|
@ -562,17 +612,11 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
|
|||
pthru->sense_buf_phys_addr_hi = 0;
|
||||
pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
|
||||
|
||||
sge_bytes = sge_sz * pthru->sge_count;
|
||||
|
||||
/*
|
||||
* Compute the total number of frames this command consumes. FW uses
|
||||
* this number to pull sufficient number of frames from host memory.
|
||||
*/
|
||||
cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
|
||||
((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
|
||||
|
||||
if (cmd->frame_count > 7)
|
||||
cmd->frame_count = 8;
|
||||
cmd->frame_count = megasas_get_frame_count(pthru->sge_count);
|
||||
|
||||
return cmd->frame_count;
|
||||
}
|
||||
|
@ -589,8 +633,6 @@ static int
|
|||
megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
|
||||
struct megasas_cmd *cmd)
|
||||
{
|
||||
u32 sge_sz;
|
||||
int sge_bytes;
|
||||
u32 device_id;
|
||||
u8 sc = scp->cmnd[0];
|
||||
u16 flags = 0;
|
||||
|
@ -605,7 +647,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
|
|||
flags = MFI_FRAME_DIR_READ;
|
||||
|
||||
/*
|
||||
* Preare the Logical IO frame: 2nd bit is zero for all read cmds
|
||||
* Prepare the Logical IO frame: 2nd bit is zero for all read cmds
|
||||
*/
|
||||
ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
|
||||
ldio->cmd_status = 0x0;
|
||||
|
@ -674,9 +716,6 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
|
|||
/*
|
||||
* Construct SGL
|
||||
*/
|
||||
sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
|
||||
sizeof(struct megasas_sge32);
|
||||
|
||||
if (IS_DMA64) {
|
||||
ldio->flags |= MFI_FRAME_SGL64;
|
||||
ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
|
||||
|
@ -690,13 +729,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
|
|||
ldio->sense_buf_phys_addr_hi = 0;
|
||||
ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
|
||||
|
||||
sge_bytes = sge_sz * ldio->sge_count;
|
||||
|
||||
cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
|
||||
((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
|
||||
|
||||
if (cmd->frame_count > 7)
|
||||
cmd->frame_count = 8;
|
||||
/*
|
||||
* Compute the total number of frames this command consumes. FW uses
|
||||
* this number to pull sufficient number of frames from host memory.
|
||||
*/
|
||||
cmd->frame_count = megasas_get_frame_count(ldio->sge_count);
|
||||
|
||||
return cmd->frame_count;
|
||||
}
|
||||
|
@ -727,6 +764,69 @@ static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_dump_pending_frames - Dumps the frame address of all pending cmds
|
||||
* in FW
|
||||
* @instance: Adapter soft state
|
||||
*/
|
||||
static inline void
|
||||
megasas_dump_pending_frames(struct megasas_instance *instance)
|
||||
{
|
||||
struct megasas_cmd *cmd;
|
||||
int i,n;
|
||||
union megasas_sgl *mfi_sgl;
|
||||
struct megasas_io_frame *ldio;
|
||||
struct megasas_pthru_frame *pthru;
|
||||
u32 sgcount;
|
||||
u32 max_cmd = instance->max_fw_cmds;
|
||||
|
||||
printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
|
||||
printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
|
||||
if (IS_DMA64)
|
||||
printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
|
||||
else
|
||||
printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
|
||||
|
||||
printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
|
||||
for (i = 0; i < max_cmd; i++) {
|
||||
cmd = instance->cmd_list[i];
|
||||
if(!cmd->scmd)
|
||||
continue;
|
||||
printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
|
||||
if (megasas_is_ldio(cmd->scmd)){
|
||||
ldio = (struct megasas_io_frame *)cmd->frame;
|
||||
mfi_sgl = &ldio->sgl;
|
||||
sgcount = ldio->sge_count;
|
||||
printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
|
||||
}
|
||||
else {
|
||||
pthru = (struct megasas_pthru_frame *) cmd->frame;
|
||||
mfi_sgl = &pthru->sgl;
|
||||
sgcount = pthru->sge_count;
|
||||
printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
|
||||
}
|
||||
if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
|
||||
for (n = 0; n < sgcount; n++){
|
||||
if (IS_DMA64)
|
||||
printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
|
||||
else
|
||||
printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
|
||||
}
|
||||
}
|
||||
printk(KERN_ERR "\n");
|
||||
} /*for max_cmd*/
|
||||
printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
|
||||
for (i = 0; i < max_cmd; i++) {
|
||||
|
||||
cmd = instance->cmd_list[i];
|
||||
|
||||
if(cmd->sync_cmd == 1){
|
||||
printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
|
||||
}
|
||||
}
|
||||
printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_queue_command - Queue entry point
|
||||
* @scmd: SCSI command to be queued
|
||||
|
@ -832,6 +932,13 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
|
|||
}
|
||||
|
||||
if (atomic_read(&instance->fw_outstanding)) {
|
||||
/*
|
||||
* Send signal to FW to stop processing any pending cmds.
|
||||
* The controller will be taken offline by the OS now.
|
||||
*/
|
||||
writel(MFI_STOP_ADP,
|
||||
&instance->reg_set->inbound_doorbell);
|
||||
megasas_dump_pending_frames(instance);
|
||||
instance->hw_crit_error = 1;
|
||||
return FAILED;
|
||||
}
|
||||
|
@ -1168,11 +1275,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
|
|||
static int
|
||||
megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
|
||||
{
|
||||
u32 producer;
|
||||
u32 consumer;
|
||||
u32 context;
|
||||
struct megasas_cmd *cmd;
|
||||
|
||||
/*
|
||||
* Check if it is our interrupt
|
||||
* Clear the interrupt
|
||||
|
@ -1180,23 +1282,10 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
|
|||
if(instance->instancet->clear_intr(instance->reg_set))
|
||||
return IRQ_NONE;
|
||||
|
||||
producer = *instance->producer;
|
||||
consumer = *instance->consumer;
|
||||
|
||||
while (consumer != producer) {
|
||||
context = instance->reply_queue[consumer];
|
||||
|
||||
cmd = instance->cmd_list[context];
|
||||
|
||||
megasas_complete_cmd(instance, cmd, alt_status);
|
||||
|
||||
consumer++;
|
||||
if (consumer == (instance->max_fw_cmds + 1)) {
|
||||
consumer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*instance->consumer = producer;
|
||||
/*
|
||||
* Schedule the tasklet for cmd completion
|
||||
*/
|
||||
tasklet_schedule(&instance->isr_tasklet);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -1229,10 +1318,12 @@ megasas_transition_to_ready(struct megasas_instance* instance)
|
|||
|
||||
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
|
||||
|
||||
if (fw_state != MFI_STATE_READY)
|
||||
printk(KERN_INFO "megasas: Waiting for FW to come to ready"
|
||||
" state\n");
|
||||
|
||||
while (fw_state != MFI_STATE_READY) {
|
||||
|
||||
printk(KERN_INFO "megasas: Waiting for FW to come to ready"
|
||||
" state\n");
|
||||
switch (fw_state) {
|
||||
|
||||
case MFI_STATE_FAULT:
|
||||
|
@ -1244,19 +1335,27 @@ megasas_transition_to_ready(struct megasas_instance* instance)
|
|||
/*
|
||||
* Set the CLR bit in inbound doorbell
|
||||
*/
|
||||
writel(MFI_INIT_CLEAR_HANDSHAKE,
|
||||
writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
|
||||
&instance->reg_set->inbound_doorbell);
|
||||
|
||||
max_wait = 2;
|
||||
cur_state = MFI_STATE_WAIT_HANDSHAKE;
|
||||
break;
|
||||
|
||||
case MFI_STATE_BOOT_MESSAGE_PENDING:
|
||||
writel(MFI_INIT_HOTPLUG,
|
||||
&instance->reg_set->inbound_doorbell);
|
||||
|
||||
max_wait = 10;
|
||||
cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
|
||||
break;
|
||||
|
||||
case MFI_STATE_OPERATIONAL:
|
||||
/*
|
||||
* Bring it to READY state; assuming max wait 2 secs
|
||||
* Bring it to READY state; assuming max wait 10 secs
|
||||
*/
|
||||
megasas_disable_intr(instance);
|
||||
writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
|
||||
instance->instancet->disable_intr(instance->reg_set);
|
||||
writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
|
||||
|
||||
max_wait = 10;
|
||||
cur_state = MFI_STATE_OPERATIONAL;
|
||||
|
@ -1323,6 +1422,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
|
|||
return -ENODEV;
|
||||
}
|
||||
};
|
||||
printk(KERN_INFO "megasas: FW now in Ready state\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1352,7 +1452,7 @@ static void megasas_teardown_frame_pool(struct megasas_instance *instance)
|
|||
cmd->frame_phys_addr);
|
||||
|
||||
if (cmd->sense)
|
||||
pci_pool_free(instance->sense_dma_pool, cmd->frame,
|
||||
pci_pool_free(instance->sense_dma_pool, cmd->sense,
|
||||
cmd->sense_phys_addr);
|
||||
}
|
||||
|
||||
|
@ -1627,6 +1727,39 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_complete_cmd_dpc - Returns FW's controller structure
|
||||
* @instance_addr: Address of adapter soft state
|
||||
*
|
||||
* Tasklet to complete cmds
|
||||
*/
|
||||
void megasas_complete_cmd_dpc(unsigned long instance_addr)
|
||||
{
|
||||
u32 producer;
|
||||
u32 consumer;
|
||||
u32 context;
|
||||
struct megasas_cmd *cmd;
|
||||
struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
|
||||
|
||||
producer = *instance->producer;
|
||||
consumer = *instance->consumer;
|
||||
|
||||
while (consumer != producer) {
|
||||
context = instance->reply_queue[consumer];
|
||||
|
||||
cmd = instance->cmd_list[context];
|
||||
|
||||
megasas_complete_cmd(instance, cmd, DID_OK);
|
||||
|
||||
consumer++;
|
||||
if (consumer == (instance->max_fw_cmds + 1)) {
|
||||
consumer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*instance->consumer = producer;
|
||||
}
|
||||
|
||||
/**
|
||||
* megasas_init_mfi - Initializes the FW
|
||||
* @instance: Adapter soft state
|
||||
|
@ -1690,6 +1823,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
|
|||
* Get various operational parameters from status register
|
||||
*/
|
||||
instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
|
||||
/*
|
||||
* Reduce the max supported cmds by 1. This is to ensure that the
|
||||
* reply_q_sz (1 more than the max cmd that driver may send)
|
||||
* does not exceed max cmds that the FW can support
|
||||
*/
|
||||
instance->max_fw_cmds = instance->max_fw_cmds-1;
|
||||
instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
|
||||
0x10;
|
||||
/*
|
||||
|
@ -1754,7 +1893,7 @@ static int megasas_init_mfi(struct megasas_instance *instance)
|
|||
/*
|
||||
* disable the intr before firing the init frame to FW
|
||||
*/
|
||||
megasas_disable_intr(instance);
|
||||
instance->instancet->disable_intr(instance->reg_set);
|
||||
|
||||
/*
|
||||
* Issue the init frame in polled mode
|
||||
|
@ -1791,6 +1930,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
|
|||
|
||||
kfree(ctrl_info);
|
||||
|
||||
/*
|
||||
* Setup tasklet for cmd completion
|
||||
*/
|
||||
|
||||
tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
|
||||
(unsigned long)instance);
|
||||
return 0;
|
||||
|
||||
fail_fw_init:
|
||||
|
@ -2182,6 +2327,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
|
||||
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
|
||||
|
||||
megasas_dbg_lvl = 0;
|
||||
|
||||
/*
|
||||
* Initialize MFI Firmware
|
||||
*/
|
||||
|
@ -2234,7 +2381,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
megasas_mgmt_info.max_index--;
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
megasas_disable_intr(instance);
|
||||
instance->instancet->disable_intr(instance->reg_set);
|
||||
free_irq(instance->pdev->irq, instance);
|
||||
|
||||
megasas_release_mfi(instance);
|
||||
|
@ -2348,6 +2495,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
|
|||
scsi_remove_host(instance->host);
|
||||
megasas_flush_cache(instance);
|
||||
megasas_shutdown_controller(instance);
|
||||
tasklet_kill(&instance->isr_tasklet);
|
||||
|
||||
/*
|
||||
* Take the instance off the instance array. Note that we will not
|
||||
|
@ -2364,7 +2512,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
|
|||
|
||||
pci_set_drvdata(instance->pdev, NULL);
|
||||
|
||||
megasas_disable_intr(instance);
|
||||
instance->instancet->disable_intr(instance->reg_set);
|
||||
|
||||
free_irq(instance->pdev->irq, instance);
|
||||
|
||||
|
@ -2716,7 +2864,8 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
|
|||
int i;
|
||||
int error = 0;
|
||||
|
||||
clear_user(ioc, sizeof(*ioc));
|
||||
if (clear_user(ioc, sizeof(*ioc)))
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
|
||||
copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
|
||||
|
@ -2808,6 +2957,26 @@ megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
|
|||
static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
|
||||
NULL);
|
||||
|
||||
static ssize_t
|
||||
megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
|
||||
{
|
||||
return sprintf(buf,"%u",megasas_dbg_lvl);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
|
||||
{
|
||||
int retval = count;
|
||||
if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
|
||||
printk(KERN_ERR "megasas: could not set dbg_lvl\n");
|
||||
retval = -EINVAL;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
|
||||
megasas_sysfs_set_dbg_lvl);
|
||||
|
||||
/**
|
||||
* megasas_init - Driver load entry point
|
||||
*/
|
||||
|
@ -2842,14 +3011,33 @@ static int __init megasas_init(void)
|
|||
|
||||
if (rval) {
|
||||
printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
|
||||
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
|
||||
goto err_pcidrv;
|
||||
}
|
||||
|
||||
driver_create_file(&megasas_pci_driver.driver, &driver_attr_version);
|
||||
driver_create_file(&megasas_pci_driver.driver,
|
||||
&driver_attr_release_date);
|
||||
rval = driver_create_file(&megasas_pci_driver.driver,
|
||||
&driver_attr_version);
|
||||
if (rval)
|
||||
goto err_dcf_attr_ver;
|
||||
rval = driver_create_file(&megasas_pci_driver.driver,
|
||||
&driver_attr_release_date);
|
||||
if (rval)
|
||||
goto err_dcf_rel_date;
|
||||
rval = driver_create_file(&megasas_pci_driver.driver,
|
||||
&driver_attr_dbg_lvl);
|
||||
if (rval)
|
||||
goto err_dcf_dbg_lvl;
|
||||
|
||||
return rval;
|
||||
err_dcf_dbg_lvl:
|
||||
driver_remove_file(&megasas_pci_driver.driver,
|
||||
&driver_attr_release_date);
|
||||
err_dcf_rel_date:
|
||||
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
|
||||
err_dcf_attr_ver:
|
||||
pci_unregister_driver(&megasas_pci_driver);
|
||||
err_pcidrv:
|
||||
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2857,9 +3045,11 @@ static int __init megasas_init(void)
|
|||
*/
|
||||
static void __exit megasas_exit(void)
|
||||
{
|
||||
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
|
||||
driver_remove_file(&megasas_pci_driver.driver,
|
||||
&driver_attr_dbg_lvl);
|
||||
driver_remove_file(&megasas_pci_driver.driver,
|
||||
&driver_attr_release_date);
|
||||
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
|
||||
|
||||
pci_unregister_driver(&megasas_pci_driver);
|
||||
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
/**
|
||||
* MegaRAID SAS Driver meta data
|
||||
*/
|
||||
#define MEGASAS_VERSION "00.00.03.01"
|
||||
#define MEGASAS_RELDATE "May 14, 2006"
|
||||
#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006"
|
||||
#define MEGASAS_VERSION "00.00.03.05"
|
||||
#define MEGASAS_RELDATE "Oct 02, 2006"
|
||||
#define MEGASAS_EXT_VERSION "Mon Oct 02 11:21:32 PDT 2006"
|
||||
|
||||
/*
|
||||
* Device IDs
|
||||
|
@ -50,6 +50,7 @@
|
|||
#define MFI_STATE_WAIT_HANDSHAKE 0x60000000
|
||||
#define MFI_STATE_FW_INIT_2 0x70000000
|
||||
#define MFI_STATE_DEVICE_SCAN 0x80000000
|
||||
#define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000
|
||||
#define MFI_STATE_FLUSH_CACHE 0xA0000000
|
||||
#define MFI_STATE_READY 0xB0000000
|
||||
#define MFI_STATE_OPERATIONAL 0xC0000000
|
||||
|
@ -64,12 +65,18 @@
|
|||
* READY : Move from OPERATIONAL to READY state; discard queue info
|
||||
* MFIMODE : Discard (possible) low MFA posted in 64-bit mode (??)
|
||||
* CLR_HANDSHAKE: FW is waiting for HANDSHAKE from BIOS or Driver
|
||||
* HOTPLUG : Resume from Hotplug
|
||||
* MFI_STOP_ADP : Send signal to FW to stop processing
|
||||
*/
|
||||
#define MFI_INIT_ABORT 0x00000000
|
||||
#define MFI_INIT_ABORT 0x00000001
|
||||
#define MFI_INIT_READY 0x00000002
|
||||
#define MFI_INIT_MFIMODE 0x00000004
|
||||
#define MFI_INIT_CLEAR_HANDSHAKE 0x00000008
|
||||
#define MFI_RESET_FLAGS MFI_INIT_READY|MFI_INIT_MFIMODE
|
||||
#define MFI_INIT_HOTPLUG 0x00000010
|
||||
#define MFI_STOP_ADP 0x00000020
|
||||
#define MFI_RESET_FLAGS MFI_INIT_READY| \
|
||||
MFI_INIT_MFIMODE| \
|
||||
MFI_INIT_ABORT
|
||||
|
||||
/**
|
||||
* MFI frame flags
|
||||
|
@ -530,6 +537,8 @@ struct megasas_ctrl_info {
|
|||
#define MEGASAS_MAX_LUN 8
|
||||
#define MEGASAS_MAX_LD 64
|
||||
|
||||
#define MEGASAS_DBG_LVL 1
|
||||
|
||||
/*
|
||||
* When SCSI mid-layer calls driver's reset routine, driver waits for
|
||||
* MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
|
||||
|
@ -538,6 +547,7 @@ struct megasas_ctrl_info {
|
|||
* every MEGASAS_RESET_NOTICE_INTERVAL seconds
|
||||
*/
|
||||
#define MEGASAS_RESET_WAIT_TIME 180
|
||||
#define MEGASAS_INTERNAL_CMD_WAIT_TIME 180
|
||||
#define MEGASAS_RESET_NOTICE_INTERVAL 5
|
||||
|
||||
#define MEGASAS_IOCTL_CMD 0
|
||||
|
@ -1042,6 +1052,7 @@ struct megasas_evt_detail {
|
|||
void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
|
||||
|
||||
void (*enable_intr)(struct megasas_register_set __iomem *) ;
|
||||
void (*disable_intr)(struct megasas_register_set __iomem *);
|
||||
|
||||
int (*clear_intr)(struct megasas_register_set __iomem *);
|
||||
|
||||
|
@ -1092,6 +1103,7 @@ struct megasas_instance {
|
|||
u32 hw_crit_error;
|
||||
|
||||
struct megasas_instance_template *instancet;
|
||||
struct tasklet_struct isr_tasklet;
|
||||
};
|
||||
|
||||
#define MEGASAS_IS_LOGICAL(scp) \
|
||||
|
|
|
@ -3581,7 +3581,7 @@ static struct pci_driver nsp32_driver = {
|
|||
*/
|
||||
static int __init init_nsp32(void) {
|
||||
nsp32_msg(KERN_INFO, "loading...");
|
||||
return pci_module_init(&nsp32_driver);
|
||||
return pci_register_driver(&nsp32_driver);
|
||||
}
|
||||
|
||||
static void __exit exit_nsp32(void) {
|
||||
|
|
|
@ -619,47 +619,5 @@ typedef struct _nsp32_hw_data {
|
|||
#define REQSACK_TIMEOUT_TIME 10000 /* max wait time for REQ/SACK assertion
|
||||
or negation, 10000us == 10ms */
|
||||
|
||||
/**************************************************************************
|
||||
* Compatibility functions
|
||||
*/
|
||||
|
||||
/* for Kernel 2.4 */
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
|
||||
# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template)
|
||||
# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template)
|
||||
# define scsi_host_put(host) scsi_unregister(host)
|
||||
# define pci_name(pci_dev) ((pci_dev)->slot_name)
|
||||
|
||||
typedef void irqreturn_t;
|
||||
# define IRQ_NONE /* */
|
||||
# define IRQ_HANDLED /* */
|
||||
# define IRQ_RETVAL(x) /* */
|
||||
|
||||
/* This is ad-hoc version of scsi_host_get_next() */
|
||||
static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host)
|
||||
{
|
||||
if (host == NULL) {
|
||||
return scsi_hostlist;
|
||||
} else {
|
||||
return host->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is ad-hoc version of scsi_host_hn_get() */
|
||||
static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno)
|
||||
{
|
||||
struct Scsi_Host *host;
|
||||
|
||||
for (host = scsi_host_get_next(NULL); host != NULL;
|
||||
host = scsi_host_get_next(host)) {
|
||||
if (host->host_no == hostno) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NSP32_H */
|
||||
/* end */
|
||||
|
|
|
@ -4843,8 +4843,7 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp)
|
|||
static int osst_ioctl(struct inode * inode,struct file * file,
|
||||
unsigned int cmd_in, unsigned long arg)
|
||||
{
|
||||
int i, cmd_nr, cmd_type, retval = 0;
|
||||
unsigned int blk;
|
||||
int i, cmd_nr, cmd_type, blk, retval = 0;
|
||||
struct st_modedef * STm;
|
||||
struct st_partstat * STps;
|
||||
struct osst_request * SRpnt = NULL;
|
||||
|
@ -5207,12 +5206,12 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d
|
|||
priority = GFP_KERNEL;
|
||||
|
||||
i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
|
||||
tb = (struct osst_buffer *)kmalloc(i, priority);
|
||||
tb = kzalloc(i, priority);
|
||||
if (!tb) {
|
||||
printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(tb, 0, i);
|
||||
|
||||
tb->sg_segs = tb->orig_sg_segs = 0;
|
||||
tb->use_sg = max_sg;
|
||||
tb->in_use = 1;
|
||||
|
@ -5575,9 +5574,9 @@ static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
|
|||
|
||||
static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
|
||||
|
||||
static void osst_create_driverfs_files(struct device_driver *driverfs)
|
||||
static int osst_create_driverfs_files(struct device_driver *driverfs)
|
||||
{
|
||||
driver_create_file(driverfs, &driver_attr_version);
|
||||
return driver_create_file(driverfs, &driver_attr_version);
|
||||
}
|
||||
|
||||
static void osst_remove_driverfs_files(struct device_driver *driverfs)
|
||||
|
@ -5663,50 +5662,70 @@ CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
|
|||
|
||||
static struct class *osst_sysfs_class;
|
||||
|
||||
static int osst_sysfs_valid = 0;
|
||||
|
||||
static void osst_sysfs_init(void)
|
||||
static int osst_sysfs_init(void)
|
||||
{
|
||||
osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
|
||||
if ( IS_ERR(osst_sysfs_class) )
|
||||
printk(KERN_WARNING "osst :W: Unable to register sysfs class\n");
|
||||
else
|
||||
osst_sysfs_valid = 1;
|
||||
}
|
||||
|
||||
static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
|
||||
{
|
||||
struct class_device *osst_class_member;
|
||||
|
||||
if (!osst_sysfs_valid) return;
|
||||
|
||||
osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name);
|
||||
if (IS_ERR(osst_class_member)) {
|
||||
printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
|
||||
return;
|
||||
if (IS_ERR(osst_sysfs_class)) {
|
||||
printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
|
||||
return PTR_ERR(osst_sysfs_class);
|
||||
}
|
||||
class_set_devdata(osst_class_member, STp);
|
||||
class_device_create_file(osst_class_member, &class_device_attr_ADR_rev);
|
||||
class_device_create_file(osst_class_member, &class_device_attr_media_version);
|
||||
class_device_create_file(osst_class_member, &class_device_attr_capacity);
|
||||
class_device_create_file(osst_class_member, &class_device_attr_BOT_frame);
|
||||
class_device_create_file(osst_class_member, &class_device_attr_EOD_frame);
|
||||
class_device_create_file(osst_class_member, &class_device_attr_file_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void osst_sysfs_destroy(dev_t dev)
|
||||
{
|
||||
if (!osst_sysfs_valid) return;
|
||||
|
||||
class_device_destroy(osst_sysfs_class, dev);
|
||||
}
|
||||
|
||||
static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
|
||||
{
|
||||
struct class_device *osst_class_member;
|
||||
int err;
|
||||
|
||||
osst_class_member = class_device_create(osst_sysfs_class, NULL, dev,
|
||||
device, "%s", name);
|
||||
if (IS_ERR(osst_class_member)) {
|
||||
printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
|
||||
return PTR_ERR(osst_class_member);
|
||||
}
|
||||
|
||||
class_set_devdata(osst_class_member, STp);
|
||||
err = class_device_create_file(osst_class_member,
|
||||
&class_device_attr_ADR_rev);
|
||||
if (err)
|
||||
goto err_out;
|
||||
err = class_device_create_file(osst_class_member,
|
||||
&class_device_attr_media_version);
|
||||
if (err)
|
||||
goto err_out;
|
||||
err = class_device_create_file(osst_class_member,
|
||||
&class_device_attr_capacity);
|
||||
if (err)
|
||||
goto err_out;
|
||||
err = class_device_create_file(osst_class_member,
|
||||
&class_device_attr_BOT_frame);
|
||||
if (err)
|
||||
goto err_out;
|
||||
err = class_device_create_file(osst_class_member,
|
||||
&class_device_attr_EOD_frame);
|
||||
if (err)
|
||||
goto err_out;
|
||||
err = class_device_create_file(osst_class_member,
|
||||
&class_device_attr_file_count);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
osst_sysfs_destroy(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void osst_sysfs_cleanup(void)
|
||||
{
|
||||
if (osst_sysfs_valid) {
|
||||
class_destroy(osst_sysfs_class);
|
||||
osst_sysfs_valid = 0;
|
||||
}
|
||||
class_destroy(osst_sysfs_class);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -5721,7 +5740,7 @@ static int osst_probe(struct device *dev)
|
|||
struct st_partstat * STps;
|
||||
struct osst_buffer * buffer;
|
||||
struct gendisk * drive;
|
||||
int i, dev_num;
|
||||
int i, dev_num, err = -ENODEV;
|
||||
|
||||
if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
|
||||
return -ENODEV;
|
||||
|
@ -5849,13 +5868,20 @@ static int osst_probe(struct device *dev)
|
|||
init_MUTEX(&tpnt->lock);
|
||||
osst_nr_dev++;
|
||||
write_unlock(&os_scsi_tapes_lock);
|
||||
|
||||
{
|
||||
char name[8];
|
||||
|
||||
/* Rewind entry */
|
||||
osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
|
||||
err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
|
||||
if (err)
|
||||
goto out_free_buffer;
|
||||
|
||||
/* No-rewind entry */
|
||||
snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
|
||||
osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
|
||||
err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
|
||||
if (err)
|
||||
goto out_free_sysfs1;
|
||||
}
|
||||
|
||||
sdev_printk(KERN_INFO, SDp,
|
||||
|
@ -5864,9 +5890,13 @@ static int osst_probe(struct device *dev)
|
|||
|
||||
return 0;
|
||||
|
||||
out_free_sysfs1:
|
||||
osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
|
||||
out_free_buffer:
|
||||
kfree(buffer);
|
||||
out_put_disk:
|
||||
put_disk(drive);
|
||||
return -ENODEV;
|
||||
return err;
|
||||
};
|
||||
|
||||
static int osst_remove(struct device *dev)
|
||||
|
@ -5903,19 +5933,39 @@ static int osst_remove(struct device *dev)
|
|||
|
||||
static int __init init_osst(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
|
||||
|
||||
validate_options();
|
||||
osst_sysfs_init();
|
||||
|
||||
if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
|
||||
err = osst_sysfs_init();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
|
||||
osst_sysfs_cleanup();
|
||||
return 1;
|
||||
goto err_out;
|
||||
}
|
||||
osst_create_driverfs_files(&osst_template.gendrv);
|
||||
|
||||
err = scsi_register_driver(&osst_template.gendrv);
|
||||
if (err)
|
||||
goto err_out_chrdev;
|
||||
|
||||
err = osst_create_driverfs_files(&osst_template.gendrv);
|
||||
if (err)
|
||||
goto err_out_scsidrv;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_scsidrv:
|
||||
scsi_unregister_driver(&osst_template.gendrv);
|
||||
err_out_chrdev:
|
||||
unregister_chrdev(OSST_MAJOR, "osst");
|
||||
err_out:
|
||||
osst_sysfs_cleanup();
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit exit_osst (void)
|
||||
|
|
|
@ -80,7 +80,6 @@ static int free_ports = 0;
|
|||
module_param(free_ports, bool, 0);
|
||||
MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
|
||||
|
||||
/* /usr/src/linux/drivers/scsi/hosts.h */
|
||||
static struct scsi_host_template nsp_driver_template = {
|
||||
.proc_name = "nsp_cs",
|
||||
.proc_info = nsp_proc_info,
|
||||
|
|
|
@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
|
|||
memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
|
||||
|
||||
/* Set ISP command timeout. */
|
||||
pkt->timeout = cpu_to_le16(30);
|
||||
pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
|
||||
|
||||
/* Set device target ID and LUN */
|
||||
pkt->lun = SCSI_LUN_32(cmd);
|
||||
|
@ -3161,7 +3161,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
|
|||
memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
|
||||
|
||||
/* Set ISP command timeout. */
|
||||
pkt->timeout = cpu_to_le16(30);
|
||||
pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
|
||||
|
||||
/* Set device target ID and LUN */
|
||||
pkt->lun = SCSI_LUN_32(cmd);
|
||||
|
@ -4484,7 +4484,7 @@ qla1280_init(void)
|
|||
qla1280_setup(qla1280);
|
||||
#endif
|
||||
|
||||
return pci_module_init(&qla1280_pci_driver);
|
||||
return pci_register_driver(&qla1280_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
|
|
|
@ -691,13 +691,13 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
|
|||
uint32_t speed = 0;
|
||||
|
||||
switch (ha->link_data_rate) {
|
||||
case LDR_1GB:
|
||||
case PORT_SPEED_1GB:
|
||||
speed = 1;
|
||||
break;
|
||||
case LDR_2GB:
|
||||
case PORT_SPEED_2GB:
|
||||
speed = 2;
|
||||
break;
|
||||
case LDR_4GB:
|
||||
case PORT_SPEED_4GB:
|
||||
speed = 4;
|
||||
break;
|
||||
}
|
||||
|
@ -849,6 +849,49 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
|
|||
return pfc_host_stat;
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
|
||||
{
|
||||
scsi_qla_host_t *ha = to_qla_host(shost);
|
||||
|
||||
qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
|
||||
{
|
||||
scsi_qla_host_t *ha = to_qla_host(shost);
|
||||
|
||||
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
|
||||
{
|
||||
scsi_qla_host_t *ha = to_qla_host(shost);
|
||||
u64 node_name;
|
||||
|
||||
if (ha->device_flags & SWITCH_FOUND)
|
||||
node_name = wwn_to_u64(ha->fabric_node_name);
|
||||
else
|
||||
node_name = wwn_to_u64(ha->node_name);
|
||||
|
||||
fc_host_fabric_name(shost) = node_name;
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_get_host_port_state(struct Scsi_Host *shost)
|
||||
{
|
||||
scsi_qla_host_t *ha = to_qla_host(shost);
|
||||
|
||||
if (!ha->flags.online)
|
||||
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
|
||||
else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT)
|
||||
fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
|
||||
else
|
||||
fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
|
||||
}
|
||||
|
||||
struct fc_function_template qla2xxx_transport_functions = {
|
||||
|
||||
.show_host_node_name = 1,
|
||||
|
@ -861,6 +904,14 @@ struct fc_function_template qla2xxx_transport_functions = {
|
|||
.show_host_speed = 1,
|
||||
.get_host_port_type = qla2x00_get_host_port_type,
|
||||
.show_host_port_type = 1,
|
||||
.get_host_symbolic_name = qla2x00_get_host_symbolic_name,
|
||||
.show_host_symbolic_name = 1,
|
||||
.set_host_system_hostname = qla2x00_set_host_system_hostname,
|
||||
.show_host_system_hostname = 1,
|
||||
.get_host_fabric_name = qla2x00_get_host_fabric_name,
|
||||
.show_host_fabric_name = 1,
|
||||
.get_host_port_state = qla2x00_get_host_port_state,
|
||||
.show_host_port_state = 1,
|
||||
|
||||
.dd_fcrport_size = sizeof(struct fc_port *),
|
||||
.show_rport_supported_classes = 1,
|
||||
|
|
|
@ -608,6 +608,7 @@ typedef struct {
|
|||
*/
|
||||
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
|
||||
#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
|
||||
#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */
|
||||
#define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */
|
||||
#define MBC_TRACE_CONTROL 0x27 /* Trace control command. */
|
||||
#define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */
|
||||
|
@ -1497,6 +1498,9 @@ typedef struct {
|
|||
port_id_t d_id;
|
||||
uint8_t node_name[WWN_SIZE];
|
||||
uint8_t port_name[WWN_SIZE];
|
||||
uint8_t fabric_port_name[WWN_SIZE];
|
||||
uint16_t fp_speeds;
|
||||
uint16_t fp_speed;
|
||||
} sw_info_t;
|
||||
|
||||
/*
|
||||
|
@ -1524,6 +1528,9 @@ typedef struct fc_port {
|
|||
uint16_t loop_id;
|
||||
uint16_t old_loop_id;
|
||||
|
||||
uint8_t fabric_port_name[WWN_SIZE];
|
||||
uint16_t fp_speed;
|
||||
|
||||
fc_port_type_t port_type;
|
||||
|
||||
atomic_t state;
|
||||
|
@ -1635,6 +1642,15 @@ typedef struct fc_port {
|
|||
#define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255)
|
||||
#define RSNN_NN_RSP_SIZE 16
|
||||
|
||||
#define GFPN_ID_CMD 0x11C
|
||||
#define GFPN_ID_REQ_SIZE (16 + 4)
|
||||
#define GFPN_ID_RSP_SIZE (16 + 8)
|
||||
|
||||
#define GPSC_CMD 0x127
|
||||
#define GPSC_REQ_SIZE (16 + 8)
|
||||
#define GPSC_RSP_SIZE (16 + 2 + 2)
|
||||
|
||||
|
||||
/*
|
||||
* HBA attribute types.
|
||||
*/
|
||||
|
@ -1748,7 +1764,7 @@ struct ct_sns_req {
|
|||
uint8_t reserved[3];
|
||||
|
||||
union {
|
||||
/* GA_NXT, GPN_ID, GNN_ID, GFT_ID */
|
||||
/* GA_NXT, GPN_ID, GNN_ID, GFT_ID, GFPN_ID */
|
||||
struct {
|
||||
uint8_t reserved;
|
||||
uint8_t port_id[3];
|
||||
|
@ -1823,6 +1839,10 @@ struct ct_sns_req {
|
|||
struct {
|
||||
uint8_t port_name[8];
|
||||
} dpa;
|
||||
|
||||
struct {
|
||||
uint8_t port_name[8];
|
||||
} gpsc;
|
||||
} req;
|
||||
};
|
||||
|
||||
|
@ -1886,6 +1906,15 @@ struct ct_sns_rsp {
|
|||
uint8_t port_name[8];
|
||||
struct ct_fdmi_hba_attributes attrs;
|
||||
} ghat;
|
||||
|
||||
struct {
|
||||
uint8_t port_name[8];
|
||||
} gfpn_id;
|
||||
|
||||
struct {
|
||||
uint16_t speeds;
|
||||
uint16_t speed;
|
||||
} gpsc;
|
||||
} rsp;
|
||||
};
|
||||
|
||||
|
@ -2182,11 +2211,11 @@ typedef struct scsi_qla_host {
|
|||
uint16_t max_public_loop_ids;
|
||||
uint16_t min_external_loopid; /* First external loop Id */
|
||||
|
||||
#define PORT_SPEED_UNKNOWN 0xFFFF
|
||||
#define PORT_SPEED_1GB 0x00
|
||||
#define PORT_SPEED_2GB 0x01
|
||||
#define PORT_SPEED_4GB 0x03
|
||||
uint16_t link_data_rate; /* F/W operating speed */
|
||||
#define LDR_1GB 0
|
||||
#define LDR_2GB 1
|
||||
#define LDR_4GB 3
|
||||
#define LDR_UNKNOWN 0xFFFF
|
||||
|
||||
uint8_t current_topology;
|
||||
uint8_t prev_topology;
|
||||
|
@ -2333,6 +2362,7 @@ typedef struct scsi_qla_host {
|
|||
|
||||
uint8_t *node_name;
|
||||
uint8_t *port_name;
|
||||
uint8_t fabric_node_name[WWN_SIZE];
|
||||
uint32_t isp_abort_cnt;
|
||||
|
||||
/* Option ROM information. */
|
||||
|
|
|
@ -208,6 +208,12 @@ qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t);
|
|||
extern int
|
||||
qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
|
||||
|
||||
extern int
|
||||
qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
|
||||
|
||||
extern int
|
||||
qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_isr.c source file.
|
||||
*/
|
||||
|
@ -279,6 +285,9 @@ extern int qla2x00_rsnn_nn(scsi_qla_host_t *);
|
|||
extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
|
||||
extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
|
||||
extern int qla2x00_fdmi_register(scsi_qla_host_t *);
|
||||
extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *);
|
||||
extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *);
|
||||
extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_attr.c source file.
|
||||
|
|
|
@ -612,6 +612,14 @@ qla2x00_rnn_id(scsi_qla_host_t *ha)
|
|||
return (rval);
|
||||
}
|
||||
|
||||
void
|
||||
qla2x00_get_sym_node_name(scsi_qla_host_t *ha, uint8_t *snn)
|
||||
{
|
||||
sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number,
|
||||
ha->fw_major_version, ha->fw_minor_version,
|
||||
ha->fw_subminor_version, qla2x00_version_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA.
|
||||
* @ha: HA context
|
||||
|
@ -622,9 +630,6 @@ int
|
|||
qla2x00_rsnn_nn(scsi_qla_host_t *ha)
|
||||
{
|
||||
int rval;
|
||||
uint8_t *snn;
|
||||
uint8_t version[20];
|
||||
|
||||
ms_iocb_entry_t *ms_pkt;
|
||||
struct ct_sns_req *ct_req;
|
||||
struct ct_sns_rsp *ct_rsp;
|
||||
|
@ -649,20 +654,11 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
|
|||
memcpy(ct_req->req.rsnn_nn.node_name, ha->node_name, WWN_SIZE);
|
||||
|
||||
/* Prepare the Symbolic Node Name */
|
||||
/* Board type */
|
||||
snn = ct_req->req.rsnn_nn.sym_node_name;
|
||||
strcpy(snn, ha->model_number);
|
||||
/* Firmware version */
|
||||
strcat(snn, " FW:v");
|
||||
sprintf(version, "%d.%02d.%02d", ha->fw_major_version,
|
||||
ha->fw_minor_version, ha->fw_subminor_version);
|
||||
strcat(snn, version);
|
||||
/* Driver version */
|
||||
strcat(snn, " DVR:v");
|
||||
strcat(snn, qla2x00_version_str);
|
||||
qla2x00_get_sym_node_name(ha, ct_req->req.rsnn_nn.sym_node_name);
|
||||
|
||||
/* Calculate SNN length */
|
||||
ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn);
|
||||
ct_req->req.rsnn_nn.name_len =
|
||||
(uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name);
|
||||
|
||||
/* Update MS IOCB request */
|
||||
ms_pkt->req_bytecount =
|
||||
|
@ -687,7 +683,6 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
|
|||
return (rval);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query.
|
||||
* @ha: HA context
|
||||
|
@ -1585,6 +1580,21 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
|
|||
DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no,
|
||||
eiter->a.os_dev_name));
|
||||
|
||||
/* Hostname. */
|
||||
if (strlen(fc_host_system_hostname(ha->host))) {
|
||||
eiter = (struct ct_fdmi_port_attr *) (entries + size);
|
||||
eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
|
||||
snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
|
||||
"%s", fc_host_system_hostname(ha->host));
|
||||
alen = strlen(eiter->a.host_name);
|
||||
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
|
||||
eiter->len = cpu_to_be16(4 + alen);
|
||||
size += 4 + alen;
|
||||
|
||||
DEBUG13(printk("%s(%ld): HOSTNAME=%s.\n", __func__,
|
||||
ha->host_no, eiter->a.host_name));
|
||||
}
|
||||
|
||||
/* Update MS request size. */
|
||||
qla2x00_update_ms_fdmi_iocb(ha, size + 16);
|
||||
|
||||
|
@ -1647,3 +1657,189 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha)
|
|||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query.
|
||||
* @ha: HA context
|
||||
* @list: switch info entries to populate
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
|
||||
{
|
||||
int rval;
|
||||
uint16_t i;
|
||||
|
||||
ms_iocb_entry_t *ms_pkt;
|
||||
struct ct_sns_req *ct_req;
|
||||
struct ct_sns_rsp *ct_rsp;
|
||||
|
||||
if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
|
||||
/* Issue GFPN_ID */
|
||||
memset(list[i].fabric_port_name, 0, WWN_SIZE);
|
||||
|
||||
/* Prepare common MS IOCB */
|
||||
ms_pkt = qla2x00_prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
|
||||
GFPN_ID_RSP_SIZE);
|
||||
|
||||
/* Prepare CT request */
|
||||
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD,
|
||||
GFPN_ID_RSP_SIZE);
|
||||
ct_rsp = &ha->ct_sns->p.rsp;
|
||||
|
||||
/* Prepare CT arguments -- port_id */
|
||||
ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
|
||||
ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
|
||||
ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
|
||||
|
||||
/* Execute MS IOCB */
|
||||
rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
|
||||
sizeof(ms_iocb_entry_t));
|
||||
if (rval != QLA_SUCCESS) {
|
||||
/*EMPTY*/
|
||||
DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB "
|
||||
"failed (%d).\n", ha->host_no, rval));
|
||||
} else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
|
||||
"GFPN_ID") != QLA_SUCCESS) {
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
} else {
|
||||
/* Save fabric portname */
|
||||
memcpy(list[i].fabric_port_name,
|
||||
ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE);
|
||||
}
|
||||
|
||||
/* Last device exit. */
|
||||
if (list[i].d_id.b.rsvd_1 != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size,
|
||||
uint32_t rsp_size)
|
||||
{
|
||||
struct ct_entry_24xx *ct_pkt;
|
||||
|
||||
ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
|
||||
memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
|
||||
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
|
||||
ct_pkt->timeout = __constant_cpu_to_le16(59);
|
||||
ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
|
||||
|
||||
ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
|
||||
ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
|
||||
ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
|
||||
|
||||
ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
|
||||
ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
|
||||
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
|
||||
|
||||
return ct_pkt;
|
||||
}
|
||||
|
||||
|
||||
static inline struct ct_sns_req *
|
||||
qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd,
|
||||
uint16_t rsp_size)
|
||||
{
|
||||
memset(ct_req, 0, sizeof(struct ct_sns_pkt));
|
||||
|
||||
ct_req->header.revision = 0x01;
|
||||
ct_req->header.gs_type = 0xFA;
|
||||
ct_req->header.gs_subtype = 0x01;
|
||||
ct_req->command = cpu_to_be16(cmd);
|
||||
ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
|
||||
|
||||
return ct_req;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query.
|
||||
* @ha: HA context
|
||||
* @list: switch info entries to populate
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
|
||||
{
|
||||
int rval;
|
||||
uint16_t i;
|
||||
|
||||
ms_iocb_entry_t *ms_pkt;
|
||||
struct ct_sns_req *ct_req;
|
||||
struct ct_sns_rsp *ct_rsp;
|
||||
|
||||
if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
rval = qla2x00_mgmt_svr_login(ha);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
||||
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
|
||||
/* Issue GFPN_ID */
|
||||
list[i].fp_speeds = list[i].fp_speed = 0;
|
||||
|
||||
/* Prepare common MS IOCB */
|
||||
ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE,
|
||||
GPSC_RSP_SIZE);
|
||||
|
||||
/* Prepare CT request */
|
||||
ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req,
|
||||
GPSC_CMD, GPSC_RSP_SIZE);
|
||||
ct_rsp = &ha->ct_sns->p.rsp;
|
||||
|
||||
/* Prepare CT arguments -- port_name */
|
||||
memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name,
|
||||
WWN_SIZE);
|
||||
|
||||
/* Execute MS IOCB */
|
||||
rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
|
||||
sizeof(ms_iocb_entry_t));
|
||||
if (rval != QLA_SUCCESS) {
|
||||
/*EMPTY*/
|
||||
DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB "
|
||||
"failed (%d).\n", ha->host_no, rval));
|
||||
} else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
|
||||
"GPSC") != QLA_SUCCESS) {
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
} else {
|
||||
/* Save portname */
|
||||
list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds;
|
||||
list[i].fp_speed = ct_rsp->rsp.gpsc.speed;
|
||||
|
||||
DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
|
||||
"fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
|
||||
"speed=%04x.\n", ha->host_no,
|
||||
list[i].fabric_port_name[0],
|
||||
list[i].fabric_port_name[1],
|
||||
list[i].fabric_port_name[2],
|
||||
list[i].fabric_port_name[3],
|
||||
list[i].fabric_port_name[4],
|
||||
list[i].fabric_port_name[5],
|
||||
list[i].fabric_port_name[6],
|
||||
list[i].fabric_port_name[7],
|
||||
be16_to_cpu(list[i].fp_speeds),
|
||||
be16_to_cpu(list[i].fp_speed)));
|
||||
}
|
||||
|
||||
/* Last device exit. */
|
||||
if (list[i].d_id.b.rsvd_1 != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return (rval);
|
||||
}
|
||||
|
|
|
@ -2074,6 +2074,19 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
|
|||
new_fcport->flags &= ~FCF_FABRIC_DEVICE;
|
||||
}
|
||||
|
||||
/* Base iIDMA settings on HBA port speed. */
|
||||
switch (ha->link_data_rate) {
|
||||
case PORT_SPEED_1GB:
|
||||
fcport->fp_speed = cpu_to_be16(BIT_15);
|
||||
break;
|
||||
case PORT_SPEED_2GB:
|
||||
fcport->fp_speed = cpu_to_be16(BIT_14);
|
||||
break;
|
||||
case PORT_SPEED_4GB:
|
||||
fcport->fp_speed = cpu_to_be16(BIT_13);
|
||||
break;
|
||||
}
|
||||
|
||||
qla2x00_update_fcport(ha, fcport);
|
||||
|
||||
found_devs++;
|
||||
|
@ -2109,6 +2122,62 @@ qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
|
||||
{
|
||||
#define LS_UNKNOWN 2
|
||||
static char *link_speeds[5] = { "1", "2", "?", "4" };
|
||||
int rval;
|
||||
uint16_t port_speed, mb[6];
|
||||
|
||||
if (!IS_QLA24XX(ha))
|
||||
return;
|
||||
|
||||
switch (be16_to_cpu(fcport->fp_speed)) {
|
||||
case BIT_15:
|
||||
port_speed = PORT_SPEED_1GB;
|
||||
break;
|
||||
case BIT_14:
|
||||
port_speed = PORT_SPEED_2GB;
|
||||
break;
|
||||
case BIT_13:
|
||||
port_speed = PORT_SPEED_4GB;
|
||||
break;
|
||||
default:
|
||||
DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
|
||||
"unsupported FM port operating speed (%04x).\n",
|
||||
ha->host_no, fcport->port_name[0], fcport->port_name[1],
|
||||
fcport->port_name[2], fcport->port_name[3],
|
||||
fcport->port_name[4], fcport->port_name[5],
|
||||
fcport->port_name[6], fcport->port_name[7],
|
||||
be16_to_cpu(fcport->fp_speed)));
|
||||
port_speed = PORT_SPEED_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (port_speed == PORT_SPEED_UNKNOWN)
|
||||
return;
|
||||
|
||||
rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
|
||||
ha->host_no, fcport->port_name[0], fcport->port_name[1],
|
||||
fcport->port_name[2], fcport->port_name[3],
|
||||
fcport->port_name[4], fcport->port_name[5],
|
||||
fcport->port_name[6], fcport->port_name[7], rval,
|
||||
port_speed, mb[0], mb[1]));
|
||||
} else {
|
||||
DEBUG2(qla_printk(KERN_INFO, ha,
|
||||
"iIDMA adjusted to %s GB/s on "
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x.\n",
|
||||
link_speeds[port_speed], fcport->port_name[0],
|
||||
fcport->port_name[1], fcport->port_name[2],
|
||||
fcport->port_name[3], fcport->port_name[4],
|
||||
fcport->port_name[5], fcport->port_name[6],
|
||||
fcport->port_name[7]));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* qla2x00_update_fcport
|
||||
* Updates device on list.
|
||||
|
@ -2135,6 +2204,8 @@ qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
|
|||
PORT_RETRY_TIME);
|
||||
fcport->flags &= ~FCF_LOGIN_NEEDED;
|
||||
|
||||
qla2x00_iidma_fcport(ha, fcport);
|
||||
|
||||
atomic_set(&fcport->state, FCS_ONLINE);
|
||||
|
||||
if (ha->flags.init_done)
|
||||
|
@ -2209,7 +2280,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
|
|||
loop_id = NPH_F_PORT;
|
||||
else
|
||||
loop_id = SNS_FL_PORT;
|
||||
rval = qla2x00_get_port_name(ha, loop_id, NULL, 0);
|
||||
rval = qla2x00_get_port_name(ha, loop_id, ha->fabric_node_name, 1);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
|
||||
"Port\n", ha->host_no));
|
||||
|
@ -2217,6 +2288,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
|
|||
ha->device_flags &= ~SWITCH_FOUND;
|
||||
return (QLA_SUCCESS);
|
||||
}
|
||||
ha->device_flags |= SWITCH_FOUND;
|
||||
|
||||
/* Mark devices that need re-synchronization. */
|
||||
rval2 = qla2x00_device_resync(ha);
|
||||
|
@ -2416,6 +2488,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
|
|||
} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
|
||||
kfree(swl);
|
||||
swl = NULL;
|
||||
} else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
|
||||
qla2x00_gpsc(ha, swl);
|
||||
}
|
||||
}
|
||||
swl_idx = 0;
|
||||
|
@ -2450,6 +2524,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
|
|||
swl[swl_idx].node_name, WWN_SIZE);
|
||||
memcpy(new_fcport->port_name,
|
||||
swl[swl_idx].port_name, WWN_SIZE);
|
||||
memcpy(new_fcport->fabric_port_name,
|
||||
swl[swl_idx].fabric_port_name, WWN_SIZE);
|
||||
new_fcport->fp_speed = swl[swl_idx].fp_speed;
|
||||
|
||||
if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
|
||||
last_dev = 1;
|
||||
|
@ -2507,6 +2584,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
|
|||
|
||||
found++;
|
||||
|
||||
/* Update port state. */
|
||||
memcpy(fcport->fabric_port_name,
|
||||
new_fcport->fabric_port_name, WWN_SIZE);
|
||||
fcport->fp_speed = new_fcport->fp_speed;
|
||||
|
||||
/*
|
||||
* If address the same and state FCS_ONLINE, nothing
|
||||
* changed.
|
||||
|
|
|
@ -400,7 +400,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
|||
case MBA_LOOP_UP: /* Loop Up Event */
|
||||
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
|
||||
link_speed = link_speeds[0];
|
||||
ha->link_data_rate = LDR_1GB;
|
||||
ha->link_data_rate = PORT_SPEED_1GB;
|
||||
} else {
|
||||
link_speed = link_speeds[LS_UNKNOWN];
|
||||
if (mb[1] < 5)
|
||||
|
@ -429,7 +429,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
|||
}
|
||||
|
||||
ha->flags.management_server_logged_in = 0;
|
||||
ha->link_data_rate = LDR_UNKNOWN;
|
||||
ha->link_data_rate = PORT_SPEED_UNKNOWN;
|
||||
if (ql2xfdmienable)
|
||||
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
|
||||
break;
|
||||
|
|
|
@ -2540,3 +2540,89 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
|
|||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
|
||||
uint16_t *port_speed, uint16_t *mb)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA24XX(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
|
||||
|
||||
mcp->mb[0] = MBC_PORT_PARAMS;
|
||||
mcp->mb[1] = loop_id;
|
||||
mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0;
|
||||
mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
|
||||
mcp->tov = 30;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(ha, mcp);
|
||||
|
||||
/* Return mailbox statuses. */
|
||||
if (mb != NULL) {
|
||||
mb[0] = mcp->mb[0];
|
||||
mb[1] = mcp->mb[1];
|
||||
mb[3] = mcp->mb[3];
|
||||
mb[4] = mcp->mb[4];
|
||||
mb[5] = mcp->mb[5];
|
||||
}
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
|
||||
ha->host_no, rval));
|
||||
} else {
|
||||
DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
|
||||
if (port_speed)
|
||||
*port_speed = mcp->mb[3];
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
|
||||
uint16_t port_speed, uint16_t *mb)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA24XX(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
|
||||
|
||||
mcp->mb[0] = MBC_PORT_PARAMS;
|
||||
mcp->mb[1] = loop_id;
|
||||
mcp->mb[2] = BIT_0;
|
||||
mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
|
||||
mcp->mb[4] = mcp->mb[5] = 0;
|
||||
mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
|
||||
mcp->tov = 30;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(ha, mcp);
|
||||
|
||||
/* Return mailbox statuses. */
|
||||
if (mb != NULL) {
|
||||
mb[0] = mcp->mb[0];
|
||||
mb[1] = mcp->mb[1];
|
||||
mb[3] = mcp->mb[3];
|
||||
mb[4] = mcp->mb[4];
|
||||
mb[5] = mcp->mb[5];
|
||||
}
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
|
||||
ha->host_no, rval));
|
||||
} else {
|
||||
DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
|
|
@ -589,6 +589,23 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
|
|||
return (return_status);
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
struct Scsi_Host *shost = cmnd->device->host;
|
||||
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
while (rport->port_state == FC_PORTSTATE_BLOCKED) {
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
msleep(1000);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* qla2xxx_eh_abort
|
||||
*
|
||||
|
@ -615,6 +632,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
|
|||
unsigned long flags;
|
||||
int wait = 0;
|
||||
|
||||
qla2x00_block_error_handler(cmd);
|
||||
|
||||
if (!CMD_SP(cmd))
|
||||
return SUCCESS;
|
||||
|
||||
|
@ -748,6 +767,8 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
|
|||
unsigned int id, lun;
|
||||
unsigned long serial;
|
||||
|
||||
qla2x00_block_error_handler(cmd);
|
||||
|
||||
ret = FAILED;
|
||||
|
||||
id = cmd->device->id;
|
||||
|
@ -877,6 +898,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
|
|||
unsigned int id, lun;
|
||||
unsigned long serial;
|
||||
|
||||
qla2x00_block_error_handler(cmd);
|
||||
|
||||
ret = FAILED;
|
||||
|
||||
id = cmd->device->id;
|
||||
|
@ -936,6 +959,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
|
|||
unsigned int id, lun;
|
||||
unsigned long serial;
|
||||
|
||||
qla2x00_block_error_handler(cmd);
|
||||
|
||||
ret = FAILED;
|
||||
|
||||
id = cmd->device->id;
|
||||
|
@ -1385,7 +1410,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
ha->prev_topology = 0;
|
||||
ha->init_cb_size = sizeof(init_cb_t);
|
||||
ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
|
||||
ha->link_data_rate = LDR_UNKNOWN;
|
||||
ha->link_data_rate = PORT_SPEED_UNKNOWN;
|
||||
ha->optrom_size = OPTROM_SIZE_2300;
|
||||
|
||||
/* Assign ISP specific operations. */
|
||||
|
@ -2564,14 +2589,20 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
|
|||
#define FW_ISP2322 3
|
||||
#define FW_ISP24XX 4
|
||||
|
||||
#define FW_FILE_ISP21XX "ql2100_fw.bin"
|
||||
#define FW_FILE_ISP22XX "ql2200_fw.bin"
|
||||
#define FW_FILE_ISP2300 "ql2300_fw.bin"
|
||||
#define FW_FILE_ISP2322 "ql2322_fw.bin"
|
||||
#define FW_FILE_ISP24XX "ql2400_fw.bin"
|
||||
|
||||
static DECLARE_MUTEX(qla_fw_lock);
|
||||
|
||||
static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
|
||||
{ .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, },
|
||||
{ .name = "ql2200_fw.bin", .segs = { 0x1000, 0 }, },
|
||||
{ .name = "ql2300_fw.bin", .segs = { 0x800, 0 }, },
|
||||
{ .name = "ql2322_fw.bin", .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
|
||||
{ .name = "ql2400_fw.bin", },
|
||||
{ .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, },
|
||||
{ .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, },
|
||||
{ .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
|
||||
{ .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
|
||||
{ .name = FW_FILE_ISP24XX, },
|
||||
};
|
||||
|
||||
struct fw_blob *
|
||||
|
@ -2702,3 +2733,8 @@ MODULE_AUTHOR("QLogic Corporation");
|
|||
MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(QLA2XXX_VERSION);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP21XX);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP22XX);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP2300);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP2322);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP24XX);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
/*
|
||||
* Driver version
|
||||
*/
|
||||
#define QLA2XXX_VERSION "8.01.07-k1"
|
||||
#define QLA2XXX_VERSION "8.01.07-k2"
|
||||
|
||||
#define QLA_DRIVER_MAJOR_VER 8
|
||||
#define QLA_DRIVER_MINOR_VER 1
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
config SCSI_QLA_ISCSI
|
||||
tristate "QLogic ISP4XXX host adapter family support"
|
||||
depends on PCI && SCSI
|
||||
select SCSI_ISCSI_ATTRS
|
||||
---help---
|
||||
This driver supports the QLogic 40xx (ISP4XXX) iSCSI host
|
||||
adapter family.
|
|
@ -0,0 +1,5 @@
|
|||
qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
|
||||
ql4_nvram.o ql4_dbg.o
|
||||
|
||||
obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#include "ql4_def.h"
|
||||
#include <scsi/scsi_dbg.h>
|
||||
|
||||
static void qla4xxx_print_srb_info(struct srb * srb)
|
||||
{
|
||||
printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
|
||||
printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n",
|
||||
__func__, srb->cmd, (unsigned long) srb->dma_handle);
|
||||
printk("%s: fw_ddb_index = %d, lun = %d\n",
|
||||
__func__, srb->fw_ddb_index, srb->cmd->device->lun);
|
||||
printk("%s: iocb_tov = %d\n",
|
||||
__func__, srb->iocb_tov);
|
||||
printk("%s: cc_stat = 0x%x, r_start = 0x%lx, u_start = 0x%lx\n\n",
|
||||
__func__, srb->cc_stat, srb->r_start, srb->u_start);
|
||||
}
|
||||
|
||||
void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd)
|
||||
{
|
||||
printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
|
||||
printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n",
|
||||
cmd->device->channel, cmd->device->id, cmd->device->lun,
|
||||
cmd->cmd_len);
|
||||
scsi_print_command(cmd);
|
||||
printk(" seg_cnt = %d\n", cmd->use_sg);
|
||||
printk(" request buffer = 0x%p, request buffer len = 0x%x\n",
|
||||
cmd->request_buffer, cmd->request_bufflen);
|
||||
if (cmd->use_sg) {
|
||||
struct scatterlist *sg;
|
||||
sg = (struct scatterlist *)cmd->request_buffer;
|
||||
printk(" SG buffer: \n");
|
||||
qla4xxx_dump_buffer((caddr_t) sg,
|
||||
(cmd->use_sg * sizeof(*sg)));
|
||||
}
|
||||
printk(" tag = %d, transfersize = 0x%x \n", cmd->tag,
|
||||
cmd->transfersize);
|
||||
printk(" Pid = %d, SP = 0x%p\n", (int)cmd->pid, cmd->SCp.ptr);
|
||||
printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow,
|
||||
cmd->sc_data_direction);
|
||||
printk(" Current time (jiffies) = 0x%lx, "
|
||||
"timeout expires = 0x%lx\n", jiffies, cmd->eh_timeout.expires);
|
||||
qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr);
|
||||
}
|
||||
|
||||
void __dump_registers(struct scsi_qla_host *ha)
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < MBOX_REG_COUNT; i++) {
|
||||
printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
|
||||
readw(&ha->reg->mailbox[i]));
|
||||
}
|
||||
printk(KERN_INFO "0x%02X flash_address = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, flash_address),
|
||||
readw(&ha->reg->flash_address));
|
||||
printk(KERN_INFO "0x%02X flash_data = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, flash_data),
|
||||
readw(&ha->reg->flash_data));
|
||||
printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, ctrl_status),
|
||||
readw(&ha->reg->ctrl_status));
|
||||
if (is_qla4010(ha)) {
|
||||
printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
|
||||
readw(&ha->reg->u1.isp4010.nvram));
|
||||
}
|
||||
|
||||
else if (is_qla4022(ha)) {
|
||||
printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u1.isp4022.intr_mask),
|
||||
readw(&ha->reg->u1.isp4022.intr_mask));
|
||||
printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
|
||||
readw(&ha->reg->u1.isp4022.nvram));
|
||||
printk(KERN_INFO "0x%02X semaphore = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u1.isp4022.semaphore),
|
||||
readw(&ha->reg->u1.isp4022.semaphore));
|
||||
}
|
||||
printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, req_q_in),
|
||||
readw(&ha->reg->req_q_in));
|
||||
printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, rsp_q_out),
|
||||
readw(&ha->reg->rsp_q_out));
|
||||
if (is_qla4010(ha)) {
|
||||
printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4010.ext_hw_conf),
|
||||
readw(&ha->reg->u2.isp4010.ext_hw_conf));
|
||||
printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4010.port_ctrl),
|
||||
readw(&ha->reg->u2.isp4010.port_ctrl));
|
||||
printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4010.port_status),
|
||||
readw(&ha->reg->u2.isp4010.port_status));
|
||||
printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4010.req_q_out),
|
||||
readw(&ha->reg->u2.isp4010.req_q_out));
|
||||
printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
|
||||
readw(&ha->reg->u2.isp4010.gp_out));
|
||||
printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
|
||||
readw(&ha->reg->u2.isp4010.gp_in));
|
||||
printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4010.port_err_status),
|
||||
readw(&ha->reg->u2.isp4010.port_err_status));
|
||||
}
|
||||
|
||||
else if (is_qla4022(ha)) {
|
||||
printk(KERN_INFO "Page 0 Registers:\n");
|
||||
printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4022.p0.ext_hw_conf),
|
||||
readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
|
||||
printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4022.p0.port_ctrl),
|
||||
readw(&ha->reg->u2.isp4022.p0.port_ctrl));
|
||||
printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4022.p0.port_status),
|
||||
readw(&ha->reg->u2.isp4022.p0.port_status));
|
||||
printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4022.p0.gp_out),
|
||||
readw(&ha->reg->u2.isp4022.p0.gp_out));
|
||||
printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
|
||||
readw(&ha->reg->u2.isp4022.p0.gp_in));
|
||||
printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4022.p0.port_err_status),
|
||||
readw(&ha->reg->u2.isp4022.p0.port_err_status));
|
||||
printk(KERN_INFO "Page 1 Registers:\n");
|
||||
writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
|
||||
&ha->reg->ctrl_status);
|
||||
printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
|
||||
(uint8_t) offsetof(struct isp_reg,
|
||||
u2.isp4022.p1.req_q_out),
|
||||
readw(&ha->reg->u2.isp4022.p1.req_q_out));
|
||||
writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
|
||||
&ha->reg->ctrl_status);
|
||||
}
|
||||
}
|
||||
|
||||
void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
int i = 0;
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
for (i = 1; i < MBOX_REG_COUNT; i++)
|
||||
printk(KERN_INFO " Mailbox[%d] = %08x\n", i,
|
||||
readw(&ha->reg->mailbox[i]));
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
||||
|
||||
void qla4xxx_dump_registers(struct scsi_qla_host *ha)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
__dump_registers(ha);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
||||
|
||||
void qla4xxx_dump_buffer(void *b, uint32_t size)
|
||||
{
|
||||
uint32_t cnt;
|
||||
uint8_t *c = b;
|
||||
|
||||
printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh "
|
||||
"Fh\n");
|
||||
printk("------------------------------------------------------------"
|
||||
"--\n");
|
||||
for (cnt = 0; cnt < size; cnt++, c++) {
|
||||
printk(KERN_DEBUG "%02x", *c);
|
||||
if (!(cnt % 16))
|
||||
printk(KERN_DEBUG "\n");
|
||||
|
||||
else
|
||||
printk(KERN_DEBUG " ");
|
||||
}
|
||||
if (cnt % 16)
|
||||
printk(KERN_DEBUG "\n");
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Driver debug definitions.
|
||||
*/
|
||||
/* #define QL_DEBUG */ /* DEBUG messages */
|
||||
/* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */
|
||||
/* #define QL_DEBUG_LEVEL_4 */
|
||||
/* #define QL_DEBUG_LEVEL_5 */
|
||||
/* #define QL_DEBUG_LEVEL_9 */
|
||||
|
||||
#define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */
|
||||
#if defined(QL_DEBUG)
|
||||
#define DEBUG(x) do {x;} while (0);
|
||||
#else
|
||||
#define DEBUG(x) do {} while (0);
|
||||
#endif
|
||||
|
||||
#if defined(QL_DEBUG_LEVEL_2)
|
||||
#define DEBUG2(x) do {if(extended_error_logging == 2) x;} while (0);
|
||||
#define DEBUG2_3(x) do {x;} while (0);
|
||||
#else /* */
|
||||
#define DEBUG2(x) do {} while (0);
|
||||
#endif /* */
|
||||
|
||||
#if defined(QL_DEBUG_LEVEL_3)
|
||||
#define DEBUG3(x) do {if(extended_error_logging == 3) x;} while (0);
|
||||
#else /* */
|
||||
#define DEBUG3(x) do {} while (0);
|
||||
#if !defined(QL_DEBUG_LEVEL_2)
|
||||
#define DEBUG2_3(x) do {} while (0);
|
||||
#endif /* */
|
||||
#endif /* */
|
||||
#if defined(QL_DEBUG_LEVEL_4)
|
||||
#define DEBUG4(x) do {x;} while (0);
|
||||
#else /* */
|
||||
#define DEBUG4(x) do {} while (0);
|
||||
#endif /* */
|
||||
|
||||
#if defined(QL_DEBUG_LEVEL_5)
|
||||
#define DEBUG5(x) do {x;} while (0);
|
||||
#else /* */
|
||||
#define DEBUG5(x) do {} while (0);
|
||||
#endif /* */
|
||||
|
||||
#if defined(QL_DEBUG_LEVEL_9)
|
||||
#define DEBUG9(x) do {x;} while (0);
|
||||
#else /* */
|
||||
#define DEBUG9(x) do {} while (0);
|
||||
#endif /* */
|
|
@ -0,0 +1,586 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#ifndef __QL4_DEF_H
|
||||
#define __QL4_DEF_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <net/tcp.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_transport.h>
|
||||
#include <scsi/scsi_transport_iscsi.h>
|
||||
|
||||
|
||||
#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010
|
||||
#endif
|
||||
|
||||
#ifndef PCI_DEVICE_ID_QLOGIC_ISP4022
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP4022 0x4022
|
||||
#endif /* */
|
||||
|
||||
#define QLA_SUCCESS 0
|
||||
#define QLA_ERROR 1
|
||||
|
||||
/*
|
||||
* Data bit definitions
|
||||
*/
|
||||
#define BIT_0 0x1
|
||||
#define BIT_1 0x2
|
||||
#define BIT_2 0x4
|
||||
#define BIT_3 0x8
|
||||
#define BIT_4 0x10
|
||||
#define BIT_5 0x20
|
||||
#define BIT_6 0x40
|
||||
#define BIT_7 0x80
|
||||
#define BIT_8 0x100
|
||||
#define BIT_9 0x200
|
||||
#define BIT_10 0x400
|
||||
#define BIT_11 0x800
|
||||
#define BIT_12 0x1000
|
||||
#define BIT_13 0x2000
|
||||
#define BIT_14 0x4000
|
||||
#define BIT_15 0x8000
|
||||
#define BIT_16 0x10000
|
||||
#define BIT_17 0x20000
|
||||
#define BIT_18 0x40000
|
||||
#define BIT_19 0x80000
|
||||
#define BIT_20 0x100000
|
||||
#define BIT_21 0x200000
|
||||
#define BIT_22 0x400000
|
||||
#define BIT_23 0x800000
|
||||
#define BIT_24 0x1000000
|
||||
#define BIT_25 0x2000000
|
||||
#define BIT_26 0x4000000
|
||||
#define BIT_27 0x8000000
|
||||
#define BIT_28 0x10000000
|
||||
#define BIT_29 0x20000000
|
||||
#define BIT_30 0x40000000
|
||||
#define BIT_31 0x80000000
|
||||
|
||||
/*
|
||||
* Host adapter default definitions
|
||||
***********************************/
|
||||
#define MAX_HBAS 16
|
||||
#define MAX_BUSES 1
|
||||
#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
|
||||
#define MAX_LUNS 0xffff
|
||||
#define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */
|
||||
#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
|
||||
#define MAX_PDU_ENTRIES 32
|
||||
#define INVALID_ENTRY 0xFFFF
|
||||
#define MAX_CMDS_TO_RISC 1024
|
||||
#define MAX_SRBS MAX_CMDS_TO_RISC
|
||||
#define MBOX_AEN_REG_COUNT 5
|
||||
#define MAX_INIT_RETRIES 5
|
||||
#define IOCB_HIWAT_CUSHION 16
|
||||
|
||||
/*
|
||||
* Buffer sizes
|
||||
*/
|
||||
#define REQUEST_QUEUE_DEPTH MAX_CMDS_TO_RISC
|
||||
#define RESPONSE_QUEUE_DEPTH 64
|
||||
#define QUEUE_SIZE 64
|
||||
#define DMA_BUFFER_SIZE 512
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
#define MAC_ADDR_LEN 6 /* in bytes */
|
||||
#define IP_ADDR_LEN 4 /* in bytes */
|
||||
#define DRIVER_NAME "qla4xxx"
|
||||
|
||||
#define MAX_LINKED_CMDS_PER_LUN 3
|
||||
#define MAX_REQS_SERVICED_PER_INTR 16
|
||||
|
||||
#define ISCSI_IPADDR_SIZE 4 /* IP address size */
|
||||
#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */
|
||||
#define ISCSI_NAME_SIZE 255 /* ISCSI Name size -
|
||||
* usually a string */
|
||||
|
||||
#define LSDW(x) ((u32)((u64)(x)))
|
||||
#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
|
||||
|
||||
/*
|
||||
* Retry & Timeout Values
|
||||
*/
|
||||
#define MBOX_TOV 60
|
||||
#define SOFT_RESET_TOV 30
|
||||
#define RESET_INTR_TOV 3
|
||||
#define SEMAPHORE_TOV 10
|
||||
#define ADAPTER_INIT_TOV 120
|
||||
#define ADAPTER_RESET_TOV 180
|
||||
#define EXTEND_CMD_TOV 60
|
||||
#define WAIT_CMD_TOV 30
|
||||
#define EH_WAIT_CMD_TOV 120
|
||||
#define FIRMWARE_UP_TOV 60
|
||||
#define RESET_FIRMWARE_TOV 30
|
||||
#define LOGOUT_TOV 10
|
||||
#define IOCB_TOV_MARGIN 10
|
||||
#define RELOGIN_TOV 18
|
||||
#define ISNS_DEREG_TOV 5
|
||||
|
||||
#define MAX_RESET_HA_RETRIES 2
|
||||
|
||||
/*
|
||||
* SCSI Request Block structure (srb) that is placed
|
||||
* on cmd->SCp location of every I/O [We have 22 bytes available]
|
||||
*/
|
||||
struct srb {
|
||||
struct list_head list; /* (8) */
|
||||
struct scsi_qla_host *ha; /* HA the SP is queued on */
|
||||
struct ddb_entry *ddb;
|
||||
uint16_t flags; /* (1) Status flags. */
|
||||
|
||||
#define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */
|
||||
#define SRB_GOT_SENSE BIT_4 /* sense data recieved. */
|
||||
uint8_t state; /* (1) Status flags. */
|
||||
|
||||
#define SRB_NO_QUEUE_STATE 0 /* Request is in between states */
|
||||
#define SRB_FREE_STATE 1
|
||||
#define SRB_ACTIVE_STATE 3
|
||||
#define SRB_ACTIVE_TIMEOUT_STATE 4
|
||||
#define SRB_SUSPENDED_STATE 7 /* Request in suspended state */
|
||||
|
||||
struct scsi_cmnd *cmd; /* (4) SCSI command block */
|
||||
dma_addr_t dma_handle; /* (4) for unmap of single transfers */
|
||||
atomic_t ref_count; /* reference count for this srb */
|
||||
uint32_t fw_ddb_index;
|
||||
uint8_t err_id; /* error id */
|
||||
#define SRB_ERR_PORT 1 /* Request failed because "port down" */
|
||||
#define SRB_ERR_LOOP 2 /* Request failed because "loop down" */
|
||||
#define SRB_ERR_DEVICE 3 /* Request failed because "device error" */
|
||||
#define SRB_ERR_OTHER 4
|
||||
|
||||
uint16_t reserved;
|
||||
uint16_t iocb_tov;
|
||||
uint16_t iocb_cnt; /* Number of used iocbs */
|
||||
uint16_t cc_stat;
|
||||
u_long r_start; /* Time we recieve a cmd from OS */
|
||||
u_long u_start; /* Time when we handed the cmd to F/W */
|
||||
};
|
||||
|
||||
/*
|
||||
* Device Database (DDB) structure
|
||||
*/
|
||||
struct ddb_entry {
|
||||
struct list_head list; /* ddb list */
|
||||
struct scsi_qla_host *ha;
|
||||
struct iscsi_cls_session *sess;
|
||||
struct iscsi_cls_conn *conn;
|
||||
|
||||
atomic_t state; /* DDB State */
|
||||
|
||||
unsigned long flags; /* DDB Flags */
|
||||
|
||||
unsigned long dev_scan_wait_to_start_relogin;
|
||||
unsigned long dev_scan_wait_to_complete_relogin;
|
||||
|
||||
uint16_t os_target_id; /* Target ID */
|
||||
uint16_t fw_ddb_index; /* DDB firmware index */
|
||||
uint8_t reserved[2];
|
||||
uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */
|
||||
|
||||
uint32_t CmdSn;
|
||||
uint16_t target_session_id;
|
||||
uint16_t connection_id;
|
||||
uint16_t exe_throttle; /* Max mumber of cmds outstanding
|
||||
* simultaneously */
|
||||
uint16_t task_mgmt_timeout; /* Min time for task mgmt cmds to
|
||||
* complete */
|
||||
uint16_t default_relogin_timeout; /* Max time to wait for
|
||||
* relogin to complete */
|
||||
uint16_t tcp_source_port_num;
|
||||
uint32_t default_time2wait; /* Default Min time between
|
||||
* relogins (+aens) */
|
||||
|
||||
atomic_t port_down_timer; /* Device connection timer */
|
||||
atomic_t retry_relogin_timer; /* Min Time between relogins
|
||||
* (4000 only) */
|
||||
atomic_t relogin_timer; /* Max Time to wait for relogin to complete */
|
||||
atomic_t relogin_retry_count; /* Num of times relogin has been
|
||||
* retried */
|
||||
|
||||
uint16_t port;
|
||||
uint32_t tpgt;
|
||||
uint8_t ip_addr[ISCSI_IPADDR_SIZE];
|
||||
uint8_t iscsi_name[ISCSI_NAME_SIZE]; /* 72 x48 */
|
||||
uint8_t iscsi_alias[0x20];
|
||||
};
|
||||
|
||||
/*
|
||||
* DDB states.
|
||||
*/
|
||||
#define DDB_STATE_DEAD 0 /* We can no longer talk to
|
||||
* this device */
|
||||
#define DDB_STATE_ONLINE 1 /* Device ready to accept
|
||||
* commands */
|
||||
#define DDB_STATE_MISSING 2 /* Device logged off, trying
|
||||
* to re-login */
|
||||
|
||||
/*
|
||||
* DDB flags.
|
||||
*/
|
||||
#define DF_RELOGIN 0 /* Relogin to device */
|
||||
#define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL
|
||||
* logged it out */
|
||||
#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */
|
||||
#define DF_FO_MASKED 3
|
||||
|
||||
/*
|
||||
* Asynchronous Event Queue structure
|
||||
*/
|
||||
struct aen {
|
||||
uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
|
||||
};
|
||||
|
||||
|
||||
#include "ql4_fw.h"
|
||||
#include "ql4_nvram.h"
|
||||
|
||||
/*
|
||||
* Linux Host Adapter structure
|
||||
*/
|
||||
struct scsi_qla_host {
|
||||
/* Linux adapter configuration data */
|
||||
struct Scsi_Host *host; /* pointer to host data */
|
||||
uint32_t tot_ddbs;
|
||||
unsigned long flags;
|
||||
|
||||
#define AF_ONLINE 0 /* 0x00000001 */
|
||||
#define AF_INIT_DONE 1 /* 0x00000002 */
|
||||
#define AF_MBOX_COMMAND 2 /* 0x00000004 */
|
||||
#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
|
||||
#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */
|
||||
#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
|
||||
#define AF_LINK_UP 8 /* 0x00000100 */
|
||||
#define AF_TOPCAT_CHIP_PRESENT 9 /* 0x00000200 */
|
||||
#define AF_IRQ_ATTACHED 10 /* 0x00000400 */
|
||||
#define AF_ISNS_CMD_IN_PROCESS 12 /* 0x00001000 */
|
||||
#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */
|
||||
|
||||
unsigned long dpc_flags;
|
||||
|
||||
#define DPC_RESET_HA 1 /* 0x00000002 */
|
||||
#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */
|
||||
#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */
|
||||
#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */
|
||||
#define DPC_RESET_HA_INTR 5 /* 0x00000020 */
|
||||
#define DPC_ISNS_RESTART 7 /* 0x00000080 */
|
||||
#define DPC_AEN 9 /* 0x00000200 */
|
||||
#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
|
||||
|
||||
uint16_t iocb_cnt;
|
||||
uint16_t iocb_hiwat;
|
||||
|
||||
/* SRB cache. */
|
||||
#define SRB_MIN_REQ 128
|
||||
mempool_t *srb_mempool;
|
||||
|
||||
/* pci information */
|
||||
struct pci_dev *pdev;
|
||||
|
||||
struct isp_reg __iomem *reg; /* Base I/O address */
|
||||
unsigned long pio_address;
|
||||
unsigned long pio_length;
|
||||
#define MIN_IOBASE_LEN 0x100
|
||||
|
||||
uint16_t req_q_count;
|
||||
uint8_t marker_needed;
|
||||
uint8_t rsvd1;
|
||||
|
||||
unsigned long host_no;
|
||||
|
||||
/* NVRAM registers */
|
||||
struct eeprom_data *nvram;
|
||||
spinlock_t hardware_lock ____cacheline_aligned;
|
||||
spinlock_t list_lock;
|
||||
uint32_t eeprom_cmd_data;
|
||||
|
||||
/* Counters for general statistics */
|
||||
uint64_t adapter_error_count;
|
||||
uint64_t device_error_count;
|
||||
uint64_t total_io_count;
|
||||
uint64_t total_mbytes_xferred;
|
||||
uint64_t link_failure_count;
|
||||
uint64_t invalid_crc_count;
|
||||
uint32_t spurious_int_count;
|
||||
uint32_t aborted_io_count;
|
||||
uint32_t io_timeout_count;
|
||||
uint32_t mailbox_timeout_count;
|
||||
uint32_t seconds_since_last_intr;
|
||||
uint32_t seconds_since_last_heartbeat;
|
||||
uint32_t mac_index;
|
||||
|
||||
/* Info Needed for Management App */
|
||||
/* --- From GetFwVersion --- */
|
||||
uint32_t firmware_version[2];
|
||||
uint32_t patch_number;
|
||||
uint32_t build_number;
|
||||
|
||||
/* --- From Init_FW --- */
|
||||
/* init_cb_t *init_cb; */
|
||||
uint16_t firmware_options;
|
||||
uint16_t tcp_options;
|
||||
uint8_t ip_address[IP_ADDR_LEN];
|
||||
uint8_t subnet_mask[IP_ADDR_LEN];
|
||||
uint8_t gateway[IP_ADDR_LEN];
|
||||
uint8_t alias[32];
|
||||
uint8_t name_string[256];
|
||||
uint8_t heartbeat_interval;
|
||||
uint8_t rsvd;
|
||||
|
||||
/* --- From FlashSysInfo --- */
|
||||
uint8_t my_mac[MAC_ADDR_LEN];
|
||||
uint8_t serial_number[16];
|
||||
|
||||
/* --- From GetFwState --- */
|
||||
uint32_t firmware_state;
|
||||
uint32_t board_id;
|
||||
uint32_t addl_fw_state;
|
||||
|
||||
/* Linux kernel thread */
|
||||
struct workqueue_struct *dpc_thread;
|
||||
struct work_struct dpc_work;
|
||||
|
||||
/* Linux timer thread */
|
||||
struct timer_list timer;
|
||||
uint32_t timer_active;
|
||||
|
||||
/* Recovery Timers */
|
||||
uint32_t port_down_retry_count;
|
||||
uint32_t discovery_wait;
|
||||
atomic_t check_relogin_timeouts;
|
||||
uint32_t retry_reset_ha_cnt;
|
||||
uint32_t isp_reset_timer; /* reset test timer */
|
||||
uint32_t nic_reset_timer; /* simulated nic reset test timer */
|
||||
int eh_start;
|
||||
struct list_head free_srb_q;
|
||||
uint16_t free_srb_q_count;
|
||||
uint16_t num_srbs_allocated;
|
||||
|
||||
/* DMA Memory Block */
|
||||
void *queues;
|
||||
dma_addr_t queues_dma;
|
||||
unsigned long queues_len;
|
||||
|
||||
#define MEM_ALIGN_VALUE \
|
||||
((max(REQUEST_QUEUE_DEPTH, RESPONSE_QUEUE_DEPTH)) * \
|
||||
sizeof(struct queue_entry))
|
||||
/* request and response queue variables */
|
||||
dma_addr_t request_dma;
|
||||
struct queue_entry *request_ring;
|
||||
struct queue_entry *request_ptr;
|
||||
dma_addr_t response_dma;
|
||||
struct queue_entry *response_ring;
|
||||
struct queue_entry *response_ptr;
|
||||
dma_addr_t shadow_regs_dma;
|
||||
struct shadow_regs *shadow_regs;
|
||||
uint16_t request_in; /* Current indexes. */
|
||||
uint16_t request_out;
|
||||
uint16_t response_in;
|
||||
uint16_t response_out;
|
||||
|
||||
/* aen queue variables */
|
||||
uint16_t aen_q_count; /* Number of available aen_q entries */
|
||||
uint16_t aen_in; /* Current indexes */
|
||||
uint16_t aen_out;
|
||||
struct aen aen_q[MAX_AEN_ENTRIES];
|
||||
|
||||
/* This mutex protects several threads to do mailbox commands
|
||||
* concurrently.
|
||||
*/
|
||||
struct mutex mbox_sem;
|
||||
wait_queue_head_t mailbox_wait_queue;
|
||||
|
||||
/* temporary mailbox status registers */
|
||||
volatile uint8_t mbox_status_count;
|
||||
volatile uint32_t mbox_status[MBOX_REG_COUNT];
|
||||
|
||||
/* local device database list (contains internal ddb entries) */
|
||||
struct list_head ddb_list;
|
||||
|
||||
/* Map ddb_list entry by FW ddb index */
|
||||
struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES];
|
||||
|
||||
};
|
||||
|
||||
static inline int is_qla4010(struct scsi_qla_host *ha)
|
||||
{
|
||||
return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010;
|
||||
}
|
||||
|
||||
static inline int is_qla4022(struct scsi_qla_host *ha)
|
||||
{
|
||||
return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022;
|
||||
}
|
||||
|
||||
static inline int adapter_up(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (test_bit(AF_ONLINE, &ha->flags) != 0) &&
|
||||
(test_bit(AF_LINK_UP, &ha->flags) != 0);
|
||||
}
|
||||
|
||||
static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost)
|
||||
{
|
||||
return (struct scsi_qla_host *)shost->hostdata;
|
||||
}
|
||||
|
||||
static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (is_qla4022(ha) ?
|
||||
&ha->reg->u1.isp4022.semaphore :
|
||||
&ha->reg->u1.isp4010.nvram);
|
||||
}
|
||||
|
||||
static inline void __iomem* isp_nvram(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (is_qla4022(ha) ?
|
||||
&ha->reg->u1.isp4022.nvram :
|
||||
&ha->reg->u1.isp4010.nvram);
|
||||
}
|
||||
|
||||
static inline void __iomem* isp_ext_hw_conf(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (is_qla4022(ha) ?
|
||||
&ha->reg->u2.isp4022.p0.ext_hw_conf :
|
||||
&ha->reg->u2.isp4010.ext_hw_conf);
|
||||
}
|
||||
|
||||
static inline void __iomem* isp_port_status(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (is_qla4022(ha) ?
|
||||
&ha->reg->u2.isp4022.p0.port_status :
|
||||
&ha->reg->u2.isp4010.port_status);
|
||||
}
|
||||
|
||||
static inline void __iomem* isp_port_ctrl(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (is_qla4022(ha) ?
|
||||
&ha->reg->u2.isp4022.p0.port_ctrl :
|
||||
&ha->reg->u2.isp4010.port_ctrl);
|
||||
}
|
||||
|
||||
static inline void __iomem* isp_port_error_status(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (is_qla4022(ha) ?
|
||||
&ha->reg->u2.isp4022.p0.port_err_status :
|
||||
&ha->reg->u2.isp4010.port_err_status);
|
||||
}
|
||||
|
||||
static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (is_qla4022(ha) ?
|
||||
&ha->reg->u2.isp4022.p0.gp_out :
|
||||
&ha->reg->u2.isp4010.gp_out);
|
||||
}
|
||||
|
||||
static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha)
|
||||
{
|
||||
return (is_qla4022(ha) ?
|
||||
offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2 :
|
||||
offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2);
|
||||
}
|
||||
|
||||
int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
|
||||
void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask);
|
||||
int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
|
||||
|
||||
static inline int ql4xxx_lock_flash(struct scsi_qla_host *a)
|
||||
{
|
||||
if (is_qla4022(a))
|
||||
return ql4xxx_sem_spinlock(a, QL4022_FLASH_SEM_MASK,
|
||||
(QL4022_RESOURCE_BITS_BASE_CODE |
|
||||
(a->mac_index)) << 13);
|
||||
else
|
||||
return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK,
|
||||
QL4010_FLASH_SEM_BITS);
|
||||
}
|
||||
|
||||
static inline void ql4xxx_unlock_flash(struct scsi_qla_host *a)
|
||||
{
|
||||
if (is_qla4022(a))
|
||||
ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK);
|
||||
else
|
||||
ql4xxx_sem_unlock(a, QL4010_FLASH_SEM_MASK);
|
||||
}
|
||||
|
||||
static inline int ql4xxx_lock_nvram(struct scsi_qla_host *a)
|
||||
{
|
||||
if (is_qla4022(a))
|
||||
return ql4xxx_sem_spinlock(a, QL4022_NVRAM_SEM_MASK,
|
||||
(QL4022_RESOURCE_BITS_BASE_CODE |
|
||||
(a->mac_index)) << 10);
|
||||
else
|
||||
return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK,
|
||||
QL4010_NVRAM_SEM_BITS);
|
||||
}
|
||||
|
||||
static inline void ql4xxx_unlock_nvram(struct scsi_qla_host *a)
|
||||
{
|
||||
if (is_qla4022(a))
|
||||
ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK);
|
||||
else
|
||||
ql4xxx_sem_unlock(a, QL4010_NVRAM_SEM_MASK);
|
||||
}
|
||||
|
||||
static inline int ql4xxx_lock_drvr(struct scsi_qla_host *a)
|
||||
{
|
||||
if (is_qla4022(a))
|
||||
return ql4xxx_sem_lock(a, QL4022_DRVR_SEM_MASK,
|
||||
(QL4022_RESOURCE_BITS_BASE_CODE |
|
||||
(a->mac_index)) << 1);
|
||||
else
|
||||
return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK,
|
||||
QL4010_DRVR_SEM_BITS);
|
||||
}
|
||||
|
||||
static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a)
|
||||
{
|
||||
if (is_qla4022(a))
|
||||
ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK);
|
||||
else
|
||||
ql4xxx_sem_unlock(a, QL4010_DRVR_SEM_MASK);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */
|
||||
#define PRESERVE_DDB_LIST 0
|
||||
#define REBUILD_DDB_LIST 1
|
||||
|
||||
/* Defines for process_aen() */
|
||||
#define PROCESS_ALL_AENS 0
|
||||
#define FLUSH_DDB_CHANGED_AENS 1
|
||||
#define RELOGIN_DDB_CHANGED_AENS 2
|
||||
|
||||
#include "ql4_version.h"
|
||||
#include "ql4_glbl.h"
|
||||
#include "ql4_dbg.h"
|
||||
#include "ql4_inline.h"
|
||||
|
||||
|
||||
#endif /*_QLA4XXX_H */
|
|
@ -0,0 +1,843 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#ifndef _QLA4X_FW_H
|
||||
#define _QLA4X_FW_H
|
||||
|
||||
|
||||
#define MAX_PRST_DEV_DB_ENTRIES 64
|
||||
#define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES
|
||||
#define MAX_DEV_DB_ENTRIES 512
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* ISP 4010 I/O Register Set Structure and Definitions
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
struct port_ctrl_stat_regs {
|
||||
__le32 ext_hw_conf; /* 80 x50 R/W */
|
||||
__le32 intChipConfiguration; /* 84 x54 */
|
||||
__le32 port_ctrl; /* 88 x58 */
|
||||
__le32 port_status; /* 92 x5c */
|
||||
__le32 HostPrimMACHi; /* 96 x60 */
|
||||
__le32 HostPrimMACLow; /* 100 x64 */
|
||||
__le32 HostSecMACHi; /* 104 x68 */
|
||||
__le32 HostSecMACLow; /* 108 x6c */
|
||||
__le32 EPPrimMACHi; /* 112 x70 */
|
||||
__le32 EPPrimMACLow; /* 116 x74 */
|
||||
__le32 EPSecMACHi; /* 120 x78 */
|
||||
__le32 EPSecMACLow; /* 124 x7c */
|
||||
__le32 HostPrimIPHi; /* 128 x80 */
|
||||
__le32 HostPrimIPMidHi; /* 132 x84 */
|
||||
__le32 HostPrimIPMidLow; /* 136 x88 */
|
||||
__le32 HostPrimIPLow; /* 140 x8c */
|
||||
__le32 HostSecIPHi; /* 144 x90 */
|
||||
__le32 HostSecIPMidHi; /* 148 x94 */
|
||||
__le32 HostSecIPMidLow; /* 152 x98 */
|
||||
__le32 HostSecIPLow; /* 156 x9c */
|
||||
__le32 EPPrimIPHi; /* 160 xa0 */
|
||||
__le32 EPPrimIPMidHi; /* 164 xa4 */
|
||||
__le32 EPPrimIPMidLow; /* 168 xa8 */
|
||||
__le32 EPPrimIPLow; /* 172 xac */
|
||||
__le32 EPSecIPHi; /* 176 xb0 */
|
||||
__le32 EPSecIPMidHi; /* 180 xb4 */
|
||||
__le32 EPSecIPMidLow; /* 184 xb8 */
|
||||
__le32 EPSecIPLow; /* 188 xbc */
|
||||
__le32 IPReassemblyTimeout; /* 192 xc0 */
|
||||
__le32 EthMaxFramePayload; /* 196 xc4 */
|
||||
__le32 TCPMaxWindowSize; /* 200 xc8 */
|
||||
__le32 TCPCurrentTimestampHi; /* 204 xcc */
|
||||
__le32 TCPCurrentTimestampLow; /* 208 xd0 */
|
||||
__le32 LocalRAMAddress; /* 212 xd4 */
|
||||
__le32 LocalRAMData; /* 216 xd8 */
|
||||
__le32 PCSReserved1; /* 220 xdc */
|
||||
__le32 gp_out; /* 224 xe0 */
|
||||
__le32 gp_in; /* 228 xe4 */
|
||||
__le32 ProbeMuxAddr; /* 232 xe8 */
|
||||
__le32 ProbeMuxData; /* 236 xec */
|
||||
__le32 ERMQueueBaseAddr0; /* 240 xf0 */
|
||||
__le32 ERMQueueBaseAddr1; /* 244 xf4 */
|
||||
__le32 MACConfiguration; /* 248 xf8 */
|
||||
__le32 port_err_status; /* 252 xfc COR */
|
||||
};
|
||||
|
||||
struct host_mem_cfg_regs {
|
||||
__le32 NetRequestQueueOut; /* 80 x50 */
|
||||
__le32 NetRequestQueueOutAddrHi; /* 84 x54 */
|
||||
__le32 NetRequestQueueOutAddrLow; /* 88 x58 */
|
||||
__le32 NetRequestQueueBaseAddrHi; /* 92 x5c */
|
||||
__le32 NetRequestQueueBaseAddrLow; /* 96 x60 */
|
||||
__le32 NetRequestQueueLength; /* 100 x64 */
|
||||
__le32 NetResponseQueueIn; /* 104 x68 */
|
||||
__le32 NetResponseQueueInAddrHi; /* 108 x6c */
|
||||
__le32 NetResponseQueueInAddrLow; /* 112 x70 */
|
||||
__le32 NetResponseQueueBaseAddrHi; /* 116 x74 */
|
||||
__le32 NetResponseQueueBaseAddrLow; /* 120 x78 */
|
||||
__le32 NetResponseQueueLength; /* 124 x7c */
|
||||
__le32 req_q_out; /* 128 x80 */
|
||||
__le32 RequestQueueOutAddrHi; /* 132 x84 */
|
||||
__le32 RequestQueueOutAddrLow; /* 136 x88 */
|
||||
__le32 RequestQueueBaseAddrHi; /* 140 x8c */
|
||||
__le32 RequestQueueBaseAddrLow; /* 144 x90 */
|
||||
__le32 RequestQueueLength; /* 148 x94 */
|
||||
__le32 ResponseQueueIn; /* 152 x98 */
|
||||
__le32 ResponseQueueInAddrHi; /* 156 x9c */
|
||||
__le32 ResponseQueueInAddrLow; /* 160 xa0 */
|
||||
__le32 ResponseQueueBaseAddrHi; /* 164 xa4 */
|
||||
__le32 ResponseQueueBaseAddrLow; /* 168 xa8 */
|
||||
__le32 ResponseQueueLength; /* 172 xac */
|
||||
__le32 NetRxLargeBufferQueueOut; /* 176 xb0 */
|
||||
__le32 NetRxLargeBufferQueueBaseAddrHi; /* 180 xb4 */
|
||||
__le32 NetRxLargeBufferQueueBaseAddrLow; /* 184 xb8 */
|
||||
__le32 NetRxLargeBufferQueueLength; /* 188 xbc */
|
||||
__le32 NetRxLargeBufferLength; /* 192 xc0 */
|
||||
__le32 NetRxSmallBufferQueueOut; /* 196 xc4 */
|
||||
__le32 NetRxSmallBufferQueueBaseAddrHi; /* 200 xc8 */
|
||||
__le32 NetRxSmallBufferQueueBaseAddrLow; /* 204 xcc */
|
||||
__le32 NetRxSmallBufferQueueLength; /* 208 xd0 */
|
||||
__le32 NetRxSmallBufferLength; /* 212 xd4 */
|
||||
__le32 HMCReserved0[10]; /* 216 xd8 */
|
||||
};
|
||||
|
||||
struct local_ram_cfg_regs {
|
||||
__le32 BufletSize; /* 80 x50 */
|
||||
__le32 BufletMaxCount; /* 84 x54 */
|
||||
__le32 BufletCurrCount; /* 88 x58 */
|
||||
__le32 BufletPauseThresholdCount; /* 92 x5c */
|
||||
__le32 BufletTCPWinThresholdHi; /* 96 x60 */
|
||||
__le32 BufletTCPWinThresholdLow; /* 100 x64 */
|
||||
__le32 IPHashTableBaseAddr; /* 104 x68 */
|
||||
__le32 IPHashTableSize; /* 108 x6c */
|
||||
__le32 TCPHashTableBaseAddr; /* 112 x70 */
|
||||
__le32 TCPHashTableSize; /* 116 x74 */
|
||||
__le32 NCBAreaBaseAddr; /* 120 x78 */
|
||||
__le32 NCBMaxCount; /* 124 x7c */
|
||||
__le32 NCBCurrCount; /* 128 x80 */
|
||||
__le32 DRBAreaBaseAddr; /* 132 x84 */
|
||||
__le32 DRBMaxCount; /* 136 x88 */
|
||||
__le32 DRBCurrCount; /* 140 x8c */
|
||||
__le32 LRCReserved[28]; /* 144 x90 */
|
||||
};
|
||||
|
||||
struct prot_stat_regs {
|
||||
__le32 MACTxFrameCount; /* 80 x50 R */
|
||||
__le32 MACTxByteCount; /* 84 x54 R */
|
||||
__le32 MACRxFrameCount; /* 88 x58 R */
|
||||
__le32 MACRxByteCount; /* 92 x5c R */
|
||||
__le32 MACCRCErrCount; /* 96 x60 R */
|
||||
__le32 MACEncErrCount; /* 100 x64 R */
|
||||
__le32 MACRxLengthErrCount; /* 104 x68 R */
|
||||
__le32 IPTxPacketCount; /* 108 x6c R */
|
||||
__le32 IPTxByteCount; /* 112 x70 R */
|
||||
__le32 IPTxFragmentCount; /* 116 x74 R */
|
||||
__le32 IPRxPacketCount; /* 120 x78 R */
|
||||
__le32 IPRxByteCount; /* 124 x7c R */
|
||||
__le32 IPRxFragmentCount; /* 128 x80 R */
|
||||
__le32 IPDatagramReassemblyCount; /* 132 x84 R */
|
||||
__le32 IPV6RxPacketCount; /* 136 x88 R */
|
||||
__le32 IPErrPacketCount; /* 140 x8c R */
|
||||
__le32 IPReassemblyErrCount; /* 144 x90 R */
|
||||
__le32 TCPTxSegmentCount; /* 148 x94 R */
|
||||
__le32 TCPTxByteCount; /* 152 x98 R */
|
||||
__le32 TCPRxSegmentCount; /* 156 x9c R */
|
||||
__le32 TCPRxByteCount; /* 160 xa0 R */
|
||||
__le32 TCPTimerExpCount; /* 164 xa4 R */
|
||||
__le32 TCPRxAckCount; /* 168 xa8 R */
|
||||
__le32 TCPTxAckCount; /* 172 xac R */
|
||||
__le32 TCPRxErrOOOCount; /* 176 xb0 R */
|
||||
__le32 PSReserved0; /* 180 xb4 */
|
||||
__le32 TCPRxWindowProbeUpdateCount; /* 184 xb8 R */
|
||||
__le32 ECCErrCorrectionCount; /* 188 xbc R */
|
||||
__le32 PSReserved1[16]; /* 192 xc0 */
|
||||
};
|
||||
|
||||
|
||||
/* remote register set (access via PCI memory read/write) */
|
||||
struct isp_reg {
|
||||
#define MBOX_REG_COUNT 8
|
||||
__le32 mailbox[MBOX_REG_COUNT];
|
||||
|
||||
__le32 flash_address; /* 0x20 */
|
||||
__le32 flash_data;
|
||||
__le32 ctrl_status;
|
||||
|
||||
union {
|
||||
struct {
|
||||
__le32 nvram;
|
||||
__le32 reserved1[2]; /* 0x30 */
|
||||
} __attribute__ ((packed)) isp4010;
|
||||
struct {
|
||||
__le32 intr_mask;
|
||||
__le32 nvram; /* 0x30 */
|
||||
__le32 semaphore;
|
||||
} __attribute__ ((packed)) isp4022;
|
||||
} u1;
|
||||
|
||||
__le32 req_q_in; /* SCSI Request Queue Producer Index */
|
||||
__le32 rsp_q_out; /* SCSI Completion Queue Consumer Index */
|
||||
|
||||
__le32 reserved2[4]; /* 0x40 */
|
||||
|
||||
union {
|
||||
struct {
|
||||
__le32 ext_hw_conf; /* 0x50 */
|
||||
__le32 flow_ctrl;
|
||||
__le32 port_ctrl;
|
||||
__le32 port_status;
|
||||
|
||||
__le32 reserved3[8]; /* 0x60 */
|
||||
|
||||
__le32 req_q_out; /* 0x80 */
|
||||
|
||||
__le32 reserved4[23]; /* 0x84 */
|
||||
|
||||
__le32 gp_out; /* 0xe0 */
|
||||
__le32 gp_in;
|
||||
|
||||
__le32 reserved5[5];
|
||||
|
||||
__le32 port_err_status; /* 0xfc */
|
||||
} __attribute__ ((packed)) isp4010;
|
||||
struct {
|
||||
union {
|
||||
struct port_ctrl_stat_regs p0;
|
||||
struct host_mem_cfg_regs p1;
|
||||
struct local_ram_cfg_regs p2;
|
||||
struct prot_stat_regs p3;
|
||||
__le32 r_union[44];
|
||||
};
|
||||
|
||||
} __attribute__ ((packed)) isp4022;
|
||||
} u2;
|
||||
}; /* 256 x100 */
|
||||
|
||||
|
||||
/* Semaphore Defines for 4010 */
|
||||
#define QL4010_DRVR_SEM_BITS 0x00000030
|
||||
#define QL4010_GPIO_SEM_BITS 0x000000c0
|
||||
#define QL4010_SDRAM_SEM_BITS 0x00000300
|
||||
#define QL4010_PHY_SEM_BITS 0x00000c00
|
||||
#define QL4010_NVRAM_SEM_BITS 0x00003000
|
||||
#define QL4010_FLASH_SEM_BITS 0x0000c000
|
||||
|
||||
#define QL4010_DRVR_SEM_MASK 0x00300000
|
||||
#define QL4010_GPIO_SEM_MASK 0x00c00000
|
||||
#define QL4010_SDRAM_SEM_MASK 0x03000000
|
||||
#define QL4010_PHY_SEM_MASK 0x0c000000
|
||||
#define QL4010_NVRAM_SEM_MASK 0x30000000
|
||||
#define QL4010_FLASH_SEM_MASK 0xc0000000
|
||||
|
||||
/* Semaphore Defines for 4022 */
|
||||
#define QL4022_RESOURCE_MASK_BASE_CODE 0x7
|
||||
#define QL4022_RESOURCE_BITS_BASE_CODE 0x4
|
||||
|
||||
|
||||
#define QL4022_DRVR_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (1+16))
|
||||
#define QL4022_DDR_RAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (4+16))
|
||||
#define QL4022_PHY_GIO_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (7+16))
|
||||
#define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16))
|
||||
#define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16))
|
||||
|
||||
|
||||
|
||||
/* Page # defines for 4022 */
|
||||
#define PORT_CTRL_STAT_PAGE 0 /* 4022 */
|
||||
#define HOST_MEM_CFG_PAGE 1 /* 4022 */
|
||||
#define LOCAL_RAM_CFG_PAGE 2 /* 4022 */
|
||||
#define PROT_STAT_PAGE 3 /* 4022 */
|
||||
|
||||
/* Register Mask - sets corresponding mask bits in the upper word */
|
||||
static inline uint32_t set_rmask(uint32_t val)
|
||||
{
|
||||
return (val & 0xffff) | (val << 16);
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t clr_rmask(uint32_t val)
|
||||
{
|
||||
return 0 | (val << 16);
|
||||
}
|
||||
|
||||
/* ctrl_status definitions */
|
||||
#define CSR_SCSI_PAGE_SELECT 0x00000003
|
||||
#define CSR_SCSI_INTR_ENABLE 0x00000004 /* 4010 */
|
||||
#define CSR_SCSI_RESET_INTR 0x00000008
|
||||
#define CSR_SCSI_COMPLETION_INTR 0x00000010
|
||||
#define CSR_SCSI_PROCESSOR_INTR 0x00000020
|
||||
#define CSR_INTR_RISC 0x00000040
|
||||
#define CSR_BOOT_ENABLE 0x00000080
|
||||
#define CSR_NET_PAGE_SELECT 0x00000300 /* 4010 */
|
||||
#define CSR_FUNC_NUM 0x00000700 /* 4022 */
|
||||
#define CSR_NET_RESET_INTR 0x00000800 /* 4010 */
|
||||
#define CSR_FORCE_SOFT_RESET 0x00002000 /* 4022 */
|
||||
#define CSR_FATAL_ERROR 0x00004000
|
||||
#define CSR_SOFT_RESET 0x00008000
|
||||
#define ISP_CONTROL_FN_MASK CSR_FUNC_NUM
|
||||
#define ISP_CONTROL_FN0_SCSI 0x0500
|
||||
#define ISP_CONTROL_FN1_SCSI 0x0700
|
||||
|
||||
#define INTR_PENDING (CSR_SCSI_COMPLETION_INTR |\
|
||||
CSR_SCSI_PROCESSOR_INTR |\
|
||||
CSR_SCSI_RESET_INTR)
|
||||
|
||||
/* ISP InterruptMask definitions */
|
||||
#define IMR_SCSI_INTR_ENABLE 0x00000004 /* 4022 */
|
||||
|
||||
/* ISP 4022 nvram definitions */
|
||||
#define NVR_WRITE_ENABLE 0x00000010 /* 4022 */
|
||||
|
||||
/* ISP port_status definitions */
|
||||
|
||||
/* ISP Semaphore definitions */
|
||||
|
||||
/* ISP General Purpose Output definitions */
|
||||
#define GPOR_TOPCAT_RESET 0x00000004
|
||||
|
||||
/* shadow registers (DMA'd from HA to system memory. read only) */
|
||||
struct shadow_regs {
|
||||
/* SCSI Request Queue Consumer Index */
|
||||
__le32 req_q_out; /* 0 x0 R */
|
||||
|
||||
/* SCSI Completion Queue Producer Index */
|
||||
__le32 rsp_q_in; /* 4 x4 R */
|
||||
}; /* 8 x8 */
|
||||
|
||||
|
||||
/* External hardware configuration register */
|
||||
union external_hw_config_reg {
|
||||
struct {
|
||||
/* FIXME: Do we even need this? All values are
|
||||
* referred to by 16 bit quantities. Platform and
|
||||
* endianess issues. */
|
||||
__le32 bReserved0:1;
|
||||
__le32 bSDRAMProtectionMethod:2;
|
||||
__le32 bSDRAMBanks:1;
|
||||
__le32 bSDRAMChipWidth:1;
|
||||
__le32 bSDRAMChipSize:2;
|
||||
__le32 bParityDisable:1;
|
||||
__le32 bExternalMemoryType:1;
|
||||
__le32 bFlashBIOSWriteEnable:1;
|
||||
__le32 bFlashUpperBankSelect:1;
|
||||
__le32 bWriteBurst:2;
|
||||
__le32 bReserved1:3;
|
||||
__le32 bMask:16;
|
||||
};
|
||||
uint32_t Asuint32_t;
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Mailbox Commands Structures and Definitions
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
/* Mailbox command definitions */
|
||||
#define MBOX_CMD_ABOUT_FW 0x0009
|
||||
#define MBOX_CMD_LUN_RESET 0x0016
|
||||
#define MBOX_CMD_GET_FW_STATUS 0x001F
|
||||
#define MBOX_CMD_SET_ISNS_SERVICE 0x0021
|
||||
#define ISNS_DISABLE 0
|
||||
#define ISNS_ENABLE 1
|
||||
#define MBOX_CMD_READ_FLASH 0x0026
|
||||
#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031
|
||||
#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056
|
||||
#define LOGOUT_OPTION_CLOSE_SESSION 0x01
|
||||
#define LOGOUT_OPTION_RELOGIN 0x02
|
||||
#define MBOX_CMD_EXECUTE_IOCB_A64 0x005A
|
||||
#define MBOX_CMD_INITIALIZE_FIRMWARE 0x0060
|
||||
#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK 0x0061
|
||||
#define MBOX_CMD_REQUEST_DATABASE_ENTRY 0x0062
|
||||
#define MBOX_CMD_SET_DATABASE_ENTRY 0x0063
|
||||
#define MBOX_CMD_GET_DATABASE_ENTRY 0x0064
|
||||
#define DDB_DS_UNASSIGNED 0x00
|
||||
#define DDB_DS_NO_CONNECTION_ACTIVE 0x01
|
||||
#define DDB_DS_SESSION_ACTIVE 0x04
|
||||
#define DDB_DS_SESSION_FAILED 0x06
|
||||
#define DDB_DS_LOGIN_IN_PROCESS 0x07
|
||||
#define MBOX_CMD_GET_FW_STATE 0x0069
|
||||
|
||||
/* Mailbox 1 */
|
||||
#define FW_STATE_READY 0x0000
|
||||
#define FW_STATE_CONFIG_WAIT 0x0001
|
||||
#define FW_STATE_ERROR 0x0004
|
||||
#define FW_STATE_DHCP_IN_PROGRESS 0x0008
|
||||
|
||||
/* Mailbox 3 */
|
||||
#define FW_ADDSTATE_OPTICAL_MEDIA 0x0001
|
||||
#define FW_ADDSTATE_DHCP_ENABLED 0x0002
|
||||
#define FW_ADDSTATE_LINK_UP 0x0010
|
||||
#define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020
|
||||
#define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B
|
||||
#define MBOX_CMD_CONN_OPEN_SESS_LOGIN 0x0074
|
||||
#define MBOX_CMD_GET_CRASH_RECORD 0x0076 /* 4010 only */
|
||||
#define MBOX_CMD_GET_CONN_EVENT_LOG 0x0077
|
||||
|
||||
/* Mailbox status definitions */
|
||||
#define MBOX_COMPLETION_STATUS 4
|
||||
#define MBOX_STS_BUSY 0x0007
|
||||
#define MBOX_STS_INTERMEDIATE_COMPLETION 0x1000
|
||||
#define MBOX_STS_COMMAND_COMPLETE 0x4000
|
||||
#define MBOX_STS_COMMAND_ERROR 0x4005
|
||||
|
||||
#define MBOX_ASYNC_EVENT_STATUS 8
|
||||
#define MBOX_ASTS_SYSTEM_ERROR 0x8002
|
||||
#define MBOX_ASTS_REQUEST_TRANSFER_ERROR 0x8003
|
||||
#define MBOX_ASTS_RESPONSE_TRANSFER_ERROR 0x8004
|
||||
#define MBOX_ASTS_PROTOCOL_STATISTIC_ALARM 0x8005
|
||||
#define MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED 0x8006
|
||||
#define MBOX_ASTS_LINK_UP 0x8010
|
||||
#define MBOX_ASTS_LINK_DOWN 0x8011
|
||||
#define MBOX_ASTS_DATABASE_CHANGED 0x8014
|
||||
#define MBOX_ASTS_UNSOLICITED_PDU_RECEIVED 0x8015
|
||||
#define MBOX_ASTS_SELF_TEST_FAILED 0x8016
|
||||
#define MBOX_ASTS_LOGIN_FAILED 0x8017
|
||||
#define MBOX_ASTS_DNS 0x8018
|
||||
#define MBOX_ASTS_HEARTBEAT 0x8019
|
||||
#define MBOX_ASTS_NVRAM_INVALID 0x801A
|
||||
#define MBOX_ASTS_MAC_ADDRESS_CHANGED 0x801B
|
||||
#define MBOX_ASTS_IP_ADDRESS_CHANGED 0x801C
|
||||
#define MBOX_ASTS_DHCP_LEASE_EXPIRED 0x801D
|
||||
#define MBOX_ASTS_DHCP_LEASE_ACQUIRED 0x801F
|
||||
#define MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED 0x8021
|
||||
#define ISNS_EVENT_DATA_RECEIVED 0x0000
|
||||
#define ISNS_EVENT_CONNECTION_OPENED 0x0001
|
||||
#define ISNS_EVENT_CONNECTION_FAILED 0x0002
|
||||
#define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022
|
||||
#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Host Adapter Initialization Control Block (from host) */
|
||||
struct init_fw_ctrl_blk {
|
||||
uint8_t Version; /* 00 */
|
||||
uint8_t Control; /* 01 */
|
||||
|
||||
uint16_t FwOptions; /* 02-03 */
|
||||
#define FWOPT_HEARTBEAT_ENABLE 0x1000
|
||||
#define FWOPT_SESSION_MODE 0x0040
|
||||
#define FWOPT_INITIATOR_MODE 0x0020
|
||||
#define FWOPT_TARGET_MODE 0x0010
|
||||
|
||||
uint16_t ExecThrottle; /* 04-05 */
|
||||
uint8_t RetryCount; /* 06 */
|
||||
uint8_t RetryDelay; /* 07 */
|
||||
uint16_t MaxEthFrPayloadSize; /* 08-09 */
|
||||
uint16_t AddFwOptions; /* 0A-0B */
|
||||
|
||||
uint8_t HeartbeatInterval; /* 0C */
|
||||
uint8_t InstanceNumber; /* 0D */
|
||||
uint16_t RES2; /* 0E-0F */
|
||||
uint16_t ReqQConsumerIndex; /* 10-11 */
|
||||
uint16_t ComplQProducerIndex; /* 12-13 */
|
||||
uint16_t ReqQLen; /* 14-15 */
|
||||
uint16_t ComplQLen; /* 16-17 */
|
||||
uint32_t ReqQAddrLo; /* 18-1B */
|
||||
uint32_t ReqQAddrHi; /* 1C-1F */
|
||||
uint32_t ComplQAddrLo; /* 20-23 */
|
||||
uint32_t ComplQAddrHi; /* 24-27 */
|
||||
uint32_t ShadowRegBufAddrLo; /* 28-2B */
|
||||
uint32_t ShadowRegBufAddrHi; /* 2C-2F */
|
||||
|
||||
uint16_t iSCSIOptions; /* 30-31 */
|
||||
|
||||
uint16_t TCPOptions; /* 32-33 */
|
||||
|
||||
uint16_t IPOptions; /* 34-35 */
|
||||
|
||||
uint16_t MaxPDUSize; /* 36-37 */
|
||||
uint16_t RcvMarkerInt; /* 38-39 */
|
||||
uint16_t SndMarkerInt; /* 3A-3B */
|
||||
uint16_t InitMarkerlessInt; /* 3C-3D */
|
||||
uint16_t FirstBurstSize; /* 3E-3F */
|
||||
uint16_t DefaultTime2Wait; /* 40-41 */
|
||||
uint16_t DefaultTime2Retain; /* 42-43 */
|
||||
uint16_t MaxOutStndngR2T; /* 44-45 */
|
||||
uint16_t KeepAliveTimeout; /* 46-47 */
|
||||
uint16_t PortNumber; /* 48-49 */
|
||||
uint16_t MaxBurstSize; /* 4A-4B */
|
||||
uint32_t RES4; /* 4C-4F */
|
||||
uint8_t IPAddr[4]; /* 50-53 */
|
||||
uint8_t RES5[12]; /* 54-5F */
|
||||
uint8_t SubnetMask[4]; /* 60-63 */
|
||||
uint8_t RES6[12]; /* 64-6F */
|
||||
uint8_t GatewayIPAddr[4]; /* 70-73 */
|
||||
uint8_t RES7[12]; /* 74-7F */
|
||||
uint8_t PriDNSIPAddr[4]; /* 80-83 */
|
||||
uint8_t SecDNSIPAddr[4]; /* 84-87 */
|
||||
uint8_t RES8[8]; /* 88-8F */
|
||||
uint8_t Alias[32]; /* 90-AF */
|
||||
uint8_t TargAddr[8]; /* B0-B7 *//* /FIXME: Remove?? */
|
||||
uint8_t CHAPNameSecretsTable[8]; /* B8-BF */
|
||||
uint8_t EthernetMACAddr[6]; /* C0-C5 */
|
||||
uint16_t TargetPortalGroup; /* C6-C7 */
|
||||
uint8_t SendScale; /* C8 */
|
||||
uint8_t RecvScale; /* C9 */
|
||||
uint8_t TypeOfService; /* CA */
|
||||
uint8_t Time2Live; /* CB */
|
||||
uint16_t VLANPriority; /* CC-CD */
|
||||
uint16_t Reserved8; /* CE-CF */
|
||||
uint8_t SecIPAddr[4]; /* D0-D3 */
|
||||
uint8_t Reserved9[12]; /* D4-DF */
|
||||
uint8_t iSNSIPAddr[4]; /* E0-E3 */
|
||||
uint16_t iSNSServerPortNumber; /* E4-E5 */
|
||||
uint8_t Reserved10[10]; /* E6-EF */
|
||||
uint8_t SLPDAIPAddr[4]; /* F0-F3 */
|
||||
uint8_t Reserved11[12]; /* F4-FF */
|
||||
uint8_t iSCSINameString[256]; /* 100-1FF */
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
struct dev_db_entry {
|
||||
uint8_t options; /* 00 */
|
||||
#define DDB_OPT_DISC_SESSION 0x10
|
||||
#define DDB_OPT_TARGET 0x02 /* device is a target */
|
||||
|
||||
uint8_t control; /* 01 */
|
||||
|
||||
uint16_t exeThrottle; /* 02-03 */
|
||||
uint16_t exeCount; /* 04-05 */
|
||||
uint8_t retryCount; /* 06 */
|
||||
uint8_t retryDelay; /* 07 */
|
||||
uint16_t iSCSIOptions; /* 08-09 */
|
||||
|
||||
uint16_t TCPOptions; /* 0A-0B */
|
||||
|
||||
uint16_t IPOptions; /* 0C-0D */
|
||||
|
||||
uint16_t maxPDUSize; /* 0E-0F */
|
||||
uint16_t rcvMarkerInt; /* 10-11 */
|
||||
uint16_t sndMarkerInt; /* 12-13 */
|
||||
uint16_t iSCSIMaxSndDataSegLen; /* 14-15 */
|
||||
uint16_t firstBurstSize; /* 16-17 */
|
||||
uint16_t minTime2Wait; /* 18-19 : RA :default_time2wait */
|
||||
uint16_t maxTime2Retain; /* 1A-1B */
|
||||
uint16_t maxOutstndngR2T; /* 1C-1D */
|
||||
uint16_t keepAliveTimeout; /* 1E-1F */
|
||||
uint8_t ISID[6]; /* 20-25 big-endian, must be converted
|
||||
* to little-endian */
|
||||
uint16_t TSID; /* 26-27 */
|
||||
uint16_t portNumber; /* 28-29 */
|
||||
uint16_t maxBurstSize; /* 2A-2B */
|
||||
uint16_t taskMngmntTimeout; /* 2C-2D */
|
||||
uint16_t reserved1; /* 2E-2F */
|
||||
uint8_t ipAddr[0x10]; /* 30-3F */
|
||||
uint8_t iSCSIAlias[0x20]; /* 40-5F */
|
||||
uint8_t targetAddr[0x20]; /* 60-7F */
|
||||
uint8_t userID[0x20]; /* 80-9F */
|
||||
uint8_t password[0x20]; /* A0-BF */
|
||||
uint8_t iscsiName[0x100]; /* C0-1BF : xxzzy Make this a
|
||||
* pointer to a string so we
|
||||
* don't have to reserve soooo
|
||||
* much RAM */
|
||||
uint16_t ddbLink; /* 1C0-1C1 */
|
||||
uint16_t CHAPTableIndex; /* 1C2-1C3 */
|
||||
uint16_t TargetPortalGroup; /* 1C4-1C5 */
|
||||
uint16_t reserved2[2]; /* 1C6-1C7 */
|
||||
uint32_t statSN; /* 1C8-1CB */
|
||||
uint32_t expStatSN; /* 1CC-1CF */
|
||||
uint16_t reserved3[0x2C]; /* 1D0-1FB */
|
||||
uint16_t ddbValidCookie; /* 1FC-1FD */
|
||||
uint16_t ddbValidSize; /* 1FE-1FF */
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Flash definitions */
|
||||
|
||||
#define FLASH_OFFSET_SYS_INFO 0x02000000
|
||||
#define FLASH_DEFAULTBLOCKSIZE 0x20000
|
||||
#define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes
|
||||
* for EOF
|
||||
* signature */
|
||||
|
||||
struct sys_info_phys_addr {
|
||||
uint8_t address[6]; /* 00-05 */
|
||||
uint8_t filler[2]; /* 06-07 */
|
||||
};
|
||||
|
||||
struct flash_sys_info {
|
||||
uint32_t cookie; /* 00-03 */
|
||||
uint32_t physAddrCount; /* 04-07 */
|
||||
struct sys_info_phys_addr physAddr[4]; /* 08-27 */
|
||||
uint8_t vendorId[128]; /* 28-A7 */
|
||||
uint8_t productId[128]; /* A8-127 */
|
||||
uint32_t serialNumber; /* 128-12B */
|
||||
|
||||
/* PCI Configuration values */
|
||||
uint32_t pciDeviceVendor; /* 12C-12F */
|
||||
uint32_t pciDeviceId; /* 130-133 */
|
||||
uint32_t pciSubsysVendor; /* 134-137 */
|
||||
uint32_t pciSubsysId; /* 138-13B */
|
||||
|
||||
/* This validates version 1. */
|
||||
uint32_t crumbs; /* 13C-13F */
|
||||
|
||||
uint32_t enterpriseNumber; /* 140-143 */
|
||||
|
||||
uint32_t mtu; /* 144-147 */
|
||||
uint32_t reserved0; /* 148-14b */
|
||||
uint32_t crumbs2; /* 14c-14f */
|
||||
uint8_t acSerialNumber[16]; /* 150-15f */
|
||||
uint32_t crumbs3; /* 160-16f */
|
||||
|
||||
/* Leave this last in the struct so it is declared invalid if
|
||||
* any new items are added.
|
||||
*/
|
||||
uint32_t reserved1[39]; /* 170-1ff */
|
||||
}; /* 200 */
|
||||
|
||||
struct crash_record {
|
||||
uint16_t fw_major_version; /* 00 - 01 */
|
||||
uint16_t fw_minor_version; /* 02 - 03 */
|
||||
uint16_t fw_patch_version; /* 04 - 05 */
|
||||
uint16_t fw_build_version; /* 06 - 07 */
|
||||
|
||||
uint8_t build_date[16]; /* 08 - 17 */
|
||||
uint8_t build_time[16]; /* 18 - 27 */
|
||||
uint8_t build_user[16]; /* 28 - 37 */
|
||||
uint8_t card_serial_num[16]; /* 38 - 47 */
|
||||
|
||||
uint32_t time_of_crash_in_secs; /* 48 - 4B */
|
||||
uint32_t time_of_crash_in_ms; /* 4C - 4F */
|
||||
|
||||
uint16_t out_RISC_sd_num_frames; /* 50 - 51 */
|
||||
uint16_t OAP_sd_num_words; /* 52 - 53 */
|
||||
uint16_t IAP_sd_num_frames; /* 54 - 55 */
|
||||
uint16_t in_RISC_sd_num_words; /* 56 - 57 */
|
||||
|
||||
uint8_t reserved1[28]; /* 58 - 7F */
|
||||
|
||||
uint8_t out_RISC_reg_dump[256]; /* 80 -17F */
|
||||
uint8_t in_RISC_reg_dump[256]; /*180 -27F */
|
||||
uint8_t in_out_RISC_stack_dump[0]; /*280 - ??? */
|
||||
};
|
||||
|
||||
struct conn_event_log_entry {
|
||||
#define MAX_CONN_EVENT_LOG_ENTRIES 100
|
||||
uint32_t timestamp_sec; /* 00 - 03 seconds since boot */
|
||||
uint32_t timestamp_ms; /* 04 - 07 milliseconds since boot */
|
||||
uint16_t device_index; /* 08 - 09 */
|
||||
uint16_t fw_conn_state; /* 0A - 0B */
|
||||
uint8_t event_type; /* 0C - 0C */
|
||||
uint8_t error_code; /* 0D - 0D */
|
||||
uint16_t error_code_detail; /* 0E - 0F */
|
||||
uint8_t num_consecutive_events; /* 10 - 10 */
|
||||
uint8_t rsvd[3]; /* 11 - 13 */
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* IOCB Commands Structures and Definitions
|
||||
*
|
||||
*************************************************************************/
|
||||
#define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */
|
||||
#define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */
|
||||
|
||||
/* IOCB header structure */
|
||||
struct qla4_header {
|
||||
uint8_t entryType;
|
||||
#define ET_STATUS 0x03
|
||||
#define ET_MARKER 0x04
|
||||
#define ET_CONT_T1 0x0A
|
||||
#define ET_STATUS_CONTINUATION 0x10
|
||||
#define ET_CMND_T3 0x19
|
||||
#define ET_PASSTHRU0 0x3A
|
||||
#define ET_PASSTHRU_STATUS 0x3C
|
||||
|
||||
uint8_t entryStatus;
|
||||
uint8_t systemDefined;
|
||||
uint8_t entryCount;
|
||||
|
||||
/* SyetemDefined definition */
|
||||
};
|
||||
|
||||
/* Generic queue entry structure*/
|
||||
struct queue_entry {
|
||||
uint8_t data[60];
|
||||
uint32_t signature;
|
||||
|
||||
};
|
||||
|
||||
/* 64 bit addressing segment counts*/
|
||||
|
||||
#define COMMAND_SEG_A64 1
|
||||
#define CONTINUE_SEG_A64 5
|
||||
|
||||
/* 64 bit addressing segment definition*/
|
||||
|
||||
struct data_seg_a64 {
|
||||
struct {
|
||||
uint32_t addrLow;
|
||||
uint32_t addrHigh;
|
||||
|
||||
} base;
|
||||
|
||||
uint32_t count;
|
||||
|
||||
};
|
||||
|
||||
/* Command Type 3 entry structure*/
|
||||
|
||||
struct command_t3_entry {
|
||||
struct qla4_header hdr; /* 00-03 */
|
||||
|
||||
uint32_t handle; /* 04-07 */
|
||||
uint16_t target; /* 08-09 */
|
||||
uint16_t connection_id; /* 0A-0B */
|
||||
|
||||
uint8_t control_flags; /* 0C */
|
||||
|
||||
/* data direction (bits 5-6) */
|
||||
#define CF_WRITE 0x20
|
||||
#define CF_READ 0x40
|
||||
#define CF_NO_DATA 0x00
|
||||
|
||||
/* task attributes (bits 2-0) */
|
||||
#define CF_HEAD_TAG 0x03
|
||||
#define CF_ORDERED_TAG 0x02
|
||||
#define CF_SIMPLE_TAG 0x01
|
||||
|
||||
/* STATE FLAGS FIELD IS A PLACE HOLDER. THE FW WILL SET BITS
|
||||
* IN THIS FIELD AS THE COMMAND IS PROCESSED. WHEN THE IOCB IS
|
||||
* CHANGED TO AN IOSB THIS FIELD WILL HAVE THE STATE FLAGS SET
|
||||
* PROPERLY.
|
||||
*/
|
||||
uint8_t state_flags; /* 0D */
|
||||
uint8_t cmdRefNum; /* 0E */
|
||||
uint8_t reserved1; /* 0F */
|
||||
uint8_t cdb[IOCB_MAX_CDB_LEN]; /* 10-1F */
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
uint32_t cmdSeqNum; /* 28-2B */
|
||||
uint16_t timeout; /* 2C-2D */
|
||||
uint16_t dataSegCnt; /* 2E-2F */
|
||||
uint32_t ttlByteCnt; /* 30-33 */
|
||||
struct data_seg_a64 dataseg[COMMAND_SEG_A64]; /* 34-3F */
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* Continuation Type 1 entry structure*/
|
||||
struct continuation_t1_entry {
|
||||
struct qla4_header hdr;
|
||||
|
||||
struct data_seg_a64 dataseg[CONTINUE_SEG_A64];
|
||||
|
||||
};
|
||||
|
||||
/* Parameterize for 64 or 32 bits */
|
||||
#define COMMAND_SEG COMMAND_SEG_A64
|
||||
#define CONTINUE_SEG CONTINUE_SEG_A64
|
||||
|
||||
#define ET_COMMAND ET_CMND_T3
|
||||
#define ET_CONTINUE ET_CONT_T1
|
||||
|
||||
/* Marker entry structure*/
|
||||
struct marker_entry {
|
||||
struct qla4_header hdr; /* 00-03 */
|
||||
|
||||
uint32_t system_defined; /* 04-07 */
|
||||
uint16_t target; /* 08-09 */
|
||||
uint16_t modifier; /* 0A-0B */
|
||||
#define MM_LUN_RESET 0
|
||||
|
||||
uint16_t flags; /* 0C-0D */
|
||||
uint16_t reserved1; /* 0E-0F */
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
uint64_t reserved2; /* 18-1F */
|
||||
uint64_t reserved3; /* 20-27 */
|
||||
uint64_t reserved4; /* 28-2F */
|
||||
uint64_t reserved5; /* 30-37 */
|
||||
uint64_t reserved6; /* 38-3F */
|
||||
};
|
||||
|
||||
/* Status entry structure*/
|
||||
struct status_entry {
|
||||
struct qla4_header hdr; /* 00-03 */
|
||||
|
||||
uint32_t handle; /* 04-07 */
|
||||
|
||||
uint8_t scsiStatus; /* 08 */
|
||||
#define SCSI_CHECK_CONDITION 0x02
|
||||
|
||||
uint8_t iscsiFlags; /* 09 */
|
||||
#define ISCSI_FLAG_RESIDUAL_UNDER 0x02
|
||||
#define ISCSI_FLAG_RESIDUAL_OVER 0x04
|
||||
|
||||
uint8_t iscsiResponse; /* 0A */
|
||||
|
||||
uint8_t completionStatus; /* 0B */
|
||||
#define SCS_COMPLETE 0x00
|
||||
#define SCS_INCOMPLETE 0x01
|
||||
#define SCS_RESET_OCCURRED 0x04
|
||||
#define SCS_ABORTED 0x05
|
||||
#define SCS_TIMEOUT 0x06
|
||||
#define SCS_DATA_OVERRUN 0x07
|
||||
#define SCS_DATA_UNDERRUN 0x15
|
||||
#define SCS_QUEUE_FULL 0x1C
|
||||
#define SCS_DEVICE_UNAVAILABLE 0x28
|
||||
#define SCS_DEVICE_LOGGED_OUT 0x29
|
||||
|
||||
uint8_t reserved1; /* 0C */
|
||||
|
||||
/* state_flags MUST be at the same location as state_flags in
|
||||
* the Command_T3/4_Entry */
|
||||
uint8_t state_flags; /* 0D */
|
||||
|
||||
uint16_t senseDataByteCnt; /* 0E-0F */
|
||||
uint32_t residualByteCnt; /* 10-13 */
|
||||
uint32_t bidiResidualByteCnt; /* 14-17 */
|
||||
uint32_t expSeqNum; /* 18-1B */
|
||||
uint32_t maxCmdSeqNum; /* 1C-1F */
|
||||
uint8_t senseData[IOCB_MAX_SENSEDATA_LEN]; /* 20-3F */
|
||||
|
||||
};
|
||||
|
||||
struct passthru0 {
|
||||
struct qla4_header hdr; /* 00-03 */
|
||||
uint32_t handle; /* 04-07 */
|
||||
uint16_t target; /* 08-09 */
|
||||
uint16_t connectionID; /* 0A-0B */
|
||||
#define ISNS_DEFAULT_SERVER_CONN_ID ((uint16_t)0x8000)
|
||||
|
||||
uint16_t controlFlags; /* 0C-0D */
|
||||
#define PT_FLAG_ETHERNET_FRAME 0x8000
|
||||
#define PT_FLAG_ISNS_PDU 0x8000
|
||||
#define PT_FLAG_SEND_BUFFER 0x0200
|
||||
#define PT_FLAG_WAIT_4_RESPONSE 0x0100
|
||||
|
||||
uint16_t timeout; /* 0E-0F */
|
||||
#define PT_DEFAULT_TIMEOUT 30 /* seconds */
|
||||
|
||||
struct data_seg_a64 outDataSeg64; /* 10-1B */
|
||||
uint32_t res1; /* 1C-1F */
|
||||
struct data_seg_a64 inDataSeg64; /* 20-2B */
|
||||
uint8_t res2[20]; /* 2C-3F */
|
||||
};
|
||||
|
||||
struct passthru_status {
|
||||
struct qla4_header hdr; /* 00-03 */
|
||||
uint32_t handle; /* 04-07 */
|
||||
uint16_t target; /* 08-09 */
|
||||
uint16_t connectionID; /* 0A-0B */
|
||||
|
||||
uint8_t completionStatus; /* 0C */
|
||||
#define PASSTHRU_STATUS_COMPLETE 0x01
|
||||
|
||||
uint8_t residualFlags; /* 0D */
|
||||
|
||||
uint16_t timeout; /* 0E-0F */
|
||||
uint16_t portNumber; /* 10-11 */
|
||||
uint8_t res1[10]; /* 12-1B */
|
||||
uint32_t outResidual; /* 1C-1F */
|
||||
uint8_t res2[12]; /* 20-2B */
|
||||
uint32_t inResidual; /* 2C-2F */
|
||||
uint8_t res4[16]; /* 30-3F */
|
||||
};
|
||||
|
||||
#endif /* _QLA4X_FW_H */
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#ifndef __QLA4x_GBL_H
|
||||
#define __QLA4x_GBL_H
|
||||
|
||||
int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
|
||||
int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
|
||||
int qla4xxx_initialize_adapter(struct scsi_qla_host * ha,
|
||||
uint8_t renew_ddb_list);
|
||||
int qla4xxx_soft_reset(struct scsi_qla_host *ha);
|
||||
irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
|
||||
|
||||
void qla4xxx_free_ddb_list(struct scsi_qla_host * ha);
|
||||
void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
|
||||
|
||||
int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
|
||||
int qla4xxx_relogin_device(struct scsi_qla_host * ha,
|
||||
struct ddb_entry * ddb_entry);
|
||||
int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
|
||||
int lun);
|
||||
int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
|
||||
uint32_t offset, uint32_t len);
|
||||
int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
|
||||
int qla4xxx_get_firmware_state(struct scsi_qla_host * ha);
|
||||
int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha);
|
||||
|
||||
/* FIXME: Goodness! this really wants a small struct to hold the
|
||||
* parameters. On x86 the args will get passed on the stack! */
|
||||
int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
|
||||
uint16_t fw_ddb_index,
|
||||
struct dev_db_entry *fw_ddb_entry,
|
||||
dma_addr_t fw_ddb_entry_dma,
|
||||
uint32_t *num_valid_ddb_entries,
|
||||
uint32_t *next_ddb_index,
|
||||
uint32_t *fw_ddb_device_state,
|
||||
uint32_t *conn_err_detail,
|
||||
uint16_t *tcp_source_port_num,
|
||||
uint16_t *connection_id);
|
||||
|
||||
struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha,
|
||||
uint32_t fw_ddb_index);
|
||||
int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
|
||||
dma_addr_t fw_ddb_entry_dma);
|
||||
|
||||
void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
|
||||
struct ddb_entry *ddb_entry);
|
||||
u16 rd_nvram_word(struct scsi_qla_host * ha, int offset);
|
||||
void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
|
||||
struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
|
||||
int qla4xxx_add_sess(struct ddb_entry *);
|
||||
void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
|
||||
int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
|
||||
uint16_t fw_ddb_index,
|
||||
uint16_t connection_id,
|
||||
uint16_t option);
|
||||
int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
|
||||
uint16_t fw_ddb_index);
|
||||
int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
|
||||
int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
|
||||
void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
|
||||
uint32_t intr_status);
|
||||
int qla4xxx_init_rings(struct scsi_qla_host * ha);
|
||||
void qla4xxx_dump_buffer(void *b, uint32_t size);
|
||||
struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
|
||||
void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
|
||||
int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
|
||||
int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
|
||||
uint32_t fw_ddb_index, uint32_t state);
|
||||
|
||||
extern int extended_error_logging;
|
||||
extern int ql4xdiscoverywait;
|
||||
extern int ql4xdontresethba;
|
||||
#endif /* _QLA4x_GBL_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* qla4xxx_lookup_ddb_by_fw_index
|
||||
* This routine locates a device handle given the firmware device
|
||||
* database index. If device doesn't exist, returns NULL.
|
||||
*
|
||||
* Input:
|
||||
* ha - Pointer to host adapter structure.
|
||||
* fw_ddb_index - Firmware's device database index
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to the corresponding internal device database structure
|
||||
*/
|
||||
static inline struct ddb_entry *
|
||||
qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index)
|
||||
{
|
||||
struct ddb_entry *ddb_entry = NULL;
|
||||
|
||||
if ((fw_ddb_index < MAX_DDB_ENTRIES) &&
|
||||
(ha->fw_ddb_index_map[fw_ddb_index] !=
|
||||
(struct ddb_entry *) INVALID_ENTRY)) {
|
||||
ddb_entry = ha->fw_ddb_index_map[fw_ddb_index];
|
||||
}
|
||||
|
||||
DEBUG3(printk("scsi%d: %s: index [%d], ddb_entry = %p\n",
|
||||
ha->host_no, __func__, fw_ddb_index, ddb_entry));
|
||||
|
||||
return ddb_entry;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__qla4xxx_enable_intrs(struct scsi_qla_host *ha)
|
||||
{
|
||||
if (is_qla4022(ha)) {
|
||||
writel(set_rmask(IMR_SCSI_INTR_ENABLE),
|
||||
&ha->reg->u1.isp4022.intr_mask);
|
||||
readl(&ha->reg->u1.isp4022.intr_mask);
|
||||
} else {
|
||||
writel(set_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status);
|
||||
readl(&ha->reg->ctrl_status);
|
||||
}
|
||||
set_bit(AF_INTERRUPTS_ON, &ha->flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__qla4xxx_disable_intrs(struct scsi_qla_host *ha)
|
||||
{
|
||||
if (is_qla4022(ha)) {
|
||||
writel(clr_rmask(IMR_SCSI_INTR_ENABLE),
|
||||
&ha->reg->u1.isp4022.intr_mask);
|
||||
readl(&ha->reg->u1.isp4022.intr_mask);
|
||||
} else {
|
||||
writel(clr_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status);
|
||||
readl(&ha->reg->ctrl_status);
|
||||
}
|
||||
clear_bit(AF_INTERRUPTS_ON, &ha->flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
qla4xxx_enable_intrs(struct scsi_qla_host *ha)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
__qla4xxx_enable_intrs(ha);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
qla4xxx_disable_intrs(struct scsi_qla_host *ha)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
__qla4xxx_disable_intrs(ha);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
}
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#include "ql4_def.h"
|
||||
|
||||
#include <scsi/scsi_tcq.h>
|
||||
|
||||
/**
|
||||
* qla4xxx_get_req_pkt - returns a valid entry in request queue.
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @queue_entry: Pointer to pointer to queue entry structure
|
||||
*
|
||||
* This routine performs the following tasks:
|
||||
* - returns the current request_in pointer (if queue not full)
|
||||
* - advances the request_in pointer
|
||||
* - checks for queue full
|
||||
**/
|
||||
int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
|
||||
struct queue_entry **queue_entry)
|
||||
{
|
||||
uint16_t request_in;
|
||||
uint8_t status = QLA_SUCCESS;
|
||||
|
||||
*queue_entry = ha->request_ptr;
|
||||
|
||||
/* get the latest request_in and request_out index */
|
||||
request_in = ha->request_in;
|
||||
ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
|
||||
|
||||
/* Advance request queue pointer and check for queue full */
|
||||
if (request_in == (REQUEST_QUEUE_DEPTH - 1)) {
|
||||
request_in = 0;
|
||||
ha->request_ptr = ha->request_ring;
|
||||
} else {
|
||||
request_in++;
|
||||
ha->request_ptr++;
|
||||
}
|
||||
|
||||
/* request queue is full, try again later */
|
||||
if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) {
|
||||
/* restore request pointer */
|
||||
ha->request_ptr = *queue_entry;
|
||||
status = QLA_ERROR;
|
||||
} else {
|
||||
ha->request_in = request_in;
|
||||
memset(*queue_entry, 0, sizeof(**queue_entry));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_send_marker_iocb - issues marker iocb to HBA
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @ddb_entry: Pointer to device database entry
|
||||
* @lun: SCSI LUN
|
||||
* @marker_type: marker identifier
|
||||
*
|
||||
* This routine issues a marker IOCB.
|
||||
**/
|
||||
int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
|
||||
struct ddb_entry *ddb_entry, int lun)
|
||||
{
|
||||
struct marker_entry *marker_entry;
|
||||
unsigned long flags = 0;
|
||||
uint8_t status = QLA_SUCCESS;
|
||||
|
||||
/* Acquire hardware specific lock */
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
|
||||
/* Get pointer to the queue entry for the marker */
|
||||
if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) !=
|
||||
QLA_SUCCESS) {
|
||||
status = QLA_ERROR;
|
||||
goto exit_send_marker;
|
||||
}
|
||||
|
||||
/* Put the marker in the request queue */
|
||||
marker_entry->hdr.entryType = ET_MARKER;
|
||||
marker_entry->hdr.entryCount = 1;
|
||||
marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
|
||||
marker_entry->modifier = cpu_to_le16(MM_LUN_RESET);
|
||||
int_to_scsilun(lun, &marker_entry->lun);
|
||||
wmb();
|
||||
|
||||
/* Tell ISP it's got a new I/O request */
|
||||
writel(ha->request_in, &ha->reg->req_q_in);
|
||||
readl(&ha->reg->req_q_in);
|
||||
|
||||
exit_send_marker:
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
|
||||
struct scsi_qla_host *ha)
|
||||
{
|
||||
struct continuation_t1_entry *cont_entry;
|
||||
|
||||
cont_entry = (struct continuation_t1_entry *)ha->request_ptr;
|
||||
|
||||
/* Advance request queue pointer */
|
||||
if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
|
||||
ha->request_in = 0;
|
||||
ha->request_ptr = ha->request_ring;
|
||||
} else {
|
||||
ha->request_in++;
|
||||
ha->request_ptr++;
|
||||
}
|
||||
|
||||
/* Load packet defaults */
|
||||
cont_entry->hdr.entryType = ET_CONTINUE;
|
||||
cont_entry->hdr.entryCount = 1;
|
||||
cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in);
|
||||
|
||||
return cont_entry;
|
||||
}
|
||||
|
||||
uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
|
||||
{
|
||||
uint16_t iocbs;
|
||||
|
||||
iocbs = 1;
|
||||
if (dsds > COMMAND_SEG) {
|
||||
iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG;
|
||||
if ((dsds - COMMAND_SEG) % CONTINUE_SEG)
|
||||
iocbs++;
|
||||
}
|
||||
return iocbs;
|
||||
}
|
||||
|
||||
void qla4xxx_build_scsi_iocbs(struct srb *srb,
|
||||
struct command_t3_entry *cmd_entry,
|
||||
uint16_t tot_dsds)
|
||||
{
|
||||
struct scsi_qla_host *ha;
|
||||
uint16_t avail_dsds;
|
||||
struct data_seg_a64 *cur_dsd;
|
||||
struct scsi_cmnd *cmd;
|
||||
|
||||
cmd = srb->cmd;
|
||||
ha = srb->ha;
|
||||
|
||||
if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
|
||||
/* No data being transferred */
|
||||
cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0);
|
||||
return;
|
||||
}
|
||||
|
||||
avail_dsds = COMMAND_SEG;
|
||||
cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]);
|
||||
|
||||
/* Load data segments */
|
||||
if (cmd->use_sg) {
|
||||
struct scatterlist *cur_seg;
|
||||
struct scatterlist *end_seg;
|
||||
|
||||
cur_seg = (struct scatterlist *)cmd->request_buffer;
|
||||
end_seg = cur_seg + tot_dsds;
|
||||
while (cur_seg < end_seg) {
|
||||
dma_addr_t sle_dma;
|
||||
|
||||
/* Allocate additional continuation packets? */
|
||||
if (avail_dsds == 0) {
|
||||
struct continuation_t1_entry *cont_entry;
|
||||
|
||||
cont_entry = qla4xxx_alloc_cont_entry(ha);
|
||||
cur_dsd =
|
||||
(struct data_seg_a64 *)
|
||||
&cont_entry->dataseg[0];
|
||||
avail_dsds = CONTINUE_SEG;
|
||||
}
|
||||
|
||||
sle_dma = sg_dma_address(cur_seg);
|
||||
cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
|
||||
cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
|
||||
cur_dsd->count = cpu_to_le32(sg_dma_len(cur_seg));
|
||||
avail_dsds--;
|
||||
|
||||
cur_dsd++;
|
||||
cur_seg++;
|
||||
}
|
||||
} else {
|
||||
cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle));
|
||||
cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle));
|
||||
cur_dsd->count = cpu_to_le32(cmd->request_bufflen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_send_command_to_isp - issues command to HBA
|
||||
* @ha: pointer to host adapter structure.
|
||||
* @srb: pointer to SCSI Request Block to be sent to ISP
|
||||
*
|
||||
* This routine is called by qla4xxx_queuecommand to build an ISP
|
||||
* command and pass it to the ISP for execution.
|
||||
**/
|
||||
int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
|
||||
{
|
||||
struct scsi_cmnd *cmd = srb->cmd;
|
||||
struct ddb_entry *ddb_entry;
|
||||
struct command_t3_entry *cmd_entry;
|
||||
struct scatterlist *sg = NULL;
|
||||
|
||||
uint16_t tot_dsds;
|
||||
uint16_t req_cnt;
|
||||
|
||||
unsigned long flags;
|
||||
uint16_t cnt;
|
||||
uint32_t index;
|
||||
char tag[2];
|
||||
|
||||
/* Get real lun and adapter */
|
||||
ddb_entry = srb->ddb;
|
||||
|
||||
/* Send marker(s) if needed. */
|
||||
if (ha->marker_needed == 1) {
|
||||
if (qla4xxx_send_marker_iocb(ha, ddb_entry,
|
||||
cmd->device->lun) != QLA_SUCCESS)
|
||||
return QLA_ERROR;
|
||||
|
||||
ha->marker_needed = 0;
|
||||
}
|
||||
tot_dsds = 0;
|
||||
|
||||
/* Acquire hardware specific lock */
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
|
||||
index = (uint32_t)cmd->request->tag;
|
||||
|
||||
/* Calculate the number of request entries needed. */
|
||||
if (cmd->use_sg) {
|
||||
sg = (struct scatterlist *)cmd->request_buffer;
|
||||
tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
|
||||
cmd->sc_data_direction);
|
||||
if (tot_dsds == 0)
|
||||
goto queuing_error;
|
||||
} else if (cmd->request_bufflen) {
|
||||
dma_addr_t req_dma;
|
||||
|
||||
req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
|
||||
cmd->request_bufflen,
|
||||
cmd->sc_data_direction);
|
||||
if (dma_mapping_error(req_dma))
|
||||
goto queuing_error;
|
||||
|
||||
srb->dma_handle = req_dma;
|
||||
tot_dsds = 1;
|
||||
}
|
||||
req_cnt = qla4xxx_calc_request_entries(tot_dsds);
|
||||
|
||||
if (ha->req_q_count < (req_cnt + 2)) {
|
||||
cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
|
||||
if (ha->request_in < cnt)
|
||||
ha->req_q_count = cnt - ha->request_in;
|
||||
else
|
||||
ha->req_q_count = REQUEST_QUEUE_DEPTH -
|
||||
(ha->request_in - cnt);
|
||||
}
|
||||
|
||||
if (ha->req_q_count < (req_cnt + 2))
|
||||
goto queuing_error;
|
||||
|
||||
/* total iocbs active */
|
||||
if ((ha->iocb_cnt + req_cnt) >= REQUEST_QUEUE_DEPTH)
|
||||
goto queuing_error;
|
||||
|
||||
/* Build command packet */
|
||||
cmd_entry = (struct command_t3_entry *) ha->request_ptr;
|
||||
memset(cmd_entry, 0, sizeof(struct command_t3_entry));
|
||||
cmd_entry->hdr.entryType = ET_COMMAND;
|
||||
cmd_entry->handle = cpu_to_le32(index);
|
||||
cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
|
||||
cmd_entry->connection_id = cpu_to_le16(ddb_entry->connection_id);
|
||||
|
||||
int_to_scsilun(cmd->device->lun, &cmd_entry->lun);
|
||||
cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn);
|
||||
cmd_entry->ttlByteCnt = cpu_to_le32(cmd->request_bufflen);
|
||||
memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len);
|
||||
cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds);
|
||||
cmd_entry->hdr.entryCount = req_cnt;
|
||||
|
||||
/* Set data transfer direction control flags
|
||||
* NOTE: Look at data_direction bits iff there is data to be
|
||||
* transferred, as the data direction bit is sometimed filled
|
||||
* in when there is no data to be transferred */
|
||||
cmd_entry->control_flags = CF_NO_DATA;
|
||||
if (cmd->request_bufflen) {
|
||||
if (cmd->sc_data_direction == DMA_TO_DEVICE)
|
||||
cmd_entry->control_flags = CF_WRITE;
|
||||
else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
|
||||
cmd_entry->control_flags = CF_READ;
|
||||
}
|
||||
|
||||
/* Set tagged queueing control flags */
|
||||
cmd_entry->control_flags |= CF_SIMPLE_TAG;
|
||||
if (scsi_populate_tag_msg(cmd, tag))
|
||||
switch (tag[0]) {
|
||||
case MSG_HEAD_TAG:
|
||||
cmd_entry->control_flags |= CF_HEAD_TAG;
|
||||
break;
|
||||
case MSG_ORDERED_TAG:
|
||||
cmd_entry->control_flags |= CF_ORDERED_TAG;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Advance request queue pointer */
|
||||
ha->request_in++;
|
||||
if (ha->request_in == REQUEST_QUEUE_DEPTH) {
|
||||
ha->request_in = 0;
|
||||
ha->request_ptr = ha->request_ring;
|
||||
} else
|
||||
ha->request_ptr++;
|
||||
|
||||
|
||||
qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
|
||||
wmb();
|
||||
|
||||
/*
|
||||
* Check to see if adapter is online before placing request on
|
||||
* request queue. If a reset occurs and a request is in the queue,
|
||||
* the firmware will still attempt to process the request, retrieving
|
||||
* garbage for pointers.
|
||||
*/
|
||||
if (!test_bit(AF_ONLINE, &ha->flags)) {
|
||||
DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
|
||||
"Do not issue command.\n",
|
||||
ha->host_no, __func__));
|
||||
goto queuing_error;
|
||||
}
|
||||
|
||||
srb->cmd->host_scribble = (unsigned char *)srb;
|
||||
|
||||
/* update counters */
|
||||
srb->state = SRB_ACTIVE_STATE;
|
||||
srb->flags |= SRB_DMA_VALID;
|
||||
|
||||
/* Track IOCB used */
|
||||
ha->iocb_cnt += req_cnt;
|
||||
srb->iocb_cnt = req_cnt;
|
||||
ha->req_q_count -= req_cnt;
|
||||
|
||||
/* Debug print statements */
|
||||
writel(ha->request_in, &ha->reg->req_q_in);
|
||||
readl(&ha->reg->req_q_in);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
return QLA_SUCCESS;
|
||||
|
||||
queuing_error:
|
||||
|
||||
if (cmd->use_sg && tot_dsds) {
|
||||
sg = (struct scatterlist *) cmd->request_buffer;
|
||||
pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
|
||||
cmd->sc_data_direction);
|
||||
} else if (tot_dsds)
|
||||
pci_unmap_single(ha->pdev, srb->dma_handle,
|
||||
cmd->request_bufflen, cmd->sc_data_direction);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
return QLA_ERROR;
|
||||
}
|
||||
|
|
@ -0,0 +1,797 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#include "ql4_def.h"
|
||||
|
||||
/**
|
||||
* qla2x00_process_completed_request() - Process a Fast Post response.
|
||||
* @ha: SCSI driver HA context
|
||||
* @index: SRB index
|
||||
**/
|
||||
static void qla4xxx_process_completed_request(struct scsi_qla_host *ha,
|
||||
uint32_t index)
|
||||
{
|
||||
struct srb *srb;
|
||||
|
||||
srb = qla4xxx_del_from_active_array(ha, index);
|
||||
if (srb) {
|
||||
/* Save ISP completion status */
|
||||
srb->cmd->result = DID_OK << 16;
|
||||
qla4xxx_srb_compl(ha, srb);
|
||||
} else {
|
||||
DEBUG2(printk("scsi%ld: Invalid ISP SCSI completion handle = "
|
||||
"%d\n", ha->host_no, index));
|
||||
set_bit(DPC_RESET_HA, &ha->dpc_flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_status_entry - processes status IOCBs
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @sts_entry: Pointer to status entry structure.
|
||||
**/
|
||||
static void qla4xxx_status_entry(struct scsi_qla_host *ha,
|
||||
struct status_entry *sts_entry)
|
||||
{
|
||||
uint8_t scsi_status;
|
||||
struct scsi_cmnd *cmd;
|
||||
struct srb *srb;
|
||||
struct ddb_entry *ddb_entry;
|
||||
uint32_t residual;
|
||||
uint16_t sensebytecnt;
|
||||
|
||||
if (sts_entry->completionStatus == SCS_COMPLETE &&
|
||||
sts_entry->scsiStatus == 0) {
|
||||
qla4xxx_process_completed_request(ha,
|
||||
le32_to_cpu(sts_entry->
|
||||
handle));
|
||||
return;
|
||||
}
|
||||
|
||||
srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
|
||||
if (!srb) {
|
||||
/* FIXMEdg: Don't we need to reset ISP in this case??? */
|
||||
DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid "
|
||||
"handle 0x%x, sp=%p. This cmd may have already "
|
||||
"been completed.\n", ha->host_no, __func__,
|
||||
le32_to_cpu(sts_entry->handle), srb));
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = srb->cmd;
|
||||
if (cmd == NULL) {
|
||||
DEBUG2(printk("scsi%ld: %s: Command already returned back to "
|
||||
"OS pkt->handle=%d srb=%p srb->state:%d\n",
|
||||
ha->host_no, __func__, sts_entry->handle,
|
||||
srb, srb->state));
|
||||
dev_warn(&ha->pdev->dev, "Command is NULL:"
|
||||
" already returned to OS (srb=%p)\n", srb);
|
||||
return;
|
||||
}
|
||||
|
||||
ddb_entry = srb->ddb;
|
||||
if (ddb_entry == NULL) {
|
||||
cmd->result = DID_NO_CONNECT << 16;
|
||||
goto status_entry_exit;
|
||||
}
|
||||
|
||||
residual = le32_to_cpu(sts_entry->residualByteCnt);
|
||||
|
||||
/* Translate ISP error to a Linux SCSI error. */
|
||||
scsi_status = sts_entry->scsiStatus;
|
||||
switch (sts_entry->completionStatus) {
|
||||
case SCS_COMPLETE:
|
||||
if (scsi_status == 0) {
|
||||
cmd->result = DID_OK << 16;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sts_entry->iscsiFlags &
|
||||
(ISCSI_FLAG_RESIDUAL_OVER|ISCSI_FLAG_RESIDUAL_UNDER))
|
||||
cmd->resid = residual;
|
||||
|
||||
cmd->result = DID_OK << 16 | scsi_status;
|
||||
|
||||
if (scsi_status != SCSI_CHECK_CONDITION)
|
||||
break;
|
||||
|
||||
/* Copy Sense Data into sense buffer. */
|
||||
memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
|
||||
|
||||
sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
|
||||
if (sensebytecnt == 0)
|
||||
break;
|
||||
|
||||
memcpy(cmd->sense_buffer, sts_entry->senseData,
|
||||
min(sensebytecnt,
|
||||
(uint16_t) sizeof(cmd->sense_buffer)));
|
||||
|
||||
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
|
||||
"ASC/ASCQ = %02x/%02x\n", ha->host_no,
|
||||
cmd->device->channel, cmd->device->id,
|
||||
cmd->device->lun, __func__,
|
||||
sts_entry->senseData[2] & 0x0f,
|
||||
sts_entry->senseData[12],
|
||||
sts_entry->senseData[13]));
|
||||
|
||||
srb->flags |= SRB_GOT_SENSE;
|
||||
break;
|
||||
|
||||
case SCS_INCOMPLETE:
|
||||
/* Always set the status to DID_ERROR, since
|
||||
* all conditions result in that status anyway */
|
||||
cmd->result = DID_ERROR << 16;
|
||||
break;
|
||||
|
||||
case SCS_RESET_OCCURRED:
|
||||
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Device RESET occurred\n",
|
||||
ha->host_no, cmd->device->channel,
|
||||
cmd->device->id, cmd->device->lun, __func__));
|
||||
|
||||
cmd->result = DID_RESET << 16;
|
||||
break;
|
||||
|
||||
case SCS_ABORTED:
|
||||
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Abort occurred\n",
|
||||
ha->host_no, cmd->device->channel,
|
||||
cmd->device->id, cmd->device->lun, __func__));
|
||||
|
||||
cmd->result = DID_RESET << 16;
|
||||
break;
|
||||
|
||||
case SCS_TIMEOUT:
|
||||
DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: Timeout\n",
|
||||
ha->host_no, cmd->device->channel,
|
||||
cmd->device->id, cmd->device->lun));
|
||||
|
||||
cmd->result = DID_BUS_BUSY << 16;
|
||||
|
||||
/*
|
||||
* Mark device missing so that we won't continue to send
|
||||
* I/O to this device. We should get a ddb state change
|
||||
* AEN soon.
|
||||
*/
|
||||
if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
|
||||
qla4xxx_mark_device_missing(ha, ddb_entry);
|
||||
break;
|
||||
|
||||
case SCS_DATA_UNDERRUN:
|
||||
case SCS_DATA_OVERRUN:
|
||||
if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
|
||||
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "
|
||||
"residual = 0x%x\n", ha->host_no,
|
||||
cmd->device->channel, cmd->device->id,
|
||||
cmd->device->lun, __func__, residual));
|
||||
|
||||
cmd->result = DID_ERROR << 16;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
|
||||
/*
|
||||
* Firmware detected a SCSI transport underrun
|
||||
* condition
|
||||
*/
|
||||
cmd->resid = residual;
|
||||
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: UNDERRUN status "
|
||||
"detected, xferlen = 0x%x, residual = "
|
||||
"0x%x\n",
|
||||
ha->host_no, cmd->device->channel,
|
||||
cmd->device->id,
|
||||
cmd->device->lun, __func__,
|
||||
cmd->request_bufflen,
|
||||
residual));
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is scsi_status, it takes precedense over
|
||||
* underflow condition.
|
||||
*/
|
||||
if (scsi_status != 0) {
|
||||
cmd->result = DID_OK << 16 | scsi_status;
|
||||
|
||||
if (scsi_status != SCSI_CHECK_CONDITION)
|
||||
break;
|
||||
|
||||
/* Copy Sense Data into sense buffer. */
|
||||
memset(cmd->sense_buffer, 0,
|
||||
sizeof(cmd->sense_buffer));
|
||||
|
||||
sensebytecnt =
|
||||
le16_to_cpu(sts_entry->senseDataByteCnt);
|
||||
if (sensebytecnt == 0)
|
||||
break;
|
||||
|
||||
memcpy(cmd->sense_buffer, sts_entry->senseData,
|
||||
min(sensebytecnt,
|
||||
(uint16_t) sizeof(cmd->sense_buffer)));
|
||||
|
||||
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
|
||||
"ASC/ASCQ = %02x/%02x\n", ha->host_no,
|
||||
cmd->device->channel, cmd->device->id,
|
||||
cmd->device->lun, __func__,
|
||||
sts_entry->senseData[2] & 0x0f,
|
||||
sts_entry->senseData[12],
|
||||
sts_entry->senseData[13]));
|
||||
} else {
|
||||
/*
|
||||
* If RISC reports underrun and target does not
|
||||
* report it then we must have a lost frame, so
|
||||
* tell upper layer to retry it by reporting a
|
||||
* bus busy.
|
||||
*/
|
||||
if ((sts_entry->iscsiFlags &
|
||||
ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
|
||||
cmd->result = DID_BUS_BUSY << 16;
|
||||
} else if ((cmd->request_bufflen - residual) <
|
||||
cmd->underflow) {
|
||||
/*
|
||||
* Handle mid-layer underflow???
|
||||
*
|
||||
* For kernels less than 2.4, the driver must
|
||||
* return an error if an underflow is detected.
|
||||
* For kernels equal-to and above 2.4, the
|
||||
* mid-layer will appearantly handle the
|
||||
* underflow by detecting the residual count --
|
||||
* unfortunately, we do not see where this is
|
||||
* actually being done. In the interim, we
|
||||
* will return DID_ERROR.
|
||||
*/
|
||||
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
|
||||
"Mid-layer Data underrun, "
|
||||
"xferlen = 0x%x, "
|
||||
"residual = 0x%x\n", ha->host_no,
|
||||
cmd->device->channel,
|
||||
cmd->device->id,
|
||||
cmd->device->lun, __func__,
|
||||
cmd->request_bufflen, residual));
|
||||
|
||||
cmd->result = DID_ERROR << 16;
|
||||
} else {
|
||||
cmd->result = DID_OK << 16;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SCS_DEVICE_LOGGED_OUT:
|
||||
case SCS_DEVICE_UNAVAILABLE:
|
||||
/*
|
||||
* Mark device missing so that we won't continue to
|
||||
* send I/O to this device. We should get a ddb
|
||||
* state change AEN soon.
|
||||
*/
|
||||
if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
|
||||
qla4xxx_mark_device_missing(ha, ddb_entry);
|
||||
|
||||
cmd->result = DID_BUS_BUSY << 16;
|
||||
break;
|
||||
|
||||
case SCS_QUEUE_FULL:
|
||||
/*
|
||||
* SCSI Mid-Layer handles device queue full
|
||||
*/
|
||||
cmd->result = DID_OK << 16 | sts_entry->scsiStatus;
|
||||
DEBUG2(printk("scsi%ld:%d:%d: %s: QUEUE FULL detected "
|
||||
"compl=%02x, scsi=%02x, state=%02x, iFlags=%02x,"
|
||||
" iResp=%02x\n", ha->host_no, cmd->device->id,
|
||||
cmd->device->lun, __func__,
|
||||
sts_entry->completionStatus,
|
||||
sts_entry->scsiStatus, sts_entry->state_flags,
|
||||
sts_entry->iscsiFlags,
|
||||
sts_entry->iscsiResponse));
|
||||
break;
|
||||
|
||||
default:
|
||||
cmd->result = DID_ERROR << 16;
|
||||
break;
|
||||
}
|
||||
|
||||
status_entry_exit:
|
||||
|
||||
/* complete the request */
|
||||
srb->cc_stat = sts_entry->completionStatus;
|
||||
qla4xxx_srb_compl(ha, srb);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_process_response_queue - process response queue completions
|
||||
* @ha: Pointer to host adapter structure.
|
||||
*
|
||||
* This routine process response queue completions in interrupt context.
|
||||
* Hardware_lock locked upon entry
|
||||
**/
|
||||
static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
struct srb *srb = NULL;
|
||||
struct status_entry *sts_entry;
|
||||
|
||||
/* Process all responses from response queue */
|
||||
while ((ha->response_in =
|
||||
(uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) !=
|
||||
ha->response_out) {
|
||||
sts_entry = (struct status_entry *) ha->response_ptr;
|
||||
count++;
|
||||
|
||||
/* Advance pointers for next entry */
|
||||
if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) {
|
||||
ha->response_out = 0;
|
||||
ha->response_ptr = ha->response_ring;
|
||||
} else {
|
||||
ha->response_out++;
|
||||
ha->response_ptr++;
|
||||
}
|
||||
|
||||
/* process entry */
|
||||
switch (sts_entry->hdr.entryType) {
|
||||
case ET_STATUS:
|
||||
/*
|
||||
* Common status - Single completion posted in single
|
||||
* IOSB.
|
||||
*/
|
||||
qla4xxx_status_entry(ha, sts_entry);
|
||||
break;
|
||||
|
||||
case ET_PASSTHRU_STATUS:
|
||||
break;
|
||||
|
||||
case ET_STATUS_CONTINUATION:
|
||||
/* Just throw away the status continuation entries */
|
||||
DEBUG2(printk("scsi%ld: %s: Status Continuation entry "
|
||||
"- ignoring\n", ha->host_no, __func__));
|
||||
break;
|
||||
|
||||
case ET_COMMAND:
|
||||
/* ISP device queue is full. Command not
|
||||
* accepted by ISP. Queue command for
|
||||
* later */
|
||||
|
||||
srb = qla4xxx_del_from_active_array(ha,
|
||||
le32_to_cpu(sts_entry->
|
||||
handle));
|
||||
if (srb == NULL)
|
||||
goto exit_prq_invalid_handle;
|
||||
|
||||
DEBUG2(printk("scsi%ld: %s: FW device queue full, "
|
||||
"srb %p\n", ha->host_no, __func__, srb));
|
||||
|
||||
/* ETRY normally by sending it back with
|
||||
* DID_BUS_BUSY */
|
||||
srb->cmd->result = DID_BUS_BUSY << 16;
|
||||
qla4xxx_srb_compl(ha, srb);
|
||||
break;
|
||||
|
||||
case ET_CONTINUE:
|
||||
/* Just throw away the continuation entries */
|
||||
DEBUG2(printk("scsi%ld: %s: Continuation entry - "
|
||||
"ignoring\n", ha->host_no, __func__));
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Invalid entry in response queue, reset RISC
|
||||
* firmware.
|
||||
*/
|
||||
DEBUG2(printk("scsi%ld: %s: Invalid entry %x in "
|
||||
"response queue \n", ha->host_no,
|
||||
__func__,
|
||||
sts_entry->hdr.entryType));
|
||||
goto exit_prq_error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Done with responses, update the ISP For QLA4010, this also clears
|
||||
* the interrupt.
|
||||
*/
|
||||
writel(ha->response_out, &ha->reg->rsp_q_out);
|
||||
readl(&ha->reg->rsp_q_out);
|
||||
|
||||
return;
|
||||
|
||||
exit_prq_invalid_handle:
|
||||
DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n",
|
||||
ha->host_no, __func__, srb, sts_entry->hdr.entryType,
|
||||
sts_entry->completionStatus));
|
||||
|
||||
exit_prq_error:
|
||||
writel(ha->response_out, &ha->reg->rsp_q_out);
|
||||
readl(&ha->reg->rsp_q_out);
|
||||
|
||||
set_bit(DPC_RESET_HA, &ha->dpc_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_isr_decode_mailbox - decodes mailbox status
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @mailbox_status: Mailbox status.
|
||||
*
|
||||
* This routine decodes the mailbox status during the ISR.
|
||||
* Hardware_lock locked upon entry. runs in interrupt context.
|
||||
**/
|
||||
static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
|
||||
uint32_t mbox_status)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((mbox_status == MBOX_STS_BUSY) ||
|
||||
(mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
|
||||
(mbox_status >> 12 == MBOX_COMPLETION_STATUS)) {
|
||||
ha->mbox_status[0] = mbox_status;
|
||||
|
||||
if (test_bit(AF_MBOX_COMMAND, &ha->flags)) {
|
||||
/*
|
||||
* Copy all mailbox registers to a temporary
|
||||
* location and set mailbox command done flag
|
||||
*/
|
||||
for (i = 1; i < ha->mbox_status_count; i++)
|
||||
ha->mbox_status[i] =
|
||||
readl(&ha->reg->mailbox[i]);
|
||||
|
||||
set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
|
||||
wake_up(&ha->mailbox_wait_queue);
|
||||
}
|
||||
} else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
|
||||
/* Immediately process the AENs that don't require much work.
|
||||
* Only queue the database_changed AENs */
|
||||
switch (mbox_status) {
|
||||
case MBOX_ASTS_SYSTEM_ERROR:
|
||||
/* Log Mailbox registers */
|
||||
if (ql4xdontresethba) {
|
||||
DEBUG2(printk("%s:Dont Reset HBA\n",
|
||||
__func__));
|
||||
} else {
|
||||
set_bit(AF_GET_CRASH_RECORD, &ha->flags);
|
||||
set_bit(DPC_RESET_HA, &ha->dpc_flags);
|
||||
}
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_REQUEST_TRANSFER_ERROR:
|
||||
case MBOX_ASTS_RESPONSE_TRANSFER_ERROR:
|
||||
case MBOX_ASTS_NVRAM_INVALID:
|
||||
case MBOX_ASTS_IP_ADDRESS_CHANGED:
|
||||
case MBOX_ASTS_DHCP_LEASE_EXPIRED:
|
||||
DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, "
|
||||
"Reset HA\n", ha->host_no, mbox_status));
|
||||
set_bit(DPC_RESET_HA, &ha->dpc_flags);
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_LINK_UP:
|
||||
DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n",
|
||||
ha->host_no, mbox_status));
|
||||
set_bit(AF_LINK_UP, &ha->flags);
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_LINK_DOWN:
|
||||
DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n",
|
||||
ha->host_no, mbox_status));
|
||||
clear_bit(AF_LINK_UP, &ha->flags);
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_HEARTBEAT:
|
||||
ha->seconds_since_last_heartbeat = 0;
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_DHCP_LEASE_ACQUIRED:
|
||||
DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE "
|
||||
"ACQUIRED\n", ha->host_no, mbox_status));
|
||||
set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM:
|
||||
case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target
|
||||
* mode
|
||||
* only */
|
||||
case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED: /* Connection mode */
|
||||
case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR:
|
||||
case MBOX_ASTS_SUBNET_STATE_CHANGE:
|
||||
/* No action */
|
||||
DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no,
|
||||
mbox_status));
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_MAC_ADDRESS_CHANGED:
|
||||
case MBOX_ASTS_DNS:
|
||||
/* No action */
|
||||
DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, "
|
||||
"mbox_sts[1]=%04x, mbox_sts[2]=%04x\n",
|
||||
ha->host_no, mbox_status,
|
||||
readl(&ha->reg->mailbox[1]),
|
||||
readl(&ha->reg->mailbox[2])));
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_SELF_TEST_FAILED:
|
||||
case MBOX_ASTS_LOGIN_FAILED:
|
||||
/* No action */
|
||||
DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, "
|
||||
"mbox_sts[2]=%04x, mbox_sts[3]=%04x\n",
|
||||
ha->host_no, mbox_status,
|
||||
readl(&ha->reg->mailbox[1]),
|
||||
readl(&ha->reg->mailbox[2]),
|
||||
readl(&ha->reg->mailbox[3])));
|
||||
break;
|
||||
|
||||
case MBOX_ASTS_DATABASE_CHANGED:
|
||||
/* Queue AEN information and process it in the DPC
|
||||
* routine */
|
||||
if (ha->aen_q_count > 0) {
|
||||
/* advance pointer */
|
||||
if (ha->aen_in == (MAX_AEN_ENTRIES - 1))
|
||||
ha->aen_in = 0;
|
||||
else
|
||||
ha->aen_in++;
|
||||
|
||||
/* decrement available counter */
|
||||
ha->aen_q_count--;
|
||||
|
||||
for (i = 1; i < MBOX_AEN_REG_COUNT; i++)
|
||||
ha->aen_q[ha->aen_in].mbox_sts[i] =
|
||||
readl(&ha->reg->mailbox[i]);
|
||||
|
||||
ha->aen_q[ha->aen_in].mbox_sts[0] = mbox_status;
|
||||
|
||||
/* print debug message */
|
||||
DEBUG2(printk("scsi%ld: AEN[%d] %04x queued"
|
||||
" mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
|
||||
ha->host_no, ha->aen_in,
|
||||
mbox_status,
|
||||
ha->aen_q[ha->aen_in].mbox_sts[1],
|
||||
ha->aen_q[ha->aen_in].mbox_sts[2],
|
||||
ha->aen_q[ha->aen_in].mbox_sts[3],
|
||||
ha->aen_q[ha->aen_in]. mbox_sts[4]));
|
||||
|
||||
/* The DPC routine will process the aen */
|
||||
set_bit(DPC_AEN, &ha->dpc_flags);
|
||||
} else {
|
||||
DEBUG2(printk("scsi%ld: %s: aen %04x, queue "
|
||||
"overflowed! AEN LOST!!\n",
|
||||
ha->host_no, __func__,
|
||||
mbox_status));
|
||||
|
||||
DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n",
|
||||
ha->host_no));
|
||||
|
||||
for (i = 0; i < MAX_AEN_ENTRIES; i++) {
|
||||
DEBUG2(printk("AEN[%d] %04x %04x %04x "
|
||||
"%04x\n", i,
|
||||
ha->aen_q[i].mbox_sts[0],
|
||||
ha->aen_q[i].mbox_sts[1],
|
||||
ha->aen_q[i].mbox_sts[2],
|
||||
ha->aen_q[i].mbox_sts[3]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG2(printk(KERN_WARNING
|
||||
"scsi%ld: AEN %04x UNKNOWN\n",
|
||||
ha->host_no, mbox_status));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n",
|
||||
ha->host_no, mbox_status));
|
||||
|
||||
ha->mbox_status[0] = mbox_status;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_interrupt_service_routine - isr
|
||||
* @ha: pointer to host adapter structure.
|
||||
*
|
||||
* This is the main interrupt service routine.
|
||||
* hardware_lock locked upon entry. runs in interrupt context.
|
||||
**/
|
||||
void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
|
||||
uint32_t intr_status)
|
||||
{
|
||||
/* Process response queue interrupt. */
|
||||
if (intr_status & CSR_SCSI_COMPLETION_INTR)
|
||||
qla4xxx_process_response_queue(ha);
|
||||
|
||||
/* Process mailbox/asynch event interrupt.*/
|
||||
if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
|
||||
qla4xxx_isr_decode_mailbox(ha,
|
||||
readl(&ha->reg->mailbox[0]));
|
||||
|
||||
/* Clear Mailbox Interrupt */
|
||||
writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
|
||||
&ha->reg->ctrl_status);
|
||||
readl(&ha->reg->ctrl_status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_intr_handler - hardware interrupt handler.
|
||||
* @irq: Unused
|
||||
* @dev_id: Pointer to host adapter structure
|
||||
* @regs: Unused
|
||||
**/
|
||||
irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
struct scsi_qla_host *ha;
|
||||
uint32_t intr_status;
|
||||
unsigned long flags = 0;
|
||||
uint8_t reqs_count = 0;
|
||||
|
||||
ha = (struct scsi_qla_host *) dev_id;
|
||||
if (!ha) {
|
||||
DEBUG2(printk(KERN_INFO
|
||||
"qla4xxx: Interrupt with NULL host ptr\n"));
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
|
||||
/*
|
||||
* Repeatedly service interrupts up to a maximum of
|
||||
* MAX_REQS_SERVICED_PER_INTR
|
||||
*/
|
||||
while (1) {
|
||||
/*
|
||||
* Read interrupt status
|
||||
*/
|
||||
if (le32_to_cpu(ha->shadow_regs->rsp_q_in) !=
|
||||
ha->response_out)
|
||||
intr_status = CSR_SCSI_COMPLETION_INTR;
|
||||
else
|
||||
intr_status = readl(&ha->reg->ctrl_status);
|
||||
|
||||
if ((intr_status &
|
||||
(CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) ==
|
||||
0) {
|
||||
if (reqs_count == 0)
|
||||
ha->spurious_int_count++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (intr_status & CSR_FATAL_ERROR) {
|
||||
DEBUG2(printk(KERN_INFO "scsi%ld: Fatal Error, "
|
||||
"Status 0x%04x\n", ha->host_no,
|
||||
readl(isp_port_error_status (ha))));
|
||||
|
||||
/* Issue Soft Reset to clear this error condition.
|
||||
* This will prevent the RISC from repeatedly
|
||||
* interrupting the driver; thus, allowing the DPC to
|
||||
* get scheduled to continue error recovery.
|
||||
* NOTE: Disabling RISC interrupts does not work in
|
||||
* this case, as CSR_FATAL_ERROR overrides
|
||||
* CSR_SCSI_INTR_ENABLE */
|
||||
if ((readl(&ha->reg->ctrl_status) &
|
||||
CSR_SCSI_RESET_INTR) == 0) {
|
||||
writel(set_rmask(CSR_SOFT_RESET),
|
||||
&ha->reg->ctrl_status);
|
||||
readl(&ha->reg->ctrl_status);
|
||||
}
|
||||
|
||||
writel(set_rmask(CSR_FATAL_ERROR),
|
||||
&ha->reg->ctrl_status);
|
||||
readl(&ha->reg->ctrl_status);
|
||||
|
||||
__qla4xxx_disable_intrs(ha);
|
||||
|
||||
set_bit(DPC_RESET_HA, &ha->dpc_flags);
|
||||
|
||||
break;
|
||||
} else if (intr_status & CSR_SCSI_RESET_INTR) {
|
||||
clear_bit(AF_ONLINE, &ha->flags);
|
||||
__qla4xxx_disable_intrs(ha);
|
||||
|
||||
writel(set_rmask(CSR_SCSI_RESET_INTR),
|
||||
&ha->reg->ctrl_status);
|
||||
readl(&ha->reg->ctrl_status);
|
||||
|
||||
set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
|
||||
|
||||
break;
|
||||
} else if (intr_status & INTR_PENDING) {
|
||||
qla4xxx_interrupt_service_routine(ha, intr_status);
|
||||
ha->total_io_count++;
|
||||
if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
|
||||
break;
|
||||
|
||||
intr_status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_process_aen - processes AENs generated by firmware
|
||||
* @ha: pointer to host adapter structure.
|
||||
* @process_aen: type of AENs to process
|
||||
*
|
||||
* Processes specific types of Asynchronous Events generated by firmware.
|
||||
* The type of AENs to process is specified by process_aen and can be
|
||||
* PROCESS_ALL_AENS 0
|
||||
* FLUSH_DDB_CHANGED_AENS 1
|
||||
* RELOGIN_DDB_CHANGED_AENS 2
|
||||
**/
|
||||
void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
|
||||
{
|
||||
uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
|
||||
struct aen *aen;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
while (ha->aen_out != ha->aen_in) {
|
||||
/* Advance pointers for next entry */
|
||||
if (ha->aen_out == (MAX_AEN_ENTRIES - 1))
|
||||
ha->aen_out = 0;
|
||||
else
|
||||
ha->aen_out++;
|
||||
|
||||
ha->aen_q_count++;
|
||||
aen = &ha->aen_q[ha->aen_out];
|
||||
|
||||
/* copy aen information to local structure */
|
||||
for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
|
||||
mbox_sts[i] = aen->mbox_sts[i];
|
||||
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
DEBUG(printk("scsi%ld: AEN[%d] %04x, index [%d] state=%04x "
|
||||
"mod=%x conerr=%08x \n", ha->host_no, ha->aen_out,
|
||||
mbox_sts[0], mbox_sts[2], mbox_sts[3],
|
||||
mbox_sts[1], mbox_sts[4]));
|
||||
|
||||
switch (mbox_sts[0]) {
|
||||
case MBOX_ASTS_DATABASE_CHANGED:
|
||||
if (process_aen == FLUSH_DDB_CHANGED_AENS) {
|
||||
DEBUG2(printk("scsi%ld: AEN[%d] %04x, index "
|
||||
"[%d] state=%04x FLUSHED!\n",
|
||||
ha->host_no, ha->aen_out,
|
||||
mbox_sts[0], mbox_sts[2],
|
||||
mbox_sts[3]));
|
||||
break;
|
||||
} else if (process_aen == RELOGIN_DDB_CHANGED_AENS) {
|
||||
/* for use during init time, we only want to
|
||||
* relogin non-active ddbs */
|
||||
struct ddb_entry *ddb_entry;
|
||||
|
||||
ddb_entry =
|
||||
/* FIXME: name length? */
|
||||
qla4xxx_lookup_ddb_by_fw_index(ha,
|
||||
mbox_sts[2]);
|
||||
if (!ddb_entry)
|
||||
break;
|
||||
|
||||
ddb_entry->dev_scan_wait_to_complete_relogin =
|
||||
0;
|
||||
ddb_entry->dev_scan_wait_to_start_relogin =
|
||||
jiffies +
|
||||
((ddb_entry->default_time2wait +
|
||||
4) * HZ);
|
||||
|
||||
DEBUG2(printk("scsi%ld: ddb index [%d] initate"
|
||||
" RELOGIN after %d seconds\n",
|
||||
ha->host_no,
|
||||
ddb_entry->fw_ddb_index,
|
||||
ddb_entry->default_time2wait +
|
||||
4));
|
||||
break;
|
||||
}
|
||||
|
||||
if (mbox_sts[1] == 0) { /* Global DB change. */
|
||||
qla4xxx_reinitialize_ddb_list(ha);
|
||||
} else if (mbox_sts[1] == 1) { /* Specific device. */
|
||||
qla4xxx_process_ddb_changed(ha, mbox_sts[2],
|
||||
mbox_sts[3]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,930 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#include "ql4_def.h"
|
||||
|
||||
|
||||
/**
|
||||
* qla4xxx_mailbox_command - issues mailbox commands
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @inCount: number of mailbox registers to load.
|
||||
* @outCount: number of mailbox registers to return.
|
||||
* @mbx_cmd: data pointer for mailbox in registers.
|
||||
* @mbx_sts: data pointer for mailbox out registers.
|
||||
*
|
||||
* This routine sssue mailbox commands and waits for completion.
|
||||
* If outCount is 0, this routine completes successfully WITHOUT waiting
|
||||
* for the mailbox command to complete.
|
||||
**/
|
||||
int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
|
||||
uint8_t outCount, uint32_t *mbx_cmd,
|
||||
uint32_t *mbx_sts)
|
||||
{
|
||||
int status = QLA_ERROR;
|
||||
uint8_t i;
|
||||
u_long wait_count;
|
||||
uint32_t intr_status;
|
||||
unsigned long flags = 0;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
mutex_lock(&ha->mbox_sem);
|
||||
|
||||
/* Mailbox code active */
|
||||
set_bit(AF_MBOX_COMMAND, &ha->flags);
|
||||
|
||||
/* Make sure that pointers are valid */
|
||||
if (!mbx_cmd || !mbx_sts) {
|
||||
DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts "
|
||||
"pointer\n", ha->host_no, __func__));
|
||||
goto mbox_exit;
|
||||
}
|
||||
|
||||
/* To prevent overwriting mailbox registers for a command that has
|
||||
* not yet been serviced, check to see if a previously issued
|
||||
* mailbox command is interrupting.
|
||||
* -----------------------------------------------------------------
|
||||
*/
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
intr_status = readl(&ha->reg->ctrl_status);
|
||||
if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
|
||||
/* Service existing interrupt */
|
||||
qla4xxx_interrupt_service_routine(ha, intr_status);
|
||||
clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
|
||||
}
|
||||
|
||||
/* Send the mailbox command to the firmware */
|
||||
ha->mbox_status_count = outCount;
|
||||
for (i = 0; i < outCount; i++)
|
||||
ha->mbox_status[i] = 0;
|
||||
|
||||
/* Load all mailbox registers, except mailbox 0. */
|
||||
for (i = 1; i < inCount; i++)
|
||||
writel(mbx_cmd[i], &ha->reg->mailbox[i]);
|
||||
|
||||
/* Wakeup firmware */
|
||||
writel(mbx_cmd[0], &ha->reg->mailbox[0]);
|
||||
readl(&ha->reg->mailbox[0]);
|
||||
writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
|
||||
readl(&ha->reg->ctrl_status);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
/* Wait for completion */
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&ha->mailbox_wait_queue, &wait);
|
||||
|
||||
/*
|
||||
* If we don't want status, don't wait for the mailbox command to
|
||||
* complete. For example, MBOX_CMD_RESET_FW doesn't return status,
|
||||
* you must poll the inbound Interrupt Mask for completion.
|
||||
*/
|
||||
if (outCount == 0) {
|
||||
status = QLA_SUCCESS;
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&ha->mailbox_wait_queue, &wait);
|
||||
goto mbox_exit;
|
||||
}
|
||||
/* Wait for command to complete */
|
||||
wait_count = jiffies + MBOX_TOV * HZ;
|
||||
while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
|
||||
if (time_after_eq(jiffies, wait_count))
|
||||
break;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
intr_status = readl(&ha->reg->ctrl_status);
|
||||
if (intr_status & INTR_PENDING) {
|
||||
/*
|
||||
* Service the interrupt.
|
||||
* The ISR will save the mailbox status registers
|
||||
* to a temporary storage location in the adapter
|
||||
* structure.
|
||||
*/
|
||||
ha->mbox_status_count = outCount;
|
||||
qla4xxx_interrupt_service_routine(ha, intr_status);
|
||||
}
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
msleep(10);
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&ha->mailbox_wait_queue, &wait);
|
||||
|
||||
/* Check for mailbox timeout. */
|
||||
if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
|
||||
DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...,"
|
||||
" Scheduling Adapter Reset\n", ha->host_no,
|
||||
mbx_cmd[0]));
|
||||
ha->mailbox_timeout_count++;
|
||||
mbx_sts[0] = (-1);
|
||||
set_bit(DPC_RESET_HA, &ha->dpc_flags);
|
||||
goto mbox_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the mailbox out registers to the caller's mailbox in/out
|
||||
* structure.
|
||||
*/
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
for (i = 0; i < outCount; i++)
|
||||
mbx_sts[i] = ha->mbox_status[i];
|
||||
|
||||
/* Set return status and error flags (if applicable). */
|
||||
switch (ha->mbox_status[0]) {
|
||||
case MBOX_STS_COMMAND_COMPLETE:
|
||||
status = QLA_SUCCESS;
|
||||
break;
|
||||
|
||||
case MBOX_STS_INTERMEDIATE_COMPLETION:
|
||||
status = QLA_SUCCESS;
|
||||
break;
|
||||
|
||||
case MBOX_STS_BUSY:
|
||||
DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
|
||||
ha->host_no, __func__, mbx_cmd[0]));
|
||||
ha->mailbox_timeout_count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, "
|
||||
"sts = %08X ****\n", ha->host_no, __func__,
|
||||
mbx_cmd[0], mbx_sts[0]));
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
mbox_exit:
|
||||
clear_bit(AF_MBOX_COMMAND, &ha->flags);
|
||||
clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
|
||||
mutex_unlock(&ha->mbox_sem);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qla4xxx_issue_iocb - issue mailbox iocb command
|
||||
* @ha: adapter state pointer.
|
||||
* @buffer: buffer pointer.
|
||||
* @phys_addr: physical address of buffer.
|
||||
* @size: size of buffer.
|
||||
*
|
||||
* Issues iocbs via mailbox commands.
|
||||
* TARGET_QUEUE_LOCK must be released.
|
||||
* ADAPTER_STATE_LOCK must be released.
|
||||
**/
|
||||
int
|
||||
qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer,
|
||||
dma_addr_t phys_addr, size_t size)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
int status;
|
||||
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64;
|
||||
mbox_cmd[1] = 0;
|
||||
mbox_cmd[2] = LSDW(phys_addr);
|
||||
mbox_cmd[3] = MSDW(phys_addr);
|
||||
status = qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
|
||||
return status;
|
||||
}
|
||||
|
||||
int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
|
||||
uint16_t fw_ddb_index,
|
||||
uint16_t connection_id,
|
||||
uint16_t option)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
|
||||
mbox_cmd[1] = fw_ddb_index;
|
||||
mbox_cmd[2] = connection_id;
|
||||
mbox_cmd[3] = LOGOUT_OPTION_RELOGIN;
|
||||
if (qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
|
||||
"option %04x failed sts %04X %04X",
|
||||
ha->host_no, __func__,
|
||||
option, mbox_sts[0], mbox_sts[1]));
|
||||
if (mbox_sts[0] == 0x4005)
|
||||
DEBUG2(printk("%s reason %04X\n", __func__,
|
||||
mbox_sts[1]));
|
||||
}
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
|
||||
uint16_t fw_ddb_index)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY;
|
||||
mbox_cmd[1] = fw_ddb_index;
|
||||
if (qla4xxx_mailbox_command(ha, 2, 5, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS)
|
||||
return QLA_ERROR;
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_initialize_fw_cb - initializes firmware control block.
|
||||
* @ha: Pointer to host adapter structure.
|
||||
**/
|
||||
int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
|
||||
{
|
||||
struct init_fw_ctrl_blk *init_fw_cb;
|
||||
dma_addr_t init_fw_cb_dma;
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
int status = QLA_ERROR;
|
||||
|
||||
init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
|
||||
sizeof(struct init_fw_ctrl_blk),
|
||||
&init_fw_cb_dma, GFP_KERNEL);
|
||||
if (init_fw_cb == NULL) {
|
||||
DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",
|
||||
ha->host_no, __func__));
|
||||
return 10;
|
||||
}
|
||||
memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
|
||||
|
||||
/* Get Initialize Firmware Control Block. */
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
|
||||
mbox_cmd[2] = LSDW(init_fw_cb_dma);
|
||||
mbox_cmd[3] = MSDW(init_fw_cb_dma);
|
||||
if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
sizeof(struct init_fw_ctrl_blk),
|
||||
init_fw_cb, init_fw_cb_dma);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Initialize request and response queues. */
|
||||
qla4xxx_init_rings(ha);
|
||||
|
||||
/* Fill in the request and response queue information. */
|
||||
init_fw_cb->ReqQConsumerIndex = cpu_to_le16(ha->request_out);
|
||||
init_fw_cb->ComplQProducerIndex = cpu_to_le16(ha->response_in);
|
||||
init_fw_cb->ReqQLen = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
|
||||
init_fw_cb->ComplQLen = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
|
||||
init_fw_cb->ReqQAddrLo = cpu_to_le32(LSDW(ha->request_dma));
|
||||
init_fw_cb->ReqQAddrHi = cpu_to_le32(MSDW(ha->request_dma));
|
||||
init_fw_cb->ComplQAddrLo = cpu_to_le32(LSDW(ha->response_dma));
|
||||
init_fw_cb->ComplQAddrHi = cpu_to_le32(MSDW(ha->response_dma));
|
||||
init_fw_cb->ShadowRegBufAddrLo =
|
||||
cpu_to_le32(LSDW(ha->shadow_regs_dma));
|
||||
init_fw_cb->ShadowRegBufAddrHi =
|
||||
cpu_to_le32(MSDW(ha->shadow_regs_dma));
|
||||
|
||||
/* Set up required options. */
|
||||
init_fw_cb->FwOptions |=
|
||||
__constant_cpu_to_le16(FWOPT_SESSION_MODE |
|
||||
FWOPT_INITIATOR_MODE);
|
||||
init_fw_cb->FwOptions &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
|
||||
|
||||
/* Save some info in adapter structure. */
|
||||
ha->firmware_options = le16_to_cpu(init_fw_cb->FwOptions);
|
||||
ha->tcp_options = le16_to_cpu(init_fw_cb->TCPOptions);
|
||||
ha->heartbeat_interval = init_fw_cb->HeartbeatInterval;
|
||||
memcpy(ha->ip_address, init_fw_cb->IPAddr,
|
||||
min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
|
||||
memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
|
||||
min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
|
||||
memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
|
||||
min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
|
||||
memcpy(ha->name_string, init_fw_cb->iSCSINameString,
|
||||
min(sizeof(ha->name_string),
|
||||
sizeof(init_fw_cb->iSCSINameString)));
|
||||
memcpy(ha->alias, init_fw_cb->Alias,
|
||||
min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));
|
||||
|
||||
/* Save Command Line Paramater info */
|
||||
ha->port_down_retry_count = le16_to_cpu(init_fw_cb->KeepAliveTimeout);
|
||||
ha->discovery_wait = ql4xdiscoverywait;
|
||||
|
||||
/* Send Initialize Firmware Control Block. */
|
||||
mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
|
||||
mbox_cmd[1] = 0;
|
||||
mbox_cmd[2] = LSDW(init_fw_cb_dma);
|
||||
mbox_cmd[3] = MSDW(init_fw_cb_dma);
|
||||
if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) ==
|
||||
QLA_SUCCESS)
|
||||
status = QLA_SUCCESS;
|
||||
else {
|
||||
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE "
|
||||
"failed w/ status %04X\n", ha->host_no, __func__,
|
||||
mbox_sts[0]));
|
||||
}
|
||||
dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
|
||||
init_fw_cb, init_fw_cb_dma);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP
|
||||
* @ha: Pointer to host adapter structure.
|
||||
**/
|
||||
int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
|
||||
{
|
||||
struct init_fw_ctrl_blk *init_fw_cb;
|
||||
dma_addr_t init_fw_cb_dma;
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
|
||||
sizeof(struct init_fw_ctrl_blk),
|
||||
&init_fw_cb_dma, GFP_KERNEL);
|
||||
if (init_fw_cb == NULL) {
|
||||
printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no,
|
||||
__func__);
|
||||
return 10;
|
||||
}
|
||||
|
||||
/* Get Initialize Firmware Control Block. */
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
|
||||
mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
|
||||
mbox_cmd[2] = LSDW(init_fw_cb_dma);
|
||||
mbox_cmd[3] = MSDW(init_fw_cb_dma);
|
||||
|
||||
if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
|
||||
ha->host_no, __func__));
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
sizeof(struct init_fw_ctrl_blk),
|
||||
init_fw_cb, init_fw_cb_dma);
|
||||
return QLA_ERROR;
|
||||
}
|
||||
|
||||
/* Save IP Address. */
|
||||
memcpy(ha->ip_address, init_fw_cb->IPAddr,
|
||||
min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
|
||||
memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
|
||||
min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
|
||||
memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
|
||||
min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
|
||||
|
||||
dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
|
||||
init_fw_cb, init_fw_cb_dma);
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_get_firmware_state - gets firmware state of HBA
|
||||
* @ha: Pointer to host adapter structure.
|
||||
**/
|
||||
int qla4xxx_get_firmware_state(struct scsi_qla_host * ha)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
/* Get firmware version */
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_GET_FW_STATE;
|
||||
if (qla4xxx_mailbox_command(ha, 1, 4, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ "
|
||||
"status %04X\n", ha->host_no, __func__,
|
||||
mbox_sts[0]));
|
||||
return QLA_ERROR;
|
||||
}
|
||||
ha->firmware_state = mbox_sts[1];
|
||||
ha->board_id = mbox_sts[2];
|
||||
ha->addl_fw_state = mbox_sts[3];
|
||||
DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n",
|
||||
ha->host_no, __func__, ha->firmware_state);)
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_get_firmware_status - retrieves firmware status
|
||||
* @ha: Pointer to host adapter structure.
|
||||
**/
|
||||
int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
/* Get firmware version */
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS;
|
||||
if (qla4xxx_mailbox_command(ha, 1, 3, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ "
|
||||
"status %04X\n", ha->host_no, __func__,
|
||||
mbox_sts[0]));
|
||||
return QLA_ERROR;
|
||||
}
|
||||
|
||||
/* High-water mark of IOCBs */
|
||||
ha->iocb_hiwat = mbox_sts[2];
|
||||
if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION)
|
||||
ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
|
||||
else
|
||||
dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d "
|
||||
"firmare IOCBs available (%d).\n",
|
||||
IOCB_HIWAT_CUSHION, ha->iocb_hiwat);
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_get_fwddb_entry - retrieves firmware ddb entry
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @fw_ddb_index: Firmware's device database index
|
||||
* @fw_ddb_entry: Pointer to firmware's device database entry structure
|
||||
* @num_valid_ddb_entries: Pointer to number of valid ddb entries
|
||||
* @next_ddb_index: Pointer to next valid device database index
|
||||
* @fw_ddb_device_state: Pointer to device state
|
||||
**/
|
||||
int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
|
||||
uint16_t fw_ddb_index,
|
||||
struct dev_db_entry *fw_ddb_entry,
|
||||
dma_addr_t fw_ddb_entry_dma,
|
||||
uint32_t *num_valid_ddb_entries,
|
||||
uint32_t *next_ddb_index,
|
||||
uint32_t *fw_ddb_device_state,
|
||||
uint32_t *conn_err_detail,
|
||||
uint16_t *tcp_source_port_num,
|
||||
uint16_t *connection_id)
|
||||
{
|
||||
int status = QLA_ERROR;
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
/* Make sure the device index is valid */
|
||||
if (fw_ddb_index >= MAX_DDB_ENTRIES) {
|
||||
DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n",
|
||||
ha->host_no, __func__, fw_ddb_index));
|
||||
goto exit_get_fwddb;
|
||||
}
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY;
|
||||
mbox_cmd[1] = (uint32_t) fw_ddb_index;
|
||||
mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
|
||||
mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
|
||||
if (qla4xxx_mailbox_command(ha, 4, 7, &mbox_cmd[0], &mbox_sts[0]) ==
|
||||
QLA_ERROR) {
|
||||
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed"
|
||||
" with status 0x%04X\n", ha->host_no, __func__,
|
||||
mbox_sts[0]));
|
||||
goto exit_get_fwddb;
|
||||
}
|
||||
if (fw_ddb_index != mbox_sts[1]) {
|
||||
DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n",
|
||||
ha->host_no, __func__, fw_ddb_index,
|
||||
mbox_sts[1]));
|
||||
goto exit_get_fwddb;
|
||||
}
|
||||
if (fw_ddb_entry) {
|
||||
dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d "
|
||||
"State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n",
|
||||
fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3],
|
||||
mbox_sts[4], mbox_sts[5], fw_ddb_entry->ipAddr[0],
|
||||
fw_ddb_entry->ipAddr[1], fw_ddb_entry->ipAddr[2],
|
||||
fw_ddb_entry->ipAddr[3],
|
||||
le16_to_cpu(fw_ddb_entry->portNumber),
|
||||
fw_ddb_entry->iscsiName);
|
||||
}
|
||||
if (num_valid_ddb_entries)
|
||||
*num_valid_ddb_entries = mbox_sts[2];
|
||||
if (next_ddb_index)
|
||||
*next_ddb_index = mbox_sts[3];
|
||||
if (fw_ddb_device_state)
|
||||
*fw_ddb_device_state = mbox_sts[4];
|
||||
|
||||
/*
|
||||
* RA: This mailbox has been changed to pass connection error and
|
||||
* details. Its true for ISP4010 as per Version E - Not sure when it
|
||||
* was changed. Get the time2wait from the fw_dd_entry field :
|
||||
* default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY
|
||||
* struct.
|
||||
*/
|
||||
if (conn_err_detail)
|
||||
*conn_err_detail = mbox_sts[5];
|
||||
if (tcp_source_port_num)
|
||||
*tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16;
|
||||
if (connection_id)
|
||||
*connection_id = (uint16_t) mbox_sts[6] & 0x00FF;
|
||||
status = QLA_SUCCESS;
|
||||
|
||||
exit_get_fwddb:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_set_fwddb_entry - sets a ddb entry.
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @fw_ddb_index: Firmware's device database index
|
||||
* @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL.
|
||||
*
|
||||
* This routine initializes or updates the adapter's device database
|
||||
* entry for the specified device. It also triggers a login for the
|
||||
* specified device. Therefore, it may also be used as a secondary
|
||||
* login routine when a NULL pointer is specified for the fw_ddb_entry.
|
||||
**/
|
||||
int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
|
||||
dma_addr_t fw_ddb_entry_dma)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
/* Do not wait for completion. The firmware will send us an
|
||||
* ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
|
||||
*/
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
|
||||
mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY;
|
||||
mbox_cmd[1] = (uint32_t) fw_ddb_index;
|
||||
mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
|
||||
mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
|
||||
return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
|
||||
}
|
||||
|
||||
int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
|
||||
uint16_t fw_ddb_index)
|
||||
{
|
||||
int status = QLA_ERROR;
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
/* Do not wait for completion. The firmware will send us an
|
||||
* ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
|
||||
*/
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN;
|
||||
mbox_cmd[1] = (uint32_t) fw_ddb_index;
|
||||
mbox_cmd[2] = 0;
|
||||
mbox_cmd[3] = 0;
|
||||
mbox_cmd[4] = 0;
|
||||
status = qla4xxx_mailbox_command(ha, 4, 0, &mbox_cmd[0], &mbox_sts[0]);
|
||||
DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n",
|
||||
__func__, fw_ddb_index, status, mbox_sts[0],
|
||||
mbox_sts[1]);)
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_get_crash_record - retrieves crash record.
|
||||
* @ha: Pointer to host adapter structure.
|
||||
*
|
||||
* This routine retrieves a crash record from the QLA4010 after an 8002h aen.
|
||||
**/
|
||||
void qla4xxx_get_crash_record(struct scsi_qla_host * ha)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
struct crash_record *crash_record = NULL;
|
||||
dma_addr_t crash_record_dma = 0;
|
||||
uint32_t crash_record_size = 0;
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_cmd));
|
||||
|
||||
/* Get size of crash record. */
|
||||
mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
|
||||
if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n",
|
||||
ha->host_no, __func__));
|
||||
goto exit_get_crash_record;
|
||||
}
|
||||
crash_record_size = mbox_sts[4];
|
||||
if (crash_record_size == 0) {
|
||||
DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n",
|
||||
ha->host_no, __func__));
|
||||
goto exit_get_crash_record;
|
||||
}
|
||||
|
||||
/* Alloc Memory for Crash Record. */
|
||||
crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size,
|
||||
&crash_record_dma, GFP_KERNEL);
|
||||
if (crash_record == NULL)
|
||||
goto exit_get_crash_record;
|
||||
|
||||
/* Get Crash Record. */
|
||||
mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
|
||||
mbox_cmd[2] = LSDW(crash_record_dma);
|
||||
mbox_cmd[3] = MSDW(crash_record_dma);
|
||||
mbox_cmd[4] = crash_record_size;
|
||||
if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS)
|
||||
goto exit_get_crash_record;
|
||||
|
||||
/* Dump Crash Record. */
|
||||
|
||||
exit_get_crash_record:
|
||||
if (crash_record)
|
||||
dma_free_coherent(&ha->pdev->dev, crash_record_size,
|
||||
crash_record, crash_record_dma);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_get_conn_event_log - retrieves connection event log
|
||||
* @ha: Pointer to host adapter structure.
|
||||
**/
|
||||
void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
struct conn_event_log_entry *event_log = NULL;
|
||||
dma_addr_t event_log_dma = 0;
|
||||
uint32_t event_log_size = 0;
|
||||
uint32_t num_valid_entries;
|
||||
uint32_t oldest_entry = 0;
|
||||
uint32_t max_event_log_entries;
|
||||
uint8_t i;
|
||||
|
||||
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_cmd));
|
||||
|
||||
/* Get size of crash record. */
|
||||
mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
|
||||
if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS)
|
||||
goto exit_get_event_log;
|
||||
|
||||
event_log_size = mbox_sts[4];
|
||||
if (event_log_size == 0)
|
||||
goto exit_get_event_log;
|
||||
|
||||
/* Alloc Memory for Crash Record. */
|
||||
event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size,
|
||||
&event_log_dma, GFP_KERNEL);
|
||||
if (event_log == NULL)
|
||||
goto exit_get_event_log;
|
||||
|
||||
/* Get Crash Record. */
|
||||
mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
|
||||
mbox_cmd[2] = LSDW(event_log_dma);
|
||||
mbox_cmd[3] = MSDW(event_log_dma);
|
||||
if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event "
|
||||
"log!\n", ha->host_no, __func__));
|
||||
goto exit_get_event_log;
|
||||
}
|
||||
|
||||
/* Dump Event Log. */
|
||||
num_valid_entries = mbox_sts[1];
|
||||
|
||||
max_event_log_entries = event_log_size /
|
||||
sizeof(struct conn_event_log_entry);
|
||||
|
||||
if (num_valid_entries > max_event_log_entries)
|
||||
oldest_entry = num_valid_entries % max_event_log_entries;
|
||||
|
||||
DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n",
|
||||
ha->host_no, num_valid_entries));
|
||||
|
||||
if (extended_error_logging == 3) {
|
||||
if (oldest_entry == 0) {
|
||||
/* Circular Buffer has not wrapped around */
|
||||
for (i=0; i < num_valid_entries; i++) {
|
||||
qla4xxx_dump_buffer((uint8_t *)event_log+
|
||||
(i*sizeof(*event_log)),
|
||||
sizeof(*event_log));
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Circular Buffer has wrapped around -
|
||||
* display accordingly*/
|
||||
for (i=oldest_entry; i < max_event_log_entries; i++) {
|
||||
qla4xxx_dump_buffer((uint8_t *)event_log+
|
||||
(i*sizeof(*event_log)),
|
||||
sizeof(*event_log));
|
||||
}
|
||||
for (i=0; i < oldest_entry; i++) {
|
||||
qla4xxx_dump_buffer((uint8_t *)event_log+
|
||||
(i*sizeof(*event_log)),
|
||||
sizeof(*event_log));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit_get_event_log:
|
||||
if (event_log)
|
||||
dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
|
||||
event_log_dma);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_reset_lun - issues LUN Reset
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @db_entry: Pointer to device database entry
|
||||
* @un_entry: Pointer to lun entry structure
|
||||
*
|
||||
* This routine performs a LUN RESET on the specified target/lun.
|
||||
* The caller must ensure that the ddb_entry and lun_entry pointers
|
||||
* are valid before calling this routine.
|
||||
**/
|
||||
int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
|
||||
int lun)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
int status = QLA_SUCCESS;
|
||||
|
||||
DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
|
||||
ddb_entry->os_target_id, lun));
|
||||
|
||||
/*
|
||||
* Send lun reset command to ISP, so that the ISP will return all
|
||||
* outstanding requests with RESET status
|
||||
*/
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_LUN_RESET;
|
||||
mbox_cmd[1] = ddb_entry->fw_ddb_index;
|
||||
mbox_cmd[2] = lun << 8;
|
||||
mbox_cmd[5] = 0x01; /* Immediate Command Enable */
|
||||
qla4xxx_mailbox_command(ha, 6, 1, &mbox_cmd[0], &mbox_sts[0]);
|
||||
if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
|
||||
mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
|
||||
status = QLA_ERROR;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
|
||||
uint32_t offset, uint32_t len)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_READ_FLASH;
|
||||
mbox_cmd[1] = LSDW(dma_addr);
|
||||
mbox_cmd[2] = MSDW(dma_addr);
|
||||
mbox_cmd[3] = offset;
|
||||
mbox_cmd[4] = len;
|
||||
if (qla4xxx_mailbox_command(ha, 5, 2, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ "
|
||||
"status %04X %04X, offset %08x, len %08x\n", ha->host_no,
|
||||
__func__, mbox_sts[0], mbox_sts[1], offset, len));
|
||||
return QLA_ERROR;
|
||||
}
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_get_fw_version - gets firmware version
|
||||
* @ha: Pointer to host adapter structure.
|
||||
*
|
||||
* Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may
|
||||
* hold an address for data. Make sure that we write 0 to those mailboxes,
|
||||
* if unused.
|
||||
**/
|
||||
int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
/* Get firmware version. */
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
mbox_cmd[0] = MBOX_CMD_ABOUT_FW;
|
||||
if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ "
|
||||
"status %04X\n", ha->host_no, __func__, mbox_sts[0]));
|
||||
return QLA_ERROR;
|
||||
}
|
||||
|
||||
/* Save firmware version information. */
|
||||
ha->firmware_version[0] = mbox_sts[1];
|
||||
ha->firmware_version[1] = mbox_sts[2];
|
||||
ha->patch_number = mbox_sts[3];
|
||||
ha->build_number = mbox_sts[4];
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
|
||||
mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS;
|
||||
mbox_cmd[2] = LSDW(dma_addr);
|
||||
mbox_cmd[3] = MSDW(dma_addr);
|
||||
|
||||
if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
|
||||
ha->host_no, __func__, mbox_sts[0]));
|
||||
return QLA_ERROR;
|
||||
}
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
|
||||
mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY;
|
||||
mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES;
|
||||
|
||||
if (qla4xxx_mailbox_command(ha, 2, 3, &mbox_cmd[0], &mbox_sts[0]) !=
|
||||
QLA_SUCCESS) {
|
||||
if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) {
|
||||
*ddb_index = mbox_sts[2];
|
||||
} else {
|
||||
DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
|
||||
ha->host_no, __func__, mbox_sts[0]));
|
||||
return QLA_ERROR;
|
||||
}
|
||||
} else {
|
||||
*ddb_index = MAX_PRST_DEV_DB_ENTRIES;
|
||||
}
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
|
||||
{
|
||||
struct dev_db_entry *fw_ddb_entry;
|
||||
dma_addr_t fw_ddb_entry_dma;
|
||||
uint32_t ddb_index;
|
||||
int ret_val = QLA_SUCCESS;
|
||||
|
||||
|
||||
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
|
||||
sizeof(*fw_ddb_entry),
|
||||
&fw_ddb_entry_dma, GFP_KERNEL);
|
||||
if (!fw_ddb_entry) {
|
||||
DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
|
||||
ha->host_no, __func__));
|
||||
ret_val = QLA_ERROR;
|
||||
goto qla4xxx_send_tgts_exit;
|
||||
}
|
||||
|
||||
ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma);
|
||||
if (ret_val != QLA_SUCCESS)
|
||||
goto qla4xxx_send_tgts_exit;
|
||||
|
||||
ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index);
|
||||
if (ret_val != QLA_SUCCESS)
|
||||
goto qla4xxx_send_tgts_exit;
|
||||
|
||||
memset((void *)fw_ddb_entry->iSCSIAlias, 0,
|
||||
sizeof(fw_ddb_entry->iSCSIAlias));
|
||||
|
||||
memset((void *)fw_ddb_entry->iscsiName, 0,
|
||||
sizeof(fw_ddb_entry->iscsiName));
|
||||
|
||||
memset((void *)fw_ddb_entry->ipAddr, 0, sizeof(fw_ddb_entry->ipAddr));
|
||||
memset((void *)fw_ddb_entry->targetAddr, 0,
|
||||
sizeof(fw_ddb_entry->targetAddr));
|
||||
|
||||
fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET);
|
||||
fw_ddb_entry->portNumber = cpu_to_le16(ntohs(port));
|
||||
|
||||
fw_ddb_entry->ipAddr[0] = *ip;
|
||||
fw_ddb_entry->ipAddr[1] = *(ip + 1);
|
||||
fw_ddb_entry->ipAddr[2] = *(ip + 2);
|
||||
fw_ddb_entry->ipAddr[3] = *(ip + 3);
|
||||
|
||||
ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma);
|
||||
|
||||
qla4xxx_send_tgts_exit:
|
||||
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
|
||||
fw_ddb_entry, fw_ddb_entry_dma);
|
||||
return ret_val;
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#include "ql4_def.h"
|
||||
|
||||
static inline int eeprom_size(struct scsi_qla_host *ha)
|
||||
{
|
||||
return is_qla4022(ha) ? FM93C86A_SIZE_16 : FM93C66A_SIZE_16;
|
||||
}
|
||||
|
||||
static inline int eeprom_no_addr_bits(struct scsi_qla_host *ha)
|
||||
{
|
||||
return is_qla4022(ha) ? FM93C86A_NO_ADDR_BITS_16 :
|
||||
FM93C56A_NO_ADDR_BITS_16;
|
||||
}
|
||||
|
||||
static inline int eeprom_no_data_bits(struct scsi_qla_host *ha)
|
||||
{
|
||||
return FM93C56A_DATA_BITS_16;
|
||||
}
|
||||
|
||||
static int fm93c56a_select(struct scsi_qla_host * ha)
|
||||
{
|
||||
DEBUG5(printk(KERN_ERR "fm93c56a_select:\n"));
|
||||
|
||||
ha->eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000;
|
||||
writel(ha->eeprom_cmd_data, isp_nvram(ha));
|
||||
readl(isp_nvram(ha));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr)
|
||||
{
|
||||
int i;
|
||||
int mask;
|
||||
int dataBit;
|
||||
int previousBit;
|
||||
|
||||
/* Clock in a zero, then do the start bit. */
|
||||
writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, isp_nvram(ha));
|
||||
writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
|
||||
AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
|
||||
writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
|
||||
AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
|
||||
readl(isp_nvram(ha));
|
||||
mask = 1 << (FM93C56A_CMD_BITS - 1);
|
||||
|
||||
/* Force the previous data bit to be different. */
|
||||
previousBit = 0xffff;
|
||||
for (i = 0; i < FM93C56A_CMD_BITS; i++) {
|
||||
dataBit =
|
||||
(cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
|
||||
if (previousBit != dataBit) {
|
||||
|
||||
/*
|
||||
* If the bit changed, then change the DO state to
|
||||
* match.
|
||||
*/
|
||||
writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha));
|
||||
previousBit = dataBit;
|
||||
}
|
||||
writel(ha->eeprom_cmd_data | dataBit |
|
||||
AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
|
||||
writel(ha->eeprom_cmd_data | dataBit |
|
||||
AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
|
||||
readl(isp_nvram(ha));
|
||||
cmd = cmd << 1;
|
||||
}
|
||||
mask = 1 << (eeprom_no_addr_bits(ha) - 1);
|
||||
|
||||
/* Force the previous data bit to be different. */
|
||||
previousBit = 0xffff;
|
||||
for (i = 0; i < eeprom_no_addr_bits(ha); i++) {
|
||||
dataBit = addr & mask ? AUBURN_EEPROM_DO_1 :
|
||||
AUBURN_EEPROM_DO_0;
|
||||
if (previousBit != dataBit) {
|
||||
/*
|
||||
* If the bit changed, then change the DO state to
|
||||
* match.
|
||||
*/
|
||||
writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha));
|
||||
previousBit = dataBit;
|
||||
}
|
||||
writel(ha->eeprom_cmd_data | dataBit |
|
||||
AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
|
||||
writel(ha->eeprom_cmd_data | dataBit |
|
||||
AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
|
||||
readl(isp_nvram(ha));
|
||||
addr = addr << 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fm93c56a_deselect(struct scsi_qla_host * ha)
|
||||
{
|
||||
ha->eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000;
|
||||
writel(ha->eeprom_cmd_data, isp_nvram(ha));
|
||||
readl(isp_nvram(ha));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fm93c56a_datain(struct scsi_qla_host * ha, unsigned short *value)
|
||||
{
|
||||
int i;
|
||||
int data = 0;
|
||||
int dataBit;
|
||||
|
||||
/* Read the data bits
|
||||
* The first bit is a dummy. Clock right over it. */
|
||||
for (i = 0; i < eeprom_no_data_bits(ha); i++) {
|
||||
writel(ha->eeprom_cmd_data |
|
||||
AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
|
||||
writel(ha->eeprom_cmd_data |
|
||||
AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
|
||||
dataBit =
|
||||
(readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0;
|
||||
data = (data << 1) | dataBit;
|
||||
}
|
||||
|
||||
*value = data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int eeprom_readword(int eepromAddr, u16 * value,
|
||||
struct scsi_qla_host * ha)
|
||||
{
|
||||
fm93c56a_select(ha);
|
||||
fm93c56a_cmd(ha, FM93C56A_READ, eepromAddr);
|
||||
fm93c56a_datain(ha, value);
|
||||
fm93c56a_deselect(ha);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Hardware_lock must be set before calling */
|
||||
u16 rd_nvram_word(struct scsi_qla_host * ha, int offset)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
/* NOTE: NVRAM uses half-word addresses */
|
||||
eeprom_readword(offset, &val, ha);
|
||||
return val;
|
||||
}
|
||||
|
||||
int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha)
|
||||
{
|
||||
int status = QLA_ERROR;
|
||||
uint16_t checksum = 0;
|
||||
uint32_t index;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
for (index = 0; index < eeprom_size(ha); index++)
|
||||
checksum += rd_nvram_word(ha, index);
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
if (checksum == 0)
|
||||
status = QLA_SUCCESS;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Hardware Semaphore routines
|
||||
*
|
||||
*************************************************************************/
|
||||
int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits)
|
||||
{
|
||||
uint32_t value;
|
||||
unsigned long flags;
|
||||
unsigned int seconds = 30;
|
||||
|
||||
DEBUG2(printk("scsi%ld : Trying to get SEM lock - mask= 0x%x, code = "
|
||||
"0x%x\n", ha->host_no, sem_mask, sem_bits));
|
||||
do {
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
writel((sem_mask | sem_bits), isp_semaphore(ha));
|
||||
value = readw(isp_semaphore(ha));
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
if ((value & (sem_mask >> 16)) == sem_bits) {
|
||||
DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, "
|
||||
"code = 0x%x\n", ha->host_no,
|
||||
sem_mask, sem_bits));
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
ssleep(1);
|
||||
} while (--seconds);
|
||||
return QLA_ERROR;
|
||||
}
|
||||
|
||||
void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
writel(sem_mask, isp_semaphore(ha));
|
||||
readl(isp_semaphore(ha));
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
DEBUG2(printk("scsi%ld : UNLOCK SEM - mask= 0x%x\n", ha->host_no,
|
||||
sem_mask));
|
||||
}
|
||||
|
||||
int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits)
|
||||
{
|
||||
uint32_t value;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
writel((sem_mask | sem_bits), isp_semaphore(ha));
|
||||
value = readw(isp_semaphore(ha));
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
if ((value & (sem_mask >> 16)) == sem_bits) {
|
||||
DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, code = "
|
||||
"0x%x, sema code=0x%x\n", ha->host_no,
|
||||
sem_mask, sem_bits, value));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#ifndef _QL4XNVRM_H_
|
||||
#define _QL4XNVRM_H_
|
||||
|
||||
/*
|
||||
* AM29LV Flash definitions
|
||||
*/
|
||||
#define FM93C56A_SIZE_8 0x100
|
||||
#define FM93C56A_SIZE_16 0x80
|
||||
#define FM93C66A_SIZE_8 0x200
|
||||
#define FM93C66A_SIZE_16 0x100/* 4010 */
|
||||
#define FM93C86A_SIZE_16 0x400/* 4022 */
|
||||
|
||||
#define FM93C56A_START 0x1
|
||||
|
||||
// Commands
|
||||
#define FM93C56A_READ 0x2
|
||||
#define FM93C56A_WEN 0x0
|
||||
#define FM93C56A_WRITE 0x1
|
||||
#define FM93C56A_WRITE_ALL 0x0
|
||||
#define FM93C56A_WDS 0x0
|
||||
#define FM93C56A_ERASE 0x3
|
||||
#define FM93C56A_ERASE_ALL 0x0
|
||||
|
||||
/* Command Extentions */
|
||||
#define FM93C56A_WEN_EXT 0x3
|
||||
#define FM93C56A_WRITE_ALL_EXT 0x1
|
||||
#define FM93C56A_WDS_EXT 0x0
|
||||
#define FM93C56A_ERASE_ALL_EXT 0x2
|
||||
|
||||
/* Address Bits */
|
||||
#define FM93C56A_NO_ADDR_BITS_16 8 /* 4010 */
|
||||
#define FM93C56A_NO_ADDR_BITS_8 9 /* 4010 */
|
||||
#define FM93C86A_NO_ADDR_BITS_16 10 /* 4022 */
|
||||
|
||||
/* Data Bits */
|
||||
#define FM93C56A_DATA_BITS_16 16
|
||||
#define FM93C56A_DATA_BITS_8 8
|
||||
|
||||
/* Special Bits */
|
||||
#define FM93C56A_READ_DUMMY_BITS 1
|
||||
#define FM93C56A_READY 0
|
||||
#define FM93C56A_BUSY 1
|
||||
#define FM93C56A_CMD_BITS 2
|
||||
|
||||
/* Auburn Bits */
|
||||
#define AUBURN_EEPROM_DI 0x8
|
||||
#define AUBURN_EEPROM_DI_0 0x0
|
||||
#define AUBURN_EEPROM_DI_1 0x8
|
||||
#define AUBURN_EEPROM_DO 0x4
|
||||
#define AUBURN_EEPROM_DO_0 0x0
|
||||
#define AUBURN_EEPROM_DO_1 0x4
|
||||
#define AUBURN_EEPROM_CS 0x2
|
||||
#define AUBURN_EEPROM_CS_0 0x0
|
||||
#define AUBURN_EEPROM_CS_1 0x2
|
||||
#define AUBURN_EEPROM_CLK_RISE 0x1
|
||||
#define AUBURN_EEPROM_CLK_FALL 0x0
|
||||
|
||||
/* */
|
||||
/* EEPROM format */
|
||||
/* */
|
||||
struct bios_params {
|
||||
uint16_t SpinUpDelay:1;
|
||||
uint16_t BIOSDisable:1;
|
||||
uint16_t MMAPEnable:1;
|
||||
uint16_t BootEnable:1;
|
||||
uint16_t Reserved0:12;
|
||||
uint8_t bootID0:7;
|
||||
uint8_t bootID0Valid:1;
|
||||
uint8_t bootLUN0[8];
|
||||
uint8_t bootID1:7;
|
||||
uint8_t bootID1Valid:1;
|
||||
uint8_t bootLUN1[8];
|
||||
uint16_t MaxLunsPerTarget;
|
||||
uint8_t Reserved1[10];
|
||||
};
|
||||
|
||||
struct eeprom_port_cfg {
|
||||
|
||||
/* MTU MAC 0 */
|
||||
u16 etherMtu_mac;
|
||||
|
||||
/* Flow Control MAC 0 */
|
||||
u16 pauseThreshold_mac;
|
||||
u16 resumeThreshold_mac;
|
||||
u16 reserved[13];
|
||||
};
|
||||
|
||||
struct eeprom_function_cfg {
|
||||
u8 reserved[30];
|
||||
|
||||
/* MAC ADDR */
|
||||
u8 macAddress[6];
|
||||
u8 macAddressSecondary[6];
|
||||
u16 subsysVendorId;
|
||||
u16 subsysDeviceId;
|
||||
};
|
||||
|
||||
struct eeprom_data {
|
||||
union {
|
||||
struct { /* isp4010 */
|
||||
u8 asic_id[4]; /* x00 */
|
||||
u8 version; /* x04 */
|
||||
u8 reserved; /* x05 */
|
||||
u16 board_id; /* x06 */
|
||||
#define EEPROM_BOARDID_ELDORADO 1
|
||||
#define EEPROM_BOARDID_PLACER 2
|
||||
|
||||
#define EEPROM_SERIAL_NUM_SIZE 16
|
||||
u8 serial_number[EEPROM_SERIAL_NUM_SIZE]; /* x08 */
|
||||
|
||||
/* ExtHwConfig: */
|
||||
/* Offset = 24bytes
|
||||
*
|
||||
* | SSRAM Size| |ST|PD|SDRAM SZ| W| B| SP | |
|
||||
* |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
|
||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
*/
|
||||
u16 ext_hw_conf; /* x18 */
|
||||
u8 mac0[6]; /* x1A */
|
||||
u8 mac1[6]; /* x20 */
|
||||
u8 mac2[6]; /* x26 */
|
||||
u8 mac3[6]; /* x2C */
|
||||
u16 etherMtu; /* x32 */
|
||||
u16 macConfig; /* x34 */
|
||||
#define MAC_CONFIG_ENABLE_ANEG 0x0001
|
||||
#define MAC_CONFIG_ENABLE_PAUSE 0x0002
|
||||
u16 phyConfig; /* x36 */
|
||||
#define PHY_CONFIG_PHY_ADDR_MASK 0x1f
|
||||
#define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20
|
||||
u16 topcat; /* x38 */
|
||||
#define TOPCAT_PRESENT 0x0100
|
||||
#define TOPCAT_MASK 0xFF00
|
||||
|
||||
#define EEPROM_UNUSED_1_SIZE 2
|
||||
u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */
|
||||
u16 bufletSize; /* x3C */
|
||||
u16 bufletCount; /* x3E */
|
||||
u16 bufletPauseThreshold; /* x40 */
|
||||
u16 tcpWindowThreshold50; /* x42 */
|
||||
u16 tcpWindowThreshold25; /* x44 */
|
||||
u16 tcpWindowThreshold0; /* x46 */
|
||||
u16 ipHashTableBaseHi; /* x48 */
|
||||
u16 ipHashTableBaseLo; /* x4A */
|
||||
u16 ipHashTableSize; /* x4C */
|
||||
u16 tcpHashTableBaseHi; /* x4E */
|
||||
u16 tcpHashTableBaseLo; /* x50 */
|
||||
u16 tcpHashTableSize; /* x52 */
|
||||
u16 ncbTableBaseHi; /* x54 */
|
||||
u16 ncbTableBaseLo; /* x56 */
|
||||
u16 ncbTableSize; /* x58 */
|
||||
u16 drbTableBaseHi; /* x5A */
|
||||
u16 drbTableBaseLo; /* x5C */
|
||||
u16 drbTableSize; /* x5E */
|
||||
|
||||
#define EEPROM_UNUSED_2_SIZE 4
|
||||
u8 unused_2[EEPROM_UNUSED_2_SIZE]; /* x60 */
|
||||
u16 ipReassemblyTimeout; /* x64 */
|
||||
u16 tcpMaxWindowSizeHi; /* x66 */
|
||||
u16 tcpMaxWindowSizeLo; /* x68 */
|
||||
u32 net_ip_addr0; /* x6A Added for TOE
|
||||
* functionality. */
|
||||
u32 net_ip_addr1; /* x6E */
|
||||
u32 scsi_ip_addr0; /* x72 */
|
||||
u32 scsi_ip_addr1; /* x76 */
|
||||
#define EEPROM_UNUSED_3_SIZE 128 /* changed from 144 to account
|
||||
* for ip addresses */
|
||||
u8 unused_3[EEPROM_UNUSED_3_SIZE]; /* x7A */
|
||||
u16 subsysVendorId_f0; /* xFA */
|
||||
u16 subsysDeviceId_f0; /* xFC */
|
||||
|
||||
/* Address = 0x7F */
|
||||
#define FM93C56A_SIGNATURE 0x9356
|
||||
#define FM93C66A_SIGNATURE 0x9366
|
||||
u16 signature; /* xFE */
|
||||
|
||||
#define EEPROM_UNUSED_4_SIZE 250
|
||||
u8 unused_4[EEPROM_UNUSED_4_SIZE]; /* x100 */
|
||||
u16 subsysVendorId_f1; /* x1FA */
|
||||
u16 subsysDeviceId_f1; /* x1FC */
|
||||
u16 checksum; /* x1FE */
|
||||
} __attribute__ ((packed)) isp4010;
|
||||
struct { /* isp4022 */
|
||||
u8 asicId[4]; /* x00 */
|
||||
u8 version; /* x04 */
|
||||
u8 reserved_5; /* x05 */
|
||||
u16 boardId; /* x06 */
|
||||
u8 boardIdStr[16]; /* x08 */
|
||||
u8 serialNumber[16]; /* x18 */
|
||||
|
||||
/* External Hardware Configuration */
|
||||
u16 ext_hw_conf; /* x28 */
|
||||
|
||||
/* MAC 0 CONFIGURATION */
|
||||
struct eeprom_port_cfg macCfg_port0; /* x2A */
|
||||
|
||||
/* MAC 1 CONFIGURATION */
|
||||
struct eeprom_port_cfg macCfg_port1; /* x4A */
|
||||
|
||||
/* DDR SDRAM Configuration */
|
||||
u16 bufletSize; /* x6A */
|
||||
u16 bufletCount; /* x6C */
|
||||
u16 tcpWindowThreshold50; /* x6E */
|
||||
u16 tcpWindowThreshold25; /* x70 */
|
||||
u16 tcpWindowThreshold0; /* x72 */
|
||||
u16 ipHashTableBaseHi; /* x74 */
|
||||
u16 ipHashTableBaseLo; /* x76 */
|
||||
u16 ipHashTableSize; /* x78 */
|
||||
u16 tcpHashTableBaseHi; /* x7A */
|
||||
u16 tcpHashTableBaseLo; /* x7C */
|
||||
u16 tcpHashTableSize; /* x7E */
|
||||
u16 ncbTableBaseHi; /* x80 */
|
||||
u16 ncbTableBaseLo; /* x82 */
|
||||
u16 ncbTableSize; /* x84 */
|
||||
u16 drbTableBaseHi; /* x86 */
|
||||
u16 drbTableBaseLo; /* x88 */
|
||||
u16 drbTableSize; /* x8A */
|
||||
u16 reserved_142[4]; /* x8C */
|
||||
|
||||
/* TCP/IP Parameters */
|
||||
u16 ipReassemblyTimeout; /* x94 */
|
||||
u16 tcpMaxWindowSize; /* x96 */
|
||||
u16 ipSecurity; /* x98 */
|
||||
u8 reserved_156[294]; /* x9A */
|
||||
u16 qDebug[8]; /* QLOGIC USE ONLY x1C0 */
|
||||
struct eeprom_function_cfg funcCfg_fn0; /* x1D0 */
|
||||
u16 reserved_510; /* x1FE */
|
||||
|
||||
/* Address = 512 */
|
||||
u8 oemSpace[432]; /* x200 */
|
||||
struct bios_params sBIOSParams_fn1; /* x3B0 */
|
||||
struct eeprom_function_cfg funcCfg_fn1; /* x3D0 */
|
||||
u16 reserved_1022; /* x3FE */
|
||||
|
||||
/* Address = 1024 */
|
||||
u8 reserved_1024[464]; /* x400 */
|
||||
struct eeprom_function_cfg funcCfg_fn2; /* x5D0 */
|
||||
u16 reserved_1534; /* x5FE */
|
||||
|
||||
/* Address = 1536 */
|
||||
u8 reserved_1536[432]; /* x600 */
|
||||
struct bios_params sBIOSParams_fn3; /* x7B0 */
|
||||
struct eeprom_function_cfg funcCfg_fn3; /* x7D0 */
|
||||
u16 checksum; /* x7FE */
|
||||
} __attribute__ ((packed)) isp4022;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif /* _QL4XNVRM_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* QLogic iSCSI HBA Driver
|
||||
* Copyright (c) 2003-2006 QLogic Corporation
|
||||
*
|
||||
* See LICENSE.qla4xxx for copyright and licensing details.
|
||||
*/
|
||||
|
||||
#define QLA4XXX_DRIVER_VERSION "5.00.05b9-k"
|
||||
|
||||
#define QL4_DRIVER_MAJOR_VER 5
|
||||
#define QL4_DRIVER_MINOR_VER 0
|
||||
#define QL4_DRIVER_PATCH_VER 5
|
||||
#define QL4_DRIVER_BETA_VER 9
|
|
@ -215,18 +215,19 @@ static void raid_component_release(struct class_device *cdev)
|
|||
kfree(rc);
|
||||
}
|
||||
|
||||
void raid_component_add(struct raid_template *r,struct device *raid_dev,
|
||||
struct device *component_dev)
|
||||
int raid_component_add(struct raid_template *r,struct device *raid_dev,
|
||||
struct device *component_dev)
|
||||
{
|
||||
struct class_device *cdev =
|
||||
attribute_container_find_class_device(&r->raid_attrs.ac,
|
||||
raid_dev);
|
||||
struct raid_component *rc;
|
||||
struct raid_data *rd = class_get_devdata(cdev);
|
||||
int err;
|
||||
|
||||
rc = kzalloc(sizeof(*rc), GFP_KERNEL);
|
||||
if (!rc)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&rc->node);
|
||||
class_device_initialize(&rc->cdev);
|
||||
|
@ -239,7 +240,18 @@ void raid_component_add(struct raid_template *r,struct device *raid_dev,
|
|||
list_add_tail(&rc->node, &rd->component_list);
|
||||
rc->cdev.parent = cdev;
|
||||
rc->cdev.class = &raid_class.class;
|
||||
class_device_add(&rc->cdev);
|
||||
err = class_device_add(&rc->cdev);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
list_del(&rc->node);
|
||||
rd->component_count--;
|
||||
put_device(component_dev);
|
||||
kfree(rc);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(raid_component_add);
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ const char * scsi_device_type(unsigned type)
|
|||
return "Well-known LUN ";
|
||||
if (type == 0x1f)
|
||||
return "No Device ";
|
||||
if (type > ARRAY_SIZE(scsi_device_types))
|
||||
if (type >= ARRAY_SIZE(scsi_device_types))
|
||||
return "Unknown ";
|
||||
return scsi_device_types[type];
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ static struct {
|
|||
{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
|
||||
{"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */
|
||||
{"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */
|
||||
{"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
|
||||
{"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN},
|
||||
{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
|
@ -161,6 +162,11 @@ static struct {
|
|||
{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
|
||||
{"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */
|
||||
{"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */
|
||||
{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
|
||||
|
@ -168,6 +174,14 @@ static struct {
|
|||
{"HP", "C1557A", NULL, BLIST_FORCELUN},
|
||||
{"HP", "C3323-300", "4269", BLIST_NOTQ},
|
||||
{"HP", "C5713A", NULL, BLIST_NOREPORTLUN},
|
||||
{"HP", "DF400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HP", "DF500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HP", "DF600", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
|
||||
{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
|
||||
{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
|
||||
|
@ -188,6 +202,7 @@ static struct {
|
|||
{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
|
||||
{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
|
||||
{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
|
||||
{"NEC", "iStorage", NULL, BLIST_REPORTLUN2},
|
||||
{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
|
||||
{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
|
||||
{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
|
||||
|
@ -210,6 +225,7 @@ static struct {
|
|||
{"SUN", "T300", "*", BLIST_SPARSELUN},
|
||||
{"SUN", "T4", "*", BLIST_SPARSELUN},
|
||||
{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
|
||||
{"Tornado-", "F4", "*", BLIST_NOREPORTLUN},
|
||||
{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
|
||||
{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
|
||||
{"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36},
|
||||
|
|
|
@ -426,7 +426,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
|
|||
free_req:
|
||||
blk_put_request(req);
|
||||
free_sense:
|
||||
kfree(sioc);
|
||||
kmem_cache_free(scsi_io_context_cache, sioc);
|
||||
return DRIVER_ERROR << 24;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scsi_execute_async);
|
||||
|
|
|
@ -1794,7 +1794,7 @@ static void sd_shutdown(struct device *dev)
|
|||
**/
|
||||
static int __init init_sd(void)
|
||||
{
|
||||
int majors = 0, i;
|
||||
int majors = 0, i, err;
|
||||
|
||||
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
|
||||
|
||||
|
@ -1805,9 +1805,22 @@ static int __init init_sd(void)
|
|||
if (!majors)
|
||||
return -ENODEV;
|
||||
|
||||
class_register(&sd_disk_class);
|
||||
err = class_register(&sd_disk_class);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return scsi_register_driver(&sd_template.gendrv);
|
||||
err = scsi_register_driver(&sd_template.gendrv);
|
||||
if (err)
|
||||
goto err_out_class;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_class:
|
||||
class_unregister(&sd_disk_class);
|
||||
err_out:
|
||||
for (i = 0; i < SD_MAJORS; i++)
|
||||
unregister_blkdev(sd_major(i), "sd");
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1822,10 +1835,10 @@ static void __exit exit_sd(void)
|
|||
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
|
||||
|
||||
scsi_unregister_driver(&sd_template.gendrv);
|
||||
class_unregister(&sd_disk_class);
|
||||
|
||||
for (i = 0; i < SD_MAJORS; i++)
|
||||
unregister_blkdev(sd_major(i), "sd");
|
||||
|
||||
class_unregister(&sd_disk_class);
|
||||
}
|
||||
|
||||
module_init(init_sd);
|
||||
|
|
|
@ -94,7 +94,6 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -103,12 +102,13 @@
|
|||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
||||
#include <scsi/scsi_dbg.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "seagate.h"
|
||||
|
||||
#include <scsi/scsi_ioctl.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
|
||||
|
@ -322,6 +322,7 @@ static Signature __initdata signatures[] = {
|
|||
static int hostno = -1;
|
||||
static void seagate_reconnect_intr (int, void *, struct pt_regs *);
|
||||
static irqreturn_t do_seagate_reconnect_intr (int, void *, struct pt_regs *);
|
||||
static int seagate_st0x_bus_reset(struct scsi_cmnd *);
|
||||
|
||||
#ifdef FAST
|
||||
static int fast = 1;
|
||||
|
@ -585,8 +586,8 @@ static int linked_connected = 0;
|
|||
static unsigned char linked_target, linked_lun;
|
||||
#endif
|
||||
|
||||
static void (*done_fn) (Scsi_Cmnd *) = NULL;
|
||||
static Scsi_Cmnd *SCint = NULL;
|
||||
static void (*done_fn) (struct scsi_cmnd *) = NULL;
|
||||
static struct scsi_cmnd *SCint = NULL;
|
||||
|
||||
/*
|
||||
* These control whether or not disconnect / reconnect will be attempted,
|
||||
|
@ -633,7 +634,7 @@ static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id,
|
|||
static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
int temp;
|
||||
Scsi_Cmnd *SCtmp;
|
||||
struct scsi_cmnd *SCtmp;
|
||||
|
||||
DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
|
||||
|
||||
|
@ -675,10 +676,11 @@ static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
|
|||
|
||||
static int recursion_depth = 0;
|
||||
|
||||
static int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
|
||||
static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt,
|
||||
void (*done) (struct scsi_cmnd *))
|
||||
{
|
||||
int result, reconnect;
|
||||
Scsi_Cmnd *SCtmp;
|
||||
struct scsi_cmnd *SCtmp;
|
||||
|
||||
DANY ("seagate: que_command");
|
||||
done_fn = done;
|
||||
|
@ -1609,7 +1611,7 @@ connect_loop:
|
|||
return retcode (st0x_aborted);
|
||||
} /* end of internal_command */
|
||||
|
||||
static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
|
||||
static int seagate_st0x_abort(struct scsi_cmnd * SCpnt)
|
||||
{
|
||||
st0x_aborted = DID_ABORT;
|
||||
return SUCCESS;
|
||||
|
@ -1624,7 +1626,7 @@ static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
|
|||
* May be called with SCpnt = NULL
|
||||
*/
|
||||
|
||||
static int seagate_st0x_bus_reset(Scsi_Cmnd * SCpnt)
|
||||
static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt)
|
||||
{
|
||||
/* No timeouts - this command is going to fail because it was reset. */
|
||||
DANY ("scsi%d: Reseting bus... ", hostno);
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* seagate.h Copyright (C) 1992 Drew Eckhardt
|
||||
* low level scsi driver header for ST01/ST02 by
|
||||
* Drew Eckhardt
|
||||
*
|
||||
* <drew@colorado.edu>
|
||||
*/
|
||||
|
||||
#ifndef _SEAGATE_H
|
||||
#define SEAGATE_H
|
||||
|
||||
static int seagate_st0x_detect(struct scsi_host_template *);
|
||||
static int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
|
||||
|
||||
static int seagate_st0x_abort(Scsi_Cmnd *);
|
||||
static const char *seagate_st0x_info(struct Scsi_Host *);
|
||||
static int seagate_st0x_bus_reset(Scsi_Cmnd *);
|
||||
|
||||
#endif /* _SEAGATE_H */
|
|
@ -60,7 +60,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
|
|||
|
||||
#ifdef CONFIG_SCSI_PROC_FS
|
||||
#include <linux/proc_fs.h>
|
||||
static char *sg_version_date = "20060818";
|
||||
static char *sg_version_date = "20060920";
|
||||
|
||||
static int sg_proc_init(void);
|
||||
static void sg_proc_cleanup(void);
|
||||
|
@ -94,6 +94,9 @@ int sg_big_buff = SG_DEF_RESERVED_SIZE;
|
|||
static int def_reserved_size = -1; /* picks up init parameter */
|
||||
static int sg_allow_dio = SG_ALLOW_DIO_DEF;
|
||||
|
||||
static int scatter_elem_sz = SG_SCATTER_SZ;
|
||||
static int scatter_elem_sz_prev = SG_SCATTER_SZ;
|
||||
|
||||
#define SG_SECTOR_SZ 512
|
||||
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
|
||||
|
||||
|
@ -1537,11 +1540,9 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf)
|
|||
msleep(10); /* dirty detach so delay device destruction */
|
||||
}
|
||||
|
||||
/* Set 'perm' (4th argument) to 0 to disable module_param's definition
|
||||
* of sysfs parameters (which module_param doesn't yet support).
|
||||
* Sysfs parameters defined explicitly below.
|
||||
*/
|
||||
module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO);
|
||||
module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
|
||||
module_param_named(def_reserved_size, def_reserved_size, int,
|
||||
S_IRUGO | S_IWUSR);
|
||||
module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);
|
||||
|
||||
MODULE_AUTHOR("Douglas Gilbert");
|
||||
|
@ -1550,6 +1551,8 @@ MODULE_LICENSE("GPL");
|
|||
MODULE_VERSION(SG_VERSION_STR);
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
|
||||
|
||||
MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element "
|
||||
"size (default: max(SG_SCATTER_SZ, PAGE_SIZE))");
|
||||
MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
|
||||
MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
|
||||
|
||||
|
@ -1558,8 +1561,14 @@ init_sg(void)
|
|||
{
|
||||
int rc;
|
||||
|
||||
if (scatter_elem_sz < PAGE_SIZE) {
|
||||
scatter_elem_sz = PAGE_SIZE;
|
||||
scatter_elem_sz_prev = scatter_elem_sz;
|
||||
}
|
||||
if (def_reserved_size >= 0)
|
||||
sg_big_buff = def_reserved_size;
|
||||
else
|
||||
def_reserved_size = sg_big_buff;
|
||||
|
||||
rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
|
||||
SG_MAX_DEVS, "sg");
|
||||
|
@ -1842,15 +1851,30 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
|
|||
if (mx_sc_elems < 0)
|
||||
return mx_sc_elems; /* most likely -ENOMEM */
|
||||
|
||||
num = scatter_elem_sz;
|
||||
if (unlikely(num != scatter_elem_sz_prev)) {
|
||||
if (num < PAGE_SIZE) {
|
||||
scatter_elem_sz = PAGE_SIZE;
|
||||
scatter_elem_sz_prev = PAGE_SIZE;
|
||||
} else
|
||||
scatter_elem_sz_prev = num;
|
||||
}
|
||||
for (k = 0, sg = schp->buffer, rem_sz = blk_size;
|
||||
(rem_sz > 0) && (k < mx_sc_elems);
|
||||
++k, rem_sz -= ret_sz, ++sg) {
|
||||
|
||||
num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
|
||||
num = (rem_sz > scatter_elem_sz_prev) ?
|
||||
scatter_elem_sz_prev : rem_sz;
|
||||
p = sg_page_malloc(num, sfp->low_dma, &ret_sz);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
if (num == scatter_elem_sz_prev) {
|
||||
if (unlikely(ret_sz > scatter_elem_sz_prev)) {
|
||||
scatter_elem_sz = ret_sz;
|
||||
scatter_elem_sz_prev = ret_sz;
|
||||
}
|
||||
}
|
||||
sg->page = p;
|
||||
sg->length = ret_sz;
|
||||
|
||||
|
@ -2341,6 +2365,9 @@ sg_add_sfp(Sg_device * sdp, int dev)
|
|||
}
|
||||
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
|
||||
if (unlikely(sg_big_buff != def_reserved_size))
|
||||
sg_big_buff = def_reserved_size;
|
||||
|
||||
sg_build_reserve(sfp, sg_big_buff);
|
||||
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
|
||||
sfp->reserve.bufflen, sfp->reserve.k_use_sg));
|
||||
|
@ -2437,16 +2464,16 @@ sg_res_in_use(Sg_fd * sfp)
|
|||
return srp ? 1 : 0;
|
||||
}
|
||||
|
||||
/* If retSzp==NULL want exact size or fail */
|
||||
/* The size fetched (value output via retSzp) set when non-NULL return */
|
||||
static struct page *
|
||||
sg_page_malloc(int rqSz, int lowDma, int *retSzp)
|
||||
{
|
||||
struct page *resp = NULL;
|
||||
gfp_t page_mask;
|
||||
int order, a_size;
|
||||
int resSz = rqSz;
|
||||
int resSz;
|
||||
|
||||
if (rqSz <= 0)
|
||||
if ((rqSz <= 0) || (NULL == retSzp))
|
||||
return resp;
|
||||
|
||||
if (lowDma)
|
||||
|
@ -2456,8 +2483,9 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
|
|||
|
||||
for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
|
||||
order++, a_size <<= 1) ;
|
||||
resSz = a_size; /* rounded up if necessary */
|
||||
resp = alloc_pages(page_mask, order);
|
||||
while ((!resp) && order && retSzp) {
|
||||
while ((!resp) && order) {
|
||||
--order;
|
||||
a_size >>= 1; /* divide by 2, until PAGE_SIZE */
|
||||
resp = alloc_pages(page_mask, order); /* try half */
|
||||
|
@ -2466,8 +2494,7 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
|
|||
if (resp) {
|
||||
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
|
||||
memset(page_address(resp), 0, resSz);
|
||||
if (retSzp)
|
||||
*retSzp = resSz;
|
||||
*retSzp = resSz;
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
|
|
@ -195,9 +195,9 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
|
|||
static int st_probe(struct device *);
|
||||
static int st_remove(struct device *);
|
||||
|
||||
static void do_create_driverfs_files(void);
|
||||
static int do_create_driverfs_files(void);
|
||||
static void do_remove_driverfs_files(void);
|
||||
static void do_create_class_files(struct scsi_tape *, int, int);
|
||||
static int do_create_class_files(struct scsi_tape *, int, int);
|
||||
|
||||
static struct scsi_driver st_template = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -4048,7 +4048,9 @@ static int st_probe(struct device *dev)
|
|||
STm->cdevs[j] = cdev;
|
||||
|
||||
}
|
||||
do_create_class_files(tpnt, dev_num, mode);
|
||||
error = do_create_class_files(tpnt, dev_num, mode);
|
||||
if (error)
|
||||
goto out_free_tape;
|
||||
}
|
||||
|
||||
sdev_printk(KERN_WARNING, SDp,
|
||||
|
@ -4157,32 +4159,45 @@ static void scsi_tape_release(struct kref *kref)
|
|||
|
||||
static int __init init_st(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
validate_options();
|
||||
|
||||
printk(KERN_INFO
|
||||
"st: Version %s, fixed bufsize %d, s/g segs %d\n",
|
||||
printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
|
||||
verstr, st_fixed_buffer_size, st_max_sg_segs);
|
||||
|
||||
st_sysfs_class = class_create(THIS_MODULE, "scsi_tape");
|
||||
if (IS_ERR(st_sysfs_class)) {
|
||||
st_sysfs_class = NULL;
|
||||
printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n");
|
||||
return 1;
|
||||
return PTR_ERR(st_sysfs_class);
|
||||
}
|
||||
|
||||
if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
|
||||
ST_MAX_TAPE_ENTRIES, "st")) {
|
||||
if (scsi_register_driver(&st_template.gendrv) == 0) {
|
||||
do_create_driverfs_files();
|
||||
return 0;
|
||||
}
|
||||
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
|
||||
ST_MAX_TAPE_ENTRIES);
|
||||
err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
|
||||
ST_MAX_TAPE_ENTRIES, "st");
|
||||
if (err) {
|
||||
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
|
||||
SCSI_TAPE_MAJOR);
|
||||
goto err_class;
|
||||
}
|
||||
|
||||
err = scsi_register_driver(&st_template.gendrv);
|
||||
if (err)
|
||||
goto err_chrdev;
|
||||
|
||||
err = do_create_driverfs_files();
|
||||
if (err)
|
||||
goto err_scsidrv;
|
||||
|
||||
return 0;
|
||||
|
||||
err_scsidrv:
|
||||
scsi_unregister_driver(&st_template.gendrv);
|
||||
err_chrdev:
|
||||
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
|
||||
ST_MAX_TAPE_ENTRIES);
|
||||
err_class:
|
||||
class_destroy(st_sysfs_class);
|
||||
|
||||
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR);
|
||||
return 1;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit exit_st(void)
|
||||
|
@ -4225,14 +4240,33 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf)
|
|||
}
|
||||
static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
|
||||
|
||||
static void do_create_driverfs_files(void)
|
||||
static int do_create_driverfs_files(void)
|
||||
{
|
||||
struct device_driver *driverfs = &st_template.gendrv;
|
||||
int err;
|
||||
|
||||
driver_create_file(driverfs, &driver_attr_try_direct_io);
|
||||
driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
|
||||
driver_create_file(driverfs, &driver_attr_max_sg_segs);
|
||||
driver_create_file(driverfs, &driver_attr_version);
|
||||
err = driver_create_file(driverfs, &driver_attr_try_direct_io);
|
||||
if (err)
|
||||
return err;
|
||||
err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
|
||||
if (err)
|
||||
goto err_try_direct_io;
|
||||
err = driver_create_file(driverfs, &driver_attr_max_sg_segs);
|
||||
if (err)
|
||||
goto err_attr_fixed_buf;
|
||||
err = driver_create_file(driverfs, &driver_attr_version);
|
||||
if (err)
|
||||
goto err_attr_max_sg;
|
||||
|
||||
return 0;
|
||||
|
||||
err_attr_max_sg:
|
||||
driver_remove_file(driverfs, &driver_attr_max_sg_segs);
|
||||
err_attr_fixed_buf:
|
||||
driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
|
||||
err_try_direct_io:
|
||||
driver_remove_file(driverfs, &driver_attr_try_direct_io);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void do_remove_driverfs_files(void)
|
||||
|
@ -4293,15 +4327,12 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf)
|
|||
|
||||
CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
|
||||
|
||||
static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
|
||||
static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
|
||||
{
|
||||
int i, rew, error;
|
||||
char name[10];
|
||||
struct class_device *st_class_member;
|
||||
|
||||
if (!st_sysfs_class)
|
||||
return;
|
||||
|
||||
for (rew=0; rew < 2; rew++) {
|
||||
/* Make sure that the minor numbers corresponding to the four
|
||||
first modes always get the same names */
|
||||
|
@ -4316,18 +4347,24 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
|
|||
if (IS_ERR(st_class_member)) {
|
||||
printk(KERN_WARNING "st%d: class_device_create failed\n",
|
||||
dev_num);
|
||||
error = PTR_ERR(st_class_member);
|
||||
goto out;
|
||||
}
|
||||
class_set_devdata(st_class_member, &STp->modes[mode]);
|
||||
|
||||
class_device_create_file(st_class_member,
|
||||
&class_device_attr_defined);
|
||||
class_device_create_file(st_class_member,
|
||||
&class_device_attr_default_blksize);
|
||||
class_device_create_file(st_class_member,
|
||||
&class_device_attr_default_density);
|
||||
class_device_create_file(st_class_member,
|
||||
&class_device_attr_default_compression);
|
||||
error = class_device_create_file(st_class_member,
|
||||
&class_device_attr_defined);
|
||||
if (error) goto out;
|
||||
error = class_device_create_file(st_class_member,
|
||||
&class_device_attr_default_blksize);
|
||||
if (error) goto out;
|
||||
error = class_device_create_file(st_class_member,
|
||||
&class_device_attr_default_density);
|
||||
if (error) goto out;
|
||||
error = class_device_create_file(st_class_member,
|
||||
&class_device_attr_default_compression);
|
||||
if (error) goto out;
|
||||
|
||||
if (mode == 0 && rew == 0) {
|
||||
error = sysfs_create_link(&STp->device->sdev_gendev.kobj,
|
||||
&st_class_member->kobj,
|
||||
|
@ -4336,11 +4373,15 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
|
|||
printk(KERN_ERR
|
||||
"st%d: Can't create sysfs link from SCSI device.\n",
|
||||
dev_num);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
return;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* The following functions may be useful for a larger audience. */
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
* Written By:
|
||||
* Ed Lin <promise_linux@promise.com>
|
||||
*
|
||||
* Version: 2.9.0.13
|
||||
* Version: 3.0.0.1
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -37,11 +37,11 @@
|
|||
#include <scsi/scsi_tcq.h>
|
||||
|
||||
#define DRV_NAME "stex"
|
||||
#define ST_DRIVER_VERSION "2.9.0.13"
|
||||
#define ST_VER_MAJOR 2
|
||||
#define ST_VER_MINOR 9
|
||||
#define ST_DRIVER_VERSION "3.0.0.1"
|
||||
#define ST_VER_MAJOR 3
|
||||
#define ST_VER_MINOR 0
|
||||
#define ST_OEM 0
|
||||
#define ST_BUILD_VER 13
|
||||
#define ST_BUILD_VER 1
|
||||
|
||||
enum {
|
||||
/* MU register offset */
|
||||
|
@ -120,12 +120,18 @@ enum {
|
|||
|
||||
st_shasta = 0,
|
||||
st_vsc = 1,
|
||||
st_yosemite = 2,
|
||||
|
||||
PASSTHRU_REQ_TYPE = 0x00000001,
|
||||
PASSTHRU_REQ_NO_WAKEUP = 0x00000100,
|
||||
ST_INTERNAL_TIMEOUT = 30,
|
||||
|
||||
ST_TO_CMD = 0,
|
||||
ST_FROM_CMD = 1,
|
||||
|
||||
/* vendor specific commands of Promise */
|
||||
MGT_CMD = 0xd8,
|
||||
SINBAND_MGT_CMD = 0xd9,
|
||||
ARRAY_CMD = 0xe0,
|
||||
CONTROLLER_CMD = 0xe1,
|
||||
DEBUGGING_CMD = 0xe2,
|
||||
|
@ -133,14 +139,48 @@ enum {
|
|||
|
||||
PASSTHRU_GET_ADAPTER = 0x05,
|
||||
PASSTHRU_GET_DRVVER = 0x10,
|
||||
|
||||
CTLR_CONFIG_CMD = 0x03,
|
||||
CTLR_SHUTDOWN = 0x0d,
|
||||
|
||||
CTLR_POWER_STATE_CHANGE = 0x0e,
|
||||
CTLR_POWER_SAVING = 0x01,
|
||||
|
||||
PASSTHRU_SIGNATURE = 0x4e415041,
|
||||
MGT_CMD_SIGNATURE = 0xba,
|
||||
|
||||
INQUIRY_EVPD = 0x01,
|
||||
};
|
||||
|
||||
/* SCSI inquiry data */
|
||||
typedef struct st_inq {
|
||||
u8 DeviceType :5;
|
||||
u8 DeviceTypeQualifier :3;
|
||||
u8 DeviceTypeModifier :7;
|
||||
u8 RemovableMedia :1;
|
||||
u8 Versions;
|
||||
u8 ResponseDataFormat :4;
|
||||
u8 HiSupport :1;
|
||||
u8 NormACA :1;
|
||||
u8 ReservedBit :1;
|
||||
u8 AERC :1;
|
||||
u8 AdditionalLength;
|
||||
u8 Reserved[2];
|
||||
u8 SoftReset :1;
|
||||
u8 CommandQueue :1;
|
||||
u8 Reserved2 :1;
|
||||
u8 LinkedCommands :1;
|
||||
u8 Synchronous :1;
|
||||
u8 Wide16Bit :1;
|
||||
u8 Wide32Bit :1;
|
||||
u8 RelativeAddressing :1;
|
||||
u8 VendorId[8];
|
||||
u8 ProductId[16];
|
||||
u8 ProductRevisionLevel[4];
|
||||
u8 VendorSpecific[20];
|
||||
u8 Reserved3[40];
|
||||
} ST_INQ;
|
||||
|
||||
struct st_sgitem {
|
||||
u8 ctrl; /* SG_CF_xxx */
|
||||
u8 reserved[3];
|
||||
|
@ -181,7 +221,7 @@ struct req_msg {
|
|||
u8 task_attr;
|
||||
u8 task_manage;
|
||||
u8 prd_entry;
|
||||
u8 payload_sz; /* payload size in 4-byte */
|
||||
u8 payload_sz; /* payload size in 4-byte, not used */
|
||||
u8 cdb[STEX_CDB_LENGTH];
|
||||
u8 variable[REQ_VARIABLE_LEN];
|
||||
};
|
||||
|
@ -242,7 +282,8 @@ struct st_drvver {
|
|||
#define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg))
|
||||
#define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg))
|
||||
#define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
|
||||
#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + sizeof(struct st_frame))
|
||||
#define STEX_EXTRA_SIZE max(sizeof(struct st_frame), sizeof(ST_INQ))
|
||||
#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + STEX_EXTRA_SIZE)
|
||||
|
||||
struct st_ccb {
|
||||
struct req_msg *req;
|
||||
|
@ -403,7 +444,7 @@ static int stex_map_sg(struct st_hba *hba,
|
|||
}
|
||||
|
||||
static void stex_internal_copy(struct scsi_cmnd *cmd,
|
||||
const void *src, size_t *count, int sg_count)
|
||||
const void *src, size_t *count, int sg_count, int direction)
|
||||
{
|
||||
size_t lcount;
|
||||
size_t len;
|
||||
|
@ -427,7 +468,10 @@ static void stex_internal_copy(struct scsi_cmnd *cmd,
|
|||
} else
|
||||
d = cmd->request_buffer;
|
||||
|
||||
memcpy(d, s, len);
|
||||
if (direction == ST_TO_CMD)
|
||||
memcpy(d, s, len);
|
||||
else
|
||||
memcpy(s, d, len);
|
||||
|
||||
lcount -= len;
|
||||
if (cmd->use_sg)
|
||||
|
@ -449,7 +493,7 @@ static int stex_direct_copy(struct scsi_cmnd *cmd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
stex_internal_copy(cmd, src, &cp_len, n_elem);
|
||||
stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);
|
||||
|
||||
if (cmd->use_sg)
|
||||
pci_unmap_sg(hba->pdev, cmd->request_buffer,
|
||||
|
@ -480,7 +524,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
|
|||
p->subid =
|
||||
hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
|
||||
|
||||
stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count);
|
||||
stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -489,7 +533,6 @@ stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
|
|||
req->tag = cpu_to_le16(tag);
|
||||
req->task_attr = TASK_ATTRIBUTE_SIMPLE;
|
||||
req->task_manage = 0; /* not supported yet */
|
||||
req->payload_sz = (u8)(sizeof(struct req_msg)/sizeof(u32));
|
||||
|
||||
hba->ccb[tag].req = req;
|
||||
hba->out_req_cnt++;
|
||||
|
@ -595,8 +638,14 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
|
|||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
|
||||
req = stex_alloc_req(hba);
|
||||
req->lun = lun;
|
||||
req->target = id;
|
||||
|
||||
if (hba->cardtype == st_yosemite) {
|
||||
req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id;
|
||||
req->target = 0;
|
||||
} else {
|
||||
req->lun = lun;
|
||||
req->target = id;
|
||||
}
|
||||
|
||||
/* cdb */
|
||||
memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
|
||||
|
@ -680,7 +729,51 @@ static void stex_copy_data(struct st_ccb *ccb,
|
|||
|
||||
if (ccb->cmd == NULL)
|
||||
return;
|
||||
stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count);
|
||||
stex_internal_copy(ccb->cmd,
|
||||
resp->variable, &count, ccb->sg_count, ST_TO_CMD);
|
||||
}
|
||||
|
||||
static void stex_ys_commands(struct st_hba *hba,
|
||||
struct st_ccb *ccb, struct status_msg *resp)
|
||||
{
|
||||
size_t count;
|
||||
|
||||
if (ccb->cmd->cmnd[0] == MGT_CMD &&
|
||||
resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
|
||||
ccb->cmd->request_bufflen =
|
||||
le32_to_cpu(*(__le32 *)&resp->variable[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp->srb_status != 0)
|
||||
return;
|
||||
|
||||
/* determine inquiry command status by DeviceTypeQualifier */
|
||||
if (ccb->cmd->cmnd[0] == INQUIRY &&
|
||||
resp->scsi_status == SAM_STAT_GOOD) {
|
||||
ST_INQ *inq_data;
|
||||
|
||||
count = STEX_EXTRA_SIZE;
|
||||
stex_internal_copy(ccb->cmd, hba->copy_buffer,
|
||||
&count, ccb->sg_count, ST_FROM_CMD);
|
||||
inq_data = (ST_INQ *)hba->copy_buffer;
|
||||
if (inq_data->DeviceTypeQualifier != 0)
|
||||
ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT;
|
||||
else
|
||||
ccb->srb_status = SRB_STATUS_SUCCESS;
|
||||
} else if (ccb->cmd->cmnd[0] == REPORT_LUNS) {
|
||||
u8 *report_lun_data = (u8 *)hba->copy_buffer;
|
||||
|
||||
count = STEX_EXTRA_SIZE;
|
||||
stex_internal_copy(ccb->cmd, report_lun_data,
|
||||
&count, ccb->sg_count, ST_FROM_CMD);
|
||||
if (report_lun_data[2] || report_lun_data[3]) {
|
||||
report_lun_data[2] = 0x00;
|
||||
report_lun_data[3] = 0x08;
|
||||
stex_internal_copy(ccb->cmd, report_lun_data,
|
||||
&count, ccb->sg_count, ST_TO_CMD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
|
||||
|
@ -702,8 +795,17 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
|
|||
return;
|
||||
}
|
||||
|
||||
if (unlikely(hba->mu_status != MU_STATE_STARTED ||
|
||||
hba->out_req_cnt <= 0)) {
|
||||
/*
|
||||
* it's not a valid status payload if:
|
||||
* 1. there are no pending requests(e.g. during init stage)
|
||||
* 2. there are some pending requests, but the controller is in
|
||||
* reset status, and its type is not st_yosemite
|
||||
* firmware of st_yosemite in reset status will return pending requests
|
||||
* to driver, so we allow it to pass
|
||||
*/
|
||||
if (unlikely(hba->out_req_cnt <= 0 ||
|
||||
(hba->mu_status == MU_STATE_RESETTING &&
|
||||
hba->cardtype != st_yosemite))) {
|
||||
hba->status_tail = hba->status_head;
|
||||
goto update_status;
|
||||
}
|
||||
|
@ -723,6 +825,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
|
|||
if (unlikely(ccb->req == NULL)) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"(%s): lagging req\n", pci_name(hba->pdev));
|
||||
hba->out_req_cnt--;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -741,9 +844,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
|
|||
ccb->scsi_status = resp->scsi_status;
|
||||
|
||||
if (likely(ccb->cmd != NULL)) {
|
||||
if (hba->cardtype == st_yosemite)
|
||||
stex_ys_commands(hba, ccb, resp);
|
||||
|
||||
if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
|
||||
ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
|
||||
stex_controller_info(hba, ccb);
|
||||
|
||||
stex_unmap_sg(hba, ccb->cmd);
|
||||
stex_scsi_done(ccb);
|
||||
hba->out_req_cnt--;
|
||||
|
@ -948,6 +1055,7 @@ static int stex_reset(struct scsi_cmnd *cmd)
|
|||
{
|
||||
struct st_hba *hba;
|
||||
unsigned long flags;
|
||||
unsigned long before;
|
||||
hba = (struct st_hba *) &cmd->device->host->hostdata[0];
|
||||
|
||||
hba->mu_status = MU_STATE_RESETTING;
|
||||
|
@ -955,20 +1063,37 @@ static int stex_reset(struct scsi_cmnd *cmd)
|
|||
if (hba->cardtype == st_shasta)
|
||||
stex_hard_reset(hba);
|
||||
|
||||
if (stex_handshake(hba)) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"(%s): resetting: handshake failed\n",
|
||||
pci_name(hba->pdev));
|
||||
return FAILED;
|
||||
if (hba->cardtype != st_yosemite) {
|
||||
if (stex_handshake(hba)) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"(%s): resetting: handshake failed\n",
|
||||
pci_name(hba->pdev));
|
||||
return FAILED;
|
||||
}
|
||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||
hba->req_head = 0;
|
||||
hba->req_tail = 0;
|
||||
hba->status_head = 0;
|
||||
hba->status_tail = 0;
|
||||
hba->out_req_cnt = 0;
|
||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||
return SUCCESS;
|
||||
}
|
||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||
hba->req_head = 0;
|
||||
hba->req_tail = 0;
|
||||
hba->status_head = 0;
|
||||
hba->status_tail = 0;
|
||||
hba->out_req_cnt = 0;
|
||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||
|
||||
/* st_yosemite */
|
||||
writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);
|
||||
readl(hba->mmio_base + IDBL); /* flush */
|
||||
before = jiffies;
|
||||
while (hba->out_req_cnt > 0) {
|
||||
if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
"(%s): reset timeout\n", pci_name(hba->pdev));
|
||||
return FAILED;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
hba->mu_status = MU_STATE_STARTED;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1156,9 +1281,16 @@ static void stex_hba_stop(struct st_hba *hba)
|
|||
req = stex_alloc_req(hba);
|
||||
memset(req->cdb, 0, STEX_CDB_LENGTH);
|
||||
|
||||
req->cdb[0] = CONTROLLER_CMD;
|
||||
req->cdb[1] = CTLR_POWER_STATE_CHANGE;
|
||||
req->cdb[2] = CTLR_POWER_SAVING;
|
||||
if (hba->cardtype == st_yosemite) {
|
||||
req->cdb[0] = MGT_CMD;
|
||||
req->cdb[1] = MGT_CMD_SIGNATURE;
|
||||
req->cdb[2] = CTLR_CONFIG_CMD;
|
||||
req->cdb[3] = CTLR_SHUTDOWN;
|
||||
} else {
|
||||
req->cdb[0] = CONTROLLER_CMD;
|
||||
req->cdb[1] = CTLR_POWER_STATE_CHANGE;
|
||||
req->cdb[2] = CTLR_POWER_SAVING;
|
||||
}
|
||||
|
||||
hba->ccb[tag].cmd = NULL;
|
||||
hba->ccb[tag].sg_count = 0;
|
||||
|
@ -1222,6 +1354,7 @@ static struct pci_device_id stex_pci_tbl[] = {
|
|||
{ 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
|
||||
{ 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
|
||||
{ 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
|
||||
{ 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite },
|
||||
{ } /* terminate list */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
|
||||
|
|
|
@ -279,6 +279,10 @@ static void dc390_ResetDevParam(struct dc390_acb* pACB);
|
|||
static u32 dc390_laststatus = 0;
|
||||
static u8 dc390_adapterCnt = 0;
|
||||
|
||||
static int disable_clustering;
|
||||
module_param(disable_clustering, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(disable_clustering, "If you experience problems with your devices, try setting to 1");
|
||||
|
||||
/* Startup values, to be overriden on the commandline */
|
||||
static int tmscsim[] = {-2, -2, -2, -2, -2, -2};
|
||||
|
||||
|
@ -2299,7 +2303,7 @@ static struct scsi_host_template driver_template = {
|
|||
.this_id = 7,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.cmd_per_lun = 1,
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -2525,6 +2529,8 @@ static int __devinit dc390_probe_one(struct pci_dev *pdev,
|
|||
pci_set_master(pdev);
|
||||
|
||||
error = -ENOMEM;
|
||||
if (disable_clustering)
|
||||
driver_template.use_clustering = DISABLE_CLUSTERING;
|
||||
shost = scsi_host_alloc(&driver_template, sizeof(struct dc390_acb));
|
||||
if (!shost)
|
||||
goto out_disable_device;
|
||||
|
@ -2660,6 +2666,10 @@ static struct pci_driver dc390_driver = {
|
|||
|
||||
static int __init dc390_module_init(void)
|
||||
{
|
||||
if (!disable_clustering)
|
||||
printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n"
|
||||
"\twith \"disable_clustering=1\" and report to maintainers\n");
|
||||
|
||||
if (tmscsim[0] == -1 || tmscsim[0] > 15) {
|
||||
tmscsim[0] = 7;
|
||||
tmscsim[1] = 4;
|
||||
|
|
|
@ -77,5 +77,6 @@ DEFINE_RAID_ATTRIBUTE(enum raid_state, state)
|
|||
struct raid_template *raid_class_attach(struct raid_function_template *);
|
||||
void raid_class_release(struct raid_template *);
|
||||
|
||||
void raid_component_add(struct raid_template *, struct device *,
|
||||
struct device *);
|
||||
int __must_check raid_component_add(struct raid_template *, struct device *,
|
||||
struct device *);
|
||||
|
||||
|
|
|
@ -11,26 +11,10 @@
|
|||
Original driver (sg.h):
|
||||
* Copyright (C) 1992 Lawrence Foard
|
||||
Version 2 and 3 extensions to driver:
|
||||
* Copyright (C) 1998 - 2003 Douglas Gilbert
|
||||
* Copyright (C) 1998 - 2006 Douglas Gilbert
|
||||
|
||||
Version: 3.5.29 (20030529)
|
||||
This version is for 2.5 series kernels.
|
||||
|
||||
Changes since 3.5.28 (20030308)
|
||||
- fix bug introduced in version 3.1.24 (last segment of sgat list)
|
||||
Changes since 3.5.27 (20020812)
|
||||
- remove procfs entries: hosts, host_hdr + host_strs (now in sysfs)
|
||||
- add sysfs sg driver params: def_reserved_size, allow_dio, version
|
||||
- new boot option: "sg_allow_dio" and module parameter: "allow_dio"
|
||||
- multiple internal changes due to scsi subsystem rework
|
||||
Changes since 3.5.26 (20020708)
|
||||
- re-add direct IO using Kai Makisara's work
|
||||
- re-tab to 8, start using C99-isms
|
||||
- simplify memory management
|
||||
Changes since 3.5.25 (20020504)
|
||||
- driverfs additions
|
||||
- copy_to/from_user() fixes [William Stinson]
|
||||
- disable kiobufs support
|
||||
Version: 3.5.34 (20060920)
|
||||
This version is for 2.6 series kernels.
|
||||
|
||||
For a full changelog see http://www.torque.net/sg
|
||||
|
||||
|
@ -40,7 +24,7 @@ Map of SG verions to the Linux kernels in which they appear:
|
|||
2.1.40 2.2.20
|
||||
3.0.x optional version 3 sg driver for 2.2 series
|
||||
3.1.17++ 2.4.0++
|
||||
3.5.23++ 2.5.0++
|
||||
3.5.30++ 2.6.0++
|
||||
|
||||
Major new features in SG 3.x driver (cf SG 2.x drivers)
|
||||
- SG_IO ioctl() combines function if write() and read()
|
||||
|
@ -51,14 +35,15 @@ Major new features in SG 3.x driver (cf SG 2.x drivers)
|
|||
data into kernel buffers and then use the CPU to copy the data into the
|
||||
user space (vice versa for writes). That is called "indirect" IO due to
|
||||
the double handling of data. There are two methods offered to remove the
|
||||
redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and
|
||||
2) using the mmap() system call to map the reserve buffer (this driver has
|
||||
one reserve buffer per fd) into the user space. Both have their advantages.
|
||||
redundant copy: 1) direct IO and 2) using the mmap() system call to map
|
||||
the reserve buffer (this driver has one reserve buffer per fd) into the
|
||||
user space. Both have their advantages.
|
||||
In terms of absolute speed mmap() is faster. If speed is not a concern,
|
||||
indirect IO should be fine. Read the documentation for more information.
|
||||
|
||||
** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
|
||||
needed. That pseudo file's content is defaulted to 0. **
|
||||
** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or
|
||||
'echo 1 > /sys/module/sg/parameters/allow_dio' is needed.
|
||||
That attribute is 0 by default. **
|
||||
|
||||
Historical note: this SCSI pass-through driver has been known as "sg" for
|
||||
a decade. In broader kernel discussions "sg" is used to refer to scatter
|
||||
|
@ -72,20 +57,17 @@ Major new features in SG 3.x driver (cf SG 2.x drivers)
|
|||
http://www.torque.net/sg/p/sg_v3_ho.html
|
||||
This is a rendering from DocBook source [change the extension to "sgml"
|
||||
or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
|
||||
The SG_IO ioctl is now found in other parts kernel (e.g. the block layer).
|
||||
For more information see http://www.torque.net/sg/sg_io.html
|
||||
|
||||
The older, version 2 documents discuss the original sg interface in detail:
|
||||
http://www.torque.net/sg/p/scsi-generic.txt
|
||||
http://www.torque.net/sg/p/scsi-generic_long.txt
|
||||
A version of this document (potentially out of date) may also be found in
|
||||
the kernel source tree, probably at:
|
||||
Documentation/scsi/scsi-generic.txt .
|
||||
Also available: <kernel_source>/Documentation/scsi/scsi-generic.txt
|
||||
|
||||
Utility and test programs are available at the sg web site. They are
|
||||
bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
|
||||
lk 2.4 series).
|
||||
|
||||
There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
|
||||
http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
|
||||
packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils
|
||||
(for the lk 2.2 series).
|
||||
*/
|
||||
|
||||
|
||||
|
@ -238,13 +220,12 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
|
|||
#define SG_GET_ACCESS_COUNT 0x2289
|
||||
|
||||
|
||||
#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */
|
||||
#define SG_SCATTER_SZ (8 * 4096)
|
||||
/* Largest size (in bytes) a single scatter-gather list element can have.
|
||||
The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on
|
||||
i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
|
||||
by adapter then this value is the largest data block that can be
|
||||
read/written by a single scsi command. The user can find the value of
|
||||
PAGE_SIZE by calling getpagesize() defined in unistd.h . */
|
||||
The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'.
|
||||
This value should be a power of 2 (and may be rounded up internally).
|
||||
If scatter-gather is not supported by adapter then this value is the
|
||||
largest data block that can be read/written by a single scsi command. */
|
||||
|
||||
#define SG_DEFAULT_RETRIES 0
|
||||
|
||||
|
|
Loading…
Reference in New Issue