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 | ||||
|  | ||||
							
								
								
									
										7
									
								
								drivers/scsi/qla4xxx/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								drivers/scsi/qla4xxx/Kconfig
									
									
									
									
									
										Normal file
									
								
							| @ -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. | ||||
							
								
								
									
										5
									
								
								drivers/scsi/qla4xxx/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								drivers/scsi/qla4xxx/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| 
 | ||||
							
								
								
									
										197
									
								
								drivers/scsi/qla4xxx/ql4_dbg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								drivers/scsi/qla4xxx/ql4_dbg.c
									
									
									
									
									
										Normal file
									
								
							| @ -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"); | ||||
| } | ||||
							
								
								
									
										55
									
								
								drivers/scsi/qla4xxx/ql4_dbg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								drivers/scsi/qla4xxx/ql4_dbg.h
									
									
									
									
									
										Normal file
									
								
							| @ -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				/*  */ | ||||
							
								
								
									
										586
									
								
								drivers/scsi/qla4xxx/ql4_def.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										586
									
								
								drivers/scsi/qla4xxx/ql4_def.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 */ | ||||
							
								
								
									
										843
									
								
								drivers/scsi/qla4xxx/ql4_fw.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										843
									
								
								drivers/scsi/qla4xxx/ql4_fw.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 */ | ||||
							
								
								
									
										78
									
								
								drivers/scsi/qla4xxx/ql4_glbl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								drivers/scsi/qla4xxx/ql4_glbl.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 */ | ||||
							
								
								
									
										1340
									
								
								drivers/scsi/qla4xxx/ql4_init.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1340
									
								
								drivers/scsi/qla4xxx/ql4_init.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										84
									
								
								drivers/scsi/qla4xxx/ql4_inline.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								drivers/scsi/qla4xxx/ql4_inline.h
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| } | ||||
							
								
								
									
										368
									
								
								drivers/scsi/qla4xxx/ql4_iocb.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								drivers/scsi/qla4xxx/ql4_iocb.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										797
									
								
								drivers/scsi/qla4xxx/ql4_isr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										797
									
								
								drivers/scsi/qla4xxx/ql4_isr.c
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										930
									
								
								drivers/scsi/qla4xxx/ql4_mbx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										930
									
								
								drivers/scsi/qla4xxx/ql4_mbx.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										224
									
								
								drivers/scsi/qla4xxx/ql4_nvram.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								drivers/scsi/qla4xxx/ql4_nvram.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										256
									
								
								drivers/scsi/qla4xxx/ql4_nvram.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								drivers/scsi/qla4xxx/ql4_nvram.h
									
									
									
									
									
										Normal file
									
								
							| @ -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_ */ | ||||
							
								
								
									
										1755
									
								
								drivers/scsi/qla4xxx/ql4_os.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1755
									
								
								drivers/scsi/qla4xxx/ql4_os.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										13
									
								
								drivers/scsi/qla4xxx/ql4_version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								drivers/scsi/qla4xxx/ql4_version.h
									
									
									
									
									
										Normal file
									
								
							| @ -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
	
	Block a user