summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/3w-xxxx.c3
-rw-r--r--drivers/scsi/Kconfig20
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/NCR5380.c2868
-rw-r--r--drivers/scsi/NCR5380.h87
-rw-r--r--drivers/scsi/aacraid/linit.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h4
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h5
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h5
-rw-r--r--drivers/scsi/aic7xxx/queue.h2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sas.h49
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h14
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c209
-rw-r--r--drivers/scsi/arm/cumana_1.c31
-rw-r--r--drivers/scsi/arm/oak.c27
-rw-r--r--drivers/scsi/atari_NCR5380.c2266
-rw-r--r--drivers/scsi/atari_scsi.c102
-rw-r--r--drivers/scsi/atp870u.c3635
-rw-r--r--drivers/scsi/atp870u.h4
-rw-r--r--drivers/scsi/be2iscsi/Kconfig1
-rw-r--r--drivers/scsi/be2iscsi/be.h4
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c4
-rw-r--r--drivers/scsi/be2iscsi/be_main.c20
-rw-r--r--drivers/scsi/bfa/bfa.h7
-rw-r--r--drivers/scsi/bfa/bfa_core.c7
-rw-r--r--drivers/scsi/bfa/bfa_cs.h7
-rw-r--r--drivers/scsi/bfa/bfa_defs.h7
-rw-r--r--drivers/scsi/bfa/bfa_defs_fcs.h7
-rw-r--r--drivers/scsi/bfa/bfa_defs_svc.h7
-rw-r--r--drivers/scsi/bfa/bfa_fc.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcbuild.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.h7
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h9
-rw-r--r--drivers/scsi/bfa/bfa_fcs_fcpim.c7
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c9
-rw-r--r--drivers/scsi/bfa/bfa_fcs_rport.c7
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c7
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c7
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c9
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h7
-rw-r--r--drivers/scsi/bfa/bfa_ioc_cb.c7
-rw-r--r--drivers/scsi/bfa/bfa_ioc_ct.c7
-rw-r--r--drivers/scsi/bfa/bfa_modules.h7
-rw-r--r--drivers/scsi/bfa/bfa_plog.h7
-rw-r--r--drivers/scsi/bfa/bfa_port.c7
-rw-r--r--drivers/scsi/bfa/bfa_port.h7
-rw-r--r--drivers/scsi/bfa/bfa_svc.c7
-rw-r--r--drivers/scsi/bfa/bfa_svc.h7
-rw-r--r--drivers/scsi/bfa/bfad.c24
-rw-r--r--drivers/scsi/bfa/bfad_attr.c75
-rw-r--r--drivers/scsi/bfa/bfad_bsg.c7
-rw-r--r--drivers/scsi/bfa/bfad_bsg.h7
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c7
-rw-r--r--drivers/scsi/bfa/bfad_drv.h9
-rw-r--r--drivers/scsi/bfa/bfad_im.c35
-rw-r--r--drivers/scsi/bfa/bfad_im.h7
-rw-r--r--drivers/scsi/bfa/bfi.h7
-rw-r--r--drivers/scsi/bfa/bfi_ms.h7
-rw-r--r--drivers/scsi/bfa/bfi_reg.h9
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c2
-rw-r--r--drivers/scsi/cxlflash/common.h2
-rw-r--r--drivers/scsi/cxlflash/main.c54
-rw-r--r--drivers/scsi/cxlflash/main.h5
-rw-r--r--drivers/scsi/cxlflash/superpipe.c8
-rw-r--r--drivers/scsi/cxlflash/vlun.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c294
-rw-r--r--drivers/scsi/dmx3191d.c33
-rw-r--r--drivers/scsi/dtc.c115
-rw-r--r--drivers/scsi/dtc.h45
-rw-r--r--drivers/scsi/fcoe/fcoe.c2
-rw-r--r--drivers/scsi/g_NCR5380.c408
-rw-r--r--drivers/scsi/g_NCR5380.h66
-rw-r--r--drivers/scsi/hisi_sas/Kconfig8
-rw-r--r--drivers/scsi/hisi_sas/Makefile2
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas.h341
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c1358
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v1_hw.c1832
-rw-r--r--drivers/scsi/hpsa.c117
-rw-r--r--drivers/scsi/hpsa.h2
-rw-r--r--drivers/scsi/hpsa_cmd.h13
-rw-r--r--drivers/scsi/imm.c50
-rw-r--r--drivers/scsi/initio.c16
-rw-r--r--drivers/scsi/ipr.c35
-rw-r--r--drivers/scsi/ipr.h4
-rw-r--r--drivers/scsi/lpfc/lpfc.h16
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c48
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c1864
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c484
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c65
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h184
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h52
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c198
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c134
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c41
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c23
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c8
-rw-r--r--drivers/scsi/mac_scsi.c117
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c4
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c4
-rw-r--r--drivers/scsi/mvsas/mv_94xx.c134
-rw-r--r--drivers/scsi/mvsas/mv_94xx.h71
-rw-r--r--drivers/scsi/mvsas/mv_init.c2
-rw-r--r--drivers/scsi/mvsas/mv_sas.c17
-rw-r--r--drivers/scsi/mvsas/mv_sas.h5
-rw-r--r--drivers/scsi/osd/osd_initiator.c5
-rw-r--r--drivers/scsi/pas16.c116
-rw-r--r--drivers/scsi/pas16.h40
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c36
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h83
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c106
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h18
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c58
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c188
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c126
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c265
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c165
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c699
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h93
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c114
-rw-r--r--drivers/scsi/scsi.c20
-rw-r--r--drivers/scsi/scsi_debug.c14
-rw-r--r--drivers/scsi/scsi_devinfo.c1
-rw-r--r--drivers/scsi/scsi_dh.c72
-rw-r--r--drivers/scsi/scsi_lib.c189
-rw-r--r--drivers/scsi/scsi_priv.h3
-rw-r--r--drivers/scsi/scsi_scan.c4
-rw-r--r--drivers/scsi/scsi_sysfs.c90
-rw-r--r--drivers/scsi/scsi_transport_fc.c12
-rw-r--r--drivers/scsi/scsi_transport_sas.c30
-rw-r--r--drivers/scsi/sd.c4
-rw-r--r--drivers/scsi/ses.c22
-rw-r--r--drivers/scsi/st.h2
-rw-r--r--drivers/scsi/storvsc_drv.c327
-rw-r--r--drivers/scsi/sun3_scsi.c141
-rw-r--r--drivers/scsi/t128.c102
-rw-r--r--drivers/scsi/t128.h39
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c2
-rw-r--r--drivers/scsi/vmw_pvscsi.c45
-rw-r--r--drivers/scsi/vmw_pvscsi.h2
149 files changed, 12731 insertions, 8584 deletions
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 2940bd769..25aba1613 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1045,6 +1045,9 @@ static int tw_chrdev_open(struct inode *inode, struct file *file)
static const struct file_operations tw_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = tw_chrdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = tw_chrdev_ioctl,
+#endif
.open = tw_chrdev_open,
.release = NULL,
.llseek = noop_llseek,
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 64eed87d3..e2f31c937 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -194,6 +194,7 @@ config CHR_DEV_SCH
config SCSI_ENCLOSURE
tristate "SCSI Enclosure Support"
depends on SCSI && ENCLOSURE_SERVICES
+ depends on m || SCSI_SAS_ATTRS != m
help
Enclosures are devices sitting on or in SCSI backplanes that
manage devices. If you have a disk cage, the chances are that
@@ -474,6 +475,7 @@ config SCSI_AACRAID
source "drivers/scsi/aic7xxx/Kconfig.aic7xxx"
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
source "drivers/scsi/aic94xx/Kconfig"
+source "drivers/scsi/hisi_sas/Kconfig"
source "drivers/scsi/mvsas/Kconfig"
config SCSI_MVUMI
@@ -1104,6 +1106,7 @@ config SCSI_IPR
tristate "IBM Power Linux RAID adapter support"
depends on PCI && SCSI && ATA
select FW_LOADER
+ select IRQ_POLL
---help---
This driver supports the IBM Power Linux family RAID adapters.
This includes IBM pSeries 5712, 5703, 5709, and 570A, as well
@@ -1618,23 +1621,6 @@ config ATARI_SCSI
ST-DMA, replacing ACSI). It does NOT support other schemes, like
in the Hades (without DMA).
-config ATARI_SCSI_TOSHIBA_DELAY
- bool "Long delays for Toshiba CD-ROMs"
- depends on ATARI_SCSI
- help
- This option increases the delay after a SCSI arbitration to
- accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to
- use a Toshiba CD-ROM drive; otherwise, the option is not needed and
- would impact performance a bit, so say N.
-
-config ATARI_SCSI_RESET_BOOT
- bool "Reset SCSI-devices at boottime"
- depends on ATARI_SCSI
- help
- Reset the devices on your Atari whenever it boots. This makes the
- boot process fractionally longer but may assist recovery from errors
- that leave the devices with SCSI operations partway completed.
-
config MAC_SCSI
tristate "Macintosh NCR5380 SCSI"
depends on MAC && SCSI=y
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index c14bca4a9..862ab4efa 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -157,6 +157,7 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o
obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o
obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas/
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index a777e5c41..d72867257 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -1,17 +1,17 @@
-/*
+/*
* NCR 5380 generic driver routines. These should make it *trivial*
- * to implement 5380 SCSI drivers under Linux with a non-trantor
- * architecture.
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
*
- * Note that these routines also work with NR53c400 family chips.
+ * Note that these routines also work with NR53c400 family chips.
*
* Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 666-5836
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
*
- * For more information, please consult
+ * For more information, please consult
*
* NCR 5380 Family
* SCSI Protocol Controller
@@ -25,84 +25,28 @@
*/
/*
- * Revision 1.10 1998/9/2 Alan Cox
- * (alan@lxorguk.ukuu.org.uk)
- * Fixed up the timer lockups reported so far. Things still suck. Looking
- * forward to 2.3 and per device request queues. Then it'll be possible to
- * SMP thread this beast and improve life no end.
-
- * Revision 1.9 1997/7/27 Ronald van Cuijlenborg
- * (ronald.van.cuijlenborg@tip.nl or nutty@dds.nl)
- * (hopefully) fixed and enhanced USLEEP
- * added support for DTC3181E card (for Mustek scanner)
- *
-
- * Revision 1.8 Ingmar Baumgart
- * (ingmar@gonzo.schwaben.de)
- * added support for NCR53C400a card
- *
-
- * Revision 1.7 1996/3/2 Ray Van Tassle (rayvt@comm.mot.com)
- * added proc_info
- * added support needed for DTC 3180/3280
- * fixed a couple of bugs
- *
-
- * Revision 1.5 1994/01/19 09:14:57 drew
- * Fixed udelay() hack that was being used on DATAOUT phases
- * instead of a proper wait for the final handshake.
- *
- * Revision 1.4 1994/01/19 06:44:25 drew
- * *** empty log message ***
- *
- * Revision 1.3 1994/01/19 05:24:40 drew
- * Added support for TCR LAST_BYTE_SENT bit.
- *
- * Revision 1.2 1994/01/15 06:14:11 drew
- * REAL DMA support, bug fixes.
- *
- * Revision 1.1 1994/01/15 06:00:54 drew
- * Initial revision
- *
+ * With contributions from Ray Van Tassle, Ingmar Baumgart,
+ * Ronald van Cuijlenborg, Alan Cox and others.
*/
/*
- * Further development / testing that should be done :
+ * Further development / testing that should be done :
* 1. Cleanup the NCR5380_transfer_dma function and DMA operation complete
- * code so that everything does the same thing that's done at the
- * end of a pseudo-DMA read operation.
+ * code so that everything does the same thing that's done at the
+ * end of a pseudo-DMA read operation.
*
* 2. Fix REAL_DMA (interrupt driven, polled works fine) -
- * basically, transfer size needs to be reduced by one
- * and the last byte read as is done with PSEUDO_DMA.
- *
- * 4. Test SCSI-II tagged queueing (I have no devices which support
- * tagged queueing)
- *
- * 5. Test linked command handling code after Eric is ready with
- * the high level code.
+ * basically, transfer size needs to be reduced by one
+ * and the last byte read as is done with PSEUDO_DMA.
+ *
+ * 4. Test SCSI-II tagged queueing (I have no devices which support
+ * tagged queueing)
*/
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_transport_spi.h>
-
-#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x,y) {printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
-#define REMOVE(w,x,y,z) {printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
-#else
-#define LIST(x,y)
-#define REMOVE(w,x,y,z)
-#endif
#ifndef notyet
-#undef LINKED
#undef REAL_DMA
#endif
-#ifdef REAL_DMA_POLL
-#undef READ_OVERRUNS
-#define READ_OVERRUNS
-#endif
-
#ifdef BOARD_REQUIRES_NO_DELAY
#define io_recovery_delay(x)
#else
@@ -112,44 +56,28 @@
/*
* Design
*
- * This is a generic 5380 driver. To use it on a different platform,
+ * This is a generic 5380 driver. To use it on a different platform,
* one simply writes appropriate system specific macros (ie, data
- * transfer - some PC's will use the I/O bus, 68K's must use
+ * transfer - some PC's will use the I/O bus, 68K's must use
* memory mapped) and drops this file in their 'C' wrapper.
*
- * (Note from hch: unfortunately it was not enough for the different
- * m68k folks and instead of improving this driver they copied it
- * and hacked it up for their needs. As a consequence they lost
- * most updates to this driver. Maybe someone will fix all these
- * drivers to use a common core one day..)
- *
- * As far as command queueing, two queues are maintained for
+ * As far as command queueing, two queues are maintained for
* each 5380 in the system - commands that haven't been issued yet,
- * and commands that are currently executing. This means that an
- * unlimited number of commands may be queued, letting
- * more commands propagate from the higher driver levels giving higher
- * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
- * allowing multiple commands to propagate all the way to a SCSI-II device
+ * and commands that are currently executing. This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propagate from the higher driver levels giving higher
+ * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propagate all the way to a SCSI-II device
* while a command is already executing.
*
*
- * Issues specific to the NCR5380 :
+ * Issues specific to the NCR5380 :
*
- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
- * piece of hardware that requires you to sit in a loop polling for
- * the REQ signal as long as you are connected. Some devices are
- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
- * while doing long seek operations.
- *
- * The workaround for this is to keep track of devices that have
- * disconnected. If the device hasn't disconnected, for commands that
- * should disconnect, we do something like
- *
- * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- *
- * Some tweaking of N and M needs to be done. An algorithm based
- * on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected. Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * while doing long seek operations. [...] These
* broken devices are the exception rather than the rule and I'd rather
* spend my time optimizing for the normal case.
*
@@ -159,23 +87,23 @@
* which is started from a workqueue for each NCR5380 host in the
* system. It attempts to establish I_T_L or I_T_L_Q nexuses by
* removing the commands from the issue queue and calling
- * NCR5380_select() if a nexus is not established.
+ * NCR5380_select() if a nexus is not established.
*
* Once a nexus is established, the NCR5380_information_transfer()
* phase goes through the various phases as instructed by the target.
* if the target goes into MSG IN and sends a DISCONNECT message,
* the command structure is placed into the per instance disconnected
- * queue, and NCR5380_main tries to find more work. If the target is
+ * queue, and NCR5380_main tries to find more work. If the target is
* idle for too long, the system will try to sleep.
*
* If a command has disconnected, eventually an interrupt will trigger,
* calling NCR5380_intr() which will in turn call NCR5380_reselect
* to reestablish a nexus. This will run main if necessary.
*
- * On command termination, the done function will be called as
+ * On command termination, the done function will be called as
* appropriate.
*
- * SCSI pointers are maintained in the SCp field of SCSI command
+ * SCSI pointers are maintained in the SCp field of SCSI command
* structures, being initialized after the command is connected
* in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
* Note that in violation of the standard, an implicit SAVE POINTERS operation
@@ -185,73 +113,48 @@
/*
* Using this file :
* This file a skeleton Linux SCSI driver for the NCR 5380 series
- * of chips. To use it, you write an architecture specific functions
+ * of chips. To use it, you write an architecture specific functions
* and macros and include this file in your driver.
*
- * These macros control options :
- * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be
- * defined.
- *
+ * These macros control options :
+ * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be
+ * defined.
+ *
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
+ * for commands that return with a CHECK CONDITION status.
*
* DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
- * transceivers.
+ * transceivers.
*
* DONT_USE_INTR - if defined, never use interrupts, even if we probe or
- * override-configure an IRQ.
- *
- * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
- * bytes at a time. Since interrupts are disabled by default during
- * these transfers, we might need this to give reasonable interrupt
- * service time if the transfer size gets too large.
- *
- * LINKED - if defined, linked commands are supported.
+ * override-configure an IRQ.
*
* PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
*
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
*
* REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't
- * rely on phase mismatch and EOP interrupts to determine end
- * of phase.
- *
- * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You
- * only really want to use this if you're having a problem with
- * dropped characters during high speed communications, and even
- * then, you're going to be better off twiddling with transfersize
- * in the high level code.
- *
- * Defaults for these will be provided although the user may want to adjust
- * these to allocate CPU resources to the SCSI driver or "real" code.
- *
- * USLEEP_SLEEP - amount of time, in jiffies, to sleep
- *
- * USLEEP_POLL - amount of time, in jiffies, to poll
+ * rely on phase mismatch and EOP interrupts to determine end
+ * of phase.
*
* These macros MUST be defined :
- * NCR5380_local_declare() - declare any local variables needed for your
- * transfer routines.
*
- * NCR5380_setup(instance) - initialize any local variables needed from a given
- * instance of the host adapter for NCR5380_{read,write,pread,pwrite}
- *
* NCR5380_read(register) - read from the specified register
*
- * NCR5380_write(register, value) - write to the specific register
+ * NCR5380_write(register, value) - write to the specific register
*
- * NCR5380_implementation_fields - additional fields needed for this
- * specific implementation of the NCR5380
+ * NCR5380_implementation_fields - additional fields needed for this
+ * specific implementation of the NCR5380
*
* Either real DMA *or* pseudo DMA may be implemented
- * REAL functions :
+ * REAL functions :
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
- * Note that the DMA setup functions should return the number of bytes
- * that they were able to program the controller for.
+ * Note that the DMA setup functions should return the number of bytes
+ * that they were able to program the controller for.
*
- * Also note that generic i386/PC versions of these macros are
- * available as NCR5380_i386_dma_write_setup,
- * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ * Also note that generic i386/PC versions of these macros are
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
*
* NCR5380_dma_write_setup(instance, src, count) - initialize
* NCR5380_dma_read_setup(instance, dst, count) - initialize
@@ -262,25 +165,25 @@
* NCR5380_pread(instance, dst, count);
*
* The generic driver is initialized by calling NCR5380_init(instance),
- * after setting the appropriate host specific fields and ID. If the
+ * after setting the appropriate host specific fields and ID. If the
* driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
* possible) function may be used.
*/
-static int do_abort(struct Scsi_Host *host);
-static void do_reset(struct Scsi_Host *host);
+static int do_abort(struct Scsi_Host *);
+static void do_reset(struct Scsi_Host *);
-/*
- * initialize_SCp - init the scsi pointer field
- * @cmd: command block to set up
+/**
+ * initialize_SCp - init the scsi pointer field
+ * @cmd: command block to set up
*
- * Set up the internal fields in the SCSI command.
+ * Set up the internal fields in the SCSI command.
*/
static inline void initialize_SCp(struct scsi_cmnd *cmd)
{
- /*
- * Initialize the Scsi Pointer field so that all of the commands in the
+ /*
+ * Initialize the Scsi Pointer field so that all of the commands in the
* various queues are valid.
*/
@@ -295,120 +198,123 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
cmd->SCp.ptr = NULL;
cmd->SCp.this_residual = 0;
}
+
+ cmd->SCp.Status = 0;
+ cmd->SCp.Message = 0;
}
/**
- * NCR5380_poll_politely - wait for NCR5380 status bits
- * @instance: controller to poll
- * @reg: 5380 register to poll
- * @bit: Bitmask to check
- * @val: Value required to exit
- *
- * Polls the NCR5380 in a reasonably efficient manner waiting for
- * an event to occur, after a short quick poll we begin giving the
- * CPU back in non IRQ contexts
- *
- * Returns the value of the register or a negative error code.
+ * NCR5380_poll_politely2 - wait for two chip register values
+ * @instance: controller to poll
+ * @reg1: 5380 register to poll
+ * @bit1: Bitmask to check
+ * @val1: Expected value
+ * @reg2: Second 5380 register to poll
+ * @bit2: Second bitmask to check
+ * @val2: Second expected value
+ * @wait: Time-out in jiffies
+ *
+ * Polls the chip in a reasonably efficient manner waiting for an
+ * event to occur. After a short quick poll we begin to yield the CPU
+ * (if possible). In irq contexts the time-out is arbitrarily limited.
+ * Callers may hold locks as long as they are held in irq mode.
+ *
+ * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT.
*/
-
-static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, int val, int t)
+
+static int NCR5380_poll_politely2(struct Scsi_Host *instance,
+ int reg1, int bit1, int val1,
+ int reg2, int bit2, int val2, int wait)
{
- NCR5380_local_declare();
- int n = 500; /* At about 8uS a cycle for the cpu access */
- unsigned long end = jiffies + t;
- int r;
-
- NCR5380_setup(instance);
-
- while( n-- > 0)
- {
- r = NCR5380_read(reg);
- if((r & bit) == val)
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long deadline = jiffies + wait;
+ unsigned long n;
+
+ /* Busy-wait for up to 10 ms */
+ n = min(10000U, jiffies_to_usecs(wait));
+ n *= hostdata->accesses_per_ms;
+ n /= 2000;
+ do {
+ if ((NCR5380_read(reg1) & bit1) == val1)
+ return 0;
+ if ((NCR5380_read(reg2) & bit2) == val2)
return 0;
cpu_relax();
- }
-
- /* t time yet ? */
- while(time_before(jiffies, end))
- {
- r = NCR5380_read(reg);
- if((r & bit) == val)
+ } while (n--);
+
+ if (irqs_disabled() || in_interrupt())
+ return -ETIMEDOUT;
+
+ /* Repeatedly sleep for 1 ms until deadline */
+ while (time_is_after_jiffies(deadline)) {
+ schedule_timeout_uninterruptible(1);
+ if ((NCR5380_read(reg1) & bit1) == val1)
+ return 0;
+ if ((NCR5380_read(reg2) & bit2) == val2)
return 0;
- if(!in_interrupt())
- cond_resched();
- else
- cpu_relax();
}
+
return -ETIMEDOUT;
}
-static struct {
- unsigned char value;
- const char *name;
-} phases[] __maybe_unused = {
- {PHASE_DATAOUT, "DATAOUT"},
- {PHASE_DATAIN, "DATAIN"},
- {PHASE_CMDOUT, "CMDOUT"},
- {PHASE_STATIN, "STATIN"},
- {PHASE_MSGOUT, "MSGOUT"},
- {PHASE_MSGIN, "MSGIN"},
- {PHASE_UNKNOWN, "UNKNOWN"}
-};
+static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
+ int reg, int bit, int val, int wait)
+{
+ return NCR5380_poll_politely2(instance, reg, bit, val,
+ reg, bit, val, wait);
+}
#if NDEBUG
static struct {
unsigned char mask;
const char *name;
-} signals[] = {
- {SR_DBP, "PARITY"},
- {SR_RST, "RST"},
- {SR_BSY, "BSY"},
- {SR_REQ, "REQ"},
- {SR_MSG, "MSG"},
- {SR_CD, "CD"},
- {SR_IO, "IO"},
- {SR_SEL, "SEL"},
+} signals[] = {
+ {SR_DBP, "PARITY"},
+ {SR_RST, "RST"},
+ {SR_BSY, "BSY"},
+ {SR_REQ, "REQ"},
+ {SR_MSG, "MSG"},
+ {SR_CD, "CD"},
+ {SR_IO, "IO"},
+ {SR_SEL, "SEL"},
{0, NULL}
-},
+},
basrs[] = {
- {BASR_ATN, "ATN"},
- {BASR_ACK, "ACK"},
+ {BASR_ATN, "ATN"},
+ {BASR_ACK, "ACK"},
{0, NULL}
-},
-icrs[] = {
- {ICR_ASSERT_RST, "ASSERT RST"},
- {ICR_ASSERT_ACK, "ASSERT ACK"},
- {ICR_ASSERT_BSY, "ASSERT BSY"},
- {ICR_ASSERT_SEL, "ASSERT SEL"},
- {ICR_ASSERT_ATN, "ASSERT ATN"},
- {ICR_ASSERT_DATA, "ASSERT DATA"},
+},
+icrs[] = {
+ {ICR_ASSERT_RST, "ASSERT RST"},
+ {ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"},
+ {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"},
+ {ICR_ASSERT_DATA, "ASSERT DATA"},
{0, NULL}
-},
-mrs[] = {
- {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
- {MR_TARGET, "MODE TARGET"},
- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
- {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
- {MR_MONITOR_BSY, "MODE MONITOR BSY"},
- {MR_DMA_MODE, "MODE DMA"},
- {MR_ARBITRATE, "MODE ARBITRATION"},
+},
+mrs[] = {
+ {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
+ {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
+ {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
+ {MR_ENABLE_EOP_INTR, "MODE EOP INTR"},
+ {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+ {MR_DMA_MODE, "MODE DMA"},
+ {MR_ARBITRATE, "MODE ARBITRATION"},
{0, NULL}
};
/**
- * NCR5380_print - print scsi bus signals
- * @instance: adapter state to dump
- *
- * Print the SCSI bus signals for debugging purposes
+ * NCR5380_print - print scsi bus signals
+ * @instance: adapter state to dump
*
- * Locks: caller holds hostdata lock (not essential)
+ * Print the SCSI bus signals for debugging purposes
*/
static void NCR5380_print(struct Scsi_Host *instance)
{
- NCR5380_local_declare();
unsigned char status, data, basr, mr, icr, i;
- NCR5380_setup(instance);
data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
@@ -435,117 +341,56 @@ static void NCR5380_print(struct Scsi_Host *instance)
printk("\n");
}
+static struct {
+ unsigned char value;
+ const char *name;
+} phases[] = {
+ {PHASE_DATAOUT, "DATAOUT"},
+ {PHASE_DATAIN, "DATAIN"},
+ {PHASE_CMDOUT, "CMDOUT"},
+ {PHASE_STATIN, "STATIN"},
+ {PHASE_MSGOUT, "MSGOUT"},
+ {PHASE_MSGIN, "MSGIN"},
+ {PHASE_UNKNOWN, "UNKNOWN"}
+};
-/*
- * NCR5380_print_phase - show SCSI phase
- * @instance: adapter to dump
- *
- * Print the current SCSI phase for debugging purposes
+/**
+ * NCR5380_print_phase - show SCSI phase
+ * @instance: adapter to dump
*
- * Locks: none
+ * Print the current SCSI phase for debugging purposes
*/
static void NCR5380_print_phase(struct Scsi_Host *instance)
{
- NCR5380_local_declare();
unsigned char status;
int i;
- NCR5380_setup(instance);
status = NCR5380_read(STATUS_REG);
if (!(status & SR_REQ))
- printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no);
+ shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n");
else {
- for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
- printk("scsi%d : phase %s\n", instance->host_no, phases[i].name);
+ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+ (phases[i].value != (status & PHASE_MASK)); ++i)
+ ;
+ shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name);
}
}
#endif
-/*
- * These need tweaking, and would probably work best as per-device
- * flags initialized differently for disk, tape, cd, etc devices.
- * People with broken devices are free to experiment as to what gives
- * the best results for them.
- *
- * USLEEP_SLEEP should be a minimum seek time.
- *
- * USLEEP_POLL should be a maximum rotational latency.
- */
-#ifndef USLEEP_SLEEP
-/* 20 ms (reasonable hard disk speed) */
-#define USLEEP_SLEEP msecs_to_jiffies(20)
-#endif
-/* 300 RPM (floppy speed) */
-#ifndef USLEEP_POLL
-#define USLEEP_POLL msecs_to_jiffies(200)
-#endif
-#ifndef USLEEP_WAITLONG
-/* RvC: (reasonable time to wait on select error) */
-#define USLEEP_WAITLONG USLEEP_SLEEP
-#endif
-/*
- * Function : int should_disconnect (unsigned char cmd)
- *
- * Purpose : decide whether a command would normally disconnect or
- * not, since if it won't disconnect we should go to sleep.
- *
- * Input : cmd - opcode of SCSI command
- *
- * Returns : DISCONNECT_LONG if we should disconnect for a really long
- * time (ie always, sleep, look for REQ active, sleep),
- * DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal
- * time-to-data delay, DISCONNECT_NONE if this command would return
- * immediately.
- *
- * Future sleep algorithms based on time to data can exploit
- * something like this so they can differentiate between "normal"
- * (ie, read, write, seek) and unusual commands (ie, * format).
- *
- * Note : We don't deal with commands that handle an immediate disconnect,
- *
- */
-
-static int should_disconnect(unsigned char cmd)
-{
- switch (cmd) {
- case READ_6:
- case WRITE_6:
- case SEEK_6:
- case READ_10:
- case WRITE_10:
- case SEEK_10:
- return DISCONNECT_TIME_TO_DATA;
- case FORMAT_UNIT:
- case SEARCH_HIGH:
- case SEARCH_LOW:
- case SEARCH_EQUAL:
- return DISCONNECT_LONG;
- default:
- return DISCONNECT_NONE;
- }
-}
-
-static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout)
-{
- hostdata->time_expires = jiffies + timeout;
- schedule_delayed_work(&hostdata->coroutine, timeout);
-}
-
-
-static int probe_irq __initdata = 0;
+static int probe_irq __initdata;
/**
- * probe_intr - helper for IRQ autoprobe
- * @irq: interrupt number
- * @dev_id: unused
- * @regs: unused
+ * probe_intr - helper for IRQ autoprobe
+ * @irq: interrupt number
+ * @dev_id: unused
+ * @regs: unused
*
- * Set a flag to indicate the IRQ in question was received. This is
- * used by the IRQ probe code.
+ * Set a flag to indicate the IRQ in question was received. This is
+ * used by the IRQ probe code.
*/
-
+
static irqreturn_t __init probe_intr(int irq, void *dev_id)
{
probe_irq = irq;
@@ -553,24 +398,20 @@ static irqreturn_t __init probe_intr(int irq, void *dev_id)
}
/**
- * NCR5380_probe_irq - find the IRQ of an NCR5380
- * @instance: NCR5380 controller
- * @possible: bitmask of ISA IRQ lines
+ * NCR5380_probe_irq - find the IRQ of an NCR5380
+ * @instance: NCR5380 controller
+ * @possible: bitmask of ISA IRQ lines
*
- * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
- * and then looking to see what interrupt actually turned up.
- *
- * Locks: none, irqs must be enabled on entry
+ * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
+ * and then looking to see what interrupt actually turned up.
*/
static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
int possible)
{
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned long timeout;
int trying_irqs, i, mask;
- NCR5380_setup(instance);
for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1)
if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
@@ -581,7 +422,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
/*
* A interrupt is triggered whenever BSY = false, SEL = true
- * and a bit set in the SELECT_ENABLE_REG is asserted on the
+ * and a bit set in the SELECT_ENABLE_REG is asserted on the
* SCSI bus.
*
* Note that the bus is only driven when the phase control signals
@@ -596,7 +437,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
while (probe_irq == NO_IRQ && time_before(jiffies, timeout))
schedule_timeout_uninterruptible(1);
-
+
NCR5380_write(SELECT_ENABLE_REG, 0);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -608,12 +449,10 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
}
/**
- * NCR58380_info - report driver and host information
- * @instance: relevant scsi host instance
- *
- * For use as the host template info() handler.
+ * NCR58380_info - report driver and host information
+ * @instance: relevant scsi host instance
*
- * Locks: none
+ * For use as the host template info() handler.
*/
static const char *NCR5380_info(struct Scsi_Host *instance)
@@ -633,20 +472,14 @@ static void prepare_info(struct Scsi_Host *instance)
"can_queue %d, cmd_per_lun %d, "
"sg_tablesize %d, this_id %d, "
"flags { %s%s%s}, "
-#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
- "USLEEP_POLL %lu, USLEEP_WAITLONG %lu, "
-#endif
"options { %s} ",
instance->hostt->name, instance->io_port, instance->n_io_port,
instance->base, instance->irq,
instance->can_queue, instance->cmd_per_lun,
instance->sg_tablesize, instance->this_id,
- hostdata->flags & FLAG_NCR53C400 ? "NCR53C400 " : "",
- hostdata->flags & FLAG_DTC3181E ? "DTC3181E " : "",
+ hostdata->flags & FLAG_NO_DMA_FIXUP ? "NO_DMA_FIXUP " : "",
hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
-#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
- USLEEP_POLL, USLEEP_WAITLONG,
-#endif
+ hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "",
#ifdef AUTOPROBE_IRQ
"AUTOPROBE_IRQ "
#endif
@@ -665,46 +498,10 @@ static void prepare_info(struct Scsi_Host *instance)
#ifdef PSEUDO_DMA
"PSEUDO_DMA "
#endif
-#ifdef UNSAFE
- "UNSAFE "
-#endif
-#ifdef NCR53C400
- "NCR53C400 "
-#endif
"");
}
-/**
- * NCR5380_print_status - dump controller info
- * @instance: controller to dump
- *
- * Print commands in the various queues, called from NCR5380_abort
- * and NCR5380_debug to aid debugging.
- *
- * Locks: called functions disable irqs
- */
-
-static void NCR5380_print_status(struct Scsi_Host *instance)
-{
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_dprint_phase(NDEBUG_ANY, instance);
-}
-
#ifdef PSEUDO_DMA
-/******************************************/
-/*
- * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
- *
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
- *
- * Return the number of bytes read from or written
- */
-
static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
char *buffer, int length)
{
@@ -714,104 +511,41 @@ static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
hostdata->spin_max_w = 0;
return 0;
}
-#endif
-
-static
-void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m);
-static
-void lprint_command(unsigned char *cmd, struct seq_file *m);
-static
-void lprint_opcode(int opcode, struct seq_file *m);
static int __maybe_unused NCR5380_show_info(struct seq_file *m,
- struct Scsi_Host *instance)
+ struct Scsi_Host *instance)
{
- struct NCR5380_hostdata *hostdata;
- struct scsi_cmnd *ptr;
-
- hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
-#ifdef PSEUDO_DMA
seq_printf(m, "Highwater I/O busy spin counts: write %d, read %d\n",
hostdata->spin_max_w, hostdata->spin_max_r);
-#endif
- spin_lock_irq(instance->host_lock);
- if (!hostdata->connected)
- seq_printf(m, "scsi%d: no currently connected command\n", instance->host_no);
- else
- lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
- seq_printf(m, "scsi%d: issue_queue\n", instance->host_no);
- for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
- lprint_Scsi_Cmnd(ptr, m);
-
- seq_printf(m, "scsi%d: disconnected_queue\n", instance->host_no);
- for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
- lprint_Scsi_Cmnd(ptr, m);
- spin_unlock_irq(instance->host_lock);
return 0;
}
-
-static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
-{
- seq_printf(m, "scsi%d : destination target %d, lun %llu\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);
- seq_puts(m, " command = ");
- lprint_command(cmd->cmnd, m);
-}
-
-static void lprint_command(unsigned char *command, struct seq_file *m)
-{
- int i, s;
- lprint_opcode(command[0], m);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- seq_printf(m, "%02x ", command[i]);
- seq_putc(m, '\n');
-}
-
-static void lprint_opcode(int opcode, struct seq_file *m)
-{
- seq_printf(m, "%2d (0x%02x)", opcode, opcode);
-}
-
+#endif
/**
- * NCR5380_init - initialise an NCR5380
- * @instance: adapter to configure
- * @flags: control flags
+ * NCR5380_init - initialise an NCR5380
+ * @instance: adapter to configure
+ * @flags: control flags
*
- * Initializes *instance and corresponding 5380 chip,
- * with flags OR'd into the initial flags value.
+ * Initializes *instance and corresponding 5380 chip,
+ * with flags OR'd into the initial flags value.
*
- * Notes : I assume that the host, hostno, and id bits have been
- * set correctly. I don't care about the irq and other fields.
+ * Notes : I assume that the host, hostno, and id bits have been
+ * set correctly. I don't care about the irq and other fields.
*
- * Returns 0 for success
- *
- * Locks: interrupts must be enabled when we are called
+ * Returns 0 for success
*/
static int NCR5380_init(struct Scsi_Host *instance, int flags)
{
- NCR5380_local_declare();
- int i, pass;
- unsigned long timeout;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-
- if(in_interrupt())
- printk(KERN_ERR "NCR5380_init called with interrupts off!\n");
- /*
- * On NCR53C400 boards, NCR5380 registers are mapped 8 past
- * the base address.
- */
-
-#ifdef NCR53C400
- if (flags & FLAG_NCR53C400)
- instance->NCR5380_instance_name += NCR53C400_address_adjust;
-#endif
-
- NCR5380_setup(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int i;
+ unsigned long deadline;
- hostdata->aborted = 0;
+ hostdata->host = instance;
hostdata->id_mask = 1 << instance->this_id;
+ hostdata->id_higher_mask = 0;
for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
if (i > hostdata->id_mask)
hostdata->id_higher_mask |= i;
@@ -820,21 +554,21 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
#ifdef REAL_DMA
hostdata->dmalen = 0;
#endif
- hostdata->targets_present = 0;
+ spin_lock_init(&hostdata->lock);
hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
-
- INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main);
-
- /* The CHECK code seems to break the 53C400. Will check it later maybe */
- if (flags & FLAG_NCR53C400)
- hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags;
- else
- hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags;
+ hostdata->sensing = NULL;
+ INIT_LIST_HEAD(&hostdata->autosense);
+ INIT_LIST_HEAD(&hostdata->unissued);
+ INIT_LIST_HEAD(&hostdata->disconnected);
- hostdata->host = instance;
- hostdata->time_expires = 0;
+ hostdata->flags = flags;
+
+ INIT_WORK(&hostdata->main_task, NCR5380_main);
+ hostdata->work_q = alloc_workqueue("ncr5380_%d",
+ WQ_UNBOUND | WQ_MEM_RECLAIM,
+ 1, instance->host_no);
+ if (!hostdata->work_q)
+ return -ENOMEM;
prepare_info(instance);
@@ -843,43 +577,69 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
-#ifdef NCR53C400
- if (hostdata->flags & FLAG_NCR53C400) {
- NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
- }
-#endif
+ /* Calibrate register polling loop */
+ i = 0;
+ deadline = jiffies + 1;
+ do {
+ cpu_relax();
+ } while (time_is_after_jiffies(deadline));
+ deadline += msecs_to_jiffies(256);
+ do {
+ NCR5380_read(STATUS_REG);
+ ++i;
+ cpu_relax();
+ } while (time_is_after_jiffies(deadline));
+ hostdata->accesses_per_ms = i / 256;
- /*
- * Detect and correct bus wedge problems.
- *
- * If the system crashed, it may have crashed in a state
- * where a SCSI command was still executing, and the
- * SCSI bus is not in a BUS FREE STATE.
- *
- * If this is the case, we'll try to abort the currently
- * established nexus which we know nothing about, and that
- * failing, do a hard reset of the SCSI bus
- */
+ return 0;
+}
+
+/**
+ * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
+ * @instance: adapter to check
+ *
+ * If the system crashed, it may have crashed with a connected target and
+ * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
+ * currently established nexus, which we know nothing about. Failing that
+ * do a bus reset.
+ *
+ * Note that a bus reset will cause the chip to assert IRQ.
+ *
+ * Returns 0 if successful, otherwise -ENXIO.
+ */
+
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int pass;
for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
switch (pass) {
case 1:
case 3:
case 5:
- printk(KERN_INFO "scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no);
- timeout = jiffies + 5 * HZ;
- NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, 0, 5*HZ);
+ shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
+ NCR5380_poll_politely(instance,
+ STATUS_REG, SR_BSY, 0, 5 * HZ);
break;
case 2:
- printk(KERN_WARNING "scsi%d: bus busy, attempting abort\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
do_abort(instance);
break;
case 4:
- printk(KERN_WARNING "scsi%d: bus busy, attempting reset\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
do_reset(instance);
+ /* Wait after a reset; the SCSI standard calls for
+ * 250ms, we wait 500ms to be on the safe side.
+ * But some Toshiba CD-ROMs need ten times that.
+ */
+ if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+ msleep(2500);
+ else
+ msleep(500);
break;
case 6:
- printk(KERN_ERR "scsi%d: bus locked solid or invalid override\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "bus locked solid\n");
return -ENXIO;
}
}
@@ -887,450 +647,513 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
}
/**
- * NCR5380_exit - remove an NCR5380
- * @instance: adapter to remove
+ * NCR5380_exit - remove an NCR5380
+ * @instance: adapter to remove
+ *
+ * Assumes that no more work can be queued (e.g. by NCR5380_intr).
*/
static void NCR5380_exit(struct Scsi_Host *instance)
{
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
- cancel_delayed_work_sync(&hostdata->coroutine);
+ cancel_work_sync(&hostdata->main_task);
+ destroy_workqueue(hostdata->work_q);
}
/**
- * NCR5380_queue_command - queue a command
- * @cmd: SCSI command
- * @done: completion handler
- *
- * cmd is added to the per instance issue_queue, with minor
- * twiddling done to the host specific fields of cmd. If the
- * main coroutine is not running, it is restarted.
+ * complete_cmd - finish processing a command and return it to the SCSI ML
+ * @instance: the host instance
+ * @cmd: command to complete
+ */
+
+static void complete_cmd(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd);
+
+ if (hostdata->sensing == cmd) {
+ /* Autosense processing ends here */
+ if ((cmd->result & 0xff) != SAM_STAT_GOOD) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ set_host_byte(cmd, DID_ERROR);
+ } else
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->sensing = NULL;
+ }
+
+ hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
+
+ cmd->scsi_done(cmd);
+}
+
+/**
+ * NCR5380_queue_command - queue a command
+ * @instance: the relevant SCSI adapter
+ * @cmd: SCSI command
*
- * Locks: host lock taken by caller
+ * cmd is added to the per-instance issue queue, with minor
+ * twiddling done to the host specific fields of cmd. If the
+ * main coroutine is not running, it is restarted.
*/
-static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *))
+static int NCR5380_queue_command(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
{
- struct Scsi_Host *instance = cmd->device->host;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- struct scsi_cmnd *tmp;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+ unsigned long flags;
#if (NDEBUG & NDEBUG_NO_WRITE)
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
- printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no);
+ shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n");
cmd->result = (DID_ERROR << 16);
- done(cmd);
+ cmd->scsi_done(cmd);
return 0;
}
-#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
-
- /*
- * We use the host_scribble field as a pointer to the next command
- * in a queue
- */
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
- cmd->host_scribble = NULL;
- cmd->scsi_done = done;
cmd->result = 0;
- /*
- * Insert the cmd into the issue queue. Note that REQUEST SENSE
+ spin_lock_irqsave(&hostdata->lock, flags);
+
+ /*
+ * Insert the cmd into the issue queue. Note that REQUEST SENSE
* commands are added to the head of the queue since any command will
- * clear the contingent allegiance condition that exists and the
+ * clear the contingent allegiance condition that exists and the
* sense data is only guaranteed to be valid while the condition exists.
*/
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- LIST(cmd, hostdata->issue_queue);
- cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (struct scsi_cmnd *) tmp->host_scribble);
- LIST(cmd, tmp);
- tmp->host_scribble = (unsigned char *) cmd;
- }
- dprintk(NDEBUG_QUEUES, "scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ list_add(&ncmd->list, &hostdata->unissued);
+ else
+ list_add_tail(&ncmd->list, &hostdata->unissued);
+
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+
+ dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n",
+ cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
- /* Run the coroutine if it isn't already running. */
/* Kick off command processing */
- schedule_delayed_work(&hostdata->coroutine, 0);
+ queue_work(hostdata->work_q, &hostdata->main_task);
return 0;
}
-static DEF_SCSI_QCMD(NCR5380_queue_command)
+/**
+ * dequeue_next_cmd - dequeue a command for processing
+ * @instance: the scsi host instance
+ *
+ * Priority is given to commands on the autosense queue. These commands
+ * need autosense because of a CHECK CONDITION result.
+ *
+ * Returns a command pointer if a command is found for a target that is
+ * not already busy. Otherwise returns NULL.
+ */
+
+static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd;
+ struct scsi_cmnd *cmd;
+
+ if (list_empty(&hostdata->autosense)) {
+ list_for_each_entry(ncmd, &hostdata->unissued, list) {
+ cmd = NCR5380_to_scmd(ncmd);
+ dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
+ cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun);
+
+ if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) {
+ list_del(&ncmd->list);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "dequeue: removed %p from issue queue\n", cmd);
+ return cmd;
+ }
+ }
+ } else {
+ /* Autosense processing begins here */
+ ncmd = list_first_entry(&hostdata->autosense,
+ struct NCR5380_cmd, list);
+ list_del(&ncmd->list);
+ cmd = NCR5380_to_scmd(ncmd);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "dequeue: removed %p from autosense queue\n", cmd);
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+ hostdata->sensing = cmd;
+ return cmd;
+ }
+ return NULL;
+}
+
+static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
+ if (hostdata->sensing) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ list_add(&ncmd->list, &hostdata->autosense);
+ hostdata->sensing = NULL;
+ } else
+ list_add(&ncmd->list, &hostdata->unissued);
+}
/**
- * NCR5380_main - NCR state machines
- *
- * NCR5380_main is a coroutine that runs as long as more work can
- * be done on the NCR5380 host adapters in a system. Both
- * NCR5380_queue_command() and NCR5380_intr() will try to start it
- * in case it is not running.
- *
- * Locks: called as its own thread with no locks held. Takes the
- * host lock and called routines may take the isa dma lock.
+ * NCR5380_main - NCR state machines
+ *
+ * NCR5380_main is a coroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system. Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * in case it is not running.
*/
static void NCR5380_main(struct work_struct *work)
{
struct NCR5380_hostdata *hostdata =
- container_of(work, struct NCR5380_hostdata, coroutine.work);
+ container_of(work, struct NCR5380_hostdata, main_task);
struct Scsi_Host *instance = hostdata->host;
- struct scsi_cmnd *tmp, *prev;
+ struct scsi_cmnd *cmd;
int done;
-
- spin_lock_irq(instance->host_lock);
+
do {
- /* Lock held here */
done = 1;
- if (!hostdata->connected && !hostdata->selecting) {
- dprintk(NDEBUG_MAIN, "scsi%d : not connected\n", instance->host_no);
- /*
- * Search through the issue_queue for a command destined
- * for a target that's not busy.
- */
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
- {
- if (prev != tmp)
- dprintk(NDEBUG_LISTS, "MAIN tmp=%p target=%d busy=%d lun=%llu\n", tmp, tmp->device->id, hostdata->busy[tmp->device->id], tmp->device->lun);
- /* When we find one, remove it from the issue queue. */
- if (!(hostdata->busy[tmp->device->id] &
- (1 << (u8)(tmp->device->lun & 0xff)))) {
- if (prev) {
- REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
- prev->host_scribble = tmp->host_scribble;
- } else {
- REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble);
- hostdata->issue_queue = (struct scsi_cmnd *) tmp->host_scribble;
- }
- tmp->host_scribble = NULL;
- /*
- * Attempt to establish an I_T_L nexus here.
- * On success, instance->hostdata->connected is set.
- * On failure, we must add the command back to the
- * issue queue so we can keep trying.
- */
- dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, "scsi%d : main() : command for target %d lun %llu removed from issue_queue\n", instance->host_no, tmp->device->id, tmp->device->lun);
-
- /*
- * A successful selection is defined as one that
- * leaves us with the command connected and
- * in hostdata->connected, OR has terminated the
- * command.
- *
- * With successful commands, we fall through
- * and see if we can do an information transfer,
- * with failures we will restart.
- */
- hostdata->selecting = NULL;
- /* RvC: have to preset this to indicate a new command is being performed */
+ spin_lock_irq(&hostdata->lock);
+ while (!hostdata->connected &&
+ (cmd = dequeue_next_cmd(instance))) {
- /*
- * REQUEST SENSE commands are issued without tagged
- * queueing, even on SCSI-II devices because the
- * contingent allegiance condition exists for the
- * entire unit.
- */
+ dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
- if (!NCR5380_select(instance, tmp)) {
- break;
- } else {
- LIST(tmp, hostdata->issue_queue);
- tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = tmp;
- done = 0;
- dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, "scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no);
- }
- /* lock held here still */
- } /* if target/lun is not busy */
- } /* for */
- /* exited locked */
- } /* if (!hostdata->connected) */
- if (hostdata->selecting) {
- tmp = (struct scsi_cmnd *) hostdata->selecting;
- /* Selection will drop and retake the lock */
- if (!NCR5380_select(instance, tmp)) {
- /* Ok ?? */
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+
+ cmd = NCR5380_select(instance, cmd);
+ if (!cmd) {
+ dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
} else {
- /* RvC: device failed, so we wait a long time
- this is needed for Mustek scanners, that
- do not respond to commands immediately
- after a scan */
- printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->device->id);
- LIST(tmp, hostdata->issue_queue);
- tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = tmp;
- NCR5380_set_timer(hostdata, USLEEP_WAITLONG);
+ dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
+ "main: select failed, returning %p to queue\n", cmd);
+ requeue_cmd(instance, cmd);
}
- } /* if hostdata->selecting */
+ }
if (hostdata->connected
#ifdef REAL_DMA
&& !hostdata->dmalen
#endif
- && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))
) {
- dprintk(NDEBUG_MAIN, "scsi%d : main() : performing information transfer\n", instance->host_no);
+ dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n");
NCR5380_information_transfer(instance);
- dprintk(NDEBUG_MAIN, "scsi%d : main() : done set false\n", instance->host_no);
done = 0;
- } else
- break;
+ }
+ spin_unlock_irq(&hostdata->lock);
+ if (!done)
+ cond_resched();
} while (!done);
-
- spin_unlock_irq(instance->host_lock);
}
#ifndef DONT_USE_INTR
/**
- * NCR5380_intr - generic NCR5380 irq handler
- * @irq: interrupt number
- * @dev_id: device info
- *
- * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
- * from the disconnected queue, and restarting NCR5380_main()
- * as required.
- *
- * Locks: takes the needed instance locks
+ * NCR5380_intr - generic NCR5380 irq handler
+ * @irq: interrupt number
+ * @dev_id: device info
+ *
+ * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ * from the disconnected queue, and restarting NCR5380_main()
+ * as required.
+ *
+ * The chip can assert IRQ in any of six different conditions. The IRQ flag
+ * is then cleared by reading the Reset Parity/Interrupt Register (RPIR).
+ * Three of these six conditions are latched in the Bus and Status Register:
+ * - End of DMA (cleared by ending DMA Mode)
+ * - Parity error (cleared by reading RPIR)
+ * - Loss of BSY (cleared by reading RPIR)
+ * Two conditions have flag bits that are not latched:
+ * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode)
+ * - Bus reset (non-maskable)
+ * The remaining condition has no flag bit at all:
+ * - Selection/reselection
+ *
+ * Hence, establishing the cause(s) of any interrupt is partly guesswork.
+ * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor
+ * claimed that "the design of the [DP8490] interrupt logic ensures
+ * interrupts will not be lost (they can be on the DP5380)."
+ * The L5380/53C80 datasheet from LOGIC Devices has more details.
+ *
+ * Checking for bus reset by reading RST is futile because of interrupt
+ * latency, but a bus reset will reset chip logic. Checking for parity error
+ * is unnecessary because that interrupt is never enabled. A Loss of BSY
+ * condition will clear DMA Mode. We can tell when this occurs because the
+ * the Busy Monitor interrupt is enabled together with DMA Mode.
*/
-static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
+static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
- NCR5380_local_declare();
struct Scsi_Host *instance = dev_id;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- int done;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int handled = 0;
unsigned char basr;
unsigned long flags;
- dprintk(NDEBUG_INTR, "scsi : NCR5380 irq %d triggered\n",
- instance->irq);
+ spin_lock_irqsave(&hostdata->lock, flags);
+
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ if (basr & BASR_IRQ) {
+ unsigned char mr = NCR5380_read(MODE_REG);
+ unsigned char sr = NCR5380_read(STATUS_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
+ irq, basr, sr, mr);
- do {
- done = 1;
- spin_lock_irqsave(instance->host_lock, flags);
- /* Look for pending interrupts */
- NCR5380_setup(instance);
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- /* XXX dispatch to appropriate routine if found and done=0 */
- if (basr & BASR_IRQ) {
- NCR5380_dprint(NDEBUG_INTR, instance);
- if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
- done = 0;
- dprintk(NDEBUG_INTR, "scsi%d : SEL interrupt\n", instance->host_no);
- NCR5380_reselect(instance);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else if (basr & BASR_PARITY_ERROR) {
- dprintk(NDEBUG_INTR, "scsi%d : PARITY interrupt\n", instance->host_no);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
- dprintk(NDEBUG_INTR, "scsi%d : RESET interrupt\n", instance->host_no);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else {
#if defined(REAL_DMA)
- /*
- * We should only get PHASE MISMATCH and EOP interrupts
- * if we have DMA enabled, so do a sanity check based on
- * the current setting of the MODE register.
- */
+ if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
+ /* Probably End of DMA, Phase Mismatch or Loss of BSY.
+ * We ack IRQ after clearing Mode Register. Workarounds
+ * for End of DMA errata need to happen in DMA Mode.
+ */
- if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) {
- int transferred;
+ dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n");
- if (!hostdata->connected)
- panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno);
+ int transferred;
- transferred = (hostdata->dmalen - NCR5380_dma_residual(instance));
- hostdata->connected->SCp.this_residual -= transferred;
- hostdata->connected->SCp.ptr += transferred;
- hostdata->dmalen = 0;
+ if (!hostdata->connected)
+ panic("scsi%d : DMA interrupt with no connected cmd\n",
+ instance->hostno);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-
- /* FIXME: we need to poll briefly then defer a workqueue task ! */
- NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2*HZ);
+ transferred = hostdata->dmalen - NCR5380_dma_residual(instance);
+ hostdata->connected->SCp.this_residual -= transferred;
+ hostdata->connected->SCp.ptr += transferred;
+ hostdata->dmalen = 0;
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- }
-#else
- dprintk(NDEBUG_INTR, "scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-#endif
+ /* FIXME: we need to poll briefly then defer a workqueue task ! */
+ NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2 * HZ);
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else
+#endif /* REAL_DMA */
+ if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
+ (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
+ /* Probably reselected */
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n");
+
+ if (!hostdata->connected) {
+ NCR5380_reselect(instance);
+ queue_work(hostdata->work_q, &hostdata->main_task);
}
- } /* if BASR_IRQ */
- spin_unlock_irqrestore(instance->host_lock, flags);
- if(!done)
- schedule_delayed_work(&hostdata->coroutine, 0);
- } while (!done);
- return IRQ_HANDLED;
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ } else {
+ /* Probably Bus Reset */
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
+ }
+ handled = 1;
+ } else {
+ shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n");
+ }
+
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+
+ return IRQ_RETVAL(handled);
}
-#endif
+#endif
-/*
+/*
* Function : int NCR5380_select(struct Scsi_Host *instance,
- * struct scsi_cmnd *cmd)
+ * struct scsi_cmnd *cmd)
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- * including ARBITRATION, SELECTION, and initial message out for
- * IDENTIFY and queue messages.
- *
- * Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute.
- *
- * Returns : -1 if selection could not execute for some reason,
- * 0 if selection succeeded or failed because the target
- * did not respond.
- *
- * Side effects :
- * If bus busy, arbitration failed, etc, NCR5380_select() will exit
- * with registers as they should have been on entry - ie
- * SELECT_ENABLE will be set appropriately, the NCR5380
- * will cease to drive any SCSI bus signals.
- *
- * If successful : I_T_L or I_T_L_Q nexus will be established,
- * instance->connected will be set to cmd.
- * SELECT interrupt will be disabled.
- *
- * If failed (no target) : cmd->scsi_done() will be called, and the
- * cmd->result host byte set to DID_BAD_TARGET.
- *
- * Locks: caller holds hostdata lock in IRQ mode
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ * target lives, cmd - SCSI command to execute.
+ *
+ * Returns cmd if selection failed but should be retried,
+ * NULL if selection failed and should not be retried, or
+ * NULL if selection succeeded (hostdata->connected == cmd).
+ *
+ * Side effects :
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
+ *
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
+ *
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
*/
-
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
{
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char tmp[3], phase;
unsigned char *data;
int len;
- unsigned long timeout;
- unsigned char value;
int err;
- NCR5380_setup(instance);
-
- if (hostdata->selecting)
- goto part2;
-
- hostdata->restart_select = 0;
NCR5380_dprint(NDEBUG_ARBITRATION, instance);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id);
+ dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
+ instance->this_id);
+
+ /*
+ * Arbitration and selection phases are slow and involve dropping the
+ * lock, so we have to watch out for EH. An exception handler may
+ * change 'selecting' to NULL. This function will then return NULL
+ * so that the caller will forget about 'cmd'. (During information
+ * transfer phases, EH may change 'connected' to NULL.)
+ */
+ hostdata->selecting = cmd;
- /*
- * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+ /*
+ * Set the phase bits to 0, otherwise the NCR5380 won't drive the
* data bus during SELECTION.
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- /*
+ /*
* Start arbitration.
*/
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(MODE_REG, MR_ARBITRATE);
+ /* The chip now waits for BUS FREE phase. Then after the 800 ns
+ * Bus Free Delay, arbitration will begin.
+ */
- /* We can be relaxed here, interrupts are on, we are
- in workqueue context, the birds are singing in the trees */
- spin_unlock_irq(instance->host_lock);
- err = NCR5380_poll_politely(instance, INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, ICR_ARBITRATION_PROGRESS, 5*HZ);
- spin_lock_irq(instance->host_lock);
+ spin_unlock_irq(&hostdata->lock);
+ err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0,
+ INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS,
+ ICR_ARBITRATION_PROGRESS, HZ);
+ spin_lock_irq(&hostdata->lock);
+ if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) {
+ /* Reselection interrupt */
+ goto out;
+ }
if (err < 0) {
- printk(KERN_DEBUG "scsi: arbitration timeout at %d\n", __LINE__);
NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- goto failed;
+ shost_printk(KERN_ERR, instance,
+ "select: arbitration timeout\n");
+ goto out;
}
+ spin_unlock_irq(&hostdata->lock);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : arbitration complete\n", instance->host_no);
-
- /*
- * The arbitration delay is 2.2us, but this is a minimum and there is
- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
- * the integral nature of udelay().
- *
- */
-
+ /* The SCSI-2 arbitration delay is 2.4 us */
udelay(3);
/* Check for lost arbitration */
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
- NCR5380_write(MODE_REG, MR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no);
- goto failed;
- }
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
-
- if (!(hostdata->flags & FLAG_DTC3181E) &&
- /* RvC: DTC3181E has some trouble with this
- * so we simply removed it. Seems to work with
- * only Mustek scanner attached
- */
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no);
- goto failed;
+ dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n");
+ spin_lock_irq(&hostdata->lock);
+ goto out;
}
- /*
- * Again, bus clear + bus settle time is 1.2us, however, this is
+
+ /* After/during arbitration, BSY should be asserted.
+ * IBM DPES-31080 Version S31Q works now
+ * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman)
+ */
+ NCR5380_write(INITIATOR_COMMAND_REG,
+ ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
+
+ /*
+ * Again, bus clear + bus settle time is 1.2us, however, this is
* a minimum so we'll udelay ceil(1.2)
*/
- udelay(2);
+ if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+ udelay(15);
+ else
+ udelay(2);
+
+ spin_lock_irq(&hostdata->lock);
+
+ /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
+ if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
+ goto out;
+
+ if (!hostdata->selecting) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ goto out;
+ }
- dprintk(NDEBUG_ARBITRATION, "scsi%d : won arbitration\n", instance->host_no);
+ dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
- /*
- * Now that we have won arbitration, start Selection process, asserting
+ /*
+ * Now that we have won arbitration, start Selection process, asserting
* the host and target ID's on the SCSI bus.
*/
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << scmd_id(cmd))));
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd)));
- /*
+ /*
* Raise ATN while SEL is true before BSY goes false from arbitration,
* since this is the only way to guarantee that we'll get a MESSAGE OUT
* phase immediately after selection.
*/
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL);
NCR5380_write(MODE_REG, MR_BASE);
- /*
+ /*
* Reselect interrupts must be turned off prior to the dropping of BSY,
* otherwise we will trigger an interrupt.
*/
NCR5380_write(SELECT_ENABLE_REG, 0);
+ spin_unlock_irq(&hostdata->lock);
+
/*
- * The initiator shall then wait at least two deskew delays and release
+ * The initiator shall then wait at least two deskew delays and release
* the BSY signal.
*/
- udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
+ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
/* Reset BSY */
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL);
- /*
+ /*
* Something weird happens when we cease to drive BSY - looks
- * like the board/chip is letting us do another read before the
+ * like the board/chip is letting us do another read before the
* appropriate propagation delay has expired, and we're confusing
* a BSY signal from ourselves as the target's response to SELECTION.
*
* A small delay (the 'C++' frontend breaks the pipeline with an
* unnecessary jump, making it work on my 386-33/Trantor T128, the
- * tighter 'C' code breaks and requires this) solves the problem -
- * the 1 us delay is arbitrary, and only used because this delay will
- * be the same on other platforms and since it works here, it should
+ * tighter 'C' code breaks and requires this) solves the problem -
+ * the 1 us delay is arbitrary, and only used because this delay will
+ * be the same on other platforms and since it works here, it should
* work there.
*
* wingel suggests that this could be due to failing to wait
@@ -1339,50 +1162,43 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
udelay(1);
- dprintk(NDEBUG_SELECTION, "scsi%d : selecting target %d\n", instance->host_no, scmd_id(cmd));
+ dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd));
- /*
- * The SCSI specification calls for a 250 ms timeout for the actual
+ /*
+ * The SCSI specification calls for a 250 ms timeout for the actual
* selection.
*/
- timeout = jiffies + msecs_to_jiffies(250);
-
- /*
- * XXX very interesting - we're seeing a bounce where the BSY we
- * asserted is being reflected / still asserted (propagation delay?)
- * and it's detecting as true. Sigh.
- */
-
- hostdata->select_time = 0; /* we count the clock ticks at which we polled */
- hostdata->selecting = cmd;
+ err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY,
+ msecs_to_jiffies(250));
-part2:
- /* RvC: here we enter after a sleeping period, or immediately after
- execution of part 1
- we poll only once ech clock tick */
- value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO);
-
- if (!value && (hostdata->select_time < HZ/4)) {
- /* RvC: we still must wait for a device response */
- hostdata->select_time++; /* after 25 ticks the device has failed */
- NCR5380_set_timer(hostdata, 1);
- return 0; /* RvC: we return here with hostdata->selecting set,
- to go to sleep */
- }
-
- hostdata->selecting = NULL;/* clear this pointer, because we passed the
- waiting period */
if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+ spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_reselect(instance);
- printk("scsi%d : reselection after won arbitration?\n", instance->host_no);
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
+ goto out;
+ }
+
+ if (err < 0) {
+ spin_lock_irq(&hostdata->lock);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
+ /* Can't touch cmd if it has been reclaimed by the scsi ML */
+ if (hostdata->selecting) {
+ cmd->result = DID_BAD_TARGET << 16;
+ complete_cmd(instance, cmd);
+ dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
+ cmd = NULL;
+ }
+ goto out;
}
- /*
- * No less than two deskew delays after the initiator detects the
- * BSY signal is true, it shall release the SEL signal and may
+
+ /*
+ * No less than two deskew delays after the initiator detects the
+ * BSY signal is true, it shall release the SEL signal and may
* change the DATA BUS. -wingel
*/
@@ -1390,53 +1206,38 @@ part2:
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << scmd_id(cmd))) {
- printk(KERN_DEBUG "scsi%d : weirdness\n", instance->host_no);
- if (hostdata->restart_select)
- printk(KERN_DEBUG "\trestart select\n");
- NCR5380_dprint(NDEBUG_SELECTION, instance);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- cmd->result = DID_BAD_TARGET << 16;
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- dprintk(NDEBUG_SELECTION, "scsi%d : target did not respond within 250ms\n", instance->host_no);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return 0;
- }
- hostdata->targets_present |= (1 << scmd_id(cmd));
-
/*
- * Since we followed the SCSI spec, and raised ATN while SEL
+ * Since we followed the SCSI spec, and raised ATN while SEL
* was true but before BSY was false during selection, the information
* transfer phase should be a MESSAGE OUT phase so that we can send the
* IDENTIFY message.
- *
+ *
* If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
* message (2 bytes) with a tag ID that we increment with every command
* until it wraps back to 0.
*
* XXX - it turns out that there are some broken SCSI-II devices,
- * which claim to support tagged queuing but fail when more than
- * some number of commands are issued at once.
+ * which claim to support tagged queuing but fail when more than
+ * some number of commands are issued at once.
*/
/* Wait for start of REQ/ACK handshake */
- spin_unlock_irq(instance->host_lock);
err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
- spin_lock_irq(instance->host_lock);
-
- if(err) {
- printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
+ spin_lock_irq(&hostdata->lock);
+ if (err < 0) {
+ shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- goto failed;
+ goto out;
+ }
+ if (!hostdata->selecting) {
+ do_abort(instance);
+ goto out;
}
- dprintk(NDEBUG_SELECTION, "scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id);
+ dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
+ scmd_id(cmd));
tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun);
len = 1;
@@ -1446,104 +1247,82 @@ part2:
data = tmp;
phase = PHASE_MSGOUT;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_SELECTION, "scsi%d : nexus established.\n", instance->host_no);
+ dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n");
/* XXX need to handle errors here */
+
hostdata->connected = cmd;
- hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF));
+ hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun;
initialize_SCp(cmd);
- return 0;
-
- /* Selection failed */
-failed:
- return -1;
+ cmd = NULL;
+out:
+ if (!hostdata->selecting)
+ return NULL;
+ hostdata->selecting = NULL;
+ return cmd;
}
-/*
- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using polled I/O
*
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
- *
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
* Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes or transferred or exit
- * is in same phase.
+ * maximum number of bytes, 0 if all bytes are transferred or exit
+ * is in same phase.
*
- * Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
*
* XXX Note : handling for bus free may be useful.
*/
/*
- * Note : this code is not as quick as it could be, however it
+ * Note : this code is not as quick as it could be, however it
* IS 100% reliable, and for the actual data transfer where speed
* counts, we will always do a pseudo DMA or DMA transfer.
*/
-static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
- NCR5380_local_declare();
+static int NCR5380_transfer_pio(struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
+{
unsigned char p = *phase, tmp;
int c = *count;
unsigned char *d = *data;
- /*
- * RvC: some administrative data to process polling time
- */
- int break_allowed = 0;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- NCR5380_setup(instance);
-
- if (!(p & SR_IO))
- dprintk(NDEBUG_PIO, "scsi%d : pio write %d bytes\n", instance->host_no, c);
- else
- dprintk(NDEBUG_PIO, "scsi%d : pio read %d bytes\n", instance->host_no, c);
- /*
- * The NCR5380 chip will only drive the SCSI bus when the
+ /*
+ * The NCR5380 chip will only drive the SCSI bus when the
* phase specified in the appropriate bits of the TARGET COMMAND
* REGISTER match the STATUS REGISTER
*/
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
- /* RvC: don't know if this is necessary, but other SCSI I/O is short
- * so breaks are not necessary there
- */
- if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) {
- break_allowed = 1;
- }
do {
- /*
- * Wait for assertion of REQ, after which the phase bits will be
- * valid
- */
-
- /* RvC: we simply poll once, after that we stop temporarily
- * and let the device buffer fill up
- * if breaking is not allowed, we keep polling as long as needed
+ /*
+ * Wait for assertion of REQ, after which the phase bits will be
+ * valid
*/
- /* FIXME */
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed);
- if (!(tmp & SR_REQ)) {
- /* timeout condition */
- NCR5380_set_timer(hostdata, USLEEP_SLEEP);
+ if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0)
break;
- }
- dprintk(NDEBUG_HANDSHAKE, "scsi%d : REQ detected\n", instance->host_no);
+ dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n");
/* Check for phase mismatch */
- if ((tmp & PHASE_MASK) != p) {
- dprintk(NDEBUG_HANDSHAKE, "scsi%d : phase mismatch\n", instance->host_no);
- NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance);
+ if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) {
+ dsprintk(NDEBUG_PIO, instance, "phase mismatch\n");
+ NCR5380_dprint_phase(NDEBUG_PIO, instance);
break;
}
+
/* Do actual transfer from SCSI bus to / from memory */
if (!(p & SR_IO))
NCR5380_write(OUTPUT_DATA_REG, *d);
@@ -1552,7 +1331,7 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
++d;
- /*
+ /*
* The SCSI standard suggests that in MSGOUT phase, the initiator
* should drop ATN on the last byte of the message phase
* after REQ has been asserted for the handshake but before
@@ -1563,29 +1342,34 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
if (!((p & SR_MSG) && c > 1)) {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
} else {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
}
} else {
NCR5380_dprint(NDEBUG_PIO, instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
}
- /* FIXME - if this fails bus reset ?? */
- NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 5*HZ);
- dprintk(NDEBUG_HANDSHAKE, "scsi%d : req false, handshake complete\n", instance->host_no);
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_REQ, 0, 5 * HZ) < 0)
+ break;
+
+ dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n");
/*
- * We have several special cases to consider during REQ/ACK handshaking :
- * 1. We were in MSGOUT phase, and we are on the last byte of the
- * message. ATN must be dropped as ACK is dropped.
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1. We were in MSGOUT phase, and we are on the last byte of the
+ * message. ATN must be dropped as ACK is dropped.
*
- * 2. We are in a MSGIN phase, and we are on the last byte of the
- * message. We must exit with ACK asserted, so that the calling
- * code may raise ATN before dropping ACK to reject the message.
+ * 2. We are in a MSGIN phase, and we are on the last byte of the
+ * message. We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
*
* 3. ACK and ATN are clear and the target may proceed as normal.
*/
@@ -1597,12 +1381,16 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
}
} while (--c);
- dprintk(NDEBUG_PIO, "scsi%d : residual %d\n", instance->host_no, c);
+ dsprintk(NDEBUG_PIO, instance, "residual %d\n", c);
*count = c;
*data = d;
tmp = NCR5380_read(STATUS_REG);
- if (tmp & SR_REQ)
+ /* The phase read from the bus is valid if either REQ is (already)
+ * asserted or if ACK hasn't been released yet. The latter applies if
+ * we're in MSG IN, DATA IN or STATUS and all bytes have been received.
+ */
+ if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0))
*phase = tmp & PHASE_MASK;
else
*phase = PHASE_UNKNOWN;
@@ -1614,79 +1402,80 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase
}
/**
- * do_reset - issue a reset command
- * @host: adapter to reset
+ * do_reset - issue a reset command
+ * @instance: adapter to reset
*
- * Issue a reset sequence to the NCR5380 and try and get the bus
- * back into sane shape.
+ * Issue a reset sequence to the NCR5380 and try and get the bus
+ * back into sane shape.
*
- * Locks: caller holds queue lock
+ * This clears the reset interrupt flag because there may be no handler for
+ * it. When the driver is initialized, the NCR5380_intr() handler has not yet
+ * been installed. And when in EH we may have released the ST DMA interrupt.
*/
-
-static void do_reset(struct Scsi_Host *host) {
- NCR5380_local_declare();
- NCR5380_setup(host);
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
+static void do_reset(struct Scsi_Host *instance)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ NCR5380_write(TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
- udelay(25);
+ udelay(50);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ local_irq_restore(flags);
}
-/*
- * Function : do_abort (Scsi_Host *host)
- *
- * Purpose : abort the currently established nexus. Should only be
- * called from a routine which can drop into a
- *
- * Returns : 0 on success, -1 on failure.
- *
- * Locks: queue lock held by caller
- * FIXME: sort this out and get new_eh running
+/**
+ * do_abort - abort the currently established nexus by going to
+ * MESSAGE OUT phase and sending an ABORT message.
+ * @instance: relevant scsi host instance
+ *
+ * Returns 0 on success, -1 on failure.
*/
-static int do_abort(struct Scsi_Host *host) {
- NCR5380_local_declare();
+static int do_abort(struct Scsi_Host *instance)
+{
unsigned char *msgptr, phase, tmp;
int len;
int rc;
- NCR5380_setup(host);
-
/* Request message out phase */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- /*
- * Wait for the target to indicate a valid phase by asserting
- * REQ. Once this happens, we'll have either a MSGOUT phase
- * and can immediately send the ABORT message, or we'll have some
+ /*
+ * Wait for the target to indicate a valid phase by asserting
+ * REQ. Once this happens, we'll have either a MSGOUT phase
+ * and can immediately send the ABORT message, or we'll have some
* other phase and will have to source/sink data.
- *
+ *
* We really don't care what value was on the bus or what value
* the target sees, so we just handshake.
*/
- rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, SR_REQ, 60 * HZ);
-
- if(rc < 0)
- return -1;
+ rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
+ if (rc < 0)
+ goto timeout;
+
+ tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
- tmp = (unsigned char)rc;
-
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, 0, 3*HZ);
+ if (tmp != PHASE_MSGOUT) {
+ NCR5380_write(INITIATOR_COMMAND_REG,
+ ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ);
+ if (rc < 0)
+ goto timeout;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- if(rc == -1)
- return -1;
}
+
tmp = ABORT;
msgptr = &tmp;
len = 1;
phase = PHASE_MSGOUT;
- NCR5380_transfer_pio(host, &phase, &len, &msgptr);
+ NCR5380_transfer_pio(instance, &phase, &len, &msgptr);
/*
* If we got here, and the command completed successfully,
@@ -1694,32 +1483,37 @@ static int do_abort(struct Scsi_Host *host) {
*/
return len ? -1 : 0;
+
+timeout:
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
}
#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)
-/*
- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using either real
- * or pseudo DMA.
+ * or pseudo DMA.
*
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
- *
- * Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes or transferred or exit
- * is in same phase.
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
*
- * Also, *phase, *count, *data are modified in place.
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes or transferred or exit
+ * is in same phase.
*
- * Locks: io_request lock held by caller
+ * Also, *phase, *count, *data are modified in place.
*/
-static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
- NCR5380_local_declare();
+static int NCR5380_transfer_dma(struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
register int c = *count;
register unsigned char p = *phase;
register unsigned char *d = *data;
@@ -1730,54 +1524,47 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
unsigned char saved_data = 0, overrun = 0, residue;
#endif
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
-
- NCR5380_setup(instance);
-
if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
*phase = tmp;
return -1;
}
#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
-#ifdef READ_OVERRUNS
if (p & SR_IO) {
- c -= 2;
+ if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS))
+ c -= 2;
}
-#endif
- dprintk(NDEBUG_DMA, "scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c);
+
+ dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+ (p & SR_IO) ? "receive" : "send", c, *data);
#endif
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
#ifdef REAL_DMA
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+ MR_ENABLE_EOP_INTR);
#elif defined(REAL_DMA_POLL)
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY);
#else
/*
* Note : on my sample board, watch-dog timeouts occurred when interrupts
- * were not disabled for the duration of a single DMA transfer, from
+ * were not disabled for the duration of a single DMA transfer, from
* before the setting of DMA mode to after transfer of the last byte.
*/
-#if defined(PSEUDO_DMA) && defined(UNSAFE)
- spin_unlock_irq(instance->host_lock);
-#endif
- /* KLL May need eop and parity in 53c400 */
- if (hostdata->flags & FLAG_NCR53C400)
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE |
- MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR |
- MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+ if (hostdata->flags & FLAG_NO_DMA_FIXUP)
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+ MR_ENABLE_EOP_INTR);
else
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY);
#endif /* def REAL_DMA */
dprintk(NDEBUG_DMA, "scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));
- /*
- * On the PAS16 at least I/O recovery delays are not needed here.
- * Everyone else seems to want them.
+ /*
+ * On the PAS16 at least I/O recovery delays are not needed here.
+ * Everyone else seems to want them.
*/
if (p & SR_IO) {
@@ -1797,49 +1584,49 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER)));
/*
- At this point, either we've completed DMA, or we have a phase mismatch,
- or we've unexpectedly lost BUSY (which is a real error).
-
- For write DMAs, we want to wait until the last byte has been
- transferred out over the bus before we turn off DMA mode. Alas, there
- seems to be no terribly good way of doing this on a 5380 under all
- conditions. For non-scatter-gather operations, we can wait until REQ
- and ACK both go false, or until a phase mismatch occurs. Gather-writes
- are nastier, since the device will be expecting more data than we
- are prepared to send it, and REQ will remain asserted. On a 53C8[01] we
- could test LAST BIT SENT to assure transfer (I imagine this is precisely
- why this signal was added to the newer chips) but on the older 538[01]
- this signal does not exist. The workaround for this lack is a watchdog;
- we bail out of the wait-loop after a modest amount of wait-time if
- the usual exit conditions are not met. Not a terribly clean or
- correct solution :-%
-
- Reads are equally tricky due to a nasty characteristic of the NCR5380.
- If the chip is in DMA mode for an READ, it will respond to a target's
- REQ by latching the SCSI data into the INPUT DATA register and asserting
- ACK, even if it has _already_ been notified by the DMA controller that
- the current DMA transfer has completed! If the NCR5380 is then taken
- out of DMA mode, this already-acknowledged byte is lost.
-
- This is not a problem for "one DMA transfer per command" reads, because
- the situation will never arise... either all of the data is DMA'ed
- properly, or the target switches to MESSAGE IN phase to signal a
- disconnection (either operation bringing the DMA to a clean halt).
- However, in order to handle scatter-reads, we must work around the
- problem. The chosen fix is to DMA N-2 bytes, then check for the
- condition before taking the NCR5380 out of DMA mode. One or two extra
- bytes are transferred via PIO as necessary to fill out the original
- request.
+ * At this point, either we've completed DMA, or we have a phase mismatch,
+ * or we've unexpectedly lost BUSY (which is a real error).
+ *
+ * For DMA sends, we want to wait until the last byte has been
+ * transferred out over the bus before we turn off DMA mode. Alas, there
+ * seems to be no terribly good way of doing this on a 5380 under all
+ * conditions. For non-scatter-gather operations, we can wait until REQ
+ * and ACK both go false, or until a phase mismatch occurs. Gather-sends
+ * are nastier, since the device will be expecting more data than we
+ * are prepared to send it, and REQ will remain asserted. On a 53C8[01] we
+ * could test Last Byte Sent to assure transfer (I imagine this is precisely
+ * why this signal was added to the newer chips) but on the older 538[01]
+ * this signal does not exist. The workaround for this lack is a watchdog;
+ * we bail out of the wait-loop after a modest amount of wait-time if
+ * the usual exit conditions are not met. Not a terribly clean or
+ * correct solution :-%
+ *
+ * DMA receive is equally tricky due to a nasty characteristic of the NCR5380.
+ * If the chip is in DMA receive mode, it will respond to a target's
+ * REQ by latching the SCSI data into the INPUT DATA register and asserting
+ * ACK, even if it has _already_ been notified by the DMA controller that
+ * the current DMA transfer has completed! If the NCR5380 is then taken
+ * out of DMA mode, this already-acknowledged byte is lost. This is
+ * not a problem for "one DMA transfer per READ command", because
+ * the situation will never arise... either all of the data is DMA'ed
+ * properly, or the target switches to MESSAGE IN phase to signal a
+ * disconnection (either operation bringing the DMA to a clean halt).
+ * However, in order to handle scatter-receive, we must work around the
+ * problem. The chosen fix is to DMA N-2 bytes, then check for the
+ * condition before taking the NCR5380 out of DMA mode. One or two extra
+ * bytes are transferred via PIO as necessary to fill out the original
+ * request.
*/
if (p & SR_IO) {
-#ifdef READ_OVERRUNS
- udelay(10);
- if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) {
- saved_data = NCR5380_read(INPUT_DATA_REGISTER);
- overrun = 1;
+ if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS)) {
+ udelay(10);
+ if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) ==
+ (BASR_PHASE_MATCH | BASR_ACK)) {
+ saved_data = NCR5380_read(INPUT_DATA_REGISTER);
+ overrun = 1;
+ }
}
-#endif
} else {
int limit = 100;
while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) {
@@ -1850,7 +1637,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
}
}
- dprintk(NDEBUG_DMA, "scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG));
+ dsprintk(NDEBUG_DMA, "polled DMA transfer complete, basr 0x%02x, sr 0x%02x\n",
+ tmp, NCR5380_read(STATUS_REG));
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1861,8 +1649,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
*data += c;
*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
-#ifdef READ_OVERRUNS
- if (*phase == p && (p & SR_IO) && residue == 0) {
+ if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS) &&
+ *phase == p && (p & SR_IO) && residue == 0) {
if (overrun) {
dprintk(NDEBUG_DMA, "Got an input overrun, using saved byte\n");
**data = saved_data;
@@ -1877,7 +1665,6 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
NCR5380_transfer_pio(instance, phase, &cnt, data);
*count -= toPIO - cnt;
}
-#endif
dprintk(NDEBUG_DMA, "Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count));
return 0;
@@ -1886,95 +1673,64 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
return 0;
#else /* defined(REAL_DMA_POLL) */
if (p & SR_IO) {
-#ifdef DMA_WORKS_RIGHT
- foo = NCR5380_pread(instance, d, c);
-#else
- int diff = 1;
- if (hostdata->flags & FLAG_NCR53C400) {
- diff = 0;
- }
- if (!(foo = NCR5380_pread(instance, d, c - diff))) {
+ foo = NCR5380_pread(instance, d,
+ hostdata->flags & FLAG_NO_DMA_FIXUP ? c : c - 1);
+ if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) {
/*
- * We can't disable DMA mode after successfully transferring
+ * We can't disable DMA mode after successfully transferring
* what we plan to be the last byte, since that would open up
- * a race condition where if the target asserted REQ before
+ * a race condition where if the target asserted REQ before
* we got the DMA mode reset, the NCR5380 would have latched
* an additional byte into the INPUT DATA register and we'd
* have dropped it.
- *
- * The workaround was to transfer one fewer bytes than we
- * intended to with the pseudo-DMA read function, wait for
+ *
+ * The workaround was to transfer one fewer bytes than we
+ * intended to with the pseudo-DMA read function, wait for
* the chip to latch the last byte, read it, and then disable
* pseudo-DMA mode.
- *
+ *
* After REQ is asserted, the NCR5380 asserts DRQ and ACK.
* REQ is deasserted when ACK is asserted, and not reasserted
* until ACK goes false. Since the NCR5380 won't lower ACK
* until DACK is asserted, which won't happen unless we twiddle
- * the DMA port or we take the NCR5380 out of DMA mode, we
- * can guarantee that we won't handshake another extra
+ * the DMA port or we take the NCR5380 out of DMA mode, we
+ * can guarantee that we won't handshake another extra
* byte.
*/
- if (!(hostdata->flags & FLAG_NCR53C400)) {
- while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
- /* Wait for clean handshake */
- while (NCR5380_read(STATUS_REG) & SR_REQ);
- d[c - 1] = NCR5380_read(INPUT_DATA_REG);
+ if (NCR5380_poll_politely(instance, BUS_AND_STATUS_REG,
+ BASR_DRQ, BASR_DRQ, HZ) < 0) {
+ foo = -1;
+ shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n");
+ }
+ if (NCR5380_poll_politely(instance, STATUS_REG,
+ SR_REQ, 0, HZ) < 0) {
+ foo = -1;
+ shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n");
}
+ d[c - 1] = NCR5380_read(INPUT_DATA_REG);
}
-#endif
} else {
-#ifdef DMA_WORKS_RIGHT
foo = NCR5380_pwrite(instance, d, c);
-#else
- int timeout;
- dprintk(NDEBUG_C400_PWRITE, "About to pwrite %d bytes\n", c);
- if (!(foo = NCR5380_pwrite(instance, d, c))) {
+ if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) {
/*
- * Wait for the last byte to be sent. If REQ is being asserted for
- * the byte we're interested, we'll ACK it and it will go false.
+ * Wait for the last byte to be sent. If REQ is being asserted for
+ * the byte we're interested, we'll ACK it and it will go false.
*/
- if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
- timeout = 20000;
- while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH));
-
- if (!timeout)
- dprintk(NDEBUG_LAST_BYTE_SENT, "scsi%d : timed out on last byte\n", instance->host_no);
-
- if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
- hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
- if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) {
- hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
- dprintk(NDEBUG_LAST_BYTE_SENT, "scsi%d : last byte sent works\n", instance->host_no);
- }
- }
- } else {
- dprintk(NDEBUG_C400_PWRITE, "Waiting for LASTBYTE\n");
- while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));
- dprintk(NDEBUG_C400_PWRITE, "Got LASTBYTE\n");
+ if (NCR5380_poll_politely2(instance,
+ BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ,
+ BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) {
+ foo = -1;
+ shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n");
}
}
-#endif
}
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) {
- dprintk(NDEBUG_C400_PWRITE, "53C400w: Checking for IRQ\n");
- if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) {
- dprintk(NDEBUG_C400_PWRITE, "53C400w: got it, reading reset interrupt reg\n");
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else {
- printk("53C400w: IRQ NOT THERE!\n");
- }
- }
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
*data = d + c;
*count = 0;
*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
-#if defined(PSEUDO_DMA) && defined(UNSAFE)
- spin_lock_irq(instance->host_lock);
-#endif /* defined(REAL_DMA_POLL) */
return foo;
#endif /* def REAL_DMA */
}
@@ -1983,25 +1739,23 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase
/*
* Function : NCR5380_information_transfer (struct Scsi_Host *instance)
*
- * Purpose : run through the various SCSI phases and do as the target
- * directs us to. Operates on the currently connected command,
- * instance->connected.
+ * Purpose : run through the various SCSI phases and do as the target
+ * directs us to. Operates on the currently connected command,
+ * instance->connected.
*
* Inputs : instance, instance for which we are doing commands
*
- * Side effects : SCSI things happen, the disconnected queue will be
- * modified if a command disconnects, *instance->connected will
- * change.
- *
- * XXX Note : we need to watch for bus free or a reset condition here
- * to recover from an unexpected bus free condition.
+ * Side effects : SCSI things happen, the disconnected queue will be
+ * modified if a command disconnects, *instance->connected will
+ * change.
*
- * Locks: io_request_lock held by caller in IRQ mode
+ * XXX Note : we need to watch for bus free or a reset condition here
+ * to recover from an unexpected bus free condition.
*/
-static void NCR5380_information_transfer(struct Scsi_Host *instance) {
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+static void NCR5380_information_transfer(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char msgout = NOP;
int sink = 0;
int len;
@@ -2010,13 +1764,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
- struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
- /* RvC: we need to set the end of the polling time */
- unsigned long poll_time = jiffies + USLEEP_POLL;
+ struct scsi_cmnd *cmd;
- NCR5380_setup(instance);
+ while ((cmd = hostdata->connected)) {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
- while (1) {
tmp = NCR5380_read(STATUS_REG);
/* We only have a valid SCSI phase when REQ is asserted */
if (tmp & SR_REQ) {
@@ -2028,24 +1780,28 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
if (sink && (phase != PHASE_MSGOUT)) {
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ)
+ ;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
sink = 0;
continue;
}
+
switch (phase) {
- case PHASE_DATAIN:
case PHASE_DATAOUT:
#if (NDEBUG & NDEBUG_NO_DATAOUT)
- printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no);
+ shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n");
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
+ complete_cmd(instance, cmd);
return;
#endif
- /*
+ case PHASE_DATAIN:
+ /*
* If there is no room left in the current buffer in the
* scatter-gather list, move onto the next one.
*/
@@ -2055,10 +1811,13 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- dprintk(NDEBUG_INFORMATION, "scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual);
+ dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
+ cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
}
+
/*
- * The preferred transfer method is going to be
+ * The preferred transfer method is going to be
* PSEUDO-DMA for systems that are strictly PIO,
* since we can let the hardware do the handshaking.
*
@@ -2068,50 +1827,39 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
*/
#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
- /* KLL
- * PSEUDO_DMA is defined here. If this is the g_NCR5380
- * driver then it will always be defined, so the
- * FLAG_NO_PSEUDO_DMA is used to inhibit PDMA in the base
- * NCR5380 case. I think this is a fairly clean solution.
- * We supplement these 2 if's with the flag.
- */
-#ifdef NCR5380_dma_xfer_len
- if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
-#else
- transfersize = cmd->transfersize;
-
-#ifdef LIMIT_TRANSFERSIZE /* If we have problems with interrupt service */
- if (transfersize > 512)
- transfersize = 512;
-#endif /* LIMIT_TRANSFERSIZE */
-
- if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) {
- /* Limit transfers to 32K, for xx400 & xx406
- * pseudoDMA that transfers in 128 bytes blocks. */
- if (transfersize > 32 * 1024)
- transfersize = 32 * 1024;
-#endif
+ transfersize = 0;
+ if (!cmd->device->borken &&
+ !(hostdata->flags & FLAG_NO_PSEUDO_DMA))
+ transfersize = NCR5380_dma_xfer_len(instance, cmd, phase);
+
+ if (transfersize) {
len = transfersize;
- if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) {
+ if (NCR5380_transfer_dma(instance, &phase,
+ &len, (unsigned char **)&cmd->SCp.ptr)) {
/*
- * If the watchdog timer fires, all future accesses to this
- * device will use the polled-IO.
+ * If the watchdog timer fires, all future
+ * accesses to this device will use the
+ * polled-IO.
*/
scmd_printk(KERN_INFO, cmd,
- "switching to slow handshake\n");
+ "switching to slow handshake\n");
cmd->device->borken = 1;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
+ complete_cmd(instance, cmd);
/* XXX - need to source or sink data here, as appropriate */
} else
cmd->SCp.this_residual -= transfersize - len;
} else
#endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
- NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **)
- &cmd->SCp.ptr);
+ {
+ spin_unlock_irq(&hostdata->lock);
+ NCR5380_transfer_pio(instance, &phase,
+ (int *)&cmd->SCp.this_residual,
+ (unsigned char **)&cmd->SCp.ptr);
+ spin_lock_irq(&hostdata->lock);
+ }
break;
case PHASE_MSGIN:
len = 1;
@@ -2120,101 +1868,42 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
cmd->SCp.Message = tmp;
switch (tmp) {
- /*
- * Linking lets us reduce the time required to get the
- * next command out to the device, hopefully this will
- * mean we don't waste another revolution due to the delays
- * required by ARBITRATION and another SELECTION.
- *
- * In the current implementation proposal, low level drivers
- * merely have to start the next command, pointed to by
- * next_link, done() is called as with unlinked commands.
- */
-#ifdef LINKED
- case LINKED_CMD_COMPLETE:
- case LINKED_FLG_CMD_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_LINKED, "scsi%d : target %d lun %llu linked command complete.\n", instance->host_no, cmd->device->id, cmd->device->lun);
- /*
- * Sanity check : A linked command should only terminate with
- * one of these messages if there are more linked commands
- * available.
- */
- if (!cmd->next_link) {
- printk("scsi%d : target %d lun %llu linked command complete, no next_link\n" instance->host_no, cmd->device->id, cmd->device->lun);
- sink = 1;
- do_abort(instance);
- return;
- }
- initialize_SCp(cmd->next_link);
- /* The next command is still part of this process */
- cmd->next_link->tag = cmd->tag;
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- dprintk(NDEBUG_LINKED, "scsi%d : target %d lun %llu linked request done, calling scsi_done().\n", instance->host_no, cmd->device->id, cmd->device->lun);
- cmd->scsi_done(cmd);
- cmd = hostdata->connected;
- break;
-#endif /* def LINKED */
case ABORT:
case COMMAND_COMPLETE:
/* Accept message by clearing ACK */
sink = 1;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- hostdata->connected = NULL;
- dprintk(NDEBUG_QUEUES, "scsi%d : command for target %d, lun %llu completed\n", instance->host_no, cmd->device->id, cmd->device->lun);
- hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xFF));
-
- /*
- * I'm not sure what the correct thing to do here is :
- *
- * If the command that just executed is NOT a request
- * sense, the obvious thing to do is to set the result
- * code to the values of the stored parameters.
- *
- * If it was a REQUEST SENSE command, we need some way
- * to differentiate between the failure code of the original
- * and the failure code of the REQUEST sense - the obvious
- * case is success, where we fall through and leave the result
- * code unchanged.
- *
- * The non-obvious place is where the REQUEST SENSE failed
- */
-
- if (cmd->cmnd[0] != REQUEST_SENSE)
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- else if (status_byte(cmd->SCp.Status) != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "COMMAND COMPLETE %p target %d lun %llu\n",
+ cmd, scmd_id(cmd), cmd->device->lun);
- if ((cmd->cmnd[0] == REQUEST_SENSE) &&
- hostdata->ses.cmd_len) {
- scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- hostdata->ses.cmd_len = 0 ;
- }
-
- if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
- scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
-
- dprintk(NDEBUG_AUTOSENSE, "scsi%d : performing request sense\n", instance->host_no);
+ hostdata->connected = NULL;
- LIST(cmd, hostdata->issue_queue);
- cmd->host_scribble = (unsigned char *)
- hostdata->issue_queue;
- hostdata->issue_queue = (struct scsi_cmnd *) cmd;
- dprintk(NDEBUG_QUEUES, "scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no);
- } else {
- cmd->scsi_done(cmd);
+ cmd->result &= ~0xffff;
+ cmd->result |= cmd->SCp.Status;
+ cmd->result |= cmd->SCp.Message << 8;
+
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ complete_cmd(instance, cmd);
+ else {
+ if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION ||
+ cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) {
+ dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n",
+ cmd);
+ list_add_tail(&ncmd->list,
+ &hostdata->autosense);
+ } else
+ complete_cmd(instance, cmd);
}
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Restore phase bits to 0 so an interrupted selection,
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
case MESSAGE_REJECT:
/* Accept message by clearing ACK */
@@ -2229,38 +1918,33 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
default:
break;
}
- case DISCONNECT:{
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- cmd->device->disconnect = 1;
- LIST(cmd, hostdata->disconnected_queue);
- cmd->host_scribble = (unsigned char *)
- hostdata->disconnected_queue;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = cmd;
- dprintk(NDEBUG_QUEUES, "scsi%d : command for target %d lun %llu was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->device->id, cmd->device->lun);
- /*
- * Restore phase bits to 0 so an interrupted selection,
- * arbitration can resume.
- */
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /* Wait for bus free to avoid nasty timeouts - FIXME timeout !*/
- /* NCR538_poll_politely(instance, STATUS_REG, SR_BSY, 0, 30 * HZ); */
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
- return;
- }
- /*
+ break;
+ case DISCONNECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ hostdata->connected = NULL;
+ list_add(&ncmd->list, &hostdata->disconnected);
+ dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES,
+ instance, "connected command %p for target %d lun %llu moved to disconnected queue\n",
+ cmd, scmd_id(cmd), cmd->device->lun);
+
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return;
+ /*
* The SCSI data pointer is *IMPLICITLY* saved on a disconnect
- * operation, in violation of the SCSI spec so we can safely
+ * operation, in violation of the SCSI spec so we can safely
* ignore SAVE/RESTORE pointers calls.
*
- * Unfortunately, some disks violate the SCSI spec and
+ * Unfortunately, some disks violate the SCSI spec and
* don't issue the required SAVE_POINTERS message before
- * disconnecting, and we have to break spec to remain
+ * disconnecting, and we have to break spec to remain
* compatible.
*/
case SAVE_POINTERS:
@@ -2269,31 +1953,28 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
break;
case EXTENDED_MESSAGE:
-/*
- * Extended messages are sent in the following format :
- * Byte
- * 0 EXTENDED_MESSAGE == 1
- * 1 length (includes one byte for code, doesn't
- * include first two bytes)
- * 2 code
- * 3..length+1 arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since spi_print_msg() wants the whole thing.
- */
+ /*
+ * Start the message buffer with the EXTENDED_MESSAGE
+ * byte, since spi_print_msg() wants the whole thing.
+ */
extended_msg[0] = EXTENDED_MESSAGE;
/* Accept first byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_EXTENDED, "scsi%d : receiving extended message\n", instance->host_no);
+
+ spin_unlock_irq(&hostdata->lock);
+
+ dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n");
len = 2;
data = extended_msg + 1;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
+ dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n",
+ (int)extended_msg[1],
+ (int)extended_msg[2]);
- dprintk(NDEBUG_EXTENDED, "scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2]);
-
- if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) {
+ if (!len && extended_msg[1] > 0 &&
+ extended_msg[1] <= sizeof(extended_msg) - 2) {
/* Accept third byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
len = extended_msg[1] - 1;
@@ -2301,7 +1982,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_EXTENDED, "scsi%d : message received, residual %d\n", instance->host_no, len);
+ dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n",
+ len);
switch (extended_msg[2]) {
case EXTENDED_SDTR:
@@ -2311,34 +1993,42 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
tmp = 0;
}
} else if (len) {
- printk("scsi%d: error receiving extended message\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "error receiving extended message\n");
tmp = 0;
} else {
- printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]);
+ shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n",
+ extended_msg[2], extended_msg[1]);
tmp = 0;
}
+
+ spin_lock_irq(&hostdata->lock);
+ if (!hostdata->connected)
+ return;
+
/* Fall through to reject message */
- /*
- * If we get something weird that we aren't expecting,
+ /*
+ * If we get something weird that we aren't expecting,
* reject it.
*/
default:
if (!tmp) {
- printk("scsi%d: rejecting message ", instance->host_no);
+ shost_printk(KERN_ERR, instance, "rejecting message ");
spi_print_msg(extended_msg);
printk("\n");
} else if (tmp != EXTENDED_MESSAGE)
scmd_printk(KERN_INFO, cmd,
- "rejecting unknown message %02x\n",tmp);
+ "rejecting unknown message %02x\n",
+ tmp);
else
scmd_printk(KERN_INFO, cmd,
- "rejecting unknown extended message code %02x, length %d\n", extended_msg[1], extended_msg[0]);
+ "rejecting unknown extended message code %02x, length %d\n",
+ extended_msg[1], extended_msg[0]);
msgout = MESSAGE_REJECT;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
break;
- } /* switch (tmp) */
+ } /* switch (tmp) */
break;
case PHASE_MSGOUT:
len = 1;
@@ -2346,10 +2036,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
hostdata->last_message = msgout;
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (msgout == ABORT) {
- hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xFF));
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
+ complete_cmd(instance, cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
}
@@ -2358,17 +2047,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
case PHASE_CMDOUT:
len = cmd->cmd_len;
data = cmd->cmnd;
- /*
- * XXX for performance reasons, on machines with a
- * PSEUDO-DMA architecture we should probably
- * use the dma transfer function.
+ /*
+ * XXX for performance reasons, on machines with a
+ * PSEUDO-DMA architecture we should probably
+ * use the dma transfer function.
*/
NCR5380_transfer_pio(instance, &phase, &len, &data);
- if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) {
- NCR5380_set_timer(hostdata, USLEEP_SLEEP);
- dprintk(NDEBUG_USLEEP, "scsi%d : issued command, sleeping until %lu\n", instance->host_no, hostdata->time_expires);
- return;
- }
break;
case PHASE_STATIN:
len = 1;
@@ -2377,46 +2061,37 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
cmd->SCp.Status = tmp;
break;
default:
- printk("scsi%d : unknown phase\n", instance->host_no);
+ shost_printk(KERN_ERR, instance, "unknown phase\n");
NCR5380_dprint(NDEBUG_ANY, instance);
- } /* switch(phase) */
- } /* if (tmp * SR_REQ) */
- else {
- /* RvC: go to sleep if polling time expired
- */
- if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) {
- NCR5380_set_timer(hostdata, USLEEP_SLEEP);
- dprintk(NDEBUG_USLEEP, "scsi%d : poll timed out, sleeping until %lu\n", instance->host_no, hostdata->time_expires);
- return;
- }
+ } /* switch(phase) */
+ } else {
+ spin_unlock_irq(&hostdata->lock);
+ NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+ spin_lock_irq(&hostdata->lock);
}
- } /* while (1) */
+ }
}
/*
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
- * Purpose : does reselection, initializing the instance->connected
- * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
- * nexus has been reestablished,
- *
- * Inputs : instance - this instance of the NCR5380.
+ * Purpose : does reselection, initializing the instance->connected
+ * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
*
- * Locks: io_request_lock held by caller if IRQ driven
+ * Inputs : instance - this instance of the NCR5380.
*/
-static void NCR5380_reselect(struct Scsi_Host *instance) {
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
- instance->hostdata;
+static void NCR5380_reselect(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char target_mask;
unsigned char lun, phase;
int len;
unsigned char msg[3];
unsigned char *data;
- struct scsi_cmnd *tmp = NULL, *prev;
- int abort = 0;
- NCR5380_setup(instance);
+ struct NCR5380_cmd *ncmd;
+ struct scsi_cmnd *tmp;
/*
* Disable arbitration, etc. since the host adapter obviously
@@ -2424,12 +2099,12 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
*/
NCR5380_write(MODE_REG, MR_BASE);
- hostdata->restart_select = 1;
target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
- dprintk(NDEBUG_SELECTION, "scsi%d : reselect\n", instance->host_no);
- /*
+ dsprintk(NDEBUG_RESELECTION, instance, "reselect\n");
+
+ /*
* At this point, we have detected that our SCSI ID is on the bus,
* SEL is true and BSY was false for at least one bus settle delay
* (400 ns).
@@ -2439,103 +2114,110 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
*/
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
- /* FIXME: timeout too long, must fail to workqueue */
- if(NCR5380_poll_politely(instance, STATUS_REG, SR_SEL, 0, 2*HZ)<0)
- abort = 1;
-
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return;
+ }
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/*
* Wait for target to go into MSGIN.
- * FIXME: timeout needed and fail to work queeu
*/
- if(NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 2*HZ))
- abort = 1;
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
+ do_abort(instance);
+ return;
+ }
len = 1;
data = msg;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
+ if (len) {
+ do_abort(instance);
+ return;
+ }
+
if (!(msg[0] & 0x80)) {
- printk(KERN_ERR "scsi%d : expecting IDENTIFY message, got ", instance->host_no);
+ shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
spi_print_msg(msg);
- abort = 1;
- } else {
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- lun = (msg[0] & 0x07);
+ printk("\n");
+ do_abort(instance);
+ return;
+ }
+ lun = msg[0] & 0x07;
- /*
- * We need to add code for SCSI-II to track which devices have
- * I_T_L_Q nexuses established, and which have simple I_T_L
- * nexuses so we can chose to do additional data transfer.
- */
+ /*
+ * We need to add code for SCSI-II to track which devices have
+ * I_T_L_Q nexuses established, and which have simple I_T_L
+ * nexuses so we can chose to do additional data transfer.
+ */
- /*
- * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
- * just reestablished, and remove it from the disconnected queue.
- */
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just reestablished, and remove it from the disconnected queue.
+ */
+ tmp = NULL;
+ list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
- if ((target_mask == (1 << tmp->device->id)) && (lun == (u8)tmp->device->lun)
- ) {
- if (prev) {
- REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
- prev->host_scribble = tmp->host_scribble;
- } else {
- REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble);
- hostdata->disconnected_queue = (struct scsi_cmnd *) tmp->host_scribble;
- }
- tmp->host_scribble = NULL;
- break;
- }
- if (!tmp) {
- printk(KERN_ERR "scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun);
- /*
- * Since we have an established nexus that we can't do anything with,
- * we must abort it.
- */
- abort = 1;
+ if (target_mask == (1 << scmd_id(cmd)) &&
+ lun == (u8)cmd->device->lun) {
+ list_del(&ncmd->list);
+ tmp = cmd;
+ break;
}
}
- if (abort) {
- do_abort(instance);
+ if (tmp) {
+ dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
+ "reselect: removed %p from disconnected queue\n", tmp);
} else {
- hostdata->connected = tmp;
- dprintk(NDEBUG_RESELECTION, "scsi%d : nexus established, target = %d, lun = %llu, tag = %d\n", instance->host_no, tmp->device->id, tmp->device->lun, tmp->tag);
+ shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
+ target_mask, lun);
+ /*
+ * Since we have an established nexus that we can't do anything
+ * with, we must abort it.
+ */
+ do_abort(instance);
+ return;
}
+
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ hostdata->connected = tmp;
+ dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu, tag %d\n",
+ scmd_id(tmp), tmp->device->lun, tmp->tag);
}
/*
* Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
*
* Purpose : called by interrupt handler when DMA finishes or a phase
- * mismatch occurs (which would finish the DMA transfer).
+ * mismatch occurs (which would finish the DMA transfer).
*
* Inputs : instance - this instance of the NCR5380.
*
* Returns : pointer to the scsi_cmnd structure for which the I_T_L
- * nexus has been reestablished, on failure NULL is returned.
+ * nexus has been reestablished, on failure NULL is returned.
*/
#ifdef REAL_DMA
static void NCR5380_dma_complete(NCR5380_instance * instance) {
- NCR5380_local_declare();
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int transferred;
- NCR5380_setup(instance);
/*
* XXX this might not be right.
*
* Wait for final byte to transfer, ie wait for ACK to go false.
*
- * We should use the Last Byte Sent bit, unfortunately this is
+ * We should use the Last Byte Sent bit, unfortunately this is
* not available on the 5380/5381 (only the various CMOS chips)
*
* FIXME: timeout, and need to handle long timeout/irq case
@@ -2543,7 +2225,6 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) {
NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ);
- NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/*
@@ -2560,190 +2241,251 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) {
}
#endif /* def REAL_DMA */
-/*
- * Function : int NCR5380_abort (struct scsi_cmnd *cmd)
- *
- * Purpose : abort a command
- *
- * Inputs : cmd - the scsi_cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
- * used.
- *
- * Returns : SUCCESS - success, FAILED on failure.
- *
- * XXX - there is no way to abort the command that is currently
- * connected, you have to wait for it to complete. If this is
- * a problem, we could implement longjmp() / setjmp(), setjmp()
- * called where the loop started in NCR5380_main().
- *
- * Locks: host lock taken by caller
+/**
+ * list_find_cmd - test for presence of a command in a linked list
+ * @haystack: list of commands
+ * @needle: command to search for
*/
-static int NCR5380_abort(struct scsi_cmnd *cmd)
+static bool list_find_cmd(struct list_head *haystack,
+ struct scsi_cmnd *needle)
{
- NCR5380_local_declare();
- struct Scsi_Host *instance = cmd->device->host;
- struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- struct scsi_cmnd *tmp, **prev;
+ struct NCR5380_cmd *ncmd;
- scmd_printk(KERN_WARNING, cmd, "aborting command\n");
+ list_for_each_entry(ncmd, haystack, list)
+ if (NCR5380_to_scmd(ncmd) == needle)
+ return true;
+ return false;
+}
- NCR5380_print_status(instance);
+/**
+ * list_remove_cmd - remove a command from linked list
+ * @haystack: list of commands
+ * @needle: command to remove
+ */
- NCR5380_setup(instance);
+static bool list_del_cmd(struct list_head *haystack,
+ struct scsi_cmnd *needle)
+{
+ if (list_find_cmd(haystack, needle)) {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle);
- dprintk(NDEBUG_ABORT, "scsi%d : abort called\n", instance->host_no);
- dprintk(NDEBUG_ABORT, " basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG));
+ list_del(&ncmd->list);
+ return true;
+ }
+ return false;
+}
-#if 0
-/*
- * Case 1 : If the command is the currently executing command,
- * we'll set the aborted flag and return control so that
- * information transfer routine can exit cleanly.
+/**
+ * NCR5380_abort - scsi host eh_abort_handler() method
+ * @cmd: the command to be aborted
+ *
+ * Try to abort a given command by removing it from queues and/or sending
+ * the target an abort message. This may not succeed in causing a target
+ * to abort the command. Nonetheless, the low-level driver must forget about
+ * the command because the mid-layer reclaims it and it may be re-issued.
+ *
+ * The normal path taken by a command is as follows. For EH we trace this
+ * same path to locate and abort the command.
+ *
+ * unissued -> selecting -> [unissued -> selecting ->]... connected ->
+ * [disconnected -> connected ->]...
+ * [autosense -> connected ->] done
+ *
+ * If cmd is unissued then just remove it.
+ * If cmd is disconnected, try to select the target.
+ * If cmd is connected, try to send an abort message.
+ * If cmd is waiting for autosense, give it a chance to complete but check
+ * that it isn't left connected.
+ * If cmd was not found at all then presumably it has already been completed,
+ * in which case return SUCCESS to try to avoid further EH measures.
+ * If the command has not completed yet, we must not fail to find it.
*/
- if (hostdata->connected == cmd) {
- dprintk(NDEBUG_ABORT, "scsi%d : aborting connected command\n", instance->host_no);
- hostdata->aborted = 1;
-/*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
+static int NCR5380_abort(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long flags;
+ int result = SUCCESS;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN);
-/*
- * Since we can't change phases until we've completed the current
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
+ spin_lock_irqsave(&hostdata->lock, flags);
-/*
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */
+#if (NDEBUG & NDEBUG_ANY)
+ scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
- return SUCCESS;
+ if (list_del_cmd(&hostdata->unissued, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from issue queue\n", cmd);
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
}
-#endif
-/*
- * Case 2 : If the command hasn't been issued yet, we simply remove it
- * from the issue queue.
- */
-
- dprintk(NDEBUG_ABORT, "scsi%d : abort going into loop.\n", instance->host_no);
- for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue), tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, tmp->host_scribble);
- (*prev) = (struct scsi_cmnd *) tmp->host_scribble;
- tmp->host_scribble = NULL;
- tmp->result = DID_ABORT << 16;
- dprintk(NDEBUG_ABORT, "scsi%d : abort removed command from issue queue.\n", instance->host_no);
- tmp->scsi_done(tmp);
- return SUCCESS;
+ if (hostdata->selecting == cmd) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: cmd %p == selecting\n", cmd);
+ hostdata->selecting = NULL;
+ cmd->result = DID_ABORT << 16;
+ complete_cmd(instance, cmd);
+ goto out;
+ }
+
+ if (list_del_cmd(&hostdata->disconnected, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from disconnected list\n", cmd);
+ cmd->result = DID_ERROR << 16;
+ if (!hostdata->connected)
+ NCR5380_select(instance, cmd);
+ if (hostdata->connected != cmd) {
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
+ }
+ }
+
+ if (hostdata->connected == cmd) {
+ dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+ hostdata->connected = NULL;
+ if (do_abort(instance)) {
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
}
-#if (NDEBUG & NDEBUG_ABORT)
- /* KLL */
- else if (prev == tmp)
- printk(KERN_ERR "scsi%d : LOOP\n", instance->host_no);
+ set_host_byte(cmd, DID_ABORT);
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
#endif
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ complete_cmd(instance, cmd);
+ else {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
-/*
- * Case 3 : If any commands are connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail.
- */
+ /* Perform autosense for this command */
+ list_add(&ncmd->list, &hostdata->autosense);
+ }
+ }
- if (hostdata->connected) {
- dprintk(NDEBUG_ABORT, "scsi%d : abort failed, command connected.\n", instance->host_no);
- return FAILED;
+ if (list_find_cmd(&hostdata->autosense, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: found %p on sense queue\n", cmd);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ msleep(1000);
+ spin_lock_irqsave(&hostdata->lock, flags);
+ if (list_del_cmd(&hostdata->autosense, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from sense queue\n", cmd);
+ set_host_byte(cmd, DID_ABORT);
+ complete_cmd(instance, cmd);
+ goto out;
+ }
}
-/*
- * Case 4: If the command is currently disconnected from the bus, and
- * there are no connected commands, we reconnect the I_T_L or
- * I_T_L_Q nexus associated with it, go into message out, and send
- * an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select(). The easiest way to implement this
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that
- * device reselected.
- *
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; tmp = (struct scsi_cmnd *) tmp->host_scribble)
- if (cmd == tmp) {
- dprintk(NDEBUG_ABORT, "scsi%d : aborting disconnected command.\n", instance->host_no);
+ if (hostdata->connected == cmd) {
+ dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+ hostdata->connected = NULL;
+ if (do_abort(instance)) {
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
+ }
+ set_host_byte(cmd, DID_ABORT);
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+ complete_cmd(instance, cmd);
+ }
- if (NCR5380_select(instance, cmd))
- return FAILED;
- dprintk(NDEBUG_ABORT, "scsi%d : nexus reestablished.\n", instance->host_no);
+out:
+ if (result == FAILED)
+ dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
+ else
+ dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
- do_abort(instance);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
- for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue), tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, tmp->host_scribble);
- *prev = (struct scsi_cmnd *) tmp->host_scribble;
- tmp->host_scribble = NULL;
- tmp->result = DID_ABORT << 16;
- tmp->scsi_done(tmp);
- return SUCCESS;
- }
- }
-/*
- * Case 5 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
- printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n"
- " before abortion\n", instance->host_no);
- return FAILED;
+ return result;
}
-/*
- * Function : int NCR5380_bus_reset (struct scsi_cmnd *cmd)
- *
- * Purpose : reset the SCSI bus.
- *
- * Returns : SUCCESS
+/**
+ * NCR5380_bus_reset - reset the SCSI bus
+ * @cmd: SCSI command undergoing EH
*
- * Locks: host lock taken by caller
+ * Returns SUCCESS
*/
static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
{
struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int i;
+ unsigned long flags;
+ struct NCR5380_cmd *ncmd;
- NCR5380_local_declare();
- NCR5380_setup(instance);
- NCR5380_print_status(instance);
+ spin_lock_irqsave(&hostdata->lock, flags);
+
+#if (NDEBUG & NDEBUG_ANY)
+ scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
- spin_lock_irq(instance->host_lock);
do_reset(instance);
- spin_unlock_irq(instance->host_lock);
+
+ /* reset NCR registers */
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; so clear the low-level status here to avoid
+ * conflicts when the mid-level code tries to wake up the affected
+ * commands!
+ */
+
+ hostdata->selecting = NULL;
+
+ list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ set_host_byte(cmd, DID_RESET);
+ cmd->scsi_done(cmd);
+ }
+
+ list_for_each_entry(ncmd, &hostdata->autosense, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ set_host_byte(cmd, DID_RESET);
+ cmd->scsi_done(cmd);
+ }
+
+ if (hostdata->connected) {
+ set_host_byte(hostdata->connected, DID_RESET);
+ complete_cmd(instance, hostdata->connected);
+ hostdata->connected = NULL;
+ }
+
+ if (hostdata->sensing) {
+ set_host_byte(hostdata->connected, DID_RESET);
+ complete_cmd(instance, hostdata->sensing);
+ hostdata->sensing = NULL;
+ }
+
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
return SUCCESS;
}
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index 162112dd1..a79288682 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -22,8 +22,13 @@
#ifndef NCR5380_H
#define NCR5380_H
+#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_transport_spi.h>
#define NDEBUG_ARBITRATION 0x1
#define NDEBUG_AUTOSENSE 0x2
@@ -158,8 +163,7 @@
/* Write any value to this register to start an ini mode DMA receive */
#define START_DMA_INITIATOR_RECEIVE_REG 7 /* wo */
-#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */
-
+/* NCR 53C400(A) Control Status Register bits: */
#define CSR_RESET 0x80 /* wo Resets 53c400 */
#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */
#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */
@@ -176,16 +180,6 @@
#define CSR_BASE CSR_53C80_INTR
#endif
-/* Number of 128-byte blocks to be transferred */
-#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */
-
-/* Resume transfer after disconnect */
-#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */
-
-/* Access to host buffer stack */
-#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */
-
-
/* Note : PHASE_* macros are based on the values of the STATUS register */
#define PHASE_MASK (SR_MSG | SR_CD | SR_IO)
@@ -205,16 +199,6 @@
#define PHASE_SR_TO_TCR(phase) ((phase) >> 2)
-/*
- * The internal should_disconnect() function returns these based on the
- * expected length of a disconnect if a device supports disconnect/
- * reconnect.
- */
-
-#define DISCONNECT_NONE 0
-#define DISCONNECT_TIME_TO_DATA 1
-#define DISCONNECT_LONG 2
-
/*
* "Special" value for the (unsigned char) command tag, to indicate
* I_T_L nexus instead of I_T_L_Q.
@@ -236,15 +220,11 @@
#define NO_IRQ 0
#endif
-#define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */
-#define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */
-#define FLAG_NCR53C400 4 /* NCR53c400 */
+#define FLAG_NO_DMA_FIXUP 1 /* No DMA errata workarounds */
#define FLAG_NO_PSEUDO_DMA 8 /* Inhibit DMA */
-#define FLAG_DTC3181E 16 /* DTC3181E */
#define FLAG_LATE_DMA_SETUP 32 /* Setup NCR before DMA H/W */
#define FLAG_TAGGED_QUEUING 64 /* as X3T9.2 spelled it */
-
-#ifndef ASM
+#define FLAG_TOSHIBA_DELAY 128 /* Allow for borken CD-ROMs */
#ifdef SUPPORT_TAGS
struct tag_alloc {
@@ -258,33 +238,24 @@ struct NCR5380_hostdata {
NCR5380_implementation_fields; /* implementation specific */
struct Scsi_Host *host; /* Host backpointer */
unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */
- unsigned char targets_present; /* targets we have connected
- to, so we can call a select
- failure a retryable condition */
- volatile unsigned char busy[8]; /* index = target, bit = lun */
+ unsigned char busy[8]; /* index = target, bit = lun */
#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
- volatile int dma_len; /* requested length of DMA */
+ int dma_len; /* requested length of DMA */
#endif
- volatile unsigned char last_message; /* last message OUT */
- volatile struct scsi_cmnd *connected; /* currently connected command */
- volatile struct scsi_cmnd *issue_queue; /* waiting to be issued */
- volatile struct scsi_cmnd *disconnected_queue; /* waiting for reconnect */
- volatile int restart_select; /* we have disconnected,
- used to restart
- NCR5380_select() */
- volatile unsigned aborted:1; /* flag, says aborted */
+ unsigned char last_message; /* last message OUT */
+ struct scsi_cmnd *connected; /* currently connected cmnd */
+ struct scsi_cmnd *selecting; /* cmnd to be connected */
+ struct list_head unissued; /* waiting to be issued */
+ struct list_head autosense; /* priority issue queue */
+ struct list_head disconnected; /* waiting for reconnect */
+ spinlock_t lock; /* protects this struct */
int flags;
- unsigned long time_expires; /* in jiffies, set prior to sleeping */
- int select_time; /* timer in select for target response */
- volatile struct scsi_cmnd *selecting;
- struct delayed_work coroutine; /* our co-routine */
struct scsi_eh_save ses;
+ struct scsi_cmnd *sensing;
char info[256];
int read_overruns; /* number of bytes to cut from a
* transfer to handle chip overruns */
- int retain_dma_intr;
struct work_struct main_task;
- volatile int main_running;
#ifdef SUPPORT_TAGS
struct tag_alloc TagAlloc[8][8]; /* 8 targets and 8 LUNs */
#endif
@@ -292,10 +263,23 @@ struct NCR5380_hostdata {
unsigned spin_max_r;
unsigned spin_max_w;
#endif
+ struct workqueue_struct *work_q;
+ unsigned long accesses_per_ms; /* chip register accesses per ms */
};
#ifdef __KERNEL__
+struct NCR5380_cmd {
+ struct list_head list;
+};
+
+#define NCR5380_CMD_SIZE (sizeof(struct NCR5380_cmd))
+
+static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr)
+{
+ return ((struct scsi_cmnd *)ncmd_ptr) - 1;
+}
+
#ifndef NDEBUG
#define NDEBUG (0)
#endif
@@ -304,6 +288,11 @@ struct NCR5380_hostdata {
do { if ((NDEBUG) & (flg)) \
printk(KERN_DEBUG fmt, ## __VA_ARGS__); } while (0)
+#define dsprintk(flg, host, fmt, ...) \
+ do { if ((NDEBUG) & (flg)) \
+ shost_printk(KERN_DEBUG, host, fmt, ## __VA_ARGS__); \
+ } while (0)
+
#if NDEBUG
#define NCR5380_dprint(flg, arg) \
do { if ((NDEBUG) & (flg)) NCR5380_print(arg); } while (0)
@@ -320,6 +309,7 @@ static void NCR5380_print(struct Scsi_Host *instance);
static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible);
#endif
static int NCR5380_init(struct Scsi_Host *instance, int flags);
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *);
static void NCR5380_exit(struct Scsi_Host *instance);
static void NCR5380_information_transfer(struct Scsi_Host *instance);
#ifndef DONT_USE_INTR
@@ -328,7 +318,7 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id);
static void NCR5380_main(struct work_struct *work);
static const char *NCR5380_info(struct Scsi_Host *instance);
static void NCR5380_reselect(struct Scsi_Host *instance);
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd);
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *, struct scsi_cmnd *);
#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
#endif
@@ -443,5 +433,4 @@ static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance)
#endif /* defined(i386) || defined(__alpha__) */
#endif /* defined(REAL_DMA) */
#endif /* __KERNEL__ */
-#endif /* ndef ASM */
#endif /* NCR5380_H */
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 3b6e5c67e..76eaa38ff 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1318,7 +1318,7 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
#if (defined(CONFIG_PM))
-void aac_release_resources(struct aac_dev *aac)
+static void aac_release_resources(struct aac_dev *aac)
{
int i;
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index df2e0e536..d47b527b2 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -624,7 +624,7 @@ struct scb {
};
TAILQ_HEAD(scb_tailq, scb);
-LIST_HEAD(scb_list, scb);
+BSD_LIST_HEAD(scb_list, scb);
struct scb_data {
/*
@@ -1069,7 +1069,7 @@ struct ahd_softc {
/*
* SCBs that have been sent to the controller
*/
- LIST_HEAD(, scb) pending_scbs;
+ BSD_LIST_HEAD(, scb) pending_scbs;
/*
* Current register window mode information.
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index c58fa33c6..728193a42 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -65,11 +65,6 @@
/* Core SCSI definitions */
#define AIC_LIB_PREFIX ahd
-/* Name space conflict with BSD queue macros */
-#ifdef LIST_HEAD
-#undef LIST_HEAD
-#endif
-
#include "cam.h"
#include "queue.h"
#include "scsi_message.h"
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index f69577464..4ce4e903a 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -916,7 +916,7 @@ struct ahc_softc {
/*
* SCBs that have been sent to the controller
*/
- LIST_HEAD(, scb) pending_scbs;
+ BSD_LIST_HEAD(, scb) pending_scbs;
/*
* Counting lock for deferring the release of additional
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index bc4cca92f..54c702864 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -82,11 +82,6 @@
/* Core SCSI definitions */
#define AIC_LIB_PREFIX ahc
-/* Name space conflict with BSD queue macros */
-#ifdef LIST_HEAD
-#undef LIST_HEAD
-#endif
-
#include "cam.h"
#include "queue.h"
#include "scsi_message.h"
diff --git a/drivers/scsi/aic7xxx/queue.h b/drivers/scsi/aic7xxx/queue.h
index 8adf8003a..ba602981f 100644
--- a/drivers/scsi/aic7xxx/queue.h
+++ b/drivers/scsi/aic7xxx/queue.h
@@ -246,7 +246,7 @@ struct { \
/*
* List declarations.
*/
-#define LIST_HEAD(name, type) \
+#define BSD_LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
index 912e6b755..101072cab 100644
--- a/drivers/scsi/aic94xx/aic94xx_sas.h
+++ b/drivers/scsi/aic94xx/aic94xx_sas.h
@@ -327,46 +327,9 @@ struct scb_header {
#define LUN_SIZE 8
-/* See SAS spec, task IU
- */
-struct ssp_task_iu {
- u8 lun[LUN_SIZE]; /* BE */
- u16 _r_a;
- u8 tmf;
- u8 _r_b;
- __be16 tag; /* BE */
- u8 _r_c[14];
-} __attribute__ ((packed));
-
-/* See SAS spec, command IU
- */
-struct ssp_command_iu {
- u8 lun[LUN_SIZE];
- u8 _r_a;
- u8 efb_prio_attr; /* enable first burst, task prio & attr */
-#define EFB_MASK 0x80
-#define TASK_PRIO_MASK 0x78
-#define TASK_ATTR_MASK 0x07
-
- u8 _r_b;
- u8 add_cdb_len; /* in dwords, since bit 0,1 are reserved */
- union {
- u8 cdb[16];
- struct {
- __le64 long_cdb_addr; /* bus address, LE */
- __le32 long_cdb_size; /* LE */
- u8 _r_c[3];
- u8 eol_ds; /* eol:6,6, ds:5,4 */
- } long_cdb; /* sequencer extension */
- };
-} __attribute__ ((packed));
-
-struct xfer_rdy_iu {
- __be32 requested_offset; /* BE */
- __be32 write_data_len; /* BE */
- __be32 _r_a;
-} __attribute__ ((packed));
-
+#define EFB_MASK 0x80
+#define TASK_PRIO_MASK 0x78
+#define TASK_ATTR_MASK 0x07
/* ---------- SCB tasks ---------- */
/* This is both ssp_task and long_ssp_task
@@ -511,7 +474,7 @@ struct abort_task {
u8 proto_conn_rate;
__le32 _r_a;
struct ssp_frame_hdr ssp_frame;
- struct ssp_task_iu ssp_task;
+ struct ssp_tmf_iu ssp_task;
__le16 sister_scb;
__le16 conn_handle;
u8 flags; /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */
@@ -549,7 +512,7 @@ struct clear_nexus {
u8 _r_b[3];
u8 conn_mask;
u8 _r_c[19];
- struct ssp_task_iu ssp_task; /* LUN and TAG */
+ struct ssp_tmf_iu ssp_task; /* LUN and TAG */
__le16 _r_d;
__le16 conn_handle;
__le64 _r_e;
@@ -562,7 +525,7 @@ struct initiate_ssp_tmf {
u8 proto_conn_rate;
__le32 _r_a;
struct ssp_frame_hdr ssp_frame;
- struct ssp_task_iu ssp_task;
+ struct ssp_tmf_iu ssp_task;
__le16 sister_scb;
__le16 conn_handle;
u8 flags; /* itnl override and suspend data tx */
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index 3bcaaac0a..cf99f8cf4 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -52,7 +52,7 @@ struct device_attribute;
#define ARCMSR_MAX_FREECCB_NUM 320
#define ARCMSR_MAX_OUTSTANDING_CMD 255
#endif
-#define ARCMSR_DRIVER_VERSION "v1.30.00.04-20140919"
+#define ARCMSR_DRIVER_VERSION "v1.30.00.22-20151126"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
@@ -74,6 +74,9 @@ struct device_attribute;
#ifndef PCI_DEVICE_ID_ARECA_1214
#define PCI_DEVICE_ID_ARECA_1214 0x1214
#endif
+#ifndef PCI_DEVICE_ID_ARECA_1203
+ #define PCI_DEVICE_ID_ARECA_1203 0x1203
+#endif
/*
**********************************************************************************
**
@@ -245,6 +248,12 @@ struct FIRMWARE_INFO
/* window of "instruction flags" from iop to driver */
#define ARCMSR_IOP2DRV_DOORBELL 0x00020408
#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL_1203 0x00021870
+#define ARCMSR_IOP2DRV_DOORBELL_MASK_1203 0x00021874
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL_1203 0x00021878
+#define ARCMSR_DRV2IOP_DOORBELL_MASK_1203 0x0002187C
/* ARECA FLAG LANGUAGE */
/* ioctl transfer */
#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001
@@ -288,6 +297,9 @@ struct FIRMWARE_INFO
#define ARCMSR_MESSAGE_RBUFFER 0x0000ff00
/* iop message_rwbuffer for message command */
#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00
+
+#define MEM_BASE0(x) (u32 __iomem *)((unsigned long)acb->mem_base0 + x)
+#define MEM_BASE1(x) (u32 __iomem *)((unsigned long)acb->mem_base1 + x)
/*
************************************************************************
** SPEC. for Areca HBC adapter
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 333db5953..764049896 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -114,6 +114,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *);
+static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
{
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
@@ -157,6 +158,8 @@ static struct pci_device_id arcmsr_device_id_table[] = {
.driver_data = ACB_ADAPTER_TYPE_B},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202),
.driver_data = ACB_ADAPTER_TYPE_B},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1203),
+ .driver_data = ACB_ADAPTER_TYPE_B},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210),
.driver_data = ACB_ADAPTER_TYPE_A},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214),
@@ -495,6 +498,91 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
}
}
+static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb)
+{
+ bool rtn = true;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle;
+ struct pci_dev *pdev = acb->pdev;
+
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg;
+ acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
+ dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent) {
+ pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+ return false;
+ }
+ acb->dma_coherent_handle2 = dma_coherent_handle;
+ acb->dma_coherent2 = dma_coherent;
+ reg = (struct MessageUnit_B *)dma_coherent;
+ acb->pmuB = reg;
+ if (acb->pdev->device == PCI_DEVICE_ID_ARECA_1203) {
+ reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_1203);
+ reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK_1203);
+ reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_1203);
+ reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK_1203);
+ } else {
+ reg->drv2iop_doorbell = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL);
+ reg->drv2iop_doorbell_mask = MEM_BASE0(ARCMSR_DRV2IOP_DOORBELL_MASK);
+ reg->iop2drv_doorbell = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL);
+ reg->iop2drv_doorbell_mask = MEM_BASE0(ARCMSR_IOP2DRV_DOORBELL_MASK);
+ }
+ reg->message_wbuffer = MEM_BASE1(ARCMSR_MESSAGE_WBUFFER);
+ reg->message_rbuffer = MEM_BASE1(ARCMSR_MESSAGE_RBUFFER);
+ reg->message_rwbuffer = MEM_BASE1(ARCMSR_MESSAGE_RWBUFFER);
+ }
+ break;
+ case ACB_ADAPTER_TYPE_D: {
+ struct MessageUnit_D *reg;
+
+ acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
+ dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent) {
+ pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
+ return false;
+ }
+ acb->dma_coherent_handle2 = dma_coherent_handle;
+ acb->dma_coherent2 = dma_coherent;
+ reg = (struct MessageUnit_D *)dma_coherent;
+ acb->pmuD = reg;
+ reg->chip_id = MEM_BASE0(ARCMSR_ARC1214_CHIP_ID);
+ reg->cpu_mem_config = MEM_BASE0(ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION);
+ reg->i2o_host_interrupt_mask = MEM_BASE0(ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK);
+ reg->sample_at_reset = MEM_BASE0(ARCMSR_ARC1214_SAMPLE_RESET);
+ reg->reset_request = MEM_BASE0(ARCMSR_ARC1214_RESET_REQUEST);
+ reg->host_int_status = MEM_BASE0(ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS);
+ reg->pcief0_int_enable = MEM_BASE0(ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE);
+ reg->inbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE0);
+ reg->inbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_INBOUND_MESSAGE1);
+ reg->outbound_msgaddr0 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE0);
+ reg->outbound_msgaddr1 = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_MESSAGE1);
+ reg->inbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_INBOUND_DOORBELL);
+ reg->outbound_doorbell = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL);
+ reg->outbound_doorbell_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE);
+ reg->inboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW);
+ reg->inboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH);
+ reg->inboundlist_write_pointer = MEM_BASE0(ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER);
+ reg->outboundlist_base_low = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW);
+ reg->outboundlist_base_high = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH);
+ reg->outboundlist_copy_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER);
+ reg->outboundlist_read_pointer = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER);
+ reg->outboundlist_interrupt_cause = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE);
+ reg->outboundlist_interrupt_enable = MEM_BASE0(ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE);
+ reg->message_wbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_WBUFFER);
+ reg->message_rbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RBUFFER);
+ reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER);
+ }
+ break;
+ default:
+ break;
+ }
+ return rtn;
+}
+
static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
@@ -739,9 +827,12 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if(!error){
goto pci_release_regs;
}
+ error = arcmsr_alloc_io_queue(acb);
+ if (!error)
+ goto unmap_pci_region;
error = arcmsr_get_firmware_spec(acb);
if(!error){
- goto unmap_pci_region;
+ goto free_hbb_mu;
}
error = arcmsr_alloc_ccb_pool(acb);
if(error){
@@ -2622,9 +2713,6 @@ static bool arcmsr_hbaA_get_config(struct AdapterControlBlock *acb)
static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
- struct pci_dev *pdev = acb->pdev;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle;
char *acb_firm_model = acb->firm_model;
char *acb_firm_version = acb->firm_version;
char *acb_device_map = acb->device_map;
@@ -2636,30 +2724,16 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
/*firm_version,21,84-99*/
int count;
- acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32);
- dma_coherent = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
- &dma_coherent_handle, GFP_KERNEL);
- if (!dma_coherent){
- printk(KERN_NOTICE
- "arcmsr%d: dma_alloc_coherent got error for hbb mu\n",
- acb->host->host_no);
- return false;
- }
- acb->dma_coherent_handle2 = dma_coherent_handle;
- acb->dma_coherent2 = dma_coherent;
- reg = (struct MessageUnit_B *)dma_coherent;
- acb->pmuB = reg;
- reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
- reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
- reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
- reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
- reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
- reg->message_rbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
- reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]); /*firm_model,15,60-67*/
iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]); /*firm_version,17,68-83*/
iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]); /*firm_version,21,84-99*/
+ arcmsr_wait_firmware_ready(acb);
+ writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
+ if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+ printk(KERN_ERR "arcmsr%d: can't set driver mode.\n", acb->host->host_no);
+ return false;
+ }
writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
@@ -2694,15 +2768,15 @@ static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
acb->firm_model,
acb->firm_version);
- acb->signature = readl(&reg->message_rwbuffer[1]);
+ acb->signature = readl(&reg->message_rwbuffer[0]);
/*firm_signature,1,00-03*/
- acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
+ acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
/*firm_request_len,1,04-07*/
- acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
+ acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
/*firm_numbers_queue,2,08-11*/
- acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
+ acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
/*firm_sdram_size,3,12-15*/
- acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
+ acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
/*firm_ide_channels,4,16-19*/
acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
/*firm_ide_channels,4,16-19*/
@@ -2777,70 +2851,8 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
char __iomem *iop_firm_version;
char __iomem *iop_device_map;
u32 count;
- struct MessageUnit_D *reg;
- void *dma_coherent2;
- dma_addr_t dma_coherent_handle2;
- struct pci_dev *pdev = acb->pdev;
+ struct MessageUnit_D *reg = acb->pmuD;
- acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
- dma_coherent2 = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
- &dma_coherent_handle2, GFP_KERNEL);
- if (!dma_coherent2) {
- pr_notice("DMA allocation failed...\n");
- return false;
- }
- memset(dma_coherent2, 0, acb->roundup_ccbsize);
- acb->dma_coherent_handle2 = dma_coherent_handle2;
- acb->dma_coherent2 = dma_coherent2;
- reg = (struct MessageUnit_D *)dma_coherent2;
- acb->pmuD = reg;
- reg->chip_id = acb->mem_base0 + ARCMSR_ARC1214_CHIP_ID;
- reg->cpu_mem_config = acb->mem_base0 +
- ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION;
- reg->i2o_host_interrupt_mask = acb->mem_base0 +
- ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK;
- reg->sample_at_reset = acb->mem_base0 + ARCMSR_ARC1214_SAMPLE_RESET;
- reg->reset_request = acb->mem_base0 + ARCMSR_ARC1214_RESET_REQUEST;
- reg->host_int_status = acb->mem_base0 +
- ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS;
- reg->pcief0_int_enable = acb->mem_base0 +
- ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE;
- reg->inbound_msgaddr0 = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_MESSAGE0;
- reg->inbound_msgaddr1 = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_MESSAGE1;
- reg->outbound_msgaddr0 = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_MESSAGE0;
- reg->outbound_msgaddr1 = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_MESSAGE1;
- reg->inbound_doorbell = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_DOORBELL;
- reg->outbound_doorbell = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_DOORBELL;
- reg->outbound_doorbell_enable = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE;
- reg->inboundlist_base_low = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW;
- reg->inboundlist_base_high = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH;
- reg->inboundlist_write_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER;
- reg->outboundlist_base_low = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW;
- reg->outboundlist_base_high = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH;
- reg->outboundlist_copy_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER;
- reg->outboundlist_read_pointer = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER;
- reg->outboundlist_interrupt_cause = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE;
- reg->outboundlist_interrupt_enable = acb->mem_base0 +
- ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE;
- reg->message_wbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_WBUFFER;
- reg->message_rbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RBUFFER;
- reg->msgcode_rwbuffer = acb->mem_base0 +
- ARCMSR_ARC1214_MESSAGE_RWBUFFER;
iop_firm_model = (char __iomem *)(&reg->msgcode_rwbuffer[15]);
iop_firm_version = (char __iomem *)(&reg->msgcode_rwbuffer[17]);
iop_device_map = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
@@ -2855,8 +2867,6 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
pr_notice("arcmsr%d: wait get adapter firmware "
"miscellaneous data timeout\n", acb->host->host_no);
- dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
- acb->dma_coherent2, acb->dma_coherent_handle2);
return false;
}
count = 8;
@@ -2880,15 +2890,15 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
iop_device_map++;
count--;
}
- acb->signature = readl(&reg->msgcode_rwbuffer[1]);
+ acb->signature = readl(&reg->msgcode_rwbuffer[0]);
/*firm_signature,1,00-03*/
- acb->firm_request_len = readl(&reg->msgcode_rwbuffer[2]);
+ acb->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);
/*firm_request_len,1,04-07*/
- acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[3]);
+ acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]);
/*firm_numbers_queue,2,08-11*/
- acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[4]);
+ acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);
/*firm_sdram_size,3,12-15*/
- acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[5]);
+ acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);
/*firm_hd_channels,4,16-19*/
acb->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
@@ -3998,6 +4008,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
case PCI_DEVICE_ID_ARECA_1160:
case PCI_DEVICE_ID_ARECA_1170:
case PCI_DEVICE_ID_ARECA_1201:
+ case PCI_DEVICE_ID_ARECA_1203:
case PCI_DEVICE_ID_ARECA_1220:
case PCI_DEVICE_ID_ARECA_1230:
case PCI_DEVICE_ID_ARECA_1260:
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index d28d6c0f1..221f18c5d 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -4,9 +4,7 @@
* Copyright 1995-2002, Russell King
*/
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/ioport.h>
-#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/init.h>
@@ -15,15 +13,14 @@
#include <scsi/scsi_host.h>
-#include <scsi/scsicam.h>
-
#define PSEUDO_DMA
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
-#define NCR5380_local_declare() struct Scsi_Host *_instance
-#define NCR5380_setup(instance) _instance = instance
-#define NCR5380_read(reg) cumanascsi_read(_instance, reg)
-#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
+#define NCR5380_read(reg) cumanascsi_read(instance, reg)
+#define NCR5380_write(reg, value) cumanascsi_write(instance, reg, value)
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
+
#define NCR5380_intr cumanascsi_intr
#define NCR5380_queue_command cumanascsi_queue_command
#define NCR5380_info cumanascsi_info
@@ -211,6 +208,8 @@ static struct scsi_host_template cumanascsi_template = {
.cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING,
.proc_name = "CumanaSCSI-1",
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
static int cumanascsi1_probe(struct expansion_card *ec,
@@ -240,23 +239,21 @@ static int cumanascsi1_probe(struct expansion_card *ec,
host->irq = ec->irq;
- NCR5380_init(host, 0);
+ ret = NCR5380_init(host, 0);
+ if (ret)
+ goto out_unmap;
+
+ NCR5380_maybe_reset_bus(host);
priv(host)->ctrl = 0;
writeb(0, priv(host)->base + CTRL);
- host->n_io_port = 255;
- if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
- ret = -EBUSY;
- goto out_unmap;
- }
-
ret = request_irq(host->irq, cumanascsi_intr, 0,
"CumanaSCSI-1", host);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, host->irq, ret);
- goto out_unmap;
+ goto out_exit;
}
ret = scsi_add_host(host, &ec->dev);
@@ -268,6 +265,8 @@ static int cumanascsi1_probe(struct expansion_card *ec,
out_free_irq:
free_irq(host->irq, host);
+ out_exit:
+ NCR5380_exit(host);
out_unmap:
iounmap(priv(host)->base);
iounmap(priv(host)->dma);
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index 7c6fa1479..1fab1d189 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -5,9 +5,7 @@
*/
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/ioport.h>
-#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/init.h>
@@ -20,14 +18,16 @@
#define DONT_USE_INTR
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
-#define NCR5380_local_declare() void __iomem *_base
-#define NCR5380_setup(host) _base = priv(host)->base
-#define NCR5380_read(reg) readb(_base + ((reg) << 2))
-#define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2))
+#define NCR5380_read(reg) \
+ readb(priv(instance)->base + ((reg) << 2))
+#define NCR5380_write(reg, value) \
+ writeb(value, priv(instance)->base + ((reg) << 2))
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
+
#define NCR5380_queue_command oakscsi_queue_command
#define NCR5380_info oakscsi_info
-#define NCR5380_show_info oakscsi_show_info
#define NCR5380_implementation_fields \
void __iomem *base
@@ -103,7 +103,6 @@ printk("reading %p len %d\n", addr, len);
static struct scsi_host_template oakscsi_template = {
.module = THIS_MODULE,
- .show_info = oakscsi_show_info,
.name = "Oak 16-bit SCSI",
.info = oakscsi_info,
.queuecommand = oakscsi_queue_command,
@@ -115,6 +114,8 @@ static struct scsi_host_template oakscsi_template = {
.cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING,
.proc_name = "oakscsi",
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
@@ -142,15 +143,21 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
host->irq = NO_IRQ;
host->n_io_port = 255;
- NCR5380_init(host, 0);
+ ret = NCR5380_init(host, 0);
+ if (ret)
+ goto out_unmap;
+
+ NCR5380_maybe_reset_bus(host);
ret = scsi_add_host(host, &ec->dev);
if (ret)
- goto out_unmap;
+ goto out_exit;
scsi_scan_host(host);
goto out;
+ out_exit:
+ NCR5380_exit(host);
out_unmap:
iounmap(priv(host)->base);
unreg:
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index db87ece6e..e65478651 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -1,15 +1,15 @@
/*
* NCR 5380 generic driver routines. These should make it *trivial*
- * to implement 5380 SCSI drivers under Linux with a non-trantor
- * architecture.
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
*
- * Note that these routines also work with NR53c400 family chips.
+ * Note that these routines also work with NR53c400 family chips.
*
* Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 666-5836
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
*
* For more information, please consult
*
@@ -24,84 +24,10 @@
* 1+ (800) 334-5454
*/
-/*
- * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
- * this file, too:
- *
- * - Some of the debug statements were incorrect (undefined variables and the
- * like). I fixed that.
- *
- * - In information_transfer(), I think a #ifdef was wrong. Looking at the
- * possible DMA transfer size should also happen for REAL_DMA. I added this
- * in the #if statement.
- *
- * - When using real DMA, information_transfer() should return in a DATAOUT
- * phase after starting the DMA. It has nothing more to do.
- *
- * - The interrupt service routine should run main after end of DMA, too (not
- * only after RESELECTION interrupts). Additionally, it should _not_ test
- * for more interrupts after running main, since a DMA process may have
- * been started and interrupts are turned on now. The new int could happen
- * inside the execution of NCR5380_intr(), leading to recursive
- * calls.
- *
- * - I've added a function merge_contiguous_buffers() that tries to
- * merge scatter-gather buffers that are located at contiguous
- * physical addresses and can be processed with the same DMA setup.
- * Since most scatter-gather operations work on a page (4K) of
- * 4 buffers (1K), in more than 90% of all cases three interrupts and
- * DMA setup actions are saved.
- *
- * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
- * and USLEEP, because these were messing up readability and will never be
- * needed for Atari SCSI.
- *
- * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
- * stuff), and 'main' is executed in a bottom half if awoken by an
- * interrupt.
- *
- * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
- * constructs. In my eyes, this made the source rather unreadable, so I
- * finally replaced that by the *_PRINTK() macros.
- *
- */
-
-/*
- * Further development / testing that should be done :
- * 1. Test linked command handling code after Eric is ready with
- * the high level code.
- */
+/* Ported to Atari by Roman Hodek and others. */
/* Adapted for the sun3 by Sam Creasey. */
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_transport_spi.h>
-
-#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x, y) \
- do { \
- printk("LINE:%d Adding %p to %p\n", \
- __LINE__, (void*)(x), (void*)(y)); \
- if ((x) == (y)) \
- udelay(5); \
- } while (0)
-#define REMOVE(w, x, y, z) \
- do { \
- printk("LINE:%d Removing: %p->%p %p->%p \n", \
- __LINE__, (void*)(w), (void*)(x), \
- (void*)(y), (void*)(z)); \
- if ((x) == (y)) \
- udelay(5); \
- } while (0)
-#else
-#define LIST(x,y)
-#define REMOVE(w,x,y,z)
-#endif
-
-#ifndef notyet
-#undef LINKED
-#endif
-
/*
* Design
*
@@ -126,17 +52,7 @@
* piece of hardware that requires you to sit in a loop polling for
* the REQ signal as long as you are connected. Some devices are
* brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
- * while doing long seek operations.
- *
- * The workaround for this is to keep track of devices that have
- * disconnected. If the device hasn't disconnected, for commands that
- * should disconnect, we do something like
- *
- * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- *
- * Some tweaking of N and M needs to be done. An algorithm based
- * on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these
+ * while doing long seek operations. [...] These
* broken devices are the exception rather than the rule and I'd rather
* spend my time optimizing for the normal case.
*
@@ -177,12 +93,10 @@
*
* These macros control options :
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
+ * for commands that return with a CHECK CONDITION status.
*
* DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
- * transceivers.
- *
- * LINKED - if defined, linked commands are supported.
+ * transceivers.
*
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
*
@@ -195,17 +109,17 @@
* NCR5380_write(register, value) - write to the specific register
*
* NCR5380_implementation_fields - additional fields needed for this
- * specific implementation of the NCR5380
+ * specific implementation of the NCR5380
*
* Either real DMA *or* pseudo DMA may be implemented
* REAL functions :
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
* Note that the DMA setup functions should return the number of bytes
- * that they were able to program the controller for.
+ * that they were able to program the controller for.
*
* Also note that generic i386/PC versions of these macros are
- * available as NCR5380_i386_dma_write_setup,
- * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
*
* NCR5380_dma_write_setup(instance, src, count) - initialize
* NCR5380_dma_read_setup(instance, dst, count) - initialize
@@ -221,18 +135,8 @@
* possible) function may be used.
*/
-/* Macros ease life... :-) */
-#define SETUP_HOSTDATA(in) \
- struct NCR5380_hostdata *hostdata = \
- (struct NCR5380_hostdata *)(in)->hostdata
-#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-
-#define NEXT(cmd) ((struct scsi_cmnd *)(cmd)->host_scribble)
-#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next))
-#define NEXTADDR(cmd) ((struct scsi_cmnd **)&(cmd)->host_scribble)
-
-#define HOSTNO instance->host_no
-#define H_NO(cmd) (cmd)->device->host->host_no
+static int do_abort(struct Scsi_Host *);
+static void do_reset(struct Scsi_Host *);
#ifdef SUPPORT_TAGS
@@ -251,9 +155,7 @@
* cannot know it in advance :-( We just see a QUEUE_FULL status being
* returned. So, in this case, the driver internal queue size assumption is
* reduced to the number of active tags if QUEUE_FULL is returned by the
- * target. The command is returned to the mid-level, but with status changed
- * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
- * correctly.
+ * target.
*
* We're also not allowed running tagged commands as long as an untagged
* command is active. And REQUEST SENSE commands after a contingent allegiance
@@ -304,7 +206,8 @@ static void __init init_tags(struct NCR5380_hostdata *hostdata)
static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
{
u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
if (hostdata->busy[cmd->device->id] & (1 << lun))
return 1;
@@ -314,8 +217,8 @@ static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
return 0;
if (hostdata->TagAlloc[scmd_id(cmd)][lun].nr_allocated >=
hostdata->TagAlloc[scmd_id(cmd)][lun].queue_size) {
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d: no free tags\n",
- H_NO(cmd), cmd->device->id, lun);
+ dsprintk(NDEBUG_TAGS, instance, "target %d lun %d: no free tags\n",
+ scmd_id(cmd), lun);
return 1;
}
return 0;
@@ -330,7 +233,8 @@ static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
{
u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
/* If we or the target don't support tagged queuing, allocate the LUN for
* an untagged command.
@@ -340,18 +244,16 @@ static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
!cmd->device->tagged_supported) {
cmd->tag = TAG_NONE;
hostdata->busy[cmd->device->id] |= (1 << lun);
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d now allocated by untagged "
- "command\n", H_NO(cmd), cmd->device->id, lun);
+ dsprintk(NDEBUG_TAGS, instance, "target %d lun %d now allocated by untagged command\n",
+ scmd_id(cmd), lun);
} else {
struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
set_bit(cmd->tag, ta->allocated);
ta->nr_allocated++;
- dprintk(NDEBUG_TAGS, "scsi%d: using tag %d for target %d lun %d "
- "(now %d tags in use)\n",
- H_NO(cmd), cmd->tag, cmd->device->id,
- lun, ta->nr_allocated);
+ dsprintk(NDEBUG_TAGS, instance, "using tag %d for target %d lun %d (%d tags allocated)\n",
+ cmd->tag, scmd_id(cmd), lun, ta->nr_allocated);
}
}
@@ -363,21 +265,22 @@ static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
static void cmd_free_tag(struct scsi_cmnd *cmd)
{
u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
if (cmd->tag == TAG_NONE) {
hostdata->busy[cmd->device->id] &= ~(1 << lun);
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d untagged cmd finished\n",
- H_NO(cmd), cmd->device->id, lun);
+ dsprintk(NDEBUG_TAGS, instance, "target %d lun %d untagged cmd freed\n",
+ scmd_id(cmd), lun);
} else if (cmd->tag >= MAX_TAGS) {
- printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
- H_NO(cmd), cmd->tag);
+ shost_printk(KERN_NOTICE, instance,
+ "trying to free bad tag %d!\n", cmd->tag);
} else {
struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
clear_bit(cmd->tag, ta->allocated);
ta->nr_allocated--;
- dprintk(NDEBUG_TAGS, "scsi%d: freed tag %d for target %d lun %d\n",
- H_NO(cmd), cmd->tag, cmd->device->id, lun);
+ dsprintk(NDEBUG_TAGS, instance, "freed tag %d for target %d lun %d\n",
+ cmd->tag, scmd_id(cmd), lun);
}
}
@@ -401,17 +304,15 @@ static void free_all_tags(struct NCR5380_hostdata *hostdata)
#endif /* SUPPORT_TAGS */
-
-/*
- * Function: void merge_contiguous_buffers( struct scsi_cmnd *cmd )
- *
- * Purpose: Try to merge several scatter-gather requests into one DMA
- * transfer. This is possible if the scatter buffers lie on
- * physical contiguous addresses.
- *
- * Parameters: struct scsi_cmnd *cmd
- * The command to work on. The first scatter buffer's data are
- * assumed to be already transferred into ptr/this_residual.
+/**
+ * merge_contiguous_buffers - coalesce scatter-gather list entries
+ * @cmd: command requesting IO
+ *
+ * Try to merge several scatter-gather buffers into one DMA transfer.
+ * This is possible if the scatter buffers lie on physically
+ * contiguous addresses. The first scatter-gather buffer's data are
+ * assumed to be already transferred into cmd->SCp.this_residual.
+ * Every buffer merged avoids an interrupt and a DMA setup operation.
*/
static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
@@ -463,9 +364,7 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- /* ++roman: Try to merge some scatter-buffers if they are at
- * contiguous physical addresses.
- */
+
merge_contiguous_buffers(cmd);
} else {
cmd->SCp.buffer = NULL;
@@ -473,31 +372,110 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
cmd->SCp.ptr = NULL;
cmd->SCp.this_residual = 0;
}
+
+ cmd->SCp.Status = 0;
+ cmd->SCp.Message = 0;
+}
+
+/**
+ * NCR5380_poll_politely2 - wait for two chip register values
+ * @instance: controller to poll
+ * @reg1: 5380 register to poll
+ * @bit1: Bitmask to check
+ * @val1: Expected value
+ * @reg2: Second 5380 register to poll
+ * @bit2: Second bitmask to check
+ * @val2: Second expected value
+ * @wait: Time-out in jiffies
+ *
+ * Polls the chip in a reasonably efficient manner waiting for an
+ * event to occur. After a short quick poll we begin to yield the CPU
+ * (if possible). In irq contexts the time-out is arbitrarily limited.
+ * Callers may hold locks as long as they are held in irq mode.
+ *
+ * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT.
+ */
+
+static int NCR5380_poll_politely2(struct Scsi_Host *instance,
+ int reg1, int bit1, int val1,
+ int reg2, int bit2, int val2, int wait)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long deadline = jiffies + wait;
+ unsigned long n;
+
+ /* Busy-wait for up to 10 ms */
+ n = min(10000U, jiffies_to_usecs(wait));
+ n *= hostdata->accesses_per_ms;
+ n /= 2000;
+ do {
+ if ((NCR5380_read(reg1) & bit1) == val1)
+ return 0;
+ if ((NCR5380_read(reg2) & bit2) == val2)
+ return 0;
+ cpu_relax();
+ } while (n--);
+
+ if (irqs_disabled() || in_interrupt())
+ return -ETIMEDOUT;
+
+ /* Repeatedly sleep for 1 ms until deadline */
+ while (time_is_after_jiffies(deadline)) {
+ schedule_timeout_uninterruptible(1);
+ if ((NCR5380_read(reg1) & bit1) == val1)
+ return 0;
+ if ((NCR5380_read(reg2) & bit2) == val2)
+ return 0;
+ }
+
+ return -ETIMEDOUT;
}
-#include <linux/delay.h>
+static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
+ int reg, int bit, int val, int wait)
+{
+ return NCR5380_poll_politely2(instance, reg, bit, val,
+ reg, bit, val, wait);
+}
#if NDEBUG
static struct {
unsigned char mask;
const char *name;
} signals[] = {
- { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
- { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
- { SR_SEL, "SEL" }, {0, NULL}
-}, basrs[] = {
- {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}
-}, icrs[] = {
- {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
- {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
- {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {SR_DBP, "PARITY"},
+ {SR_RST, "RST"},
+ {SR_BSY, "BSY"},
+ {SR_REQ, "REQ"},
+ {SR_MSG, "MSG"},
+ {SR_CD, "CD"},
+ {SR_IO, "IO"},
+ {SR_SEL, "SEL"},
+ {0, NULL}
+},
+basrs[] = {
+ {BASR_ATN, "ATN"},
+ {BASR_ACK, "ACK"},
{0, NULL}
-}, mrs[] = {
- {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
- "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+},
+icrs[] = {
+ {ICR_ASSERT_RST, "ASSERT RST"},
+ {ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"},
+ {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"},
+ {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {0, NULL}
+},
+mrs[] = {
+ {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
+ {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
+ {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
+ {MR_ENABLE_EOP_INTR, "MODE EOP INTR"},
{MR_MONITOR_BSY, "MODE MONITOR BSY"},
- {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+ {MR_DMA_MODE, "MODE DMA"},
+ {MR_ARBITRATE, "MODE ARBITRATION"},
{0, NULL}
};
@@ -511,15 +489,13 @@ static struct {
static void NCR5380_print(struct Scsi_Host *instance)
{
unsigned char status, data, basr, mr, icr, i;
- unsigned long flags;
- local_irq_save(flags);
data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
mr = NCR5380_read(MODE_REG);
icr = NCR5380_read(INITIATOR_COMMAND_REG);
basr = NCR5380_read(BUS_AND_STATUS_REG);
- local_irq_restore(flags);
+
printk("STATUS_REG: %02x ", status);
for (i = 0; signals[i].mask; ++i)
if (status & signals[i].mask)
@@ -543,8 +519,12 @@ static struct {
unsigned char value;
const char *name;
} phases[] = {
- {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
- {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+ {PHASE_DATAOUT, "DATAOUT"},
+ {PHASE_DATAIN, "DATAIN"},
+ {PHASE_CMDOUT, "CMDOUT"},
+ {PHASE_STATIN, "STATIN"},
+ {PHASE_MSGOUT, "MSGOUT"},
+ {PHASE_MSGIN, "MSGIN"},
{PHASE_UNKNOWN, "UNKNOWN"}
};
@@ -553,8 +533,6 @@ static struct {
* @instance: adapter to dump
*
* Print the current SCSI phase for debugging purposes
- *
- * Locks: none
*/
static void NCR5380_print_phase(struct Scsi_Host *instance)
@@ -564,54 +542,21 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
status = NCR5380_read(STATUS_REG);
if (!(status & SR_REQ))
- printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+ shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n");
else {
for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
(phases[i].value != (status & PHASE_MASK)); ++i)
;
- printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+ shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name);
}
}
-
#endif
-/*
- * ++roman: New scheme of calling NCR5380_main()
- *
- * If we're not in an interrupt, we can call our main directly, it cannot be
- * already running. Else, we queue it on a task queue, if not 'main_running'
- * tells us that a lower level is already executing it. This way,
- * 'main_running' needs not be protected in a special way.
- *
- * queue_main() is a utility function for putting our main onto the task
- * queue, if main_running is false. It should be called only from a
- * interrupt or bottom half.
- */
-
-#include <linux/gfp.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-
-static inline void queue_main(struct NCR5380_hostdata *hostdata)
-{
- if (!hostdata->main_running) {
- /* If in interrupt and NCR5380_main() not already running,
- queue it on the 'immediate' task queue, to be processed
- immediately after the current interrupt processing has
- finished. */
- schedule_work(&hostdata->main_task);
- }
- /* else: nothing to do: the running NCR5380_main() will pick up
- any newly queued command. */
-}
-
/**
* NCR58380_info - report driver and host information
* @instance: relevant scsi host instance
*
* For use as the host template info() handler.
- *
- * Locks: none
*/
static const char *NCR5380_info(struct Scsi_Host *instance)
@@ -630,13 +575,14 @@ static void prepare_info(struct Scsi_Host *instance)
"base 0x%lx, irq %d, "
"can_queue %d, cmd_per_lun %d, "
"sg_tablesize %d, this_id %d, "
- "flags { %s}, "
+ "flags { %s%s}, "
"options { %s} ",
instance->hostt->name, instance->io_port, instance->n_io_port,
instance->base, instance->irq,
instance->can_queue, instance->cmd_per_lun,
instance->sg_tablesize, instance->this_id,
hostdata->flags & FLAG_TAGGED_QUEUING ? "TAGGED_QUEUING " : "",
+ hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "",
#ifdef DIFFERENTIAL
"DIFFERENTIAL "
#endif
@@ -653,102 +599,6 @@ static void prepare_info(struct Scsi_Host *instance)
}
/**
- * NCR5380_print_status - dump controller info
- * @instance: controller to dump
- *
- * Print commands in the various queues, called from NCR5380_abort
- * to aid debugging.
- */
-
-static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd)
-{
- int i, s;
- unsigned char *command;
- printk("scsi%d: destination target %d, lun %llu\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- printk(KERN_CONT " command = ");
- command = cmd->cmnd;
- printk(KERN_CONT "%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- printk(KERN_CONT " %02x", command[i]);
- printk("\n");
-}
-
-static void NCR5380_print_status(struct Scsi_Host *instance)
-{
- struct NCR5380_hostdata *hostdata;
- struct scsi_cmnd *ptr;
- unsigned long flags;
-
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_dprint_phase(NDEBUG_ANY, instance);
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- local_irq_save(flags);
- printk("NCR5380: coroutine is%s running.\n",
- hostdata->main_running ? "" : "n't");
- if (!hostdata->connected)
- printk("scsi%d: no currently connected command\n", HOSTNO);
- else
- lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected);
- printk("scsi%d: issue_queue\n", HOSTNO);
- for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
- lprint_Scsi_Cmnd(ptr);
-
- printk("scsi%d: disconnected_queue\n", HOSTNO);
- for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr))
- lprint_Scsi_Cmnd(ptr);
-
- local_irq_restore(flags);
- printk("\n");
-}
-
-static void show_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
-{
- int i, s;
- unsigned char *command;
- seq_printf(m, "scsi%d: destination target %d, lun %llu\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- seq_puts(m, " command = ");
- command = cmd->cmnd;
- seq_printf(m, "%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- seq_printf(m, " %02x", command[i]);
- seq_putc(m, '\n');
-}
-
-static int __maybe_unused NCR5380_show_info(struct seq_file *m,
- struct Scsi_Host *instance)
-{
- struct NCR5380_hostdata *hostdata;
- struct scsi_cmnd *ptr;
- unsigned long flags;
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- local_irq_save(flags);
- seq_printf(m, "NCR5380: coroutine is%s running.\n",
- hostdata->main_running ? "" : "n't");
- if (!hostdata->connected)
- seq_printf(m, "scsi%d: no currently connected command\n", HOSTNO);
- else
- show_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
- seq_printf(m, "scsi%d: issue_queue\n", HOSTNO);
- for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
- show_Scsi_Cmnd(ptr, m);
-
- seq_printf(m, "scsi%d: disconnected_queue\n", HOSTNO);
- for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr))
- show_Scsi_Cmnd(ptr, m);
-
- local_irq_restore(flags);
- return 0;
-}
-
-/**
* NCR5380_init - initialise an NCR5380
* @instance: adapter to configure
* @flags: control flags
@@ -764,11 +614,11 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m,
static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int i;
- SETUP_HOSTDATA(instance);
+ unsigned long deadline;
hostdata->host = instance;
- hostdata->aborted = 0;
hostdata->id_mask = 1 << instance->this_id;
hostdata->id_higher_mask = 0;
for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
@@ -782,13 +632,21 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
#if defined (REAL_DMA)
hostdata->dma_len = 0;
#endif
- hostdata->targets_present = 0;
+ spin_lock_init(&hostdata->lock);
hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
+ hostdata->sensing = NULL;
+ INIT_LIST_HEAD(&hostdata->autosense);
+ INIT_LIST_HEAD(&hostdata->unissued);
+ INIT_LIST_HEAD(&hostdata->disconnected);
+
hostdata->flags = flags;
INIT_WORK(&hostdata->main_task, NCR5380_main);
+ hostdata->work_q = alloc_workqueue("ncr5380_%d",
+ WQ_UNBOUND | WQ_MEM_RECLAIM,
+ 1, instance->host_no);
+ if (!hostdata->work_q)
+ return -ENOMEM;
prepare_info(instance);
@@ -797,6 +655,72 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
+ /* Calibrate register polling loop */
+ i = 0;
+ deadline = jiffies + 1;
+ do {
+ cpu_relax();
+ } while (time_is_after_jiffies(deadline));
+ deadline += msecs_to_jiffies(256);
+ do {
+ NCR5380_read(STATUS_REG);
+ ++i;
+ cpu_relax();
+ } while (time_is_after_jiffies(deadline));
+ hostdata->accesses_per_ms = i / 256;
+
+ return 0;
+}
+
+/**
+ * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
+ * @instance: adapter to check
+ *
+ * If the system crashed, it may have crashed with a connected target and
+ * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
+ * currently established nexus, which we know nothing about. Failing that
+ * do a bus reset.
+ *
+ * Note that a bus reset will cause the chip to assert IRQ.
+ *
+ * Returns 0 if successful, otherwise -ENXIO.
+ */
+
+static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int pass;
+
+ for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
+ switch (pass) {
+ case 1:
+ case 3:
+ case 5:
+ shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
+ NCR5380_poll_politely(instance,
+ STATUS_REG, SR_BSY, 0, 5 * HZ);
+ break;
+ case 2:
+ shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
+ do_abort(instance);
+ break;
+ case 4:
+ shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
+ do_reset(instance);
+ /* Wait after a reset; the SCSI standard calls for
+ * 250ms, we wait 500ms to be on the safe side.
+ * But some Toshiba CD-ROMs need ten times that.
+ */
+ if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+ msleep(2500);
+ else
+ msleep(500);
+ break;
+ case 6:
+ shost_printk(KERN_ERR, instance, "bus locked solid\n");
+ return -ENXIO;
+ }
+ }
return 0;
}
@@ -812,6 +736,38 @@ static void NCR5380_exit(struct Scsi_Host *instance)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
cancel_work_sync(&hostdata->main_task);
+ destroy_workqueue(hostdata->work_q);
+}
+
+/**
+ * complete_cmd - finish processing a command and return it to the SCSI ML
+ * @instance: the host instance
+ * @cmd: command to complete
+ */
+
+static void complete_cmd(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd);
+
+ if (hostdata->sensing == cmd) {
+ /* Autosense processing ends here */
+ if ((cmd->result & 0xff) != SAM_STAT_GOOD) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ set_host_byte(cmd, DID_ERROR);
+ } else
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->sensing = NULL;
+ }
+
+#ifdef SUPPORT_TAGS
+ cmd_free_tag(cmd);
+#else
+ hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
+#endif
+ cmd->scsi_done(cmd);
}
/**
@@ -819,7 +775,7 @@ static void NCR5380_exit(struct Scsi_Host *instance)
* @instance: the relevant SCSI adapter
* @cmd: SCSI command
*
- * cmd is added to the per instance issue_queue, with minor
+ * cmd is added to the per-instance issue queue, with minor
* twiddling done to the host specific fields of cmd. If the
* main coroutine is not running, it is restarted.
*/
@@ -828,44 +784,23 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
struct scsi_cmnd *cmd)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
- struct scsi_cmnd *tmp;
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
unsigned long flags;
#if (NDEBUG & NDEBUG_NO_WRITE)
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
- printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
- H_NO(cmd));
+ shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n");
cmd->result = (DID_ERROR << 16);
cmd->scsi_done(cmd);
return 0;
}
#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
- /*
- * We use the host_scribble field as a pointer to the next command
- * in a queue
- */
-
- SET_NEXT(cmd, NULL);
cmd->result = 0;
/*
- * Insert the cmd into the issue queue. Note that REQUEST SENSE
- * commands are added to the head of the queue since any command will
- * clear the contingent allegiance condition that exists and the
- * sense data is only guaranteed to be valid while the condition exists.
- */
-
- /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
- * Otherwise a running NCR5380_main may steal the lock.
- * Lock before actually inserting due to fairness reasons explained in
- * atari_scsi.c. If we insert first, then it's impossible for this driver
- * to release the lock.
- * Stop timer for this command while waiting for the lock, or timeouts
- * may happen (and they really do), and it's no good if the command doesn't
- * appear in any of the queues.
* ++roman: Just disabling the NCR interrupt isn't sufficient here,
* because also a timer int can trigger an abort or reset, which would
* alter queues and touch the lock.
@@ -873,7 +808,7 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
if (!NCR5380_acquire_dma_irq(instance))
return SCSI_MLQUEUE_HOST_BUSY;
- local_irq_save(flags);
+ spin_lock_irqsave(&hostdata->lock, flags);
/*
* Insert the cmd into the issue queue. Note that REQUEST SENSE
@@ -882,33 +817,18 @@ static int NCR5380_queue_command(struct Scsi_Host *instance,
* sense data is only guaranteed to be valid while the condition exists.
*/
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- LIST(cmd, hostdata->issue_queue);
- SET_NEXT(cmd, hostdata->issue_queue);
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (struct scsi_cmnd *)hostdata->issue_queue;
- NEXT(tmp); tmp = NEXT(tmp))
- ;
- LIST(cmd, tmp);
- SET_NEXT(tmp, cmd);
- }
- local_irq_restore(flags);
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ list_add(&ncmd->list, &hostdata->unissued);
+ else
+ list_add_tail(&ncmd->list, &hostdata->unissued);
- dprintk(NDEBUG_QUEUES, "scsi%d: command added to %s of queue\n", H_NO(cmd),
- (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+ spin_unlock_irqrestore(&hostdata->lock, flags);
- /* If queue_command() is called from an interrupt (real one or bottom
- * half), we let queue_main() do the job of taking care about main. If it
- * is already running, this is a no-op, else main will be queued.
- *
- * If we're not in an interrupt, we can call NCR5380_main()
- * unconditionally, because it cannot be already running.
- */
- if (in_interrupt() || irqs_disabled())
- queue_main(hostdata);
- else
- NCR5380_main(&hostdata->main_task);
+ dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n",
+ cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+ /* Kick off command processing */
+ queue_work(hostdata->work_q, &hostdata->main_task);
return 0;
}
@@ -917,22 +837,85 @@ static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
/* Caller does the locking needed to set & test these data atomically */
- if (!hostdata->disconnected_queue &&
- !hostdata->issue_queue &&
+ if (list_empty(&hostdata->disconnected) &&
+ list_empty(&hostdata->unissued) &&
+ list_empty(&hostdata->autosense) &&
!hostdata->connected &&
- !hostdata->retain_dma_intr)
+ !hostdata->selecting)
NCR5380_release_dma_irq(instance);
}
/**
+ * dequeue_next_cmd - dequeue a command for processing
+ * @instance: the scsi host instance
+ *
+ * Priority is given to commands on the autosense queue. These commands
+ * need autosense because of a CHECK CONDITION result.
+ *
+ * Returns a command pointer if a command is found for a target that is
+ * not already busy. Otherwise returns NULL.
+ */
+
+static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd;
+ struct scsi_cmnd *cmd;
+
+ if (list_empty(&hostdata->autosense)) {
+ list_for_each_entry(ncmd, &hostdata->unissued, list) {
+ cmd = NCR5380_to_scmd(ncmd);
+ dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
+ cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun);
+
+ if (
+#ifdef SUPPORT_TAGS
+ !is_lun_busy(cmd, 1)
+#else
+ !(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))
+#endif
+ ) {
+ list_del(&ncmd->list);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "dequeue: removed %p from issue queue\n", cmd);
+ return cmd;
+ }
+ }
+ } else {
+ /* Autosense processing begins here */
+ ncmd = list_first_entry(&hostdata->autosense,
+ struct NCR5380_cmd, list);
+ list_del(&ncmd->list);
+ cmd = NCR5380_to_scmd(ncmd);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "dequeue: removed %p from autosense queue\n", cmd);
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+ hostdata->sensing = cmd;
+ return cmd;
+ }
+ return NULL;
+}
+
+static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
+ if (hostdata->sensing) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ list_add(&ncmd->list, &hostdata->autosense);
+ hostdata->sensing = NULL;
+ } else
+ list_add(&ncmd->list, &hostdata->unissued);
+}
+
+/**
* NCR5380_main - NCR state machines
*
* NCR5380_main is a coroutine that runs as long as more work can
* be done on the NCR5380 host adapters in a system. Both
* NCR5380_queue_command() and NCR5380_intr() will try to start it
* in case it is not running.
- *
- * Locks: called as its own thread with no locks held.
*/
static void NCR5380_main(struct work_struct *work)
@@ -940,154 +923,69 @@ static void NCR5380_main(struct work_struct *work)
struct NCR5380_hostdata *hostdata =
container_of(work, struct NCR5380_hostdata, main_task);
struct Scsi_Host *instance = hostdata->host;
- struct scsi_cmnd *tmp, *prev;
+ struct scsi_cmnd *cmd;
int done;
- unsigned long flags;
/*
- * We run (with interrupts disabled) until we're sure that none of
- * the host adapters have anything that can be done, at which point
- * we set main_running to 0 and exit.
- *
- * Interrupts are enabled before doing various other internal
- * instructions, after we've decided that we need to run through
- * the loop again.
- *
- * this should prevent any race conditions.
- *
* ++roman: Just disabling the NCR interrupt isn't sufficient here,
* because also a timer int can trigger an abort or reset, which can
* alter queues and touch the Falcon lock.
*/
- /* Tell int handlers main() is now already executing. Note that
- no races are possible here. If an int comes in before
- 'main_running' is set here, and queues/executes main via the
- task queue, it doesn't do any harm, just this instance of main
- won't find any work left to do. */
- if (hostdata->main_running)
- return;
- hostdata->main_running = 1;
-
- local_save_flags(flags);
do {
- local_irq_disable(); /* Freeze request queues */
done = 1;
- if (!hostdata->connected) {
- dprintk(NDEBUG_MAIN, "scsi%d: not connected\n", HOSTNO);
- /*
- * Search through the issue_queue for a command destined
- * for a target that's not busy.
- */
-#if (NDEBUG & NDEBUG_LISTS)
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL;
- tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
- ;
- /*printk("%p ", tmp);*/
- if ((tmp == prev) && tmp)
- printk(" LOOP\n");
- /* else printk("\n"); */
-#endif
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue,
- prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
- u8 lun = tmp->device->lun;
-
- dprintk(NDEBUG_LISTS,
- "MAIN tmp=%p target=%d busy=%d lun=%d\n",
- tmp, scmd_id(tmp), hostdata->busy[scmd_id(tmp)],
- lun);
- /* When we find one, remove it from the issue queue. */
- /* ++guenther: possible race with Falcon locking */
- if (
-#ifdef SUPPORT_TAGS
- !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
-#else
- !(hostdata->busy[tmp->device->id] & (1 << lun))
-#endif
- ) {
- /* ++guenther: just to be sure, this must be atomic */
- local_irq_disable();
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- SET_NEXT(prev, NEXT(tmp));
- } else {
- REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
- hostdata->issue_queue = NEXT(tmp);
- }
- SET_NEXT(tmp, NULL);
- hostdata->retain_dma_intr++;
+ spin_lock_irq(&hostdata->lock);
+ while (!hostdata->connected &&
+ (cmd = dequeue_next_cmd(instance))) {
- /* reenable interrupts after finding one */
- local_irq_restore(flags);
+ dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
- /*
- * Attempt to establish an I_T_L nexus here.
- * On success, instance->hostdata->connected is set.
- * On failure, we must add the command back to the
- * issue queue so we can keep trying.
- */
- dprintk(NDEBUG_MAIN, "scsi%d: main(): command for target %d "
- "lun %d removed from issue_queue\n",
- HOSTNO, tmp->device->id, lun);
- /*
- * REQUEST SENSE commands are issued without tagged
- * queueing, even on SCSI-II devices because the
- * contingent allegiance condition exists for the
- * entire unit.
- */
- /* ++roman: ...and the standard also requires that
- * REQUEST SENSE command are untagged.
- */
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+ /* ++roman: ...and the standard also requires that
+ * REQUEST SENSE command are untagged.
+ */
#ifdef SUPPORT_TAGS
- cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
+ cmd_get_tag(cmd, cmd->cmnd[0] != REQUEST_SENSE);
#endif
- if (!NCR5380_select(instance, tmp)) {
- local_irq_disable();
- hostdata->retain_dma_intr--;
- /* release if target did not response! */
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- break;
- } else {
- local_irq_disable();
- LIST(tmp, hostdata->issue_queue);
- SET_NEXT(tmp, hostdata->issue_queue);
- hostdata->issue_queue = tmp;
+ cmd = NCR5380_select(instance, cmd);
+ if (!cmd) {
+ dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
+ maybe_release_dma_irq(instance);
+ } else {
+ dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
+ "main: select failed, returning %p to queue\n", cmd);
+ requeue_cmd(instance, cmd);
#ifdef SUPPORT_TAGS
- cmd_free_tag(tmp);
+ cmd_free_tag(cmd);
#endif
- hostdata->retain_dma_intr--;
- local_irq_restore(flags);
- dprintk(NDEBUG_MAIN, "scsi%d: main(): select() failed, "
- "returned to issue_queue\n", HOSTNO);
- if (hostdata->connected)
- break;
- }
- } /* if target/lun/target queue is not busy */
- } /* for issue_queue */
- } /* if (!hostdata->connected) */
-
+ }
+ }
if (hostdata->connected
#ifdef REAL_DMA
&& !hostdata->dma_len
#endif
) {
- local_irq_restore(flags);
- dprintk(NDEBUG_MAIN, "scsi%d: main: performing information transfer\n",
- HOSTNO);
+ dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n");
NCR5380_information_transfer(instance);
- dprintk(NDEBUG_MAIN, "scsi%d: main: done set false\n", HOSTNO);
done = 0;
}
+ spin_unlock_irq(&hostdata->lock);
+ if (!done)
+ cond_resched();
} while (!done);
-
- /* Better allow ints _after_ 'main_running' has been cleared, else
- an interrupt could believe we'll pick up the work it left for
- us, but we won't see it anymore here... */
- hostdata->main_running = 0;
- local_irq_restore(flags);
}
@@ -1096,27 +994,20 @@ static void NCR5380_main(struct work_struct *work)
* Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
*
* Purpose : Called by interrupt handler when DMA finishes or a phase
- * mismatch occurs (which would finish the DMA transfer).
+ * mismatch occurs (which would finish the DMA transfer).
*
* Inputs : instance - this instance of the NCR5380.
- *
*/
static void NCR5380_dma_complete(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int transferred;
unsigned char **data;
- volatile int *count;
+ int *count;
int saved_data = 0, overrun = 0;
unsigned char p;
- if (!hostdata->connected) {
- printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
- "no connected cmd\n", HOSTNO);
- return;
- }
-
if (hostdata->read_overruns) {
p = hostdata->connected->SCp.phase;
if (p & SR_IO) {
@@ -1126,15 +1017,11 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
(BASR_PHASE_MATCH|BASR_ACK)) {
saved_data = NCR5380_read(INPUT_DATA_REG);
overrun = 1;
- dprintk(NDEBUG_DMA, "scsi%d: read overrun handled\n", HOSTNO);
+ dsprintk(NDEBUG_DMA, instance, "read overrun handled\n");
}
}
}
- dprintk(NDEBUG_DMA, "scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
- HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
-
#if defined(CONFIG_SUN3)
if ((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) {
pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n",
@@ -1153,9 +1040,9 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
}
#endif
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
transferred = hostdata->dma_len - NCR5380_dma_residual(instance);
hostdata->dma_len = 0;
@@ -1194,140 +1081,160 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
* Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
* from the disconnected queue, and restarting NCR5380_main()
* as required.
+ *
+ * The chip can assert IRQ in any of six different conditions. The IRQ flag
+ * is then cleared by reading the Reset Parity/Interrupt Register (RPIR).
+ * Three of these six conditions are latched in the Bus and Status Register:
+ * - End of DMA (cleared by ending DMA Mode)
+ * - Parity error (cleared by reading RPIR)
+ * - Loss of BSY (cleared by reading RPIR)
+ * Two conditions have flag bits that are not latched:
+ * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode)
+ * - Bus reset (non-maskable)
+ * The remaining condition has no flag bit at all:
+ * - Selection/reselection
+ *
+ * Hence, establishing the cause(s) of any interrupt is partly guesswork.
+ * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor
+ * claimed that "the design of the [DP8490] interrupt logic ensures
+ * interrupts will not be lost (they can be on the DP5380)."
+ * The L5380/53C80 datasheet from LOGIC Devices has more details.
+ *
+ * Checking for bus reset by reading RST is futile because of interrupt
+ * latency, but a bus reset will reset chip logic. Checking for parity error
+ * is unnecessary because that interrupt is never enabled. A Loss of BSY
+ * condition will clear DMA Mode. We can tell when this occurs because the
+ * the Busy Monitor interrupt is enabled together with DMA Mode.
*/
static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
struct Scsi_Host *instance = dev_id;
- int done = 1, handled = 0;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ int handled = 0;
unsigned char basr;
+ unsigned long flags;
- dprintk(NDEBUG_INTR, "scsi%d: NCR5380 irq triggered\n", HOSTNO);
+ spin_lock_irqsave(&hostdata->lock, flags);
- /* Look for pending interrupts */
basr = NCR5380_read(BUS_AND_STATUS_REG);
- dprintk(NDEBUG_INTR, "scsi%d: BASR=%02x\n", HOSTNO, basr);
- /* dispatch to appropriate routine if found and done=0 */
if (basr & BASR_IRQ) {
- NCR5380_dprint(NDEBUG_INTR, instance);
- if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
- done = 0;
- dprintk(NDEBUG_INTR, "scsi%d: SEL interrupt\n", HOSTNO);
- NCR5380_reselect(instance);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else if (basr & BASR_PARITY_ERROR) {
- dprintk(NDEBUG_INTR, "scsi%d: PARITY interrupt\n", HOSTNO);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
- dprintk(NDEBUG_INTR, "scsi%d: RESET interrupt\n", HOSTNO);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- } else {
- /*
- * The rest of the interrupt conditions can occur only during a
- * DMA transfer
- */
+ unsigned char mr = NCR5380_read(MODE_REG);
+ unsigned char sr = NCR5380_read(STATUS_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
+ irq, basr, sr, mr);
#if defined(REAL_DMA)
- /*
- * We should only get PHASE MISMATCH and EOP interrupts if we have
- * DMA enabled, so do a sanity check based on the current setting
- * of the MODE register.
+ if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
+ /* Probably End of DMA, Phase Mismatch or Loss of BSY.
+ * We ack IRQ after clearing Mode Register. Workarounds
+ * for End of DMA errata need to happen in DMA Mode.
*/
- if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
- ((basr & BASR_END_DMA_TRANSFER) ||
- !(basr & BASR_PHASE_MATCH))) {
+ dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n");
- dprintk(NDEBUG_INTR, "scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
- NCR5380_dma_complete( instance );
- done = 0;
- } else
+ if (hostdata->connected) {
+ NCR5380_dma_complete(instance);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ } else {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ } else
#endif /* REAL_DMA */
- {
-/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
- if (basr & BASR_PHASE_MATCH)
- dprintk(NDEBUG_INTR, "scsi%d: unknown interrupt, "
- "BASR 0x%x, MR 0x%x, SR 0x%x\n",
- HOSTNO, basr, NCR5380_read(MODE_REG),
- NCR5380_read(STATUS_REG));
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
+ (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
+ /* Probably reselected */
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n");
+
+ if (!hostdata->connected) {
+ NCR5380_reselect(instance);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ }
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ } else {
+ /* Probably Bus Reset */
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n");
#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
+ dregs->csr |= CSR_DMA_ENABLE;
#endif
- }
- } /* if !(SELECTION || PARITY) */
+ }
handled = 1;
- } /* BASR & IRQ */ else {
- printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
- "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
- NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else {
+ shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n");
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
}
- if (!done) {
- dprintk(NDEBUG_INTR, "scsi%d: in int routine, calling main\n", HOSTNO);
- /* Put a call to NCR5380_main() on the queue... */
- queue_main(shost_priv(instance));
- }
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+
return IRQ_RETVAL(handled);
}
/*
* Function : int NCR5380_select(struct Scsi_Host *instance,
- * struct scsi_cmnd *cmd)
+ * struct scsi_cmnd *cmd)
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- * including ARBITRATION, SELECTION, and initial message out for
- * IDENTIFY and queue messages.
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
*
* Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute.
+ * target lives, cmd - SCSI command to execute.
*
- * Returns : -1 if selection could not execute for some reason,
- * 0 if selection succeeded or failed because the target
- * did not respond.
+ * Returns cmd if selection failed but should be retried,
+ * NULL if selection failed and should not be retried, or
+ * NULL if selection succeeded (hostdata->connected == cmd).
*
* Side effects :
- * If bus busy, arbitration failed, etc, NCR5380_select() will exit
- * with registers as they should have been on entry - ie
- * SELECT_ENABLE will be set appropriately, the NCR5380
- * will cease to drive any SCSI bus signals.
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
*
- * If successful : I_T_L or I_T_L_Q nexus will be established,
- * instance->connected will be set to cmd.
- * SELECT interrupt will be disabled.
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
*
- * If failed (no target) : cmd->scsi_done() will be called, and the
- * cmd->result host byte set to DID_BAD_TARGET.
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
*/
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
+static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
{
- SETUP_HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char tmp[3], phase;
unsigned char *data;
int len;
- unsigned long timeout;
- unsigned long flags;
+ int err;
- hostdata->restart_select = 0;
NCR5380_dprint(NDEBUG_ARBITRATION, instance);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: starting arbitration, id = %d\n", HOSTNO,
- instance->this_id);
+ dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n",
+ instance->this_id);
+
+ /*
+ * Arbitration and selection phases are slow and involve dropping the
+ * lock, so we have to watch out for EH. An exception handler may
+ * change 'selecting' to NULL. This function will then return NULL
+ * so that the caller will forget about 'cmd'. (During information
+ * transfer phases, EH may change 'connected' to NULL.)
+ */
+ hostdata->selecting = cmd;
/*
* Set the phase bits to 0, otherwise the NCR5380 won't drive the
* data bus during SELECTION.
*/
- local_irq_save(flags);
- if (hostdata->connected) {
- local_irq_restore(flags);
- return -1;
- }
NCR5380_write(TARGET_COMMAND_REG, 0);
/*
@@ -1337,96 +1244,77 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(MODE_REG, MR_ARBITRATE);
- local_irq_restore(flags);
-
- /* Wait for arbitration logic to complete */
-#if defined(NCR_TIMEOUT)
- {
- unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+ /* The chip now waits for BUS FREE phase. Then after the 800 ns
+ * Bus Free Delay, arbitration will begin.
+ */
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
- time_before(jiffies, timeout) && !hostdata->connected)
- ;
- if (time_after_eq(jiffies, timeout)) {
- printk("scsi : arbitration timeout at %d\n", __LINE__);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
+ spin_unlock_irq(&hostdata->lock);
+ err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0,
+ INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS,
+ ICR_ARBITRATION_PROGRESS, HZ);
+ spin_lock_irq(&hostdata->lock);
+ if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) {
+ /* Reselection interrupt */
+ goto out;
}
-#else /* NCR_TIMEOUT */
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
- !hostdata->connected)
- ;
-#endif
-
- dprintk(NDEBUG_ARBITRATION, "scsi%d: arbitration complete\n", HOSTNO);
-
- if (hostdata->connected) {
+ if (err < 0) {
NCR5380_write(MODE_REG, MR_BASE);
- return -1;
+ shost_printk(KERN_ERR, instance,
+ "select: arbitration timeout\n");
+ goto out;
}
- /*
- * The arbitration delay is 2.2us, but this is a minimum and there is
- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
- * the integral nature of udelay().
- *
- */
+ spin_unlock_irq(&hostdata->lock);
+ /* The SCSI-2 arbitration delay is 2.4 us */
udelay(3);
/* Check for lost arbitration */
if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
NCR5380_write(MODE_REG, MR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
- HOSTNO);
- return -1;
+ dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n");
+ spin_lock_irq(&hostdata->lock);
+ goto out;
}
- /* after/during arbitration, BSY should be asserted.
- IBM DPES-31080 Version S31Q works now */
- /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+ /* After/during arbitration, BSY should be asserted.
+ * IBM DPES-31080 Version S31Q works now
+ * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman)
+ */
NCR5380_write(INITIATOR_COMMAND_REG,
ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
- HOSTNO);
- return -1;
- }
-
/*
* Again, bus clear + bus settle time is 1.2us, however, this is
* a minimum so we'll udelay ceil(1.2)
*/
-#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
- /* ++roman: But some targets (see above :-) seem to need a bit more... */
- udelay(15);
-#else
- udelay(2);
-#endif
+ if (hostdata->flags & FLAG_TOSHIBA_DELAY)
+ udelay(15);
+ else
+ udelay(2);
- if (hostdata->connected) {
+ spin_lock_irq(&hostdata->lock);
+
+ /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
+ if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
+ goto out;
+
+ if (!hostdata->selecting) {
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
+ goto out;
}
- dprintk(NDEBUG_ARBITRATION, "scsi%d: won arbitration\n", HOSTNO);
+ dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
/*
* Now that we have won arbitration, start Selection process, asserting
* the host and target ID's on the SCSI bus.
*/
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd)));
/*
* Raise ATN while SEL is true before BSY goes false from arbitration,
@@ -1434,22 +1322,18 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
* phase immediately after selection.
*/
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL);
NCR5380_write(MODE_REG, MR_BASE);
/*
* Reselect interrupts must be turned off prior to the dropping of BSY,
* otherwise we will trigger an interrupt.
*/
-
- if (hostdata->connected) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
- }
-
NCR5380_write(SELECT_ENABLE_REG, 0);
+ spin_unlock_irq(&hostdata->lock);
+
/*
* The initiator shall then wait at least two deskew delays and release
* the BSY signal.
@@ -1457,8 +1341,8 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
/* Reset BSY */
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
- ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL);
/*
* Something weird happens when we cease to drive BSY - looks
@@ -1479,45 +1363,39 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
udelay(1);
- dprintk(NDEBUG_SELECTION, "scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
+ dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd));
/*
* The SCSI specification calls for a 250 ms timeout for the actual
* selection.
*/
- timeout = jiffies + msecs_to_jiffies(250);
-
- /*
- * XXX very interesting - we're seeing a bounce where the BSY we
- * asserted is being reflected / still asserted (propagation delay?)
- * and it's detecting as true. Sigh.
- */
-
-#if 0
- /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
- * IO while SEL is true. But again, there are some disks out the in the
- * world that do that nevertheless. (Somebody claimed that this announces
- * reselection capability of the target.) So we better skip that test and
- * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
- */
-
- while (time_before(jiffies, timeout) &&
- !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO)))
- ;
+ err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY,
+ msecs_to_jiffies(250));
if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+ spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_reselect(instance);
- printk(KERN_ERR "scsi%d: reselection after won arbitration?\n",
- HOSTNO);
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
+ goto out;
+ }
+
+ if (err < 0) {
+ spin_lock_irq(&hostdata->lock);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
+ /* Can't touch cmd if it has been reclaimed by the scsi ML */
+ if (hostdata->selecting) {
+ cmd->result = DID_BAD_TARGET << 16;
+ complete_cmd(instance, cmd);
+ dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
+ cmd = NULL;
+ }
+ goto out;
}
-#else
- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY))
- ;
-#endif
/*
* No less than two deskew delays after the initiator detects the
@@ -1529,29 +1407,6 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << cmd->device->id)) {
- printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
- if (hostdata->restart_select)
- printk(KERN_NOTICE "\trestart select\n");
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- cmd->result = DID_BAD_TARGET << 16;
-#ifdef SUPPORT_TAGS
- cmd_free_tag(cmd);
-#endif
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- dprintk(NDEBUG_SELECTION, "scsi%d: target did not respond within 250ms\n", HOSTNO);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return 0;
- }
-
- hostdata->targets_present |= (1 << cmd->device->id);
-
/*
* Since we followed the SCSI spec, and raised ATN while SEL
* was true but before BSY was false during selection, the information
@@ -1563,16 +1418,27 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
* until it wraps back to 0.
*
* XXX - it turns out that there are some broken SCSI-II devices,
- * which claim to support tagged queuing but fail when more than
- * some number of commands are issued at once.
+ * which claim to support tagged queuing but fail when more than
+ * some number of commands are issued at once.
*/
/* Wait for start of REQ/ACK handshake */
- while (!(NCR5380_read(STATUS_REG) & SR_REQ))
- ;
- dprintk(NDEBUG_SELECTION, "scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
- HOSTNO, cmd->device->id);
+ err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+ spin_lock_irq(&hostdata->lock);
+ if (err < 0) {
+ shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ goto out;
+ }
+ if (!hostdata->selecting) {
+ do_abort(instance);
+ goto out;
+ }
+
+ dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
+ scmd_id(cmd));
tmp[0] = IDENTIFY(1, cmd->device->lun);
#ifdef SUPPORT_TAGS
@@ -1591,11 +1457,12 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
data = tmp;
phase = PHASE_MSGOUT;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_SELECTION, "scsi%d: nexus established.\n", HOSTNO);
+ dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n");
/* XXX need to handle errors here */
+
hostdata->connected = cmd;
#ifndef SUPPORT_TAGS
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun;
#endif
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_INTR;
@@ -1603,24 +1470,30 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
initialize_SCp(cmd);
- return 0;
+ cmd = NULL;
+
+out:
+ if (!hostdata->selecting)
+ return NULL;
+ hostdata->selecting = NULL;
+ return cmd;
}
/*
* Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
+ * unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using polled I/O
*
* Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
*
* Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes are transferred or exit
- * is in same phase.
+ * maximum number of bytes, 0 if all bytes are transferred or exit
+ * is in same phase.
*
- * Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
*
* XXX Note : handling for bus free may be useful.
*/
@@ -1635,9 +1508,9 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
unsigned char *phase, int *count,
unsigned char **data)
{
- register unsigned char p = *phase, tmp;
- register int c = *count;
- register unsigned char *d = *data;
+ unsigned char p = *phase, tmp;
+ int c = *count;
+ unsigned char *d = *data;
/*
* The NCR5380 chip will only drive the SCSI bus when the
@@ -1652,14 +1525,15 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
* Wait for assertion of REQ, after which the phase bits will be
* valid
*/
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
- ;
- dprintk(NDEBUG_HANDSHAKE, "scsi%d: REQ detected\n", HOSTNO);
+ if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0)
+ break;
+
+ dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n");
/* Check for phase mismatch */
- if ((tmp & PHASE_MASK) != p) {
- dprintk(NDEBUG_PIO, "scsi%d: phase mismatch\n", HOSTNO);
+ if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) {
+ dsprintk(NDEBUG_PIO, instance, "phase mismatch\n");
NCR5380_dprint_phase(NDEBUG_PIO, instance);
break;
}
@@ -1684,35 +1558,36 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
NCR5380_dprint(NDEBUG_PIO, instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
} else {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
NCR5380_dprint(NDEBUG_PIO, instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
}
} else {
NCR5380_dprint(NDEBUG_PIO, instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
}
- while (NCR5380_read(STATUS_REG) & SR_REQ)
- ;
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_REQ, 0, 5 * HZ) < 0)
+ break;
- dprintk(NDEBUG_HANDSHAKE, "scsi%d: req false, handshake complete\n", HOSTNO);
+ dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n");
- /*
- * We have several special cases to consider during REQ/ACK handshaking :
- * 1. We were in MSGOUT phase, and we are on the last byte of the
- * message. ATN must be dropped as ACK is dropped.
- *
- * 2. We are in a MSGIN phase, and we are on the last byte of the
- * message. We must exit with ACK asserted, so that the calling
- * code may raise ATN before dropping ACK to reject the message.
- *
- * 3. ACK and ATN are clear and the target may proceed as normal.
- */
+/*
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1. We were in MSGOUT phase, and we are on the last byte of the
+ * message. ATN must be dropped as ACK is dropped.
+ *
+ * 2. We are in a MSGIN phase, and we are on the last byte of the
+ * message. We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3. ACK and ATN are clear and the target may proceed as normal.
+ */
if (!(p == PHASE_MSGIN && c == 1)) {
if (p == PHASE_MSGOUT && c > 1)
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
@@ -1721,16 +1596,16 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
}
} while (--c);
- dprintk(NDEBUG_PIO, "scsi%d: residual %d\n", HOSTNO, c);
+ dsprintk(NDEBUG_PIO, instance, "residual %d\n", c);
*count = c;
*data = d;
tmp = NCR5380_read(STATUS_REG);
/* The phase read from the bus is valid if either REQ is (already)
- * asserted or if ACK hasn't been released yet. The latter is the case if
- * we're in MSGIN and all wanted bytes have been received.
+ * asserted or if ACK hasn't been released yet. The latter applies if
+ * we're in MSG IN, DATA IN or STATUS and all bytes have been received.
*/
- if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+ if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0))
*phase = tmp & PHASE_MASK;
else
*phase = PHASE_UNKNOWN;
@@ -1741,19 +1616,45 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
return -1;
}
-/*
- * Function : do_abort (Scsi_Host *host)
+/**
+ * do_reset - issue a reset command
+ * @instance: adapter to reset
*
- * Purpose : abort the currently established nexus. Should only be
- * called from a routine which can drop into a
+ * Issue a reset sequence to the NCR5380 and try and get the bus
+ * back into sane shape.
*
- * Returns : 0 on success, -1 on failure.
+ * This clears the reset interrupt flag because there may be no handler for
+ * it. When the driver is initialized, the NCR5380_intr() handler has not yet
+ * been installed. And when in EH we may have released the ST DMA interrupt.
+ */
+
+static void do_reset(struct Scsi_Host *instance)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ NCR5380_write(TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+ udelay(50);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ local_irq_restore(flags);
+}
+
+/**
+ * do_abort - abort the currently established nexus by going to
+ * MESSAGE OUT phase and sending an ABORT message.
+ * @instance: relevant scsi host instance
+ *
+ * Returns 0 on success, -1 on failure.
*/
static int do_abort(struct Scsi_Host *instance)
{
- unsigned char tmp, *msgptr, phase;
+ unsigned char *msgptr, phase, tmp;
int len;
+ int rc;
/* Request message out phase */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
@@ -1768,16 +1669,20 @@ static int do_abort(struct Scsi_Host *instance)
* the target sees, so we just handshake.
*/
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
- ;
+ rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
+ if (rc < 0)
+ goto timeout;
+
+ tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ)
- ;
+ if (tmp != PHASE_MSGOUT) {
+ NCR5380_write(INITIATOR_COMMAND_REG,
+ ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ);
+ if (rc < 0)
+ goto timeout;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
}
@@ -1793,26 +1698,29 @@ static int do_abort(struct Scsi_Host *instance)
*/
return len ? -1 : 0;
+
+timeout:
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
}
#if defined(REAL_DMA)
/*
* Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
+ * unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using either real
- * or pseudo DMA.
+ * or pseudo DMA.
*
* Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
*
* Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes or transferred or exit
- * is in same phase.
- *
- * Also, *phase, *count, *data are modified in place.
+ * maximum number of bytes, 0 if all bytes or transferred or exit
+ * is in same phase.
*
+ * Also, *phase, *count, *data are modified in place.
*/
@@ -1820,10 +1728,9 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
unsigned char *phase, int *count,
unsigned char **data)
{
- SETUP_HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
register int c = *count;
register unsigned char p = *phase;
- unsigned long flags;
#if defined(CONFIG_SUN3)
/* sanity check */
@@ -1834,29 +1741,22 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
}
hostdata->dma_len = c;
- dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
- instance->host_no, (p & SR_IO) ? "reading" : "writing",
- c, (p & SR_IO) ? "to" : "from", *data);
+ dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+ (p & SR_IO) ? "receive" : "send", c, *data);
/* netbsd turns off ints here, why not be safe and do it too */
- local_irq_save(flags);
/* send start chain */
sun3scsi_dma_start(c, *data);
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+ MR_ENABLE_EOP_INTR);
if (p & SR_IO) {
- NCR5380_write(TARGET_COMMAND_REG, 1);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(INITIATOR_COMMAND_REG, 0);
- NCR5380_write(MODE_REG,
- (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
} else {
- NCR5380_write(TARGET_COMMAND_REG, 0);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
- NCR5380_write(MODE_REG,
- (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
NCR5380_write(START_DMA_SEND_REG, 0);
}
@@ -1864,8 +1764,6 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
dregs->csr |= CSR_DMA_ENABLE;
#endif
- local_irq_restore(flags);
-
sun3_dma_active = 1;
#else /* !defined(CONFIG_SUN3) */
@@ -1880,25 +1778,20 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
if (hostdata->read_overruns && (p & SR_IO))
c -= hostdata->read_overruns;
- dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
- HOSTNO, (p & SR_IO) ? "reading" : "writing",
- c, (p & SR_IO) ? "to" : "from", d);
+ dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n",
+ (p & SR_IO) ? "receive" : "send", c, d);
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
-
-#ifdef REAL_DMA
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
-#endif /* def REAL_DMA */
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
+ MR_ENABLE_EOP_INTR);
if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) {
/* On the Medusa, it is a must to initialize the DMA before
* starting the NCR. This is also the cleaner way for the TT.
*/
- local_irq_save(flags);
hostdata->dma_len = (p & SR_IO) ?
NCR5380_dma_read_setup(instance, d, c) :
NCR5380_dma_write_setup(instance, d, c);
- local_irq_restore(flags);
}
if (p & SR_IO)
@@ -1912,11 +1805,9 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
/* On the Falcon, the DMA setup must be done after the last */
/* NCR access, else the DMA setup gets trashed!
*/
- local_irq_save(flags);
hostdata->dma_len = (p & SR_IO) ?
NCR5380_dma_read_setup(instance, d, c) :
NCR5380_dma_write_setup(instance, d, c);
- local_irq_restore(flags);
}
#endif /* !defined(CONFIG_SUN3) */
@@ -1928,23 +1819,22 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
* Function : NCR5380_information_transfer (struct Scsi_Host *instance)
*
* Purpose : run through the various SCSI phases and do as the target
- * directs us to. Operates on the currently connected command,
- * instance->connected.
+ * directs us to. Operates on the currently connected command,
+ * instance->connected.
*
* Inputs : instance, instance for which we are doing commands
*
* Side effects : SCSI things happen, the disconnected queue will be
- * modified if a command disconnects, *instance->connected will
- * change.
+ * modified if a command disconnects, *instance->connected will
+ * change.
*
* XXX Note : we need to watch for bus free or a reset condition here
- * to recover from an unexpected bus free condition.
+ * to recover from an unexpected bus free condition.
*/
static void NCR5380_information_transfer(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
- unsigned long flags;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char msgout = NOP;
int sink = 0;
int len;
@@ -1953,13 +1843,15 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
- struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
+ struct scsi_cmnd *cmd;
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_INTR;
#endif
- while (1) {
+ while ((cmd = hostdata->connected)) {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
+
tmp = NCR5380_read(STATUS_REG);
/* We only have a valid SCSI phase when REQ is asserted */
if (tmp & SR_REQ) {
@@ -1984,7 +1876,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/* this command setup for dma yet? */
if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != cmd)) {
if (cmd->request->cmd_type == REQ_TYPE_FS) {
- sun3scsi_dma_setup(d, count,
+ sun3scsi_dma_setup(instance, d, count,
rq_data_dir(cmd->request));
sun3_dma_setup_done = cmd;
}
@@ -2000,11 +1892,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
+ ICR_ASSERT_ACK);
while (NCR5380_read(STATUS_REG) & SR_REQ)
;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
+ ICR_ASSERT_ATN);
sink = 0;
continue;
}
@@ -2012,12 +1904,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
switch (phase) {
case PHASE_DATAOUT:
#if (NDEBUG & NDEBUG_NO_DATAOUT)
- printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
- "aborted\n", HOSTNO);
+ shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n");
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
+ complete_cmd(instance, cmd);
return;
#endif
case PHASE_DATAIN:
@@ -2031,13 +1922,10 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
- /* ++roman: Try to merge some scatter-buffers if
- * they are at contiguous physical addresses.
- */
merge_contiguous_buffers(cmd);
- dprintk(NDEBUG_INFORMATION, "scsi%d: %d bytes and %d buffers left\n",
- HOSTNO, cmd->SCp.this_residual,
- cmd->SCp.buffers_residual);
+ dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n",
+ cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
}
/*
@@ -2051,16 +1939,18 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
/* ++roman: I suggest, this should be
- * #if def(REAL_DMA)
+ * #if def(REAL_DMA)
* instead of leaving REAL_DMA out.
*/
#if defined(REAL_DMA)
- if (
#if !defined(CONFIG_SUN3)
- !cmd->device->borken &&
+ transfersize = 0;
+ if (!cmd->device->borken)
#endif
- (transfersize = NCR5380_dma_xfer_len(instance, cmd, phase)) >= DMA_MIN_SIZE) {
+ transfersize = NCR5380_dma_xfer_len(instance, cmd, phase);
+
+ if (transfersize >= DMA_MIN_SIZE) {
len = transfersize;
cmd->SCp.phase = phase;
if (NCR5380_transfer_dma(instance, &phase,
@@ -2068,16 +1958,15 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/*
* If the watchdog timer fires, all future
* accesses to this device will use the
- * polled-IO. */
+ * polled-IO.
+ */
scmd_printk(KERN_INFO, cmd,
"switching to slow handshake\n");
cmd->device->borken = 1;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
+ complete_cmd(instance, cmd);
/* XXX - need to source or sink data here, as appropriate */
} else {
#ifdef REAL_DMA
@@ -2093,9 +1982,13 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
}
} else
#endif /* defined(REAL_DMA) */
+ {
+ spin_unlock_irq(&hostdata->lock);
NCR5380_transfer_pio(instance, &phase,
- (int *)&cmd->SCp.this_residual,
- (unsigned char **)&cmd->SCp.ptr);
+ (int *)&cmd->SCp.this_residual,
+ (unsigned char **)&cmd->SCp.ptr);
+ spin_lock_irq(&hostdata->lock);
+ }
#if defined(CONFIG_SUN3) && defined(REAL_DMA)
/* if we had intended to dma that command clear it */
if (sun3_dma_setup_done == cmd)
@@ -2105,162 +1998,64 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
case PHASE_MSGIN:
len = 1;
data = &tmp;
- NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
NCR5380_transfer_pio(instance, &phase, &len, &data);
cmd->SCp.Message = tmp;
switch (tmp) {
- /*
- * Linking lets us reduce the time required to get the
- * next command out to the device, hopefully this will
- * mean we don't waste another revolution due to the delays
- * required by ARBITRATION and another SELECTION.
- *
- * In the current implementation proposal, low level drivers
- * merely have to start the next command, pointed to by
- * next_link, done() is called as with unlinked commands.
- */
-#ifdef LINKED
- case LINKED_CMD_COMPLETE:
- case LINKED_FLG_CMD_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked command "
- "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Sanity check : A linked command should only terminate
- * with one of these messages if there are more linked
- * commands available.
- */
-
- if (!cmd->next_link) {
- printk(KERN_NOTICE "scsi%d: target %d lun %llu "
- "linked command complete, no next_link\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- sink = 1;
- do_abort(instance);
- return;
- }
-
- initialize_SCp(cmd->next_link);
- /* The next command is still part of this process; copy it
- * and don't free it! */
- cmd->next_link->tag = cmd->tag;
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked request "
- "done, calling scsi_done().\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- cmd->scsi_done(cmd);
- cmd = hostdata->connected;
- break;
-#endif /* def LINKED */
case ABORT:
case COMMAND_COMPLETE:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d, lun %llu "
- "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+ dsprintk(NDEBUG_QUEUES, instance,
+ "COMMAND COMPLETE %p target %d lun %llu\n",
+ cmd, scmd_id(cmd), cmd->device->lun);
- local_irq_save(flags);
- hostdata->retain_dma_intr++;
hostdata->connected = NULL;
#ifdef SUPPORT_TAGS
cmd_free_tag(cmd);
if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
- /* Turn a QUEUE FULL status into BUSY, I think the
- * mid level cannot handle QUEUE FULL :-( (The
- * command is retried after BUSY). Also update our
- * queue size to the number of currently issued
- * commands now.
- */
- /* ++Andreas: the mid level code knows about
- QUEUE_FULL now. */
- struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][cmd->device->lun];
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu returned "
- "QUEUE_FULL after %d commands\n",
- HOSTNO, cmd->device->id, cmd->device->lun,
- ta->nr_allocated);
+ u8 lun = cmd->device->lun;
+ struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
+
+ dsprintk(NDEBUG_TAGS, instance,
+ "QUEUE_FULL %p target %d lun %d nr_allocated %d\n",
+ cmd, scmd_id(cmd), lun, ta->nr_allocated);
if (ta->queue_size > ta->nr_allocated)
- ta->nr_allocated = ta->queue_size;
+ ta->queue_size = ta->nr_allocated;
}
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
- /*
- * I'm not sure what the correct thing to do here is :
- *
- * If the command that just executed is NOT a request
- * sense, the obvious thing to do is to set the result
- * code to the values of the stored parameters.
- *
- * If it was a REQUEST SENSE command, we need some way to
- * differentiate between the failure code of the original
- * and the failure code of the REQUEST sense - the obvious
- * case is success, where we fall through and leave the
- * result code unchanged.
- *
- * The non-obvious place is where the REQUEST SENSE failed
- */
-
- if (cmd->cmnd[0] != REQUEST_SENSE)
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- else if (status_byte(cmd->SCp.Status) != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-
- if ((cmd->cmnd[0] == REQUEST_SENSE) &&
- hostdata->ses.cmd_len) {
- scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- hostdata->ses.cmd_len = 0 ;
- }
-
- if ((cmd->cmnd[0] != REQUEST_SENSE) &&
- (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
- scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
-
- dprintk(NDEBUG_AUTOSENSE, "scsi%d: performing request sense\n", HOSTNO);
- LIST(cmd,hostdata->issue_queue);
- SET_NEXT(cmd, hostdata->issue_queue);
- hostdata->issue_queue = (struct scsi_cmnd *) cmd;
- dprintk(NDEBUG_QUEUES, "scsi%d: REQUEST SENSE added to head of "
- "issue queue\n", H_NO(cmd));
- } else {
- cmd->scsi_done(cmd);
+ cmd->result &= ~0xffff;
+ cmd->result |= cmd->SCp.Status;
+ cmd->result |= cmd->SCp.Message << 8;
+
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ complete_cmd(instance, cmd);
+ else {
+ if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION ||
+ cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) {
+ dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n",
+ cmd);
+ list_add_tail(&ncmd->list,
+ &hostdata->autosense);
+ } else
+ complete_cmd(instance, cmd);
}
- local_irq_restore(flags);
-
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- local_irq_save(flags);
- hostdata->retain_dma_intr--;
- /* ++roman: For Falcon SCSI, release the lock on the
- * ST-DMA here if no other commands are waiting on the
- * disconnected queue.
- */
maybe_release_dma_irq(instance);
- local_irq_restore(flags);
return;
case MESSAGE_REJECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
switch (hostdata->last_message) {
case HEAD_OF_QUEUE_TAG:
case ORDERED_QUEUE_TAG:
@@ -2274,27 +2069,20 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->device->tagged_supported = 0;
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
cmd->tag = TAG_NONE;
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu rejected "
- "QUEUE_TAG message; tagged queuing "
- "disabled\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
+ dsprintk(NDEBUG_TAGS, instance, "target %d lun %llu rejected QUEUE_TAG message; tagged queuing disabled\n",
+ scmd_id(cmd), cmd->device->lun);
break;
}
break;
case DISCONNECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- local_irq_save(flags);
- cmd->device->disconnect = 1;
- LIST(cmd,hostdata->disconnected_queue);
- SET_NEXT(cmd, hostdata->disconnected_queue);
hostdata->connected = NULL;
- hostdata->disconnected_queue = cmd;
- local_irq_restore(flags);
- dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d lun %llu was "
- "moved from connected to the "
- "disconnected_queue\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
+ list_add(&ncmd->list, &hostdata->disconnected);
+ dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES,
+ instance, "connected command %p for target %d lun %llu moved to disconnected queue\n",
+ cmd, scmd_id(cmd), cmd->device->lun);
+
/*
* Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
@@ -2303,9 +2091,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /* Wait for bus free to avoid nasty timeouts */
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
@@ -2324,37 +2109,30 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
case RESTORE_POINTERS:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
break;
case EXTENDED_MESSAGE:
/*
- * Extended messages are sent in the following format :
- * Byte
- * 0 EXTENDED_MESSAGE == 1
- * 1 length (includes one byte for code, doesn't
- * include first two bytes)
- * 2 code
- * 3..length+1 arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
+ * Start the message buffer with the EXTENDED_MESSAGE
* byte, since spi_print_msg() wants the whole thing.
*/
extended_msg[0] = EXTENDED_MESSAGE;
/* Accept first byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_EXTENDED, "scsi%d: receiving extended message\n", HOSTNO);
+ spin_unlock_irq(&hostdata->lock);
+
+ dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n");
len = 2;
data = extended_msg + 1;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_EXTENDED, "scsi%d: length=%d, code=0x%02x\n", HOSTNO,
- (int)extended_msg[1], (int)extended_msg[2]);
+ dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n",
+ (int)extended_msg[1],
+ (int)extended_msg[2]);
- if (!len && extended_msg[1] <=
- (sizeof(extended_msg) - 1)) {
+ if (!len && extended_msg[1] > 0 &&
+ extended_msg[1] <= sizeof(extended_msg) - 2) {
/* Accept third byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
len = extended_msg[1] - 1;
@@ -2362,8 +2140,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_EXTENDED, "scsi%d: message received, residual %d\n",
- HOSTNO, len);
+ dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n",
+ len);
switch (extended_msg[2]) {
case EXTENDED_SDTR:
@@ -2373,15 +2151,18 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
tmp = 0;
}
} else if (len) {
- printk(KERN_NOTICE "scsi%d: error receiving "
- "extended message\n", HOSTNO);
+ shost_printk(KERN_ERR, instance, "error receiving extended message\n");
tmp = 0;
} else {
- printk(KERN_NOTICE "scsi%d: extended message "
- "code %02x length %d is too long\n",
- HOSTNO, extended_msg[2], extended_msg[1]);
+ shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n",
+ extended_msg[2], extended_msg[1]);
tmp = 0;
}
+
+ spin_lock_irq(&hostdata->lock);
+ if (!hostdata->connected)
+ return;
+
/* Fall through to reject message */
/*
@@ -2390,8 +2171,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
default:
if (!tmp) {
- printk(KERN_INFO "scsi%d: rejecting message ",
- instance->host_no);
+ shost_printk(KERN_ERR, instance, "rejecting message ");
spi_print_msg(extended_msg);
printk("\n");
} else if (tmp != EXTENDED_MESSAGE)
@@ -2414,18 +2194,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
hostdata->last_message = msgout;
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (msgout == ABORT) {
- local_irq_save(flags);
-#ifdef SUPPORT_TAGS
- cmd_free_tag(cmd);
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ complete_cmd(instance, cmd);
maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
}
msgout = NOP;
@@ -2447,22 +2220,25 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->SCp.Status = tmp;
break;
default:
- printk("scsi%d: unknown phase\n", HOSTNO);
+ shost_printk(KERN_ERR, instance, "unknown phase\n");
NCR5380_dprint(NDEBUG_ANY, instance);
} /* switch(phase) */
- } /* if (tmp * SR_REQ) */
- } /* while (1) */
+ } else {
+ spin_unlock_irq(&hostdata->lock);
+ NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+ spin_lock_irq(&hostdata->lock);
+ }
+ }
}
/*
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
* Purpose : does reselection, initializing the instance->connected
- * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
- * nexus has been reestablished,
+ * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
*
* Inputs : instance - this instance of the NCR5380.
- *
*/
@@ -2471,7 +2247,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
static void NCR5380_reselect(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned char target_mask;
unsigned char lun;
#ifdef SUPPORT_TAGS
@@ -2480,7 +2256,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
unsigned char msg[3];
int __maybe_unused len;
unsigned char __maybe_unused *data, __maybe_unused phase;
- struct scsi_cmnd *tmp = NULL, *prev;
+ struct NCR5380_cmd *ncmd;
+ struct scsi_cmnd *tmp;
/*
* Disable arbitration, etc. since the host adapter obviously
@@ -2488,11 +2265,10 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
*/
NCR5380_write(MODE_REG, MR_BASE);
- hostdata->restart_select = 1;
target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
- dprintk(NDEBUG_RESELECTION, "scsi%d: reselect\n", HOSTNO);
+ dsprintk(NDEBUG_RESELECTION, instance, "reselect\n");
/*
* At this point, we have detected that our SCSI ID is on the bus,
@@ -2504,17 +2280,22 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
*/
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
- while (NCR5380_read(STATUS_REG) & SR_SEL)
- ;
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return;
+ }
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/*
* Wait for target to go into MSGIN.
*/
- while (!(NCR5380_read(STATUS_REG) & SR_REQ))
- ;
+ if (NCR5380_poll_politely(instance,
+ STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
+ do_abort(instance);
+ return;
+ }
#if defined(CONFIG_SUN3) && defined(REAL_DMA)
/* acknowledge toggle to MSGIN */
@@ -2527,15 +2308,21 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
data = msg;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+ if (len) {
+ do_abort(instance);
+ return;
+ }
#endif
if (!(msg[0] & 0x80)) {
- printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+ shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
spi_print_msg(msg);
+ printk("\n");
do_abort(instance);
return;
}
- lun = (msg[0] & 0x07);
+ lun = msg[0] & 0x07;
#if defined(SUPPORT_TAGS) && !defined(CONFIG_SUN3)
/* If the phase is still MSGIN, the target wants to send some more
@@ -2551,8 +2338,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
msg[1] == SIMPLE_QUEUE_TAG)
tag = msg[2];
- dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at "
- "reselection\n", HOSTNO, target_mask, lun, tag);
+ dsprintk(NDEBUG_TAGS, instance, "reselect: target mask %02x, lun %d sent tag %d\n",
+ target_mask, lun, tag);
}
#endif
@@ -2561,36 +2348,34 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
* just reestablished, and remove it from the disconnected queue.
*/
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
- tmp; prev = tmp, tmp = NEXT(tmp)) {
- if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+ tmp = NULL;
+ list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ if (target_mask == (1 << scmd_id(cmd)) &&
+ lun == (u8)cmd->device->lun
#ifdef SUPPORT_TAGS
- && (tag == tmp->tag)
+ && (tag == cmd->tag)
#endif
) {
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- SET_NEXT(prev, NEXT(tmp));
- } else {
- REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
- hostdata->disconnected_queue = NEXT(tmp);
- }
- SET_NEXT(tmp, NULL);
+ list_del(&ncmd->list);
+ tmp = cmd;
break;
}
}
- if (!tmp) {
- printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
-#ifdef SUPPORT_TAGS
- "tag %d "
-#endif
- "not in disconnected_queue.\n",
- HOSTNO, target_mask, lun
+ if (tmp) {
+ dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
+ "reselect: removed %p from disconnected queue\n", tmp);
+ } else {
+
#ifdef SUPPORT_TAGS
- , tag
+ shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d tag %d not in disconnected queue.\n",
+ target_mask, lun, tag);
+#else
+ shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
+ target_mask, lun);
#endif
- );
/*
* Since we have an established nexus that we can't do anything
* with, we must abort it.
@@ -2614,7 +2399,8 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
}
/* setup this command for dma if not already */
if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != tmp)) {
- sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request));
+ sun3scsi_dma_setup(instance, d, count,
+ rq_data_dir(tmp->request));
sun3_dma_setup_done = tmp;
}
}
@@ -2639,235 +2425,196 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
msg[1] == SIMPLE_QUEUE_TAG)
tag = msg[2];
- dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at reselection\n"
- HOSTNO, target_mask, lun, tag);
+ dsprintk(NDEBUG_TAGS, instance, "reselect: target mask %02x, lun %d sent tag %d\n"
+ target_mask, lun, tag);
}
#endif
hostdata->connected = tmp;
- dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n",
- HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
+ dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu, tag %d\n",
+ scmd_id(tmp), tmp->device->lun, tmp->tag);
}
-/*
- * Function : int NCR5380_abort (struct scsi_cmnd *cmd)
- *
- * Purpose : abort a command
- *
- * Inputs : cmd - the scsi_cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
- * used.
- *
- * Returns : SUCCESS - success, FAILED on failure.
- *
- * XXX - there is no way to abort the command that is currently
- * connected, you have to wait for it to complete. If this is
- * a problem, we could implement longjmp() / setjmp(), setjmp()
- * called where the loop started in NCR5380_main().
+/**
+ * list_find_cmd - test for presence of a command in a linked list
+ * @haystack: list of commands
+ * @needle: command to search for
*/
-static
-int NCR5380_abort(struct scsi_cmnd *cmd)
+static bool list_find_cmd(struct list_head *haystack,
+ struct scsi_cmnd *needle)
{
- struct Scsi_Host *instance = cmd->device->host;
- SETUP_HOSTDATA(instance);
- struct scsi_cmnd *tmp, **prev;
- unsigned long flags;
+ struct NCR5380_cmd *ncmd;
- scmd_printk(KERN_NOTICE, cmd, "aborting command\n");
+ list_for_each_entry(ncmd, haystack, list)
+ if (NCR5380_to_scmd(ncmd) == needle)
+ return true;
+ return false;
+}
- NCR5380_print_status(instance);
+/**
+ * list_remove_cmd - remove a command from linked list
+ * @haystack: list of commands
+ * @needle: command to remove
+ */
- local_irq_save(flags);
+static bool list_del_cmd(struct list_head *haystack,
+ struct scsi_cmnd *needle)
+{
+ if (list_find_cmd(haystack, needle)) {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle);
- dprintk(NDEBUG_ABORT, "scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
- NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
+ list_del(&ncmd->list);
+ return true;
+ }
+ return false;
+}
-#if 1
- /*
- * Case 1 : If the command is the currently executing command,
- * we'll set the aborted flag and return control so that
- * information transfer routine can exit cleanly.
- */
+/**
+ * NCR5380_abort - scsi host eh_abort_handler() method
+ * @cmd: the command to be aborted
+ *
+ * Try to abort a given command by removing it from queues and/or sending
+ * the target an abort message. This may not succeed in causing a target
+ * to abort the command. Nonetheless, the low-level driver must forget about
+ * the command because the mid-layer reclaims it and it may be re-issued.
+ *
+ * The normal path taken by a command is as follows. For EH we trace this
+ * same path to locate and abort the command.
+ *
+ * unissued -> selecting -> [unissued -> selecting ->]... connected ->
+ * [disconnected -> connected ->]...
+ * [autosense -> connected ->] done
+ *
+ * If cmd is unissued then just remove it.
+ * If cmd is disconnected, try to select the target.
+ * If cmd is connected, try to send an abort message.
+ * If cmd is waiting for autosense, give it a chance to complete but check
+ * that it isn't left connected.
+ * If cmd was not found at all then presumably it has already been completed,
+ * in which case return SUCCESS to try to avoid further EH measures.
+ * If the command has not completed yet, we must not fail to find it.
+ */
- if (hostdata->connected == cmd) {
+static int NCR5380_abort(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned long flags;
+ int result = SUCCESS;
- dprintk(NDEBUG_ABORT, "scsi%d: aborting connected command\n", HOSTNO);
- /*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
+ spin_lock_irqsave(&hostdata->lock, flags);
- /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
- /*
- * Since we can't change phases until we've completed the current
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
+#if (NDEBUG & NDEBUG_ANY)
+ scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
- /*
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */
+ if (list_del_cmd(&hostdata->unissued, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from issue queue\n", cmd);
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
+ }
- if (do_abort(instance) == 0) {
- hostdata->aborted = 1;
- hostdata->connected = NULL;
- cmd->result = DID_ABORT << 16;
-#ifdef SUPPORT_TAGS
- cmd_free_tag(cmd);
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
- return SUCCESS;
- } else {
- local_irq_restore(flags);
- printk("scsi%d: abort of connected command failed!\n", HOSTNO);
- return FAILED;
- }
+ if (hostdata->selecting == cmd) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: cmd %p == selecting\n", cmd);
+ hostdata->selecting = NULL;
+ cmd->result = DID_ABORT << 16;
+ complete_cmd(instance, cmd);
+ goto out;
}
-#endif
- /*
- * Case 2 : If the command hasn't been issued yet, we simply remove it
- * from the issue queue.
- */
- for (prev = (struct scsi_cmnd **)&(hostdata->issue_queue),
- tmp = (struct scsi_cmnd *)hostdata->issue_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- (*prev) = NEXT(tmp);
- SET_NEXT(tmp, NULL);
- tmp->result = DID_ABORT << 16;
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: abort removed command from issue queue.\n",
- HOSTNO);
- /* Tagged queuing note: no tag to free here, hasn't been assigned
- * yet... */
- tmp->scsi_done(tmp);
- return SUCCESS;
+ if (list_del_cmd(&hostdata->disconnected, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from disconnected list\n", cmd);
+ cmd->result = DID_ERROR << 16;
+ if (!hostdata->connected)
+ NCR5380_select(instance, cmd);
+ if (hostdata->connected != cmd) {
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
}
}
- /*
- * Case 3 : If any commands are connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail.
- */
+ if (hostdata->connected == cmd) {
+ dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+ hostdata->connected = NULL;
+ if (do_abort(instance)) {
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
+ }
+ set_host_byte(cmd, DID_ABORT);
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+ if (cmd->cmnd[0] == REQUEST_SENSE)
+ complete_cmd(instance, cmd);
+ else {
+ struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
- if (hostdata->connected) {
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: abort failed, command connected.\n", HOSTNO);
- return FAILED;
+ /* Perform autosense for this command */
+ list_add(&ncmd->list, &hostdata->autosense);
+ }
}
- /*
- * Case 4: If the command is currently disconnected from the bus, and
- * there are no connected commands, we reconnect the I_T_L or
- * I_T_L_Q nexus associated with it, go into message out, and send
- * an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select(). The easiest way to implement this
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that
- * device reselected.
- *
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
-
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp;
- tmp = NEXT(tmp)) {
- if (cmd == tmp) {
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: aborting disconnected command.\n", HOSTNO);
-
- if (NCR5380_select(instance, cmd))
- return FAILED;
-
- dprintk(NDEBUG_ABORT, "scsi%d: nexus reestablished.\n", HOSTNO);
-
- do_abort(instance);
-
- local_irq_save(flags);
- for (prev = (struct scsi_cmnd **)&(hostdata->disconnected_queue),
- tmp = (struct scsi_cmnd *)hostdata->disconnected_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- *prev = NEXT(tmp);
- SET_NEXT(tmp, NULL);
- tmp->result = DID_ABORT << 16;
- /* We must unlock the tag/LUN immediately here, since the
- * target goes to BUS FREE and doesn't send us another
- * message (COMMAND_COMPLETE or the like)
- */
-#ifdef SUPPORT_TAGS
- cmd_free_tag(tmp);
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
- tmp->scsi_done(tmp);
- return SUCCESS;
- }
- }
+ if (list_find_cmd(&hostdata->autosense, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: found %p on sense queue\n", cmd);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ msleep(1000);
+ spin_lock_irqsave(&hostdata->lock, flags);
+ if (list_del_cmd(&hostdata->autosense, cmd)) {
+ dsprintk(NDEBUG_ABORT, instance,
+ "abort: removed %p from sense queue\n", cmd);
+ set_host_byte(cmd, DID_ABORT);
+ complete_cmd(instance, cmd);
+ goto out;
}
}
- /* Maybe it is sufficient just to release the ST-DMA lock... (if
- * possible at all) At least, we should check if the lock could be
- * released after the abort, in case it is kept due to some bug.
- */
- maybe_release_dma_irq(instance);
- local_irq_restore(flags);
+ if (hostdata->connected == cmd) {
+ dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
+ hostdata->connected = NULL;
+ if (do_abort(instance)) {
+ set_host_byte(cmd, DID_ERROR);
+ complete_cmd(instance, cmd);
+ result = FAILED;
+ goto out;
+ }
+ set_host_byte(cmd, DID_ABORT);
+#ifdef REAL_DMA
+ hostdata->dma_len = 0;
+#endif
+ complete_cmd(instance, cmd);
+ }
- /*
- * Case 5 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
+out:
+ if (result == FAILED)
+ dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
+ else
+ dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
- printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO);
+ queue_work(hostdata->work_q, &hostdata->main_task);
+ maybe_release_dma_irq(instance);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
- return FAILED;
+ return result;
}
-/*
- * Function : int NCR5380_reset (struct scsi_cmnd *cmd)
- *
- * Purpose : reset the SCSI bus.
- *
- * Returns : SUCCESS or FAILURE
+/**
+ * NCR5380_bus_reset - reset the SCSI bus
+ * @cmd: SCSI command undergoing EH
*
+ * Returns SUCCESS
*/
static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
@@ -2876,23 +2623,22 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
int i;
unsigned long flags;
+ struct NCR5380_cmd *ncmd;
- NCR5380_print_status(instance);
+ spin_lock_irqsave(&hostdata->lock, flags);
+
+#if (NDEBUG & NDEBUG_ANY)
+ scmd_printk(KERN_INFO, cmd, __func__);
+#endif
+ NCR5380_dprint(NDEBUG_ANY, instance);
+ NCR5380_dprint_phase(NDEBUG_ANY, instance);
+
+ do_reset(instance);
- /* get in phase */
- NCR5380_write(TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
- /* assert RST */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
- udelay(40);
/* reset NCR registers */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
- /* ++roman: reset interrupt condition! otherwise no interrupts don't get
- * through anymore ... */
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
/* After the reset, there are no more connected or disconnected commands
* and no busy units; so clear the low-level status here to avoid
@@ -2900,17 +2646,34 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
* commands!
*/
- if (hostdata->issue_queue)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
- if (hostdata->connected)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted a connected command\n", H_NO(cmd));
- if (hostdata->disconnected_queue)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+ hostdata->selecting = NULL;
+
+ list_for_each_entry(ncmd, &hostdata->disconnected, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ set_host_byte(cmd, DID_RESET);
+ cmd->scsi_done(cmd);
+ }
+
+ list_for_each_entry(ncmd, &hostdata->autosense, list) {
+ struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
+
+ set_host_byte(cmd, DID_RESET);
+ cmd->scsi_done(cmd);
+ }
+
+ if (hostdata->connected) {
+ set_host_byte(hostdata->connected, DID_RESET);
+ complete_cmd(instance, hostdata->connected);
+ hostdata->connected = NULL;
+ }
+
+ if (hostdata->sensing) {
+ set_host_byte(hostdata->connected, DID_RESET);
+ complete_cmd(instance, hostdata->sensing);
+ hostdata->sensing = NULL;
+ }
- local_irq_save(flags);
- hostdata->issue_queue = NULL;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = NULL;
#ifdef SUPPORT_TAGS
free_all_tags(hostdata);
#endif
@@ -2920,8 +2683,9 @@ static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
hostdata->dma_len = 0;
#endif
+ queue_work(hostdata->work_q, &hostdata->main_task);
maybe_release_dma_irq(instance);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&hostdata->lock, flags);
return SUCCESS;
}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 5ede3daa9..78d1b2963 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -66,7 +66,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -98,7 +97,6 @@
#define NCR5380_queue_command atari_scsi_queue_command
#define NCR5380_abort atari_scsi_abort
-#define NCR5380_show_info atari_scsi_show_info
#define NCR5380_info atari_scsi_info
#define NCR5380_dma_read_setup(instance, data, count) \
@@ -161,23 +159,10 @@ static inline unsigned long SCSI_DMA_GETADR(void)
return adr;
}
-#define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \
- (atari_scsi_host->hostdata))->dma_len)
-
-/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
- * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
- * need ten times the standard value... */
-#ifndef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
-#define AFTER_RESET_DELAY (HZ/2)
-#else
-#define AFTER_RESET_DELAY (5*HZ/2)
-#endif
-
#ifdef REAL_DMA
static void atari_scsi_fetch_restbytes(void);
#endif
-static struct Scsi_Host *atari_scsi_host;
static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value);
@@ -208,12 +193,12 @@ static int setup_cmd_per_lun = -1;
module_param(setup_cmd_per_lun, int, 0);
static int setup_sg_tablesize = -1;
module_param(setup_sg_tablesize, int, 0);
-#ifdef SUPPORT_TAGS
static int setup_use_tagged_queuing = -1;
module_param(setup_use_tagged_queuing, int, 0);
-#endif
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
+static int setup_toshiba_delay = -1;
+module_param(setup_toshiba_delay, int, 0);
#if defined(REAL_DMA)
@@ -273,15 +258,17 @@ static void scsi_dma_buserr(int irq, void *dummy)
#endif
-static irqreturn_t scsi_tt_intr(int irq, void *dummy)
+static irqreturn_t scsi_tt_intr(int irq, void *dev)
{
#ifdef REAL_DMA
+ struct Scsi_Host *instance = dev;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int dma_stat;
dma_stat = tt_scsi_dma.dma_ctrl;
- dprintk(NDEBUG_INTR, "scsi%d: NCR5380 interrupt, DMA status = %02x\n",
- atari_scsi_host->host_no, dma_stat & 0xff);
+ dsprintk(NDEBUG_INTR, instance, "NCR5380 interrupt, DMA status = %02x\n",
+ dma_stat & 0xff);
/* Look if it was the DMA that has interrupted: First possibility
* is that a bus error occurred...
@@ -304,7 +291,8 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy)
* data reg!
*/
if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
- atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
+ atari_dma_residual = hostdata->dma_len -
+ (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
dprintk(NDEBUG_DMA, "SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
@@ -356,15 +344,17 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy)
#endif /* REAL_DMA */
- NCR5380_intr(irq, dummy);
+ NCR5380_intr(irq, dev);
return IRQ_HANDLED;
}
-static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
+static irqreturn_t scsi_falcon_intr(int irq, void *dev)
{
#ifdef REAL_DMA
+ struct Scsi_Host *instance = dev;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int dma_stat;
/* Turn off DMA and select sector counter register before
@@ -399,7 +389,7 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
printk(KERN_ERR "SCSI DMA error: %ld bytes lost in "
"ST-DMA fifo\n", transferred & 15);
- atari_dma_residual = HOSTDATA_DMALEN - transferred;
+ atari_dma_residual = hostdata->dma_len - transferred;
dprintk(NDEBUG_DMA, "SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
} else
@@ -411,13 +401,14 @@ static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
* data to the original destination address.
*/
memcpy(atari_dma_orig_addr, phys_to_virt(atari_dma_startaddr),
- HOSTDATA_DMALEN - atari_dma_residual);
+ hostdata->dma_len - atari_dma_residual);
atari_dma_orig_addr = NULL;
}
#endif /* REAL_DMA */
- NCR5380_intr(irq, dummy);
+ NCR5380_intr(irq, dev);
+
return IRQ_HANDLED;
}
@@ -488,7 +479,7 @@ static int __init atari_scsi_setup(char *str)
* Defaults depend on TT or Falcon, determined at run time.
* Negative values mean don't change.
*/
- int ints[6];
+ int ints[8];
get_options(str, ARRAY_SIZE(ints), ints);
@@ -504,10 +495,11 @@ static int __init atari_scsi_setup(char *str)
setup_sg_tablesize = ints[3];
if (ints[0] >= 4)
setup_hostid = ints[4];
-#ifdef SUPPORT_TAGS
if (ints[0] >= 5)
setup_use_tagged_queuing = ints[5];
-#endif
+ /* ints[6] (use_pdma) is ignored */
+ if (ints[0] >= 7)
+ setup_toshiba_delay = ints[7];
return 1;
}
@@ -516,38 +508,6 @@ __setup("atascsi=", atari_scsi_setup);
#endif /* !MODULE */
-#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
-static void __init atari_scsi_reset_boot(void)
-{
- unsigned long end;
-
- /*
- * Do a SCSI reset to clean up the bus during initialization. No messing
- * with the queues, interrupts, or locks necessary here.
- */
-
- printk("Atari SCSI: resetting the SCSI bus...");
-
- /* get in phase */
- NCR5380_write(TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
-
- /* assert RST */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
- /* The min. reset hold time is 25us, so 40us should be enough */
- udelay(50);
- /* reset RST and interrupt */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-
- end = jiffies + AFTER_RESET_DELAY;
- while (time_before(jiffies, end))
- barrier();
-
- printk(" done\n");
-}
-#endif
-
#if defined(REAL_DMA)
static unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance,
@@ -815,14 +775,14 @@ static int atari_scsi_bus_reset(struct scsi_cmnd *cmd)
static struct scsi_host_template atari_scsi_template = {
.module = THIS_MODULE,
.proc_name = DRV_MODULE_NAME,
- .show_info = atari_scsi_show_info,
.name = "Atari native SCSI",
.info = atari_scsi_info,
.queuecommand = atari_scsi_queue_command,
.eh_abort_handler = atari_scsi_abort,
.eh_bus_reset_handler = atari_scsi_bus_reset,
.this_id = 7,
- .use_clustering = DISABLE_CLUSTERING
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
};
static int __init atari_scsi_probe(struct platform_device *pdev)
@@ -880,7 +840,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
} else {
/* Test if a host id is set in the NVRam */
if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
- unsigned char b = nvram_read_byte(14);
+ unsigned char b = nvram_read_byte(16);
/* Arbitration enabled? (for TOS)
* If yes, use configured host ID
@@ -915,21 +875,18 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
error = -ENOMEM;
goto fail_alloc;
}
- atari_scsi_host = instance;
-
-#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
- atari_scsi_reset_boot();
-#endif
instance->irq = irq->start;
host_flags |= IS_A_TT() ? 0 : FLAG_LATE_DMA_SETUP;
-
#ifdef SUPPORT_TAGS
host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
#endif
+ host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
- NCR5380_init(instance, host_flags);
+ error = NCR5380_init(instance, host_flags);
+ if (error)
+ goto fail_init;
if (IS_A_TT()) {
error = request_irq(instance->irq, scsi_tt_intr, 0,
@@ -975,6 +932,8 @@ static int __init atari_scsi_probe(struct platform_device *pdev)
#endif
}
+ NCR5380_maybe_reset_bus(instance);
+
error = scsi_add_host(instance, NULL);
if (error)
goto fail_host;
@@ -989,6 +948,7 @@ fail_host:
free_irq(instance->irq, instance);
fail_irq:
NCR5380_exit(instance);
+fail_init:
scsi_host_put(instance);
fail_alloc:
if (atari_dma_buffer)
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 05301bc75..8b52a9dbb 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -41,77 +41,128 @@
static struct scsi_host_template atp870u_template;
static void send_s870(struct atp_unit *dev,unsigned char c);
-static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
-static void tscam_885(void);
+static void atp_is(struct atp_unit *dev, unsigned char c, bool wide_chip, unsigned char lvdmode);
+
+static inline void atp_writeb_base(struct atp_unit *atp, u8 reg, u8 val)
+{
+ outb(val, atp->baseport + reg);
+}
+
+static inline void atp_writew_base(struct atp_unit *atp, u8 reg, u16 val)
+{
+ outw(val, atp->baseport + reg);
+}
+
+static inline void atp_writeb_io(struct atp_unit *atp, u8 channel, u8 reg, u8 val)
+{
+ outb(val, atp->ioport[channel] + reg);
+}
+
+static inline void atp_writew_io(struct atp_unit *atp, u8 channel, u8 reg, u16 val)
+{
+ outw(val, atp->ioport[channel] + reg);
+}
+
+static inline void atp_writeb_pci(struct atp_unit *atp, u8 channel, u8 reg, u8 val)
+{
+ outb(val, atp->pciport[channel] + reg);
+}
+
+static inline void atp_writel_pci(struct atp_unit *atp, u8 channel, u8 reg, u32 val)
+{
+ outl(val, atp->pciport[channel] + reg);
+}
+
+static inline u8 atp_readb_base(struct atp_unit *atp, u8 reg)
+{
+ return inb(atp->baseport + reg);
+}
+
+static inline u16 atp_readw_base(struct atp_unit *atp, u8 reg)
+{
+ return inw(atp->baseport + reg);
+}
+
+static inline u32 atp_readl_base(struct atp_unit *atp, u8 reg)
+{
+ return inl(atp->baseport + reg);
+}
+
+static inline u8 atp_readb_io(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inb(atp->ioport[channel] + reg);
+}
+
+static inline u16 atp_readw_io(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inw(atp->ioport[channel] + reg);
+}
+
+static inline u8 atp_readb_pci(struct atp_unit *atp, u8 channel, u8 reg)
+{
+ return inb(atp->pciport[channel] + reg);
+}
+
+static inline bool is880(struct atp_unit *atp)
+{
+ return atp->pdev->device == ATP880_DEVID1 ||
+ atp->pdev->device == ATP880_DEVID2;
+}
+
+static inline bool is885(struct atp_unit *atp)
+{
+ return atp->pdev->device == ATP885_DEVID;
+}
static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
{
unsigned long flags;
- unsigned short int tmpcip, id;
+ unsigned short int id;
unsigned char i, j, c, target_id, lun,cmdp;
unsigned char *prd;
struct scsi_cmnd *workreq;
- unsigned int workport, tmport, tmport1;
unsigned long adrcnt, k;
#ifdef ED_DBGP
unsigned long l;
#endif
- int errstus;
struct Scsi_Host *host = dev_id;
struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
for (c = 0; c < 2; c++) {
- tmport = dev->ioport[c] + 0x1f;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x80) != 0)
- {
- goto ch_sel;
- }
+ break;
dev->in_int[c] = 0;
}
- return IRQ_NONE;
-ch_sel:
+ if ((j & 0x80) == 0)
+ return IRQ_NONE;
#ifdef ED_DBGP
printk("atp870u_intr_handle enter\n");
#endif
dev->in_int[c] = 1;
- cmdp = inb(dev->ioport[c] + 0x10);
- workport = dev->ioport[c];
+ cmdp = atp_readb_io(dev, c, 0x10);
if (dev->working[c] != 0) {
- if (dev->dev_id == ATP885_DEVID) {
- tmport1 = workport + 0x16;
- if ((inb(tmport1) & 0x80) == 0)
- outb((inb(tmport1) | 0x80), tmport1);
+ if (is885(dev)) {
+ if ((atp_readb_io(dev, c, 0x16) & 0x80) == 0)
+ atp_writeb_io(dev, c, 0x16, (atp_readb_io(dev, c, 0x16) | 0x80));
}
- tmpcip = dev->pciport[c];
- if ((inb(tmpcip) & 0x08) != 0)
+ if ((atp_readb_pci(dev, c, 0x00) & 0x08) != 0)
{
- tmpcip += 0x2;
for (k=0; k < 1000; k++) {
- if ((inb(tmpcip) & 0x08) == 0) {
- goto stop_dma;
- }
- if ((inb(tmpcip) & 0x01) == 0) {
- goto stop_dma;
- }
+ if ((atp_readb_pci(dev, c, 2) & 0x08) == 0)
+ break;
+ if ((atp_readb_pci(dev, c, 2) & 0x01) == 0)
+ break;
}
}
-stop_dma:
- tmpcip = dev->pciport[c];
- outb(0x00, tmpcip);
- tmport -= 0x08;
+ atp_writeb_pci(dev, c, 0, 0x00);
- i = inb(tmport);
+ i = atp_readb_io(dev, c, 0x17);
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip += 2;
- outb(0x06, tmpcip);
- tmpcip -= 2;
- }
+ if (is885(dev))
+ atp_writeb_pci(dev, c, 2, 0x06);
- tmport -= 0x02;
- target_id = inb(tmport);
- tmport += 0x02;
+ target_id = atp_readb_io(dev, c, 0x15);
/*
* Remap wide devices onto id numbers
@@ -129,7 +180,7 @@ stop_dma:
}
dev->last_cmd[c] |= 0x40;
}
- if (dev->dev_id == ATP885_DEVID)
+ if (is885(dev))
dev->r1f[c][target_id] |= j;
#ifdef ED_DBGP
printk("atp870u_intr_handle status = %x\n",i);
@@ -138,12 +189,11 @@ stop_dma:
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- if (dev->dev_id == ATP885_DEVID) {
- tmport -= 0x05;
+ if (is885(dev)) {
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
if (dev->id[c][target_id].last_len != adrcnt)
{
k = dev->id[c][target_id].last_len;
@@ -152,7 +202,7 @@ stop_dma:
dev->id[c][target_id].last_len = adrcnt;
}
#ifdef ED_DBGP
- printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
+ printk("dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
#endif
}
@@ -160,11 +210,9 @@ stop_dma:
* Flip wide
*/
if (dev->wide_id[c] != 0) {
- tmport = workport + 0x1b;
- outb(0x01, tmport);
- while ((inb(tmport) & 0x01) != 0x01) {
- outb(0x01, tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != 0x01)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
}
/*
* Issue more commands
@@ -185,37 +233,34 @@ stop_dma:
#ifdef ED_DBGP
printk("Status 0x85 return\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x40) {
dev->last_cmd[c] |= 0x40;
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x21) {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- tmport -= 0x05;
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
k = dev->id[c][target_id].last_len;
k -= adrcnt;
dev->id[c][target_id].tran_len = k;
dev->id[c][target_id].last_len = adrcnt;
- tmport -= 0x04;
- outb(0x41, tmport);
- tmport += 0x08;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
- if (dev->dev_id == ATP885_DEVID) {
+ if (is885(dev)) {
if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) {
if ((i == 0x4c) || (i == 0x8c))
i=0x48;
@@ -229,11 +274,9 @@ stop_dma:
printk(KERN_DEBUG "Device reselect\n");
#endif
lun = 0;
- tmport -= 0x07;
- if (cmdp == 0x44 || i==0x80) {
- tmport += 0x0d;
- lun = inb(tmport) & 0x07;
- } else {
+ if (cmdp == 0x44 || i == 0x80)
+ lun = atp_readb_io(dev, c, 0x1d) & 0x07;
+ else {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
@@ -241,49 +284,41 @@ stop_dma:
#ifdef ED_DBGP
printk("cmdp = 0x41\n");
#endif
- tmport += 0x02;
adrcnt = 0;
- ((unsigned char *) &adrcnt)[2] = inb(tmport++);
- ((unsigned char *) &adrcnt)[1] = inb(tmport++);
- ((unsigned char *) &adrcnt)[0] = inb(tmport);
+ ((unsigned char *) &adrcnt)[2] = atp_readb_io(dev, c, 0x12);
+ ((unsigned char *) &adrcnt)[1] = atp_readb_io(dev, c, 0x13);
+ ((unsigned char *) &adrcnt)[0] = atp_readb_io(dev, c, 0x14);
k = dev->id[c][target_id].last_len;
k -= adrcnt;
dev->id[c][target_id].tran_len = k;
dev->id[c][target_id].last_len = adrcnt;
- tmport += 0x04;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
} else {
#ifdef ED_DBGP
printk("cmdp != 0x41\n");
#endif
- outb(0x46, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x46);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x02;
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x12, 0x00);
+ atp_writeb_io(dev, c, 0x13, 0x00);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
}
if (dev->last_cmd[c] != 0xff) {
dev->last_cmd[c] |= 0x40;
}
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) & 0xfe;
- outb(j, dev->baseport + 0x29);
- tmport = workport + 0x16;
- } else {
- tmport = workport + 0x10;
- outb(0x45, tmport);
- tmport += 0x06;
- }
-
- target_id = inb(tmport);
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) & 0xfe;
+ atp_writeb_base(dev, 0x29, j);
+ } else
+ atp_writeb_io(dev, c, 0x10, 0x45);
+
+ target_id = atp_readb_io(dev, c, 0x16);
/*
* Remap wide identifiers
*/
@@ -292,10 +327,8 @@ stop_dma:
} else {
target_id &= 0x07;
}
- if (dev->dev_id == ATP885_DEVID) {
- tmport = workport + 0x10;
- outb(0x45, tmport);
- }
+ if (is885(dev))
+ atp_writeb_io(dev, c, 0x10, 0x45);
workreq = dev->id[c][target_id].curr_req;
#ifdef ED_DBGP
scmd_printk(KERN_DEBUG, workreq, "CDB");
@@ -304,18 +337,16 @@ stop_dma:
printk("\n");
#endif
- tmport = workport + 0x0f;
- outb(lun, tmport);
- tmport += 0x02;
- outb(dev->id[c][target_id].devsp, tmport++);
+ atp_writeb_io(dev, c, 0x0f, lun);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
adrcnt = dev->id[c][target_id].tran_len;
k = dev->id[c][target_id].last_len;
- outb(((unsigned char *) &k)[2], tmport++);
- outb(((unsigned char *) &k)[1], tmport++);
- outb(((unsigned char *) &k)[0], tmport++);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) &k)[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) &k)[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) &k)[0]);
#ifdef ED_DBGP
- printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3));
+ printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, atp_readb_io(dev, c, 0x14), atp_readb_io(dev, c, 0x13), atp_readb_io(dev, c, 0x12));
#endif
/* Remap wide */
j = target_id;
@@ -324,35 +355,28 @@ stop_dma:
}
/* Add direction */
j |= dev->id[c][target_id].dirct;
- outb(j, tmport++);
- outb(0x80,tmport);
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x16, 0x80);
/* enable 32 bit fifo transfer */
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip = dev->pciport[c] + 1;
- i=inb(tmpcip) & 0xf3;
+ if (is885(dev)) {
+ i = atp_readb_pci(dev, c, 1) & 0xf3;
//j=workreq->cmnd[0];
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
i |= 0x0c;
}
- outb(i,tmpcip);
- } else if ((dev->dev_id == ATP880_DEVID1) ||
- (dev->dev_id == ATP880_DEVID2) ) {
- tmport = workport - 0x05;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0x3f), tmport);
- }
+ atp_writeb_pci(dev, c, 1, i);
+ } else if (is880(dev)) {
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3b, (atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
+ else
+ atp_writeb_base(dev, 0x3b, atp_readb_base(dev, 0x3b) & 0x3f);
} else {
- tmport = workport + 0x3a;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0xf3), tmport);
- }
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3a, (atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
+ else
+ atp_writeb_base(dev, 0x3a, atp_readb_base(dev, 0x3a) & 0xf3);
}
- tmport = workport + 0x1b;
j = 0;
id = 1;
id = id << target_id;
@@ -362,18 +386,16 @@ stop_dma:
if ((id & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- while ((inb(tmport) & 0x01) != j) {
- outb(j,tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, j);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j)
+ atp_writeb_io(dev, c, 0x1b, j);
if (dev->id[c][target_id].last_len == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
+ atp_writeb_io(dev, c, 0x18, 0x08);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("dev->id[c][target_id].last_len = 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
#ifdef ED_DBGP
printk("target_id = %d adrcnt = %d\n",target_id,adrcnt);
@@ -401,39 +423,33 @@ stop_dma:
}
}
}
- tmpcip = dev->pciport[c] + 0x04;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
+ atp_writel_pci(dev, c, 0x04, dev->id[c][target_id].prdaddr);
#ifdef ED_DBGP
printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr);
#endif
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip -= 0x04;
- } else {
- tmpcip -= 0x02;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip -= 0x02;
+ if (!is885(dev)) {
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
}
- tmport = workport + 0x18;
/*
* Check transfer direction
*/
if (dev->id[c][target_id].dirct != 0) {
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("status 0x80 return dirct != 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
dev->in_int[c] = 0;
#ifdef ED_DBGP
printk("status 0x80 return dirct = 0\n");
#endif
- goto handled;
+ return IRQ_HANDLED;
}
/*
@@ -442,31 +458,22 @@ stop_dma:
workreq = dev->id[c][target_id].curr_req;
- if (i == 0x42) {
- if ((dev->last_cmd[c] & 0xf0) != 0x40)
- {
- dev->last_cmd[c] = 0xff;
- }
- errstus = 0x02;
- workreq->result = errstus;
- goto go_42;
- }
- if (i == 0x16) {
+ if (i == 0x42 || i == 0x16) {
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
}
- errstus = 0;
- tmport -= 0x08;
- errstus = inb(tmport);
- if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) {
- printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
- errstus = 0x02;
- }
- workreq->result = errstus;
-go_42:
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) | 0x01;
- outb(j, dev->baseport + 0x29);
+ if (i == 0x16) {
+ workreq->result = atp_readb_io(dev, c, 0x0f);
+ if (((dev->r1f[c][target_id] & 0x10) != 0) && is885(dev)) {
+ printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
+ workreq->result = 0x02;
+ }
+ } else
+ workreq->result = 0x02;
+
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) | 0x01;
+ atp_writeb_base(dev, 0x29, j);
}
/*
* Complete the command
@@ -488,11 +495,9 @@ go_42:
* Take it back wide
*/
if (dev->wide_id[c] != 0) {
- tmport = workport + 0x1b;
- outb(0x01, tmport);
- while ((inb(tmport) & 0x01) != 0x01) {
- outb(0x01, tmport);
- }
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != 0x01)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
}
/*
* If there is stuff to send and nothing going then send it
@@ -507,7 +512,7 @@ go_42:
}
spin_unlock_irqrestore(dev->host->host_lock, flags);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if ((dev->last_cmd[c] & 0xf0) != 0x40) {
dev->last_cmd[c] = 0xff;
@@ -517,84 +522,54 @@ go_42:
}
i &= 0x0f;
if (i == 0x09) {
- tmpcip += 4;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip = tmpcip - 2;
- tmport = workport + 0x10;
- outb(0x41, tmport);
- if (dev->dev_id == ATP885_DEVID) {
- tmport += 2;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ if (is885(dev)) {
k = dev->id[c][target_id].last_len;
- outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[0]), tmport);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&k))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&k))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&k))[0]);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x04;
} else {
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x08;
}
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
dev->in_int[c] = 0;
- goto handled;
+ return IRQ_HANDLED;
}
if (i == 0x08) {
- tmpcip += 4;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- tmpcip = tmpcip - 2;
- tmport = workport + 0x10;
- outb(0x41, tmport);
- if (dev->dev_id == ATP885_DEVID) {
- tmport += 2;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ atp_writeb_io(dev, c, 0x10, 0x41);
+ if (is885(dev)) {
k = dev->id[c][target_id].last_len;
- outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++);
- } else {
- tmport += 5;
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&k))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&k))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&k))[0]);
}
- outb((unsigned char) (inb(tmport) | 0x20), tmport);
+ atp_writeb_io(dev, c, 0x15, atp_readb_io(dev, c, 0x15) | 0x20);
dev->id[c][target_id].dirct = 0x20;
- tmport += 0x03;
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
dev->in_int[c] = 0;
- goto handled;
- }
- tmport -= 0x07;
- if (i == 0x0a) {
- outb(0x30, tmport);
- } else {
- outb(0x46, tmport);
+ return IRQ_HANDLED;
}
+ if (i == 0x0a)
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ else
+ atp_writeb_io(dev, c, 0x10, 0x46);
dev->id[c][target_id].dirct = 0x00;
- tmport += 0x02;
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- outb(0x00, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- dev->in_int[c] = 0;
- goto handled;
- } else {
-// tmport = workport + 0x17;
-// inb(tmport);
-// dev->working[c] = 0;
- dev->in_int[c] = 0;
- goto handled;
+ atp_writeb_io(dev, c, 0x12, 0x00);
+ atp_writeb_io(dev, c, 0x13, 0x00);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
}
-
-handled:
-#ifdef ED_DBGP
- printk("atp870u_intr_handle exit\n");
-#endif
+ dev->in_int[c] = 0;
+
return IRQ_HANDLED;
}
/**
@@ -608,7 +583,7 @@ static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
void (*done) (struct scsi_cmnd *))
{
unsigned char c;
- unsigned int tmport,m;
+ unsigned int m;
struct atp_unit *dev;
struct Scsi_Host *host;
@@ -677,11 +652,10 @@ static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p,
return 0;
}
dev->quereq[c][dev->quend[c]] = req_p;
- tmport = dev->ioport[c] + 0x1c;
#ifdef ED_DBGP
- printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]);
+ printk("dev->ioport[c] = %x atp_readb_io(dev, c, 0x1c) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],atp_readb_io(dev, c, 0x1c),c,dev->in_int[c],c,dev->in_snd[c]);
#endif
- if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
+ if ((atp_readb_io(dev, c, 0x1c) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
#ifdef ED_DBGP
printk("Call sent_s870(atp870u_queuecommand)\n");
#endif
@@ -706,14 +680,12 @@ static DEF_SCSI_QCMD(atp870u_queuecommand)
*/
static void send_s870(struct atp_unit *dev,unsigned char c)
{
- unsigned int tmport;
- struct scsi_cmnd *workreq;
+ struct scsi_cmnd *workreq = NULL;
unsigned int i;//,k;
unsigned char j, target_id;
unsigned char *prd;
- unsigned short int tmpcip, w;
+ unsigned short int w;
unsigned long l, bttl = 0;
- unsigned int workport;
unsigned long sg_count;
if (dev->in_snd[c] != 0) {
@@ -729,53 +701,42 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) {
dev->last_cmd[c] &= 0x0f;
workreq = dev->id[c][dev->last_cmd[c]].curr_req;
- if (workreq != NULL) { /* check NULL pointer */
- goto cmd_subp;
- }
- dev->last_cmd[c] = 0xff;
- if (dev->quhd[c] == dev->quend[c]) {
- dev->in_snd[c] = 0;
- return ;
+ if (!workreq) {
+ dev->last_cmd[c] = 0xff;
+ if (dev->quhd[c] == dev->quend[c]) {
+ dev->in_snd[c] = 0;
+ return;
+ }
}
}
- if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
- dev->in_snd[c] = 0;
- return ;
- }
- dev->working[c]++;
- j = dev->quhd[c];
- dev->quhd[c]++;
- if (dev->quhd[c] >= qcnt) {
- dev->quhd[c] = 0;
- }
- workreq = dev->quereq[c][dev->quhd[c]];
- if (dev->id[c][scmd_id(workreq)].curr_req == NULL) {
+ if (!workreq) {
+ if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
+ dev->in_snd[c] = 0;
+ return;
+ }
+ dev->working[c]++;
+ j = dev->quhd[c];
+ dev->quhd[c]++;
+ if (dev->quhd[c] >= qcnt)
+ dev->quhd[c] = 0;
+ workreq = dev->quereq[c][dev->quhd[c]];
+ if (dev->id[c][scmd_id(workreq)].curr_req != NULL) {
+ dev->quhd[c] = j;
+ dev->working[c]--;
+ dev->in_snd[c] = 0;
+ return;
+ }
dev->id[c][scmd_id(workreq)].curr_req = workreq;
dev->last_cmd[c] = scmd_id(workreq);
- goto cmd_subp;
- }
- dev->quhd[c] = j;
- dev->working[c]--;
- dev->in_snd[c] = 0;
- return;
-cmd_subp:
- workport = dev->ioport[c];
- tmport = workport + 0x1f;
- if ((inb(tmport) & 0xb0) != 0) {
- goto abortsnd;
- }
- tmport = workport + 0x1c;
- if (inb(tmport) == 0) {
- goto oktosend;
}
-abortsnd:
+ if ((atp_readb_io(dev, c, 0x1f) & 0xb0) != 0 || atp_readb_io(dev, c, 0x1c) != 0) {
#ifdef ED_DBGP
- printk("Abort to Send\n");
+ printk("Abort to Send\n");
#endif
- dev->last_cmd[c] |= 0x40;
- dev->in_snd[c] = 0;
- return;
-oktosend:
+ dev->last_cmd[c] |= 0x40;
+ dev->in_snd[c] = 0;
+ return;
+ }
#ifdef ED_DBGP
printk("OK to Send\n");
scmd_printk(KERN_DEBUG, workreq, "CDB");
@@ -786,9 +747,9 @@ oktosend:
#endif
l = scsi_bufflen(workreq);
- if (dev->dev_id == ATP885_DEVID) {
- j = inb(dev->baseport + 0x29) & 0xfe;
- outb(j, dev->baseport + 0x29);
+ if (is885(dev)) {
+ j = atp_readb_base(dev, 0x29) & 0xfe;
+ atp_writeb_base(dev, 0x29, j);
dev->r1f[c][scmd_id(workreq)] = 0;
}
@@ -800,7 +761,6 @@ oktosend:
l = 0;
}
- tmport = workport + 0x1b;
j = 0;
target_id = scmd_id(workreq);
@@ -812,9 +772,9 @@ oktosend:
if ((w & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- while ((inb(tmport) & 0x01) != j) {
- outb(j,tmport);
+ atp_writeb_io(dev, c, 0x1b, j);
+ while ((atp_readb_io(dev, c, 0x1b) & 0x01) != j) {
+ atp_writeb_pci(dev, c, 0x1b, j);
#ifdef ED_DBGP
printk("send_s870 while loop 1\n");
#endif
@@ -823,24 +783,19 @@ oktosend:
* Write the command
*/
- tmport = workport;
- outb(workreq->cmd_len, tmport++);
- outb(0x2c, tmport++);
- if (dev->dev_id == ATP885_DEVID) {
- outb(0x7f, tmport++);
- } else {
- outb(0xcf, tmport++);
- }
- for (i = 0; i < workreq->cmd_len; i++) {
- outb(workreq->cmnd[i], tmport++);
- }
- tmport = workport + 0x0f;
- outb(workreq->device->lun, tmport);
- tmport += 0x02;
+ atp_writeb_io(dev, c, 0x00, workreq->cmd_len);
+ atp_writeb_io(dev, c, 0x01, 0x2c);
+ if (is885(dev))
+ atp_writeb_io(dev, c, 0x02, 0x7f);
+ else
+ atp_writeb_io(dev, c, 0x02, 0xcf);
+ for (i = 0; i < workreq->cmd_len; i++)
+ atp_writeb_io(dev, c, 0x03 + i, workreq->cmnd[i]);
+ atp_writeb_io(dev, c, 0x0f, workreq->device->lun);
/*
* Write the target
*/
- outb(dev->id[c][target_id].devsp, tmport++);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][target_id].devsp);
#ifdef ED_DBGP
printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
#endif
@@ -849,9 +804,9 @@ oktosend:
/*
* Write transfer size
*/
- outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
- outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
- outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
+ atp_writeb_io(dev, c, 0x12, ((unsigned char *) (&l))[2]);
+ atp_writeb_io(dev, c, 0x13, ((unsigned char *) (&l))[1]);
+ atp_writeb_io(dev, c, 0x14, ((unsigned char *) (&l))[0]);
j = target_id;
dev->id[c][j].last_len = l;
dev->id[c][j].tran_len = 0;
@@ -867,29 +822,24 @@ oktosend:
/*
* Check transfer direction
*/
- if (workreq->sc_data_direction == DMA_TO_DEVICE) {
- outb((unsigned char) (j | 0x20), tmport++);
- } else {
- outb(j, tmport++);
- }
- outb((unsigned char) (inb(tmport) | 0x80), tmport);
- outb(0x80, tmport);
- tmport = workport + 0x1c;
+ if (workreq->sc_data_direction == DMA_TO_DEVICE)
+ atp_writeb_io(dev, c, 0x15, j | 0x20);
+ else
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x16, atp_readb_io(dev, c, 0x16) | 0x80);
+ atp_writeb_io(dev, c, 0x16, 0x80);
dev->id[c][target_id].dirct = 0;
if (l == 0) {
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
#ifdef ED_DBGP
printk("change SCSI_CMD_REG 0x08\n");
#endif
- outb(0x08, tmport);
- } else {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ } else
dev->last_cmd[c] |= 0x40;
- }
dev->in_snd[c] = 0;
return;
}
- tmpcip = dev->pciport[c];
prd = dev->id[c][target_id].prd_table;
dev->id[c][target_id].prd_pos = prd;
@@ -926,50 +876,37 @@ oktosend:
printk("2. bttl %x, l %x\n",bttl, l);
#endif
}
- tmpcip += 4;
#ifdef ED_DBGP
- printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id);
+ printk("send_s870: prdaddr_2 0x%8x target_id %d\n", dev->id[c][target_id].prdaddr,target_id);
#endif
dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus;
- outl(dev->id[c][target_id].prdaddr, tmpcip);
- tmpcip = tmpcip - 2;
- outb(0x06, tmpcip);
- outb(0x00, tmpcip);
- if (dev->dev_id == ATP885_DEVID) {
- tmpcip--;
- j=inb(tmpcip) & 0xf3;
+ atp_writel_pci(dev, c, 4, dev->id[c][target_id].prdaddr);
+ atp_writeb_pci(dev, c, 2, 0x06);
+ atp_writeb_pci(dev, c, 2, 0x00);
+ if (is885(dev)) {
+ j = atp_readb_pci(dev, c, 1) & 0xf3;
if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) ||
(workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
j |= 0x0c;
}
- outb(j,tmpcip);
- tmpcip--;
- } else if ((dev->dev_id == ATP880_DEVID1) ||
- (dev->dev_id == ATP880_DEVID2)) {
- tmpcip =tmpcip -2;
- tmport = workport - 0x05;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
- } else {
- outb((unsigned char) (inb(tmport) & 0x3f), tmport);
- }
+ atp_writeb_pci(dev, c, 1, j);
+ } else if (is880(dev)) {
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3b, (atp_readb_base(dev, 0x3b) & 0x3f) | 0xc0);
+ else
+ atp_writeb_base(dev, 0x3b, atp_readb_base(dev, 0x3b) & 0x3f);
} else {
- tmpcip =tmpcip -2;
- tmport = workport + 0x3a;
- if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
- outb((inb(tmport) & 0xf3) | 0x08, tmport);
- } else {
- outb(inb(tmport) & 0xf3, tmport);
- }
+ if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a))
+ atp_writeb_base(dev, 0x3a, (atp_readb_base(dev, 0x3a) & 0xf3) | 0x08);
+ else
+ atp_writeb_base(dev, 0x3a, atp_readb_base(dev, 0x3a) & 0xf3);
}
- tmport = workport + 0x1c;
if(workreq->sc_data_direction == DMA_TO_DEVICE) {
dev->id[c][target_id].dirct = 0x20;
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
- outb(0x01, tmpcip);
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x01);
#ifdef ED_DBGP
printk( "start DMA(to target)\n");
#endif
@@ -979,10 +916,9 @@ oktosend:
dev->in_snd[c] = 0;
return;
}
- if (inb(tmport) == 0) {
- tmport = workport + 0x18;
- outb(0x08, tmport);
- outb(0x09, tmpcip);
+ if (atp_readb_io(dev, c, 0x1c) == 0) {
+ atp_writeb_io(dev, c, 0x18, 0x08);
+ atp_writeb_pci(dev, c, 0, 0x09);
#ifdef ED_DBGP
printk( "start DMA(to host)\n");
#endif
@@ -996,49 +932,40 @@ oktosend:
static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
{
- unsigned int tmport;
unsigned short int i, k;
unsigned char j;
- tmport = dev->ioport[0] + 0x1c;
- outw(*val, tmport);
-FUN_D7:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- k = inw(tmport);
+ k = atp_readw_io(dev, 0, 0x1c);
j = (unsigned char) (k >> 8);
- if ((k & 0x8000) != 0) { /* DB7 all release? */
- goto FUN_D7;
- }
+ if ((k & 0x8000) != 0) /* DB7 all release? */
+ i = 0;
}
*val |= 0x4000; /* assert DB6 */
- outw(*val, tmport);
+ atp_writew_io(dev, 0, 0x1c, *val);
*val &= 0xdfff; /* assert DB5 */
- outw(*val, tmport);
-FUN_D5:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */
- goto FUN_D5;
- }
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x2000) != 0) /* DB5 all release? */
+ i = 0;
}
*val |= 0x8000; /* no DB4-0, assert DB7 */
*val &= 0xe0ff;
- outw(*val, tmport);
+ atp_writew_io(dev, 0, 0x1c, *val);
*val &= 0xbfff; /* release DB6 */
- outw(*val, tmport);
-FUN_D6:
+ atp_writew_io(dev, 0, 0x1c, *val);
for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */
- if ((inw(tmport) & 0x4000) != 0) { /* DB6 all release? */
- goto FUN_D6;
- }
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x4000) != 0) /* DB6 all release? */
+ i = 0;
}
return j;
}
-static void tscam(struct Scsi_Host *host)
+static void tscam(struct Scsi_Host *host, bool wide_chip, u8 scam_on)
{
- unsigned int tmport;
unsigned char i, j, k;
unsigned long n;
unsigned short int m, assignid_map, val;
@@ -1055,31 +982,28 @@ static void tscam(struct Scsi_Host *host)
}
*/
- tmport = dev->ioport[0] + 1;
- outb(0x08, tmport++);
- outb(0x7f, tmport);
- tmport = dev->ioport[0] + 0x11;
- outb(0x20, tmport);
+ atp_writeb_io(dev, 0, 1, 0x08);
+ atp_writeb_io(dev, 0, 2, 0x7f);
+ atp_writeb_io(dev, 0, 0x11, 0x20);
- if ((dev->scam_on & 0x40) == 0) {
+ if ((scam_on & 0x40) == 0) {
return;
}
m = 1;
m <<= dev->host_id[0];
j = 16;
- if (dev->chip_ver < 4) {
+ if (!wide_chip) {
m |= 0xff00;
j = 8;
}
assignid_map = m;
- tmport = dev->ioport[0] + 0x02;
- outb(0x02, tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
+ atp_writeb_io(dev, 0, 0x02, 0x02); /* 2*2=4ms,3EH 2/32*3E=3.9ms */
+ atp_writeb_io(dev, 0, 0x03, 0);
+ atp_writeb_io(dev, 0, 0x04, 0);
+ atp_writeb_io(dev, 0, 0x05, 0);
+ atp_writeb_io(dev, 0, 0x06, 0);
+ atp_writeb_io(dev, 0, 0x07, 0);
+ atp_writeb_io(dev, 0, 0x08, 0);
for (i = 0; i < j; i++) {
m = 1;
@@ -1087,92 +1011,73 @@ static void tscam(struct Scsi_Host *host)
if ((m & assignid_map) != 0) {
continue;
}
- tmport = dev->ioport[0] + 0x0f;
- outb(0, tmport++);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
+ atp_writeb_io(dev, 0, 0x0f, 0);
+ atp_writeb_io(dev, 0, 0x12, 0);
+ atp_writeb_io(dev, 0, 0x13, 0);
+ atp_writeb_io(dev, 0, 0x14, 0);
if (i > 7) {
k = (i & 0x07) | 0x40;
} else {
k = i;
}
- outb(k, tmport++);
- tmport = dev->ioport[0] + 0x1b;
- if (dev->chip_ver == 4) {
- outb(0x01, tmport);
- } else {
- outb(0x00, tmport);
- }
-wait_rdyok:
- tmport = dev->ioport[0] + 0x18;
- outb(0x09, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
- tmport -= 0x08;
- k = inb(tmport);
- if (k != 0x16) {
- if ((k == 0x85) || (k == 0x42)) {
- continue;
- }
- tmport = dev->ioport[0] + 0x10;
- outb(0x41, tmport);
- goto wait_rdyok;
- }
+ atp_writeb_io(dev, 0, 0x15, k);
+ if (wide_chip)
+ atp_writeb_io(dev, 0, 0x1b, 0x01);
+ else
+ atp_writeb_io(dev, 0, 0x1b, 0x00);
+ do {
+ atp_writeb_io(dev, 0, 0x18, 0x09);
+
+ while ((atp_readb_io(dev, 0, 0x1f) & 0x80) == 0x00)
+ cpu_relax();
+ k = atp_readb_io(dev, 0, 0x17);
+ if ((k == 0x85) || (k == 0x42))
+ break;
+ if (k != 0x16)
+ atp_writeb_io(dev, 0, 0x10, 0x41);
+ } while (k != 0x16);
+ if ((k == 0x85) || (k == 0x42))
+ continue;
assignid_map |= m;
}
- tmport = dev->ioport[0] + 0x02;
- outb(0x7f, tmport);
- tmport = dev->ioport[0] + 0x1b;
- outb(0x02, tmport);
+ atp_writeb_io(dev, 0, 0x02, 0x7f);
+ atp_writeb_io(dev, 0, 0x1b, 0x02);
- outb(0, 0x80);
+ udelay(2);
val = 0x0080; /* bsy */
- tmport = dev->ioport[0] + 0x1c;
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
val |= 0x0040; /* sel */
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
val |= 0x0004; /* msg */
- outw(val, tmport);
- inb(0x80); /* 2 deskew delay(45ns*2=90ns) */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2); /* 2 deskew delay(45ns*2=90ns) */
val &= 0x007f; /* no bsy */
- outw(val, tmport);
+ atp_writew_io(dev, 0, 0x1c, val);
mdelay(128);
val &= 0x00fb; /* after 1ms no msg */
- outw(val, tmport);
-wait_nomsg:
- if ((inb(tmport) & 0x04) != 0) {
- goto wait_nomsg;
- }
- outb(1, 0x80);
+ atp_writew_io(dev, 0, 0x1c, val);
+ while ((atp_readb_io(dev, 0, 0x1c) & 0x04) != 0)
+ ;
+ udelay(2);
udelay(100);
- for (n = 0; n < 0x30000; n++) {
- if ((inb(tmport) & 0x80) != 0) { /* bsy ? */
- goto wait_io;
- }
- }
- goto TCM_SYNC;
-wait_io:
- for (n = 0; n < 0x30000; n++) {
- if ((inb(tmport) & 0x81) == 0x0081) {
- goto wait_io1;
- }
- }
- goto TCM_SYNC;
-wait_io1:
- inb(0x80);
- val |= 0x8003; /* io,cd,db7 */
- outw(val, tmport);
- inb(0x80);
- val &= 0x00bf; /* no sel */
- outw(val, tmport);
- outb(2, 0x80);
-TCM_SYNC:
+ for (n = 0; n < 0x30000; n++)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x80) != 0) /* bsy ? */
+ break;
+ if (n < 0x30000)
+ for (n = 0; n < 0x30000; n++)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x81) == 0x0081) {
+ udelay(2);
+ val |= 0x8003; /* io,cd,db7 */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2);
+ val &= 0x00bf; /* no sel */
+ atp_writew_io(dev, 0, 0x1c, val);
+ udelay(2);
+ break;
+ }
+ while (1) {
/*
* The funny division into multiple delays is to accomodate
* arches like ARM where udelay() multiplies its argument by
@@ -1183,55 +1088,48 @@ TCM_SYNC:
*/
mdelay(2);
udelay(48);
- if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */
- outw(0, tmport--);
- outb(0, tmport);
- tmport = dev->ioport[0] + 0x15;
- outb(0, tmport);
- tmport += 0x03;
- outb(0x09, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
+ if ((atp_readb_io(dev, 0, 0x1c) & 0x80) == 0x00) { /* bsy ? */
+ atp_writew_io(dev, 0, 0x1c, 0);
+ atp_writeb_io(dev, 0, 0x1b, 0);
+ atp_writeb_io(dev, 0, 0x15, 0);
+ atp_writeb_io(dev, 0, 0x18, 0x09);
+ while ((atp_readb_io(dev, 0, 0x1f) & 0x80) == 0)
cpu_relax();
- tmport -= 0x08;
- inb(tmport);
+ atp_readb_io(dev, 0, 0x17);
return;
}
val &= 0x00ff; /* synchronization */
val |= 0x3f00;
fun_scam(dev, &val);
- outb(3, 0x80);
+ udelay(2);
val &= 0x00ff; /* isolation */
val |= 0x2000;
fun_scam(dev, &val);
- outb(4, 0x80);
+ udelay(2);
i = 8;
j = 0;
-TCM_ID:
- if ((inw(tmport) & 0x2000) == 0) {
- goto TCM_ID;
- }
- outb(5, 0x80);
- val &= 0x00ff; /* get ID_STRING */
- val |= 0x2000;
- k = fun_scam(dev, &val);
- if ((k & 0x03) == 0) {
- goto TCM_5;
- }
- mbuf[j] <<= 0x01;
- mbuf[j] &= 0xfe;
- if ((k & 0x02) != 0) {
- mbuf[j] |= 0x01;
- }
- i--;
- if (i > 0) {
- goto TCM_ID;
+
+ while (1) {
+ if ((atp_readw_io(dev, 0, 0x1c) & 0x2000) == 0)
+ continue;
+ udelay(2);
+ val &= 0x00ff; /* get ID_STRING */
+ val |= 0x2000;
+ k = fun_scam(dev, &val);
+ if ((k & 0x03) == 0)
+ break;
+ mbuf[j] <<= 0x01;
+ mbuf[j] &= 0xfe;
+ if ((k & 0x02) != 0)
+ mbuf[j] |= 0x01;
+ i--;
+ if (i > 0)
+ continue;
+ j++;
+ i = 8;
}
- j++;
- i = 8;
- goto TCM_ID;
-TCM_5: /* isolation complete.. */
+ /* isolation complete.. */
/* mbuf[32]=0;
printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
i = 15;
@@ -1239,33 +1137,33 @@ TCM_5: /* isolation complete.. */
if ((j & 0x20) != 0) { /* bit5=1:ID up to 7 */
i = 7;
}
- if ((j & 0x06) == 0) { /* IDvalid? */
- goto G2Q5;
- }
- k = mbuf[1];
-small_id:
- m = 1;
- m <<= k;
- if ((m & assignid_map) == 0) {
- goto G2Q_QUIN;
- }
- if (k > 0) {
- k--;
- goto small_id;
- }
-G2Q5: /* srch from max acceptable ID# */
- k = i; /* max acceptable ID# */
-G2Q_LP:
- m = 1;
- m <<= k;
- if ((m & assignid_map) == 0) {
- goto G2Q_QUIN;
+ if ((j & 0x06) != 0) { /* IDvalid? */
+ k = mbuf[1];
+ while (1) {
+ m = 1;
+ m <<= k;
+ if ((m & assignid_map) == 0)
+ break;
+ if (k > 0)
+ k--;
+ else
+ break;
+ }
}
- if (k > 0) {
- k--;
- goto G2Q_LP;
+ if ((m & assignid_map) != 0) { /* srch from max acceptable ID# */
+ k = i; /* max acceptable ID# */
+ while (1) {
+ m = 1;
+ m <<= k;
+ if ((m & assignid_map) == 0)
+ break;
+ if (k > 0)
+ k--;
+ else
+ break;
+ }
}
-G2Q_QUIN: /* k=binID#, */
+ /* k=binID#, */
assignid_map |= m;
if (k < 8) {
quintet[0] = 0x38; /* 1st dft ID<8 */
@@ -1284,1227 +1182,6 @@ G2Q_QUIN: /* k=binID#, */
val |= m;
fun_scam(dev, &val);
- goto TCM_SYNC;
-
-}
-
-static void is870(struct atp_unit *dev, unsigned int wkport)
-{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n;
- unsigned short int m;
- static unsigned char mbuf[512];
- static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
- static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
- static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e };
- static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
- static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
-
- tmport = wkport + 0x3a;
- outb((unsigned char) (inb(tmport) | 0x10), tmport);
-
- for (i = 0; i < 16; i++) {
- if ((dev->chip_ver != 4) && (i > 7)) {
- break;
- }
- m = 1;
- m = m << i;
- if ((m & dev->active_id[0]) != 0) {
- continue;
- }
- if (i == dev->host_id[0]) {
- printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]);
- continue;
- }
- tmport = wkport + 0x1b;
- if (dev->chip_ver == 4) {
- outb(0x01, tmport);
- } else {
- outb(0x00, tmport);
- }
- tmport = wkport + 1;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- j = i;
- if ((j & 0x08) != 0) {
- j = (j & 0x07) | 0x40;
- }
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- dev->active_id[0] |= m;
-
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x04;
- outb(0x00, tmport);
-
-phase_cmd:
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- tmport = wkport + 0x10;
- outb(0x41, tmport);
- goto phase_cmd;
- }
-sel_ok:
- tmport = wkport + 3;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- tmport = wkport + 0x1b;
- if (dev->chip_ver == 4)
- outb(0x00, tmport);
-
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- j = 0;
-rd_inq_data:
- k = inb(tmport);
- if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
- goto rd_inq_data;
- }
- if ((k & 0x80) == 0) {
- goto rd_inq_data;
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x16) {
- goto inq_ok;
- }
- tmport = wkport + 0x10;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x16) {
- goto sel_ok;
- }
-inq_ok:
- mbuf[36] = 0;
- printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
- dev->id[0][i].devtype = mbuf[0];
- rmb = mbuf[1];
- n = mbuf[7];
- if (dev->chip_ver != 4) {
- goto not_wide;
- }
- if ((mbuf[7] & 0x60) == 0) {
- goto not_wide;
- }
- if ((dev->global_map[0] & 0x20) == 0) {
- goto not_wide;
- }
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 3;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_wide:
- j = 0;
- tmport = wkport + 0x14;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto try_wide;
- }
- continue;
-widep_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_in:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-widep_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto widep_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto widep_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto widep_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto not_wide;
- }
- if (mbuf[1] != 0x02) {
- goto not_wide;
- }
- if (mbuf[2] != 0x03) {
- goto not_wide;
- }
- if (mbuf[3] != 0x01) {
- goto not_wide;
- }
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
-not_wide:
- if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
- goto set_sync;
- }
- continue;
-set_sync:
- tmport = wkport + 0x1b;
- j = 0;
- if ((m & dev->wide_id[0]) != 0) {
- j |= 0x01;
- }
- outb(j, tmport);
- tmport = wkport + 3;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_sync:
- j = 0;
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- if ((m & dev->wide_id[0]) != 0) {
- outb(synw[j++], tmport);
- } else {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synu[j++], tmport);
- } else {
- outb(synn[j++], tmport);
- }
- }
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto try_sync;
- }
- continue;
-phase_outs:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_ins:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-phase_ins1:
- j = inb(tmport);
- if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto phase_ins1;
- }
- if ((j & 0x80) == 0x00) {
- goto phase_ins1;
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_cmds:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
-tar_dcons:
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- continue;
- }
- if (mbuf[0] != 0x01) {
- continue;
- }
- if (mbuf[1] != 0x03) {
- continue;
- }
- if (mbuf[4] == 0x00) {
- continue;
- }
- if (mbuf[3] > 0x64) {
- continue;
- }
- if (mbuf[4] > 0x0c) {
- mbuf[4] = 0x0c;
- }
- dev->id[0][i].devsp = mbuf[4];
- if ((mbuf[3] < 0x0d) && (rmb == 0)) {
- j = 0xa0;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x1a) {
- j = 0x20;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x33) {
- j = 0x40;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x4c) {
- j = 0x50;
- goto set_syn_ok;
- }
- j = 0x60;
-set_syn_ok:
- dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
- }
- tmport = wkport + 0x3a;
- outb((unsigned char) (inb(tmport) & 0xef), tmport);
-}
-
-static void is880(struct atp_unit *dev, unsigned int wkport)
-{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n, lvdmode;
- unsigned short int m;
- static unsigned char mbuf[512];
- static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
- static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
- static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
- static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
- unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
- static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
- static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
-
- lvdmode = inb(wkport + 0x3f) & 0x40;
-
- for (i = 0; i < 16; i++) {
- m = 1;
- m = m << i;
- if ((m & dev->active_id[0]) != 0) {
- continue;
- }
- if (i == dev->host_id[0]) {
- printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]);
- continue;
- }
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x41;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- j = i;
- if ((j & 0x08) != 0) {
- j = (j & 0x07) | 0x40;
- }
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- dev->active_id[0] |= m;
-
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
-
-phase_cmd:
- tmport = wkport + 0x58;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- tmport = wkport + 0x50;
- outb(0x41, tmport);
- goto phase_cmd;
- }
-sel_ok:
- tmport = wkport + 0x43;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
- tmport = wkport + 0x5b;
- outb(0x00, tmport);
- tmport = wkport + 0x58;
- outb(0x08, tmport);
- tmport += 0x07;
- j = 0;
-rd_inq_data:
- k = inb(tmport);
- if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
- goto rd_inq_data;
- }
- if ((k & 0x80) == 0) {
- goto rd_inq_data;
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x16) {
- goto inq_ok;
- }
- tmport = wkport + 0x50;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x16)
- goto sel_ok;
-
-inq_ok:
- mbuf[36] = 0;
- printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
- dev->id[0][i].devtype = mbuf[0];
- rmb = mbuf[1];
- n = mbuf[7];
- if ((mbuf[7] & 0x60) == 0) {
- goto not_wide;
- }
- if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) {
- goto not_wide;
- }
- if (lvdmode == 0) {
- goto chg_wide;
- }
- if (dev->sp[0][i] != 0x04) // force u2
- {
- goto chg_wide;
- }
-
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
-
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_u3:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(u3[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto try_u3;
- }
- continue;
-u3p_out:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto u3p_out;
- }
- continue;
-u3p_in:
- tmport = wkport + 0x54;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-u3p_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto u3p_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto u3p_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto u3p_in;
- }
- if (j == 0x0a) {
- goto u3p_cmd;
- }
- if (j == 0x0e) {
- goto u3p_out;
- }
- continue;
-u3p_cmd:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto u3p_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto chg_wide;
- }
- if (mbuf[1] != 0x06) {
- goto chg_wide;
- }
- if (mbuf[2] != 0x04) {
- goto chg_wide;
- }
- if (mbuf[3] == 0x09) {
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
- dev->id[0][i].devsp = 0xce;
- continue;
- }
-chg_wide:
- tmport = wkport + 0x5b;
- outb(0x01, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
- continue;
-
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_wide:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto try_wide;
- }
- continue;
-widep_out:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_in:
- tmport = wkport + 0x54;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-widep_in1:
- j = inb(tmport);
- if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto widep_in1;
- }
- if ((j & 0x80) == 0x00) {
- goto widep_in1;
- }
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto widep_in;
- }
- if (j == 0x0a) {
- goto widep_cmd;
- }
- if (j == 0x0e) {
- goto widep_out;
- }
- continue;
-widep_cmd:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- if (j == 0x4e) {
- goto widep_out;
- }
- continue;
- }
- if (mbuf[0] != 0x01) {
- goto not_wide;
- }
- if (mbuf[1] != 0x02) {
- goto not_wide;
- }
- if (mbuf[2] != 0x03) {
- goto not_wide;
- }
- if (mbuf[3] != 0x01) {
- goto not_wide;
- }
- m = 1;
- m = m << i;
- dev->wide_id[0] |= m;
-not_wide:
- if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
- m = 1;
- m = m << i;
- if ((dev->async[0] & m) != 0) {
- goto set_sync;
- }
- }
- continue;
-set_sync:
- if (dev->sp[0][i] == 0x02) {
- synu[4] = 0x0c;
- synuw[4] = 0x0c;
- } else {
- if (dev->sp[0][i] >= 0x03) {
- synu[4] = 0x0a;
- synuw[4] = 0x0a;
- }
- }
- tmport = wkport + 0x5b;
- j = 0;
- if ((m & dev->wide_id[0]) != 0) {
- j |= 0x01;
- }
- outb(j, tmport);
- tmport = wkport + 0x43;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[0][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
- continue;
- }
- while (inb(tmport) != 0x8e)
- cpu_relax();
-
-try_sync:
- j = 0;
- tmport = wkport + 0x54;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- if ((m & dev->wide_id[0]) != 0) {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synuw[j++], tmport);
- } else {
- outb(synw[j++], tmport);
- }
- } else {
- if ((m & dev->ultra_map[0]) != 0) {
- outb(synu[j++], tmport);
- } else {
- outb(synn[j++], tmport);
- }
- }
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport) & 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto try_sync;
- }
- continue;
-phase_outs:
- tmport = wkport + 0x58;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
- }
- tmport -= 0x08;
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_ins:
- tmport = wkport + 0x54;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
- k = 0;
-phase_ins1:
- j = inb(tmport);
- if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
- goto phase_ins1;
- }
- if ((j & 0x80) == 0x00) {
- goto phase_ins1;
- }
- tmport -= 0x08;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- j = inb(tmport);
- if (j == 0x85) {
- goto tar_dcons;
- }
- j &= 0x0f;
- if (j == 0x0f) {
- goto phase_ins;
- }
- if (j == 0x0a) {
- goto phase_cmds;
- }
- if (j == 0x0e) {
- goto phase_outs;
- }
- continue;
-phase_cmds:
- tmport = wkport + 0x50;
- outb(0x30, tmport);
-tar_dcons:
- tmport = wkport + 0x54;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
- cpu_relax();
-
- tmport -= 0x08;
- j = inb(tmport);
- if (j != 0x16) {
- continue;
- }
- if (mbuf[0] != 0x01) {
- continue;
- }
- if (mbuf[1] != 0x03) {
- continue;
- }
- if (mbuf[4] == 0x00) {
- continue;
- }
- if (mbuf[3] > 0x64) {
- continue;
- }
- if (mbuf[4] > 0x0e) {
- mbuf[4] = 0x0e;
- }
- dev->id[0][i].devsp = mbuf[4];
- if (mbuf[3] < 0x0c) {
- j = 0xb0;
- goto set_syn_ok;
- }
- if ((mbuf[3] < 0x0d) && (rmb == 0)) {
- j = 0xa0;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x1a) {
- j = 0x20;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x33) {
- j = 0x40;
- goto set_syn_ok;
- }
- if (mbuf[3] < 0x4c) {
- j = 0x50;
- goto set_syn_ok;
- }
- j = 0x60;
-set_syn_ok:
- dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
}
}
@@ -2560,491 +1237,345 @@ static int atp870u_init_tables(struct Scsi_Host *host)
return 0;
}
-/* return non-zero on detection */
-static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void atp_set_host_id(struct atp_unit *atp, u8 c, u8 host_id)
{
- unsigned char k, m, c;
- unsigned long flags;
- unsigned int base_io, tmport, error,n;
- unsigned char host_id;
- struct Scsi_Host *shpnt = NULL;
- struct atp_unit *atpdev, *p;
- unsigned char setupdata[2][16];
- int count = 0;
+ atp_writeb_io(atp, c, 0, host_id | 0x08);
+ atp_writeb_io(atp, c, 0x18, 0);
+ while ((atp_readb_io(atp, c, 0x1f) & 0x80) == 0)
+ mdelay(1);
+ atp_readb_io(atp, c, 0x17);
+ atp_writeb_io(atp, c, 1, 8);
+ atp_writeb_io(atp, c, 2, 0x7f);
+ atp_writeb_io(atp, c, 0x11, 0x20);
+}
- atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL);
- if (!atpdev)
- return -ENOMEM;
+static void atp870_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, host_id;
+ u8 scam_on;
+ bool wide_chip =
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7610 &&
+ pdev->revision == 4) ||
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7612UW) ||
+ (pdev->device == PCI_DEVICE_ID_ARTOP_AEC7612SUW);
+
+ pci_read_config_byte(pdev, 0x49, &host_id);
+
+ dev_info(&pdev->dev, "ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+
+ atpdev->ioport[0] = shpnt->io_port;
+ atpdev->pciport[0] = shpnt->io_port + 0x20;
+ host_id &= 0x07;
+ atpdev->host_id[0] = host_id;
+ scam_on = atp_readb_pci(atpdev, 0, 2);
+ atpdev->global_map[0] = atp_readb_base(atpdev, 0x2d);
+ atpdev->ultra_map[0] = atp_readw_base(atpdev, 0x2e);
+
+ if (atpdev->ultra_map[0] == 0) {
+ scam_on = 0x00;
+ atpdev->global_map[0] = 0x20;
+ atpdev->ultra_map[0] = 0xffff;
+ }
- if (pci_enable_device(pdev))
- goto err_eio;
+ if (pdev->revision > 0x07) /* check if atp876 chip */
+ atp_writeb_base(atpdev, 0x3e, 0x00); /* enable terminator */
+
+ k = (atp_readb_base(atpdev, 0x3a) & 0xf3) | 0x10;
+ atp_writeb_base(atpdev, 0x3a, k);
+ atp_writeb_base(atpdev, 0x3a, k & 0xdf);
+ mdelay(32);
+ atp_writeb_base(atpdev, 0x3a, k);
+ mdelay(32);
+ atp_set_host_id(atpdev, 0, host_id);
+
+ tscam(shpnt, wide_chip, scam_on);
+ atp_writeb_base(atpdev, 0x3a, atp_readb_base(atpdev, 0x3a) | 0x10);
+ atp_is(atpdev, 0, wide_chip, 0);
+ atp_writeb_base(atpdev, 0x3a, atp_readb_base(atpdev, 0x3a) & 0xef);
+ atp_writeb_base(atpdev, 0x3b, atp_readb_base(atpdev, 0x3b) | 0x20);
+ shpnt->max_id = wide_chip ? 16 : 8;
+ shpnt->this_id = host_id;
+}
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
- } else {
- printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
- goto err_eio;
- }
+static void atp880_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, m, host_id;
+ unsigned int n;
- /*
- * It's probably easier to weed out some revisions like
- * this than via the PCI device table
- */
- if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
- atpdev->chip_ver = pdev->revision;
- if (atpdev->chip_ver < 2)
- goto err_eio;
- }
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
- switch (ent->device) {
- case PCI_DEVICE_ID_ARTOP_AEC7612UW:
- case PCI_DEVICE_ID_ARTOP_AEC7612SUW:
- case ATP880_DEVID1:
- case ATP880_DEVID2:
- case ATP885_DEVID:
- atpdev->chip_ver = 0x04;
- default:
- break;
- }
- base_io = pci_resource_start(pdev, 0);
- base_io &= 0xfffffff8;
-
- if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
- atpdev->chip_ver = pdev->revision;
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
-
- host_id = inb(base_io + 0x39);
- host_id >>= 0x04;
-
- printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
- " IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
- atpdev->ioport[0] = base_io + 0x40;
- atpdev->pciport[0] = base_io + 0x28;
- atpdev->dev_id = ent->device;
- atpdev->host_id[0] = host_id;
-
- tmport = base_io + 0x22;
- atpdev->scam_on = inb(tmport);
- tmport += 0x13;
- atpdev->global_map[0] = inb(tmport);
- tmport += 0x07;
- atpdev->ultra_map[0] = inw(tmport);
-
- n = 0x3f09;
-next_fblk_880:
- if (n >= 0x4000)
- goto flash_ok_880;
+ atpdev->ioport[0] = shpnt->io_port + 0x40;
+ atpdev->pciport[0] = shpnt->io_port + 0x28;
+
+ host_id = atp_readb_base(atpdev, 0x39) >> 4;
+ dev_info(&pdev->dev, "ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+ atpdev->host_id[0] = host_id;
+
+ atpdev->global_map[0] = atp_readb_base(atpdev, 0x35);
+ atpdev->ultra_map[0] = atp_readw_base(atpdev, 0x3c);
+
+ n = 0x3f09;
+ while (n < 0x4000) {
m = 0;
- outw(n, base_io + 0x34);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- if (inb(base_io + 0x30) == 0xff)
- goto flash_ok_880;
-
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ if (atp_readb_base(atpdev, 0x30) == 0xff)
+ break;
+
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
- outw(n, base_io + 0x34);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
+ atp_writew_base(atpdev, 0x34, n);
n += 0x0002;
- atpdev->sp[0][m++] = inb(base_io + 0x30);
- atpdev->sp[0][m++] = inb(base_io + 0x31);
- atpdev->sp[0][m++] = inb(base_io + 0x32);
- atpdev->sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x30);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x31);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x32);
+ atpdev->sp[0][m++] = atp_readb_base(atpdev, 0x33);
n += 0x0018;
- goto next_fblk_880;
-flash_ok_880:
- outw(0, base_io + 0x34);
- atpdev->ultra_map[0] = 0;
- atpdev->async[0] = 0;
+ }
+ atp_writew_base(atpdev, 0x34, 0);
+ atpdev->ultra_map[0] = 0;
+ atpdev->async[0] = 0;
+ for (k = 0; k < 16; k++) {
+ n = 1 << k;
+ if (atpdev->sp[0][k] > 1)
+ atpdev->ultra_map[0] |= n;
+ else
+ if (atpdev->sp[0][k] == 0)
+ atpdev->async[0] |= n;
+ }
+ atpdev->async[0] = ~(atpdev->async[0]);
+ atp_writeb_base(atpdev, 0x35, atpdev->global_map[0]);
+
+ k = atp_readb_base(atpdev, 0x38) & 0x80;
+ atp_writeb_base(atpdev, 0x38, k);
+ atp_writeb_base(atpdev, 0x3b, 0x20);
+ mdelay(32);
+ atp_writeb_base(atpdev, 0x3b, 0);
+ mdelay(32);
+ atp_readb_io(atpdev, 0, 0x1b);
+ atp_readb_io(atpdev, 0, 0x17);
+
+ atp_set_host_id(atpdev, 0, host_id);
+
+ tscam(shpnt, true, atp_readb_base(atpdev, 0x22));
+ atp_is(atpdev, 0, true, atp_readb_base(atpdev, 0x3f) & 0x40);
+ atp_writeb_base(atpdev, 0x38, 0xb0);
+ shpnt->max_id = 16;
+ shpnt->this_id = host_id;
+}
+
+static void atp885_init(struct Scsi_Host *shpnt)
+{
+ struct atp_unit *atpdev = shost_priv(shpnt);
+ struct pci_dev *pdev = atpdev->pdev;
+ unsigned char k, m, c;
+ unsigned int n;
+ unsigned char setupdata[2][16];
+
+ dev_info(&pdev->dev, "ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%lx, IRQ:%d.\n",
+ shpnt->io_port, shpnt->irq);
+
+ atpdev->ioport[0] = shpnt->io_port + 0x80;
+ atpdev->ioport[1] = shpnt->io_port + 0xc0;
+ atpdev->pciport[0] = shpnt->io_port + 0x40;
+ atpdev->pciport[1] = shpnt->io_port + 0x50;
+
+ c = atp_readb_base(atpdev, 0x29);
+ atp_writeb_base(atpdev, 0x29, c | 0x04);
+
+ n = 0x1f80;
+ while (n < 0x2000) {
+ atp_writew_base(atpdev, 0x3c, n);
+ if (atp_readl_base(atpdev, 0x38) == 0xffffffff)
+ break;
+ for (m = 0; m < 2; m++) {
+ atpdev->global_map[m] = 0;
+ for (k = 0; k < 4; k++) {
+ atp_writew_base(atpdev, 0x3c, n++);
+ ((unsigned long *)&setupdata[m][0])[k] = atp_readl_base(atpdev, 0x38);
+ }
+ for (k = 0; k < 4; k++) {
+ atp_writew_base(atpdev, 0x3c, n++);
+ ((unsigned long *)&atpdev->sp[m][0])[k] = atp_readl_base(atpdev, 0x38);
+ }
+ n += 8;
+ }
+ }
+ c = atp_readb_base(atpdev, 0x29);
+ atp_writeb_base(atpdev, 0x29, c & 0xfb);
+ for (c = 0; c < 2; c++) {
+ atpdev->ultra_map[c] = 0;
+ atpdev->async[c] = 0;
for (k = 0; k < 16; k++) {
- n = 1;
- n = n << k;
- if (atpdev->sp[0][k] > 1) {
- atpdev->ultra_map[0] |= n;
- } else {
- if (atpdev->sp[0][k] == 0)
- atpdev->async[0] |= n;
- }
- }
- atpdev->async[0] = ~(atpdev->async[0]);
- outb(atpdev->global_map[0], base_io + 0x35);
-
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
-
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(*atpdev));
- if (atp870u_init_tables(shpnt) < 0) {
- printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
- goto unregister;
- }
-
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp880i", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
- goto free_tables;
- }
-
- spin_lock_irqsave(shpnt->host_lock, flags);
- tmport = base_io + 0x38;
- k = inb(tmport) & 0x80;
- outb(k, tmport);
- tmport += 0x03;
- outb(0x20, tmport);
- mdelay(32);
- outb(0, tmport);
- mdelay(32);
- tmport = base_io + 0x5b;
- inb(tmport);
- tmport -= 0x04;
- inb(tmport);
- tmport = base_io + 0x40;
- outb((host_id | 0x08), tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
- mdelay(1);
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0x41;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x51;
- outb(0x20, tmport);
-
- tscam(shpnt);
- is880(p, base_io);
- tmport = base_io + 0x38;
- outb(0xb0, tmport);
- shpnt->max_id = 16;
- shpnt->this_id = host_id;
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
- } else if (ent->device == ATP885_DEVID) {
- printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n"
- , base_io, pdev->irq);
-
- atpdev->pdev = pdev;
- atpdev->dev_id = ent->device;
- atpdev->baseport = base_io;
- atpdev->ioport[0] = base_io + 0x80;
- atpdev->ioport[1] = base_io + 0xc0;
- atpdev->pciport[0] = base_io + 0x40;
- atpdev->pciport[1] = base_io + 0x50;
-
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
-
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(struct atp_unit));
- if (atp870u_init_tables(shpnt) < 0)
- goto unregister;
-
-#ifdef ED_DBGP
- printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
-#endif
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
- goto free_tables;
+ n = 1 << k;
+ if (atpdev->sp[c][k] > 1)
+ atpdev->ultra_map[c] |= n;
+ else
+ if (atpdev->sp[c][k] == 0)
+ atpdev->async[c] |= n;
+ }
+ atpdev->async[c] = ~(atpdev->async[c]);
+
+ if (atpdev->global_map[c] == 0) {
+ k = setupdata[c][1];
+ if ((k & 0x40) != 0)
+ atpdev->global_map[c] |= 0x20;
+ k &= 0x07;
+ atpdev->global_map[c] |= k;
+ if ((setupdata[c][2] & 0x04) != 0)
+ atpdev->global_map[c] |= 0x08;
+ atpdev->host_id[c] = setupdata[c][0] & 0x07;
}
-
- spin_lock_irqsave(shpnt->host_lock, flags);
-
- c=inb(base_io + 0x29);
- outb((c | 0x04),base_io + 0x29);
-
- n=0x1f80;
-next_fblk_885:
- if (n >= 0x2000) {
- goto flash_ok_885;
- }
- outw(n,base_io + 0x3c);
- if (inl(base_io + 0x38) == 0xffffffff) {
- goto flash_ok_885;
- }
- for (m=0; m < 2; m++) {
- p->global_map[m]= 0;
- for (k=0; k < 4; k++) {
- outw(n++,base_io + 0x3c);
- ((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38);
- }
- for (k=0; k < 4; k++) {
- outw(n++,base_io + 0x3c);
- ((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38);
- }
- n += 8;
- }
- goto next_fblk_885;
-flash_ok_885:
-#ifdef ED_DBGP
- printk( "Flash Read OK\n");
-#endif
- c=inb(base_io + 0x29);
- outb((c & 0xfb),base_io + 0x29);
- for (c=0;c < 2;c++) {
- p->ultra_map[c]=0;
- p->async[c] = 0;
- for (k=0; k < 16; k++) {
- n=1;
- n = n << k;
- if (p->sp[c][k] > 1) {
- p->ultra_map[c] |= n;
- } else {
- if (p->sp[c][k] == 0) {
- p->async[c] |= n;
- }
- }
- }
- p->async[c] = ~(p->async[c]);
-
- if (p->global_map[c] == 0) {
- k=setupdata[c][1];
- if ((k & 0x40) != 0)
- p->global_map[c] |= 0x20;
- k &= 0x07;
- p->global_map[c] |= k;
- if ((setupdata[c][2] & 0x04) != 0)
- p->global_map[c] |= 0x08;
- p->host_id[c] = setupdata[c][0] & 0x07;
- }
- }
-
- k = inb(base_io + 0x28) & 0x8f;
- k |= 0x10;
- outb(k, base_io + 0x28);
- outb(0x80, base_io + 0x41);
- outb(0x80, base_io + 0x51);
- mdelay(100);
- outb(0, base_io + 0x41);
- outb(0, base_io + 0x51);
- mdelay(1000);
- inb(base_io + 0x9b);
- inb(base_io + 0x97);
- inb(base_io + 0xdb);
- inb(base_io + 0xd7);
- tmport = base_io + 0x80;
- k=p->host_id[0];
- if (k > 7)
- k = (k & 0x07) | 0x40;
- k |= 0x08;
- outb(k, tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0)
- cpu_relax();
-
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0x81;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x91;
- outb(0x20, tmport);
-
- tmport = base_io + 0xc0;
- k=p->host_id[1];
- if (k > 7)
- k = (k & 0x07) | 0x40;
- k |= 0x08;
- outb(k, tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0)
- cpu_relax();
+ }
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 0xc1;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0xd1;
- outb(0x20, tmport);
-
- tscam_885();
- printk(KERN_INFO " Scanning Channel A SCSI Device ...\n");
- is885(p, base_io + 0x80, 0);
- printk(KERN_INFO " Scanning Channel B SCSI Device ...\n");
- is885(p, base_io + 0xc0, 1);
-
- k = inb(base_io + 0x28) & 0xcf;
- k |= 0xc0;
- outb(k, base_io + 0x28);
- k = inb(base_io + 0x1f) | 0x80;
- outb(k, base_io + 0x1f);
- k = inb(base_io + 0x29) | 0x01;
- outb(k, base_io + 0x29);
-#ifdef ED_DBGP
- //printk("atp885: atp_host[0] 0x%p\n", atp_host[0]);
-#endif
- shpnt->max_id = 16;
- shpnt->max_lun = (p->global_map[0] & 0x07) + 1;
- shpnt->max_channel = 1;
- shpnt->this_id = p->host_id[0];
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0xff; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
-
- } else {
- error = pci_read_config_byte(pdev, 0x49, &host_id);
+ k = atp_readb_base(atpdev, 0x28) & 0x8f;
+ k |= 0x10;
+ atp_writeb_base(atpdev, 0x28, k);
+ atp_writeb_pci(atpdev, 0, 1, 0x80);
+ atp_writeb_pci(atpdev, 1, 1, 0x80);
+ mdelay(100);
+ atp_writeb_pci(atpdev, 0, 1, 0);
+ atp_writeb_pci(atpdev, 1, 1, 0);
+ mdelay(1000);
+ atp_readb_io(atpdev, 0, 0x1b);
+ atp_readb_io(atpdev, 0, 0x17);
+ atp_readb_io(atpdev, 1, 0x1b);
+ atp_readb_io(atpdev, 1, 0x17);
+
+ k = atpdev->host_id[0];
+ if (k > 7)
+ k = (k & 0x07) | 0x40;
+ atp_set_host_id(atpdev, 0, k);
+
+ k = atpdev->host_id[1];
+ if (k > 7)
+ k = (k & 0x07) | 0x40;
+ atp_set_host_id(atpdev, 1, k);
+
+ mdelay(600); /* this delay used to be called tscam_885() */
+ dev_info(&pdev->dev, "Scanning Channel A SCSI Device ...\n");
+ atp_is(atpdev, 0, true, atp_readb_io(atpdev, 0, 0x1b) >> 7);
+ atp_writeb_io(atpdev, 0, 0x16, 0x80);
+ dev_info(&pdev->dev, "Scanning Channel B SCSI Device ...\n");
+ atp_is(atpdev, 1, true, atp_readb_io(atpdev, 1, 0x1b) >> 7);
+ atp_writeb_io(atpdev, 1, 0x16, 0x80);
+ k = atp_readb_base(atpdev, 0x28) & 0xcf;
+ k |= 0xc0;
+ atp_writeb_base(atpdev, 0x28, k);
+ k = atp_readb_base(atpdev, 0x1f) | 0x80;
+ atp_writeb_base(atpdev, 0x1f, k);
+ k = atp_readb_base(atpdev, 0x29) | 0x01;
+ atp_writeb_base(atpdev, 0x29, k);
+ shpnt->max_id = 16;
+ shpnt->max_lun = (atpdev->global_map[0] & 0x07) + 1;
+ shpnt->max_channel = 1;
+ shpnt->this_id = atpdev->host_id[0];
+}
- printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
- "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
+/* return non-zero on detection */
+static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct Scsi_Host *shpnt = NULL;
+ struct atp_unit *atpdev;
+ int err;
- atpdev->ioport[0] = base_io;
- atpdev->pciport[0] = base_io + 0x20;
- atpdev->dev_id = ent->device;
- host_id &= 0x07;
- atpdev->host_id[0] = host_id;
- tmport = base_io + 0x22;
- atpdev->scam_on = inb(tmport);
- tmport += 0x0b;
- atpdev->global_map[0] = inb(tmport++);
- atpdev->ultra_map[0] = inw(tmport);
+ if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610 && pdev->revision < 2) {
+ dev_err(&pdev->dev, "ATP850S chips (AEC6710L/F cards) are not supported.\n");
+ return -ENODEV;
+ }
- if (atpdev->ultra_map[0] == 0) {
- atpdev->scam_on = 0x00;
- atpdev->global_map[0] = 0x20;
- atpdev->ultra_map[0] = 0xffff;
- }
+ err = pci_enable_device(pdev);
+ if (err)
+ goto fail;
- shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
- if (!shpnt)
- goto err_nomem;
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
+ err = -EIO;
+ goto disable_device;
+ }
- p = (struct atp_unit *)&shpnt->hostdata;
-
- atpdev->host = shpnt;
- atpdev->pdev = pdev;
- pci_set_drvdata(pdev, p);
- memcpy(p, atpdev, sizeof(*atpdev));
- if (atp870u_init_tables(shpnt) < 0)
- goto unregister;
-
- if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870i", shpnt)) {
- printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
- goto free_tables;
- }
-
- spin_lock_irqsave(shpnt->host_lock, flags);
- if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */
- tmport = base_io + 0x3e;
- outb(0x00, tmport);
- }
-
- tmport = base_io + 0x3a;
- k = (inb(tmport) & 0xf3) | 0x10;
- outb(k, tmport);
- outb((k & 0xdf), tmport);
- mdelay(32);
- outb(k, tmport);
- mdelay(32);
- tmport = base_io;
- outb((host_id | 0x08), tmport);
- tmport += 0x18;
- outb(0, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0)
- mdelay(1);
-
- tmport -= 0x08;
- inb(tmport);
- tmport = base_io + 1;
- outb(8, tmport++);
- outb(0x7f, tmport);
- tmport = base_io + 0x11;
- outb(0x20, tmport);
-
- tscam(shpnt);
- is870(p, base_io);
- tmport = base_io + 0x3a;
- outb((inb(tmport) & 0xef), tmport);
- tmport++;
- outb((inb(tmport) | 0x20), tmport);
- if (atpdev->chip_ver == 4)
- shpnt->max_id = 16;
- else
- shpnt->max_id = 8;
- shpnt->this_id = host_id;
- shpnt->unique_id = base_io;
- shpnt->io_port = base_io;
- shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */
- shpnt->irq = pdev->irq;
- }
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- if(ent->device==ATP885_DEVID) {
- if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
- if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- } else {
- if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */
- goto request_io_fail;
- }
- count++;
- if (scsi_add_host(shpnt, &pdev->dev))
- goto scsi_add_fail;
- scsi_scan_host(shpnt);
-#ifdef ED_DBGP
- printk("atp870u_prob : exit\n");
-#endif
- return 0;
+ err = pci_request_regions(pdev, "atp870u");
+ if (err)
+ goto disable_device;
+ pci_set_master(pdev);
+
+ err = -ENOMEM;
+ shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+ if (!shpnt)
+ goto release_region;
+
+ atpdev = shost_priv(shpnt);
+
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
+ pci_set_drvdata(pdev, atpdev);
+
+ shpnt->io_port = pci_resource_start(pdev, 0);
+ shpnt->io_port &= 0xfffffff8;
+ shpnt->n_io_port = pci_resource_len(pdev, 0);
+ atpdev->baseport = shpnt->io_port;
+ shpnt->unique_id = shpnt->io_port;
+ shpnt->irq = pdev->irq;
+
+ err = atp870u_init_tables(shpnt);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to allocate tables for Acard controller\n");
+ goto unregister;
+ }
-scsi_add_fail:
- printk("atp870u_prob:scsi_add_fail\n");
- if(ent->device==ATP885_DEVID) {
- release_region(base_io, 0xff);
- } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
- release_region(base_io, 0x60);
- } else {
- release_region(base_io, 0x40);
+ if (is880(atpdev))
+ atp880_init(shpnt);
+ else if (is885(atpdev))
+ atp885_init(shpnt);
+ else
+ atp870_init(shpnt);
+
+ err = request_irq(shpnt->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to allocate IRQ %d.\n", shpnt->irq);
+ goto free_tables;
}
-request_io_fail:
- printk("atp870u_prob:request_io_fail\n");
- free_irq(pdev->irq, shpnt);
+
+ err = scsi_add_host(shpnt, &pdev->dev);
+ if (err)
+ goto scsi_add_fail;
+ scsi_scan_host(shpnt);
+
+ return 0;
+
+scsi_add_fail:
+ free_irq(shpnt->irq, shpnt);
free_tables:
- printk("atp870u_prob:free_table\n");
atp870u_free_tables(shpnt);
unregister:
- printk("atp870u_prob:unregister\n");
scsi_host_put(shpnt);
- return -1;
-err_eio:
- kfree(atpdev);
- return -EIO;
-err_nomem:
- kfree(atpdev);
- return -ENOMEM;
+release_region:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+fail:
+ return err;
}
/* The abort command does not leave the device in a clean state where
@@ -3055,7 +1586,6 @@ static int atp870u_abort(struct scsi_cmnd * SCpnt)
{
unsigned char j, k, c;
struct scsi_cmnd *workrequ;
- unsigned int tmport;
struct atp_unit *dev;
struct Scsi_Host *host;
host = SCpnt->device->host;
@@ -3065,18 +1595,13 @@ static int atp870u_abort(struct scsi_cmnd * SCpnt)
printk(" atp870u: abort Channel = %x \n", c);
printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]);
printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]);
- tmport = dev->ioport[c];
for (j = 0; j < 0x18; j++) {
- printk(" r%2x=%2x", j, inb(tmport++));
+ printk(" r%2x=%2x", j, atp_readb_io(dev, c, j));
}
- tmport += 0x04;
- printk(" r1c=%2x", inb(tmport));
- tmport += 0x03;
- printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd[c]);
- tmport= dev->pciport[c];
- printk(" d00=%2x", inb(tmport));
- tmport += 0x02;
- printk(" d02=%2x", inb(tmport));
+ printk(" r1c=%2x", atp_readb_io(dev, c, 0x1c));
+ printk(" r1f=%2x in_snd=%2x ", atp_readb_io(dev, c, 0x1f), dev->in_snd[c]);
+ printk(" d00=%2x", atp_readb_pci(dev, c, 0x00));
+ printk(" d02=%2x", atp_readb_pci(dev, c, 0x02));
for(j=0;j<16;j++) {
if (dev->id[c][j].curr_req != NULL) {
workrequ = dev->id[c][j].curr_req;
@@ -3136,12 +1661,10 @@ static void atp870u_remove (struct pci_dev *pdev)
scsi_remove_host(pshost);
- printk(KERN_INFO "free_irq : %d\n",pshost->irq);
free_irq(pshost->irq, pshost);
- release_region(pshost->io_port, pshost->n_io_port);
- printk(KERN_INFO "atp870u_free_tables : %p\n",pshost);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
atp870u_free_tables(pshost);
- printk(KERN_INFO "scsi_host_put : %p\n",pshost);
scsi_host_put(pshost);
}
MODULE_LICENSE("GPL");
@@ -3185,52 +1708,26 @@ static struct pci_driver atp870u_driver = {
.remove = atp870u_remove,
};
-static int __init atp870u_init(void)
-{
-#ifdef ED_DBGP
- printk("atp870u_init: Entry\n");
-#endif
- return pci_register_driver(&atp870u_driver);
-}
-
-static void __exit atp870u_exit(void)
-{
-#ifdef ED_DBGP
- printk("atp870u_exit: Entry\n");
-#endif
- pci_unregister_driver(&atp870u_driver);
-}
-
-static void tscam_885(void)
-{
- unsigned char i;
-
- for (i = 0; i < 0x2; i++) {
- mdelay(300);
- }
- return;
-}
-
-
+module_pci_driver(atp870u_driver);
-static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
+static void atp_is(struct atp_unit *dev, unsigned char c, bool wide_chip, unsigned char lvdmode)
{
- unsigned int tmport;
- unsigned char i, j, k, rmb, n, lvdmode;
+ unsigned char i, j, k, rmb, n;
unsigned short int m;
static unsigned char mbuf[512];
- static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6};
- static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
- static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
- unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e};
- static unsigned char synw[6] = {0x80, 1, 3, 1, 0x19, 0x0e};
- unsigned char synuw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e};
- static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0};
- static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
-
- lvdmode=inb(wkport + 0x1b) >> 7;
+ static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
+ static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
+ static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+ unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+ static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+ static unsigned char synw_870[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
+ unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+ static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
+ static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
for (i = 0; i < 16; i++) {
+ if (!wide_chip && (i > 7))
+ break;
m = 1;
m = m << i;
if ((m & dev->active_id[c]) != 0) {
@@ -3240,192 +1737,172 @@ static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[c]);
continue;
}
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x01;
- outb(0x08, tmport++);
- outb(0x7f, tmport++);
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
-
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
+ atp_writeb_io(dev, c, 0x1b, wide_chip ? 0x01 : 0x00);
+ atp_writeb_io(dev, c, 1, 0x08);
+ atp_writeb_io(dev, c, 2, 0x7f);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
j = i;
if ((j & 0x08) != 0) {
j = (j & 0x07) | 0x40;
}
- outb(j, tmport);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x15, j);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
- while ((inb(tmport) & 0x80) == 0x00)
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
dev->active_id[c] |= m;
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ if (is885(dev) || is880(dev))
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ else /* result of is870() merge - is this a bug? */
+ atp_writeb_io(dev, c, 0x04, 0x00);
phase_cmd:
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
- tmport = wkport + 0x10;
- outb(0x41, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x41);
goto phase_cmd;
}
sel_ok:
- tmport = wkport + 0x03;
- outb(inqd[0], tmport++);
- outb(inqd[1], tmport++);
- outb(inqd[2], tmport++);
- outb(inqd[3], tmport++);
- outb(inqd[4], tmport++);
- outb(inqd[5], tmport);
- tmport += 0x07;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(inqd[6], tmport++);
- outb(inqd[7], tmport++);
- tmport += 0x03;
- outb(inqd[8], tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 3, inqd[0]);
+ atp_writeb_io(dev, c, 4, inqd[1]);
+ atp_writeb_io(dev, c, 5, inqd[2]);
+ atp_writeb_io(dev, c, 6, inqd[3]);
+ atp_writeb_io(dev, c, 7, inqd[4]);
+ atp_writeb_io(dev, c, 8, inqd[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, inqd[6]);
+ atp_writeb_io(dev, c, 0x14, inqd[7]);
+ atp_writeb_io(dev, c, 0x18, inqd[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
- tmport = wkport + 0x1b;
- outb(0x00, tmport);
- tmport = wkport + 0x18;
- outb(0x08, tmport);
- tmport += 0x07;
+
+ if (wide_chip)
+ atp_writeb_io(dev, c, 0x1b, 0x00);
+
+ atp_writeb_io(dev, c, 0x18, 0x08);
j = 0;
rd_inq_data:
- k = inb(tmport);
+ k = atp_readb_io(dev, c, 0x1f);
if ((k & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[j++] = inb(tmport);
- tmport += 0x06;
+ mbuf[j++] = atp_readb_io(dev, c, 0x19);
goto rd_inq_data;
}
if ((k & 0x80) == 0) {
goto rd_inq_data;
}
- tmport -= 0x08;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x16) {
goto inq_ok;
}
- tmport = wkport + 0x10;
- outb(0x46, tmport);
- tmport += 0x02;
- outb(0, tmport++);
- outb(0, tmport++);
- outb(0, tmport++);
- tmport += 0x03;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x10, 0x46);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, 0);
+ atp_writeb_io(dev, c, 0x14, 0);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if (inb(tmport) != 0x16) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x16)
goto sel_ok;
- }
+
inq_ok:
mbuf[36] = 0;
- printk( KERN_INFO" ID: %2d %s\n", i, &mbuf[8]);
+ printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]);
dev->id[c][i].devtype = mbuf[0];
rmb = mbuf[1];
n = mbuf[7];
+ if (!wide_chip)
+ goto not_wide;
if ((mbuf[7] & 0x60) == 0) {
goto not_wide;
}
- if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) {
- goto not_wide;
+ if (is885(dev) || is880(dev)) {
+ if ((i < 8) && ((dev->global_map[c] & 0x20) == 0))
+ goto not_wide;
+ } else { /* result of is870() merge - is this a bug? */
+ if ((dev->global_map[c] & 0x20) == 0)
+ goto not_wide;
}
if (lvdmode == 0) {
- goto chg_wide;
- }
- if (dev->sp[c][i] != 0x04) { // force u2
- goto chg_wide;
- }
-
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ goto chg_wide;
+ }
+ if (dev->sp[c][i] != 0x04) // force u2
+ {
+ goto chg_wide;
+ }
+
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_u3:
j = 0;
- tmport = wkport + 0x14;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(u3[j++], tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x14, 0x09);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, u3[j++]);
cpu_relax();
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3437,19 +1914,13 @@ try_u3:
}
continue;
u3p_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, 0);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3461,25 +1932,19 @@ u3p_out:
}
continue;
u3p_in:
- tmport = wkport + 0x14;
- outb(0x09, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x14, 0x09);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
u3p_in1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto u3p_in1;
}
if ((j & 0x80) == 0x00) {
goto u3p_in1;
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto u3p_in;
}
@@ -3491,16 +1956,13 @@ u3p_in1:
}
continue;
u3p_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00);
- tmport -= 0x08;
- j = inb(tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
if (j == 0x4e) {
goto u3p_out;
@@ -3527,54 +1989,44 @@ u3p_cmd:
continue;
}
chg_wide:
- tmport = wkport + 0x1b;
- outb(0x01, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x1b, 0x01);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_wide:
j = 0;
- tmport = wkport + 0x14;
- outb(0x05, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(wide[j++], tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x14, 0x05);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, wide[j++]);
cpu_relax();
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3586,19 +2038,13 @@ try_wide:
}
continue;
widep_out:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
- outb(0, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0)
+ atp_writeb_io(dev, c, 0x19, 0);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3610,25 +2056,19 @@ widep_out:
}
continue;
widep_in:
- tmport = wkport + 0x14;
- outb(0xff, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ atp_writeb_io(dev, c, 0x14, 0xff);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
widep_in1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto widep_in1;
}
if ((j & 0x80) == 0x00) {
goto widep_in1;
}
- tmport -= 0x08;
- j = inb(tmport) & 0x0f;
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto widep_in;
}
@@ -3640,17 +2080,14 @@ widep_in1:
}
continue;
widep_cmd:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x10, 0x30);
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
if (j == 0x4e) {
goto widep_out;
@@ -3673,88 +2110,81 @@ widep_cmd:
m = m << i;
dev->wide_id[c] |= m;
not_wide:
- if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) ||
- ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
+ if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) || ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
m = 1;
m = m << i;
if ((dev->async[c] & m) != 0) {
- goto set_sync;
+ goto set_sync;
}
}
continue;
set_sync:
- if (dev->sp[c][i] == 0x02) {
- synu[4]=0x0c;
- synuw[4]=0x0c;
+ if ((!is885(dev) && !is880(dev)) || (dev->sp[c][i] == 0x02)) {
+ synu[4] = 0x0c;
+ synuw[4] = 0x0c;
} else {
- if (dev->sp[c][i] >= 0x03) {
- synu[4]=0x0a;
- synuw[4]=0x0a;
- }
+ if (dev->sp[c][i] >= 0x03) {
+ synu[4] = 0x0a;
+ synuw[4] = 0x0a;
+ }
}
- tmport = wkport + 0x1b;
j = 0;
if ((m & dev->wide_id[c]) != 0) {
j |= 0x01;
}
- outb(j, tmport);
- tmport = wkport + 0x03;
- outb(satn[0], tmport++);
- outb(satn[1], tmport++);
- outb(satn[2], tmport++);
- outb(satn[3], tmport++);
- outb(satn[4], tmport++);
- outb(satn[5], tmport++);
- tmport += 0x06;
- outb(0, tmport);
- tmport += 0x02;
- outb(dev->id[c][i].devsp, tmport++);
- outb(0, tmport++);
- outb(satn[6], tmport++);
- outb(satn[7], tmport++);
- tmport += 0x03;
- outb(satn[8], tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x1b, j);
+ atp_writeb_io(dev, c, 3, satn[0]);
+ atp_writeb_io(dev, c, 4, satn[1]);
+ atp_writeb_io(dev, c, 5, satn[2]);
+ atp_writeb_io(dev, c, 6, satn[3]);
+ atp_writeb_io(dev, c, 7, satn[4]);
+ atp_writeb_io(dev, c, 8, satn[5]);
+ atp_writeb_io(dev, c, 0x0f, 0);
+ atp_writeb_io(dev, c, 0x11, dev->id[c][i].devsp);
+ atp_writeb_io(dev, c, 0x12, 0);
+ atp_writeb_io(dev, c, 0x13, satn[6]);
+ atp_writeb_io(dev, c, 0x14, satn[7]);
+ atp_writeb_io(dev, c, 0x18, satn[8]);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+
+ if (atp_readb_io(dev, c, 0x17) != 0x11 && atp_readb_io(dev, c, 0x17) != 0x8e)
continue;
- }
- while (inb(tmport) != 0x8e)
+
+ while (atp_readb_io(dev, c, 0x17) != 0x8e)
cpu_relax();
+
try_sync:
j = 0;
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
-
- while ((inb(tmport) & 0x80) == 0) {
- if ((inb(tmport) & 0x01) != 0) {
- tmport -= 0x06;
+ atp_writeb_io(dev, c, 0x14, 0x06);
+ atp_writeb_io(dev, c, 0x18, 0x20);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0) {
if ((m & dev->wide_id[c]) != 0) {
- if ((m & dev->ultra_map[c]) != 0) {
- outb(synuw[j++], tmport);
- } else {
- outb(synw[j++], tmport);
- }
+ if (is885(dev) || is880(dev)) {
+ if ((m & dev->ultra_map[c]) != 0) {
+ atp_writeb_io(dev, c, 0x19, synuw[j++]);
+ } else {
+ atp_writeb_io(dev, c, 0x19, synw[j++]);
+ }
+ } else
+ atp_writeb_io(dev, c, 0x19, synw_870[j++]);
} else {
if ((m & dev->ultra_map[c]) != 0) {
- outb(synu[j++], tmport);
+ atp_writeb_io(dev, c, 0x19, synu[j++]);
} else {
- outb(synn[j++], tmport);
+ atp_writeb_io(dev, c, 0x19, synn[j++]);
}
}
- tmport += 0x06;
}
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00)
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00)
cpu_relax();
- j = inb(tmport) & 0x0f;
+
+ j = atp_readb_io(dev, c, 0x17) & 0x0f;
if (j == 0x0f) {
goto phase_ins;
}
@@ -3766,19 +2196,13 @@ try_sync:
}
continue;
phase_outs:
- tmport = wkport + 0x18;
- outb(0x20, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00) {
- if ((inb(tmport) & 0x01) != 0x00) {
- tmport -= 0x06;
- outb(0x00, tmport);
- tmport += 0x06;
- }
+ atp_writeb_io(dev, c, 0x18, 0x20);
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00) {
+ if ((atp_readb_io(dev, c, 0x1f) & 0x01) != 0x00)
+ atp_writeb_io(dev, c, 0x19, 0x00);
cpu_relax();
}
- tmport -= 0x08;
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x85) {
goto tar_dcons;
}
@@ -3794,26 +2218,25 @@ phase_outs:
}
continue;
phase_ins:
- tmport = wkport + 0x14;
- outb(0x06, tmport);
- tmport += 0x04;
- outb(0x20, tmport);
- tmport += 0x07;
+ if (is885(dev) || is880(dev))
+ atp_writeb_io(dev, c, 0x14, 0x06);
+ else
+ atp_writeb_io(dev, c, 0x14, 0xff);
+ atp_writeb_io(dev, c, 0x18, 0x20);
k = 0;
phase_ins1:
- j = inb(tmport);
+ j = atp_readb_io(dev, c, 0x1f);
if ((j & 0x01) != 0x00) {
- tmport -= 0x06;
- mbuf[k++] = inb(tmport);
- tmport += 0x06;
+ mbuf[k++] = atp_readb_io(dev, c, 0x19);
goto phase_ins1;
}
if ((j & 0x80) == 0x00) {
goto phase_ins1;
}
- tmport -= 0x08;
- while ((inb(tmport) & 0x80) == 0x00);
- j = inb(tmport);
+
+ while ((atp_readb_io(dev, c, 0x17) & 0x80) == 0x00);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j == 0x85) {
goto tar_dcons;
}
@@ -3829,18 +2252,15 @@ phase_ins1:
}
continue;
phase_cmds:
- tmport = wkport + 0x10;
- outb(0x30, tmport);
+ atp_writeb_io(dev, c, 0x10, 0x30);
tar_dcons:
- tmport = wkport + 0x14;
- outb(0x00, tmport);
- tmport += 0x04;
- outb(0x08, tmport);
- tmport += 0x07;
- while ((inb(tmport) & 0x80) == 0x00)
+ atp_writeb_io(dev, c, 0x14, 0x00);
+ atp_writeb_io(dev, c, 0x18, 0x08);
+
+ while ((atp_readb_io(dev, c, 0x1f) & 0x80) == 0x00)
cpu_relax();
- tmport -= 0x08;
- j = inb(tmport);
+
+ j = atp_readb_io(dev, c, 0x17);
if (j != 0x16) {
continue;
}
@@ -3856,14 +2276,21 @@ tar_dcons:
if (mbuf[3] > 0x64) {
continue;
}
- if (mbuf[4] > 0x0e) {
- mbuf[4] = 0x0e;
+ if (is885(dev) || is880(dev)) {
+ if (mbuf[4] > 0x0e) {
+ mbuf[4] = 0x0e;
+ }
+ } else {
+ if (mbuf[4] > 0x0c) {
+ mbuf[4] = 0x0c;
+ }
}
dev->id[c][i].devsp = mbuf[4];
- if (mbuf[3] < 0x0c){
- j = 0xb0;
- goto set_syn_ok;
- }
+ if (is885(dev) || is880(dev))
+ if (mbuf[3] < 0x0c) {
+ j = 0xb0;
+ goto set_syn_ok;
+ }
if ((mbuf[3] < 0x0d) && (rmb == 0)) {
j = 0xa0;
goto set_syn_ok;
@@ -3881,16 +2308,10 @@ tar_dcons:
goto set_syn_ok;
}
j = 0x60;
- set_syn_ok:
+set_syn_ok:
dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j;
-#ifdef ED_DBGP
+#ifdef ED_DBGP
printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
#endif
}
- tmport = wkport + 0x16;
- outb(0x80, tmport);
}
-
-module_init(atp870u_init);
-module_exit(atp870u_exit);
-
diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
index 5cf62566a..9b839b1e8 100644
--- a/drivers/scsi/atp870u.h
+++ b/drivers/scsi/atp870u.h
@@ -26,22 +26,18 @@ struct atp_unit
unsigned long baseport;
unsigned long ioport[2];
unsigned long pciport[2];
- unsigned long irq;
unsigned char last_cmd[2];
unsigned char in_snd[2];
unsigned char in_int[2];
unsigned char quhd[2];
unsigned char quend[2];
unsigned char global_map[2];
- unsigned char chip_ver;
- unsigned char scam_on;
unsigned char host_id[2];
unsigned int working[2];
unsigned short wide_id[2];
unsigned short active_id[2];
unsigned short ultra_map[2];
unsigned short async[2];
- unsigned short dev_id;
unsigned char sp[2][16];
unsigned char r1f[2][16];
struct scsi_cmnd *quereq[2][qcnt];
diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig
index 4e7cad272..bad5f32e1 100644
--- a/drivers/scsi/be2iscsi/Kconfig
+++ b/drivers/scsi/be2iscsi/Kconfig
@@ -3,6 +3,7 @@ config BE2ISCSI
depends on PCI && SCSI && NET
select SCSI_ISCSI_ATTRS
select ISCSI_BOOT_SYSFS
+ select IRQ_POLL
help
This driver implements the iSCSI functionality for Emulex
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 77f992e74..a41c6432f 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -20,7 +20,7 @@
#include <linux/pci.h>
#include <linux/if_vlan.h>
-#include <linux/blk-iopoll.h>
+#include <linux/irq_poll.h>
#define FW_VER_LEN 32
#define MCC_Q_LEN 128
#define MCC_CQ_LEN 256
@@ -101,7 +101,7 @@ struct be_eq_obj {
struct beiscsi_hba *phba;
struct be_queue_info *cq;
struct work_struct work_cqs; /* Work Item */
- struct blk_iopoll iopoll;
+ struct irq_poll iopoll;
};
struct be_mcc_obj {
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index b7087ba69..022e87b62 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -1292,9 +1292,9 @@ static void beiscsi_flush_cq(struct beiscsi_hba *phba)
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
+ irq_poll_disable(&pbe_eq->iopoll);
beiscsi_process_cq(pbe_eq);
- blk_iopoll_enable(&pbe_eq->iopoll);
+ irq_poll_enable(&pbe_eq->iopoll);
}
}
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index fe0c5143f..cb9072a84 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -910,8 +910,7 @@ static irqreturn_t be_isr_msix(int irq, void *dev_id)
num_eq_processed = 0;
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
& EQE_VALID_MASK) {
- if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
- blk_iopoll_sched(&pbe_eq->iopoll);
+ irq_poll_sched(&pbe_eq->iopoll);
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
queue_tail_inc(eq);
@@ -972,8 +971,7 @@ static irqreturn_t be_isr(int irq, void *dev_id)
spin_unlock_irqrestore(&phba->isr_lock, flags);
num_mcceq_processed++;
} else {
- if (!blk_iopoll_sched_prep(&pbe_eq->iopoll))
- blk_iopoll_sched(&pbe_eq->iopoll);
+ irq_poll_sched(&pbe_eq->iopoll);
num_ioeq_processed++;
}
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
@@ -2295,7 +2293,7 @@ void beiscsi_process_all_cqs(struct work_struct *work)
hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
}
-static int be_iopoll(struct blk_iopoll *iop, int budget)
+static int be_iopoll(struct irq_poll *iop, int budget)
{
unsigned int ret;
struct beiscsi_hba *phba;
@@ -2306,7 +2304,7 @@ static int be_iopoll(struct blk_iopoll *iop, int budget)
pbe_eq->cq_count += ret;
if (ret < budget) {
phba = pbe_eq->phba;
- blk_iopoll_complete(iop);
+ irq_poll_complete(iop);
beiscsi_log(phba, KERN_INFO,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
"BM_%d : rearm pbe_eq->q.id =%d\n",
@@ -5293,7 +5291,7 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba,
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
+ irq_poll_disable(&pbe_eq->iopoll);
}
if (unload_state == BEISCSI_CLEAN_UNLOAD) {
@@ -5579,9 +5577,8 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget,
be_iopoll);
- blk_iopoll_enable(&pbe_eq->iopoll);
}
i = (phba->msix_enabled) ? i : 0;
@@ -5752,9 +5749,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget,
+ irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget,
be_iopoll);
- blk_iopoll_enable(&pbe_eq->iopoll);
}
i = (phba->msix_enabled) ? i : 0;
@@ -5795,7 +5791,7 @@ free_blkenbld:
destroy_workqueue(phba->wq);
for (i = 0; i < phba->num_cpus; i++) {
pbe_eq = &phwi_context->be_eq[i];
- blk_iopoll_disable(&pbe_eq->iopoll);
+ irq_poll_disable(&pbe_eq->iopoll);
}
free_twq:
beiscsi_clean_port(phba);
diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h
index 4ad7e368b..0e119d838 100644
--- a/drivers/scsi/bfa/bfa.h
+++ b/drivers/scsi/bfa/bfa.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
index e3f67b097..2ea0db4b6 100644
--- a/drivers/scsi/bfa/bfa_core.c
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_cs.h b/drivers/scsi/bfa/bfa_cs.h
index 91a8aa394..da9cf655b 100644
--- a/drivers/scsi/bfa/bfa_cs.h
+++ b/drivers/scsi/bfa/bfa_cs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_defs.h b/drivers/scsi/bfa/bfa_defs.h
index 877b86dd2..5dc3782d6 100644
--- a/drivers/scsi/bfa/bfa_defs.h
+++ b/drivers/scsi/bfa/bfa_defs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_defs_fcs.h b/drivers/scsi/bfa/bfa_defs_fcs.h
index 06f0a163c..5815a9045 100644
--- a/drivers/scsi/bfa/bfa_defs_fcs.h
+++ b/drivers/scsi/bfa/bfa_defs_fcs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h
index 638f441ff..e81707f93 100644
--- a/drivers/scsi/bfa/bfa_defs_svc.h
+++ b/drivers/scsi/bfa/bfa_defs_svc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h
index 64069a0a3..18b7304d6 100644
--- a/drivers/scsi/bfa/bfa_fc.h
+++ b/drivers/scsi/bfa/bfa_fc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c
index dce787f6c..b8dadc9cc 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.c
+++ b/drivers/scsi/bfa/bfa_fcbuild.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h
index 03c753d1e..b109a8813 100644
--- a/drivers/scsi/bfa/bfa_fcbuild.h
+++ b/drivers/scsi/bfa/bfa_fcbuild.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
index d7385d1d9..20982e7cd 100644
--- a/drivers/scsi/bfa/bfa_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h
index e693af6e5..e93921dec 100644
--- a/drivers/scsi/bfa/bfa_fcpim.h
+++ b/drivers/scsi/bfa/bfa_fcpim.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
index 0f1945595..1e7e139d7 100644
--- a/drivers/scsi/bfa/bfa_fcs.c
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h
index 42bcb9704..06dc215ea 100644
--- a/drivers/scsi/bfa/bfa_fcs.h
+++ b/drivers/scsi/bfa/bfa_fcs.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -633,7 +634,7 @@ void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim,
/*
* HBA Attribute Block : BFA internal representation. Note : Some variable
- * sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based
+ * sizes have been trimmed to suit BFA For Ex : Model will be "QLogic ". Based
* on this the size has been reduced to 16 bytes from the standard's 64 bytes.
*/
struct bfa_fcs_fdmi_hba_attr_s {
diff --git a/drivers/scsi/bfa/bfa_fcs_fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c
index 6dc7926a3..4f089d76a 100644
--- a/drivers/scsi/bfa/bfa_fcs_fcpim.c
+++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
index ff75ef891..7733ad530 100644
--- a/drivers/scsi/bfa/bfa_fcs_lport.c
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -2653,7 +2654,7 @@ bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi,
strncpy(hba_attr->node_sym_name.symname,
port->port_cfg.node_sym_name.symname, BFA_SYMNAME_MAXLEN);
- strcpy(hba_attr->vendor_info, "BROCADE");
+ strcpy(hba_attr->vendor_info, "QLogic");
hba_attr->num_ports =
cpu_to_be32(bfa_ioc_get_nports(&port->fcs->bfa->ioc));
hba_attr->fabric_name = port->fabric->lps->pr_nwwn;
diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c
index 2035b0d64..de50349a3 100644
--- a/drivers/scsi/bfa/bfa_fcs_rport.c
+++ b/drivers/scsi/bfa/bfa_fcs_rport.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
index ea24d4c6e..c4a0c0eb8 100644
--- a/drivers/scsi/bfa/bfa_hw_cb.c
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
index 637527f48..b0ff378de 100644
--- a/drivers/scsi/bfa/bfa_hw_ct.c
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
index 98f7e8cca..251e2ff8f 100644
--- a/drivers/scsi/bfa/bfa_ioc.c
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -2697,7 +2698,7 @@ bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc)
bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);
}
-#define BFA_MFG_NAME "Brocade"
+#define BFA_MFG_NAME "QLogic"
void
bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
struct bfa_adapter_attr_s *ad_attr)
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
index a38aafa03..713745da4 100644
--- a/drivers/scsi/bfa/bfa_ioc.h
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c
index 453c2f5b5..f1b80da29 100644
--- a/drivers/scsi/bfa/bfa_ioc_cb.c
+++ b/drivers/scsi/bfa/bfa_ioc_cb.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c
index bd53150e4..651a8fb93 100644
--- a/drivers/scsi/bfa/bfa_ioc_ct.c
+++ b/drivers/scsi/bfa/bfa_ioc_ct.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h
index a14c784ff..53135f21f 100644
--- a/drivers/scsi/bfa/bfa_modules.h
+++ b/drivers/scsi/bfa/bfa_modules.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_plog.h b/drivers/scsi/bfa/bfa_plog.h
index 1c9baa683..da570c0b8 100644
--- a/drivers/scsi/bfa/bfa_plog.h
+++ b/drivers/scsi/bfa/bfa_plog.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
index 8ea7697de..da1721e0d 100644
--- a/drivers/scsi/bfa/bfa_port.c
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_port.h b/drivers/scsi/bfa/bfa_port.h
index 2fcab6bc6..26dc1bf14 100644
--- a/drivers/scsi/bfa/bfa_port.h
+++ b/drivers/scsi/bfa/bfa_port.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c
index 625225f31..12de29217 100644
--- a/drivers/scsi/bfa/bfa_svc.c
+++ b/drivers/scsi/bfa/bfa_svc.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h
index ef0736599..ea2278bc7 100644
--- a/drivers/scsi/bfa/bfa_svc.h
+++ b/drivers/scsi/bfa/bfa_svc.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index f95adcadb..0e76e8669 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -128,13 +129,9 @@ MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for "
"boot port. Otherwise 10 secs in RHEL4 & 0 for "
"[RHEL5, SLES10, ESX40] Range[>0]");
module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts "
- "for Brocade-415/425/815/825 cards, default=0, "
- " Range[false:0|true:1]");
+MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts for QLogic-415/425/815/825 cards, default=0 Range[false:0|true:1]");
module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts "
- "if possible for Brocade-1010/1020/804/1007/902/1741 "
- "cards, default=0, Range[false:0|true:1]");
+MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts if possible for QLogic-1010/1020/804/1007/902/1741 cards, default=0, Range[false:0|true:1]");
module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1, "
"Range[false:0|true:1]");
@@ -836,8 +833,7 @@ bfad_drv_init(struct bfad_s *bfad)
printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n",
bfad->inst_no);
printk(KERN_WARNING
- "Not enough memory to attach all Brocade HBA ports, %s",
- "System may need more memory.\n");
+ "Not enough memory to attach all QLogic BR-series HBA ports. System may need more memory.\n");
return BFA_STATUS_FAILED;
}
@@ -1708,7 +1704,7 @@ bfad_init(void)
{
int error = 0;
- printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n",
+ pr_info("QLogic BR-series BFA FC/FCOE SCSI driver - version: %s\n",
BFAD_DRIVER_VERSION);
if (num_sgpgs > 0)
@@ -1815,6 +1811,6 @@ bfad_free_fwimg(void)
module_init(bfad_init);
module_exit(bfad_exit);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME);
-MODULE_AUTHOR("Brocade Communications Systems, Inc.");
+MODULE_DESCRIPTION("QLogic BR-series Fibre Channel HBA Driver" BFAD_PROTO_NAME);
+MODULE_AUTHOR("QLogic Corporation");
MODULE_VERSION(BFAD_DRIVER_VERSION);
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
index 40be670a1..13db3b7bc 100644
--- a/drivers/scsi/bfa/bfad_attr.c
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -750,65 +751,65 @@ bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
bfa_get_adapter_model(&bfad->bfa, model);
nports = bfa_get_nports(&bfad->bfa);
- if (!strcmp(model, "Brocade-425"))
+ if (!strcmp(model, "QLogic-425"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe dual port FC HBA");
- else if (!strcmp(model, "Brocade-825"))
+ "QLogic BR-series 4Gbps PCIe dual port FC HBA");
+ else if (!strcmp(model, "QLogic-825"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe dual port FC HBA");
- else if (!strcmp(model, "Brocade-42B"))
+ "QLogic BR-series 8Gbps PCIe dual port FC HBA");
+ else if (!strcmp(model, "QLogic-42B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe dual port FC HBA for HP");
- else if (!strcmp(model, "Brocade-82B"))
+ "QLogic BR-series 4Gbps PCIe dual port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-82B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe dual port FC HBA for HP");
- else if (!strcmp(model, "Brocade-1010"))
+ "QLogic BR-series 8Gbps PCIe dual port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-1010"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps single port CNA");
- else if (!strcmp(model, "Brocade-1020"))
+ "QLogic BR-series 10Gbps single port CNA");
+ else if (!strcmp(model, "QLogic-1020"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps dual port CNA");
- else if (!strcmp(model, "Brocade-1007"))
+ "QLogic BR-series 10Gbps dual port CNA");
+ else if (!strcmp(model, "QLogic-1007"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps CNA for IBM Blade Center");
- else if (!strcmp(model, "Brocade-415"))
+ "QLogic BR-series 10Gbps CNA for IBM Blade Center");
+ else if (!strcmp(model, "QLogic-415"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe single port FC HBA");
- else if (!strcmp(model, "Brocade-815"))
+ "QLogic BR-series 4Gbps PCIe single port FC HBA");
+ else if (!strcmp(model, "QLogic-815"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe single port FC HBA");
- else if (!strcmp(model, "Brocade-41B"))
+ "QLogic BR-series 8Gbps PCIe single port FC HBA");
+ else if (!strcmp(model, "QLogic-41B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 4Gbps PCIe single port FC HBA for HP");
- else if (!strcmp(model, "Brocade-81B"))
+ "QLogic BR-series 4Gbps PCIe single port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-81B"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps PCIe single port FC HBA for HP");
- else if (!strcmp(model, "Brocade-804"))
+ "QLogic BR-series 8Gbps PCIe single port FC HBA for HP");
+ else if (!strcmp(model, "QLogic-804"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 8Gbps FC HBA for HP Bladesystem C-class");
- else if (!strcmp(model, "Brocade-1741"))
+ "QLogic BR-series 8Gbps FC HBA for HP Bladesystem C-class");
+ else if (!strcmp(model, "QLogic-1741"))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps CNA for Dell M-Series Blade Servers");
- else if (strstr(model, "Brocade-1860")) {
+ "QLogic BR-series 10Gbps CNA for Dell M-Series Blade Servers");
+ else if (strstr(model, "QLogic-1860")) {
if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps single port CNA");
+ "QLogic BR-series 10Gbps single port CNA");
else if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe single port FC HBA");
+ "QLogic BR-series 16Gbps PCIe single port FC HBA");
else if (nports == 2 && bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 10Gbps dual port CNA");
+ "QLogic BR-series 10Gbps dual port CNA");
else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe dual port FC HBA");
- } else if (!strcmp(model, "Brocade-1867")) {
+ "QLogic BR-series 16Gbps PCIe dual port FC HBA");
+ } else if (!strcmp(model, "QLogic-1867")) {
if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe single port FC HBA for IBM");
+ "QLogic BR-series 16Gbps PCIe single port FC HBA for IBM");
else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc))
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
- "Brocade 16Gbps PCIe dual port FC HBA for IBM");
+ "QLogic BR-series 16Gbps PCIe dual port FC HBA for IBM");
} else
snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN,
"Invalid Model");
diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c
index 023b9d42a..d1ad0208d 100644
--- a/drivers/scsi/bfa/bfad_bsg.c
+++ b/drivers/scsi/bfa/bfad_bsg.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfad_bsg.h b/drivers/scsi/bfa/bfad_bsg.h
index 90abef691..917e140df 100644
--- a/drivers/scsi/bfa/bfad_bsg.h
+++ b/drivers/scsi/bfa/bfad_bsg.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index 74a307c0a..8dcd8c70c 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
index 8b97877d4..f9e862093 100644
--- a/drivers/scsi/bfa/bfad_drv.h
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -57,7 +58,7 @@
#ifdef BFA_DRIVER_VERSION
#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
#else
-#define BFAD_DRIVER_VERSION "3.2.23.0"
+#define BFAD_DRIVER_VERSION "3.2.25.0"
#endif
#define BFAD_PROTO_NAME FCPI_NAME
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 299c6f80d..6c805e13f 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -185,7 +186,7 @@ bfad_im_info(struct Scsi_Host *shost)
memset(bfa_buf, 0, sizeof(bfa_buf));
snprintf(bfa_buf, sizeof(bfa_buf),
- "Brocade FC/FCOE Adapter, " "hwpath: %s driver: %s",
+ "QLogic BR-series FC/FCOE Adapter, hwpath: %s driver: %s",
bfad->pci_name, BFAD_DRIVER_VERSION);
return bfa_buf;
@@ -271,6 +272,19 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
cmnd->host_scribble = NULL;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ /*
+ * bfa_itnim can be NULL if the port gets disconnected and the bfa
+ * and fcs layers have cleaned up their nexus with the targets and
+ * the same has not been cleaned up by the shim
+ */
+ if (bfa_itnim == NULL) {
+ bfa_tskim_free(tskim);
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+ "target reset, bfa_itnim is NULL\n");
+ rc = BFA_STATUS_FAILED;
+ goto out;
+ }
+
memset(&scsilun, 0, sizeof(scsilun));
bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
@@ -326,6 +340,19 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
cmnd->SCp.ptr = (char *)&wq;
cmnd->SCp.Status = 0;
bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ /*
+ * bfa_itnim can be NULL if the port gets disconnected and the bfa
+ * and fcs layers have cleaned up their nexus with the targets and
+ * the same has not been cleaned up by the shim
+ */
+ if (bfa_itnim == NULL) {
+ bfa_tskim_free(tskim);
+ BFA_LOG(KERN_ERR, bfad, bfa_log_level,
+ "lun reset, bfa_itnim is NULL\n");
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ rc = FAILED;
+ goto out;
+ }
int_to_scsilun(cmnd->device->lun, &scsilun);
bfa_tskim_start(tskim, bfa_itnim, scsilun,
FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
index f6c1023e5..836fdc221 100644
--- a/drivers/scsi/bfa/bfad_im.h
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h
index 9ef91f907..97600dcec 100644
--- a/drivers/scsi/bfa/bfi.h
+++ b/drivers/scsi/bfa/bfi.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfi_ms.h b/drivers/scsi/bfa/bfi_ms.h
index 1a3fe5ad5..ae5bfe039 100644
--- a/drivers/scsi/bfa/bfi_ms.h
+++ b/drivers/scsi/bfa/bfi_ms.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
diff --git a/drivers/scsi/bfa/bfi_reg.h b/drivers/scsi/bfa/bfi_reg.h
index 99133bcf5..fd5b87616 100644
--- a/drivers/scsi/bfa/bfi_reg.h
+++ b/drivers/scsi/bfa/bfi_reg.h
@@ -1,9 +1,10 @@
/*
- * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
+ * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
+ * Copyright (c) 2014- QLogic Corporation.
* All rights reserved
- * www.brocade.com
+ * www.qlogic.com
*
- * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) Version 2 as
@@ -16,7 +17,7 @@
*/
/*
- * bfi_reg.h ASIC register defines for all Brocade adapter ASICs
+ * bfi_reg.h ASIC register defines for all QLogic BR-series adapter ASICs
*/
#ifndef __BFI_REG_H__
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index 0e2bee937..e22a268fd 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(cxgb3i_snd_win, "TCP send window in bytes (default=128KB)");
static int cxgb3i_rx_credit_thres = 10 * 1024;
module_param(cxgb3i_rx_credit_thres, int, 0644);
-MODULE_PARM_DESC(rx_credit_thres,
+MODULE_PARM_DESC(cxgb3i_rx_credit_thres,
"RX credits return threshold in bytes (default=10KB)");
static unsigned int cxgb3i_max_connect = 8 * 1024;
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index c11cd193f..5ada9268a 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -165,6 +165,8 @@ struct afu {
struct sisl_host_map __iomem *host_map; /* MC host map */
struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */
+ struct kref mapcount;
+
ctx_hndl_t ctx_hndl; /* master's context handle */
u64 *hrrq_start;
u64 *hrrq_end;
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index 1e5bf0ca8..f6d90ce8f 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -368,6 +368,7 @@ out:
no_room:
afu->read_room = true;
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
rc = SCSI_MLQUEUE_HOST_BUSY;
goto out;
@@ -473,6 +474,16 @@ out:
return rc;
}
+static void afu_unmap(struct kref *ref)
+{
+ struct afu *afu = container_of(ref, struct afu, mapcount);
+
+ if (likely(afu->afu_map)) {
+ cxl_psa_unmap((void __iomem *)afu->afu_map);
+ afu->afu_map = NULL;
+ }
+}
+
/**
* cxlflash_driver_info() - information handler for this host driver
* @host: SCSI host associated with device.
@@ -503,6 +514,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
ulong lock_flags;
short lflag = 0;
int rc = 0;
+ int kref_got = 0;
dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
"cdb=(%08X-%08X-%08X-%08X)\n",
@@ -547,6 +559,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
goto out;
}
+ kref_get(&cfg->afu->mapcount);
+ kref_got = 1;
+
cmd->rcb.ctx_id = afu->ctx_hndl;
cmd->rcb.port_sel = port_sel;
cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
@@ -587,6 +602,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
}
out:
+ if (kref_got)
+ kref_put(&afu->mapcount, afu_unmap);
pr_devel("%s: returning rc=%d\n", __func__, rc);
return rc;
}
@@ -632,20 +649,36 @@ static void free_mem(struct cxlflash_cfg *cfg)
* @cfg: Internal structure associated with the host.
*
* Safe to call with AFU in a partially allocated/initialized state.
+ *
+ * Cleans up all state associated with the command queue, and unmaps
+ * the MMIO space.
+ *
+ * - complete() will take care of commands we initiated (they'll be checked
+ * in as part of the cleanup that occurs after the completion)
+ *
+ * - cmd_checkin() will take care of entries that we did not initiate and that
+ * have not (and will not) complete because they are sitting on a [now stale]
+ * hardware queue
*/
static void stop_afu(struct cxlflash_cfg *cfg)
{
int i;
struct afu *afu = cfg->afu;
+ struct afu_cmd *cmd;
if (likely(afu)) {
- for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
- complete(&afu->cmd[i].cevent);
+ for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
+ cmd = &afu->cmd[i];
+ complete(&cmd->cevent);
+ if (!atomic_read(&cmd->free))
+ cmd_checkin(cmd);
+ }
if (likely(afu->afu_map)) {
cxl_psa_unmap((void __iomem *)afu->afu_map);
afu->afu_map = NULL;
}
+ kref_put(&afu->mapcount, afu_unmap);
}
}
@@ -731,8 +764,8 @@ static void cxlflash_remove(struct pci_dev *pdev)
scsi_remove_host(cfg->host);
/* fall through */
case INIT_STATE_AFU:
- term_afu(cfg);
cancel_work_sync(&cfg->work_q);
+ term_afu(cfg);
case INIT_STATE_PCI:
pci_release_regions(cfg->dev);
pci_disable_device(pdev);
@@ -1108,7 +1141,7 @@ static const struct asyc_intr_info ainfo[] = {
{SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET},
{SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0},
{SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET},
- {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0},
+ {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET},
{SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR},
{SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST},
{SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0},
@@ -1316,6 +1349,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
__func__, port);
cfg->lr_state = LINK_RESET_REQUIRED;
cfg->lr_port = port;
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
}
@@ -1336,6 +1370,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
if (info->action & SCAN_HOST) {
atomic_inc(&cfg->scan_host_needed);
+ kref_get(&cfg->afu->mapcount);
schedule_work(&cfg->work_q);
}
}
@@ -1731,6 +1766,7 @@ static int init_afu(struct cxlflash_cfg *cfg)
rc = -ENOMEM;
goto err1;
}
+ kref_init(&afu->mapcount);
/* No byte reverse on reading afu_version or string will be backwards */
reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1765,8 +1801,7 @@ out:
return rc;
err2:
- cxl_psa_unmap((void __iomem *)afu->afu_map);
- afu->afu_map = NULL;
+ kref_put(&afu->mapcount, afu_unmap);
err1:
term_mc(cfg, UNDO_START);
goto out;
@@ -2274,6 +2309,7 @@ static struct scsi_host_template driver_template = {
* Device dependent values
*/
static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
+static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS };
/*
* PCI device binding table
@@ -2281,6 +2317,8 @@ static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
static struct pci_device_id cxlflash_pci_table[] = {
{PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
+ {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals},
{}
};
@@ -2339,6 +2377,7 @@ static void cxlflash_worker_thread(struct work_struct *work)
if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
scsi_scan_host(cfg->host);
+ kref_put(&afu->mapcount, afu_unmap);
}
/**
@@ -2585,8 +2624,7 @@ static struct pci_driver cxlflash_driver = {
*/
static int __init init_cxlflash(void)
{
- pr_info("%s: IBM Power CXL Flash Adapter: %s\n",
- __func__, CXLFLASH_DRIVER_DATE);
+ pr_info("%s: %s\n", __func__, CXLFLASH_ADAPTER_NAME);
cxlflash_list_init();
diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h
index 60324566c..0faed422c 100644
--- a/drivers/scsi/cxlflash/main.h
+++ b/drivers/scsi/cxlflash/main.h
@@ -22,10 +22,9 @@
#define CXLFLASH_NAME "cxlflash"
#define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter"
-#define CXLFLASH_DRIVER_DATE "(August 13, 2015)"
-#define PCI_DEVICE_ID_IBM_CORSA 0x04F0
-#define CXLFLASH_SUBS_DEV_ID 0x04F0
+#define PCI_DEVICE_ID_IBM_CORSA 0x04F0
+#define PCI_DEVICE_ID_IBM_FLASH_GT 0x0600
/* Since there is only one target, make it 0 */
#define CXLFLASH_TARGET 0
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index cac2e6a50..f4020dbb5 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -1372,7 +1372,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
}
ctx = cxl_dev_context_init(cfg->dev);
- if (unlikely(IS_ERR_OR_NULL(ctx))) {
+ if (IS_ERR_OR_NULL(ctx)) {
dev_err(dev, "%s: Could not initialize context %p\n",
__func__, ctx);
rc = -ENODEV;
@@ -1380,7 +1380,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev,
}
ctxid = cxl_process_element(ctx);
- if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+ if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
rc = -EPERM;
goto err2;
@@ -1500,7 +1500,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
struct afu *afu = cfg->afu;
ctx = cxl_dev_context_init(cfg->dev);
- if (unlikely(IS_ERR_OR_NULL(ctx))) {
+ if (IS_ERR_OR_NULL(ctx)) {
dev_err(dev, "%s: Could not initialize context %p\n",
__func__, ctx);
rc = -ENODEV;
@@ -1508,7 +1508,7 @@ static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi)
}
ctxid = cxl_process_element(ctx);
- if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) {
+ if (unlikely((ctxid >= MAX_CONTEXT) || (ctxid < 0))) {
dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid);
rc = -EPERM;
goto err1;
diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c
index a53f583e2..50f8e9300 100644
--- a/drivers/scsi/cxlflash/vlun.c
+++ b/drivers/scsi/cxlflash/vlun.c
@@ -1008,6 +1008,8 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
virt->last_lba = last_lba;
virt->rsrc_handle = rsrc_handle;
+ if (lli->port_sel == BOTH_PORTS)
+ virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE;
out:
if (likely(ctxi))
put_context(ctxi);
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index cc2773b5d..5a328bf81 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -22,7 +22,9 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>
@@ -58,8 +60,9 @@
#define ALUA_FAILOVER_TIMEOUT 60
#define ALUA_FAILOVER_RETRIES 5
-/* flags passed from user level */
+/* device handler flags */
#define ALUA_OPTIMIZE_STPG 1
+#define ALUA_RTPG_EXT_HDR_UNSUPP 2
struct alua_dh_data {
int group_id;
@@ -73,7 +76,6 @@ struct alua_dh_data {
int bufflen;
unsigned char transition_tmo;
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
- int senselen;
struct scsi_device *sdev;
activate_complete callback_fn;
void *callback_data;
@@ -83,7 +85,6 @@ struct alua_dh_data {
#define ALUA_POLICY_SWITCH_ALL 1
static char print_alua_state(int);
-static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
static int realloc_buffer(struct alua_dh_data *h, unsigned len)
{
@@ -131,93 +132,47 @@ static struct request *get_alua_req(struct scsi_device *sdev,
}
/*
- * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
- * @sdev: sdev the command should be sent to
- */
-static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
-{
- struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
-
- rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
- goto done;
-
- /* Prepare the command. */
- rq->cmd[0] = INQUIRY;
- rq->cmd[1] = 1;
- rq->cmd[2] = 0x83;
- rq->cmd[4] = h->bufflen;
- rq->cmd_len = COMMAND_SIZE(INQUIRY);
-
- rq->sense = h->sense;
- memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
-
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: evpd inquiry failed with %x\n",
- ALUA_DH_NAME, rq->errors);
- h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
- }
- blk_put_request(rq);
-done:
- return err;
-}
-
-/*
* submit_rtpg - Issue a REPORT TARGET GROUP STATES command
* @sdev: sdev the command should be sent to
*/
-static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h,
- bool rtpg_ext_hdr_req)
+static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
{
struct request *rq;
- int err = SCSI_DH_RES_TEMP_UNAVAIL;
+ int err = 0;
rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
- if (!rq)
+ if (!rq) {
+ err = DRIVER_BUSY << 24;
goto done;
+ }
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_IN;
- if (rtpg_ext_hdr_req)
+ if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP))
rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT;
else
rq->cmd[1] = MI_REPORT_TARGET_PGS;
- rq->cmd[6] = (h->bufflen >> 24) & 0xff;
- rq->cmd[7] = (h->bufflen >> 16) & 0xff;
- rq->cmd[8] = (h->bufflen >> 8) & 0xff;
- rq->cmd[9] = h->bufflen & 0xff;
+ put_unaligned_be32(h->bufflen, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
+ rq->sense_len = 0;
- err = blk_execute_rq(rq->q, NULL, rq, 1);
- if (err == -EIO) {
- sdev_printk(KERN_INFO, sdev,
- "%s: rtpg failed with %x\n",
- ALUA_DH_NAME, rq->errors);
- h->senselen = rq->sense_len;
- err = SCSI_DH_IO;
- }
+ blk_execute_rq(rq->q, NULL, rq, 1);
+ if (rq->errors)
+ err = rq->errors;
blk_put_request(rq);
done:
return err;
}
/*
- * alua_stpg - Evaluate SET TARGET GROUP STATES
+ * stpg_endio - Evaluate SET TARGET GROUP STATES
* @sdev: the device to be evaluated
* @state: the new target group state
*
- * Send a SET TARGET GROUP STATES command to the device.
- * We only have to test here if we should resubmit the command;
- * any other error is assumed as a failure.
+ * Evaluate a SET TARGET GROUP STATES command response.
*/
static void stpg_endio(struct request *req, int error)
{
@@ -231,22 +186,21 @@ static void stpg_endio(struct request *req, int error)
goto done;
}
- if (req->sense_len > 0) {
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr);
- if (!err) {
- err = SCSI_DH_IO;
+ if (scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr)) {
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) {
+ /* ALUA state transition already in progress */
+ err = SCSI_DH_OK;
goto done;
}
- err = alua_check_sense(h->sdev, &sense_hdr);
- if (err == ADD_TO_MLQUEUE) {
+ if (sense_hdr.sense_key == UNIT_ATTENTION) {
err = SCSI_DH_RETRY;
goto done;
}
- sdev_printk(KERN_INFO, h->sdev,
- "%s: stpg sense code: %02x/%02x/%02x\n",
- ALUA_DH_NAME, sense_hdr.sense_key,
- sense_hdr.asc, sense_hdr.ascq);
+ sdev_printk(KERN_INFO, h->sdev, "%s: stpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(h->sdev, ALUA_DH_NAME, &sense_hdr);
err = SCSI_DH_IO;
} else if (error)
err = SCSI_DH_IO;
@@ -284,8 +238,7 @@ static unsigned submit_stpg(struct alua_dh_data *h)
/* Prepare the data buffer */
memset(h->buff, 0, stpg_len);
h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
- h->buff[6] = (h->group_id >> 8) & 0xff;
- h->buff[7] = h->group_id & 0xff;
+ put_unaligned_be16(h->group_id, &h->buff[6]);
rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
if (!rq)
@@ -294,15 +247,12 @@ static unsigned submit_stpg(struct alua_dh_data *h)
/* Prepare the command. */
rq->cmd[0] = MAINTENANCE_OUT;
rq->cmd[1] = MO_SET_TARGET_PGS;
- rq->cmd[6] = (stpg_len >> 24) & 0xff;
- rq->cmd[7] = (stpg_len >> 16) & 0xff;
- rq->cmd[8] = (stpg_len >> 8) & 0xff;
- rq->cmd[9] = stpg_len & 0xff;
+ put_unaligned_be32(stpg_len, &rq->cmd[6]);
rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
- rq->sense_len = h->senselen = 0;
+ rq->sense_len = 0;
rq->end_io_data = h;
blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio);
@@ -316,12 +266,23 @@ static unsigned submit_stpg(struct alua_dh_data *h)
* Examine the TPGS setting of the sdev to find out if ALUA
* is supported.
*/
-static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_tpgs(struct scsi_device *sdev)
{
- int err = SCSI_DH_OK;
+ int tpgs = TPGS_MODE_NONE;
+
+ /*
+ * ALUA support for non-disk devices is fraught with
+ * difficulties, so disable it for now.
+ */
+ if (sdev->type != TYPE_DISK) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: disable for non-disk devices\n",
+ ALUA_DH_NAME);
+ return tpgs;
+ }
- h->tpgs = scsi_device_tpgs(sdev);
- switch (h->tpgs) {
+ tpgs = scsi_device_tpgs(sdev);
+ switch (tpgs) {
case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
sdev_printk(KERN_INFO, sdev,
"%s: supports implicit and explicit TPGS\n",
@@ -335,71 +296,34 @@ static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
ALUA_DH_NAME);
break;
- default:
- h->tpgs = TPGS_MODE_NONE;
+ case TPGS_MODE_NONE:
sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
ALUA_DH_NAME);
- err = SCSI_DH_DEV_UNSUPP;
+ break;
+ default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: unsupported TPGS setting %d\n",
+ ALUA_DH_NAME, tpgs);
+ tpgs = TPGS_MODE_NONE;
break;
}
- return err;
+ return tpgs;
}
/*
- * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
+ * alua_check_vpd - Evaluate INQUIRY vpd page 0x83
* @sdev: device to be checked
*
* Extract the relative target port and the target port group
* descriptor from the list of identificators.
*/
-static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+static int alua_check_vpd(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int len;
- unsigned err;
- unsigned char *d;
-
- retry:
- err = submit_vpd_inquiry(sdev, h);
-
- if (err != SCSI_DH_OK)
- return err;
-
- /* Check if vpd page exceeds initial buffer */
- len = (h->buff[2] << 8) + h->buff[3] + 4;
- if (len > h->bufflen) {
- /* Resubmit with the correct length */
- if (realloc_buffer(h, len)) {
- sdev_printk(KERN_WARNING, sdev,
- "%s: kmalloc buffer failed\n",
- ALUA_DH_NAME);
- /* Temporary failure, bypass */
- return SCSI_DH_DEV_TEMP_BUSY;
- }
- goto retry;
- }
+ int rel_port = -1, group_id;
- /*
- * Now look for the correct descriptor.
- */
- d = h->buff + 4;
- while (d < h->buff + len) {
- switch (d[1] & 0xf) {
- case 0x4:
- /* Relative target port */
- h->rel_port = (d[6] << 8) + d[7];
- break;
- case 0x5:
- /* Target port group */
- h->group_id = (d[6] << 8) + d[7];
- break;
- default:
- break;
- }
- d += d[3] + 4;
- }
-
- if (h->group_id == -1) {
+ group_id = scsi_vpd_tpg_id(sdev, &rel_port);
+ if (group_id < 0) {
/*
* Internal error; TPGS supported but required
* VPD identification descriptors not present.
@@ -408,16 +332,16 @@ static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
sdev_printk(KERN_INFO, sdev,
"%s: No target port descriptors found\n",
ALUA_DH_NAME);
- h->state = TPGS_STATE_OPTIMIZED;
- h->tpgs = TPGS_MODE_NONE;
- err = SCSI_DH_DEV_UNSUPP;
- } else {
- sdev_printk(KERN_INFO, sdev,
- "%s: port group %02x rel port %02x\n",
- ALUA_DH_NAME, h->group_id, h->rel_port);
+ return SCSI_DH_DEV_UNSUPP;
}
+ h->state = TPGS_STATE_OPTIMIZED;
+ h->group_id = group_id;
- return err;
+ sdev_printk(KERN_INFO, sdev,
+ "%s: port group %02x rel port %02x\n",
+ ALUA_DH_NAME, h->group_id, h->rel_port);
+
+ return 0;
}
static char print_alua_state(int state)
@@ -452,28 +376,6 @@ static int alua_check_sense(struct scsi_device *sdev,
* LUN Not Accessible - ALUA state transition
*/
return ADD_TO_MLQUEUE;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
- /*
- * LUN Not Accessible -- Target port in standby state
- */
- return SUCCESS;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
- /*
- * LUN Not Accessible -- Target port in unavailable state
- */
- return SUCCESS;
- if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
- /*
- * LUN Not Ready -- Offline
- */
- return SUCCESS;
- if (sdev->allow_restart &&
- sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x02)
- /*
- * if the device is not started, we need to wake
- * the error handler to start the motor
- */
- return FAILED;
break;
case UNIT_ATTENTION:
if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
@@ -533,8 +435,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
struct scsi_sense_hdr sense_hdr;
int len, k, off, valid_states = 0;
unsigned char *ucp;
- unsigned err;
- bool rtpg_ext_hdr_req = 1;
+ unsigned err, retval;
unsigned long expiry, interval = 0;
unsigned int tpg_desc_tbl_off;
unsigned char orig_transition_tmo;
@@ -545,13 +446,17 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
expiry = round_jiffies_up(jiffies + h->transition_tmo * HZ);
retry:
- err = submit_rtpg(sdev, h, rtpg_ext_hdr_req);
-
- if (err == SCSI_DH_IO && h->senselen > 0) {
- err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
- &sense_hdr);
- if (!err)
+ retval = submit_rtpg(sdev, h);
+ if (retval) {
+ if (!scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr)) {
+ sdev_printk(KERN_INFO, sdev,
+ "%s: rtpg failed, result %d\n",
+ ALUA_DH_NAME, retval);
+ if (driver_byte(retval) == DRIVER_BUSY)
+ return SCSI_DH_DEV_TEMP_BUSY;
return SCSI_DH_IO;
+ }
/*
* submit_rtpg() has failed on existing arrays
@@ -561,27 +466,34 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
* The retry without rtpg_ext_hdr_req set
* handles this.
*/
- if (rtpg_ext_hdr_req == 1 &&
+ if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP) &&
sense_hdr.sense_key == ILLEGAL_REQUEST &&
sense_hdr.asc == 0x24 && sense_hdr.ascq == 0) {
- rtpg_ext_hdr_req = 0;
+ h->flags |= ALUA_RTPG_EXT_HDR_UNSUPP;
goto retry;
}
-
- err = alua_check_sense(sdev, &sense_hdr);
- if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry))
+ /*
+ * Retry on ALUA state transition or if any
+ * UNIT ATTENTION occurred.
+ */
+ if (sense_hdr.sense_key == NOT_READY &&
+ sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
+ err = SCSI_DH_RETRY;
+ else if (sense_hdr.sense_key == UNIT_ATTENTION)
+ err = SCSI_DH_RETRY;
+ if (err == SCSI_DH_RETRY && time_before(jiffies, expiry)) {
+ sdev_printk(KERN_ERR, sdev, "%s: rtpg retry\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
goto retry;
- sdev_printk(KERN_INFO, sdev,
- "%s: rtpg sense code %02x/%02x/%02x\n",
- ALUA_DH_NAME, sense_hdr.sense_key,
- sense_hdr.asc, sense_hdr.ascq);
- err = SCSI_DH_IO;
+ }
+ sdev_printk(KERN_ERR, sdev, "%s: rtpg failed\n",
+ ALUA_DH_NAME);
+ scsi_print_sense_hdr(sdev, ALUA_DH_NAME, &sense_hdr);
+ return SCSI_DH_IO;
}
- if (err != SCSI_DH_OK)
- return err;
- len = (h->buff[0] << 24) + (h->buff[1] << 16) +
- (h->buff[2] << 8) + h->buff[3] + 4;
+ len = get_unaligned_be32(&h->buff[0]) + 4;
if (len > h->bufflen) {
/* Resubmit with the correct length */
@@ -616,7 +528,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
k < len;
k += off, ucp += off) {
- if (h->group_id == (ucp[2] << 8) + ucp[3]) {
+ if (h->group_id == get_unaligned_be16(&ucp[2])) {
h->state = ucp[0] & 0x0f;
h->pref = ucp[0] >> 7;
valid_states = ucp[1];
@@ -674,13 +586,13 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h, int wait_
*/
static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
{
- int err;
+ int err = SCSI_DH_DEV_UNSUPP;
- err = alua_check_tpgs(sdev, h);
- if (err != SCSI_DH_OK)
+ h->tpgs = alua_check_tpgs(sdev);
+ if (h->tpgs == TPGS_MODE_NONE)
goto out;
- err = alua_vpd_inquiry(sdev, h);
+ err = alua_check_vpd(sdev, h);
if (err != SCSI_DH_OK)
goto out;
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 3e088125a..6c14e68b9 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -36,17 +36,10 @@
#define DONT_USE_INTR
-#define NCR5380_read(reg) inb(port + reg)
-#define NCR5380_write(reg, value) outb(value, port + reg)
+#define NCR5380_read(reg) inb(instance->io_port + reg)
+#define NCR5380_write(reg, value) outb(value, instance->io_port + reg)
#define NCR5380_implementation_fields /* none */
-#define NCR5380_local_declare() unsigned int port
-#define NCR5380_setup(instance) port = instance->io_port
-
-/*
- * Includes needed for NCR5380.[ch] (XXX: Move them to NCR5380.h)
- */
-#include <linux/delay.h>
#include "NCR5380.h"
#include "NCR5380.c"
@@ -56,6 +49,7 @@
static struct scsi_host_template dmx3191d_driver_template = {
+ .module = THIS_MODULE,
.proc_name = DMX3191D_DRIVER_NAME,
.name = "Domex DMX3191D",
.info = NCR5380_info,
@@ -67,6 +61,8 @@ static struct scsi_host_template dmx3191d_driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
static int dmx3191d_probe_one(struct pci_dev *pdev,
@@ -97,17 +93,25 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
*/
shost->irq = NO_IRQ;
- NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
+ error = NCR5380_init(shost, FLAG_NO_PSEUDO_DMA);
+ if (error)
+ goto out_host_put;
+
+ NCR5380_maybe_reset_bus(shost);
pci_set_drvdata(pdev, shost);
error = scsi_add_host(shost, &pdev->dev);
if (error)
- goto out_release_region;
+ goto out_exit;
scsi_scan_host(shost);
return 0;
+out_exit:
+ NCR5380_exit(shost);
+out_host_put:
+ scsi_host_put(shost);
out_release_region:
release_region(io, DMX3191D_REGION_LEN);
out_disable_device:
@@ -119,15 +123,14 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
static void dmx3191d_remove_one(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ unsigned long io = shost->io_port;
scsi_remove_host(shost);
NCR5380_exit(shost);
-
- release_region(shost->io_port, DMX3191D_REGION_LEN);
- pci_disable_device(pdev);
-
scsi_host_put(shost);
+ release_region(io, DMX3191D_REGION_LEN);
+ pci_disable_device(pdev);
}
static struct pci_device_id dmx3191d_pci_tbl[] = {
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 4c74c7ba2..6c736b071 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -1,9 +1,5 @@
-
#define PSEUDO_DMA
#define DONT_USE_INTR
-#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */
-#define DMA_WORKS_RIGHT
-
/*
* DTC 3180/3280 driver, by
@@ -50,15 +46,13 @@
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/stat.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <scsi/scsi_host.h>
+
#include "dtc.h"
#define AUTOPROBE_IRQ
#include "NCR5380.h"
@@ -150,7 +144,7 @@ static const struct signature {
static int __init dtc_setup(char *str)
{
- static int commandline_current = 0;
+ static int commandline_current;
int i;
int ints[10];
@@ -188,7 +182,7 @@ __setup("dtc=", dtc_setup);
static int __init dtc_detect(struct scsi_host_template * tpnt)
{
- static int current_override = 0, current_base = 0;
+ static int current_override, current_base;
struct Scsi_Host *instance;
unsigned int addr;
void __iomem *base;
@@ -205,9 +199,8 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
addr = 0;
} else
for (; !addr && (current_base < NO_BASES); ++current_base) {
-#if (DTCDEBUG & DTCDEBUG_INIT)
- printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address);
-#endif
+ dprintk(NDEBUG_INIT, "dtc: probing address 0x%08x\n",
+ (unsigned int)bases[current_base].address);
if (bases[current_base].noauto)
continue;
base = ioremap(bases[current_base].address, 0x2000);
@@ -216,18 +209,14 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
for (sig = 0; sig < NO_SIGNATURES; ++sig) {
if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
addr = bases[current_base].address;
-#if (DTCDEBUG & DTCDEBUG_INIT)
- printk(KERN_DEBUG "scsi-dtc : detected board.\n");
-#endif
+ dprintk(NDEBUG_INIT, "dtc: detected board\n");
goto found;
}
}
iounmap(base);
}
-#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
- printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr);
-#endif
+ dprintk(NDEBUG_INIT, "dtc: addr = 0x%08x\n", addr);
if (!addr)
break;
@@ -235,12 +224,15 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
found:
instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
if (instance == NULL)
- break;
+ goto out_unmap;
instance->base = addr;
((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
- NCR5380_init(instance, 0);
+ if (NCR5380_init(instance, FLAG_NO_DMA_FIXUP))
+ goto out_unregister;
+
+ NCR5380_maybe_reset_bus(instance);
NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */
if (overrides[current_override].irq != IRQ_AUTO)
@@ -271,14 +263,19 @@ found:
printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
instance->irq = NO_IRQ;
#endif
-#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
- printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+ dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
+ instance->host_no, instance->irq);
++current_override;
++count;
}
return count;
+
+out_unregister:
+ scsi_unregister(instance);
+out_unmap:
+ iounmap(base);
+ return count;
}
/*
@@ -331,12 +328,8 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
unsigned char *d = dst;
int i; /* For counting time spent in the poll-loop */
struct NCR5380_hostdata *hostdata = shost_priv(instance);
- NCR5380_local_declare();
- NCR5380_setup(instance);
i = 0;
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
if (instance->irq == NO_IRQ)
NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
else
@@ -348,7 +341,7 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
++i;
rtrc(3);
- memcpy_fromio(d, base + DTC_DATA_BUF, 128);
+ memcpy_fromio(d, hostdata->base + DTC_DATA_BUF, 128);
d += 128;
len -= 128;
rtrc(7);
@@ -358,9 +351,7 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
rtrc(4);
while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
++i;
- NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
rtrc(0);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
if (i > hostdata->spin_max_r)
hostdata->spin_max_r = i;
return (0);
@@ -383,12 +374,7 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
{
int i;
struct NCR5380_hostdata *hostdata = shost_priv(instance);
- NCR5380_local_declare();
- NCR5380_setup(instance);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
- /* set direction (write) */
if (instance->irq == NO_IRQ)
NCR5380_write(DTC_CONTROL_REG, 0);
else
@@ -400,7 +386,7 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
++i;
rtrc(3);
- memcpy_toio(base + DTC_DATA_BUF, src, 128);
+ memcpy_toio(hostdata->base + DTC_DATA_BUF, src, 128);
src += 128;
len -= 128;
}
@@ -413,47 +399,60 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
++i;
rtrc(7);
/* Check for parity error here. fixme. */
- NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
rtrc(0);
if (i > hostdata->spin_max_w)
hostdata->spin_max_w = i;
return (0);
}
+static int dtc_dma_xfer_len(struct scsi_cmnd *cmd)
+{
+ int transfersize = cmd->transfersize;
+
+ /* Limit transfers to 32K, for xx400 & xx406
+ * pseudoDMA that transfers in 128 bytes blocks.
+ */
+ if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
+ !(cmd->SCp.this_residual % transfersize))
+ transfersize = 32 * 1024;
+
+ return transfersize;
+}
+
MODULE_LICENSE("GPL");
#include "NCR5380.c"
static int dtc_release(struct Scsi_Host *shost)
{
- NCR5380_local_declare();
- NCR5380_setup(shost);
+ struct NCR5380_hostdata *hostdata = shost_priv(shost);
+
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
scsi_unregister(shost);
- iounmap(base);
+ iounmap(hostdata->base);
return 0;
}
static struct scsi_host_template driver_template = {
- .name = "DTC 3180/3280 ",
- .detect = dtc_detect,
- .release = dtc_release,
- .proc_name = "dtc3x80",
- .show_info = dtc_show_info,
- .write_info = dtc_write_info,
- .info = dtc_info,
- .queuecommand = dtc_queue_command,
- .eh_abort_handler = dtc_abort,
- .eh_bus_reset_handler = dtc_bus_reset,
- .bios_param = dtc_biosparam,
- .can_queue = CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING,
+ .name = "DTC 3180/3280",
+ .detect = dtc_detect,
+ .release = dtc_release,
+ .proc_name = "dtc3x80",
+ .show_info = dtc_show_info,
+ .write_info = dtc_write_info,
+ .info = dtc_info,
+ .queuecommand = dtc_queue_command,
+ .eh_abort_handler = dtc_abort,
+ .eh_bus_reset_handler = dtc_bus_reset,
+ .bios_param = dtc_biosparam,
+ .can_queue = 32,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index 78a2332e9..56732cba8 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -10,54 +10,17 @@
#ifndef DTC3280_H
#define DTC3280_H
-#define DTCDEBUG 0
-#define DTCDEBUG_INIT 0x1
-#define DTCDEBUG_TRANSFER 0x2
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32
-#endif
-
#define NCR5380_implementation_fields \
void __iomem *base
-#define NCR5380_local_declare() \
- void __iomem *base
-
-#define NCR5380_setup(instance) \
- base = ((struct NCR5380_hostdata *)(instance)->hostdata)->base
+#define DTC_address(reg) \
+ (((struct NCR5380_hostdata *)shost_priv(instance))->base + DTC_5380_OFFSET + reg)
-#define DTC_address(reg) (base + DTC_5380_OFFSET + reg)
-
-#define dbNCR5380_read(reg) \
- (rval=readb(DTC_address(reg)), \
- (((unsigned char) printk("DTC : read register %d at addr %p is: %02x\n"\
- , (reg), DTC_address(reg), rval)), rval ) )
-
-#define dbNCR5380_write(reg, value) do { \
- printk("DTC : write %02x to register %d at address %p\n", \
- (value), (reg), DTC_address(reg)); \
- writeb(value, DTC_address(reg));} while(0)
-
-
-#if !(DTCDEBUG & DTCDEBUG_TRANSFER)
#define NCR5380_read(reg) (readb(DTC_address(reg)))
#define NCR5380_write(reg, value) (writeb(value, DTC_address(reg)))
-#else
-#define NCR5380_read(reg) (readb(DTC_address(reg)))
-#define xNCR5380_read(reg) \
- (((unsigned char) printk("DTC : read register %d at address %p\n"\
- , (reg), DTC_address(reg))), readb(DTC_address(reg)))
-#define NCR5380_write(reg, value) do { \
- printk("DTC : write %02x to register %d at address %p\n", \
- (value), (reg), DTC_address(reg)); \
- writeb(value, DTC_address(reg));} while(0)
-#endif
+#define NCR5380_dma_xfer_len(instance, cmd, phase) \
+ dtc_dma_xfer_len(cmd)
#define NCR5380_intr dtc_intr
#define NCR5380_queue_command dtc_queue_command
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index f4424063b..0efe7112f 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -1625,7 +1625,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
/* crc offload */
if (likely(lport->crc_offload)) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum_start = skb_headroom(skb);
skb->csum_offset = skb->len;
crc = 0;
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index f8d2478b1..90091e693 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -56,40 +56,31 @@
*
*/
-/* settings for DTC3181E card with only Mustek scanner attached */
-#define USLEEP_POLL msecs_to_jiffies(10)
-#define USLEEP_SLEEP msecs_to_jiffies(200)
-#define USLEEP_WAITLONG msecs_to_jiffies(5000)
-
#define AUTOPROBE_IRQ
#ifdef CONFIG_SCSI_GENERIC_NCR53C400
-#define NCR53C400_PSEUDO_DMA 1
#define PSEUDO_DMA
-#define NCR53C400
#endif
#include <asm/io.h>
-#include <linux/signal.h>
#include <linux/blkdev.h>
+#include <linux/module.h>
#include <scsi/scsi_host.h>
#include "g_NCR5380.h"
#include "NCR5380.h"
-#include <linux/stat.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/isapnp.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
-#define NCR_NOT_SET 0
-static int ncr_irq = NCR_NOT_SET;
-static int ncr_dma = NCR_NOT_SET;
-static int ncr_addr = NCR_NOT_SET;
-static int ncr_5380 = NCR_NOT_SET;
-static int ncr_53c400 = NCR_NOT_SET;
-static int ncr_53c400a = NCR_NOT_SET;
-static int dtc_3181e = NCR_NOT_SET;
+static int ncr_irq;
+static int ncr_dma;
+static int ncr_addr;
+static int ncr_5380;
+static int ncr_53c400;
+static int ncr_53c400a;
+static int dtc_3181e;
+static int hp_c2502;
static struct override {
NCR5380_map_type NCR5380_map_name;
@@ -121,7 +112,7 @@ static struct override {
static void __init internal_setup(int board, char *str, int *ints)
{
- static int commandline_current = 0;
+ static int commandline_current;
switch (board) {
case BOARD_NCR5380:
if (ints[0] != 2 && ints[0] != 3) {
@@ -235,6 +226,30 @@ static int __init do_DTC3181E_setup(char *str)
#endif
+#ifndef SCSI_G_NCR5380_MEM
+/*
+ * Configure I/O address of 53C400A or DTC436 by writing magic numbers
+ * to ports 0x779 and 0x379.
+ */
+static void magic_configure(int idx, u8 irq, u8 magic[])
+{
+ u8 cfg = 0;
+
+ outb(magic[0], 0x779);
+ outb(magic[1], 0x379);
+ outb(magic[2], 0x379);
+ outb(magic[3], 0x379);
+ outb(magic[4], 0x379);
+
+ /* allowed IRQs for HP C2502 */
+ if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7)
+ irq = 0;
+ if (idx >= 0 && idx <= 7)
+ cfg = 0x80 | idx | (irq << 4);
+ outb(cfg, 0x379);
+}
+#endif
+
/**
* generic_NCR5380_detect - look for NCR5380 controllers
* @tpnt: the scsi template
@@ -243,19 +258,18 @@ static int __init do_DTC3181E_setup(char *str)
* and DTC436(ISAPnP) controllers. If overrides have been set we use
* them.
*
- * The caller supplied NCR5380_init function is invoked from here, before
- * the interrupt line is taken.
- *
* Locks: none
*/
static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
{
- static int current_override = 0;
+ static int current_override;
int count;
unsigned int *ports;
+ u8 *magic = NULL;
#ifndef SCSI_G_NCR5380_MEM
int i;
+ int port_idx = -1;
unsigned long region_size = 16;
#endif
static unsigned int __initdata ncr_53c400a_ports[] = {
@@ -264,27 +278,36 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
static unsigned int __initdata dtc_3181e_ports[] = {
0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
};
- int flags = 0;
+ static u8 ncr_53c400a_magic[] __initdata = { /* 53C400A & DTC436 */
+ 0x59, 0xb9, 0xc5, 0xae, 0xa6
+ };
+ static u8 hp_c2502_magic[] __initdata = { /* HP C2502 */
+ 0x0f, 0x22, 0xf0, 0x20, 0x80
+ };
+ int flags;
struct Scsi_Host *instance;
+ struct NCR5380_hostdata *hostdata;
#ifdef SCSI_G_NCR5380_MEM
unsigned long base;
void __iomem *iomem;
#endif
- if (ncr_irq != NCR_NOT_SET)
+ if (ncr_irq)
overrides[0].irq = ncr_irq;
- if (ncr_dma != NCR_NOT_SET)
+ if (ncr_dma)
overrides[0].dma = ncr_dma;
- if (ncr_addr != NCR_NOT_SET)
+ if (ncr_addr)
overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr;
- if (ncr_5380 != NCR_NOT_SET)
+ if (ncr_5380)
overrides[0].board = BOARD_NCR5380;
- else if (ncr_53c400 != NCR_NOT_SET)
+ else if (ncr_53c400)
overrides[0].board = BOARD_NCR53C400;
- else if (ncr_53c400a != NCR_NOT_SET)
+ else if (ncr_53c400a)
overrides[0].board = BOARD_NCR53C400A;
- else if (dtc_3181e != NCR_NOT_SET)
+ else if (dtc_3181e)
overrides[0].board = BOARD_DTC3181E;
+ else if (hp_c2502)
+ overrides[0].board = BOARD_HP_C2502;
#ifndef SCSI_G_NCR5380_MEM
if (!current_override && isapnp_present()) {
struct pnp_dev *dev = NULL;
@@ -318,41 +341,45 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
}
}
#endif
- tpnt->proc_name = "g_NCR5380";
for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
if (!(overrides[current_override].NCR5380_map_name))
continue;
ports = NULL;
+ flags = 0;
switch (overrides[current_override].board) {
case BOARD_NCR5380:
flags = FLAG_NO_PSEUDO_DMA;
break;
case BOARD_NCR53C400:
- flags = FLAG_NCR53C400;
+#ifdef PSEUDO_DMA
+ flags = FLAG_NO_DMA_FIXUP;
+#endif
break;
case BOARD_NCR53C400A:
- flags = FLAG_NO_PSEUDO_DMA;
+ flags = FLAG_NO_DMA_FIXUP;
+ ports = ncr_53c400a_ports;
+ magic = ncr_53c400a_magic;
+ break;
+ case BOARD_HP_C2502:
+ flags = FLAG_NO_DMA_FIXUP;
ports = ncr_53c400a_ports;
+ magic = hp_c2502_magic;
break;
case BOARD_DTC3181E:
- flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E;
+ flags = FLAG_NO_DMA_FIXUP;
ports = dtc_3181e_ports;
+ magic = ncr_53c400a_magic;
break;
}
#ifndef SCSI_G_NCR5380_MEM
- if (ports) {
+ if (ports && magic) {
/* wakeup sequence for the NCR53C400A and DTC3181E */
/* Disable the adapter and look for a free io port */
- outb(0x59, 0x779);
- outb(0xb9, 0x379);
- outb(0xc5, 0x379);
- outb(0xae, 0x379);
- outb(0xa6, 0x379);
- outb(0x00, 0x379);
+ magic_configure(-1, 0, magic);
if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
for (i = 0; ports[i]; i++) {
@@ -371,17 +398,12 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
}
if (ports[i]) {
/* At this point we have our region reserved */
- outb(0x59, 0x779);
- outb(0xb9, 0x379);
- outb(0xc5, 0x379);
- outb(0xae, 0x379);
- outb(0xa6, 0x379);
- outb(0x80 | i, 0x379); /* set io port to be used */
+ magic_configure(i, 0, magic); /* no IRQ yet */
outb(0xc0, ports[i] + 9);
if (inb(ports[i] + 9) != 0x80)
continue;
- else
- overrides[current_override].NCR5380_map_name = ports[i];
+ overrides[current_override].NCR5380_map_name = ports[i];
+ port_idx = i;
} else
continue;
}
@@ -403,24 +425,65 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
}
#endif
instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
- if (instance == NULL) {
-#ifndef SCSI_G_NCR5380_MEM
- release_region(overrides[current_override].NCR5380_map_name, region_size);
-#else
- iounmap(iomem);
- release_mem_region(base, NCR5380_region_size);
-#endif
- continue;
- }
+ if (instance == NULL)
+ goto out_release;
+ hostdata = shost_priv(instance);
- instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
#ifndef SCSI_G_NCR5380_MEM
+ instance->io_port = overrides[current_override].NCR5380_map_name;
instance->n_io_port = region_size;
+ hostdata->io_width = 1; /* 8-bit PDMA by default */
+
+ /*
+ * On NCR53C400 boards, NCR5380 registers are mapped 8 past
+ * the base address.
+ */
+ switch (overrides[current_override].board) {
+ case BOARD_NCR53C400:
+ instance->io_port += 8;
+ hostdata->c400_ctl_status = 0;
+ hostdata->c400_blk_cnt = 1;
+ hostdata->c400_host_buf = 4;
+ break;
+ case BOARD_DTC3181E:
+ hostdata->io_width = 2; /* 16-bit PDMA */
+ /* fall through */
+ case BOARD_NCR53C400A:
+ case BOARD_HP_C2502:
+ hostdata->c400_ctl_status = 9;
+ hostdata->c400_blk_cnt = 10;
+ hostdata->c400_host_buf = 8;
+ break;
+ }
#else
- ((struct NCR5380_hostdata *)instance->hostdata)->iomem = iomem;
+ instance->base = overrides[current_override].NCR5380_map_name;
+ hostdata->iomem = iomem;
+ switch (overrides[current_override].board) {
+ case BOARD_NCR53C400:
+ hostdata->c400_ctl_status = 0x100;
+ hostdata->c400_blk_cnt = 0x101;
+ hostdata->c400_host_buf = 0x104;
+ break;
+ case BOARD_DTC3181E:
+ case BOARD_NCR53C400A:
+ case BOARD_HP_C2502:
+ pr_err(DRV_MODULE_NAME ": unknown register offsets\n");
+ goto out_unregister;
+ }
#endif
- NCR5380_init(instance, flags);
+ if (NCR5380_init(instance, flags))
+ goto out_unregister;
+
+ switch (overrides[current_override].board) {
+ case BOARD_NCR53C400:
+ case BOARD_DTC3181E:
+ case BOARD_NCR53C400A:
+ case BOARD_HP_C2502:
+ NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
+ }
+
+ NCR5380_maybe_reset_bus(instance);
if (overrides[current_override].irq != IRQ_AUTO)
instance->irq = overrides[current_override].irq;
@@ -431,12 +494,18 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
if (instance->irq == 255)
instance->irq = NO_IRQ;
- if (instance->irq != NO_IRQ)
+ if (instance->irq != NO_IRQ) {
+#ifndef SCSI_G_NCR5380_MEM
+ /* set IRQ for HP C2502 */
+ if (overrides[current_override].board == BOARD_HP_C2502)
+ magic_configure(port_idx, instance->irq, magic);
+#endif
if (request_irq(instance->irq, generic_NCR5380_intr,
0, "NCR5380", instance)) {
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = NO_IRQ;
}
+ }
if (instance->irq == NO_IRQ) {
printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
@@ -447,6 +516,17 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
++count;
}
return count;
+
+out_unregister:
+ scsi_unregister(instance);
+out_release:
+#ifndef SCSI_G_NCR5380_MEM
+ release_region(overrides[current_override].NCR5380_map_name, region_size);
+#else
+ iounmap(iomem);
+ release_mem_region(base, NCR5380_region_size);
+#endif
+ return count;
}
/**
@@ -460,21 +540,15 @@ static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
static int generic_NCR5380_release_resources(struct Scsi_Host *instance)
{
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
if (instance->irq != NO_IRQ)
free_irq(instance->irq, instance);
NCR5380_exit(instance);
-
#ifndef SCSI_G_NCR5380_MEM
- release_region(instance->NCR5380_instance_name, instance->n_io_port);
+ release_region(instance->io_port, instance->n_io_port);
#else
iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem);
- release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size);
+ release_mem_region(instance->base, NCR5380_region_size);
#endif
-
-
return 0;
}
@@ -507,7 +581,7 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
}
#endif
-#ifdef NCR53C400_PSEUDO_DMA
+#ifdef PSEUDO_DMA
/**
* NCR5380_pread - pseudo DMA read
@@ -521,75 +595,68 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int blocks = len / 128;
int start = 0;
- int bl;
-
- NCR5380_local_declare();
- NCR5380_setup(instance);
- NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
- NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+ NCR5380_write(hostdata->c400_ctl_status, CSR_BASE | CSR_TRANS_DIR);
+ NCR5380_write(hostdata->c400_blk_cnt, blocks);
while (1) {
- if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+ if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
break;
- }
- if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+ if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
return -1;
}
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY);
+ while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
+ ; /* FIXME - no timeout */
#ifndef SCSI_G_NCR5380_MEM
- {
- int i;
- for (i = 0; i < 128; i++)
- dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
- }
+ if (hostdata->io_width == 2)
+ insw(instance->io_port + hostdata->c400_host_buf,
+ dst + start, 64);
+ else
+ insb(instance->io_port + hostdata->c400_host_buf,
+ dst + start, 128);
#else
/* implies SCSI_G_NCR5380_MEM */
- memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128);
+ memcpy_fromio(dst + start,
+ hostdata->iomem + NCR53C400_host_buffer, 128);
#endif
start += 128;
blocks--;
}
if (blocks) {
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
- {
- // FIXME - no timeout
- }
+ while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
+ ; /* FIXME - no timeout */
#ifndef SCSI_G_NCR5380_MEM
- {
- int i;
- for (i = 0; i < 128; i++)
- dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
- }
+ if (hostdata->io_width == 2)
+ insw(instance->io_port + hostdata->c400_host_buf,
+ dst + start, 64);
+ else
+ insb(instance->io_port + hostdata->c400_host_buf,
+ dst + start, 128);
#else
/* implies SCSI_G_NCR5380_MEM */
- memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128);
+ memcpy_fromio(dst + start,
+ hostdata->iomem + NCR53C400_host_buffer, 128);
#endif
start += 128;
blocks--;
}
- if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+ if (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ))
printk("53C400r: no 53C80 gated irq after transfer");
-#if 0
- /*
- * DON'T DO THIS - THEY NEVER ARRIVE!
- */
- printk("53C400r: Waiting for 53C80 registers\n");
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
+ /* wait for 53C80 registers to be available */
+ while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG))
;
-#endif
+
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
printk(KERN_ERR "53C400r: no end dma signal\n");
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
return 0;
}
@@ -605,89 +672,91 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int blocks = len / 128;
int start = 0;
- int bl;
- int i;
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
- NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
- NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+ NCR5380_write(hostdata->c400_ctl_status, CSR_BASE);
+ NCR5380_write(hostdata->c400_blk_cnt, blocks);
while (1) {
- if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+ if (NCR5380_read(hostdata->c400_ctl_status) & CSR_GATED_53C80_IRQ) {
printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
return -1;
}
- if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+ if (NCR5380_read(hostdata->c400_blk_cnt) == 0)
break;
- }
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+ while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
; // FIXME - timeout
#ifndef SCSI_G_NCR5380_MEM
- {
- for (i = 0; i < 128; i++)
- NCR5380_write(C400_HOST_BUFFER, src[start + i]);
- }
+ if (hostdata->io_width == 2)
+ outsw(instance->io_port + hostdata->c400_host_buf,
+ src + start, 64);
+ else
+ outsb(instance->io_port + hostdata->c400_host_buf,
+ src + start, 128);
#else
/* implies SCSI_G_NCR5380_MEM */
- memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128);
+ memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
+ src + start, 128);
#endif
start += 128;
blocks--;
}
if (blocks) {
- while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+ while (NCR5380_read(hostdata->c400_ctl_status) & CSR_HOST_BUF_NOT_RDY)
; // FIXME - no timeout
#ifndef SCSI_G_NCR5380_MEM
- {
- for (i = 0; i < 128; i++)
- NCR5380_write(C400_HOST_BUFFER, src[start + i]);
- }
+ if (hostdata->io_width == 2)
+ outsw(instance->io_port + hostdata->c400_host_buf,
+ src + start, 64);
+ else
+ outsb(instance->io_port + hostdata->c400_host_buf,
+ src + start, 128);
#else
/* implies SCSI_G_NCR5380_MEM */
- memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128);
+ memcpy_toio(hostdata->iomem + NCR53C400_host_buffer,
+ src + start, 128);
#endif
start += 128;
blocks--;
}
-#if 0
- printk("53C400w: waiting for registers to be available\n");
- THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG);
- printk("53C400w: Got em\n");
-#endif
-
- /* Let's wait for this instead - could be ugly */
- /* All documentation says to check for this. Maybe my hardware is too
- * fast. Waiting for it seems to work fine! KLL
- */
- while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
- ; // FIXME - no timeout
-
- /*
- * I know. i is certainly != 0 here but the loop is new. See previous
- * comment.
- */
- if (i) {
- if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
- printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i);
- } else
- printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n");
+ /* wait for 53C80 registers to be available */
+ while (!(NCR5380_read(hostdata->c400_ctl_status) & CSR_53C80_REG)) {
+ udelay(4); /* DTC436 chip hangs without this */
+ /* FIXME - no timeout */
+ }
-#if 0
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
printk(KERN_ERR "53C400w: no end dma signal\n");
}
-#endif
+
while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
; // TIMEOUT
return 0;
}
-#endif /* PSEUDO_DMA */
+
+static int generic_NCR5380_dma_xfer_len(struct scsi_cmnd *cmd)
+{
+ int transfersize = cmd->transfersize;
+
+ /* Limit transfers to 32K, for xx400 & xx406
+ * pseudoDMA that transfers in 128 bytes blocks.
+ */
+ if (transfersize > 32 * 1024 && cmd->SCp.this_residual &&
+ !(cmd->SCp.this_residual % transfersize))
+ transfersize = 32 * 1024;
+
+ /* 53C400 datasheet: non-modulo-128-byte transfers should use PIO */
+ if (transfersize % 128)
+ transfersize = 0;
+
+ return transfersize;
+}
+
+#endif /* PSEUDO_DMA */
/*
* Include the NCR5380 core code that we build our driver around
@@ -696,22 +765,24 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
#include "NCR5380.c"
static struct scsi_host_template driver_template = {
- .show_info = generic_NCR5380_show_info,
- .name = "Generic NCR5380/NCR53C400 SCSI",
- .detect = generic_NCR5380_detect,
- .release = generic_NCR5380_release_resources,
- .info = generic_NCR5380_info,
- .queuecommand = generic_NCR5380_queue_command,
+ .proc_name = DRV_MODULE_NAME,
+ .name = "Generic NCR5380/NCR53C400 SCSI",
+ .detect = generic_NCR5380_detect,
+ .release = generic_NCR5380_release_resources,
+ .info = generic_NCR5380_info,
+ .queuecommand = generic_NCR5380_queue_command,
.eh_abort_handler = generic_NCR5380_abort,
.eh_bus_reset_handler = generic_NCR5380_bus_reset,
- .bios_param = NCR5380_BIOSPARAM,
- .can_queue = CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING,
+ .bios_param = NCR5380_BIOSPARAM,
+ .can_queue = 16,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
-#include <linux/module.h>
+
#include "scsi_module.c"
module_param(ncr_irq, int, 0);
@@ -721,6 +792,7 @@ module_param(ncr_5380, int, 0);
module_param(ncr_53c400, int, 0);
module_param(ncr_53c400a, int, 0);
module_param(dtc_3181e, int, 0);
+module_param(hp_c2502, int, 0);
MODULE_LICENSE("GPL");
#if !defined(SCSI_G_NCR5380_MEM) && defined(MODULE)
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index bea1a3b9b..6f3d2ac4f 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -14,81 +14,67 @@
#ifndef GENERIC_NCR5380_H
#define GENERIC_NCR5380_H
-#ifdef NCR53C400
+#ifdef CONFIG_SCSI_GENERIC_NCR53C400
#define BIOSPARAM
#define NCR5380_BIOSPARAM generic_NCR5380_biosparam
#else
#define NCR5380_BIOSPARAM NULL
#endif
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 16
-#endif
-
#define __STRVAL(x) #x
#define STRVAL(x) __STRVAL(x)
#ifndef SCSI_G_NCR5380_MEM
+#define DRV_MODULE_NAME "g_NCR5380"
-#define NCR5380_map_config port
#define NCR5380_map_type int
#define NCR5380_map_name port
-#define NCR5380_instance_name io_port
-#define NCR53C400_register_offset 0
-#define NCR53C400_address_adjust 8
-#ifdef NCR53C400
+#ifdef CONFIG_SCSI_GENERIC_NCR53C400
#define NCR5380_region_size 16
#else
#define NCR5380_region_size 8
#endif
-#define NCR5380_read(reg) (inb(NCR5380_map_name + (reg)))
-#define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg))))
+#define NCR5380_read(reg) \
+ inb(instance->io_port + (reg))
+#define NCR5380_write(reg, value) \
+ outb(value, instance->io_port + (reg))
#define NCR5380_implementation_fields \
- NCR5380_map_type NCR5380_map_name
-
-#define NCR5380_local_declare() \
- register NCR5380_implementation_fields
-
-#define NCR5380_setup(instance) \
- NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name)
+ int c400_ctl_status; \
+ int c400_blk_cnt; \
+ int c400_host_buf; \
+ int io_width;
#else
/* therefore SCSI_G_NCR5380_MEM */
+#define DRV_MODULE_NAME "g_NCR5380_mmio"
-#define NCR5380_map_config memory
#define NCR5380_map_type unsigned long
#define NCR5380_map_name base
-#define NCR5380_instance_name base
-#define NCR53C400_register_offset 0x108
-#define NCR53C400_address_adjust 0
#define NCR53C400_mem_base 0x3880
#define NCR53C400_host_buffer 0x3900
#define NCR5380_region_size 0x3a00
-#define NCR5380_read(reg) readb(iomem + NCR53C400_mem_base + (reg))
-#define NCR5380_write(reg, value) writeb(value, iomem + NCR53C400_mem_base + (reg))
+#define NCR5380_read(reg) \
+ readb(((struct NCR5380_hostdata *)shost_priv(instance))->iomem + \
+ NCR53C400_mem_base + (reg))
+#define NCR5380_write(reg, value) \
+ writeb(value, ((struct NCR5380_hostdata *)shost_priv(instance))->iomem + \
+ NCR53C400_mem_base + (reg))
#define NCR5380_implementation_fields \
- NCR5380_map_type NCR5380_map_name; \
- void __iomem *iomem;
-
-#define NCR5380_local_declare() \
- register void __iomem *iomem
-
-#define NCR5380_setup(instance) \
- iomem = (((struct NCR5380_hostdata *)(instance)->hostdata)->iomem)
+ void __iomem *iomem; \
+ int c400_ctl_status; \
+ int c400_blk_cnt; \
+ int c400_host_buf;
#endif
+#define NCR5380_dma_xfer_len(instance, cmd, phase) \
+ generic_NCR5380_dma_xfer_len(cmd)
+
#define NCR5380_intr generic_NCR5380_intr
#define NCR5380_queue_command generic_NCR5380_queue_command
#define NCR5380_abort generic_NCR5380_abort
@@ -102,7 +88,7 @@
#define BOARD_NCR53C400 1
#define BOARD_NCR53C400A 2
#define BOARD_DTC3181E 3
+#define BOARD_HP_C2502 4
-#endif /* ndef ASM */
#endif /* GENERIC_NCR5380_H */
diff --git a/drivers/scsi/hisi_sas/Kconfig b/drivers/scsi/hisi_sas/Kconfig
new file mode 100644
index 000000000..d1dd1616f
--- /dev/null
+++ b/drivers/scsi/hisi_sas/Kconfig
@@ -0,0 +1,8 @@
+config SCSI_HISI_SAS
+ tristate "HiSilicon SAS"
+ depends on HAS_DMA && HAS_IOMEM
+ depends on ARM64 || COMPILE_TEST
+ select SCSI_SAS_LIBSAS
+ select BLK_DEV_INTEGRITY
+ help
+ This driver supports HiSilicon's SAS HBA
diff --git a/drivers/scsi/hisi_sas/Makefile b/drivers/scsi/hisi_sas/Makefile
new file mode 100644
index 000000000..3e70eae81
--- /dev/null
+++ b/drivers/scsi/hisi_sas/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_main.o
+obj-$(CONFIG_SCSI_HISI_SAS) += hisi_sas_v1_hw.o
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
new file mode 100644
index 000000000..5af2e4187
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef _HISI_SAS_H_
+#define _HISI_SAS_H_
+
+#include <linux/dmapool.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <scsi/libsas.h>
+
+#define DRV_VERSION "v1.0"
+
+#define HISI_SAS_MAX_PHYS 9
+#define HISI_SAS_MAX_QUEUES 32
+#define HISI_SAS_QUEUE_SLOTS 512
+#define HISI_SAS_MAX_ITCT_ENTRIES 4096
+#define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
+#define HISI_SAS_COMMAND_ENTRIES 8192
+
+#define HISI_SAS_STATUS_BUF_SZ \
+ (sizeof(struct hisi_sas_err_record) + 1024)
+#define HISI_SAS_COMMAND_TABLE_SZ \
+ (((sizeof(union hisi_sas_command_table)+3)/4)*4)
+
+#define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024)
+#define HISI_SAS_MAX_SMP_RESP_SZ 1028
+
+struct hisi_hba;
+
+enum {
+ PORT_TYPE_SAS = (1U << 1),
+ PORT_TYPE_SATA = (1U << 0),
+};
+
+enum dev_status {
+ HISI_SAS_DEV_NORMAL,
+ HISI_SAS_DEV_EH,
+};
+
+enum hisi_sas_dev_type {
+ HISI_SAS_DEV_TYPE_STP = 0,
+ HISI_SAS_DEV_TYPE_SSP,
+ HISI_SAS_DEV_TYPE_SATA,
+};
+
+struct hisi_sas_phy {
+ struct hisi_hba *hisi_hba;
+ struct hisi_sas_port *port;
+ struct asd_sas_phy sas_phy;
+ struct sas_identify identify;
+ struct timer_list timer;
+ struct work_struct phyup_ws;
+ u64 port_id; /* from hw */
+ u64 dev_sas_addr;
+ u64 phy_type;
+ u64 frame_rcvd_size;
+ u8 frame_rcvd[32];
+ u8 phy_attached;
+ u8 reserved[3];
+ enum sas_linkrate minimum_linkrate;
+ enum sas_linkrate maximum_linkrate;
+};
+
+struct hisi_sas_port {
+ struct asd_sas_port sas_port;
+ u8 port_attached;
+ u8 id; /* from hw */
+ struct list_head list;
+};
+
+struct hisi_sas_cq {
+ struct hisi_hba *hisi_hba;
+ int id;
+};
+
+struct hisi_sas_device {
+ enum sas_device_type dev_type;
+ struct hisi_hba *hisi_hba;
+ struct domain_device *sas_device;
+ u64 attached_phy;
+ u64 device_id;
+ u64 running_req;
+ u8 dev_status;
+};
+
+struct hisi_sas_slot {
+ struct list_head entry;
+ struct sas_task *task;
+ struct hisi_sas_port *port;
+ u64 n_elem;
+ int dlvry_queue;
+ int dlvry_queue_slot;
+ int cmplt_queue;
+ int cmplt_queue_slot;
+ int idx;
+ void *cmd_hdr;
+ dma_addr_t cmd_hdr_dma;
+ void *status_buffer;
+ dma_addr_t status_buffer_dma;
+ void *command_table;
+ dma_addr_t command_table_dma;
+ struct hisi_sas_sge_page *sge_page;
+ dma_addr_t sge_page_dma;
+};
+
+struct hisi_sas_tmf_task {
+ u8 tmf;
+ u16 tag_of_task_to_be_managed;
+};
+
+struct hisi_sas_hw {
+ int (*hw_init)(struct hisi_hba *hisi_hba);
+ void (*setup_itct)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *device);
+ void (*sl_notify)(struct hisi_hba *hisi_hba, int phy_no);
+ int (*get_free_slot)(struct hisi_hba *hisi_hba, int *q, int *s);
+ void (*start_delivery)(struct hisi_hba *hisi_hba);
+ int (*prep_ssp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf);
+ int (*prep_smp)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot);
+ int (*slot_complete)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int abort);
+ void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*phy_hard_reset)(struct hisi_hba *hisi_hba, int phy_no);
+ void (*free_device)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *dev);
+ int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id);
+ int complete_hdr_size;
+};
+
+struct hisi_hba {
+ /* This must be the first element, used by SHOST_TO_SAS_HA */
+ struct sas_ha_struct *p;
+
+ struct platform_device *pdev;
+ void __iomem *regs;
+ struct regmap *ctrl;
+ u32 ctrl_reset_reg;
+ u32 ctrl_reset_sts_reg;
+ u32 ctrl_clock_ena_reg;
+ u8 sas_addr[SAS_ADDR_SIZE];
+
+ int n_phy;
+ int scan_finished;
+ spinlock_t lock;
+
+ struct timer_list timer;
+ struct workqueue_struct *wq;
+
+ int slot_index_count;
+ unsigned long *slot_index_tags;
+
+ /* SCSI/SAS glue */
+ struct sas_ha_struct sha;
+ struct Scsi_Host *shost;
+
+ struct hisi_sas_cq cq[HISI_SAS_MAX_QUEUES];
+ struct hisi_sas_phy phy[HISI_SAS_MAX_PHYS];
+ struct hisi_sas_port port[HISI_SAS_MAX_PHYS];
+
+ int queue_count;
+ int queue;
+ struct hisi_sas_slot *slot_prep;
+
+ struct dma_pool *sge_page_pool;
+ struct hisi_sas_device devices[HISI_SAS_MAX_DEVICES];
+ struct dma_pool *command_table_pool;
+ struct dma_pool *status_buffer_pool;
+ struct hisi_sas_cmd_hdr *cmd_hdr[HISI_SAS_MAX_QUEUES];
+ dma_addr_t cmd_hdr_dma[HISI_SAS_MAX_QUEUES];
+ void *complete_hdr[HISI_SAS_MAX_QUEUES];
+ dma_addr_t complete_hdr_dma[HISI_SAS_MAX_QUEUES];
+ struct hisi_sas_initial_fis *initial_fis;
+ dma_addr_t initial_fis_dma;
+ struct hisi_sas_itct *itct;
+ dma_addr_t itct_dma;
+ struct hisi_sas_iost *iost;
+ dma_addr_t iost_dma;
+ struct hisi_sas_breakpoint *breakpoint;
+ dma_addr_t breakpoint_dma;
+ struct hisi_sas_breakpoint *sata_breakpoint;
+ dma_addr_t sata_breakpoint_dma;
+ struct hisi_sas_slot *slot_info;
+ const struct hisi_sas_hw *hw; /* Low level hw interface */
+};
+
+/* Generic HW DMA host memory structures */
+/* Delivery queue header */
+struct hisi_sas_cmd_hdr {
+ /* dw0 */
+ __le32 dw0;
+
+ /* dw1 */
+ __le32 dw1;
+
+ /* dw2 */
+ __le32 dw2;
+
+ /* dw3 */
+ __le32 transfer_tags;
+
+ /* dw4 */
+ __le32 data_transfer_len;
+
+ /* dw5 */
+ __le32 first_burst_num;
+
+ /* dw6 */
+ __le32 sg_len;
+
+ /* dw7 */
+ __le32 dw7;
+
+ /* dw8-9 */
+ __le64 cmd_table_addr;
+
+ /* dw10-11 */
+ __le64 sts_buffer_addr;
+
+ /* dw12-13 */
+ __le64 prd_table_addr;
+
+ /* dw14-15 */
+ __le64 dif_prd_table_addr;
+};
+
+struct hisi_sas_itct {
+ __le64 qw0;
+ __le64 sas_addr;
+ __le64 qw2;
+ __le64 qw3;
+ __le64 qw4;
+ __le64 qw_sata_ncq0_3;
+ __le64 qw_sata_ncq7_4;
+ __le64 qw_sata_ncq11_8;
+ __le64 qw_sata_ncq15_12;
+ __le64 qw_sata_ncq19_16;
+ __le64 qw_sata_ncq23_20;
+ __le64 qw_sata_ncq27_24;
+ __le64 qw_sata_ncq31_28;
+ __le64 qw_non_ncq_iptt;
+ __le64 qw_rsvd0;
+ __le64 qw_rsvd1;
+};
+
+struct hisi_sas_iost {
+ __le64 qw0;
+ __le64 qw1;
+ __le64 qw2;
+ __le64 qw3;
+};
+
+struct hisi_sas_err_record {
+ /* dw0 */
+ __le32 dma_err_type;
+
+ /* dw1 */
+ __le32 trans_tx_fail_type;
+
+ /* dw2 */
+ __le32 trans_rx_fail_type;
+
+ /* dw3 */
+ u32 rsvd;
+};
+
+struct hisi_sas_initial_fis {
+ struct hisi_sas_err_record err_record;
+ struct dev_to_host_fis fis;
+ u32 rsvd[3];
+};
+
+struct hisi_sas_breakpoint {
+ u8 data[128]; /*io128 byte*/
+};
+
+struct hisi_sas_sge {
+ __le64 addr;
+ __le32 page_ctrl_0;
+ __le32 page_ctrl_1;
+ __le32 data_len;
+ __le32 data_off;
+};
+
+struct hisi_sas_command_table_smp {
+ u8 bytes[44];
+};
+
+struct hisi_sas_command_table_stp {
+ struct host_to_dev_fis command_fis;
+ u8 dummy[12];
+ u8 atapi_cdb[ATAPI_CDB_LEN];
+};
+
+#define HISI_SAS_SGE_PAGE_CNT SCSI_MAX_SG_SEGMENTS
+struct hisi_sas_sge_page {
+ struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT];
+};
+
+struct hisi_sas_command_table_ssp {
+ struct ssp_frame_hdr hdr;
+ union {
+ struct {
+ struct ssp_command_iu task;
+ u32 prot[6];
+ };
+ struct ssp_tmf_iu ssp_task;
+ struct xfer_rdy_iu xfer_rdy;
+ struct ssp_response_iu ssp_res;
+ } u;
+};
+
+union hisi_sas_command_table {
+ struct hisi_sas_command_table_ssp ssp;
+ struct hisi_sas_command_table_smp smp;
+ struct hisi_sas_command_table_stp stp;
+};
+extern int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *ops);
+extern int hisi_sas_remove(struct platform_device *pdev);
+
+extern void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy);
+extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot);
+#endif
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
new file mode 100644
index 000000000..99b1950d7
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -0,0 +1,1358 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas"
+
+#define DEV_IS_EXPANDER(type) \
+ ((type == SAS_EDGE_EXPANDER_DEVICE) || \
+ (type == SAS_FANOUT_EXPANDER_DEVICE))
+
+#define DEV_IS_GONE(dev) \
+ ((!dev) || (dev->dev_type == SAS_PHY_UNUSED))
+
+static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
+{
+ return device->port->ha->lldd_ha;
+}
+
+static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ clear_bit(slot_idx, bitmap);
+}
+
+static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ hisi_sas_slot_index_clear(hisi_hba, slot_idx);
+}
+
+static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx)
+{
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ set_bit(slot_idx, bitmap);
+}
+
+static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, int *slot_idx)
+{
+ unsigned int index;
+ void *bitmap = hisi_hba->slot_index_tags;
+
+ index = find_first_zero_bit(bitmap, hisi_hba->slot_index_count);
+ if (index >= hisi_hba->slot_index_count)
+ return -SAS_QUEUE_FULL;
+ hisi_sas_slot_index_set(hisi_hba, index);
+ *slot_idx = index;
+ return 0;
+}
+
+static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->slot_index_count; ++i)
+ hisi_sas_slot_index_clear(hisi_hba, i);
+}
+
+void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ if (!slot->task)
+ return;
+
+ if (!sas_protocol_ata(task->task_proto))
+ if (slot->n_elem)
+ dma_unmap_sg(dev, task->scatter, slot->n_elem,
+ task->data_dir);
+
+ if (slot->command_table)
+ dma_pool_free(hisi_hba->command_table_pool,
+ slot->command_table, slot->command_table_dma);
+
+ if (slot->status_buffer)
+ dma_pool_free(hisi_hba->status_buffer_pool,
+ slot->status_buffer, slot->status_buffer_dma);
+
+ if (slot->sge_page)
+ dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+ slot->sge_page_dma);
+
+ list_del_init(&slot->entry);
+ task->lldd_task = NULL;
+ slot->task = NULL;
+ slot->port = NULL;
+ hisi_sas_slot_index_free(hisi_hba, slot->idx);
+ memset(slot, 0, sizeof(*slot));
+}
+EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free);
+
+static int hisi_sas_task_prep_smp(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ return hisi_hba->hw->prep_smp(hisi_hba, slot);
+}
+
+static int hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf)
+{
+ return hisi_hba->hw->prep_ssp(hisi_hba, slot, is_tmf, tmf);
+}
+
+static int hisi_sas_task_prep(struct sas_task *task, struct hisi_hba *hisi_hba,
+ int is_tmf, struct hisi_sas_tmf_task *tmf,
+ int *pass)
+{
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port;
+ struct hisi_sas_slot *slot;
+ struct hisi_sas_cmd_hdr *cmd_hdr_base;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+
+ if (!device->port) {
+ struct task_status_struct *ts = &task->task_status;
+
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ /*
+ * libsas will use dev->port, should
+ * not call task_done for sata
+ */
+ if (device->dev_type != SAS_SATA_DEV)
+ task->task_done(task);
+ return 0;
+ }
+
+ if (DEV_IS_GONE(sas_dev)) {
+ if (sas_dev)
+ dev_info(dev, "task prep: device %llu not ready\n",
+ sas_dev->device_id);
+ else
+ dev_info(dev, "task prep: device %016llx not ready\n",
+ SAS_ADDR(device->sas_addr));
+
+ rc = SAS_PHY_DOWN;
+ return rc;
+ }
+ port = device->port->lldd_port;
+ if (port && !port->port_attached && !tmf) {
+ if (sas_protocol_ata(task->task_proto)) {
+ struct task_status_struct *ts = &task->task_status;
+
+ dev_info(dev,
+ "task prep: SATA/STP port%d not attach device\n",
+ device->port->id);
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PHY_DOWN;
+ task->task_done(task);
+ } else {
+ struct task_status_struct *ts = &task->task_status;
+
+ dev_info(dev,
+ "task prep: SAS port%d does not attach device\n",
+ device->port->id);
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ task->task_done(task);
+ }
+ return 0;
+ }
+
+ if (!sas_protocol_ata(task->task_proto)) {
+ if (task->num_scatter) {
+ n_elem = dma_map_sg(dev, task->scatter,
+ task->num_scatter, task->data_dir);
+ if (!n_elem) {
+ rc = -ENOMEM;
+ goto prep_out;
+ }
+ }
+ } else
+ n_elem = task->num_scatter;
+
+ rc = hisi_sas_slot_index_alloc(hisi_hba, &slot_idx);
+ if (rc)
+ goto err_out;
+ rc = hisi_hba->hw->get_free_slot(hisi_hba, &dlvry_queue,
+ &dlvry_queue_slot);
+ if (rc)
+ goto err_out_tag;
+
+ slot = &hisi_hba->slot_info[slot_idx];
+ memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+ slot->idx = slot_idx;
+ slot->n_elem = n_elem;
+ slot->dlvry_queue = dlvry_queue;
+ slot->dlvry_queue_slot = dlvry_queue_slot;
+ cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
+ slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
+ slot->task = task;
+ slot->port = port;
+ task->lldd_task = slot;
+
+ slot->status_buffer = dma_pool_alloc(hisi_hba->status_buffer_pool,
+ GFP_ATOMIC,
+ &slot->status_buffer_dma);
+ if (!slot->status_buffer) {
+ rc = -ENOMEM;
+ goto err_out_slot_buf;
+ }
+ memset(slot->status_buffer, 0, HISI_SAS_STATUS_BUF_SZ);
+
+ slot->command_table = dma_pool_alloc(hisi_hba->command_table_pool,
+ GFP_ATOMIC,
+ &slot->command_table_dma);
+ if (!slot->command_table) {
+ rc = -ENOMEM;
+ goto err_out_status_buf;
+ }
+ memset(slot->command_table, 0, HISI_SAS_COMMAND_TABLE_SZ);
+ memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ rc = hisi_sas_task_prep_smp(hisi_hba, slot);
+ break;
+ case SAS_PROTOCOL_SSP:
+ rc = hisi_sas_task_prep_ssp(hisi_hba, slot, is_tmf, tmf);
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ default:
+ dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n",
+ task->task_proto);
+ rc = -EINVAL;
+ break;
+ }
+
+ if (rc) {
+ dev_err(dev, "task prep: rc = 0x%x\n", rc);
+ if (slot->sge_page)
+ goto err_out_sge;
+ goto err_out_command_table;
+ }
+
+ list_add_tail(&slot->entry, &port->list);
+ spin_lock(&task->task_state_lock);
+ task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock(&task->task_state_lock);
+
+ hisi_hba->slot_prep = slot;
+
+ sas_dev->running_req++;
+ ++(*pass);
+
+ return 0;
+
+err_out_sge:
+ dma_pool_free(hisi_hba->sge_page_pool, slot->sge_page,
+ slot->sge_page_dma);
+err_out_command_table:
+ dma_pool_free(hisi_hba->command_table_pool, slot->command_table,
+ slot->command_table_dma);
+err_out_status_buf:
+ dma_pool_free(hisi_hba->status_buffer_pool, slot->status_buffer,
+ slot->status_buffer_dma);
+err_out_slot_buf:
+ /* Nothing to be done */
+err_out_tag:
+ hisi_sas_slot_index_free(hisi_hba, slot_idx);
+err_out:
+ dev_err(dev, "task prep: failed[%d]!\n", rc);
+ if (!sas_protocol_ata(task->task_proto))
+ if (n_elem)
+ dma_unmap_sg(dev, task->scatter, n_elem,
+ task->data_dir);
+prep_out:
+ return rc;
+}
+
+static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
+ int is_tmf, struct hisi_sas_tmf_task *tmf)
+{
+ u32 rc;
+ u32 pass = 0;
+ unsigned long flags;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ /* protect task_prep and start_delivery sequence */
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ rc = hisi_sas_task_prep(task, hisi_hba, is_tmf, tmf, &pass);
+ if (rc)
+ dev_err(dev, "task exec: failed[%d]!\n", rc);
+
+ if (likely(pass))
+ hisi_hba->hw->start_delivery(hisi_hba);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+ return rc;
+}
+
+static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha;
+
+ if (!phy->phy_attached)
+ return;
+
+ sas_ha = &hisi_hba->sha;
+ sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE);
+
+ if (sas_phy->phy) {
+ struct sas_phy *sphy = sas_phy->phy;
+
+ sphy->negotiated_linkrate = sas_phy->linkrate;
+ sphy->minimum_linkrate = phy->minimum_linkrate;
+ sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+ sphy->maximum_linkrate = phy->maximum_linkrate;
+ }
+
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ struct sas_identify_frame *id;
+
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTOCOL_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ /*Nothing*/
+ }
+
+ sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
+ sas_ha->notify_port_event(sas_phy, PORTE_BYTES_DMAED);
+}
+
+static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
+{
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct hisi_sas_device *sas_dev = NULL;
+ int i;
+
+ spin_lock(&hisi_hba->lock);
+ for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+ if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
+ hisi_hba->devices[i].device_id = i;
+ sas_dev = &hisi_hba->devices[i];
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+ sas_dev->dev_type = device->dev_type;
+ sas_dev->hisi_hba = hisi_hba;
+ sas_dev->sas_device = device;
+ break;
+ }
+ }
+ spin_unlock(&hisi_hba->lock);
+
+ return sas_dev;
+}
+
+static int hisi_sas_dev_found(struct domain_device *device)
+{
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct domain_device *parent_dev = device->parent;
+ struct hisi_sas_device *sas_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ sas_dev = hisi_sas_alloc_dev(device);
+ if (!sas_dev) {
+ dev_err(dev, "fail alloc dev: max support %d devices\n",
+ HISI_SAS_MAX_DEVICES);
+ return -EINVAL;
+ }
+
+ device->lldd_dev = sas_dev;
+ hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
+
+ if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) {
+ int phy_no;
+ u8 phy_num = parent_dev->ex_dev.num_phys;
+ struct ex_phy *phy;
+
+ for (phy_no = 0; phy_no < phy_num; phy_no++) {
+ phy = &parent_dev->ex_dev.ex_phy[phy_no];
+ if (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(device->sas_addr)) {
+ sas_dev->attached_phy = phy_no;
+ break;
+ }
+ }
+
+ if (phy_no == phy_num) {
+ dev_info(dev, "dev found: no attached "
+ "dev:%016llx at ex:%016llx\n",
+ SAS_ADDR(device->sas_addr),
+ SAS_ADDR(parent_dev->sas_addr));
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void hisi_sas_scan_start(struct Scsi_Host *shost)
+{
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; ++i)
+ hisi_sas_bytes_dmaed(hisi_hba, i);
+
+ hisi_hba->scan_finished = 1;
+}
+
+static int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ struct hisi_hba *hisi_hba = shost_priv(shost);
+ struct sas_ha_struct *sha = &hisi_hba->sha;
+
+ if (hisi_hba->scan_finished == 0)
+ return 0;
+
+ sas_drain_work(sha);
+ return 1;
+}
+
+static void hisi_sas_phyup_work(struct work_struct *work)
+{
+ struct hisi_sas_phy *phy =
+ container_of(work, struct hisi_sas_phy, phyup_ws);
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ int phy_no = sas_phy->id;
+
+ hisi_hba->hw->sl_notify(hisi_hba, phy_no); /* This requires a sleep */
+ hisi_sas_bytes_dmaed(hisi_hba, phy_no);
+}
+
+static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ phy->hisi_hba = hisi_hba;
+ phy->port = NULL;
+ init_timer(&phy->timer);
+ sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0;
+ sas_phy->class = SAS;
+ sas_phy->iproto = SAS_PROTOCOL_ALL;
+ sas_phy->tproto = 0;
+ sas_phy->type = PHY_TYPE_PHYSICAL;
+ sas_phy->role = PHY_ROLE_INITIATOR;
+ sas_phy->oob_mode = OOB_NOT_CONNECTED;
+ sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+ sas_phy->id = phy_no;
+ sas_phy->sas_addr = &hisi_hba->sas_addr[0];
+ sas_phy->frame_rcvd = &phy->frame_rcvd[0];
+ sas_phy->ha = (struct sas_ha_struct *)hisi_hba->shost->hostdata;
+ sas_phy->lldd_phy = phy;
+
+ INIT_WORK(&phy->phyup_ws, hisi_sas_phyup_work);
+}
+
+static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
+{
+ struct sas_ha_struct *sas_ha = sas_phy->ha;
+ struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+ struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+ struct asd_sas_port *sas_port = sas_phy->port;
+ struct hisi_sas_port *port = &hisi_hba->port[sas_phy->id];
+ unsigned long flags;
+
+ if (!sas_port)
+ return;
+
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ port->port_attached = 1;
+ port->id = phy->port_id;
+ phy->port = port;
+ sas_port->lldd_port = port;
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+}
+
+static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, int phy_no,
+ struct domain_device *device)
+{
+ struct hisi_sas_phy *phy;
+ struct hisi_sas_port *port;
+ struct hisi_sas_slot *slot, *slot2;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ phy = &hisi_hba->phy[phy_no];
+ port = phy->port;
+ if (!port)
+ return;
+
+ list_for_each_entry_safe(slot, slot2, &port->list, entry) {
+ struct sas_task *task;
+
+ task = slot->task;
+ if (device && task->dev != device)
+ continue;
+
+ dev_info(dev, "Release slot [%d:%d], task [%p]:\n",
+ slot->dlvry_queue, slot->dlvry_queue_slot, task);
+ hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+ }
+}
+
+static void hisi_sas_port_notify_deformed(struct asd_sas_phy *sas_phy)
+{
+ struct domain_device *device;
+ struct hisi_sas_phy *phy = sas_phy->lldd_phy;
+ struct asd_sas_port *sas_port = sas_phy->port;
+
+ list_for_each_entry(device, &sas_port->dev_list, dev_list_node)
+ hisi_sas_do_release_task(phy->hisi_hba, sas_phy->id, device);
+}
+
+static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
+ struct domain_device *device)
+{
+ struct asd_sas_port *port = device->port;
+ struct asd_sas_phy *sas_phy;
+
+ list_for_each_entry(sas_phy, &port->phy_list, port_phy_el)
+ hisi_sas_do_release_task(hisi_hba, sas_phy->id, device);
+}
+
+static void hisi_sas_dev_gone(struct domain_device *device)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct device *dev = &hisi_hba->pdev->dev;
+ u64 dev_id = sas_dev->device_id;
+
+ dev_info(dev, "found dev[%lld:%x] is gone\n",
+ sas_dev->device_id, sas_dev->dev_type);
+
+ hisi_hba->hw->free_device(hisi_hba, sas_dev);
+ device->lldd_dev = NULL;
+ memset(sas_dev, 0, sizeof(*sas_dev));
+ sas_dev->device_id = dev_id;
+ sas_dev->dev_type = SAS_PHY_UNUSED;
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+}
+
+static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
+{
+ return hisi_sas_task_exec(task, gfp_flags, 0, NULL);
+}
+
+static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
+ void *funcdata)
+{
+ struct sas_ha_struct *sas_ha = sas_phy->ha;
+ struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
+ int phy_no = sas_phy->id;
+
+ switch (func) {
+ case PHY_FUNC_HARD_RESET:
+ hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_LINK_RESET:
+ hisi_hba->hw->phy_enable(hisi_hba, phy_no);
+ hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_DISABLE:
+ hisi_hba->hw->phy_disable(hisi_hba, phy_no);
+ break;
+
+ case PHY_FUNC_SET_LINK_RATE:
+ case PHY_FUNC_RELEASE_SPINUP_HOLD:
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static void hisi_sas_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->slow_task->timer))
+ return;
+ complete(&task->slow_task->completion);
+}
+
+static void hisi_sas_tmf_timedout(unsigned long data)
+{
+ struct sas_task *task = (struct sas_task *)data;
+
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ complete(&task->slow_task->completion);
+}
+
+#define TASK_TIMEOUT 20
+#define TASK_RETRY 3
+static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
+ void *parameter, u32 para_len,
+ struct hisi_sas_tmf_task *tmf)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct sas_task *task;
+ int res, retry;
+
+ for (retry = 0; retry < TASK_RETRY; retry++) {
+ task = sas_alloc_slow_task(GFP_KERNEL);
+ if (!task)
+ return -ENOMEM;
+
+ task->dev = device;
+ task->task_proto = device->tproto;
+
+ memcpy(&task->ssp_task, parameter, para_len);
+ task->task_done = hisi_sas_task_done;
+
+ task->slow_task->timer.data = (unsigned long) task;
+ task->slow_task->timer.function = hisi_sas_tmf_timedout;
+ task->slow_task->timer.expires = jiffies + TASK_TIMEOUT*HZ;
+ add_timer(&task->slow_task->timer);
+
+ res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf);
+
+ if (res) {
+ del_timer(&task->slow_task->timer);
+ dev_err(dev, "abort tmf: executing internal task failed: %d\n",
+ res);
+ goto ex_err;
+ }
+
+ wait_for_completion(&task->slow_task->completion);
+ res = TMF_RESP_FUNC_FAILED;
+ /* Even TMF timed out, return direct. */
+ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ dev_err(dev, "abort tmf: TMF task[%d] timeout\n",
+ tmf->tag_of_task_to_be_managed);
+ if (task->lldd_task) {
+ struct hisi_sas_slot *slot =
+ task->lldd_task;
+
+ hisi_sas_slot_task_free(hisi_hba,
+ task, slot);
+ }
+
+ goto ex_err;
+ }
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAM_STAT_GOOD) {
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_UNDERRUN) {
+ /* no error, but return the number of bytes of
+ * underrun
+ */
+ dev_warn(dev, "abort tmf: task to dev %016llx "
+ "resp: 0x%x sts 0x%x underrun\n",
+ SAS_ADDR(device->sas_addr),
+ task->task_status.resp,
+ task->task_status.stat);
+ res = task->task_status.residual;
+ break;
+ }
+
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAS_DATA_OVERRUN) {
+ dev_warn(dev, "abort tmf: blocked task error\n");
+ res = -EMSGSIZE;
+ break;
+ }
+
+ dev_warn(dev, "abort tmf: task to dev "
+ "%016llx resp: 0x%x status 0x%x\n",
+ SAS_ADDR(device->sas_addr), task->task_status.resp,
+ task->task_status.stat);
+ sas_free_task(task);
+ task = NULL;
+ }
+ex_err:
+ WARN_ON(retry == TASK_RETRY);
+ sas_free_task(task);
+ return res;
+}
+
+static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
+ u8 *lun, struct hisi_sas_tmf_task *tmf)
+{
+ struct sas_ssp_task ssp_task;
+
+ if (!(device->tproto & SAS_PROTOCOL_SSP))
+ return TMF_RESP_FUNC_ESUPP;
+
+ memcpy(ssp_task.LUN, lun, 8);
+
+ return hisi_sas_exec_internal_tmf_task(device, &ssp_task,
+ sizeof(ssp_task), tmf);
+}
+
+static int hisi_sas_abort_task(struct sas_task *task)
+{
+ struct scsi_lun lun;
+ struct hisi_sas_tmf_task tmf_task;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(task->dev);
+ struct device *dev = &hisi_hba->pdev->dev;
+ int rc = TMF_RESP_FUNC_FAILED;
+ unsigned long flags;
+
+ if (!sas_dev) {
+ dev_warn(dev, "Device has been removed\n");
+ return TMF_RESP_FUNC_FAILED;
+ }
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ }
+
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ sas_dev->dev_status = HISI_SAS_DEV_EH;
+ if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct hisi_sas_slot *slot = task->lldd_task;
+ u32 tag = slot->idx;
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ tmf_task.tmf = TMF_ABORT_TASK;
+ tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+ rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun,
+ &tmf_task);
+
+ /* if successful, clear the task and callback forwards.*/
+ if (rc == TMF_RESP_FUNC_COMPLETE) {
+ if (task->lldd_task) {
+ struct hisi_sas_slot *slot;
+
+ slot = &hisi_hba->slot_info
+ [tmf_task.tag_of_task_to_be_managed];
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_hba->hw->slot_complete(hisi_hba, slot, 1);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ }
+ }
+
+ } else if (task->task_proto & SAS_PROTOCOL_SATA ||
+ task->task_proto & SAS_PROTOCOL_STP) {
+ if (task->dev->dev_type == SAS_SATA_DEV) {
+ struct hisi_slot_info *slot = task->lldd_task;
+
+ dev_notice(dev, "abort task: hba=%p task=%p slot=%p\n",
+ hisi_hba, task, slot);
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out;
+ }
+
+ }
+
+out:
+ if (rc != TMF_RESP_FUNC_COMPLETE)
+ dev_notice(dev, "abort task: rc=%d\n", rc);
+ return rc;
+}
+
+static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
+{
+ struct hisi_sas_tmf_task tmf_task;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ tmf_task.tmf = TMF_ABORT_TASK_SET;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+
+ return rc;
+}
+
+static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun)
+{
+ int rc = TMF_RESP_FUNC_FAILED;
+ struct hisi_sas_tmf_task tmf_task;
+
+ tmf_task.tmf = TMF_CLEAR_ACA;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+
+ return rc;
+}
+
+static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
+{
+ struct sas_phy *phy = sas_get_local_phy(device);
+ int rc, reset_type = (device->dev_type == SAS_SATA_DEV ||
+ (device->tproto & SAS_PROTOCOL_STP)) ? 0 : 1;
+ rc = sas_phy_reset(phy, reset_type);
+ sas_put_local_phy(phy);
+ msleep(2000);
+ return rc;
+}
+
+static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
+{
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ unsigned long flags;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ if (sas_dev->dev_status != HISI_SAS_DEV_EH)
+ return TMF_RESP_FUNC_FAILED;
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+
+ rc = hisi_sas_debug_I_T_nexus_reset(device);
+
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_release_task(hisi_hba, device);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+
+ return 0;
+}
+
+static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
+{
+ struct hisi_sas_tmf_task tmf_task;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
+ struct device *dev = &hisi_hba->pdev->dev;
+ unsigned long flags;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ tmf_task.tmf = TMF_LU_RESET;
+ sas_dev->dev_status = HISI_SAS_DEV_EH;
+ rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
+ if (rc == TMF_RESP_FUNC_COMPLETE) {
+ spin_lock_irqsave(&hisi_hba->lock, flags);
+ hisi_sas_release_task(hisi_hba, device);
+ spin_unlock_irqrestore(&hisi_hba->lock, flags);
+ }
+
+ /* If failed, fall-through I_T_Nexus reset */
+ dev_err(dev, "lu_reset: for device[%llx]:rc= %d\n",
+ sas_dev->device_id, rc);
+ return rc;
+}
+
+static int hisi_sas_query_task(struct sas_task *task)
+{
+ struct scsi_lun lun;
+ struct hisi_sas_tmf_task tmf_task;
+ int rc = TMF_RESP_FUNC_FAILED;
+
+ if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
+ struct scsi_cmnd *cmnd = task->uldd_task;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_slot *slot = task->lldd_task;
+ u32 tag = slot->idx;
+
+ int_to_scsilun(cmnd->device->lun, &lun);
+ tmf_task.tmf = TMF_QUERY_TASK;
+ tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag);
+
+ rc = hisi_sas_debug_issue_ssp_tmf(device,
+ lun.scsi_lun,
+ &tmf_task);
+ switch (rc) {
+ /* The task is still in Lun, release it then */
+ case TMF_RESP_FUNC_SUCC:
+ /* The task is not in Lun or failed, reset the phy */
+ case TMF_RESP_FUNC_FAILED:
+ case TMF_RESP_FUNC_COMPLETE:
+ break;
+ }
+ }
+ return rc;
+}
+
+static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
+{
+ hisi_sas_port_notify_formed(sas_phy);
+}
+
+static void hisi_sas_port_deformed(struct asd_sas_phy *sas_phy)
+{
+ hisi_sas_port_notify_deformed(sas_phy);
+}
+
+static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
+{
+ phy->phy_attached = 0;
+ phy->phy_type = 0;
+ phy->port = NULL;
+}
+
+void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
+{
+ struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sas_ha = &hisi_hba->sha;
+
+ if (rdy) {
+ /* Phy down but ready */
+ hisi_sas_bytes_dmaed(hisi_hba, phy_no);
+ hisi_sas_port_notify_formed(sas_phy);
+ } else {
+ struct hisi_sas_port *port = phy->port;
+
+ /* Phy down and not ready */
+ sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
+ sas_phy_disconnected(sas_phy);
+
+ if (port) {
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ int port_id = port->id;
+
+ if (!hisi_hba->hw->get_wideport_bitmap(hisi_hba,
+ port_id))
+ port->port_attached = 0;
+ } else if (phy->phy_type & PORT_TYPE_SATA)
+ port->port_attached = 0;
+ }
+ hisi_sas_phy_disconnected(phy);
+ }
+}
+EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
+
+static struct scsi_transport_template *hisi_sas_stt;
+
+static struct scsi_host_template hisi_sas_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = sas_slave_configure,
+ .scan_finished = hisi_sas_scan_finished,
+ .scan_start = hisi_sas_scan_start,
+ .change_queue_depth = sas_change_queue_depth,
+ .bios_param = sas_bios_param,
+ .can_queue = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+ .eh_bus_reset_handler = sas_eh_bus_reset_handler,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
+};
+
+static struct sas_domain_function_template hisi_sas_transport_ops = {
+ .lldd_dev_found = hisi_sas_dev_found,
+ .lldd_dev_gone = hisi_sas_dev_gone,
+ .lldd_execute_task = hisi_sas_queue_command,
+ .lldd_control_phy = hisi_sas_control_phy,
+ .lldd_abort_task = hisi_sas_abort_task,
+ .lldd_abort_task_set = hisi_sas_abort_task_set,
+ .lldd_clear_aca = hisi_sas_clear_aca,
+ .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset,
+ .lldd_lu_reset = hisi_sas_lu_reset,
+ .lldd_query_task = hisi_sas_query_task,
+ .lldd_port_formed = hisi_sas_port_formed,
+ .lldd_port_deformed = hisi_sas_port_deformed,
+};
+
+static int hisi_sas_alloc(struct hisi_hba *hisi_hba, struct Scsi_Host *shost)
+{
+ int i, s;
+ struct platform_device *pdev = hisi_hba->pdev;
+ struct device *dev = &pdev->dev;
+
+ spin_lock_init(&hisi_hba->lock);
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_init(hisi_hba, i);
+ hisi_hba->port[i].port_attached = 0;
+ hisi_hba->port[i].id = -1;
+ INIT_LIST_HEAD(&hisi_hba->port[i].list);
+ }
+
+ for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
+ hisi_hba->devices[i].dev_type = SAS_PHY_UNUSED;
+ hisi_hba->devices[i].device_id = i;
+ hisi_hba->devices[i].dev_status = HISI_SAS_DEV_NORMAL;
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ struct hisi_sas_cq *cq = &hisi_hba->cq[i];
+
+ /* Completion queue structure */
+ cq->id = i;
+ cq->hisi_hba = hisi_hba;
+
+ /* Delivery queue */
+ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+ hisi_hba->cmd_hdr[i] = dma_alloc_coherent(dev, s,
+ &hisi_hba->cmd_hdr_dma[i], GFP_KERNEL);
+ if (!hisi_hba->cmd_hdr[i])
+ goto err_out;
+ memset(hisi_hba->cmd_hdr[i], 0, s);
+
+ /* Completion queue */
+ s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+ hisi_hba->complete_hdr[i] = dma_alloc_coherent(dev, s,
+ &hisi_hba->complete_hdr_dma[i], GFP_KERNEL);
+ if (!hisi_hba->complete_hdr[i])
+ goto err_out;
+ memset(hisi_hba->complete_hdr[i], 0, s);
+ }
+
+ s = HISI_SAS_STATUS_BUF_SZ;
+ hisi_hba->status_buffer_pool = dma_pool_create("status_buffer",
+ dev, s, 16, 0);
+ if (!hisi_hba->status_buffer_pool)
+ goto err_out;
+
+ s = HISI_SAS_COMMAND_TABLE_SZ;
+ hisi_hba->command_table_pool = dma_pool_create("command_table",
+ dev, s, 16, 0);
+ if (!hisi_hba->command_table_pool)
+ goto err_out;
+
+ s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ hisi_hba->itct = dma_alloc_coherent(dev, s, &hisi_hba->itct_dma,
+ GFP_KERNEL);
+ if (!hisi_hba->itct)
+ goto err_out;
+
+ memset(hisi_hba->itct, 0, s);
+
+ hisi_hba->slot_info = devm_kcalloc(dev, HISI_SAS_COMMAND_ENTRIES,
+ sizeof(struct hisi_sas_slot),
+ GFP_KERNEL);
+ if (!hisi_hba->slot_info)
+ goto err_out;
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost);
+ hisi_hba->iost = dma_alloc_coherent(dev, s, &hisi_hba->iost_dma,
+ GFP_KERNEL);
+ if (!hisi_hba->iost)
+ goto err_out;
+
+ memset(hisi_hba->iost, 0, s);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+ hisi_hba->breakpoint = dma_alloc_coherent(dev, s,
+ &hisi_hba->breakpoint_dma, GFP_KERNEL);
+ if (!hisi_hba->breakpoint)
+ goto err_out;
+
+ memset(hisi_hba->breakpoint, 0, s);
+
+ hisi_hba->slot_index_count = HISI_SAS_COMMAND_ENTRIES;
+ s = hisi_hba->slot_index_count / sizeof(unsigned long);
+ hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL);
+ if (!hisi_hba->slot_index_tags)
+ goto err_out;
+
+ hisi_hba->sge_page_pool = dma_pool_create("status_sge", dev,
+ sizeof(struct hisi_sas_sge_page), 16, 0);
+ if (!hisi_hba->sge_page_pool)
+ goto err_out;
+
+ s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+ hisi_hba->initial_fis = dma_alloc_coherent(dev, s,
+ &hisi_hba->initial_fis_dma, GFP_KERNEL);
+ if (!hisi_hba->initial_fis)
+ goto err_out;
+ memset(hisi_hba->initial_fis, 0, s);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2;
+ hisi_hba->sata_breakpoint = dma_alloc_coherent(dev, s,
+ &hisi_hba->sata_breakpoint_dma, GFP_KERNEL);
+ if (!hisi_hba->sata_breakpoint)
+ goto err_out;
+ memset(hisi_hba->sata_breakpoint, 0, s);
+
+ hisi_sas_slot_index_init(hisi_hba);
+
+ hisi_hba->wq = create_singlethread_workqueue(dev_name(dev));
+ if (!hisi_hba->wq) {
+ dev_err(dev, "sas_alloc: failed to create workqueue\n");
+ goto err_out;
+ }
+
+ return 0;
+err_out:
+ return -ENOMEM;
+}
+
+static void hisi_sas_free(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ int i, s;
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
+ if (hisi_hba->cmd_hdr[i])
+ dma_free_coherent(dev, s,
+ hisi_hba->cmd_hdr[i],
+ hisi_hba->cmd_hdr_dma[i]);
+
+ s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
+ if (hisi_hba->complete_hdr[i])
+ dma_free_coherent(dev, s,
+ hisi_hba->complete_hdr[i],
+ hisi_hba->complete_hdr_dma[i]);
+ }
+
+ dma_pool_destroy(hisi_hba->status_buffer_pool);
+ dma_pool_destroy(hisi_hba->command_table_pool);
+ dma_pool_destroy(hisi_hba->sge_page_pool);
+
+ s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
+ if (hisi_hba->itct)
+ dma_free_coherent(dev, s,
+ hisi_hba->itct, hisi_hba->itct_dma);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_iost);
+ if (hisi_hba->iost)
+ dma_free_coherent(dev, s,
+ hisi_hba->iost, hisi_hba->iost_dma);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint);
+ if (hisi_hba->breakpoint)
+ dma_free_coherent(dev, s,
+ hisi_hba->breakpoint,
+ hisi_hba->breakpoint_dma);
+
+
+ s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
+ if (hisi_hba->initial_fis)
+ dma_free_coherent(dev, s,
+ hisi_hba->initial_fis,
+ hisi_hba->initial_fis_dma);
+
+ s = HISI_SAS_COMMAND_ENTRIES * sizeof(struct hisi_sas_breakpoint) * 2;
+ if (hisi_hba->sata_breakpoint)
+ dma_free_coherent(dev, s,
+ hisi_hba->sata_breakpoint,
+ hisi_hba->sata_breakpoint_dma);
+
+ if (hisi_hba->wq)
+ destroy_workqueue(hisi_hba->wq);
+}
+
+static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
+ const struct hisi_sas_hw *hw)
+{
+ struct resource *res;
+ struct Scsi_Host *shost;
+ struct hisi_hba *hisi_hba;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct property *sas_addr_prop;
+
+ shost = scsi_host_alloc(&hisi_sas_sht, sizeof(*hisi_hba));
+ if (!shost)
+ goto err_out;
+ hisi_hba = shost_priv(shost);
+
+ hisi_hba->hw = hw;
+ hisi_hba->pdev = pdev;
+ hisi_hba->shost = shost;
+ SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
+
+ init_timer(&hisi_hba->timer);
+
+ sas_addr_prop = of_find_property(np, "sas-addr", NULL);
+ if (!sas_addr_prop || (sas_addr_prop->length != SAS_ADDR_SIZE))
+ goto err_out;
+ memcpy(hisi_hba->sas_addr, sas_addr_prop->value, SAS_ADDR_SIZE);
+
+ if (of_property_read_u32(np, "ctrl-reset-reg",
+ &hisi_hba->ctrl_reset_reg))
+ goto err_out;
+
+ if (of_property_read_u32(np, "ctrl-reset-sts-reg",
+ &hisi_hba->ctrl_reset_sts_reg))
+ goto err_out;
+
+ if (of_property_read_u32(np, "ctrl-clock-ena-reg",
+ &hisi_hba->ctrl_clock_ena_reg))
+ goto err_out;
+
+ if (of_property_read_u32(np, "phy-count", &hisi_hba->n_phy))
+ goto err_out;
+
+ if (of_property_read_u32(np, "queue-count", &hisi_hba->queue_count))
+ goto err_out;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hisi_hba->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hisi_hba->regs))
+ goto err_out;
+
+ hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(
+ np, "hisilicon,sas-syscon");
+ if (IS_ERR(hisi_hba->ctrl))
+ goto err_out;
+
+ if (hisi_sas_alloc(hisi_hba, shost)) {
+ hisi_sas_free(hisi_hba);
+ goto err_out;
+ }
+
+ return shost;
+err_out:
+ dev_err(dev, "shost alloc failed\n");
+ return NULL;
+}
+
+static void hisi_sas_init_add(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ memcpy(&hisi_hba->phy[i].dev_sas_addr,
+ hisi_hba->sas_addr,
+ SAS_ADDR_SIZE);
+}
+
+int hisi_sas_probe(struct platform_device *pdev,
+ const struct hisi_sas_hw *hw)
+{
+ struct Scsi_Host *shost;
+ struct hisi_hba *hisi_hba;
+ struct device *dev = &pdev->dev;
+ struct asd_sas_phy **arr_phy;
+ struct asd_sas_port **arr_port;
+ struct sas_ha_struct *sha;
+ int rc, phy_nr, port_nr, i;
+
+ shost = hisi_sas_shost_alloc(pdev, hw);
+ if (!shost) {
+ rc = -ENOMEM;
+ goto err_out_ha;
+ }
+
+ sha = SHOST_TO_SAS_HA(shost);
+ hisi_hba = shost_priv(shost);
+ platform_set_drvdata(pdev, sha);
+
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)) &&
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
+ dev_err(dev, "No usable DMA addressing method\n");
+ rc = -EIO;
+ goto err_out_ha;
+ }
+
+ phy_nr = port_nr = hisi_hba->n_phy;
+
+ arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL);
+ arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL);
+ if (!arr_phy || !arr_port)
+ return -ENOMEM;
+
+ sha->sas_phy = arr_phy;
+ sha->sas_port = arr_port;
+ sha->core.shost = shost;
+ sha->lldd_ha = hisi_hba;
+
+ shost->transportt = hisi_sas_stt;
+ shost->max_id = HISI_SAS_MAX_DEVICES;
+ shost->max_lun = ~0;
+ shost->max_channel = 1;
+ shost->max_cmd_len = 16;
+ shost->sg_tablesize = min_t(u16, SG_ALL, HISI_SAS_SGE_PAGE_CNT);
+ shost->can_queue = HISI_SAS_COMMAND_ENTRIES;
+ shost->cmd_per_lun = HISI_SAS_COMMAND_ENTRIES;
+
+ sha->sas_ha_name = DRV_NAME;
+ sha->dev = &hisi_hba->pdev->dev;
+ sha->lldd_module = THIS_MODULE;
+ sha->sas_addr = &hisi_hba->sas_addr[0];
+ sha->num_phys = hisi_hba->n_phy;
+ sha->core.shost = hisi_hba->shost;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy;
+ sha->sas_port[i] = &hisi_hba->port[i].sas_port;
+ }
+
+ hisi_sas_init_add(hisi_hba);
+
+ rc = hisi_hba->hw->hw_init(hisi_hba);
+ if (rc)
+ goto err_out_ha;
+
+ rc = scsi_add_host(shost, &pdev->dev);
+ if (rc)
+ goto err_out_ha;
+
+ rc = sas_register_ha(sha);
+ if (rc)
+ goto err_out_register_ha;
+
+ scsi_scan_host(shost);
+
+ return 0;
+
+err_out_register_ha:
+ scsi_remove_host(shost);
+err_out_ha:
+ kfree(shost);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_probe);
+
+int hisi_sas_remove(struct platform_device *pdev)
+{
+ struct sas_ha_struct *sha = platform_get_drvdata(pdev);
+ struct hisi_hba *hisi_hba = sha->lldd_ha;
+
+ scsi_remove_host(sha->core.shost);
+ sas_unregister_ha(sha);
+ sas_remove_host(sha->core.shost);
+
+ hisi_sas_free(hisi_hba);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hisi_sas_remove);
+
+static __init int hisi_sas_init(void)
+{
+ pr_info("hisi_sas: driver version %s\n", DRV_VERSION);
+
+ hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops);
+ if (!hisi_sas_stt)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static __exit void hisi_sas_exit(void)
+{
+ sas_release_transport(hisi_sas_stt);
+}
+
+module_init(hisi_sas_init);
+module_exit(hisi_sas_exit);
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
new file mode 100644
index 000000000..eea24d753
--- /dev/null
+++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
@@ -0,0 +1,1832 @@
+/*
+ * Copyright (c) 2015 Linaro Ltd.
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hisi_sas.h"
+#define DRV_NAME "hisi_sas_v1_hw"
+
+/* global registers need init*/
+#define DLVRY_QUEUE_ENABLE 0x0
+#define IOST_BASE_ADDR_LO 0x8
+#define IOST_BASE_ADDR_HI 0xc
+#define ITCT_BASE_ADDR_LO 0x10
+#define ITCT_BASE_ADDR_HI 0x14
+#define BROKEN_MSG_ADDR_LO 0x18
+#define BROKEN_MSG_ADDR_HI 0x1c
+#define PHY_CONTEXT 0x20
+#define PHY_STATE 0x24
+#define PHY_PORT_NUM_MA 0x28
+#define PORT_STATE 0x2c
+#define PHY_CONN_RATE 0x30
+#define HGC_TRANS_TASK_CNT_LIMIT 0x38
+#define AXI_AHB_CLK_CFG 0x3c
+#define HGC_SAS_TXFAIL_RETRY_CTRL 0x84
+#define HGC_GET_ITV_TIME 0x90
+#define DEVICE_MSG_WORK_MODE 0x94
+#define I_T_NEXUS_LOSS_TIME 0xa0
+#define BUS_INACTIVE_LIMIT_TIME 0xa8
+#define REJECT_TO_OPEN_LIMIT_TIME 0xac
+#define CFG_AGING_TIME 0xbc
+#define CFG_AGING_TIME_ITCT_REL_OFF 0
+#define CFG_AGING_TIME_ITCT_REL_MSK (0x1 << CFG_AGING_TIME_ITCT_REL_OFF)
+#define HGC_DFX_CFG2 0xc0
+#define FIS_LIST_BADDR_L 0xc4
+#define CFG_1US_TIMER_TRSH 0xcc
+#define CFG_SAS_CONFIG 0xd4
+#define HGC_IOST_ECC_ADDR 0x140
+#define HGC_IOST_ECC_ADDR_BAD_OFF 16
+#define HGC_IOST_ECC_ADDR_BAD_MSK (0x3ff << HGC_IOST_ECC_ADDR_BAD_OFF)
+#define HGC_DQ_ECC_ADDR 0x144
+#define HGC_DQ_ECC_ADDR_BAD_OFF 16
+#define HGC_DQ_ECC_ADDR_BAD_MSK (0xfff << HGC_DQ_ECC_ADDR_BAD_OFF)
+#define HGC_INVLD_DQE_INFO 0x148
+#define HGC_INVLD_DQE_INFO_DQ_OFF 0
+#define HGC_INVLD_DQE_INFO_DQ_MSK (0xffff << HGC_INVLD_DQE_INFO_DQ_OFF)
+#define HGC_INVLD_DQE_INFO_TYPE_OFF 16
+#define HGC_INVLD_DQE_INFO_TYPE_MSK (0x1 << HGC_INVLD_DQE_INFO_TYPE_OFF)
+#define HGC_INVLD_DQE_INFO_FORCE_OFF 17
+#define HGC_INVLD_DQE_INFO_FORCE_MSK (0x1 << HGC_INVLD_DQE_INFO_FORCE_OFF)
+#define HGC_INVLD_DQE_INFO_PHY_OFF 18
+#define HGC_INVLD_DQE_INFO_PHY_MSK (0x1 << HGC_INVLD_DQE_INFO_PHY_OFF)
+#define HGC_INVLD_DQE_INFO_ABORT_OFF 19
+#define HGC_INVLD_DQE_INFO_ABORT_MSK (0x1 << HGC_INVLD_DQE_INFO_ABORT_OFF)
+#define HGC_INVLD_DQE_INFO_IPTT_OF_OFF 20
+#define HGC_INVLD_DQE_INFO_IPTT_OF_MSK (0x1 << HGC_INVLD_DQE_INFO_IPTT_OF_OFF)
+#define HGC_INVLD_DQE_INFO_SSP_ERR_OFF 21
+#define HGC_INVLD_DQE_INFO_SSP_ERR_MSK (0x1 << HGC_INVLD_DQE_INFO_SSP_ERR_OFF)
+#define HGC_INVLD_DQE_INFO_OFL_OFF 22
+#define HGC_INVLD_DQE_INFO_OFL_MSK (0x1 << HGC_INVLD_DQE_INFO_OFL_OFF)
+#define HGC_ITCT_ECC_ADDR 0x150
+#define HGC_ITCT_ECC_ADDR_BAD_OFF 16
+#define HGC_ITCT_ECC_ADDR_BAD_MSK (0x3ff << HGC_ITCT_ECC_ADDR_BAD_OFF)
+#define HGC_AXI_FIFO_ERR_INFO 0x154
+#define INT_COAL_EN 0x1bc
+#define OQ_INT_COAL_TIME 0x1c0
+#define OQ_INT_COAL_CNT 0x1c4
+#define ENT_INT_COAL_TIME 0x1c8
+#define ENT_INT_COAL_CNT 0x1cc
+#define OQ_INT_SRC 0x1d0
+#define OQ_INT_SRC_MSK 0x1d4
+#define ENT_INT_SRC1 0x1d8
+#define ENT_INT_SRC2 0x1dc
+#define ENT_INT_SRC2_DQ_CFG_ERR_OFF 25
+#define ENT_INT_SRC2_DQ_CFG_ERR_MSK (0x1 << ENT_INT_SRC2_DQ_CFG_ERR_OFF)
+#define ENT_INT_SRC2_CQ_CFG_ERR_OFF 27
+#define ENT_INT_SRC2_CQ_CFG_ERR_MSK (0x1 << ENT_INT_SRC2_CQ_CFG_ERR_OFF)
+#define ENT_INT_SRC2_AXI_WRONG_INT_OFF 28
+#define ENT_INT_SRC2_AXI_WRONG_INT_MSK (0x1 << ENT_INT_SRC2_AXI_WRONG_INT_OFF)
+#define ENT_INT_SRC2_AXI_OVERLF_INT_OFF 29
+#define ENT_INT_SRC2_AXI_OVERLF_INT_MSK (0x1 << ENT_INT_SRC2_AXI_OVERLF_INT_OFF)
+#define ENT_INT_SRC_MSK1 0x1e0
+#define ENT_INT_SRC_MSK2 0x1e4
+#define SAS_ECC_INTR 0x1e8
+#define SAS_ECC_INTR_DQ_ECC1B_OFF 0
+#define SAS_ECC_INTR_DQ_ECC1B_MSK (0x1 << SAS_ECC_INTR_DQ_ECC1B_OFF)
+#define SAS_ECC_INTR_DQ_ECCBAD_OFF 1
+#define SAS_ECC_INTR_DQ_ECCBAD_MSK (0x1 << SAS_ECC_INTR_DQ_ECCBAD_OFF)
+#define SAS_ECC_INTR_IOST_ECC1B_OFF 2
+#define SAS_ECC_INTR_IOST_ECC1B_MSK (0x1 << SAS_ECC_INTR_IOST_ECC1B_OFF)
+#define SAS_ECC_INTR_IOST_ECCBAD_OFF 3
+#define SAS_ECC_INTR_IOST_ECCBAD_MSK (0x1 << SAS_ECC_INTR_IOST_ECCBAD_OFF)
+#define SAS_ECC_INTR_ITCT_ECC1B_OFF 4
+#define SAS_ECC_INTR_ITCT_ECC1B_MSK (0x1 << SAS_ECC_INTR_ITCT_ECC1B_OFF)
+#define SAS_ECC_INTR_ITCT_ECCBAD_OFF 5
+#define SAS_ECC_INTR_ITCT_ECCBAD_MSK (0x1 << SAS_ECC_INTR_ITCT_ECCBAD_OFF)
+#define SAS_ECC_INTR_MSK 0x1ec
+#define HGC_ERR_STAT_EN 0x238
+#define DLVRY_Q_0_BASE_ADDR_LO 0x260
+#define DLVRY_Q_0_BASE_ADDR_HI 0x264
+#define DLVRY_Q_0_DEPTH 0x268
+#define DLVRY_Q_0_WR_PTR 0x26c
+#define DLVRY_Q_0_RD_PTR 0x270
+#define COMPL_Q_0_BASE_ADDR_LO 0x4e0
+#define COMPL_Q_0_BASE_ADDR_HI 0x4e4
+#define COMPL_Q_0_DEPTH 0x4e8
+#define COMPL_Q_0_WR_PTR 0x4ec
+#define COMPL_Q_0_RD_PTR 0x4f0
+#define HGC_ECC_ERR 0x7d0
+
+/* phy registers need init */
+#define PORT_BASE (0x800)
+
+#define PHY_CFG (PORT_BASE + 0x0)
+#define PHY_CFG_ENA_OFF 0
+#define PHY_CFG_ENA_MSK (0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF 2
+#define PHY_CFG_DC_OPT_MSK (0x1 << PHY_CFG_DC_OPT_OFF)
+#define PROG_PHY_LINK_RATE (PORT_BASE + 0xc)
+#define PROG_PHY_LINK_RATE_MAX_OFF 0
+#define PROG_PHY_LINK_RATE_MAX_MSK (0xf << PROG_PHY_LINK_RATE_MAX_OFF)
+#define PROG_PHY_LINK_RATE_MIN_OFF 4
+#define PROG_PHY_LINK_RATE_MIN_MSK (0xf << PROG_PHY_LINK_RATE_MIN_OFF)
+#define PROG_PHY_LINK_RATE_OOB_OFF 8
+#define PROG_PHY_LINK_RATE_OOB_MSK (0xf << PROG_PHY_LINK_RATE_OOB_OFF)
+#define PHY_CTRL (PORT_BASE + 0x14)
+#define PHY_CTRL_RESET_OFF 0
+#define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF)
+#define PHY_RATE_NEGO (PORT_BASE + 0x30)
+#define PHY_PCN (PORT_BASE + 0x44)
+#define SL_TOUT_CFG (PORT_BASE + 0x8c)
+#define SL_CONTROL (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN_OFF 0
+#define SL_CONTROL_NOTIFY_EN_MSK (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define TX_ID_DWORD0 (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1 (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2 (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3 (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4 (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5 (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6 (PORT_BASE + 0xb4)
+#define RX_IDAF_DWORD0 (PORT_BASE + 0xc4)
+#define RX_IDAF_DWORD1 (PORT_BASE + 0xc8)
+#define RX_IDAF_DWORD2 (PORT_BASE + 0xcc)
+#define RX_IDAF_DWORD3 (PORT_BASE + 0xd0)
+#define RX_IDAF_DWORD4 (PORT_BASE + 0xd4)
+#define RX_IDAF_DWORD5 (PORT_BASE + 0xd8)
+#define RX_IDAF_DWORD6 (PORT_BASE + 0xdc)
+#define RXOP_CHECK_CFG_H (PORT_BASE + 0xfc)
+#define DONE_RECEIVED_TIME (PORT_BASE + 0x12c)
+#define CON_CFG_DRIVER (PORT_BASE + 0x130)
+#define PHY_CONFIG2 (PORT_BASE + 0x1a8)
+#define PHY_CONFIG2_FORCE_TXDEEMPH_OFF 3
+#define PHY_CONFIG2_FORCE_TXDEEMPH_MSK (0x1 << PHY_CONFIG2_FORCE_TXDEEMPH_OFF)
+#define PHY_CONFIG2_TX_TRAIN_COMP_OFF 24
+#define PHY_CONFIG2_TX_TRAIN_COMP_MSK (0x1 << PHY_CONFIG2_TX_TRAIN_COMP_OFF)
+#define CHL_INT0 (PORT_BASE + 0x1b0)
+#define CHL_INT0_PHYCTRL_NOTRDY_OFF 0
+#define CHL_INT0_PHYCTRL_NOTRDY_MSK (0x1 << CHL_INT0_PHYCTRL_NOTRDY_OFF)
+#define CHL_INT0_SN_FAIL_NGR_OFF 2
+#define CHL_INT0_SN_FAIL_NGR_MSK (0x1 << CHL_INT0_SN_FAIL_NGR_OFF)
+#define CHL_INT0_DWS_LOST_OFF 4
+#define CHL_INT0_DWS_LOST_MSK (0x1 << CHL_INT0_DWS_LOST_OFF)
+#define CHL_INT0_SL_IDAF_FAIL_OFF 10
+#define CHL_INT0_SL_IDAF_FAIL_MSK (0x1 << CHL_INT0_SL_IDAF_FAIL_OFF)
+#define CHL_INT0_ID_TIMEOUT_OFF 11
+#define CHL_INT0_ID_TIMEOUT_MSK (0x1 << CHL_INT0_ID_TIMEOUT_OFF)
+#define CHL_INT0_SL_OPAF_FAIL_OFF 12
+#define CHL_INT0_SL_OPAF_FAIL_MSK (0x1 << CHL_INT0_SL_OPAF_FAIL_OFF)
+#define CHL_INT0_SL_PS_FAIL_OFF 21
+#define CHL_INT0_SL_PS_FAIL_MSK (0x1 << CHL_INT0_SL_PS_FAIL_OFF)
+#define CHL_INT1 (PORT_BASE + 0x1b4)
+#define CHL_INT2 (PORT_BASE + 0x1b8)
+#define CHL_INT2_SL_RX_BC_ACK_OFF 2
+#define CHL_INT2_SL_RX_BC_ACK_MSK (0x1 << CHL_INT2_SL_RX_BC_ACK_OFF)
+#define CHL_INT2_SL_PHY_ENA_OFF 6
+#define CHL_INT2_SL_PHY_ENA_MSK (0x1 << CHL_INT2_SL_PHY_ENA_OFF)
+#define CHL_INT0_MSK (PORT_BASE + 0x1bc)
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY_OFF 0
+#define CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK (0x1 << CHL_INT0_MSK_PHYCTRL_NOTRDY_OFF)
+#define CHL_INT1_MSK (PORT_BASE + 0x1c0)
+#define CHL_INT2_MSK (PORT_BASE + 0x1c4)
+#define CHL_INT_COAL_EN (PORT_BASE + 0x1d0)
+#define DMA_TX_STATUS (PORT_BASE + 0x2d0)
+#define DMA_TX_STATUS_BUSY_OFF 0
+#define DMA_TX_STATUS_BUSY_MSK (0x1 << DMA_TX_STATUS_BUSY_OFF)
+#define DMA_RX_STATUS (PORT_BASE + 0x2e8)
+#define DMA_RX_STATUS_BUSY_OFF 0
+#define DMA_RX_STATUS_BUSY_MSK (0x1 << DMA_RX_STATUS_BUSY_OFF)
+
+#define AXI_CFG 0x5100
+#define RESET_VALUE 0x7ffff
+
+/* HW dma structures */
+/* Delivery queue header */
+/* dw0 */
+#define CMD_HDR_RESP_REPORT_OFF 5
+#define CMD_HDR_RESP_REPORT_MSK 0x20
+#define CMD_HDR_TLR_CTRL_OFF 6
+#define CMD_HDR_TLR_CTRL_MSK 0xc0
+#define CMD_HDR_PORT_OFF 17
+#define CMD_HDR_PORT_MSK 0xe0000
+#define CMD_HDR_PRIORITY_OFF 27
+#define CMD_HDR_PRIORITY_MSK 0x8000000
+#define CMD_HDR_MODE_OFF 28
+#define CMD_HDR_MODE_MSK 0x10000000
+#define CMD_HDR_CMD_OFF 29
+#define CMD_HDR_CMD_MSK 0xe0000000
+/* dw1 */
+#define CMD_HDR_VERIFY_DTL_OFF 10
+#define CMD_HDR_VERIFY_DTL_MSK 0x400
+#define CMD_HDR_SSP_FRAME_TYPE_OFF 13
+#define CMD_HDR_SSP_FRAME_TYPE_MSK 0xe000
+#define CMD_HDR_DEVICE_ID_OFF 16
+#define CMD_HDR_DEVICE_ID_MSK 0xffff0000
+/* dw2 */
+#define CMD_HDR_CFL_OFF 0
+#define CMD_HDR_CFL_MSK 0x1ff
+#define CMD_HDR_MRFL_OFF 15
+#define CMD_HDR_MRFL_MSK 0xff8000
+#define CMD_HDR_FIRST_BURST_OFF 25
+#define CMD_HDR_FIRST_BURST_MSK 0x2000000
+/* dw3 */
+#define CMD_HDR_IPTT_OFF 0
+#define CMD_HDR_IPTT_MSK 0xffff
+/* dw6 */
+#define CMD_HDR_DATA_SGL_LEN_OFF 16
+#define CMD_HDR_DATA_SGL_LEN_MSK 0xffff0000
+
+/* Completion header */
+#define CMPLT_HDR_IPTT_OFF 0
+#define CMPLT_HDR_IPTT_MSK (0xffff << CMPLT_HDR_IPTT_OFF)
+#define CMPLT_HDR_CMD_CMPLT_OFF 17
+#define CMPLT_HDR_CMD_CMPLT_MSK (0x1 << CMPLT_HDR_CMD_CMPLT_OFF)
+#define CMPLT_HDR_ERR_RCRD_XFRD_OFF 18
+#define CMPLT_HDR_ERR_RCRD_XFRD_MSK (0x1 << CMPLT_HDR_ERR_RCRD_XFRD_OFF)
+#define CMPLT_HDR_RSPNS_XFRD_OFF 19
+#define CMPLT_HDR_RSPNS_XFRD_MSK (0x1 << CMPLT_HDR_RSPNS_XFRD_OFF)
+#define CMPLT_HDR_IO_CFG_ERR_OFF 27
+#define CMPLT_HDR_IO_CFG_ERR_MSK (0x1 << CMPLT_HDR_IO_CFG_ERR_OFF)
+
+/* ITCT header */
+/* qw0 */
+#define ITCT_HDR_DEV_TYPE_OFF 0
+#define ITCT_HDR_DEV_TYPE_MSK (0x3ULL << ITCT_HDR_DEV_TYPE_OFF)
+#define ITCT_HDR_VALID_OFF 2
+#define ITCT_HDR_VALID_MSK (0x1ULL << ITCT_HDR_VALID_OFF)
+#define ITCT_HDR_AWT_CONTROL_OFF 4
+#define ITCT_HDR_AWT_CONTROL_MSK (0x1ULL << ITCT_HDR_AWT_CONTROL_OFF)
+#define ITCT_HDR_MAX_CONN_RATE_OFF 5
+#define ITCT_HDR_MAX_CONN_RATE_MSK (0xfULL << ITCT_HDR_MAX_CONN_RATE_OFF)
+#define ITCT_HDR_VALID_LINK_NUM_OFF 9
+#define ITCT_HDR_VALID_LINK_NUM_MSK (0xfULL << ITCT_HDR_VALID_LINK_NUM_OFF)
+#define ITCT_HDR_PORT_ID_OFF 13
+#define ITCT_HDR_PORT_ID_MSK (0x7ULL << ITCT_HDR_PORT_ID_OFF)
+#define ITCT_HDR_SMP_TIMEOUT_OFF 16
+#define ITCT_HDR_SMP_TIMEOUT_MSK (0xffffULL << ITCT_HDR_SMP_TIMEOUT_OFF)
+/* qw1 */
+#define ITCT_HDR_MAX_SAS_ADDR_OFF 0
+#define ITCT_HDR_MAX_SAS_ADDR_MSK (0xffffffffffffffff << \
+ ITCT_HDR_MAX_SAS_ADDR_OFF)
+/* qw2 */
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_OFF 0
+#define ITCT_HDR_IT_NEXUS_LOSS_TL_MSK (0xffffULL << \
+ ITCT_HDR_IT_NEXUS_LOSS_TL_OFF)
+#define ITCT_HDR_BUS_INACTIVE_TL_OFF 16
+#define ITCT_HDR_BUS_INACTIVE_TL_MSK (0xffffULL << \
+ ITCT_HDR_BUS_INACTIVE_TL_OFF)
+#define ITCT_HDR_MAX_CONN_TL_OFF 32
+#define ITCT_HDR_MAX_CONN_TL_MSK (0xffffULL << \
+ ITCT_HDR_MAX_CONN_TL_OFF)
+#define ITCT_HDR_REJ_OPEN_TL_OFF 48
+#define ITCT_HDR_REJ_OPEN_TL_MSK (0xffffULL << \
+ ITCT_HDR_REJ_OPEN_TL_OFF)
+
+/* Err record header */
+#define ERR_HDR_DMA_TX_ERR_TYPE_OFF 0
+#define ERR_HDR_DMA_TX_ERR_TYPE_MSK (0xffff << ERR_HDR_DMA_TX_ERR_TYPE_OFF)
+#define ERR_HDR_DMA_RX_ERR_TYPE_OFF 16
+#define ERR_HDR_DMA_RX_ERR_TYPE_MSK (0xffff << ERR_HDR_DMA_RX_ERR_TYPE_OFF)
+
+struct hisi_sas_complete_v1_hdr {
+ __le32 data;
+};
+
+enum {
+ HISI_SAS_PHY_BCAST_ACK = 0,
+ HISI_SAS_PHY_SL_PHY_ENABLED,
+ HISI_SAS_PHY_INT_ABNORMAL,
+ HISI_SAS_PHY_INT_NR
+};
+
+enum {
+ DMA_TX_ERR_BASE = 0x0,
+ DMA_RX_ERR_BASE = 0x100,
+ TRANS_TX_FAIL_BASE = 0x200,
+ TRANS_RX_FAIL_BASE = 0x300,
+
+ /* dma tx */
+ DMA_TX_DIF_CRC_ERR = DMA_TX_ERR_BASE, /* 0x0 */
+ DMA_TX_DIF_APP_ERR, /* 0x1 */
+ DMA_TX_DIF_RPP_ERR, /* 0x2 */
+ DMA_TX_AXI_BUS_ERR, /* 0x3 */
+ DMA_TX_DATA_SGL_OVERFLOW_ERR, /* 0x4 */
+ DMA_TX_DIF_SGL_OVERFLOW_ERR, /* 0x5 */
+ DMA_TX_UNEXP_XFER_RDY_ERR, /* 0x6 */
+ DMA_TX_XFER_RDY_OFFSET_ERR, /* 0x7 */
+ DMA_TX_DATA_UNDERFLOW_ERR, /* 0x8 */
+ DMA_TX_XFER_RDY_LENGTH_OVERFLOW_ERR, /* 0x9 */
+
+ /* dma rx */
+ DMA_RX_BUFFER_ECC_ERR = DMA_RX_ERR_BASE, /* 0x100 */
+ DMA_RX_DIF_CRC_ERR, /* 0x101 */
+ DMA_RX_DIF_APP_ERR, /* 0x102 */
+ DMA_RX_DIF_RPP_ERR, /* 0x103 */
+ DMA_RX_RESP_BUFFER_OVERFLOW_ERR, /* 0x104 */
+ DMA_RX_AXI_BUS_ERR, /* 0x105 */
+ DMA_RX_DATA_SGL_OVERFLOW_ERR, /* 0x106 */
+ DMA_RX_DIF_SGL_OVERFLOW_ERR, /* 0x107 */
+ DMA_RX_DATA_OFFSET_ERR, /* 0x108 */
+ DMA_RX_UNEXP_RX_DATA_ERR, /* 0x109 */
+ DMA_RX_DATA_OVERFLOW_ERR, /* 0x10a */
+ DMA_RX_DATA_UNDERFLOW_ERR, /* 0x10b */
+ DMA_RX_UNEXP_RETRANS_RESP_ERR, /* 0x10c */
+
+ /* trans tx */
+ TRANS_TX_RSVD0_ERR = TRANS_TX_FAIL_BASE, /* 0x200 */
+ TRANS_TX_PHY_NOT_ENABLE_ERR, /* 0x201 */
+ TRANS_TX_OPEN_REJCT_WRONG_DEST_ERR, /* 0x202 */
+ TRANS_TX_OPEN_REJCT_ZONE_VIOLATION_ERR, /* 0x203 */
+ TRANS_TX_OPEN_REJCT_BY_OTHER_ERR, /* 0x204 */
+ TRANS_TX_RSVD1_ERR, /* 0x205 */
+ TRANS_TX_OPEN_REJCT_AIP_TIMEOUT_ERR, /* 0x206 */
+ TRANS_TX_OPEN_REJCT_STP_BUSY_ERR, /* 0x207 */
+ TRANS_TX_OPEN_REJCT_PROTOCOL_NOT_SUPPORT_ERR, /* 0x208 */
+ TRANS_TX_OPEN_REJCT_RATE_NOT_SUPPORT_ERR, /* 0x209 */
+ TRANS_TX_OPEN_REJCT_BAD_DEST_ERR, /* 0x20a */
+ TRANS_TX_OPEN_BREAK_RECEIVE_ERR, /* 0x20b */
+ TRANS_TX_LOW_PHY_POWER_ERR, /* 0x20c */
+ TRANS_TX_OPEN_REJCT_PATHWAY_BLOCKED_ERR, /* 0x20d */
+ TRANS_TX_OPEN_TIMEOUT_ERR, /* 0x20e */
+ TRANS_TX_OPEN_REJCT_NO_DEST_ERR, /* 0x20f */
+ TRANS_TX_OPEN_RETRY_ERR, /* 0x210 */
+ TRANS_TX_RSVD2_ERR, /* 0x211 */
+ TRANS_TX_BREAK_TIMEOUT_ERR, /* 0x212 */
+ TRANS_TX_BREAK_REQUEST_ERR, /* 0x213 */
+ TRANS_TX_BREAK_RECEIVE_ERR, /* 0x214 */
+ TRANS_TX_CLOSE_TIMEOUT_ERR, /* 0x215 */
+ TRANS_TX_CLOSE_NORMAL_ERR, /* 0x216 */
+ TRANS_TX_CLOSE_PHYRESET_ERR, /* 0x217 */
+ TRANS_TX_WITH_CLOSE_DWS_TIMEOUT_ERR, /* 0x218 */
+ TRANS_TX_WITH_CLOSE_COMINIT_ERR, /* 0x219 */
+ TRANS_TX_NAK_RECEIVE_ERR, /* 0x21a */
+ TRANS_TX_ACK_NAK_TIMEOUT_ERR, /* 0x21b */
+ TRANS_TX_CREDIT_TIMEOUT_ERR, /* 0x21c */
+ TRANS_TX_IPTT_CONFLICT_ERR, /* 0x21d */
+ TRANS_TX_TXFRM_TYPE_ERR, /* 0x21e */
+ TRANS_TX_TXSMP_LENGTH_ERR, /* 0x21f */
+
+ /* trans rx */
+ TRANS_RX_FRAME_CRC_ERR = TRANS_RX_FAIL_BASE, /* 0x300 */
+ TRANS_RX_FRAME_DONE_ERR, /* 0x301 */
+ TRANS_RX_FRAME_ERRPRM_ERR, /* 0x302 */
+ TRANS_RX_FRAME_NO_CREDIT_ERR, /* 0x303 */
+ TRANS_RX_RSVD0_ERR, /* 0x304 */
+ TRANS_RX_FRAME_OVERRUN_ERR, /* 0x305 */
+ TRANS_RX_FRAME_NO_EOF_ERR, /* 0x306 */
+ TRANS_RX_LINK_BUF_OVERRUN_ERR, /* 0x307 */
+ TRANS_RX_BREAK_TIMEOUT_ERR, /* 0x308 */
+ TRANS_RX_BREAK_REQUEST_ERR, /* 0x309 */
+ TRANS_RX_BREAK_RECEIVE_ERR, /* 0x30a */
+ TRANS_RX_CLOSE_TIMEOUT_ERR, /* 0x30b */
+ TRANS_RX_CLOSE_NORMAL_ERR, /* 0x30c */
+ TRANS_RX_CLOSE_PHYRESET_ERR, /* 0x30d */
+ TRANS_RX_WITH_CLOSE_DWS_TIMEOUT_ERR, /* 0x30e */
+ TRANS_RX_WITH_CLOSE_COMINIT_ERR, /* 0x30f */
+ TRANS_RX_DATA_LENGTH0_ERR, /* 0x310 */
+ TRANS_RX_BAD_HASH_ERR, /* 0x311 */
+ TRANS_RX_XRDY_ZERO_ERR, /* 0x312 */
+ TRANS_RX_SSP_FRAME_LEN_ERR, /* 0x313 */
+ TRANS_RX_TRANS_RX_RSVD1_ERR, /* 0x314 */
+ TRANS_RX_NO_BALANCE_ERR, /* 0x315 */
+ TRANS_RX_TRANS_RX_RSVD2_ERR, /* 0x316 */
+ TRANS_RX_TRANS_RX_RSVD3_ERR, /* 0x317 */
+ TRANS_RX_BAD_FRAME_TYPE_ERR, /* 0x318 */
+ TRANS_RX_SMP_FRAME_LEN_ERR, /* 0x319 */
+ TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x31a */
+};
+
+#define HISI_SAS_PHY_MAX_INT_NR (HISI_SAS_PHY_INT_NR * HISI_SAS_MAX_PHYS)
+#define HISI_SAS_CQ_MAX_INT_NR (HISI_SAS_MAX_QUEUES)
+#define HISI_SAS_FATAL_INT_NR (2)
+
+#define HISI_SAS_MAX_INT_NR \
+ (HISI_SAS_PHY_MAX_INT_NR + HISI_SAS_CQ_MAX_INT_NR +\
+ HISI_SAS_FATAL_INT_NR)
+
+static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl(regs);
+}
+
+static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ return readl_relaxed(regs);
+}
+
+static void hisi_sas_write32(struct hisi_hba *hisi_hba,
+ u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + off;
+
+ writel(val, regs);
+}
+
+static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off, u32 val)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ writel(val, regs);
+}
+
+static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
+ int phy_no, u32 off)
+{
+ void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+ return readl(regs);
+}
+
+static void config_phy_opt_mode_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_DC_OPT_MSK;
+ cfg |= 1 << PHY_CFG_DC_OPT_OFF;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void config_tx_tfe_autoneg_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CONFIG2);
+
+ cfg &= ~PHY_CONFIG2_FORCE_TXDEEMPH_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CONFIG2, cfg);
+}
+
+static void config_id_frame_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ struct sas_identify_frame identify_frame;
+ u32 *identify_buffer;
+
+ memset(&identify_frame, 0, sizeof(identify_frame));
+ identify_frame.dev_type = SAS_END_DEVICE;
+ identify_frame.frame_type = 0;
+ identify_frame._un1 = 1;
+ identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
+ identify_frame.target_bits = SAS_PROTOCOL_NONE;
+ memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+ identify_frame.phy_id = phy_no;
+ identify_buffer = (u32 *)(&identify_frame);
+
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
+ __swab32(identify_buffer[0]));
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
+ identify_buffer[2]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
+ identify_buffer[1]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
+ identify_buffer[4]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
+ identify_buffer[3]);
+ hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
+ __swab32(identify_buffer[5]));
+}
+
+static void init_id_frame_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ config_id_frame_v1_hw(hisi_hba, i);
+}
+
+static void setup_itct_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ struct domain_device *device = sas_dev->sas_device;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u64 qw0, device_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[device_id];
+
+ memset(itct, 0, sizeof(*itct));
+
+ /* qw0 */
+ qw0 = 0;
+ switch (sas_dev->dev_type) {
+ case SAS_END_DEVICE:
+ case SAS_EDGE_EXPANDER_DEVICE:
+ case SAS_FANOUT_EXPANDER_DEVICE:
+ qw0 = HISI_SAS_DEV_TYPE_SSP << ITCT_HDR_DEV_TYPE_OFF;
+ break;
+ default:
+ dev_warn(dev, "setup itct: unsupported dev type (%d)\n",
+ sas_dev->dev_type);
+ }
+
+ qw0 |= ((1 << ITCT_HDR_VALID_OFF) |
+ (1 << ITCT_HDR_AWT_CONTROL_OFF) |
+ (device->max_linkrate << ITCT_HDR_MAX_CONN_RATE_OFF) |
+ (1 << ITCT_HDR_VALID_LINK_NUM_OFF) |
+ (device->port->id << ITCT_HDR_PORT_ID_OFF));
+ itct->qw0 = cpu_to_le64(qw0);
+
+ /* qw1 */
+ memcpy(&itct->sas_addr, device->sas_addr, SAS_ADDR_SIZE);
+ itct->sas_addr = __swab64(itct->sas_addr);
+
+ /* qw2 */
+ itct->qw2 = cpu_to_le64((500ULL << ITCT_HDR_IT_NEXUS_LOSS_TL_OFF) |
+ (0xff00ULL << ITCT_HDR_BUS_INACTIVE_TL_OFF) |
+ (0xff00ULL << ITCT_HDR_MAX_CONN_TL_OFF) |
+ (0xff00ULL << ITCT_HDR_REJ_OPEN_TL_OFF));
+}
+
+static void free_device_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_device *sas_dev)
+{
+ u64 dev_id = sas_dev->device_id;
+ struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id];
+ u64 qw0;
+ u32 reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+
+ reg_val |= CFG_AGING_TIME_ITCT_REL_MSK;
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
+
+ /* free itct */
+ udelay(1);
+ reg_val = hisi_sas_read32(hisi_hba, CFG_AGING_TIME);
+ reg_val &= ~CFG_AGING_TIME_ITCT_REL_MSK;
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, reg_val);
+
+ qw0 = cpu_to_le64(itct->qw0);
+ qw0 &= ~ITCT_HDR_VALID_MSK;
+ itct->qw0 = cpu_to_le64(qw0);
+}
+
+static int reset_hw_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ unsigned long end_time;
+ u32 val;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 phy_ctrl = hisi_sas_phy_read32(hisi_hba, i, PHY_CTRL);
+
+ phy_ctrl |= PHY_CTRL_RESET_MSK;
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL, phy_ctrl);
+ }
+ msleep(1); /* It is safe to wait for 50us */
+
+ /* Ensure DMA tx & rx idle */
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ u32 dma_tx_status, dma_rx_status;
+
+ end_time = jiffies + msecs_to_jiffies(1000);
+
+ while (1) {
+ dma_tx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_TX_STATUS);
+ dma_rx_status = hisi_sas_phy_read32(hisi_hba, i,
+ DMA_RX_STATUS);
+
+ if (!(dma_tx_status & DMA_TX_STATUS_BUSY_MSK) &&
+ !(dma_rx_status & DMA_RX_STATUS_BUSY_MSK))
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+ }
+
+ /* Ensure axi bus idle */
+ end_time = jiffies + msecs_to_jiffies(1000);
+ while (1) {
+ u32 axi_status =
+ hisi_sas_read32(hisi_hba, AXI_CFG);
+
+ if (axi_status == 0)
+ break;
+
+ msleep(20);
+ if (time_after(jiffies, end_time))
+ return -EIO;
+ }
+
+ /* Apply reset and disable clock */
+ /* clk disable reg is offset by +4 bytes from clk enable reg */
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg,
+ RESET_VALUE);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg + 4,
+ RESET_VALUE);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (RESET_VALUE != (val & RESET_VALUE)) {
+ dev_err(dev, "Reset failed\n");
+ return -EIO;
+ }
+
+ /* De-reset and enable clock */
+ /* deassert rst reg is offset by +4 bytes from assert reg */
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_reset_reg + 4,
+ RESET_VALUE);
+ regmap_write(hisi_hba->ctrl, hisi_hba->ctrl_clock_ena_reg,
+ RESET_VALUE);
+ msleep(1);
+ regmap_read(hisi_hba->ctrl, hisi_hba->ctrl_reset_sts_reg, &val);
+ if (val & RESET_VALUE) {
+ dev_err(dev, "De-reset failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void init_reg_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+
+ /* Global registers init*/
+ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE,
+ (u32)((1ULL << hisi_hba->queue_count) - 1));
+ hisi_sas_write32(hisi_hba, HGC_TRANS_TASK_CNT_LIMIT, 0x11);
+ hisi_sas_write32(hisi_hba, DEVICE_MSG_WORK_MODE, 0x1);
+ hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x1ff);
+ hisi_sas_write32(hisi_hba, HGC_ERR_STAT_EN, 0x401);
+ hisi_sas_write32(hisi_hba, CFG_1US_TIMER_TRSH, 0x64);
+ hisi_sas_write32(hisi_hba, HGC_GET_ITV_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, I_T_NEXUS_LOSS_TIME, 0x64);
+ hisi_sas_write32(hisi_hba, BUS_INACTIVE_LIMIT_TIME, 0x2710);
+ hisi_sas_write32(hisi_hba, REJECT_TO_OPEN_LIMIT_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x7a12);
+ hisi_sas_write32(hisi_hba, HGC_DFX_CFG2, 0x9c40);
+ hisi_sas_write32(hisi_hba, FIS_LIST_BADDR_L, 0x2);
+ hisi_sas_write32(hisi_hba, INT_COAL_EN, 0xc);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x186a0);
+ hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_TIME, 0x1);
+ hisi_sas_write32(hisi_hba, ENT_INT_COAL_CNT, 0x1);
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0xffffffff);
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC_MSK, 0);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC1, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1, 0);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, 0xffffffff);
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK2, 0);
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0);
+ hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 0x2);
+ hisi_sas_write32(hisi_hba, CFG_SAS_CONFIG, 0x22000000);
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x88a);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_CONFIG2, 0x7c080);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_RATE_NEGO, 0x415ee00);
+ hisi_sas_phy_write32(hisi_hba, i, PHY_PCN, 0x80a80000);
+ hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0x0);
+ hisi_sas_phy_write32(hisi_hba, i, RXOP_CHECK_CFG_H, 0x1000);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 0);
+ hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x13f0a);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT_COAL_EN, 3);
+ hisi_sas_phy_write32(hisi_hba, i, DONE_RECEIVED_TIME, 8);
+ }
+
+ for (i = 0; i < hisi_hba->queue_count; i++) {
+ /* Delivery queue */
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->cmd_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+
+ /* Completion queue */
+ hisi_sas_write32(hisi_hba,
+ COMPL_Q_0_BASE_ADDR_HI + (i * 0x14),
+ upper_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba,
+ COMPL_Q_0_BASE_ADDR_LO + (i * 0x14),
+ lower_32_bits(hisi_hba->complete_hdr_dma[i]));
+
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_DEPTH + (i * 0x14),
+ HISI_SAS_QUEUE_SLOTS);
+ }
+
+ /* itct */
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->itct_dma));
+
+ hisi_sas_write32(hisi_hba, ITCT_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->itct_dma));
+
+ /* iost */
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_LO,
+ lower_32_bits(hisi_hba->iost_dma));
+
+ hisi_sas_write32(hisi_hba, IOST_BASE_ADDR_HI,
+ upper_32_bits(hisi_hba->iost_dma));
+
+ /* breakpoint */
+ hisi_sas_write32(hisi_hba, BROKEN_MSG_ADDR_LO,
+ lower_32_bits(hisi_hba->breakpoint_dma));
+
+ hisi_sas_write32(hisi_hba, BROKEN_MSG_ADDR_HI,
+ upper_32_bits(hisi_hba->breakpoint_dma));
+}
+
+static int hw_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ int rc;
+
+ rc = reset_hw_v1_hw(hisi_hba);
+ if (rc) {
+ dev_err(dev, "hisi_sas_reset_hw failed, rc=%d", rc);
+ return rc;
+ }
+
+ msleep(100);
+ init_reg_v1_hw(hisi_hba);
+
+ init_id_frame_v1_hw(hisi_hba);
+
+ return 0;
+}
+
+static void enable_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg |= PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void disable_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+ cfg &= ~PHY_CFG_ENA_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void start_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ config_id_frame_v1_hw(hisi_hba, phy_no);
+ config_phy_opt_mode_v1_hw(hisi_hba, phy_no);
+ config_tx_tfe_autoneg_v1_hw(hisi_hba, phy_no);
+ enable_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void stop_phy_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ disable_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void phy_hard_reset_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ stop_phy_v1_hw(hisi_hba, phy_no);
+ msleep(100);
+ start_phy_v1_hw(hisi_hba, phy_no);
+}
+
+static void start_phys_v1_hw(unsigned long data)
+{
+ struct hisi_hba *hisi_hba = (struct hisi_hba *)data;
+ int i;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x12a);
+ start_phy_v1_hw(hisi_hba, i);
+ }
+}
+
+static void phys_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ struct timer_list *timer = &hisi_hba->timer;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x6a);
+ hisi_sas_phy_read32(hisi_hba, i, CHL_INT2_MSK);
+ }
+
+ setup_timer(timer, start_phys_v1_hw, (unsigned long)hisi_hba);
+ mod_timer(timer, jiffies + HZ);
+}
+
+static void sl_notify_v1_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+ u32 sl_control;
+
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+ msleep(1);
+ sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+ sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+}
+
+static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id)
+{
+ int i, bitmap = 0;
+ u32 phy_port_num_ma = hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA);
+
+ for (i = 0; i < hisi_hba->n_phy; i++)
+ if (((phy_port_num_ma >> (i * 4)) & 0xf) == port_id)
+ bitmap |= 1 << i;
+
+ return bitmap;
+}
+
+/**
+ * This function allocates across all queues to load balance.
+ * Slots are allocated from queues in a round-robin fashion.
+ *
+ * The callpath to this function and upto writing the write
+ * queue pointer should be safe from interruption.
+ */
+static int get_free_slot_v1_hw(struct hisi_hba *hisi_hba, int *q, int *s)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 r, w;
+ int queue = hisi_hba->queue;
+
+ while (1) {
+ w = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_WR_PTR + (queue * 0x14));
+ r = hisi_sas_read32_relaxed(hisi_hba,
+ DLVRY_Q_0_RD_PTR + (queue * 0x14));
+ if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) {
+ queue = (queue + 1) % hisi_hba->queue_count;
+ if (queue == hisi_hba->queue) {
+ dev_warn(dev, "could not find free slot\n");
+ return -EAGAIN;
+ }
+ continue;
+ }
+ break;
+ }
+ hisi_hba->queue = (queue + 1) % hisi_hba->queue_count;
+ *q = queue;
+ *s = w;
+ return 0;
+}
+
+static void start_delivery_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int dlvry_queue = hisi_hba->slot_prep->dlvry_queue;
+ int dlvry_queue_slot = hisi_hba->slot_prep->dlvry_queue_slot;
+
+ hisi_sas_write32(hisi_hba,
+ DLVRY_Q_0_WR_PTR + (dlvry_queue * 0x14),
+ ++dlvry_queue_slot % HISI_SAS_QUEUE_SLOTS);
+}
+
+static int prep_prd_sge_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ struct hisi_sas_cmd_hdr *hdr,
+ struct scatterlist *scatter,
+ int n_elem)
+{
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct scatterlist *sg;
+ int i;
+
+ if (n_elem > HISI_SAS_SGE_PAGE_CNT) {
+ dev_err(dev, "prd err: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT",
+ n_elem);
+ return -EINVAL;
+ }
+
+ slot->sge_page = dma_pool_alloc(hisi_hba->sge_page_pool, GFP_ATOMIC,
+ &slot->sge_page_dma);
+ if (!slot->sge_page)
+ return -ENOMEM;
+
+ for_each_sg(scatter, sg, n_elem, i) {
+ struct hisi_sas_sge *entry = &slot->sge_page->sge[i];
+
+ entry->addr = cpu_to_le64(sg_dma_address(sg));
+ entry->page_ctrl_0 = entry->page_ctrl_1 = 0;
+ entry->data_len = cpu_to_le32(sg_dma_len(sg));
+ entry->data_off = 0;
+ }
+
+ hdr->prd_table_addr = cpu_to_le64(slot->sge_page_dma);
+
+ hdr->sg_len = cpu_to_le32(n_elem << CMD_HDR_DATA_SGL_LEN_OFF);
+
+ return 0;
+}
+
+static int prep_smp_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct hisi_sas_port *port = slot->port;
+ struct scatterlist *sg_req, *sg_resp;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ dma_addr_t req_dma_addr;
+ unsigned int req_len, resp_len;
+ int elem, rc;
+
+ /*
+ * DMA-map SMP request, response buffers
+ */
+ /* req */
+ sg_req = &task->smp_task.smp_req;
+ elem = dma_map_sg(dev, sg_req, 1, DMA_TO_DEVICE);
+ if (!elem)
+ return -ENOMEM;
+ req_len = sg_dma_len(sg_req);
+ req_dma_addr = sg_dma_address(sg_req);
+
+ /* resp */
+ sg_resp = &task->smp_task.smp_resp;
+ elem = dma_map_sg(dev, sg_resp, 1, DMA_FROM_DEVICE);
+ if (!elem) {
+ rc = -ENOMEM;
+ goto err_out_req;
+ }
+ resp_len = sg_dma_len(sg_resp);
+ if ((req_len & 0x3) || (resp_len & 0x3)) {
+ rc = -EINVAL;
+ goto err_out_resp;
+ }
+
+ /* create header */
+ /* dw0 */
+ hdr->dw0 = cpu_to_le32((port->id << CMD_HDR_PORT_OFF) |
+ (1 << CMD_HDR_PRIORITY_OFF) | /* high pri */
+ (1 << CMD_HDR_MODE_OFF) | /* ini mode */
+ (2 << CMD_HDR_CMD_OFF)); /* smp */
+
+ /* map itct entry */
+ hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEVICE_ID_OFF);
+
+ /* dw2 */
+ hdr->dw2 = cpu_to_le32((((req_len-4)/4) << CMD_HDR_CFL_OFF) |
+ (HISI_SAS_MAX_SMP_RESP_SZ/4 <<
+ CMD_HDR_MRFL_OFF));
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ hdr->cmd_table_addr = cpu_to_le64(req_dma_addr);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ return 0;
+
+err_out_resp:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+err_out_req:
+ dma_unmap_sg(dev, &slot->task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ return rc;
+}
+
+static int prep_ssp_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int is_tmf,
+ struct hisi_sas_tmf_task *tmf)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
+ struct domain_device *device = task->dev;
+ struct hisi_sas_device *sas_dev = device->lldd_dev;
+ struct hisi_sas_port *port = slot->port;
+ struct sas_ssp_task *ssp_task = &task->ssp_task;
+ struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
+ int has_data = 0, rc, priority = is_tmf;
+ u8 *buf_cmd, fburst = 0;
+ u32 dw1, dw2;
+
+ /* create header */
+ hdr->dw0 = cpu_to_le32((1 << CMD_HDR_RESP_REPORT_OFF) |
+ (0x2 << CMD_HDR_TLR_CTRL_OFF) |
+ (port->id << CMD_HDR_PORT_OFF) |
+ (priority << CMD_HDR_PRIORITY_OFF) |
+ (1 << CMD_HDR_MODE_OFF) | /* ini mode */
+ (1 << CMD_HDR_CMD_OFF)); /* ssp */
+
+ dw1 = 1 << CMD_HDR_VERIFY_DTL_OFF;
+
+ if (is_tmf) {
+ dw1 |= 3 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ } else {
+ switch (scsi_cmnd->sc_data_direction) {
+ case DMA_TO_DEVICE:
+ dw1 |= 2 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ has_data = 1;
+ break;
+ case DMA_FROM_DEVICE:
+ dw1 |= 1 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ has_data = 1;
+ break;
+ default:
+ dw1 |= 0 << CMD_HDR_SSP_FRAME_TYPE_OFF;
+ }
+ }
+
+ /* map itct entry */
+ dw1 |= sas_dev->device_id << CMD_HDR_DEVICE_ID_OFF;
+ hdr->dw1 = cpu_to_le32(dw1);
+
+ if (is_tmf) {
+ dw2 = ((sizeof(struct ssp_tmf_iu) +
+ sizeof(struct ssp_frame_hdr)+3)/4) <<
+ CMD_HDR_CFL_OFF;
+ } else {
+ dw2 = ((sizeof(struct ssp_command_iu) +
+ sizeof(struct ssp_frame_hdr)+3)/4) <<
+ CMD_HDR_CFL_OFF;
+ }
+
+ dw2 |= (HISI_SAS_MAX_SSP_RESP_SZ/4) << CMD_HDR_MRFL_OFF;
+
+ hdr->transfer_tags = cpu_to_le32(slot->idx << CMD_HDR_IPTT_OFF);
+
+ if (has_data) {
+ rc = prep_prd_sge_v1_hw(hisi_hba, slot, hdr, task->scatter,
+ slot->n_elem);
+ if (rc)
+ return rc;
+ }
+
+ hdr->data_transfer_len = cpu_to_le32(task->total_xfer_len);
+ hdr->cmd_table_addr = cpu_to_le64(slot->command_table_dma);
+ hdr->sts_buffer_addr = cpu_to_le64(slot->status_buffer_dma);
+
+ buf_cmd = slot->command_table + sizeof(struct ssp_frame_hdr);
+ if (task->ssp_task.enable_first_burst) {
+ fburst = (1 << 7);
+ dw2 |= 1 << CMD_HDR_FIRST_BURST_OFF;
+ }
+ hdr->dw2 = cpu_to_le32(dw2);
+
+ memcpy(buf_cmd, &task->ssp_task.LUN, 8);
+ if (!is_tmf) {
+ buf_cmd[9] = fburst | task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
+ memcpy(buf_cmd + 12, task->ssp_task.cmd->cmnd,
+ task->ssp_task.cmd->cmd_len);
+ } else {
+ buf_cmd[10] = tmf->tmf;
+ switch (tmf->tmf) {
+ case TMF_ABORT_TASK:
+ case TMF_QUERY_TASK:
+ buf_cmd[12] =
+ (tmf->tag_of_task_to_be_managed >> 8) & 0xff;
+ buf_cmd[13] =
+ tmf->tag_of_task_to_be_managed & 0xff;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* by default, task resp is complete */
+static void slot_err_v1_hw(struct hisi_hba *hisi_hba,
+ struct sas_task *task,
+ struct hisi_sas_slot *slot)
+{
+ struct task_status_struct *ts = &task->task_status;
+ struct hisi_sas_err_record *err_record = slot->status_buffer;
+ struct device *dev = &hisi_hba->pdev->dev;
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ int error = -1;
+ u32 dma_err_type = cpu_to_le32(err_record->dma_err_type);
+ u32 dma_tx_err_type = ((dma_err_type &
+ ERR_HDR_DMA_TX_ERR_TYPE_MSK)) >>
+ ERR_HDR_DMA_TX_ERR_TYPE_OFF;
+ u32 dma_rx_err_type = ((dma_err_type &
+ ERR_HDR_DMA_RX_ERR_TYPE_MSK)) >>
+ ERR_HDR_DMA_RX_ERR_TYPE_OFF;
+ u32 trans_tx_fail_type =
+ cpu_to_le32(err_record->trans_tx_fail_type);
+ u32 trans_rx_fail_type =
+ cpu_to_le32(err_record->trans_rx_fail_type);
+
+ if (dma_tx_err_type) {
+ /* dma tx err */
+ error = ffs(dma_tx_err_type)
+ - 1 + DMA_TX_ERR_BASE;
+ } else if (dma_rx_err_type) {
+ /* dma rx err */
+ error = ffs(dma_rx_err_type)
+ - 1 + DMA_RX_ERR_BASE;
+ } else if (trans_tx_fail_type) {
+ /* trans tx err */
+ error = ffs(trans_tx_fail_type)
+ - 1 + TRANS_TX_FAIL_BASE;
+ } else if (trans_rx_fail_type) {
+ /* trans rx err */
+ error = ffs(trans_rx_fail_type)
+ - 1 + TRANS_RX_FAIL_BASE;
+ }
+
+ switch (error) {
+ case DMA_TX_DATA_UNDERFLOW_ERR:
+ case DMA_RX_DATA_UNDERFLOW_ERR:
+ {
+ ts->residual = 0;
+ ts->stat = SAS_DATA_UNDERRUN;
+ break;
+ }
+ case DMA_TX_DATA_SGL_OVERFLOW_ERR:
+ case DMA_TX_DIF_SGL_OVERFLOW_ERR:
+ case DMA_TX_XFER_RDY_LENGTH_OVERFLOW_ERR:
+ case DMA_RX_DATA_OVERFLOW_ERR:
+ case TRANS_RX_FRAME_OVERRUN_ERR:
+ case TRANS_RX_LINK_BUF_OVERRUN_ERR:
+ {
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ break;
+ }
+ case TRANS_TX_PHY_NOT_ENABLE_ERR:
+ {
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_REJCT_WRONG_DEST_ERR:
+ case TRANS_TX_OPEN_REJCT_ZONE_VIOLATION_ERR:
+ case TRANS_TX_OPEN_REJCT_BY_OTHER_ERR:
+ case TRANS_TX_OPEN_REJCT_AIP_TIMEOUT_ERR:
+ case TRANS_TX_OPEN_REJCT_STP_BUSY_ERR:
+ case TRANS_TX_OPEN_REJCT_PROTOCOL_NOT_SUPPORT_ERR:
+ case TRANS_TX_OPEN_REJCT_RATE_NOT_SUPPORT_ERR:
+ case TRANS_TX_OPEN_REJCT_BAD_DEST_ERR:
+ case TRANS_TX_OPEN_BREAK_RECEIVE_ERR:
+ case TRANS_TX_OPEN_REJCT_PATHWAY_BLOCKED_ERR:
+ case TRANS_TX_OPEN_REJCT_NO_DEST_ERR:
+ case TRANS_TX_OPEN_RETRY_ERR:
+ {
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ }
+ case TRANS_TX_OPEN_TIMEOUT_ERR:
+ {
+ ts->stat = SAS_OPEN_TO;
+ break;
+ }
+ case TRANS_TX_NAK_RECEIVE_ERR:
+ case TRANS_TX_ACK_NAK_TIMEOUT_ERR:
+ {
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ }
+ default:
+ {
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+ }
+ }
+ break;
+ case SAS_PROTOCOL_SMP:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ {
+ dev_err(dev, "slot err: SATA/STP not supported");
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot, int abort)
+{
+ struct sas_task *task = slot->task;
+ struct hisi_sas_device *sas_dev;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct task_status_struct *ts;
+ struct domain_device *device;
+ enum exec_status sts;
+ struct hisi_sas_complete_v1_hdr *complete_queue =
+ (struct hisi_sas_complete_v1_hdr *)
+ hisi_hba->complete_hdr[slot->cmplt_queue];
+ struct hisi_sas_complete_v1_hdr *complete_hdr;
+ u32 cmplt_hdr_data;
+
+ complete_hdr = &complete_queue[slot->cmplt_queue_slot];
+ cmplt_hdr_data = le32_to_cpu(complete_hdr->data);
+
+ if (unlikely(!task || !task->lldd_task || !task->dev))
+ return -EINVAL;
+
+ ts = &task->task_status;
+ device = task->dev;
+ sas_dev = device->lldd_dev;
+
+ task->task_state_flags &=
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+
+ memset(ts, 0, sizeof(*ts));
+ ts->resp = SAS_TASK_COMPLETE;
+
+ if (unlikely(!sas_dev || abort)) {
+ if (!sas_dev)
+ dev_dbg(dev, "slot complete: port has not device\n");
+ ts->stat = SAS_PHY_DOWN;
+ goto out;
+ }
+
+ if (cmplt_hdr_data & CMPLT_HDR_IO_CFG_ERR_MSK) {
+ u32 info_reg = hisi_sas_read32(hisi_hba, HGC_INVLD_DQE_INFO);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_DQ_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq IPTT err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_TYPE_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq type err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_FORCE_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq force phy err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_PHY_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq phy id err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_ABORT_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq abort flag err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_IPTT_OF_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq IPTT or ICT err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_SSP_ERR_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq SSP frame type err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ if (info_reg & HGC_INVLD_DQE_INFO_OFL_MSK)
+ dev_err(dev, "slot complete: [%d:%d] has dq order frame len err",
+ slot->cmplt_queue, slot->cmplt_queue_slot);
+
+ ts->stat = SAS_OPEN_REJECT;
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ goto out;
+ }
+
+ if (cmplt_hdr_data & CMPLT_HDR_ERR_RCRD_XFRD_MSK &&
+ !(cmplt_hdr_data & CMPLT_HDR_RSPNS_XFRD_MSK)) {
+
+ slot_err_v1_hw(hisi_hba, task, slot);
+ goto out;
+ }
+
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SSP:
+ {
+ struct ssp_response_iu *iu = slot->status_buffer +
+ sizeof(struct hisi_sas_err_record);
+ sas_ssp_task_response(dev, task, iu);
+ break;
+ }
+ case SAS_PROTOCOL_SMP:
+ {
+ void *to;
+ struct scatterlist *sg_resp = &task->smp_task.smp_resp;
+
+ ts->stat = SAM_STAT_GOOD;
+ to = kmap_atomic(sg_page(sg_resp));
+
+ dma_unmap_sg(dev, &task->smp_task.smp_resp, 1,
+ DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, &task->smp_task.smp_req, 1,
+ DMA_TO_DEVICE);
+ memcpy(to + sg_resp->offset,
+ slot->status_buffer +
+ sizeof(struct hisi_sas_err_record),
+ sg_dma_len(sg_resp));
+ kunmap_atomic(to);
+ break;
+ }
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
+ dev_err(dev, "slot complete: SATA/STP not supported");
+ break;
+
+ default:
+ ts->stat = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+
+ if (!slot->port->port_attached) {
+ dev_err(dev, "slot complete: port %d has removed\n",
+ slot->port->sas_port.id);
+ ts->stat = SAS_PHY_DOWN;
+ }
+
+out:
+ if (sas_dev && sas_dev->running_req)
+ sas_dev->running_req--;
+
+ hisi_sas_slot_task_free(hisi_hba, task, slot);
+ sts = ts->stat;
+
+ if (task->task_done)
+ task->task_done(task);
+
+ return sts;
+}
+
+/* Interrupts */
+static irqreturn_t int_phyup_v1_hw(int irq_no, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ int i, phy_no = sas_phy->id;
+ u32 irq_value, context, port_id, link_rate;
+ u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd;
+ struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd;
+ irqreturn_t res = IRQ_HANDLED;
+
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
+ if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) {
+ dev_dbg(dev, "phyup: irq_value = %x not set enable bit\n",
+ irq_value);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ context = hisi_sas_read32(hisi_hba, PHY_CONTEXT);
+ if (context & 1 << phy_no) {
+ dev_err(dev, "phyup: phy%d SATA attached equipment\n",
+ phy_no);
+ goto end;
+ }
+
+ port_id = (hisi_sas_read32(hisi_hba, PHY_PORT_NUM_MA) >> (4 * phy_no))
+ & 0xf;
+ if (port_id == 0xf) {
+ dev_err(dev, "phyup: phy%d invalid portid\n", phy_no);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ for (i = 0; i < 6; i++) {
+ u32 idaf = hisi_sas_phy_read32(hisi_hba, phy_no,
+ RX_IDAF_DWORD0 + (i * 4));
+ frame_rcvd[i] = __swab32(idaf);
+ }
+
+ /* Get the linkrate */
+ link_rate = hisi_sas_read32(hisi_hba, PHY_CONN_RATE);
+ link_rate = (link_rate >> (phy_no * 4)) & 0xf;
+ sas_phy->linkrate = link_rate;
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ memcpy(sas_phy->attached_sas_addr,
+ &id->sas_addr, SAS_ADDR_SIZE);
+ dev_info(dev, "phyup: phy%d link_rate=%d\n",
+ phy_no, link_rate);
+ phy->port_id = port_id;
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ phy->phy_type |= PORT_TYPE_SAS;
+ phy->phy_attached = 1;
+ phy->identify.device_type = id->dev_type;
+ phy->frame_rcvd_size = sizeof(struct sas_identify_frame);
+ if (phy->identify.device_type == SAS_END_DEVICE)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SSP;
+ else if (phy->identify.device_type != SAS_PHY_UNUSED)
+ phy->identify.target_port_protocols =
+ SAS_PROTOCOL_SMP;
+ queue_work(hisi_hba->wq, &phy->phyup_ws);
+
+end:
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
+ CHL_INT2_SL_PHY_ENA_MSK);
+
+ if (irq_value & CHL_INT2_SL_PHY_ENA_MSK) {
+ u32 chl_int0 = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+ chl_int0 &= ~CHL_INT0_PHYCTRL_NOTRDY_MSK;
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, chl_int0);
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3ce3ee);
+ }
+
+ return res;
+}
+
+static irqreturn_t int_bcast_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ struct sas_ha_struct *sha = &hisi_hba->sha;
+ struct device *dev = &hisi_hba->pdev->dev;
+ int phy_no = sas_phy->id;
+ u32 irq_value;
+ irqreturn_t res = IRQ_HANDLED;
+
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2);
+
+ if (!(irq_value & CHL_INT2_SL_RX_BC_ACK_MSK)) {
+ dev_err(dev, "bcast: irq_value = %x not set enable bit",
+ irq_value);
+ res = IRQ_NONE;
+ goto end;
+ }
+
+ sha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+
+end:
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2,
+ CHL_INT2_SL_RX_BC_ACK_MSK);
+
+ return res;
+}
+
+static irqreturn_t int_abnormal_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_phy *phy = p;
+ struct hisi_hba *hisi_hba = phy->hisi_hba;
+ struct device *dev = &hisi_hba->pdev->dev;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+ u32 irq_value, irq_mask_old;
+ int phy_no = sas_phy->id;
+
+ /* mask_int0 */
+ irq_mask_old = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0_MSK);
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK, 0x3fffff);
+
+ /* read int0 */
+ irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT0);
+
+ if (irq_value & CHL_INT0_PHYCTRL_NOTRDY_MSK) {
+ u32 phy_state = hisi_sas_read32(hisi_hba, PHY_STATE);
+
+ hisi_sas_phy_down(hisi_hba, phy_no,
+ (phy_state & 1 << phy_no) ? 1 : 0);
+ }
+
+ if (irq_value & CHL_INT0_ID_TIMEOUT_MSK)
+ dev_dbg(dev, "abnormal: ID_TIMEOUT phy%d identify timeout\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_DWS_LOST_MSK)
+ dev_dbg(dev, "abnormal: DWS_LOST phy%d dws lost\n", phy_no);
+
+ if (irq_value & CHL_INT0_SN_FAIL_NGR_MSK)
+ dev_dbg(dev, "abnormal: SN_FAIL_NGR phy%d sn fail ngr\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_SL_IDAF_FAIL_MSK ||
+ irq_value & CHL_INT0_SL_OPAF_FAIL_MSK)
+ dev_dbg(dev, "abnormal: SL_ID/OPAF_FAIL phy%d check adr frm err\n",
+ phy_no);
+
+ if (irq_value & CHL_INT0_SL_PS_FAIL_OFF)
+ dev_dbg(dev, "abnormal: SL_PS_FAIL phy%d fail\n", phy_no);
+
+ /* write to zero */
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, irq_value);
+
+ if (irq_value & CHL_INT0_PHYCTRL_NOTRDY_MSK)
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK,
+ 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK);
+ else
+ hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0_MSK,
+ irq_mask_old);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cq_interrupt_v1_hw(int irq, void *p)
+{
+ struct hisi_sas_cq *cq = p;
+ struct hisi_hba *hisi_hba = cq->hisi_hba;
+ struct hisi_sas_slot *slot;
+ int queue = cq->id;
+ struct hisi_sas_complete_v1_hdr *complete_queue =
+ (struct hisi_sas_complete_v1_hdr *)
+ hisi_hba->complete_hdr[queue];
+ u32 irq_value, rd_point, wr_point;
+
+ irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC);
+
+ hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue);
+
+ rd_point = hisi_sas_read32(hisi_hba,
+ COMPL_Q_0_RD_PTR + (0x14 * queue));
+ wr_point = hisi_sas_read32(hisi_hba,
+ COMPL_Q_0_WR_PTR + (0x14 * queue));
+
+ while (rd_point != wr_point) {
+ struct hisi_sas_complete_v1_hdr *complete_hdr;
+ int idx;
+ u32 cmplt_hdr_data;
+
+ complete_hdr = &complete_queue[rd_point];
+ cmplt_hdr_data = cpu_to_le32(complete_hdr->data);
+ idx = (cmplt_hdr_data & CMPLT_HDR_IPTT_MSK) >>
+ CMPLT_HDR_IPTT_OFF;
+ slot = &hisi_hba->slot_info[idx];
+
+ /* The completion queue and queue slot index are not
+ * necessarily the same as the delivery queue and
+ * queue slot index.
+ */
+ slot->cmplt_queue_slot = rd_point;
+ slot->cmplt_queue = queue;
+ slot_complete_v1_hw(hisi_hba, slot, 0);
+
+ if (++rd_point >= HISI_SAS_QUEUE_SLOTS)
+ rd_point = 0;
+ }
+
+ /* update rd_point */
+ hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fatal_ecc_int_v1_hw(int irq, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 ecc_int = hisi_sas_read32(hisi_hba, SAS_ECC_INTR);
+
+ if (ecc_int & SAS_ECC_INTR_DQ_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal DQ 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_DQ_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_DQ_ECC_ADDR) &
+ HGC_DQ_ECC_ADDR_BAD_MSK) >>
+ HGC_DQ_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal DQ RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_IOST_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal IOST 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_IOST_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_IOST_ECC_ADDR) &
+ HGC_IOST_ECC_ADDR_BAD_MSK) >>
+ HGC_IOST_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal IOST RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_ITCT_ECCBAD_MSK) {
+ u32 addr = (hisi_sas_read32(hisi_hba, HGC_ITCT_ECC_ADDR) &
+ HGC_ITCT_ECC_ADDR_BAD_MSK) >>
+ HGC_ITCT_ECC_ADDR_BAD_OFF;
+
+ panic("%s: Fatal TCT RAM ECC interrupt @ 0x%08x\n",
+ dev_name(dev), addr);
+ }
+
+ if (ecc_int & SAS_ECC_INTR_ITCT_ECC1B_MSK) {
+ u32 ecc_err = hisi_sas_read32(hisi_hba, HGC_ECC_ERR);
+
+ panic("%s: Fatal ITCT 1b ECC interrupt (0x%x)\n",
+ dev_name(dev), ecc_err);
+ }
+
+ hisi_sas_write32(hisi_hba, SAS_ECC_INTR, ecc_int | 0x3f);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fatal_axi_int_v1_hw(int irq, void *p)
+{
+ struct hisi_hba *hisi_hba = p;
+ struct device *dev = &hisi_hba->pdev->dev;
+ u32 axi_int = hisi_sas_read32(hisi_hba, ENT_INT_SRC2);
+ u32 axi_info = hisi_sas_read32(hisi_hba, HGC_AXI_FIFO_ERR_INFO);
+
+ if (axi_int & ENT_INT_SRC2_DQ_CFG_ERR_MSK)
+ panic("%s: Fatal DQ_CFG_ERR interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_CQ_CFG_ERR_MSK)
+ panic("%s: Fatal CQ_CFG_ERR interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_AXI_WRONG_INT_MSK)
+ panic("%s: Fatal AXI_WRONG_INT interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ if (axi_int & ENT_INT_SRC2_AXI_OVERLF_INT_MSK)
+ panic("%s: Fatal AXI_OVERLF_INT incorrect interrupt (0x%x)\n",
+ dev_name(dev), axi_info);
+
+ hisi_sas_write32(hisi_hba, ENT_INT_SRC2, axi_int | 0x30000000);
+
+ return IRQ_HANDLED;
+}
+
+static irq_handler_t phy_interrupts[HISI_SAS_PHY_INT_NR] = {
+ int_bcast_v1_hw,
+ int_phyup_v1_hw,
+ int_abnormal_v1_hw
+};
+
+static irq_handler_t fatal_interrupts[HISI_SAS_MAX_QUEUES] = {
+ fatal_ecc_int_v1_hw,
+ fatal_axi_int_v1_hw
+};
+
+static int interrupt_init_v1_hw(struct hisi_hba *hisi_hba)
+{
+ struct platform_device *pdev = hisi_hba->pdev;
+ struct device *dev = &pdev->dev;
+ int i, j, irq, rc, idx;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ struct hisi_sas_phy *phy = &hisi_hba->phy[i];
+
+ idx = i * HISI_SAS_PHY_INT_NR;
+ for (j = 0; j < HISI_SAS_PHY_INT_NR; j++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev,
+ "irq init: fail map phy interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, phy_interrupts[j], 0,
+ DRV_NAME " phy", phy);
+ if (rc) {
+ dev_err(dev, "irq init: could not request "
+ "phy interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+ }
+
+ idx = hisi_hba->n_phy * HISI_SAS_PHY_INT_NR;
+ for (i = 0; i < hisi_hba->queue_count; i++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev, "irq init: could not map cq interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, cq_interrupt_v1_hw, 0,
+ DRV_NAME " cq", &hisi_hba->cq[i]);
+ if (rc) {
+ dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ idx = (hisi_hba->n_phy * HISI_SAS_PHY_INT_NR) + hisi_hba->queue_count;
+ for (i = 0; i < HISI_SAS_FATAL_INT_NR; i++, idx++) {
+ irq = platform_get_irq(pdev, idx);
+ if (!irq) {
+ dev_err(dev, "irq init: could not map fatal interrupt %d\n",
+ idx);
+ return -ENOENT;
+ }
+
+ rc = devm_request_irq(dev, irq, fatal_interrupts[i], 0,
+ DRV_NAME " fatal", hisi_hba);
+ if (rc) {
+ dev_err(dev,
+ "irq init: could not request fatal interrupt %d, rc=%d\n",
+ irq, rc);
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
+static int interrupt_openall_v1_hw(struct hisi_hba *hisi_hba)
+{
+ int i;
+ u32 val;
+
+ for (i = 0; i < hisi_hba->n_phy; i++) {
+ /* Clear interrupt status */
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT0);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0, val);
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT1);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1, val);
+ val = hisi_sas_phy_read32(hisi_hba, i, CHL_INT2);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2, val);
+
+ /* Unmask interrupt */
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK, 0x3ce3ee);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT1_MSK, 0x17fff);
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT2_MSK, 0x8000012a);
+
+ /* bypass chip bug mask abnormal intr */
+ hisi_sas_phy_write32(hisi_hba, i, CHL_INT0_MSK,
+ 0x3fffff & ~CHL_INT0_MSK_PHYCTRL_NOTRDY_MSK);
+ }
+
+ return 0;
+}
+
+static int hisi_sas_v1_init(struct hisi_hba *hisi_hba)
+{
+ int rc;
+
+ rc = hw_init_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ rc = interrupt_init_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ rc = interrupt_openall_v1_hw(hisi_hba);
+ if (rc)
+ return rc;
+
+ phys_init_v1_hw(hisi_hba);
+
+ return 0;
+}
+
+static const struct hisi_sas_hw hisi_sas_v1_hw = {
+ .hw_init = hisi_sas_v1_init,
+ .setup_itct = setup_itct_v1_hw,
+ .sl_notify = sl_notify_v1_hw,
+ .free_device = free_device_v1_hw,
+ .prep_smp = prep_smp_v1_hw,
+ .prep_ssp = prep_ssp_v1_hw,
+ .get_free_slot = get_free_slot_v1_hw,
+ .start_delivery = start_delivery_v1_hw,
+ .slot_complete = slot_complete_v1_hw,
+ .phy_enable = enable_phy_v1_hw,
+ .phy_disable = disable_phy_v1_hw,
+ .phy_hard_reset = phy_hard_reset_v1_hw,
+ .get_wideport_bitmap = get_wideport_bitmap_v1_hw,
+ .complete_hdr_size = sizeof(struct hisi_sas_complete_v1_hdr),
+};
+
+static int hisi_sas_v1_probe(struct platform_device *pdev)
+{
+ return hisi_sas_probe(pdev, &hisi_sas_v1_hw);
+}
+
+static int hisi_sas_v1_remove(struct platform_device *pdev)
+{
+ return hisi_sas_remove(pdev);
+}
+
+static const struct of_device_id sas_v1_of_match[] = {
+ { .compatible = "hisilicon,hip05-sas-v1",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, sas_v1_of_match);
+
+static struct platform_driver hisi_sas_v1_driver = {
+ .probe = hisi_sas_v1_probe,
+ .remove = hisi_sas_v1_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = sas_v1_of_match,
+ },
+};
+
+module_platform_driver(hisi_sas_v1_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
+MODULE_DESCRIPTION("HISILICON SAS controller v1 hw driver");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index a3860367b..38ce0e308 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -750,7 +750,6 @@ static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
}
#define MAX_PATHS 8
-
static ssize_t path_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -792,10 +791,8 @@ static ssize_t path_info_show(struct device *dev,
hdev->bus, hdev->target, hdev->lun,
scsi_device_type(hdev->devtype));
- if (hdev->external ||
- hdev->devtype == TYPE_RAID ||
- is_logical_device(hdev)) {
- output_len += snprintf(buf + output_len,
+ if (hdev->devtype == TYPE_RAID || is_logical_device(hdev)) {
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
"%s\n", active);
continue;
@@ -808,29 +805,28 @@ static ssize_t path_info_show(struct device *dev,
phys_connector[0] = '0';
if (phys_connector[1] < '0')
phys_connector[1] = '0';
- if (hdev->phys_connector[i] > 0)
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
"PORT: %.2s ",
phys_connector);
if (hdev->devtype == TYPE_DISK && hdev->expose_device) {
if (box == 0 || box == 0xFF) {
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
"BAY: %hhu %s\n",
bay, active);
} else {
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len,
"BOX: %hhu BAY: %hhu %s\n",
box, bay, active);
}
} else if (box != 0 && box != 0xFF) {
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len, "BOX: %hhu %s\n",
box, active);
} else
- output_len += snprintf(buf + output_len,
+ output_len += scnprintf(buf + output_len,
PAGE_SIZE - output_len, "%s\n", active);
}
@@ -3191,6 +3187,87 @@ out:
return rc;
}
+/*
+ * get enclosure information
+ * struct ReportExtendedLUNdata *rlep - Used for BMIC drive number
+ * struct hpsa_scsi_dev_t *encl_dev - device entry for enclosure
+ * Uses id_physical_device to determine the box_index.
+ */
+static void hpsa_get_enclosure_info(struct ctlr_info *h,
+ unsigned char *scsi3addr,
+ struct ReportExtendedLUNdata *rlep, int rle_index,
+ struct hpsa_scsi_dev_t *encl_dev)
+{
+ int rc = -1;
+ struct CommandList *c = NULL;
+ struct ErrorInfo *ei = NULL;
+ struct bmic_sense_storage_box_params *bssbp = NULL;
+ struct bmic_identify_physical_device *id_phys = NULL;
+ struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
+ u16 bmic_device_index = 0;
+
+ bmic_device_index = GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]);
+
+ if (bmic_device_index == 0xFF00)
+ goto out;
+
+ bssbp = kzalloc(sizeof(*bssbp), GFP_KERNEL);
+ if (!bssbp)
+ goto out;
+
+ id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+ if (!id_phys)
+ goto out;
+
+ rc = hpsa_bmic_id_physical_device(h, scsi3addr, bmic_device_index,
+ id_phys, sizeof(*id_phys));
+ if (rc) {
+ dev_warn(&h->pdev->dev, "%s: id_phys failed %d bdi[0x%x]\n",
+ __func__, encl_dev->external, bmic_device_index);
+ goto out;
+ }
+
+ c = cmd_alloc(h);
+
+ rc = fill_cmd(c, BMIC_SENSE_STORAGE_BOX_PARAMS, h, bssbp,
+ sizeof(*bssbp), 0, RAID_CTLR_LUNID, TYPE_CMD);
+
+ if (rc)
+ goto out;
+
+ if (id_phys->phys_connector[1] == 'E')
+ c->Request.CDB[5] = id_phys->box_index;
+ else
+ c->Request.CDB[5] = 0;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE,
+ NO_TIMEOUT);
+ if (rc)
+ goto out;
+
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ rc = -1;
+ goto out;
+ }
+
+ encl_dev->box[id_phys->active_path_number] = bssbp->phys_box_on_port;
+ memcpy(&encl_dev->phys_connector[id_phys->active_path_number],
+ bssbp->phys_connector, sizeof(bssbp->phys_connector));
+
+ rc = IO_OK;
+out:
+ kfree(bssbp);
+ kfree(id_phys);
+
+ if (c)
+ cmd_free(h, c);
+
+ if (rc != IO_OK)
+ hpsa_show_dev_msg(KERN_INFO, h, encl_dev,
+ "Error, could not get enclosure information\n");
+}
+
static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h,
unsigned char *scsi3addr)
{
@@ -4032,7 +4109,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
/* skip masked non-disk devices */
if (MASKED_DEVICE(lunaddrbytes) && physical_device &&
- (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
+ (physdev_list->LUN[phys_dev_index].device_type != 0x06) &&
+ (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
continue;
/* Get device type, vendor, model, device id */
@@ -4116,7 +4194,12 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
break;
case TYPE_TAPE:
case TYPE_MEDIUM_CHANGER:
+ ncurrent++;
+ break;
case TYPE_ENCLOSURE:
+ hpsa_get_enclosure_info(h, lunaddrbytes,
+ physdev_list, phys_dev_index,
+ this_device);
ncurrent++;
break;
case TYPE_RAID:
@@ -6629,6 +6712,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0XFF;
break;
+ case BMIC_SENSE_STORAGE_BOX_PARAMS:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_STORAGE_BOX_PARAMS;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ break;
case BMIC_IDENTIFY_CONTROLLER:
c->Request.CDBLen = 10;
c->Request.type_attr_dir =
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index ae5beda1b..fdd39fc0b 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -400,7 +400,7 @@ struct offline_device_entry {
#define HPSA_PHYSICAL_DEVICE_BUS 0
#define HPSA_RAID_VOLUME_BUS 1
#define HPSA_EXTERNAL_RAID_VOLUME_BUS 2
-#define HPSA_HBA_BUS 3
+#define HPSA_HBA_BUS 0
/*
Send the command to the hardware
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index d92ef0d35..6a919ada9 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -291,6 +291,7 @@ struct SenseSubsystem_info {
#define BMIC_SENSE_DIAG_OPTIONS 0xF5
#define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000
#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66
+#define BMIC_SENSE_STORAGE_BOX_PARAMS 0x65
/* Command List Structure */
union SCSI3Addr {
@@ -842,5 +843,17 @@ struct bmic_sense_subsystem_info {
u8 pad[332];
};
+struct bmic_sense_storage_box_params {
+ u8 reserved[36];
+ u8 inquiry_valid;
+ u8 reserved_1[68];
+ u8 phys_box_on_port;
+ u8 reserved_2[22];
+ u16 connection_info;
+ u8 reserver_3[84];
+ u8 phys_connector[2];
+ u8 reserved_4[296];
+};
+
#pragma pack()
#endif /* HPSA_CMD_H */
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 4e1a632cc..f8b88fa78 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -43,6 +43,7 @@ typedef struct {
unsigned dp:1; /* Data phase present */
unsigned rd:1; /* Read data in data phase */
unsigned wanted:1; /* Parport sharing busy flag */
+ unsigned int dev_no; /* Device number */
wait_queue_head_t *waiting;
struct Scsi_Host *host;
struct list_head list;
@@ -1120,15 +1121,40 @@ static struct scsi_host_template imm_template = {
static LIST_HEAD(imm_hosts);
+/*
+ * Finds the first available device number that can be alloted to the
+ * new imm device and returns the address of the previous node so that
+ * we can add to the tail and have a list in the ascending order.
+ */
+
+static inline imm_struct *find_parent(void)
+{
+ imm_struct *dev, *par = NULL;
+ unsigned int cnt = 0;
+
+ if (list_empty(&imm_hosts))
+ return NULL;
+
+ list_for_each_entry(dev, &imm_hosts, list) {
+ if (dev->dev_no != cnt)
+ return par;
+ cnt++;
+ par = dev;
+ }
+
+ return par;
+}
+
static int __imm_attach(struct parport *pb)
{
struct Scsi_Host *host;
- imm_struct *dev;
+ imm_struct *dev, *temp;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting);
DEFINE_WAIT(wait);
int ports;
int modes, ppb;
int err = -ENOMEM;
+ struct pardev_cb imm_cb;
init_waitqueue_head(&waiting);
@@ -1141,9 +1167,15 @@ static int __imm_attach(struct parport *pb)
dev->mode = IMM_AUTODETECT;
INIT_LIST_HEAD(&dev->list);
- dev->dev = parport_register_device(pb, "imm", NULL, imm_wakeup,
- NULL, 0, dev);
+ temp = find_parent();
+ if (temp)
+ dev->dev_no = temp->dev_no + 1;
+
+ memset(&imm_cb, 0, sizeof(imm_cb));
+ imm_cb.private = dev;
+ imm_cb.wakeup = imm_wakeup;
+ dev->dev = parport_register_dev_model(pb, "imm", &imm_cb, dev->dev_no);
if (!dev->dev)
goto out;
@@ -1207,7 +1239,10 @@ static int __imm_attach(struct parport *pb)
host->unique_id = pb->number;
*(imm_struct **)&host->hostdata = dev;
dev->host = host;
- list_add_tail(&dev->list, &imm_hosts);
+ if (!temp)
+ list_add_tail(&dev->list, &imm_hosts);
+ else
+ list_add_tail(&dev->list, &temp->list);
err = scsi_add_host(host, NULL);
if (err)
goto out2;
@@ -1245,9 +1280,10 @@ static void imm_detach(struct parport *pb)
}
static struct parport_driver imm_driver = {
- .name = "imm",
- .attach = imm_attach,
- .detach = imm_detach,
+ .name = "imm",
+ .match_port = imm_attach,
+ .detach = imm_detach,
+ .devmodel = true,
};
static int __init imm_driver_init(void)
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 6a926bae7..7a91cf3ff 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -110,11 +110,6 @@
#define i91u_MAXQUEUE 2
#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
-#define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */
-#define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */
-#define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */
-#define I920_DEVICE_ID 0x0002 /* Initio's other product ID */
-
#ifdef DEBUG_i91u
static unsigned int i91u_debug = DEBUG_DEFAULT;
#endif
@@ -127,17 +122,6 @@ static int setup_debug = 0;
static void i91uSCBPost(u8 * pHcb, u8 * pScb);
-/* PCI Devices supported by this driver */
-static struct pci_device_id i91u_pci_devices[] = {
- { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { }
-};
-MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
-
#define DEBUG_INTERRUPT 0
#define DEBUG_QUEUE 0
#define DEBUG_STATE 0
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 536cd5a80..d6a691e27 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3638,7 +3638,7 @@ static struct device_attribute ipr_ioa_reset_attr = {
.store = ipr_store_reset_adapter
};
-static int ipr_iopoll(struct blk_iopoll *iop, int budget);
+static int ipr_iopoll(struct irq_poll *iop, int budget);
/**
* ipr_show_iopoll_weight - Show ipr polling mode
* @dev: class device struct
@@ -3681,34 +3681,33 @@ static ssize_t ipr_store_iopoll_weight(struct device *dev,
int i;
if (!ioa_cfg->sis64) {
- dev_info(&ioa_cfg->pdev->dev, "blk-iopoll not supported on this adapter\n");
+ dev_info(&ioa_cfg->pdev->dev, "irq_poll not supported on this adapter\n");
return -EINVAL;
}
if (kstrtoul(buf, 10, &user_iopoll_weight))
return -EINVAL;
if (user_iopoll_weight > 256) {
- dev_info(&ioa_cfg->pdev->dev, "Invalid blk-iopoll weight. It must be less than 256\n");
+ dev_info(&ioa_cfg->pdev->dev, "Invalid irq_poll weight. It must be less than 256\n");
return -EINVAL;
}
if (user_iopoll_weight == ioa_cfg->iopoll_weight) {
- dev_info(&ioa_cfg->pdev->dev, "Current blk-iopoll weight has the same weight\n");
+ dev_info(&ioa_cfg->pdev->dev, "Current irq_poll weight has the same weight\n");
return strlen(buf);
}
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++)
- blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
+ irq_poll_disable(&ioa_cfg->hrrq[i].iopoll);
}
spin_lock_irqsave(shost->host_lock, lock_flags);
ioa_cfg->iopoll_weight = user_iopoll_weight;
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
- blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
+ irq_poll_init(&ioa_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
- blk_iopoll_enable(&ioa_cfg->hrrq[i].iopoll);
}
}
spin_unlock_irqrestore(shost->host_lock, lock_flags);
@@ -4003,13 +4002,17 @@ static ssize_t ipr_store_update_fw(struct device *dev,
struct ipr_sglist *sglist;
char fname[100];
char *src;
- int len, result, dnld_size;
+ char *endline;
+ int result, dnld_size;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- len = snprintf(fname, 99, "%s", buf);
- fname[len-1] = '\0';
+ snprintf(fname, sizeof(fname), "%s", buf);
+
+ endline = strchr(fname, '\n');
+ if (endline)
+ *endline = '\0';
if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
@@ -5569,7 +5572,7 @@ static int ipr_process_hrrq(struct ipr_hrr_queue *hrr_queue, int budget,
return num_hrrq;
}
-static int ipr_iopoll(struct blk_iopoll *iop, int budget)
+static int ipr_iopoll(struct irq_poll *iop, int budget)
{
struct ipr_ioa_cfg *ioa_cfg;
struct ipr_hrr_queue *hrrq;
@@ -5585,7 +5588,7 @@ static int ipr_iopoll(struct blk_iopoll *iop, int budget)
completed_ops = ipr_process_hrrq(hrrq, budget, &doneq);
if (completed_ops < budget)
- blk_iopoll_complete(iop);
+ irq_poll_complete(iop);
spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
list_for_each_entry_safe(ipr_cmd, temp, &doneq, queue) {
@@ -5693,8 +5696,7 @@ static irqreturn_t ipr_isr_mhrrq(int irq, void *devp)
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
if ((be32_to_cpu(*hrrq->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) ==
hrrq->toggle_bit) {
- if (!blk_iopoll_sched_prep(&hrrq->iopoll))
- blk_iopoll_sched(&hrrq->iopoll);
+ irq_poll_sched(&hrrq->iopoll);
spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
return IRQ_HANDLED;
}
@@ -10405,9 +10407,8 @@ static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
for (i = 1; i < ioa_cfg->hrrq_num; i++) {
- blk_iopoll_init(&ioa_cfg->hrrq[i].iopoll,
+ irq_poll_init(&ioa_cfg->hrrq[i].iopoll,
ioa_cfg->iopoll_weight, ipr_iopoll);
- blk_iopoll_enable(&ioa_cfg->hrrq[i].iopoll);
}
}
@@ -10436,7 +10437,7 @@ static void ipr_shutdown(struct pci_dev *pdev)
if (ioa_cfg->iopoll_weight && ioa_cfg->sis64 && ioa_cfg->nvectors > 1) {
ioa_cfg->iopoll_weight = 0;
for (i = 1; i < ioa_cfg->hrrq_num; i++)
- blk_iopoll_disable(&ioa_cfg->hrrq[i].iopoll);
+ irq_poll_disable(&ioa_cfg->hrrq[i].iopoll);
}
while (ioa_cfg->in_reset_reload) {
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index a34c7a5a9..56c570683 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -32,7 +32,7 @@
#include <linux/libata.h>
#include <linux/list.h>
#include <linux/kref.h>
-#include <linux/blk-iopoll.h>
+#include <linux/irq_poll.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -517,7 +517,7 @@ struct ipr_hrr_queue {
u8 allow_cmds:1;
u8 removing_ioa:1;
- struct blk_iopoll iopoll;
+ struct irq_poll iopoll;
};
/* Command packet structure */
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index ceee9a3fd..90a3ca5a4 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -386,7 +386,6 @@ struct lpfc_vport {
uint32_t work_port_events; /* Timeout to be handled */
#define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */
#define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */
-#define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */
#define WORKER_DELAYED_DISC_TMO 0x8 /* vport: delayed discovery */
#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
@@ -396,7 +395,6 @@ struct lpfc_vport {
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */
- struct timer_list fc_fdmitmo;
struct timer_list els_tmofunc;
struct timer_list delayed_disc_tmo;
@@ -405,6 +403,7 @@ struct lpfc_vport {
uint8_t load_flag;
#define FC_LOADING 0x1 /* HBA in process of loading drvr */
#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
+#define FC_ALLOW_FDMI 0x4 /* port is ready for FDMI requests */
/* Vport Config Parameters */
uint32_t cfg_scan_down;
uint32_t cfg_lun_queue_depth;
@@ -414,10 +413,6 @@ struct lpfc_vport {
uint32_t cfg_peer_port_login;
uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc;
- uint32_t cfg_fdmi_on;
-#define LPFC_FDMI_SUPPORT 1 /* bit 0 - FDMI supported? */
-#define LPFC_FDMI_REG_DELAY 2 /* bit 1 - 60 sec registration delay */
-#define LPFC_FDMI_ALL_ATTRIB 4 /* bit 2 - register ALL attributes? */
uint32_t cfg_discovery_threads;
uint32_t cfg_log_verbose;
uint32_t cfg_max_luns;
@@ -443,6 +438,10 @@ struct lpfc_vport {
unsigned long rcv_buffer_time_stamp;
uint32_t vport_flag;
#define STATIC_VPORT 1
+
+ uint16_t fdmi_num_disc;
+ uint32_t fdmi_hba_mask;
+ uint32_t fdmi_port_mask;
};
struct hbq_s {
@@ -755,6 +754,11 @@ struct lpfc_hba {
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */
uint32_t cfg_enable_dss;
+ uint32_t cfg_fdmi_on;
+#define LPFC_FDMI_NO_SUPPORT 0 /* FDMI not supported */
+#define LPFC_FDMI_SUPPORT 1 /* FDMI supported? */
+#define LPFC_FDMI_SMART_SAN 2 /* SmartSAN supported */
+ uint32_t cfg_enable_SmartSAN;
lpfc_vpd_t vpd; /* vital product data */
struct pci_dev *pcidev;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index f6446d759..343ae9482 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -4572,19 +4572,27 @@ LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1,
255, "Identifies TYPE for additional ring configuration");
/*
-# lpfc_fdmi_on: controls FDMI support.
-# Set NOT Set
-# bit 0 = FDMI support no FDMI support
-# LPFC_FDMI_SUPPORT just turns basic support on/off
-# bit 1 = Register delay no register delay (60 seconds)
-# LPFC_FDMI_REG_DELAY 60 sec registration delay after FDMI login
-# bit 2 = All attributes Use a attribute subset
-# LPFC_FDMI_ALL_ATTRIB applies to both port and HBA attributes
-# Port attrutes subset: 1 thru 6 OR all: 1 thru 0xd 0x101 0x102 0x103
-# HBA attributes subset: 1 thru 0xb OR all: 1 thru 0xc
-# Value range [0,7]. Default value is 0.
+# lpfc_enable_SmartSAN: Sets up FDMI support for SmartSAN
+# 0 = SmartSAN functionality disabled (default)
+# 1 = SmartSAN functionality enabled
+# This parameter will override the value of lpfc_fdmi_on module parameter.
+# Value range is [0,1]. Default value is 0.
*/
-LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 7, "Enable FDMI support");
+LPFC_ATTR_R(enable_SmartSAN, 0, 0, 1, "Enable SmartSAN functionality");
+
+/*
+# lpfc_fdmi_on: Controls FDMI support.
+# 0 No FDMI support (default)
+# 1 Traditional FDMI support
+# 2 Smart SAN support
+# If lpfc_enable_SmartSAN is set 1, the driver sets lpfc_fdmi_on to value 2
+# overwriting the current value. If lpfc_enable_SmartSAN is set 0, the
+# driver uses the current value of lpfc_fdmi_on provided it has value 0 or 1.
+# A value of 2 with lpfc_enable_SmartSAN set to 0 causes the driver to
+# set lpfc_fdmi_on back to 1.
+# Value range [0,2]. Default value is 0.
+*/
+LPFC_ATTR_R(fdmi_on, 0, 0, 2, "Enable FDMI support");
/*
# Specifies the maximum number of ELS cmds we can have outstanding (for
@@ -4815,6 +4823,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_multi_ring_rctl,
&dev_attr_lpfc_multi_ring_type,
&dev_attr_lpfc_fdmi_on,
+ &dev_attr_lpfc_enable_SmartSAN,
&dev_attr_lpfc_max_luns,
&dev_attr_lpfc_enable_npiv,
&dev_attr_lpfc_fcf_failover_policy,
@@ -4887,7 +4896,6 @@ struct device_attribute *lpfc_vport_attrs[] = {
&dev_attr_lpfc_fcp_class,
&dev_attr_lpfc_use_adisc,
&dev_attr_lpfc_first_burst_size,
- &dev_attr_lpfc_fdmi_on,
&dev_attr_lpfc_max_luns,
&dev_attr_nport_evt_cnt,
&dev_attr_npiv_info,
@@ -5247,7 +5255,7 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
spin_lock_irq(shost->host_lock);
- if (lpfc_is_link_up(phba)) {
+ if ((lpfc_is_link_up(phba)) && (!(phba->hba_flag & HBA_FCOE_MODE))) {
switch(phba->fc_linkspeed) {
case LPFC_LINK_SPEED_1GHZ:
fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
@@ -5826,6 +5834,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
+ lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
+ lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
@@ -5846,6 +5856,15 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
phba->cfg_poll = 0;
else
phba->cfg_poll = lpfc_poll;
+
+ /* Ensure fdmi_on and enable_SmartSAN don't conflict */
+ if (phba->cfg_enable_SmartSAN) {
+ phba->cfg_fdmi_on = LPFC_FDMI_SMART_SAN;
+ } else {
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ phba->cfg_fdmi_on = LPFC_FDMI_SUPPORT;
+ }
+
phba->cfg_soft_wwnn = 0L;
phba->cfg_soft_wwpn = 0L;
lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
@@ -5879,7 +5898,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
lpfc_use_adisc_init(vport, lpfc_use_adisc);
lpfc_first_burst_size_init(vport, lpfc_first_burst_size);
lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
- lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
lpfc_max_luns_init(vport, lpfc_max_luns);
lpfc_scan_down_init(vport, lpfc_scan_down);
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index b0e6fe464..4e55b3518 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -72,6 +72,7 @@ void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
void lpfc_retry_pport_discovery(struct lpfc_hba *);
void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
+void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -167,9 +168,8 @@ void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_ct_handle_unsol_abort(struct lpfc_hba *, struct hbq_dmabuf *);
int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
-int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
-void lpfc_fdmi_tmo(unsigned long);
-void lpfc_fdmi_timeout_handler(struct lpfc_vport *);
+int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int, uint32_t);
+void lpfc_fdmi_num_disc_check(struct lpfc_vport *);
void lpfc_delayed_disc_tmo(unsigned long);
void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 8fded1f76..79e261d2a 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -48,15 +48,26 @@
#include "lpfc_vport.h"
#include "lpfc_debugfs.h"
-/* FDMI Port Speed definitions */
-#define HBA_PORTSPEED_1GBIT 0x0001 /* 1 GBit/sec */
-#define HBA_PORTSPEED_2GBIT 0x0002 /* 2 GBit/sec */
-#define HBA_PORTSPEED_4GBIT 0x0008 /* 4 GBit/sec */
-#define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */
-#define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */
-#define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */
-#define HBA_PORTSPEED_32GBIT 0x0040 /* 32 GBit/sec */
-#define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */
+/* FDMI Port Speed definitions - FC-GS-7 */
+#define HBA_PORTSPEED_1GFC 0x00000001 /* 1G FC */
+#define HBA_PORTSPEED_2GFC 0x00000002 /* 2G FC */
+#define HBA_PORTSPEED_4GFC 0x00000008 /* 4G FC */
+#define HBA_PORTSPEED_10GFC 0x00000004 /* 10G FC */
+#define HBA_PORTSPEED_8GFC 0x00000010 /* 8G FC */
+#define HBA_PORTSPEED_16GFC 0x00000020 /* 16G FC */
+#define HBA_PORTSPEED_32GFC 0x00000040 /* 32G FC */
+#define HBA_PORTSPEED_20GFC 0x00000080 /* 20G FC */
+#define HBA_PORTSPEED_40GFC 0x00000100 /* 40G FC */
+#define HBA_PORTSPEED_128GFC 0x00000200 /* 128G FC */
+#define HBA_PORTSPEED_64GFC 0x00000400 /* 64G FC */
+#define HBA_PORTSPEED_256GFC 0x00000800 /* 256G FC */
+#define HBA_PORTSPEED_UNKNOWN 0x00008000 /* Unknown */
+#define HBA_PORTSPEED_10GE 0x00010000 /* 10G E */
+#define HBA_PORTSPEED_40GE 0x00020000 /* 40G E */
+#define HBA_PORTSPEED_100GE 0x00040000 /* 100G E */
+#define HBA_PORTSPEED_25GE 0x00080000 /* 25G E */
+#define HBA_PORTSPEED_50GE 0x00100000 /* 50G E */
+#define HBA_PORTSPEED_400GE 0x00200000 /* 400G E */
#define FOURBYTES 4
@@ -287,6 +298,17 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
return 0;
}
+/**
+ * lpfc_gen_req - Build and issue a GEN_REQUEST command to the SLI Layer
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @bmp: Pointer to BPL for SLI command
+ * @inp: Pointer to data buffer for response data.
+ * @outp: Pointer to data buffer that hold the CT command.
+ * @cmpl: completion routine to call when command completes
+ * @ndlp: Destination NPort nodelist entry
+ *
+ * This function as the final part for issuing a CT command.
+ */
static int
lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
@@ -311,7 +333,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
- icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64));
+ icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
if (usr_flg)
geniocb->context3 = NULL;
@@ -370,6 +392,16 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
return 0;
}
+/**
+ * lpfc_ct_cmd - Build and issue a CT command
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @inmp: Pointer to data buffer for response data.
+ * @bmp: Pointer to BPL for SLI command
+ * @ndlp: Destination NPort nodelist entry
+ * @cmpl: completion routine to call when command completes
+ *
+ * This function is called for issuing a CT command.
+ */
static int
lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
@@ -453,7 +485,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
Cnt -= 16; /* subtract length of CT header */
/* Loop through entire NameServer list of DIDs */
- while (Cnt >= sizeof (uint32_t)) {
+ while (Cnt >= sizeof(uint32_t)) {
/* Get next DID from NameServer List */
CTentry = *ctptr++;
Did = ((be32_to_cpu(CTentry)) & Mask_DID);
@@ -558,7 +590,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
}
if (CTentry & (cpu_to_be32(SLI_CT_LAST_ENTRY)))
goto nsout1;
- Cnt -= sizeof (uint32_t);
+ Cnt -= sizeof(uint32_t);
}
ctptr = NULL;
@@ -1146,7 +1178,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
/* fill in BDEs for command */
/* Allocate buffer for command payload */
- mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (!mp) {
rc=2;
goto ns_cmd_exit;
@@ -1160,7 +1192,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
}
/* Allocate buffer for Buffer ptr list */
- bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (!bmp) {
rc=4;
goto ns_cmd_free_mpvirt;
@@ -1204,7 +1236,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
bpl->tus.w = le32_to_cpu(bpl->tus.w);
CtReq = (struct lpfc_sli_ct_request *) mp->virt;
- memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request));
+ memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
CtReq->RevisionId.bits.InId = 0;
CtReq->FsType = SLI_CT_DIRECTORY_SERVICE;
@@ -1244,7 +1276,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
cpu_to_be16(SLI_CTNS_RNN_ID);
CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
cmpl = lpfc_cmpl_ct_cmd_rnn_id;
break;
@@ -1264,7 +1296,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
CtReq->CommandResponse.bits.CmdRsp =
cpu_to_be16(SLI_CTNS_RSNN_NN);
memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
size = sizeof(CtReq->un.rsnn.symbname);
CtReq->un.rsnn.len =
lpfc_vport_symbolic_node_name(vport,
@@ -1319,20 +1351,29 @@ ns_cmd_exit:
return 1;
}
+/**
+ * lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion
+ * @phba: Pointer to HBA context object.
+ * @cmdiocb: Pointer to the command IOCBQ.
+ * @rspiocb: Pointer to the response IOCBQ.
+ *
+ * This function to handle the completion of a driver initiated FDMI
+ * CT command issued during discovery.
+ */
static void
-lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_dmabuf *inp = cmdiocb->context1;
struct lpfc_dmabuf *outp = cmdiocb->context2;
- struct lpfc_sli_ct_request *CTrsp = outp->virt;
struct lpfc_sli_ct_request *CTcmd = inp->virt;
- struct lpfc_nodelist *ndlp;
+ struct lpfc_sli_ct_request *CTrsp = outp->virt;
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
- struct lpfc_vport *vport = cmdiocb->vport;
IOCB_t *irsp = &rspiocb->iocb;
- uint32_t latt;
+ struct lpfc_nodelist *ndlp;
+ uint32_t latt, cmd, err;
latt = lpfc_els_chk_latt(vport);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
@@ -1340,91 +1381,1115 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4], latt);
if (latt || irsp->ulpStatus) {
+
+ /* Look for a retryable error */
+ if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) {
+ case IOERR_SLI_ABORTED:
+ case IOERR_ABORT_IN_PROGRESS:
+ case IOERR_SEQUENCE_TIMEOUT:
+ case IOERR_ILLEGAL_FRAME:
+ case IOERR_NO_RESOURCES:
+ case IOERR_ILLEGAL_COMMAND:
+ cmdiocb->retry++;
+ if (cmdiocb->retry >= LPFC_FDMI_MAX_RETRY)
+ break;
+
+ /* Retry the same FDMI command */
+ err = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING,
+ cmdiocb, 0);
+ if (err == IOCB_ERROR)
+ break;
+ return;
+ default:
+ break;
+ }
+ }
+
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
"0229 FDMI cmd %04x failed, latt = %d "
"ulpStatus: x%x, rid x%x\n",
be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
irsp->un.ulpWord[4]);
- goto fail_out;
}
+ lpfc_ct_free_iocb(phba, cmdiocb);
ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
- goto fail_out;
+ return;
+ /* Check for a CT LS_RJT response */
+ cmd = be16_to_cpu(fdmi_cmd);
if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0220 FDMI rsp failed Data: x%x\n",
- be16_to_cpu(fdmi_cmd));
+ "0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
+
+ /* Should we fallback to FDMI-2 / FDMI-1 ? */
+ switch (cmd) {
+ case SLI_MGMT_RHBA:
+ if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+ }
+ return;
+
+ case SLI_MGMT_RPRT:
+ if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ /* Retry the same command */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ return;
+
+ case SLI_MGMT_RPA:
+ if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
+ /* Fallback to FDMI-1 */
+ vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+ vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
+ /* Start over */
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
+ }
+ if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ /* Retry the same command */
+ lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
+ }
+ return;
+ }
}
-fail_out:
- lpfc_ct_free_iocb(phba, cmdiocb);
+ /*
+ * On success, need to cycle thru FDMI registration for discovery
+ * DHBA -> DPRT -> RHBA -> RPA (physical port)
+ * DPRT -> RPRT (vports)
+ */
+ switch (cmd) {
+ case SLI_MGMT_RHBA:
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0);
+ break;
+
+ case SLI_MGMT_DHBA:
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+ break;
+
+ case SLI_MGMT_DPRT:
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0);
+ else
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ break;
+ }
+ return;
}
-static void
-lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq *rspiocb)
+
+/**
+ * lpfc_fdmi_num_disc_check - Check how many mapped NPorts we are connected to
+ * @vport: pointer to a host virtual N_Port data structure.
+ *
+ * Called from hbeat timeout routine to check if the number of discovered
+ * ports has changed. If so, re-register thar port Attribute.
+ */
+void
+lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
{
- struct lpfc_vport *vport = cmdiocb->vport;
- struct lpfc_dmabuf *inp = cmdiocb->context1;
- struct lpfc_sli_ct_request *CTcmd = inp->virt;
- uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp;
+ uint16_t cnt;
+
+ if (!lpfc_is_link_up(phba))
+ return;
+
+ if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
+ return;
- lpfc_cmpl_ct_cmd_fdmi(phba, cmdiocb, rspiocb);
+ cnt = lpfc_find_map_node(vport);
+ if (cnt == vport->fdmi_num_disc)
+ return;
ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
return;
- /*
- * Need to cycle thru FDMI registration for discovery
- * DHBA -> DPRT -> RHBA -> RPA
- */
- switch (be16_to_cpu(fdmi_cmd)) {
- case SLI_MGMT_RHBA:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA);
- break;
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
+ LPFC_FDMI_PORT_ATTR_num_disc);
+ } else {
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT,
+ LPFC_FDMI_PORT_ATTR_num_disc);
+ }
+}
- case SLI_MGMT_DHBA:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT);
- break;
+/* Routines for all individual HBA attributes */
+int
+lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
- case SLI_MGMT_DPRT:
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
- break;
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_NODENAME);
+ return size;
+}
+int
+lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString,
+ "Emulex Corporation",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->SerialNumber,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelName,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MODEL);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelDesc,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ lpfc_vpd_t *vp = &phba->vpd;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t i, j, incr, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ /* Convert JEDEC ID to ascii for hardware version */
+ incr = vp->rev.biuRev;
+ for (i = 0; i < 8; i++) {
+ j = (incr & 0xf);
+ if (j <= 9)
+ ae->un.AttrString[7 - i] =
+ (char)((uint8_t) 0x30 +
+ (uint8_t) j);
+ else
+ ae->un.AttrString[7 - i] =
+ (char)((uint8_t) 0x61 +
+ (uint8_t) (j - 10));
+ incr = (incr >> 4);
}
+ size = FOURBYTES + 8;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, lpfc_release_version,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ else
+ strncpy(ae->un.AttrString, phba->OptionROMVersion,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s %s %s",
+ init_utsname()->sysname,
+ init_utsname()->release,
+ init_utsname()->version);
+
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ ae->un.AttrInt = cpu_to_be32(LPFC_MAX_CT_SIZE);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ len = lpfc_vport_symbolic_node_name(vport,
+ ae->un.AttrString, 256);
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Nothing is defined for this currently */
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_VENDOR_INFO);
+ return size;
}
+int
+lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Each driver instance corresponds to a single port */
+ ae->un.AttrInt = cpu_to_be32(1);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_NUM_PORTS);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fabric_nodename,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_FABRIC_WWNN);
+ return size;
+}
int
-lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
+lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_BIOS_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* Driver doesn't have access to this information */
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_BIOS_STATE);
+ return size;
+}
+
+int
+lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "EMULEX",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RHBA_VENDOR_ID);
+ return size;
+}
+
+/* Routines for all individual PORT attributes */
+int
+lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 32);
+
+ ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+ ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+ size = FOURBYTES + 32;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ ae->un.AttrInt = 0;
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ if (phba->lmt & LMT_32Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_16GFC;
+ if (phba->lmt & LMT_10Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_10GFC;
+ if (phba->lmt & LMT_8Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_8GFC;
+ if (phba->lmt & LMT_4Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_4GFC;
+ if (phba->lmt & LMT_2Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_2GFC;
+ if (phba->lmt & LMT_1Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_1GFC;
+ } else {
+ /* FCoE links support only one speed */
+ switch (phba->fc_linkspeed) {
+ case LPFC_ASYNC_LINK_SPEED_10GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_10GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_25GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_25GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_40GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_40GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_100GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_100GE;
+ break;
+ }
+ }
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_1GFC;
+ break;
+ case LPFC_LINK_SPEED_2GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_2GFC;
+ break;
+ case LPFC_LINK_SPEED_4GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_4GFC;
+ break;
+ case LPFC_LINK_SPEED_8GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_8GFC;
+ break;
+ case LPFC_LINK_SPEED_10GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_10GFC;
+ break;
+ case LPFC_LINK_SPEED_16GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_16GFC;
+ break;
+ case LPFC_LINK_SPEED_32GHZ:
+ ae->un.AttrInt = HBA_PORTSPEED_32GFC;
+ break;
+ default:
+ ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+ break;
+ }
+ } else {
+ switch (phba->fc_linkspeed) {
+ case LPFC_ASYNC_LINK_SPEED_10GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_10GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_25GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_25GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_40GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_40GE;
+ break;
+ case LPFC_ASYNC_LINK_SPEED_100GBPS:
+ ae->un.AttrInt = HBA_PORTSPEED_100GE;
+ break;
+ default:
+ ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
+ break;
+ }
+ }
+
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct serv_parm *hsp;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ hsp = (struct serv_parm *)&vport->fc_sparam;
+ ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb) << 8) |
+ (uint32_t) hsp->cmn.bbRcvSizeLsb;
+ ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString),
+ "/sys/class/scsi_host/host%d", shost->host_no);
+ len = strnlen((char *)ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
+ init_utsname()->nodename);
+
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_NODENAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ len = lpfc_vport_symbolic_port_name(vport, ae->un.AttrString, 256);
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ if (phba->fc_topology == LPFC_TOPOLOGY_LOOP)
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NLPORT);
+ else
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NPORT);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_class(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, sizeof(struct lpfc_name));
+
+ memcpy(&ae->un.AttrWWN, &vport->fabric_portname,
+ sizeof(struct lpfc_name));
+ size = FOURBYTES + sizeof(struct lpfc_name);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 32);
+
+ ae->un.AttrTypes[3] = 0x02; /* Type 1 - ELS */
+ ae->un.AttrTypes[2] = 0x01; /* Type 8 - FCP */
+ ae->un.AttrTypes[7] = 0x01; /* Type 32 - CT */
+ size = FOURBYTES + 32;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ /* Link Up - operational */
+ ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTSTATE_ONLINE);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ vport->fdmi_num_disc = lpfc_find_map_node(vport);
+ ae->un.AttrInt = cpu_to_be32(vport->fdmi_num_disc);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
+ return size;
+}
+
+int
+lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(vport->fc_myDID);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "Smart SAN Initiator",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_SERVICE);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ memcpy(&ae->un.AttrString, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ memcpy((((uint8_t *)&ae->un.AttrString) +
+ sizeof(struct lpfc_name)),
+ &vport->fc_sparam.portName, sizeof(struct lpfc_name));
+ size = FOURBYTES + (2 * sizeof(struct lpfc_name));
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_GUID);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, "Smart SAN Version 1.0",
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString,
+ sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_VERSION);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t len, size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ memset(ae, 0, 256);
+
+ strncpy(ae->un.AttrString, phba->ModelName,
+ sizeof(ae->un.AttrString));
+ len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
+ len += (len & 3) ? (4 - (len & 3)) : 4;
+ size = FOURBYTES + len;
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_MODEL);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+
+ /* SRIOV (type 3) is not supported */
+ if (vport->vpi)
+ ae->un.AttrInt = cpu_to_be32(2); /* NPIV */
+ else
+ ae->un.AttrInt = cpu_to_be32(1); /* Physical */
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_PORT_INFO);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_QOS);
+ return size;
+}
+
+int
+lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport,
+ struct lpfc_fdmi_attr_def *ad)
+{
+ struct lpfc_fdmi_attr_entry *ae;
+ uint32_t size;
+
+ ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
+ ae->un.AttrInt = cpu_to_be32(0);
+ size = FOURBYTES + sizeof(uint32_t);
+ ad->AttrLen = cpu_to_be16(size);
+ ad->AttrType = cpu_to_be16(RPRT_SMART_SECURITY);
+ return size;
+}
+
+/* RHBA attribute jump table */
+int (*lpfc_fdmi_hba_action[])
+ (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+ /* Action routine Mask bit Attribute type */
+ lpfc_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */
+ lpfc_fdmi_hba_attr_manufacturer, /* bit1 RHBA_MANUFACTURER */
+ lpfc_fdmi_hba_attr_sn, /* bit2 RHBA_SERIAL_NUMBER */
+ lpfc_fdmi_hba_attr_model, /* bit3 RHBA_MODEL */
+ lpfc_fdmi_hba_attr_description, /* bit4 RHBA_MODEL_DESCRIPTION */
+ lpfc_fdmi_hba_attr_hdw_ver, /* bit5 RHBA_HARDWARE_VERSION */
+ lpfc_fdmi_hba_attr_drvr_ver, /* bit6 RHBA_DRIVER_VERSION */
+ lpfc_fdmi_hba_attr_rom_ver, /* bit7 RHBA_OPTION_ROM_VERSION */
+ lpfc_fdmi_hba_attr_fmw_ver, /* bit8 RHBA_FIRMWARE_VERSION */
+ lpfc_fdmi_hba_attr_os_ver, /* bit9 RHBA_OS_NAME_VERSION */
+ lpfc_fdmi_hba_attr_ct_len, /* bit10 RHBA_MAX_CT_PAYLOAD_LEN */
+ lpfc_fdmi_hba_attr_symbolic_name, /* bit11 RHBA_SYM_NODENAME */
+ lpfc_fdmi_hba_attr_vendor_info, /* bit12 RHBA_VENDOR_INFO */
+ lpfc_fdmi_hba_attr_num_ports, /* bit13 RHBA_NUM_PORTS */
+ lpfc_fdmi_hba_attr_fabric_wwnn, /* bit14 RHBA_FABRIC_WWNN */
+ lpfc_fdmi_hba_attr_bios_ver, /* bit15 RHBA_BIOS_VERSION */
+ lpfc_fdmi_hba_attr_bios_state, /* bit16 RHBA_BIOS_STATE */
+ lpfc_fdmi_hba_attr_vendor_id, /* bit17 RHBA_VENDOR_ID */
+};
+
+/* RPA / RPRT attribute jump table */
+int (*lpfc_fdmi_port_action[])
+ (struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
+ /* Action routine Mask bit Attribute type */
+ lpfc_fdmi_port_attr_fc4type, /* bit0 RPRT_SUPPORT_FC4_TYPES */
+ lpfc_fdmi_port_attr_support_speed, /* bit1 RPRT_SUPPORTED_SPEED */
+ lpfc_fdmi_port_attr_speed, /* bit2 RPRT_PORT_SPEED */
+ lpfc_fdmi_port_attr_max_frame, /* bit3 RPRT_MAX_FRAME_SIZE */
+ lpfc_fdmi_port_attr_os_devname, /* bit4 RPRT_OS_DEVICE_NAME */
+ lpfc_fdmi_port_attr_host_name, /* bit5 RPRT_HOST_NAME */
+ lpfc_fdmi_port_attr_wwnn, /* bit6 RPRT_NODENAME */
+ lpfc_fdmi_port_attr_wwpn, /* bit7 RPRT_PORTNAME */
+ lpfc_fdmi_port_attr_symbolic_name, /* bit8 RPRT_SYM_PORTNAME */
+ lpfc_fdmi_port_attr_port_type, /* bit9 RPRT_PORT_TYPE */
+ lpfc_fdmi_port_attr_class, /* bit10 RPRT_SUPPORTED_CLASS */
+ lpfc_fdmi_port_attr_fabric_wwpn, /* bit11 RPRT_FABRICNAME */
+ lpfc_fdmi_port_attr_active_fc4type, /* bit12 RPRT_ACTIVE_FC4_TYPES */
+ lpfc_fdmi_port_attr_port_state, /* bit13 RPRT_PORT_STATE */
+ lpfc_fdmi_port_attr_num_disc, /* bit14 RPRT_DISC_PORT */
+ lpfc_fdmi_port_attr_nportid, /* bit15 RPRT_PORT_ID */
+ lpfc_fdmi_smart_attr_service, /* bit16 RPRT_SMART_SERVICE */
+ lpfc_fdmi_smart_attr_guid, /* bit17 RPRT_SMART_GUID */
+ lpfc_fdmi_smart_attr_version, /* bit18 RPRT_SMART_VERSION */
+ lpfc_fdmi_smart_attr_model, /* bit19 RPRT_SMART_MODEL */
+ lpfc_fdmi_smart_attr_port_info, /* bit20 RPRT_SMART_PORT_INFO */
+ lpfc_fdmi_smart_attr_qos, /* bit21 RPRT_SMART_QOS */
+ lpfc_fdmi_smart_attr_security, /* bit22 RPRT_SMART_SECURITY */
+};
+
+/**
+ * lpfc_fdmi_cmd - Build and send a FDMI cmd to the specified NPort
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
+ * cmdcode: FDMI command to send
+ * mask: Mask of HBA or PORT Attributes to send
+ *
+ * Builds and sends a FDMI command using the CT subsystem.
+ */
+int
+lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ int cmdcode, uint32_t new_mask)
{
struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *mp, *bmp;
struct lpfc_sli_ct_request *CtReq;
struct ulp_bde64 *bpl;
+ uint32_t bit_pos;
uint32_t size;
uint32_t rsp_size;
+ uint32_t mask;
struct lpfc_fdmi_reg_hba *rh;
struct lpfc_fdmi_port_entry *pe;
struct lpfc_fdmi_reg_portattr *pab = NULL;
struct lpfc_fdmi_attr_block *ab = NULL;
- struct lpfc_fdmi_attr_entry *ae;
- struct lpfc_fdmi_attr_def *ad;
- void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
- struct lpfc_iocbq *);
+ int (*func)(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad);
+ void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
- if (ndlp == NULL) {
- ndlp = lpfc_findnode_did(vport, FDMI_DID);
- if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
- return 0;
- cmpl = lpfc_cmpl_ct_cmd_fdmi; /* cmd interface */
- } else {
- cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
- }
+ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
+ return 0;
+
+ cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
/* fill in BDEs for command */
/* Allocate buffer for command payload */
@@ -1470,573 +2535,99 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
switch (cmdcode) {
case SLI_MGMT_RHAT:
case SLI_MGMT_RHBA:
- {
- lpfc_vpd_t *vp = &phba->vpd;
- uint32_t i, j, incr;
- int len = 0;
+ rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
+ /* HBA Identifier */
+ memcpy(&rh->hi.PortName, &phba->pport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
- rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
- /* HBA Identifier */
- memcpy(&rh->hi.PortName, &vport->fc_sparam.portName,
+ if (cmdcode == SLI_MGMT_RHBA) {
+ /* Registered Port List */
+ /* One entry (port) per adapter */
+ rh->rpl.EntryCnt = cpu_to_be32(1);
+ memcpy(&rh->rpl.pe, &phba->pport->fc_sparam.portName,
sizeof(struct lpfc_name));
- if (cmdcode == SLI_MGMT_RHBA) {
- /* Registered Port List */
- /* One entry (port) per adapter */
- rh->rpl.EntryCnt = cpu_to_be32(1);
- memcpy(&rh->rpl.pe, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
-
- /* point to the HBA attribute block */
- size = 2 * sizeof(struct lpfc_name) +
- FOURBYTES;
- } else {
- size = sizeof(struct lpfc_name);
- }
- ab = (struct lpfc_fdmi_attr_block *)
- ((uint8_t *)rh + size);
- ab->EntryCnt = 0;
- size += FOURBYTES;
-
- /*
- * Point to beginning of first HBA attribute entry
- */
- /* #1 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RHBA_NODENAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
- sizeof(struct lpfc_name));
- ab->EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #2 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.Manufacturer));
- ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
- strncpy(ae->un.Manufacturer, "Emulex Corporation",
- sizeof(ae->un.Manufacturer));
- len = strnlen(ae->un.Manufacturer,
- sizeof(ae->un.Manufacturer));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #3 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.SerialNumber));
- ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
- strncpy(ae->un.SerialNumber, phba->SerialNumber,
- sizeof(ae->un.SerialNumber));
- len = strnlen(ae->un.SerialNumber,
- sizeof(ae->un.SerialNumber));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #4 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.Model));
- ad->AttrType = cpu_to_be16(RHBA_MODEL);
- strncpy(ae->un.Model, phba->ModelName,
- sizeof(ae->un.Model));
- len = strnlen(ae->un.Model, sizeof(ae->un.Model));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #5 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.ModelDescription));
- ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
- strncpy(ae->un.ModelDescription, phba->ModelDesc,
- sizeof(ae->un.ModelDescription));
- len = strnlen(ae->un.ModelDescription,
- sizeof(ae->un.ModelDescription));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 8) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #6 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, 8);
- ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 8);
- /* Convert JEDEC ID to ascii for hardware version */
- incr = vp->rev.biuRev;
- for (i = 0; i < 8; i++) {
- j = (incr & 0xf);
- if (j <= 9)
- ae->un.HardwareVersion[7 - i] =
- (char)((uint8_t)0x30 +
- (uint8_t)j);
- else
- ae->un.HardwareVersion[7 - i] =
- (char)((uint8_t)0x61 +
- (uint8_t)(j - 10));
- incr = (incr >> 4);
+ /* point to the HBA attribute block */
+ size = 2 * sizeof(struct lpfc_name) +
+ FOURBYTES;
+ } else {
+ size = sizeof(struct lpfc_name);
+ }
+ ab = (struct lpfc_fdmi_attr_block *)((uint8_t *)rh + size);
+ ab->EntryCnt = 0;
+ size += FOURBYTES;
+ bit_pos = 0;
+ if (new_mask)
+ mask = new_mask;
+ else
+ mask = vport->fdmi_hba_mask;
+
+ /* Mask will dictate what attributes to build in the request */
+ while (mask) {
+ if (mask & 0x1) {
+ func = lpfc_fdmi_hba_action[bit_pos];
+ size += func(vport,
+ (struct lpfc_fdmi_attr_def *)
+ ((uint8_t *)rh + size));
+ ab->EntryCnt++;
+ if ((size + 256) >
+ (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+ goto hba_out;
}
- ab->EntryCnt++;
- size += FOURBYTES + 8;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #7 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.DriverVersion));
- ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
- strncpy(ae->un.DriverVersion, lpfc_release_version,
- sizeof(ae->un.DriverVersion));
- len = strnlen(ae->un.DriverVersion,
- sizeof(ae->un.DriverVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #8 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OptionROMVersion));
- ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
- strncpy(ae->un.OptionROMVersion, phba->OptionROMVersion,
- sizeof(ae->un.OptionROMVersion));
- len = strnlen(ae->un.OptionROMVersion,
- sizeof(ae->un.OptionROMVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #9 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FirmwareVersion));
- ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
- lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion,
- 1);
- len = strnlen(ae->un.FirmwareVersion,
- sizeof(ae->un.FirmwareVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #10 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OsNameVersion));
- ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
- snprintf(ae->un.OsNameVersion,
- sizeof(ae->un.OsNameVersion),
- "%s %s %s",
- init_utsname()->sysname,
- init_utsname()->release,
- init_utsname()->version);
- len = strnlen(ae->un.OsNameVersion,
- sizeof(ae->un.OsNameVersion));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /* #11 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType =
- cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- ae->un.MaxCTPayloadLen = cpu_to_be32(LPFC_MAX_CT_SIZE);
- ab->EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto hba_out;
-
- /*
- * Currently switches don't seem to support the
- * following extended HBA attributes.
- */
- if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
- goto hba_out;
-
- /* #12 HBA attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)rh + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.NodeSymName));
- ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
- len = lpfc_vport_symbolic_node_name(vport,
- ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- ab->EntryCnt++;
- size += FOURBYTES + len;
-hba_out:
- ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
- /* Total size */
- size = GID_REQUEST_SZ - 4 + size;
+ mask = mask >> 1;
+ bit_pos++;
}
+hba_out:
+ ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
+ /* Total size */
+ size = GID_REQUEST_SZ - 4 + size;
break;
case SLI_MGMT_RPRT:
case SLI_MGMT_RPA:
- {
- struct serv_parm *hsp;
- int len = 0;
-
- if (cmdcode == SLI_MGMT_RPRT) {
- rh = (struct lpfc_fdmi_reg_hba *)
- &CtReq->un.PortID;
- /* HBA Identifier */
- memcpy(&rh->hi.PortName,
- &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
- pab = (struct lpfc_fdmi_reg_portattr *)
- &rh->rpl.EntryCnt;
- } else
- pab = (struct lpfc_fdmi_reg_portattr *)
- &CtReq->un.PortID;
- size = sizeof(struct lpfc_name) + FOURBYTES;
- memcpy((uint8_t *)&pab->PortName,
- (uint8_t *)&vport->fc_sparam.portName,
+ pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID;
+ if (cmdcode == SLI_MGMT_RPRT) {
+ rh = (struct lpfc_fdmi_reg_hba *)pab;
+ /* HBA Identifier */
+ memcpy(&rh->hi.PortName,
+ &phba->pport->fc_sparam.portName,
sizeof(struct lpfc_name));
- pab->ab.EntryCnt = 0;
-
- /* #1 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FC4Types));
- ad->AttrType =
- cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
- ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
- ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
- ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
- pab->ab.EntryCnt++;
- size += FOURBYTES + 32;
-
- /* #2 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- ae->un.SupportSpeed = 0;
- if (phba->lmt & LMT_32Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_32GBIT;
- if (phba->lmt & LMT_16Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT;
- if (phba->lmt & LMT_10Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT;
- if (phba->lmt & LMT_8Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
- if (phba->lmt & LMT_4Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_4GBIT;
- if (phba->lmt & LMT_2Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT;
- if (phba->lmt & LMT_1Gb)
- ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT;
- ae->un.SupportSpeed =
- cpu_to_be32(ae->un.SupportSpeed);
-
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-
- /* #3 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- switch (phba->fc_linkspeed) {
- case LPFC_LINK_SPEED_1GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
- break;
- case LPFC_LINK_SPEED_2GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
- break;
- case LPFC_LINK_SPEED_4GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
- break;
- case LPFC_LINK_SPEED_8GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
- break;
- case LPFC_LINK_SPEED_10GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
- break;
- case LPFC_LINK_SPEED_16GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_16GBIT;
- break;
- case LPFC_LINK_SPEED_32GHZ:
- ae->un.PortSpeed = HBA_PORTSPEED_32GBIT;
- break;
- default:
- ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN;
- break;
- }
- ae->un.PortSpeed = cpu_to_be32(ae->un.PortSpeed);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-
- /* #4 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- hsp = (struct serv_parm *)&vport->fc_sparam;
- ae->un.MaxFrameSize =
- (((uint32_t)hsp->cmn.
- bbRcvSizeMsb) << 8) | (uint32_t)hsp->cmn.
- bbRcvSizeLsb;
- ae->un.MaxFrameSize =
- cpu_to_be32(ae->un.MaxFrameSize);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #5 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.OsDeviceName));
- ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
- strncpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME,
- sizeof(ae->un.OsDeviceName));
- len = strnlen((char *)ae->un.OsDeviceName,
- sizeof(ae->un.OsDeviceName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #6 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.HostName));
- snprintf(ae->un.HostName, sizeof(ae->un.HostName), "%s",
- init_utsname()->nodename);
- ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
- len = strnlen(ae->un.HostName,
- sizeof(ae->un.HostName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen =
- cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
+ pab = (struct lpfc_fdmi_reg_portattr *)
+ ((uint8_t *)pab + sizeof(struct lpfc_name));
+ }
- /*
- * Currently switches don't seem to support the
- * following extended Port attributes.
- */
- if (!(vport->cfg_fdmi_on & LPFC_FDMI_ALL_ATTRIB))
- goto port_out;
-
- /* #7 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_NODENAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #8 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.PortName, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #9 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.NodeSymName));
- ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
- len = lpfc_vport_symbolic_port_name(vport,
- ae->un.NodeSymName, sizeof(ae->un.NodeSymName));
- len += (len & 3) ? (4 - (len & 3)) : 4;
- ad->AttrLen = cpu_to_be16(FOURBYTES + len);
- pab->ab.EntryCnt++;
- size += FOURBYTES + len;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #10 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
- ae->un.PortState = 0;
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #11 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
- ae->un.SupportClass =
- cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + sizeof(struct lpfc_name)) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #12 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(struct lpfc_name));
- ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
- ad->AttrLen = cpu_to_be16(FOURBYTES
- + sizeof(struct lpfc_name));
- memcpy(&ae->un.FabricName, &vport->fabric_nodename,
- sizeof(struct lpfc_name));
- pab->ab.EntryCnt++;
- size += FOURBYTES + sizeof(struct lpfc_name);
- if ((size + LPFC_FDMI_MAX_AE_SIZE) >
- (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #13 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- memset(ae, 0, sizeof(ae->un.FC4Types));
- ad->AttrType =
- cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 32);
- ae->un.FC4Types[0] = 0x40; /* Type 1 - ELS */
- ae->un.FC4Types[1] = 0x80; /* Type 8 - FCP */
- ae->un.FC4Types[4] = 0x80; /* Type 32 - CT */
- pab->ab.EntryCnt++;
- size += FOURBYTES + 32;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #257 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
- ae->un.PortState = 0;
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #258 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
- ae->un.PortState = lpfc_find_map_node(vport);
- ae->un.PortState = cpu_to_be32(ae->un.PortState);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
- if ((size + 4) > (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
- goto port_out;
-
- /* #259 Port attribute entry */
- ad = (struct lpfc_fdmi_attr_def *)
- ((uint8_t *)pab + size);
- ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
- ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
- ae->un.PortId = cpu_to_be32(vport->fc_myDID);
- ad->AttrLen = cpu_to_be16(FOURBYTES + 4);
- pab->ab.EntryCnt++;
- size += FOURBYTES + 4;
-port_out:
- pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
- /* Total size */
- size = GID_REQUEST_SZ - 4 + size;
+ memcpy((uint8_t *)&pab->PortName,
+ (uint8_t *)&vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ size += sizeof(struct lpfc_name) + FOURBYTES;
+ pab->ab.EntryCnt = 0;
+ bit_pos = 0;
+ if (new_mask)
+ mask = new_mask;
+ else
+ mask = vport->fdmi_port_mask;
+
+ /* Mask will dictate what attributes to build in the request */
+ while (mask) {
+ if (mask & 0x1) {
+ func = lpfc_fdmi_port_action[bit_pos];
+ size += func(vport,
+ (struct lpfc_fdmi_attr_def *)
+ ((uint8_t *)pab + size));
+ pab->ab.EntryCnt++;
+ if ((size + 256) >
+ (LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
+ goto port_out;
+ }
+ mask = mask >> 1;
+ bit_pos++;
}
+port_out:
+ pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
+ /* Total size */
+ if (cmdcode == SLI_MGMT_RPRT)
+ size += sizeof(struct lpfc_name);
+ size = GID_REQUEST_SZ - 4 + size;
break;
case SLI_MGMT_GHAT:
@@ -2158,41 +2749,6 @@ lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport)
}
void
-lpfc_fdmi_tmo(unsigned long ptr)
-{
- struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
- struct lpfc_hba *phba = vport->phba;
- uint32_t tmo_posted;
- unsigned long iflag;
-
- spin_lock_irqsave(&vport->work_port_lock, iflag);
- tmo_posted = vport->work_port_events & WORKER_FDMI_TMO;
- if (!tmo_posted)
- vport->work_port_events |= WORKER_FDMI_TMO;
- spin_unlock_irqrestore(&vport->work_port_lock, iflag);
-
- if (!tmo_posted)
- lpfc_worker_wake_up(phba);
- return;
-}
-
-void
-lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
-{
- struct lpfc_nodelist *ndlp;
-
- ndlp = lpfc_findnode_did(vport, FDMI_DID);
- if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
- if (init_utsname()->nodename[0] != '\0')
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
- else
- mod_timer(&vport->fc_fdmitmo, jiffies +
- msecs_to_jiffies(1000 * 60));
- }
- return;
-}
-
-void
lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
{
struct lpfc_sli *psli = &phba->sli;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index b6fa257ea..7f5abb8f5 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -455,9 +455,9 @@ int
lpfc_issue_reg_vfi(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
- LPFC_MBOXQ_t *mboxq;
+ LPFC_MBOXQ_t *mboxq = NULL;
struct lpfc_nodelist *ndlp;
- struct lpfc_dmabuf *dmabuf;
+ struct lpfc_dmabuf *dmabuf = NULL;
int rc = 0;
/* move forward in case of SLI4 FC port loopback test and pt2pt mode */
@@ -471,25 +471,33 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
}
}
- dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!dmabuf) {
+ mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mboxq) {
rc = -ENOMEM;
goto fail;
}
- dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
- if (!dmabuf->virt) {
- rc = -ENOMEM;
- goto fail_free_dmabuf;
- }
- mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mboxq) {
- rc = -ENOMEM;
- goto fail_free_coherent;
+ /* Supply CSP's only if we are fabric connect or pt-to-pt connect */
+ if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) {
+ dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!dmabuf) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+ dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
+ if (!dmabuf->virt) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+ memcpy(dmabuf->virt, &phba->fc_fabparam,
+ sizeof(struct serv_parm));
}
+
vport->port_state = LPFC_FABRIC_CFG_LINK;
- memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
- lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+ if (dmabuf)
+ lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+ else
+ lpfc_reg_vfi(mboxq, vport, 0);
mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
mboxq->vport = vport;
@@ -497,17 +505,19 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
rc = -ENXIO;
- goto fail_free_mbox;
+ goto fail;
}
return 0;
-fail_free_mbox:
- mempool_free(mboxq, phba->mbox_mem_pool);
-fail_free_coherent:
- lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
-fail_free_dmabuf:
- kfree(dmabuf);
fail:
+ if (mboxq)
+ mempool_free(mboxq, phba->mbox_mem_pool);
+ if (dmabuf) {
+ if (dmabuf->virt)
+ lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+ kfree(dmabuf);
+ }
+
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0289 Issue Register VFI failed: Err %d\n", rc);
@@ -678,6 +688,21 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
sp->cmn.bbRcvSizeLsb;
fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp);
+ if (fabric_param_changed) {
+ /* Reset FDMI attribute masks based on config parameter */
+ if (phba->cfg_fdmi_on == LPFC_FDMI_NO_SUPPORT) {
+ vport->fdmi_hba_mask = 0;
+ vport->fdmi_port_mask = 0;
+ } else {
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+ else
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ }
+
+ }
memcpy(&vport->fabric_portname, &sp->portName,
sizeof(struct lpfc_name));
memcpy(&vport->fabric_nodename, &sp->nodeName,
@@ -711,9 +736,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* For FC we need to do some special processing because of the SLI
* Port's default settings of the Common Service Parameters.
*/
- if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) {
+ if ((phba->sli_rev == LPFC_SLI_REV4) &&
+ (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)) {
/* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
- if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed)
+ if (fabric_param_changed)
lpfc_unregister_fcf_prep(phba);
/* This should just update the VFI CSPs*/
@@ -824,13 +850,21 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ vport->fc_flag |= FC_PT2PT;
spin_unlock_irq(shost->host_lock);
- phba->fc_edtov = FF_DEF_EDTOV;
- phba->fc_ratov = FF_DEF_RATOV;
+ /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
+ lpfc_unregister_fcf_prep(phba);
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_VFI_REGISTERED;
+ spin_unlock_irq(shost->host_lock);
+ phba->fc_topology_changed = 0;
+ }
+
rc = memcmp(&vport->fc_portname, &sp->portName,
sizeof(vport->fc_portname));
- memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
if (rc >= 0) {
/* This side will initiate the PLOGI */
@@ -839,38 +873,14 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_unlock_irq(shost->host_lock);
/*
- * N_Port ID cannot be 0, set our to LocalID the other
- * side will be RemoteID.
+ * N_Port ID cannot be 0, set our Id to LocalID
+ * the other side will be RemoteID.
*/
/* not equal */
if (rc)
vport->fc_myDID = PT2PT_LocalID;
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
-
- lpfc_config_link(phba, mbox);
-
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto fail;
- }
-
- /*
- * For SLI4, the VFI/VPI are registered AFTER the
- * Nport with the higher WWPN sends the PLOGI with
- * an assigned NPortId.
- */
-
- /* not equal */
- if ((phba->sli_rev == LPFC_SLI_REV4) && rc)
- lpfc_issue_reg_vfi(vport);
-
/* Decrement ndlp reference count indicating that ndlp can be
* safely released when other references to it are done.
*/
@@ -912,29 +922,20 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* If we are pt2pt with another NPort, force NPIV off! */
phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
- spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_PT2PT;
- spin_unlock_irq(shost->host_lock);
- /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
- if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) {
- lpfc_unregister_fcf_prep(phba);
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
- /* The FC_VFI_REGISTERED flag will get clear in the cmpl
- * handler for unreg_vfi, but if we don't force the
- * FC_VFI_REGISTERED flag then the reg_vfi mailbox could be
- * built with the update bit set instead of just the vp bit to
- * change the Nport ID. We need to have the vp set and the
- * Upd cleared on topology changes.
- */
- spin_lock_irq(shost->host_lock);
- vport->fc_flag &= ~FC_VFI_REGISTERED;
- spin_unlock_irq(shost->host_lock);
- phba->fc_topology_changed = 0;
- lpfc_issue_reg_vfi(vport);
+ lpfc_config_link(phba, mbox);
+
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto fail;
}
- /* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(vport);
return 0;
fail:
return -ENXIO;
@@ -1157,6 +1158,7 @@ flogifail:
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
spin_unlock_irq(&phba->hbalock);
+
lpfc_nlp_put(ndlp);
if (!lpfc_error_lost_link(irsp)) {
@@ -3792,14 +3794,17 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_nlp_set_state(vport, ndlp,
NLP_STE_REG_LOGIN_ISSUE);
}
+
+ ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
!= MBX_NOT_FINISHED)
goto out;
- else
- /* Decrement the ndlp reference count we
- * set for this failed mailbox command.
- */
- lpfc_nlp_put(ndlp);
+
+ /* Decrement the ndlp reference count we
+ * set for this failed mailbox command.
+ */
+ lpfc_nlp_put(ndlp);
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
/* ELS rsp: Cannot issue reg_login for <NPortid> */
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -3856,6 +3861,7 @@ out:
* the routine lpfc_els_free_iocb.
*/
cmdiocb->context1 = NULL;
+
}
lpfc_els_free_iocb(phba, cmdiocb);
@@ -3898,6 +3904,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
IOCB_t *oldcmd;
struct lpfc_iocbq *elsiocb;
uint8_t *pcmd;
+ struct serv_parm *sp;
uint16_t cmdsize;
int rc;
ELS_PKT *els_pkt_ptr;
@@ -3927,6 +3934,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
"Issue ACC: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
+ case ELS_CMD_FLOGI:
case ELS_CMD_PLOGI:
cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
@@ -3944,10 +3952,34 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
- memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+ sp = (struct serv_parm *)pcmd;
+
+ if (flag == ELS_CMD_FLOGI) {
+ /* Copy the received service parameters back */
+ memcpy(sp, &phba->fc_fabparam,
+ sizeof(struct serv_parm));
+
+ /* Clear the F_Port bit */
+ sp->cmn.fPort = 0;
+
+ /* Mark all class service parameters as invalid */
+ sp->cls1.classValid = 0;
+ sp->cls2.classValid = 0;
+ sp->cls3.classValid = 0;
+ sp->cls4.classValid = 0;
+
+ /* Copy our worldwide names */
+ memcpy(&sp->portName, &vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ memcpy(&sp->nodeName, &vport->fc_sparam.nodeName,
+ sizeof(struct lpfc_name));
+ } else {
+ memcpy(pcmd, &vport->fc_sparam,
+ sizeof(struct serv_parm));
+ }
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
- "Issue ACC PLOGI: did:x%x flg:x%x",
+ "Issue ACC FLOGI/PLOGI: did:x%x flg:x%x",
ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
case ELS_CMD_PRLO:
@@ -4673,6 +4705,23 @@ lpfc_rdp_res_link_error(struct fc_rdp_link_error_status_desc *desc,
desc->length = cpu_to_be32(sizeof(desc->info));
}
+int
+lpfc_rdp_res_fec_desc(struct fc_fec_rdp_desc *desc, READ_LNK_VAR *stat)
+{
+ if (bf_get(lpfc_read_link_stat_gec2, stat) == 0)
+ return 0;
+ desc->tag = cpu_to_be32(RDP_FEC_DESC_TAG);
+
+ desc->info.CorrectedBlocks =
+ cpu_to_be32(stat->fecCorrBlkCount);
+ desc->info.UncorrectableBlocks =
+ cpu_to_be32(stat->fecUncorrBlkCount);
+
+ desc->length = cpu_to_be32(sizeof(desc->info));
+
+ return sizeof(struct fc_fec_rdp_desc);
+}
+
void
lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
{
@@ -4681,26 +4730,26 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba)
desc->tag = cpu_to_be32(RDP_PORT_SPEED_DESC_TAG);
- switch (phba->sli4_hba.link_state.speed) {
- case LPFC_FC_LA_SPEED_1G:
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
rdp_speed = RDP_PS_1GB;
break;
- case LPFC_FC_LA_SPEED_2G:
+ case LPFC_LINK_SPEED_2GHZ:
rdp_speed = RDP_PS_2GB;
break;
- case LPFC_FC_LA_SPEED_4G:
+ case LPFC_LINK_SPEED_4GHZ:
rdp_speed = RDP_PS_4GB;
break;
- case LPFC_FC_LA_SPEED_8G:
+ case LPFC_LINK_SPEED_8GHZ:
rdp_speed = RDP_PS_8GB;
break;
- case LPFC_FC_LA_SPEED_10G:
+ case LPFC_LINK_SPEED_10GHZ:
rdp_speed = RDP_PS_10GB;
break;
- case LPFC_FC_LA_SPEED_16G:
+ case LPFC_LINK_SPEED_16GHZ:
rdp_speed = RDP_PS_16GB;
break;
- case LPFC_FC_LA_SPEED_32G:
+ case LPFC_LINK_SPEED_32GHZ:
rdp_speed = RDP_PS_32GB;
break;
default:
@@ -4778,15 +4827,18 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
struct lpfc_nodelist *ndlp = rdp_context->ndlp;
struct lpfc_vport *vport = ndlp->vport;
struct lpfc_iocbq *elsiocb;
+ struct ulp_bde64 *bpl;
IOCB_t *icmd;
uint8_t *pcmd;
struct ls_rjt *stat;
struct fc_rdp_res_frame *rdp_res;
uint32_t cmdsize;
- int rc;
+ int rc, fec_size;
if (status != SUCCESS)
goto error;
+
+ /* This will change once we know the true size of the RDP payload */
cmdsize = sizeof(struct fc_rdp_res_frame);
elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize,
@@ -4823,10 +4875,18 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
lpfc_rdp_res_diag_port_names(&rdp_res->diag_port_names_desc, phba);
lpfc_rdp_res_attach_port_names(&rdp_res->attached_port_names_desc,
vport, ndlp);
- rdp_res->length = cpu_to_be32(RDP_DESC_PAYLOAD_SIZE);
-
+ fec_size = lpfc_rdp_res_fec_desc(&rdp_res->fec_desc,
+ &rdp_context->link_stat);
+ rdp_res->length = cpu_to_be32(fec_size + RDP_DESC_PAYLOAD_SIZE);
elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
+ /* Now that we know the true size of the payload, update the BPL */
+ bpl = (struct ulp_bde64 *)
+ (((struct lpfc_dmabuf *)(elsiocb->context3))->virt);
+ bpl->tus.f.bdeSize = (fec_size + RDP_DESC_PAYLOAD_SIZE + 8);
+ bpl->tus.f.bdeFlags = 0;
+ bpl->tus.w = le32_to_cpu(bpl->tus.w);
+
phba->fc_stat.elsXmitACC++;
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR)
@@ -4956,13 +5016,12 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
if (RDP_NPORT_ID_SIZE !=
be32_to_cpu(rdp_req->nport_id_desc.length))
goto rjt_logerr;
- rdp_context = kmalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
+ rdp_context = kzalloc(sizeof(struct lpfc_rdp_context), GFP_KERNEL);
if (!rdp_context) {
rjt_err = LSRJT_UNABLE_TPC;
goto error;
}
- memset(rdp_context, 0, sizeof(struct lpfc_rdp_context));
cmd = &cmdiocb->iocb;
rdp_context->ndlp = lpfc_nlp_get(ndlp);
rdp_context->ox_id = cmd->unsli3.rcvsli3.ox_id;
@@ -5739,7 +5798,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
IOCB_t *icmd = &cmdiocb->iocb;
struct serv_parm *sp;
LPFC_MBOXQ_t *mbox;
- struct ls_rjt stat;
uint32_t cmd, did;
int rc;
uint32_t fc_flag = 0;
@@ -5765,135 +5823,92 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 1;
}
- if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
- /* For a FLOGI we accept, then if our portname is greater
- * then the remote portname we initiate Nport login.
- */
+ (void) lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1);
- rc = memcmp(&vport->fc_portname, &sp->portName,
- sizeof(struct lpfc_name));
- if (!rc) {
- if (phba->sli_rev < LPFC_SLI_REV4) {
- mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL);
- if (!mbox)
- return 1;
- lpfc_linkdown(phba);
- lpfc_init_link(phba, mbox,
- phba->cfg_topology,
- phba->cfg_link_speed);
- mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox,
- MBX_NOWAIT);
- lpfc_set_loopback_flag(phba);
- if (rc == MBX_NOT_FINISHED)
- mempool_free(mbox, phba->mbox_mem_pool);
- return 1;
- } else {
- /* abort the flogi coming back to ourselves
- * due to external loopback on the port.
- */
- lpfc_els_abort_flogi(phba);
- return 0;
- }
- } else if (rc > 0) { /* greater than */
- spin_lock_irq(shost->host_lock);
- vport->fc_flag |= FC_PT2PT_PLOGI;
- spin_unlock_irq(shost->host_lock);
+ /*
+ * If our portname is greater than the remote portname,
+ * then we initiate Nport login.
+ */
- /* If we have the high WWPN we can assign our own
- * myDID; otherwise, we have to WAIT for a PLOGI
- * from the remote NPort to find out what it
- * will be.
- */
- vport->fc_myDID = PT2PT_LocalID;
- } else
- vport->fc_myDID = PT2PT_RemoteID;
+ rc = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(struct lpfc_name));
- /*
- * The vport state should go to LPFC_FLOGI only
- * AFTER we issue a FLOGI, not receive one.
+ if (!rc) {
+ if (phba->sli_rev < LPFC_SLI_REV4) {
+ mbox = mempool_alloc(phba->mbox_mem_pool,
+ GFP_KERNEL);
+ if (!mbox)
+ return 1;
+ lpfc_linkdown(phba);
+ lpfc_init_link(phba, mbox,
+ phba->cfg_topology,
+ phba->cfg_link_speed);
+ mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ MBX_NOWAIT);
+ lpfc_set_loopback_flag(phba);
+ if (rc == MBX_NOT_FINISHED)
+ mempool_free(mbox, phba->mbox_mem_pool);
+ return 1;
+ }
+
+ /* abort the flogi coming back to ourselves
+ * due to external loopback on the port.
*/
+ lpfc_els_abort_flogi(phba);
+ return 0;
+
+ } else if (rc > 0) { /* greater than */
spin_lock_irq(shost->host_lock);
- fc_flag = vport->fc_flag;
- port_state = vport->port_state;
- vport->fc_flag |= FC_PT2PT;
- vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ vport->fc_flag |= FC_PT2PT_PLOGI;
spin_unlock_irq(shost->host_lock);
- lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- "3311 Rcv Flogi PS x%x new PS x%x "
- "fc_flag x%x new fc_flag x%x\n",
- port_state, vport->port_state,
- fc_flag, vport->fc_flag);
- /*
- * We temporarily set fc_myDID to make it look like we are
- * a Fabric. This is done just so we end up with the right
- * did / sid on the FLOGI ACC rsp.
+ /* If we have the high WWPN we can assign our own
+ * myDID; otherwise, we have to WAIT for a PLOGI
+ * from the remote NPort to find out what it
+ * will be.
*/
- did = vport->fc_myDID;
- vport->fc_myDID = Fabric_DID;
-
+ vport->fc_myDID = PT2PT_LocalID;
} else {
- /* Reject this request because invalid parameters */
- stat.un.b.lsRjtRsvd0 = 0;
- stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
- stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
- stat.un.b.vendorUnique = 0;
-
- /*
- * We temporarily set fc_myDID to make it look like we are
- * a Fabric. This is done just so we end up with the right
- * did / sid on the FLOGI LS_RJT rsp.
- */
- did = vport->fc_myDID;
- vport->fc_myDID = Fabric_DID;
-
- lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
- NULL);
+ vport->fc_myDID = PT2PT_RemoteID;
+ }
- /* Now lets put fc_myDID back to what its supposed to be */
- vport->fc_myDID = did;
+ /*
+ * The vport state should go to LPFC_FLOGI only
+ * AFTER we issue a FLOGI, not receive one.
+ */
+ spin_lock_irq(shost->host_lock);
+ fc_flag = vport->fc_flag;
+ port_state = vport->port_state;
+ vport->fc_flag |= FC_PT2PT;
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+ "3311 Rcv Flogi PS x%x new PS x%x "
+ "fc_flag x%x new fc_flag x%x\n",
+ port_state, vport->port_state,
+ fc_flag, vport->fc_flag);
- return 1;
- }
+ /*
+ * We temporarily set fc_myDID to make it look like we are
+ * a Fabric. This is done just so we end up with the right
+ * did / sid on the FLOGI ACC rsp.
+ */
+ did = vport->fc_myDID;
+ vport->fc_myDID = Fabric_DID;
- /* send our FLOGI first */
- if (vport->port_state < LPFC_FLOGI) {
- vport->fc_myDID = 0;
- lpfc_initial_flogi(vport);
- vport->fc_myDID = Fabric_DID;
- }
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
/* Send back ACC */
- lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
+ lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, cmdiocb, ndlp, NULL);
/* Now lets put fc_myDID back to what its supposed to be */
vport->fc_myDID = did;
- if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
-
- lpfc_config_link(phba, mbox);
-
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto fail;
- }
- }
-
return 0;
-fail:
- return 1;
}
/**
@@ -7345,7 +7360,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* reject till our FLOGI completes */
if ((vport->port_state < LPFC_FABRIC_CFG_LINK) &&
- (cmd != ELS_CMD_FLOGI)) {
+ (cmd != ELS_CMD_FLOGI)) {
rjt_err = LSRJT_UNABLE_TPC;
rjt_exp = LSEXP_NOTHING_MORE;
goto lsrjt;
@@ -7381,6 +7396,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
rjt_exp = LSEXP_NOTHING_MORE;
break;
}
+
if (vport->port_state < LPFC_DISC_AUTH) {
if (!(phba->pport->fc_flag & FC_PT2PT) ||
(phba->pport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -7730,6 +7746,35 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
}
+void
+lpfc_start_fdmi(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp;
+
+ /* If this is the first time, allocate an ndlp and initialize
+ * it. Otherwise, make sure the node is enabled and then do the
+ * login.
+ */
+ ndlp = lpfc_findnode_did(vport, FDMI_DID);
+ if (!ndlp) {
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (ndlp) {
+ lpfc_nlp_init(vport, ndlp, FDMI_DID);
+ ndlp->nlp_type |= NLP_FABRIC;
+ } else {
+ return;
+ }
+ }
+ if (!NLP_CHK_NODE_ACT(ndlp))
+ ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE);
+
+ if (ndlp) {
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+ }
+}
+
/**
* lpfc_do_scr_ns_plogi - Issue a plogi to the name server for scr
* @phba: pointer to lpfc hba data structure.
@@ -7746,7 +7791,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
void
lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
{
- struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+ struct lpfc_nodelist *ndlp;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
/*
@@ -7804,32 +7849,9 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
return;
}
- if (vport->cfg_fdmi_on & LPFC_FDMI_SUPPORT) {
- /* If this is the first time, allocate an ndlp and initialize
- * it. Otherwise, make sure the node is enabled and then do the
- * login.
- */
- ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID);
- if (!ndlp_fdmi) {
- ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
- GFP_KERNEL);
- if (ndlp_fdmi) {
- lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
- ndlp_fdmi->nlp_type |= NLP_FABRIC;
- } else
- return;
- }
- if (!NLP_CHK_NODE_ACT(ndlp_fdmi))
- ndlp_fdmi = lpfc_enable_node(vport,
- ndlp_fdmi,
- NLP_STE_NPR_NODE);
-
- if (ndlp_fdmi) {
- lpfc_nlp_set_state(vport, ndlp_fdmi,
- NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0);
- }
- }
+ if ((phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) &&
+ (vport->load_flag & FC_ALLOW_FDMI))
+ lpfc_start_fdmi(vport);
}
/**
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index bfc2442dd..c37d72eff 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -674,8 +674,6 @@ lpfc_work_done(struct lpfc_hba *phba)
lpfc_mbox_timeout_handler(phba);
if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
lpfc_unblock_fabric_iocbs(phba);
- if (work_port_events & WORKER_FDMI_TMO)
- lpfc_fdmi_timeout_handler(vport);
if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
lpfc_ramp_down_queue_handler(phba);
if (work_port_events & WORKER_DELAYED_DISC_TMO)
@@ -1083,7 +1081,7 @@ out:
}
-static void
+void
lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
@@ -1113,8 +1111,10 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI)
+ if (vport->port_state != LPFC_FLOGI)
lpfc_initial_flogi(vport);
+ else if (vport->fc_flag & FC_PT2PT)
+ lpfc_disc_start(vport);
return;
out:
@@ -2963,8 +2963,10 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
out_free_mem:
mempool_free(mboxq, phba->mbox_mem_pool);
- lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
- kfree(dmabuf);
+ if (dmabuf) {
+ lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
+ kfree(dmabuf);
+ }
return;
}
@@ -3035,19 +3037,22 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
uint32_t fc_flags = 0;
spin_lock_irq(&phba->hbalock);
- switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
- case LPFC_LINK_SPEED_1GHZ:
- case LPFC_LINK_SPEED_2GHZ:
- case LPFC_LINK_SPEED_4GHZ:
- case LPFC_LINK_SPEED_8GHZ:
- case LPFC_LINK_SPEED_10GHZ:
- case LPFC_LINK_SPEED_16GHZ:
- case LPFC_LINK_SPEED_32GHZ:
- phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
- break;
- default:
- phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
- break;
+ phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
+
+ if (!(phba->hba_flag & HBA_FCOE_MODE)) {
+ switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
+ case LPFC_LINK_SPEED_1GHZ:
+ case LPFC_LINK_SPEED_2GHZ:
+ case LPFC_LINK_SPEED_4GHZ:
+ case LPFC_LINK_SPEED_8GHZ:
+ case LPFC_LINK_SPEED_10GHZ:
+ case LPFC_LINK_SPEED_16GHZ:
+ case LPFC_LINK_SPEED_32GHZ:
+ break;
+ default:
+ phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
+ break;
+ }
}
if (phba->fc_topology &&
@@ -3448,10 +3453,10 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
spin_unlock_irq(shost->host_lock);
- } else
- /* Good status, call state machine */
- lpfc_disc_state_machine(vport, ndlp, pmb,
- NLP_EVT_CMPL_REG_LOGIN);
+ }
+
+ /* Call state machine */
+ lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@@ -5550,15 +5555,15 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
ndlp->nlp_usg_map, ndlp);
/*
* Start issuing Fabric-Device Management Interface (FDMI) command to
- * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if
- * fdmi-on=2 (supporting RPA/hostnmae)
+ * 0xfffffa (FDMI well known port).
+ * DHBA -> DPRT -> RHBA -> RPA (physical port)
+ * DPRT -> RPRT (vports)
*/
-
- if (vport->cfg_fdmi_on & LPFC_FDMI_REG_DELAY)
- mod_timer(&vport->fc_fdmitmo,
- jiffies + msecs_to_jiffies(1000 * 60));
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
else
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
+
/* decrement the node reference count held for this callback
* function.
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 2cce88e96..dd20412c7 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1097,6 +1097,18 @@ struct fc_rdp_port_name_desc {
};
+struct fc_rdp_fec_info {
+ uint32_t CorrectedBlocks;
+ uint32_t UncorrectableBlocks;
+};
+
+#define RDP_FEC_DESC_TAG 0x00010005
+struct fc_fec_rdp_desc {
+ uint32_t tag;
+ uint32_t length;
+ struct fc_rdp_fec_info info;
+};
+
struct fc_rdp_link_error_status_payload_info {
struct fc_link_status link_status; /* 24 bytes */
uint32_t port_type; /* bits 31-30 only */
@@ -1196,14 +1208,15 @@ struct fc_rdp_res_frame {
struct fc_rdp_link_error_status_desc link_error_desc; /* Word 13-21 */
struct fc_rdp_port_name_desc diag_port_names_desc; /* Word 22-27 */
struct fc_rdp_port_name_desc attached_port_names_desc;/* Word 28-33 */
+ struct fc_fec_rdp_desc fec_desc; /* FC Word 34 - 37 */
};
#define RDP_DESC_PAYLOAD_SIZE (sizeof(struct fc_rdp_link_service_desc) \
- + sizeof(struct fc_rdp_sfp_desc) \
- + sizeof(struct fc_rdp_port_speed_desc) \
- + sizeof(struct fc_rdp_link_error_status_desc) \
- + (sizeof(struct fc_rdp_port_name_desc) * 2))
+ + sizeof(struct fc_rdp_sfp_desc) \
+ + sizeof(struct fc_rdp_port_speed_desc) \
+ + sizeof(struct fc_rdp_link_error_status_desc) \
+ + (sizeof(struct fc_rdp_port_name_desc) * 2))
/******** FDMI ********/
@@ -1233,31 +1246,10 @@ struct lpfc_fdmi_attr_def { /* Defined in TLV format */
/* Attribute Entry */
struct lpfc_fdmi_attr_entry {
union {
- uint32_t VendorSpecific;
- uint32_t SupportClass;
- uint32_t SupportSpeed;
- uint32_t PortSpeed;
- uint32_t MaxFrameSize;
- uint32_t MaxCTPayloadLen;
- uint32_t PortState;
- uint32_t PortId;
- struct lpfc_name NodeName;
- struct lpfc_name PortName;
- struct lpfc_name FabricName;
- uint8_t FC4Types[32];
- uint8_t Manufacturer[64];
- uint8_t SerialNumber[64];
- uint8_t Model[256];
- uint8_t ModelDescription[256];
- uint8_t HardwareVersion[256];
- uint8_t DriverVersion[256];
- uint8_t OptionROMVersion[256];
- uint8_t FirmwareVersion[256];
- uint8_t OsHostName[256];
- uint8_t NodeSymName[256];
- uint8_t OsDeviceName[256];
- uint8_t OsNameVersion[256];
- uint8_t HostName[256];
+ uint32_t AttrInt;
+ uint8_t AttrTypes[32];
+ uint8_t AttrString[256];
+ struct lpfc_name AttrWWN;
} un;
};
@@ -1327,6 +1319,8 @@ struct lpfc_fdmi_reg_portattr {
#define SLI_MGMT_DPRT 0x310 /* De-register Port */
#define SLI_MGMT_DPA 0x311 /* De-register Port attributes */
+#define LPFC_FDMI_MAX_RETRY 3 /* Max retries for a FDMI command */
+
/*
* HBA Attribute Types
*/
@@ -1342,6 +1336,39 @@ struct lpfc_fdmi_reg_portattr {
#define RHBA_OS_NAME_VERSION 0xa /* 4 to 256 byte ASCII string */
#define RHBA_MAX_CT_PAYLOAD_LEN 0xb /* 32-bit unsigned int */
#define RHBA_SYM_NODENAME 0xc /* 4 to 256 byte ASCII string */
+#define RHBA_VENDOR_INFO 0xd /* 32-bit unsigned int */
+#define RHBA_NUM_PORTS 0xe /* 32-bit unsigned int */
+#define RHBA_FABRIC_WWNN 0xf /* 8 byte WWNN */
+#define RHBA_BIOS_VERSION 0x10 /* 4 to 256 byte ASCII string */
+#define RHBA_BIOS_STATE 0x11 /* 32-bit unsigned int */
+#define RHBA_VENDOR_ID 0xe0 /* 8 byte ASCII string */
+
+/* Bit mask for all individual HBA attributes */
+#define LPFC_FDMI_HBA_ATTR_wwnn 0x00000001
+#define LPFC_FDMI_HBA_ATTR_manufacturer 0x00000002
+#define LPFC_FDMI_HBA_ATTR_sn 0x00000004
+#define LPFC_FDMI_HBA_ATTR_model 0x00000008
+#define LPFC_FDMI_HBA_ATTR_description 0x00000010
+#define LPFC_FDMI_HBA_ATTR_hdw_ver 0x00000020
+#define LPFC_FDMI_HBA_ATTR_drvr_ver 0x00000040
+#define LPFC_FDMI_HBA_ATTR_rom_ver 0x00000080
+#define LPFC_FDMI_HBA_ATTR_fmw_ver 0x00000100
+#define LPFC_FDMI_HBA_ATTR_os_ver 0x00000200
+#define LPFC_FDMI_HBA_ATTR_ct_len 0x00000400
+#define LPFC_FDMI_HBA_ATTR_symbolic_name 0x00000800
+#define LPFC_FDMI_HBA_ATTR_vendor_info 0x00001000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_num_ports 0x00002000
+#define LPFC_FDMI_HBA_ATTR_fabric_wwnn 0x00004000
+#define LPFC_FDMI_HBA_ATTR_bios_ver 0x00008000
+#define LPFC_FDMI_HBA_ATTR_bios_state 0x00010000 /* Not used */
+#define LPFC_FDMI_HBA_ATTR_vendor_id 0x00020000
+
+/* Bit mask for FDMI-1 defined HBA attributes */
+#define LPFC_FDMI1_HBA_ATTR 0x000007ff
+
+/* Bit mask for FDMI-2 defined HBA attributes */
+/* Skip vendor_info and bios_state */
+#define LPFC_FDMI2_HBA_ATTR 0x0002efff
/*
* Port Attrubute Types
@@ -1353,15 +1380,65 @@ struct lpfc_fdmi_reg_portattr {
#define RPRT_OS_DEVICE_NAME 0x5 /* 4 to 256 byte ASCII string */
#define RPRT_HOST_NAME 0x6 /* 4 to 256 byte ASCII string */
#define RPRT_NODENAME 0x7 /* 8 byte WWNN */
-#define RPRT_PORTNAME 0x8 /* 8 byte WWNN */
+#define RPRT_PORTNAME 0x8 /* 8 byte WWPN */
#define RPRT_SYM_PORTNAME 0x9 /* 4 to 256 byte ASCII string */
#define RPRT_PORT_TYPE 0xa /* 32-bit unsigned int */
#define RPRT_SUPPORTED_CLASS 0xb /* 32-bit unsigned int */
-#define RPRT_FABRICNAME 0xc /* 8 byte Fabric WWNN */
+#define RPRT_FABRICNAME 0xc /* 8 byte Fabric WWPN */
#define RPRT_ACTIVE_FC4_TYPES 0xd /* 32 byte binary array */
#define RPRT_PORT_STATE 0x101 /* 32-bit unsigned int */
#define RPRT_DISC_PORT 0x102 /* 32-bit unsigned int */
#define RPRT_PORT_ID 0x103 /* 32-bit unsigned int */
+#define RPRT_SMART_SERVICE 0xf100 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_GUID 0xf101 /* 8 byte WWNN + 8 byte WWPN */
+#define RPRT_SMART_VERSION 0xf102 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_MODEL 0xf103 /* 4 to 256 byte ASCII string */
+#define RPRT_SMART_PORT_INFO 0xf104 /* 32-bit unsigned int */
+#define RPRT_SMART_QOS 0xf105 /* 32-bit unsigned int */
+#define RPRT_SMART_SECURITY 0xf106 /* 32-bit unsigned int */
+
+/* Bit mask for all individual PORT attributes */
+#define LPFC_FDMI_PORT_ATTR_fc4type 0x00000001
+#define LPFC_FDMI_PORT_ATTR_support_speed 0x00000002
+#define LPFC_FDMI_PORT_ATTR_speed 0x00000004
+#define LPFC_FDMI_PORT_ATTR_max_frame 0x00000008
+#define LPFC_FDMI_PORT_ATTR_os_devname 0x00000010
+#define LPFC_FDMI_PORT_ATTR_host_name 0x00000020
+#define LPFC_FDMI_PORT_ATTR_wwnn 0x00000040
+#define LPFC_FDMI_PORT_ATTR_wwpn 0x00000080
+#define LPFC_FDMI_PORT_ATTR_symbolic_name 0x00000100
+#define LPFC_FDMI_PORT_ATTR_port_type 0x00000200
+#define LPFC_FDMI_PORT_ATTR_class 0x00000400
+#define LPFC_FDMI_PORT_ATTR_fabric_wwpn 0x00000800
+#define LPFC_FDMI_PORT_ATTR_port_state 0x00001000
+#define LPFC_FDMI_PORT_ATTR_active_fc4type 0x00002000
+#define LPFC_FDMI_PORT_ATTR_num_disc 0x00004000
+#define LPFC_FDMI_PORT_ATTR_nportid 0x00008000
+#define LPFC_FDMI_SMART_ATTR_service 0x00010000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_guid 0x00020000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_version 0x00040000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_model 0x00080000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_port_info 0x00100000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_qos 0x00200000 /* Vendor specific */
+#define LPFC_FDMI_SMART_ATTR_security 0x00400000 /* Vendor specific */
+
+/* Bit mask for FDMI-1 defined PORT attributes */
+#define LPFC_FDMI1_PORT_ATTR 0x0000003f
+
+/* Bit mask for FDMI-2 defined PORT attributes */
+#define LPFC_FDMI2_PORT_ATTR 0x0000ffff
+
+/* Bit mask for Smart SAN defined PORT attributes */
+#define LPFC_FDMI2_SMART_ATTR 0x007fffff
+
+/* Defines for PORT port state attribute */
+#define LPFC_FDMI_PORTSTATE_UNKNOWN 1
+#define LPFC_FDMI_PORTSTATE_ONLINE 2
+
+/* Defines for PORT port type attribute */
+#define LPFC_FDMI_PORTTYPE_UNKNOWN 0
+#define LPFC_FDMI_PORTTYPE_NPORT 1
+#define LPFC_FDMI_PORTTYPE_NLPORT 2
/*
* Begin HBA configuration parameters.
@@ -2498,10 +2575,38 @@ typedef struct {
/* Structure for MB Command READ_LINK_STAT (18) */
typedef struct {
- uint32_t rsvd1;
+ uint32_t word0;
+
+#define lpfc_read_link_stat_rec_SHIFT 0
+#define lpfc_read_link_stat_rec_MASK 0x1
+#define lpfc_read_link_stat_rec_WORD word0
+
+#define lpfc_read_link_stat_gec_SHIFT 1
+#define lpfc_read_link_stat_gec_MASK 0x1
+#define lpfc_read_link_stat_gec_WORD word0
+
+#define lpfc_read_link_stat_w02oftow23of_SHIFT 2
+#define lpfc_read_link_stat_w02oftow23of_MASK 0x3FFFFF
+#define lpfc_read_link_stat_w02oftow23of_WORD word0
+
+#define lpfc_read_link_stat_rsvd_SHIFT 24
+#define lpfc_read_link_stat_rsvd_MASK 0x1F
+#define lpfc_read_link_stat_rsvd_WORD word0
+
+#define lpfc_read_link_stat_gec2_SHIFT 29
+#define lpfc_read_link_stat_gec2_MASK 0x1
+#define lpfc_read_link_stat_gec2_WORD word0
+
+#define lpfc_read_link_stat_clrc_SHIFT 30
+#define lpfc_read_link_stat_clrc_MASK 0x1
+#define lpfc_read_link_stat_clrc_WORD word0
+
+#define lpfc_read_link_stat_clof_SHIFT 31
+#define lpfc_read_link_stat_clof_MASK 0x1
+#define lpfc_read_link_stat_clof_WORD word0
+
uint32_t linkFailureCnt;
uint32_t lossSyncCnt;
-
uint32_t lossSignalCnt;
uint32_t primSeqErrCnt;
uint32_t invalidXmitWord;
@@ -2509,6 +2614,19 @@ typedef struct {
uint32_t primSeqTimeout;
uint32_t elasticOverrun;
uint32_t arbTimeout;
+ uint32_t advRecBufCredit;
+ uint32_t curRecBufCredit;
+ uint32_t advTransBufCredit;
+ uint32_t curTransBufCredit;
+ uint32_t recEofCount;
+ uint32_t recEofdtiCount;
+ uint32_t recEofniCount;
+ uint32_t recSofcount;
+ uint32_t rsvd1;
+ uint32_t rsvd2;
+ uint32_t recDrpXriCount;
+ uint32_t fecCorrBlkCount;
+ uint32_t fecUncorrBlkCount;
} READ_LNK_VAR;
/* Structure for MB Command REG_LOGIN (19) */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 33ec4fa39..608f9415f 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -3317,6 +3317,7 @@ struct lpfc_acqe_link {
#define LPFC_ASYNC_LINK_SPEED_20GBPS 0x5
#define LPFC_ASYNC_LINK_SPEED_25GBPS 0x6
#define LPFC_ASYNC_LINK_SPEED_40GBPS 0x7
+#define LPFC_ASYNC_LINK_SPEED_100GBPS 0x8
#define lpfc_acqe_link_duplex_SHIFT 16
#define lpfc_acqe_link_duplex_MASK 0x000000FF
#define lpfc_acqe_link_duplex_WORD word0
@@ -3447,23 +3448,50 @@ struct lpfc_acqe_fc_la {
struct lpfc_acqe_misconfigured_event {
struct {
uint32_t word0;
-#define lpfc_sli_misconfigured_port0_SHIFT 0
-#define lpfc_sli_misconfigured_port0_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port0_WORD word0
-#define lpfc_sli_misconfigured_port1_SHIFT 8
-#define lpfc_sli_misconfigured_port1_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port1_WORD word0
-#define lpfc_sli_misconfigured_port2_SHIFT 16
-#define lpfc_sli_misconfigured_port2_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port2_WORD word0
-#define lpfc_sli_misconfigured_port3_SHIFT 24
-#define lpfc_sli_misconfigured_port3_MASK 0x000000FF
-#define lpfc_sli_misconfigured_port3_WORD word0
+#define lpfc_sli_misconfigured_port0_state_SHIFT 0
+#define lpfc_sli_misconfigured_port0_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port0_state_WORD word0
+#define lpfc_sli_misconfigured_port1_state_SHIFT 8
+#define lpfc_sli_misconfigured_port1_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port1_state_WORD word0
+#define lpfc_sli_misconfigured_port2_state_SHIFT 16
+#define lpfc_sli_misconfigured_port2_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port2_state_WORD word0
+#define lpfc_sli_misconfigured_port3_state_SHIFT 24
+#define lpfc_sli_misconfigured_port3_state_MASK 0x000000FF
+#define lpfc_sli_misconfigured_port3_state_WORD word0
+ uint32_t word1;
+#define lpfc_sli_misconfigured_port0_op_SHIFT 0
+#define lpfc_sli_misconfigured_port0_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port0_op_WORD word1
+#define lpfc_sli_misconfigured_port0_severity_SHIFT 1
+#define lpfc_sli_misconfigured_port0_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port0_severity_WORD word1
+#define lpfc_sli_misconfigured_port1_op_SHIFT 8
+#define lpfc_sli_misconfigured_port1_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port1_op_WORD word1
+#define lpfc_sli_misconfigured_port1_severity_SHIFT 9
+#define lpfc_sli_misconfigured_port1_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port1_severity_WORD word1
+#define lpfc_sli_misconfigured_port2_op_SHIFT 16
+#define lpfc_sli_misconfigured_port2_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port2_op_WORD word1
+#define lpfc_sli_misconfigured_port2_severity_SHIFT 17
+#define lpfc_sli_misconfigured_port2_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port2_severity_WORD word1
+#define lpfc_sli_misconfigured_port3_op_SHIFT 24
+#define lpfc_sli_misconfigured_port3_op_MASK 0x00000001
+#define lpfc_sli_misconfigured_port3_op_WORD word1
+#define lpfc_sli_misconfigured_port3_severity_SHIFT 25
+#define lpfc_sli_misconfigured_port3_severity_MASK 0x00000003
+#define lpfc_sli_misconfigured_port3_severity_WORD word1
} theEvent;
#define LPFC_SLI_EVENT_STATUS_VALID 0x00
#define LPFC_SLI_EVENT_STATUS_NOT_PRESENT 0x01
#define LPFC_SLI_EVENT_STATUS_WRONG_TYPE 0x02
#define LPFC_SLI_EVENT_STATUS_UNSUPPORTED 0x03
+#define LPFC_SLI_EVENT_STATUS_UNQUALIFIED 0x04
+#define LPFC_SLI_EVENT_STATUS_UNCERTIFIED 0x05
};
struct lpfc_acqe_sli {
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index dbb8e1bbd..0b08d5e41 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1184,8 +1184,10 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
- for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
lpfc_rcv_seq_check_edtov(vports[i]);
+ lpfc_fdmi_num_disc_check(vports[i]);
+ }
lpfc_destroy_vport_work_array(phba, vports);
if ((phba->link_state == LPFC_HBA_ERROR) ||
@@ -1290,6 +1292,10 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
jiffies +
msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT));
}
+ } else {
+ mod_timer(&phba->hb_tmofunc,
+ jiffies +
+ msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
}
}
@@ -2621,7 +2627,6 @@ void
lpfc_stop_vport_timers(struct lpfc_vport *vport)
{
del_timer_sync(&vport->els_tmofunc);
- del_timer_sync(&vport->fc_fdmitmo);
del_timer_sync(&vport->delayed_disc_tmo);
lpfc_can_disctmo(vport);
return;
@@ -3340,10 +3345,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
vport->fc_disctmo.function = lpfc_disc_timeout;
vport->fc_disctmo.data = (unsigned long)vport;
- init_timer(&vport->fc_fdmitmo);
- vport->fc_fdmitmo.function = lpfc_fdmi_tmo;
- vport->fc_fdmitmo.data = (unsigned long)vport;
-
init_timer(&vport->els_tmofunc);
vport->els_tmofunc.function = lpfc_els_timeout;
vport->els_tmofunc.data = (unsigned long)vport;
@@ -3709,49 +3710,6 @@ lpfc_sli4_parse_latt_type(struct lpfc_hba *phba,
}
/**
- * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed
- * @phba: pointer to lpfc hba data structure.
- * @acqe_link: pointer to the async link completion queue entry.
- *
- * This routine is to parse the SLI4 link-attention link speed and translate
- * it into the base driver's link-attention link speed coding.
- *
- * Return: Link-attention link speed in terms of base driver's coding.
- **/
-static uint8_t
-lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba,
- struct lpfc_acqe_link *acqe_link)
-{
- uint8_t link_speed;
-
- switch (bf_get(lpfc_acqe_link_speed, acqe_link)) {
- case LPFC_ASYNC_LINK_SPEED_ZERO:
- case LPFC_ASYNC_LINK_SPEED_10MBPS:
- case LPFC_ASYNC_LINK_SPEED_100MBPS:
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- case LPFC_ASYNC_LINK_SPEED_1GBPS:
- link_speed = LPFC_LINK_SPEED_1GHZ;
- break;
- case LPFC_ASYNC_LINK_SPEED_10GBPS:
- link_speed = LPFC_LINK_SPEED_10GHZ;
- break;
- case LPFC_ASYNC_LINK_SPEED_20GBPS:
- case LPFC_ASYNC_LINK_SPEED_25GBPS:
- case LPFC_ASYNC_LINK_SPEED_40GBPS:
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- default:
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0483 Invalid link-attention link speed: x%x\n",
- bf_get(lpfc_acqe_link_speed, acqe_link));
- link_speed = LPFC_LINK_SPEED_UNKNOWN;
- break;
- }
- return link_speed;
-}
-
-/**
* lpfc_sli_port_speed_get - Get sli3 link speed code to link speed
* @phba: pointer to lpfc hba data structure.
*
@@ -3767,27 +3725,35 @@ lpfc_sli_port_speed_get(struct lpfc_hba *phba)
if (!lpfc_is_link_up(phba))
return 0;
- switch (phba->fc_linkspeed) {
- case LPFC_LINK_SPEED_1GHZ:
- link_speed = 1000;
- break;
- case LPFC_LINK_SPEED_2GHZ:
- link_speed = 2000;
- break;
- case LPFC_LINK_SPEED_4GHZ:
- link_speed = 4000;
- break;
- case LPFC_LINK_SPEED_8GHZ:
- link_speed = 8000;
- break;
- case LPFC_LINK_SPEED_10GHZ:
- link_speed = 10000;
- break;
- case LPFC_LINK_SPEED_16GHZ:
- link_speed = 16000;
- break;
- default:
- link_speed = 0;
+ if (phba->sli_rev <= LPFC_SLI_REV3) {
+ switch (phba->fc_linkspeed) {
+ case LPFC_LINK_SPEED_1GHZ:
+ link_speed = 1000;
+ break;
+ case LPFC_LINK_SPEED_2GHZ:
+ link_speed = 2000;
+ break;
+ case LPFC_LINK_SPEED_4GHZ:
+ link_speed = 4000;
+ break;
+ case LPFC_LINK_SPEED_8GHZ:
+ link_speed = 8000;
+ break;
+ case LPFC_LINK_SPEED_10GHZ:
+ link_speed = 10000;
+ break;
+ case LPFC_LINK_SPEED_16GHZ:
+ link_speed = 16000;
+ break;
+ default:
+ link_speed = 0;
+ }
+ } else {
+ if (phba->sli4_hba.link_state.logical_speed)
+ link_speed =
+ phba->sli4_hba.link_state.logical_speed;
+ else
+ link_speed = phba->sli4_hba.link_state.speed;
}
return link_speed;
}
@@ -3983,7 +3949,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
la->eventTag = acqe_link->event_tag;
bf_set(lpfc_mbx_read_top_att_type, la, att_type);
bf_set(lpfc_mbx_read_top_link_spd, la,
- lpfc_sli4_parse_latt_link_speed(phba, acqe_link));
+ (bf_get(lpfc_acqe_link_speed, acqe_link)));
/* Fake the the following irrelvant fields */
bf_set(lpfc_mbx_read_top_topology, la, LPFC_TOPOLOGY_PT_PT);
@@ -4113,22 +4079,18 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
char message[128];
uint8_t status;
uint8_t evt_type;
+ uint8_t operational = 0;
struct temp_event temp_event_data;
struct lpfc_acqe_misconfigured_event *misconfigured;
struct Scsi_Host *shost;
evt_type = bf_get(lpfc_trailer_type, acqe_sli);
- /* Special case Lancer */
- if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
- LPFC_SLI_INTF_IF_TYPE_2) {
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "2901 Async SLI event - Event Data1:x%08x Event Data2:"
- "x%08x SLI Event Type:%d\n",
- acqe_sli->event_data1, acqe_sli->event_data2,
- evt_type);
- return;
- }
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2901 Async SLI event - Event Data1:x%08x Event Data2:"
+ "x%08x SLI Event Type:%d\n",
+ acqe_sli->event_data1, acqe_sli->event_data2,
+ evt_type);
port_name = phba->Port[0];
if (port_name == 0x00)
@@ -4174,29 +4136,46 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
/* fetch the status for this port */
switch (phba->sli4_hba.lnk_info.lnk_no) {
case LPFC_LINK_NUMBER_0:
- status = bf_get(lpfc_sli_misconfigured_port0,
+ status = bf_get(lpfc_sli_misconfigured_port0_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port0_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_1:
- status = bf_get(lpfc_sli_misconfigured_port1,
+ status = bf_get(lpfc_sli_misconfigured_port1_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port1_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_2:
- status = bf_get(lpfc_sli_misconfigured_port2,
+ status = bf_get(lpfc_sli_misconfigured_port2_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port2_op,
&misconfigured->theEvent);
break;
case LPFC_LINK_NUMBER_3:
- status = bf_get(lpfc_sli_misconfigured_port3,
+ status = bf_get(lpfc_sli_misconfigured_port3_state,
+ &misconfigured->theEvent);
+ operational = bf_get(lpfc_sli_misconfigured_port3_op,
&misconfigured->theEvent);
break;
default:
- status = ~LPFC_SLI_EVENT_STATUS_VALID;
- break;
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "3296 "
+ "LPFC_SLI_EVENT_TYPE_MISCONFIGURED "
+ "event: Invalid link %d",
+ phba->sli4_hba.lnk_info.lnk_no);
+ return;
}
+ /* Skip if optic state unchanged */
+ if (phba->sli4_hba.lnk_info.optic_state == status)
+ return;
+
switch (status) {
case LPFC_SLI_EVENT_STATUS_VALID:
- return; /* no message if the sfp is okay */
+ sprintf(message, "Physical Link is functional");
+ break;
case LPFC_SLI_EVENT_STATUS_NOT_PRESENT:
sprintf(message, "Optics faulted/incorrectly "
"installed/not installed - Reseat optics, "
@@ -4211,15 +4190,26 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
sprintf(message, "Incompatible optics - Replace with "
"compatible optics for card to function.");
break;
+ case LPFC_SLI_EVENT_STATUS_UNQUALIFIED:
+ sprintf(message, "Unqualified optics - Replace with "
+ "Avago optics for Warranty and Technical "
+ "Support - Link is%s operational",
+ (operational) ? "" : " not");
+ break;
+ case LPFC_SLI_EVENT_STATUS_UNCERTIFIED:
+ sprintf(message, "Uncertified optics - Replace with "
+ "Avago-certified optics to enable link "
+ "operation - Link is%s operational",
+ (operational) ? "" : " not");
+ break;
default:
/* firmware is reporting a status we don't know about */
sprintf(message, "Unknown event status x%02x", status);
break;
}
-
+ phba->sli4_hba.lnk_info.optic_state = status;
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "3176 Misconfigured Physical Port - "
- "Port Name %c %s\n", port_name, message);
+ "3176 Port Name %c %s\n", port_name, message);
break;
case LPFC_SLI_EVENT_TYPE_REMOTE_DPORT:
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -5293,6 +5283,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list);
INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list);
+ /* initialize optic_state to 0xFF */
+ phba->sli4_hba.lnk_info.optic_state = 0xff;
+
/* Initialize the driver internal SLI layer lists. */
lpfc_sli_setup(phba);
lpfc_sli_queue_setup(phba);
@@ -6159,6 +6152,20 @@ lpfc_create_shost(struct lpfc_hba *phba)
/* Put reference to SCSI host to driver's device private data */
pci_set_drvdata(phba->pcidev, shost);
+ /*
+ * At this point we are fully registered with PSA. In addition,
+ * any initial discovery should be completed.
+ */
+ vport->load_flag |= FC_ALLOW_FDMI;
+ if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+ if (phba->cfg_fdmi_on == LPFC_FDMI_SMART_SAN)
+ vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+ else
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ }
return 0;
}
@@ -8833,9 +8840,12 @@ found:
* already mapped to this phys_id.
*/
if (cpup->irq != LPFC_VECTOR_MAP_EMPTY) {
- chann[saved_chann] =
- cpup->channel_id;
- saved_chann++;
+ if (saved_chann <=
+ LPFC_FCP_IO_CHAN_MAX) {
+ chann[saved_chann] =
+ cpup->channel_id;
+ saved_chann++;
+ }
goto out;
}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 3fa65338d..4fb3581d4 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -231,15 +231,13 @@ lpfc_mem_free(struct lpfc_hba *phba)
if (phba->lpfc_hbq_pool)
pci_pool_destroy(phba->lpfc_hbq_pool);
phba->lpfc_hbq_pool = NULL;
-
- if (phba->rrq_pool)
- mempool_destroy(phba->rrq_pool);
+ mempool_destroy(phba->rrq_pool);
phba->rrq_pool = NULL;
/* Free NLP memory pool */
mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL;
- if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) {
+ if (phba->sli_rev == LPFC_SLI_REV4) {
mempool_destroy(phba->active_rrq_pool);
phba->active_rrq_pool = NULL;
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index ed9a2c80c..193733e8c 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -280,38 +280,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t *lp;
IOCB_t *icmd;
struct serv_parm *sp;
+ uint32_t ed_tov;
LPFC_MBOXQ_t *mbox;
struct ls_rjt stat;
int rc;
memset(&stat, 0, sizeof (struct ls_rjt));
- if (vport->port_state <= LPFC_FDISC) {
- /* Before responding to PLOGI, check for pt2pt mode.
- * If we are pt2pt, with an outstanding FLOGI, abort
- * the FLOGI and resend it first.
- */
- if (vport->fc_flag & FC_PT2PT) {
- lpfc_els_abort_flogi(phba);
- if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
- /* If the other side is supposed to initiate
- * the PLOGI anyway, just ACC it now and
- * move on with discovery.
- */
- phba->fc_edtov = FF_DEF_EDTOV;
- phba->fc_ratov = FF_DEF_RATOV;
- /* Start discovery - this should just do
- CLEAR_LA */
- lpfc_disc_start(vport);
- } else
- lpfc_initial_flogi(vport);
- } else {
- stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
- stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
- ndlp, NULL);
- return 0;
- }
- }
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
@@ -404,30 +378,46 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Check for Nport to NPort pt2pt protocol */
if ((vport->fc_flag & FC_PT2PT) &&
!(vport->fc_flag & FC_PT2PT_PLOGI)) {
-
/* rcv'ed PLOGI decides what our NPortId will be */
vport->fc_myDID = icmd->un.rcvels.parmRo;
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (mbox == NULL)
- goto out;
- lpfc_config_link(phba, mbox);
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->vport = vport;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- goto out;
+
+ ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+ if (sp->cmn.edtovResolution) {
+ /* E_D_TOV ticks are in nanoseconds */
+ ed_tov = (phba->fc_edtov + 999999) / 1000000;
}
+
/*
- * For SLI4, the VFI/VPI are registered AFTER the
- * Nport with the higher WWPN sends us a PLOGI with
- * our assigned NPortId.
+ * For pt-to-pt, use the larger EDTOV
+ * RATOV = 2 * EDTOV
*/
+ if (ed_tov > phba->fc_edtov)
+ phba->fc_edtov = ed_tov;
+ phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+ /* Issue config_link / reg_vfi to account for updated TOV's */
+
if (phba->sli_rev == LPFC_SLI_REV4)
lpfc_issue_reg_vfi(vport);
+ else {
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox == NULL)
+ goto out;
+ lpfc_config_link(phba, mbox);
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto out;
+ }
+ }
lpfc_can_disctmo(vport);
}
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
goto out;
@@ -1038,7 +1028,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
uint32_t *lp;
IOCB_t *irsp;
struct serv_parm *sp;
+ uint32_t ed_tov;
LPFC_MBOXQ_t *mbox;
+ int rc;
cmdiocb = (struct lpfc_iocbq *) arg;
rspiocb = cmdiocb->context_un.rsp_iocb;
@@ -1094,18 +1086,63 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
ndlp->nlp_maxframe =
((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
+ if ((vport->fc_flag & FC_PT2PT) &&
+ (vport->fc_flag & FC_PT2PT_PLOGI)) {
+ ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
+ if (sp->cmn.edtovResolution) {
+ /* E_D_TOV ticks are in nanoseconds */
+ ed_tov = (phba->fc_edtov + 999999) / 1000000;
+ }
+
+ /*
+ * Use the larger EDTOV
+ * RATOV = 2 * EDTOV for pt-to-pt
+ */
+ if (ed_tov > phba->fc_edtov)
+ phba->fc_edtov = ed_tov;
+ phba->fc_ratov = (2 * phba->fc_edtov) / 1000;
+
+ memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
+
+ /* Issue config_link / reg_vfi to account for updated TOV's */
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ lpfc_issue_reg_vfi(vport);
+ } else {
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0133 PLOGI: no memory "
+ "for config_link "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
+ goto out;
+ }
+
+ lpfc_config_link(phba, mbox);
+
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ goto out;
+ }
+ }
+ }
+
+ lpfc_unreg_rpi(vport, ndlp);
+
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0133 PLOGI: no memory for reg_login "
- "Data: x%x x%x x%x x%x\n",
- ndlp->nlp_DID, ndlp->nlp_state,
- ndlp->nlp_flag, ndlp->nlp_rpi);
+ "0018 PLOGI: no memory for reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
goto out;
}
- lpfc_unreg_rpi(vport, ndlp);
-
if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
(uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
switch (ndlp->nlp_DID) {
@@ -2299,6 +2336,9 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
if (vport->phba->sli_rev < LPFC_SLI_REV4)
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_flag |= NLP_RPI_REGISTERED;
+ if (ndlp->nlp_flag & NLP_LOGO_ACC) {
+ lpfc_unreg_rpi(vport, ndlp);
+ }
} else {
if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
lpfc_drop_node(vport, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 4679ed444..152b3c8a5 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -3676,6 +3676,7 @@ static void
lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
struct lpfc_iocbq *rsp_iocb)
{
+ struct lpfc_hba *phba = vport->phba;
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
@@ -3685,6 +3686,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
uint32_t *lp;
uint32_t host_status = DID_OK;
uint32_t rsplen = 0;
+ uint32_t fcpDl;
uint32_t logit = LOG_FCP | LOG_FCP_ERROR;
@@ -3755,13 +3757,14 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
fcprsp->rspInfo3);
scsi_set_resid(cmnd, 0);
+ fcpDl = be32_to_cpu(fcpcmd->fcpDl);
if (resp_info & RESID_UNDER) {
scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER,
"9025 FCP Read Underrun, expected %d, "
"residual %d Data: x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
+ fcpDl,
scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
cmnd->underflow);
@@ -3777,7 +3780,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
LOG_FCP | LOG_FCP_ERROR,
"9026 FCP Read Check Error "
"and Underrun Data: x%x x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
+ fcpDl,
scsi_get_resid(cmnd), fcpi_parm,
cmnd->cmnd[0]);
scsi_set_resid(cmnd, scsi_bufflen(cmnd));
@@ -3812,13 +3815,25 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
* Check SLI validation that all the transfer was actually done
* (fcpi_parm should be zero). Apply check only to reads.
*/
- } else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
+ } else if (fcpi_parm) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
- "9029 FCP Read Check Error Data: "
+ "9029 FCP %s Check Error xri x%x Data: "
"x%x x%x x%x x%x x%x\n",
- be32_to_cpu(fcpcmd->fcpDl),
- be32_to_cpu(fcprsp->rspResId),
+ ((cmnd->sc_data_direction == DMA_FROM_DEVICE) ?
+ "Read" : "Write"),
+ ((phba->sli_rev == LPFC_SLI_REV4) ?
+ lpfc_cmd->cur_iocbq.sli4_xritag :
+ rsp_iocb->iocb.ulpContext),
+ fcpDl, be32_to_cpu(fcprsp->rspResId),
fcpi_parm, cmnd->cmnd[0], scsi_status);
+
+ /* There is some issue with the LPe12000 that causes it
+ * to miscalculate the fcpi_parm and falsely trip this
+ * recovery logic. Detect this case and don't error when true.
+ */
+ if (fcpi_parm > fcpDl)
+ goto out;
+
switch (scsi_status) {
case SAM_STAT_GOOD:
case SAM_STAT_CHECK_CONDITION:
@@ -3908,9 +3923,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
uint32_t logit = LOG_FCP;
/* Sanity check on return of outstanding command */
- if (!(lpfc_cmd->pCmd))
- return;
cmd = lpfc_cmd->pCmd;
+ if (!cmd)
+ return;
shost = cmd->device->host;
lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK);
@@ -4446,15 +4461,7 @@ lpfc_info(struct Scsi_Host *host)
phba->Port);
}
len = strlen(lpfcinfobuf);
- if (phba->sli_rev <= LPFC_SLI_REV3) {
- link_speed = lpfc_sli_port_speed_get(phba);
- } else {
- if (phba->sli4_hba.link_state.logical_speed)
- link_speed =
- phba->sli4_hba.link_state.logical_speed;
- else
- link_speed = phba->sli4_hba.link_state.speed;
- }
+ link_speed = lpfc_sli_port_speed_get(phba);
if (link_speed != 0)
snprintf(lpfcinfobuf + len, 384-len,
" Logical Link Speed: %d Mbps", link_speed);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index f9585cdd8..92dfd6a51 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -14842,10 +14842,12 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
struct lpfc_dmabuf *h_buf;
struct hbq_dmabuf *seq_dmabuf = NULL;
struct hbq_dmabuf *temp_dmabuf = NULL;
+ uint8_t found = 0;
INIT_LIST_HEAD(&dmabuf->dbuf.list);
dmabuf->time_stamp = jiffies;
new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt;
+
/* Use the hdr_buf to find the sequence that this frame belongs to */
list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) {
temp_hdr = (struct fc_frame_header *)h_buf->virt;
@@ -14885,7 +14887,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
return seq_dmabuf;
}
/* find the correct place in the sequence to insert this frame */
- list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) {
+ d_buf = list_entry(seq_dmabuf->dbuf.list.prev, typeof(*d_buf), list);
+ while (!found) {
temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt;
/*
@@ -14895,9 +14898,17 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf)
if (be16_to_cpu(new_hdr->fh_seq_cnt) >
be16_to_cpu(temp_hdr->fh_seq_cnt)) {
list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list);
- return seq_dmabuf;
+ found = 1;
+ break;
}
+
+ if (&d_buf->list == &seq_dmabuf->dbuf.list)
+ break;
+ d_buf = list_entry(d_buf->list.prev, typeof(*d_buf), list);
}
+
+ if (found)
+ return seq_dmabuf;
return NULL;
}
@@ -16173,7 +16184,7 @@ fail_fcf_read:
}
/**
- * lpfc_check_next_fcf_pri
+ * lpfc_check_next_fcf_pri_level
* phba pointer to the lpfc_hba struct for this port.
* This routine is called from the lpfc_sli4_fcf_rr_next_index_get
* routine when the rr_bmask is empty. The FCF indecies are put into the
@@ -16329,8 +16340,12 @@ next_priority:
if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX &&
phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag &
- LPFC_FCF_FLOGI_FAILED)
+ LPFC_FCF_FLOGI_FAILED) {
+ if (list_is_singular(&phba->fcf.fcf_pri_list))
+ return LPFC_FCOE_FCF_NEXT_NONE;
+
goto next_priority;
+ }
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"2845 Get next roundrobin failover FCF (x%x)\n",
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 1e916e16c..cd780c294 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -442,6 +442,7 @@ struct lpfc_sli4_lnk_info {
#define LPFC_LNK_GE 0x0 /* FCoE */
#define LPFC_LNK_FC 0x1 /* FC */
uint8_t lnk_no;
+ uint8_t optic_state;
};
#define LPFC_SLI4_HANDLER_CNT (LPFC_FCP_IO_CHAN_MAX+ \
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index ea53aa664..4dc22562a 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "11.0.0.0."
+#define LPFC_DRIVER_VERSION "11.0.0.10."
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 769012663..b3f85def1 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -393,6 +393,14 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
*(struct lpfc_vport **)fc_vport->dd_data = vport;
vport->fc_vport = fc_vport;
+ /* At this point we are fully registered with SCSI Layer. */
+ vport->load_flag |= FC_ALLOW_FDMI;
+ if (phba->cfg_fdmi_on > LPFC_FDMI_NO_SUPPORT) {
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = phba->pport->fdmi_hba_mask;
+ vport->fdmi_port_mask = phba->pport->fdmi_port_mask;
+ }
+
/*
* In SLI4, the vpi must be activated before it can be used
* by the port.
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index d64a769b8..bb2381314 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -12,7 +12,6 @@
*/
#include <linux/types.h>
-#include <linux/delay.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
@@ -32,14 +31,13 @@
#define PSEUDO_DMA
#define NCR5380_implementation_fields unsigned char *pdma_base
-#define NCR5380_local_declare() struct Scsi_Host *_instance
-#define NCR5380_setup(instance) _instance = instance
-#define NCR5380_read(reg) macscsi_read(_instance, reg)
-#define NCR5380_write(reg, value) macscsi_write(_instance, reg, value)
+#define NCR5380_read(reg) macscsi_read(instance, reg)
+#define NCR5380_write(reg, value) macscsi_write(instance, reg, value)
#define NCR5380_pread macscsi_pread
#define NCR5380_pwrite macscsi_pwrite
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_intr macscsi_intr
#define NCR5380_queue_command macscsi_queue_command
@@ -51,8 +49,6 @@
#include "NCR5380.h"
-#define RESET_BOOT
-
static int setup_can_queue = -1;
module_param(setup_can_queue, int, 0);
static int setup_cmd_per_lun = -1;
@@ -65,17 +61,8 @@ static int setup_use_tagged_queuing = -1;
module_param(setup_use_tagged_queuing, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-
-/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
- * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
- * need ten times the standard value... */
-#define TOSHIBA_DELAY
-
-#ifdef TOSHIBA_DELAY
-#define AFTER_RESET_DELAY (5*HZ/2)
-#else
-#define AFTER_RESET_DELAY (HZ/2)
-#endif
+static int setup_toshiba_delay = -1;
+module_param(setup_toshiba_delay, int, 0);
/*
* NCR 5380 register access functions
@@ -94,12 +81,12 @@ static inline void macscsi_write(struct Scsi_Host *instance, int reg, int value)
#ifndef MODULE
static int __init mac_scsi_setup(char *str)
{
- int ints[7];
+ int ints[8];
(void)get_options(str, ARRAY_SIZE(ints), ints);
- if (ints[0] < 1 || ints[0] > 6) {
- pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>]]]]]\n");
+ if (ints[0] < 1) {
+ pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>[,<toshiba_delay>]]]]]]\n");
return 0;
}
if (ints[0] >= 1)
@@ -114,50 +101,14 @@ static int __init mac_scsi_setup(char *str)
setup_use_tagged_queuing = ints[5];
if (ints[0] >= 6)
setup_use_pdma = ints[6];
+ if (ints[0] >= 7)
+ setup_toshiba_delay = ints[7];
return 1;
}
__setup("mac5380=", mac_scsi_setup);
#endif /* !MODULE */
-#ifdef RESET_BOOT
-/*
- * Our 'bus reset on boot' function
- */
-
-static void mac_scsi_reset_boot(struct Scsi_Host *instance)
-{
- unsigned long end;
-
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
- /*
- * Do a SCSI reset to clean up the bus during initialization. No messing
- * with the queues, interrupts, or locks necessary here.
- */
-
- printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
-
- /* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
-
- /* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
- /* The min. reset hold time is 25us, so 40us should be enough */
- udelay( 50 );
- /* reset RST and interrupt */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
- for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
- barrier();
-
- printk(KERN_INFO " done\n" );
-}
-#endif
-
#ifdef PSEUDO_DMA
/*
Pseudo-DMA: (Ove Edlund)
@@ -235,9 +186,6 @@ static int macscsi_pread(struct Scsi_Host *instance,
unsigned char *d;
unsigned char *s;
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
s = hostdata->pdma_base + (INPUT_DATA_REG << 4);
d = dst;
@@ -329,9 +277,6 @@ static int macscsi_pwrite(struct Scsi_Host *instance,
unsigned char *s;
unsigned char *d;
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
s = src;
d = hostdata->pdma_base + (OUTPUT_DATA_REG << 4);
@@ -364,20 +309,22 @@ static int macscsi_pwrite(struct Scsi_Host *instance,
#define PFX DRV_MODULE_NAME ": "
static struct scsi_host_template mac_scsi_template = {
- .module = THIS_MODULE,
- .proc_name = DRV_MODULE_NAME,
- .show_info = macscsi_show_info,
- .write_info = macscsi_write_info,
- .name = "Macintosh NCR5380 SCSI",
- .info = macscsi_info,
- .queuecommand = macscsi_queue_command,
- .eh_abort_handler = macscsi_abort,
- .eh_bus_reset_handler = macscsi_bus_reset,
- .can_queue = 16,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 2,
- .use_clustering = DISABLE_CLUSTERING
+ .module = THIS_MODULE,
+ .proc_name = DRV_MODULE_NAME,
+ .show_info = macscsi_show_info,
+ .write_info = macscsi_write_info,
+ .name = "Macintosh NCR5380 SCSI",
+ .info = macscsi_info,
+ .queuecommand = macscsi_queue_command,
+ .eh_abort_handler = macscsi_abort,
+ .eh_bus_reset_handler = macscsi_bus_reset,
+ .can_queue = 16,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
static int __init mac_scsi_probe(struct platform_device *pdev)
@@ -432,15 +379,14 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
} else
host_flags |= FLAG_NO_PSEUDO_DMA;
-#ifdef RESET_BOOT
- mac_scsi_reset_boot(instance);
-#endif
-
#ifdef SUPPORT_TAGS
host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
#endif
+ host_flags |= setup_toshiba_delay > 0 ? FLAG_TOSHIBA_DELAY : 0;
- NCR5380_init(instance, host_flags);
+ error = NCR5380_init(instance, host_flags);
+ if (error)
+ goto fail_init;
if (instance->irq != NO_IRQ) {
error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
@@ -449,6 +395,8 @@ static int __init mac_scsi_probe(struct platform_device *pdev)
goto fail_irq;
}
+ NCR5380_maybe_reset_bus(instance);
+
error = scsi_add_host(instance, NULL);
if (error)
goto fail_host;
@@ -463,6 +411,7 @@ fail_host:
free_irq(instance->irq, instance);
fail_irq:
NCR5380_exit(instance);
+fail_init:
scsi_host_put(instance);
return error;
}
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index a70692779..4cf9ed964 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -179,8 +179,12 @@ mraid_mm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
/*
* The following call will block till a kioc is available
+ * or return NULL if the list head is empty for the pointer
+ * of type mraid_mmapt passed to mraid_mm_alloc_kioc
*/
kioc = mraid_mm_alloc_kioc(adp);
+ if (!kioc)
+ return -ENXIO;
/*
* User sent the old mimd_t ioctl packet. Convert it to uioc_t.
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 11393ebf1..83658acdd 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -2020,8 +2020,10 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc)
_base_free_irq(ioc);
_base_disable_msix(ioc);
- if (ioc->msix96_vector)
+ if (ioc->msix96_vector) {
kfree(ioc->replyPostRegisterIndex);
+ ioc->replyPostRegisterIndex = NULL;
+ }
if (ioc->chip_phys) {
iounmap(ioc->chip);
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
index 9270d15ff..f6fc4a705 100644
--- a/drivers/scsi/mvsas/mv_94xx.c
+++ b/drivers/scsi/mvsas/mv_94xx.c
@@ -330,6 +330,51 @@ static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
}
+static void mvs_94xx_sgpio_init(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+ u32 tmp;
+
+ tmp = mr32(MVS_HST_CHIP_CONFIG);
+ tmp |= 0x100;
+ mw32(MVS_HST_CHIP_CONFIG, tmp);
+
+ mw32(MVS_SGPIO_CTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ MVS_SGPIO_CTRL_SDOUT_AUTO << MVS_SGPIO_CTRL_SDOUT_SHIFT);
+
+ mw32(MVS_SGPIO_CFG1 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ 8 << MVS_SGPIO_CFG1_LOWA_SHIFT |
+ 8 << MVS_SGPIO_CFG1_HIA_SHIFT |
+ 4 << MVS_SGPIO_CFG1_LOWB_SHIFT |
+ 4 << MVS_SGPIO_CFG1_HIB_SHIFT |
+ 2 << MVS_SGPIO_CFG1_MAXACTON_SHIFT |
+ 1 << MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT
+ );
+
+ mw32(MVS_SGPIO_CFG2 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ (300000 / 100) << MVS_SGPIO_CFG2_CLK_SHIFT | /* 100kHz clock */
+ 66 << MVS_SGPIO_CFG2_BLINK_SHIFT /* (66 * 0,121 Hz?)*/
+ );
+
+ mw32(MVS_SGPIO_CFG0 + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ MVS_SGPIO_CFG0_ENABLE |
+ MVS_SGPIO_CFG0_BLINKA |
+ MVS_SGPIO_CFG0_BLINKB |
+ /* 3*4 data bits / PDU */
+ (12 - 1) << MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT
+ );
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ DEFAULT_SGPIO_BITS);
+
+ mw32(MVS_SGPIO_DSRC + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ ((mvi->id * 4) + 3) << (8 * 3) |
+ ((mvi->id * 4) + 2) << (8 * 2) |
+ ((mvi->id * 4) + 1) << (8 * 1) |
+ ((mvi->id * 4) + 0) << (8 * 0));
+
+}
+
static int mvs_94xx_init(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
@@ -533,6 +578,8 @@ static int mvs_94xx_init(struct mvs_info *mvi)
/* Enable SRS interrupt */
mw32(MVS_INT_MASK_SRS_0, 0xFFFF);
+ mvs_94xx_sgpio_init(mvi);
+
return 0;
}
@@ -1005,6 +1052,92 @@ static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time)
}
+static int mvs_94xx_gpio_write(struct mvs_prv_info *mvs_prv,
+ u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data)
+{
+ int i;
+
+ switch (reg_type) {
+
+ case SAS_GPIO_REG_TX_GP:
+ if (reg_index == 0)
+ return -EINVAL;
+
+ if (reg_count > 1)
+ return -EINVAL;
+
+ if (reg_count == 0)
+ return 0;
+
+ /* maximum supported bits = hosts * 4 drives * 3 bits */
+ for (i = 0; i < mvs_prv->n_host * 4 * 3; i++) {
+
+ /* select host */
+ struct mvs_info *mvi = mvs_prv->mvi[i/(4*3)];
+
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+
+ int drive = (i/3) & (4-1); /* drive number on host */
+ u32 block = mr32(MVS_SGPIO_DCTRL +
+ MVS_SGPIO_HOST_OFFSET * mvi->id);
+
+
+ /*
+ * if bit is set then create a mask with the first
+ * bit of the drive set in the mask ...
+ */
+ u32 bit = (write_data[i/8] & (1 << (i&(8-1)))) ?
+ 1<<(24-drive*8) : 0;
+
+ /*
+ * ... and then shift it to the right position based
+ * on the led type (activity/id/fail)
+ */
+ switch (i%3) {
+ case 0: /* activity */
+ block &= ~((0x7 << MVS_SGPIO_DCTRL_ACT_SHIFT)
+ << (24-drive*8));
+ /* hardwire activity bit to SOF */
+ block |= LED_BLINKA_SOF << (
+ MVS_SGPIO_DCTRL_ACT_SHIFT +
+ (24-drive*8));
+ break;
+ case 1: /* id */
+ block &= ~((0x3 << MVS_SGPIO_DCTRL_LOC_SHIFT)
+ << (24-drive*8));
+ block |= bit << MVS_SGPIO_DCTRL_LOC_SHIFT;
+ break;
+ case 2: /* fail */
+ block &= ~((0x7 << MVS_SGPIO_DCTRL_ERR_SHIFT)
+ << (24-drive*8));
+ block |= bit << MVS_SGPIO_DCTRL_ERR_SHIFT;
+ break;
+ }
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ block);
+
+ }
+
+ return reg_count;
+
+ case SAS_GPIO_REG_TX:
+ if (reg_index + reg_count > mvs_prv->n_host)
+ return -EINVAL;
+
+ for (i = 0; i < reg_count; i++) {
+ struct mvs_info *mvi = mvs_prv->mvi[i+reg_index];
+ void __iomem *regs = mvi->regs_ex - 0x10200;
+
+ mw32(MVS_SGPIO_DCTRL + MVS_SGPIO_HOST_OFFSET * mvi->id,
+ be32_to_cpu(((u32 *) write_data)[i]));
+ }
+ return reg_count;
+ }
+ return -ENOSYS;
+}
+
const struct mvs_dispatch mvs_94xx_dispatch = {
"mv94xx",
mvs_94xx_init,
@@ -1057,5 +1190,6 @@ const struct mvs_dispatch mvs_94xx_dispatch = {
mvs_94xx_fix_dma,
mvs_94xx_tune_interrupt,
mvs_94xx_non_spec_ncq_error,
+ mvs_94xx_gpio_write,
};
diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h
index 14e197497..578960803 100644
--- a/drivers/scsi/mvsas/mv_94xx.h
+++ b/drivers/scsi/mvsas/mv_94xx.h
@@ -38,6 +38,10 @@ enum VANIR_REVISION_ID {
VANIR_C2_REV = 0xC2,
};
+enum host_registers {
+ MVS_HST_CHIP_CONFIG = 0x10104, /* chip configuration */
+};
+
enum hw_registers {
MVS_GBL_CTL = 0x04, /* global control */
MVS_GBL_INT_STAT = 0x00, /* global irq status */
@@ -239,6 +243,73 @@ struct mvs_prd {
__le32 im_len;
} __attribute__ ((packed));
+enum sgpio_registers {
+ MVS_SGPIO_HOST_OFFSET = 0x100, /* offset between hosts */
+
+ MVS_SGPIO_CFG0 = 0xc200,
+ MVS_SGPIO_CFG0_ENABLE = (1 << 0), /* enable pins */
+ MVS_SGPIO_CFG0_BLINKB = (1 << 1), /* blink generators */
+ MVS_SGPIO_CFG0_BLINKA = (1 << 2),
+ MVS_SGPIO_CFG0_INVSCLK = (1 << 3), /* invert signal? */
+ MVS_SGPIO_CFG0_INVSLOAD = (1 << 4),
+ MVS_SGPIO_CFG0_INVSDOUT = (1 << 5),
+ MVS_SGPIO_CFG0_SLOAD_FALLEDGE = (1 << 6), /* rise/fall edge? */
+ MVS_SGPIO_CFG0_SDOUT_FALLEDGE = (1 << 7),
+ MVS_SGPIO_CFG0_SDIN_RISEEDGE = (1 << 8),
+ MVS_SGPIO_CFG0_MAN_BITLEN_SHIFT = 18, /* bits/frame manual mode */
+ MVS_SGPIO_CFG0_AUT_BITLEN_SHIFT = 24, /* bits/frame auto mode */
+
+ MVS_SGPIO_CFG1 = 0xc204, /* blink timing register */
+ MVS_SGPIO_CFG1_LOWA_SHIFT = 0, /* A off time */
+ MVS_SGPIO_CFG1_HIA_SHIFT = 4, /* A on time */
+ MVS_SGPIO_CFG1_LOWB_SHIFT = 8, /* B off time */
+ MVS_SGPIO_CFG1_HIB_SHIFT = 12, /* B on time */
+ MVS_SGPIO_CFG1_MAXACTON_SHIFT = 16, /* max activity on time */
+
+ /* force activity off time */
+ MVS_SGPIO_CFG1_FORCEACTOFF_SHIFT = 20,
+ /* stretch activity on time */
+ MVS_SGPIO_CFG1_STRCHACTON_SHIFT = 24,
+ /* stretch activiity off time */
+ MVS_SGPIO_CFG1_STRCHACTOFF_SHIFT = 28,
+
+
+ MVS_SGPIO_CFG2 = 0xc208, /* clock speed register */
+ MVS_SGPIO_CFG2_CLK_SHIFT = 0,
+ MVS_SGPIO_CFG2_BLINK_SHIFT = 20,
+
+ MVS_SGPIO_CTRL = 0xc20c, /* SDOUT/SDIN mode control */
+ MVS_SGPIO_CTRL_SDOUT_AUTO = 2,
+ MVS_SGPIO_CTRL_SDOUT_SHIFT = 2,
+
+ MVS_SGPIO_DSRC = 0xc220, /* map ODn bits to drives */
+
+ MVS_SGPIO_DCTRL = 0xc238,
+ MVS_SGPIO_DCTRL_ERR_SHIFT = 0,
+ MVS_SGPIO_DCTRL_LOC_SHIFT = 3,
+ MVS_SGPIO_DCTRL_ACT_SHIFT = 5,
+};
+
+enum sgpio_led_status {
+ LED_OFF = 0,
+ LED_ON = 1,
+ LED_BLINKA = 2,
+ LED_BLINKA_INV = 3,
+ LED_BLINKA_SOF = 4,
+ LED_BLINKA_EOF = 5,
+ LED_BLINKB = 6,
+ LED_BLINKB_INV = 7,
+};
+
+#define DEFAULT_SGPIO_BITS ((LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 3) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 2) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 1) | \
+ (LED_BLINKA_SOF << \
+ MVS_SGPIO_DCTRL_ACT_SHIFT) << (8 * 0))
+
/*
* these registers are accessed through port vendor
* specific address/data registers
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 675e7fab0..c7c250519 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -84,6 +84,8 @@ static struct sas_domain_function_template mvs_transport_ops = {
.lldd_port_formed = mvs_port_formed,
.lldd_port_deformed = mvs_port_deformed,
+ .lldd_write_gpio = mvs_gpio_write,
+
};
static void mvs_phy_init(struct mvs_info *mvi, int phy_id)
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 9c780740f..83cd3ea2d 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -737,8 +737,8 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
mv_dprintk("device %016llx not ready.\n",
SAS_ADDR(dev->sas_addr));
- rc = SAS_PHY_DOWN;
- return rc;
+ rc = SAS_PHY_DOWN;
+ return rc;
}
tei.port = dev->port->lldd_port;
if (tei.port && !tei.port->port_attached && !tmf) {
@@ -2105,3 +2105,16 @@ int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
return 0;
}
+int mvs_gpio_write(struct sas_ha_struct *sha, u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data)
+{
+ struct mvs_prv_info *mvs_prv = sha->lldd_ha;
+ struct mvs_info *mvi = mvs_prv->mvi[0];
+
+ if (MVS_CHIP_DISP->gpio_write) {
+ return MVS_CHIP_DISP->gpio_write(mvs_prv, reg_type,
+ reg_index, reg_count, write_data);
+ }
+
+ return -ENOSYS;
+}
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index dc409c047..f9afd4cdd 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -103,6 +103,7 @@ enum dev_reset {
};
struct mvs_info;
+struct mvs_prv_info;
struct mvs_dispatch {
char *name;
@@ -172,6 +173,8 @@ struct mvs_dispatch {
int buf_len, int from, void *prd);
void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
void (*non_spec_ncq_error)(struct mvs_info *mvi);
+ int (*gpio_write)(struct mvs_prv_info *mvs_prv, u8 reg_type,
+ u8 reg_index, u8 reg_count, u8 *write_data);
};
@@ -476,5 +479,7 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
+int mvs_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index,
+ u8 reg_count, u8 *write_data);
#endif
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 0cccd6033..d8a2b5185 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -170,10 +170,7 @@ static int _osd_get_print_system_info(struct osd_dev *od,
/* FIXME: Where are the time utilities */
pFirst = get_attrs[a++].val_ptr;
- OSD_INFO("CLOCK [0x%02x%02x%02x%02x%02x%02x]\n",
- ((char *)pFirst)[0], ((char *)pFirst)[1],
- ((char *)pFirst)[2], ((char *)pFirst)[3],
- ((char *)pFirst)[4], ((char *)pFirst)[5]);
+ OSD_INFO("CLOCK [0x%6phN]\n", pFirst);
if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */
unsigned len = get_attrs[a].len;
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index e81eadd08..512037e27 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -1,6 +1,4 @@
#define PSEUDO_DMA
-#define UNSAFE /* Not unsafe for PAS16 -- use it */
-#define PDEBUG 0
/*
* This driver adapted from Drew Eckhardt's Trantor T128 driver
@@ -71,14 +69,10 @@
#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/proc_fs.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/blkdev.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/stat.h>
#include <linux/init.h>
#include <scsi/scsi_host.h>
@@ -87,8 +81,8 @@
#include "NCR5380.h"
-static unsigned short pas16_addr = 0;
-static int pas16_irq = 0;
+static unsigned short pas16_addr;
+static int pas16_irq;
static const int scsi_irq_translate[] =
@@ -146,22 +140,6 @@ static const unsigned short pas16_offset[ 8 ] =
* START_DMA_INITIATOR_RECEIVE_REG wo
*/
};
-/*----------------------------------------------------------------*/
-/* the following will set the monitor border color (useful to find
- where something crashed or gets stuck at */
-/* 1 = blue
- 2 = green
- 3 = cyan
- 4 = red
- 5 = magenta
- 6 = yellow
- 7 = white
-*/
-#if 1
-#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
-#else
-#define rtrc(i) {}
-#endif
/*
@@ -205,7 +183,7 @@ static void __init
outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */
outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+ inb(io_port + pas16_offset[RESET_PARITY_INTERRUPT_REG]);
/* Set the SCSI interrupt pointer without mucking up the sound
* interrupt pointer in the same byte.
@@ -280,13 +258,13 @@ static int __init
* put in an additional test to try to weed them out.
*/
- outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
- NCR5380_write( MODE_REG, 0x20 ); /* Is it really SCSI? */
- if( NCR5380_read( MODE_REG ) != 0x20 ) /* Write to a reg. */
- return 0; /* and try to read */
- NCR5380_write( MODE_REG, 0x00 ); /* it back. */
- if( NCR5380_read( MODE_REG ) != 0x00 )
- return 0;
+ outb(0x01, io_port + WAIT_STATE); /* 1 Wait state */
+ outb(0x20, io_port + pas16_offset[MODE_REG]); /* Is it really SCSI? */
+ if (inb(io_port + pas16_offset[MODE_REG]) != 0x20) /* Write to a reg. */
+ return 0; /* and try to read */
+ outb(0x00, io_port + pas16_offset[MODE_REG]); /* it back. */
+ if (inb(io_port + pas16_offset[MODE_REG]) != 0x00)
+ return 0;
return 1;
}
@@ -305,7 +283,7 @@ static int __init
static int __init pas16_setup(char *str)
{
- static int commandline_current = 0;
+ static int commandline_current;
int i;
int ints[10];
@@ -344,8 +322,8 @@ __setup("pas16=", pas16_setup);
static int __init pas16_detect(struct scsi_host_template *tpnt)
{
- static int current_override = 0;
- static unsigned short current_base = 0;
+ static int current_override;
+ static unsigned short current_base;
struct Scsi_Host *instance;
unsigned short io_port;
int count;
@@ -377,34 +355,32 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
}
else
for (; !io_port && (current_base < NO_BASES); ++current_base) {
-#if (PDEBUG & PDEBUG_INIT)
- printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
-#endif
+ dprintk(NDEBUG_INIT, "pas16: probing io_port 0x%04x\n",
+ (unsigned int)bases[current_base].io_port);
if ( !bases[current_base].noauto &&
pas16_hw_detect( current_base ) ){
io_port = bases[current_base].io_port;
init_board( io_port, default_irqs[ current_base ], 0 );
-#if (PDEBUG & PDEBUG_INIT)
- printk("scsi-pas16 : detected board.\n");
-#endif
+ dprintk(NDEBUG_INIT, "pas16: detected board\n");
}
}
-
-#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
- printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port);
-#endif
+ dprintk(NDEBUG_INIT, "pas16: io_port = 0x%04x\n",
+ (unsigned int)io_port);
if (!io_port)
break;
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
if(instance == NULL)
- break;
+ goto out;
instance->io_port = io_port;
- NCR5380_init(instance, 0);
+ if (NCR5380_init(instance, 0))
+ goto out_unregister;
+
+ NCR5380_maybe_reset_bus(instance);
if (overrides[current_override].irq != IRQ_AUTO)
instance->irq = overrides[current_override].irq;
@@ -431,14 +407,18 @@ static int __init pas16_detect(struct scsi_host_template *tpnt)
outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
}
-#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
- printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+ dprintk(NDEBUG_INIT, "scsi%d : irq = %d\n",
+ instance->host_no, instance->irq);
++current_override;
++count;
}
return count;
+
+out_unregister:
+ scsi_unregister(instance);
+out:
+ return count;
}
/*
@@ -561,29 +541,29 @@ static int pas16_release(struct Scsi_Host *shost)
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
scsi_unregister(shost);
return 0;
}
static struct scsi_host_template driver_template = {
- .name = "Pro Audio Spectrum-16 SCSI",
- .detect = pas16_detect,
- .release = pas16_release,
- .proc_name = "pas16",
- .show_info = pas16_show_info,
- .write_info = pas16_write_info,
- .info = pas16_info,
- .queuecommand = pas16_queue_command,
- .eh_abort_handler = pas16_abort,
- .eh_bus_reset_handler = pas16_bus_reset,
- .bios_param = pas16_biosparam,
- .can_queue = CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING,
+ .name = "Pro Audio Spectrum-16 SCSI",
+ .detect = pas16_detect,
+ .release = pas16_release,
+ .proc_name = "pas16",
+ .show_info = pas16_show_info,
+ .write_info = pas16_write_info,
+ .info = pas16_info,
+ .queuecommand = pas16_queue_command,
+ .eh_abort_handler = pas16_abort,
+ .eh_bus_reset_handler = pas16_bus_reset,
+ .bios_param = pas16_biosparam,
+ .can_queue = 32,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index c6109c800..d37527717 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -24,9 +24,6 @@
#ifndef PAS16_H
#define PAS16_H
-#define PDEBUG_INIT 0x1
-#define PDEBUG_TRANSFER 0x2
-
#define PAS16_DEFAULT_BASE_1 0x388
#define PAS16_DEFAULT_BASE_2 0x384
#define PAS16_DEFAULT_BASE_3 0x38c
@@ -98,46 +95,16 @@
#define OPERATION_MODE_1 0xec03
#define IO_CONFIG_3 0xf002
+#define NCR5380_implementation_fields /* none */
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32
-#endif
-
-#define NCR5380_implementation_fields \
- volatile unsigned short io_port
-
-#define NCR5380_local_declare() \
- volatile unsigned short io_port
+#define PAS16_io_port(reg) (instance->io_port + pas16_offset[(reg)])
-#define NCR5380_setup(instance) \
- io_port = (instance)->io_port
-
-#define PAS16_io_port(reg) ( io_port + pas16_offset[(reg)] )
-
-#if !(PDEBUG & PDEBUG_TRANSFER)
#define NCR5380_read(reg) ( inb(PAS16_io_port(reg)) )
#define NCR5380_write(reg, value) ( outb((value),PAS16_io_port(reg)) )
-#else
-#define NCR5380_read(reg) \
- (((unsigned char) printk("scsi%d : read register %d at io_port %04x\n"\
- , instance->hostno, (reg), PAS16_io_port(reg))), inb( PAS16_io_port(reg)) )
-
-#define NCR5380_write(reg, value) \
- (printk("scsi%d : write %02x to register %d at io_port %04x\n", \
- instance->hostno, (value), (reg), PAS16_io_port(reg)), \
- outb( (value),PAS16_io_port(reg) ) )
-
-#endif
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_intr pas16_intr
-#define do_NCR5380_intr do_pas16_intr
#define NCR5380_queue_command pas16_queue_command
#define NCR5380_abort pas16_abort
#define NCR5380_bus_reset pas16_bus_reset
@@ -150,5 +117,4 @@
#define PAS16_IRQS 0xd4a8
-#endif /* ndef ASM */
#endif /* PAS16_H */
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 6b942d9e5..6992ebc50 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -824,6 +824,41 @@ static struct bin_attribute sysfs_reset_attr = {
};
static ssize_t
+qla2x00_issue_logo(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ int type;
+ int rval = 0;
+ port_id_t did;
+
+ type = simple_strtol(buf, NULL, 10);
+
+ did.b.domain = (type & 0x00ff0000) >> 16;
+ did.b.area = (type & 0x0000ff00) >> 8;
+ did.b.al_pa = (type & 0x000000ff);
+
+ ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n",
+ did.b.domain, did.b.area, did.b.al_pa);
+
+ ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
+
+ rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
+ return count;
+}
+
+static struct bin_attribute sysfs_issue_logo_attr = {
+ .attr = {
+ .name = "issue_logo",
+ .mode = S_IWUSR,
+ },
+ .size = 0,
+ .write = qla2x00_issue_logo,
+};
+
+static ssize_t
qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
@@ -937,6 +972,7 @@ static struct sysfs_entry {
{ "vpd", &sysfs_vpd_attr, 1 },
{ "sfp", &sysfs_sfp_attr, 1 },
{ "reset", &sysfs_reset_attr, },
+ { "issue_logo", &sysfs_issue_logo_attr, },
{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
{ NULL },
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 34dc9a356..cd0d94ea7 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -14,25 +14,24 @@
* | Module Init and Probe | 0x017f | 0x0146 |
* | | | 0x015b-0x0160 |
* | | | 0x016e-0x0170 |
- * | Mailbox commands | 0x118d | 0x1115-0x1116 |
- * | | | 0x111a-0x111b |
+ * | Mailbox commands | 0x1192 | |
+ * | | | |
* | Device Discovery | 0x2016 | 0x2020-0x2022, |
* | | | 0x2011-0x2012, |
* | | | 0x2099-0x20a4 |
- * | Queue Command and IO tracing | 0x3075 | 0x300b |
+ * | Queue Command and IO tracing | 0x3074 | 0x300b |
* | | | 0x3027-0x3028 |
* | | | 0x303d-0x3041 |
* | | | 0x302d,0x3033 |
* | | | 0x3036,0x3038 |
* | | | 0x303a |
* | DPC Thread | 0x4023 | 0x4002,0x4013 |
- * | Async Events | 0x508a | 0x502b-0x502f |
- * | | | 0x5047 |
+ * | Async Events | 0x5089 | 0x502b-0x502f |
* | | | 0x5084,0x5075 |
* | | | 0x503d,0x5044 |
* | | | 0x507b,0x505f |
* | Timer Routines | 0x6012 | |
- * | User Space Interactions | 0x70e2 | 0x7018,0x702e |
+ * | User Space Interactions | 0x70e65 | 0x7018,0x702e |
* | | | 0x7020,0x7024 |
* | | | 0x7039,0x7045 |
* | | | 0x7073-0x7075 |
@@ -60,15 +59,11 @@
* | | | 0xb13c-0xb140 |
* | | | 0xb149 |
* | MultiQ | 0xc00c | |
- * | Misc | 0xd300 | 0xd016-0xd017 |
- * | | | 0xd021,0xd024 |
- * | | | 0xd025,0xd029 |
- * | | | 0xd02a,0xd02e |
- * | | | 0xd031-0xd0ff |
+ * | Misc | 0xd301 | 0xd031-0xd0ff |
* | | | 0xd101-0xd1fe |
* | | | 0xd214-0xd2fe |
* | Target Mode | 0xe080 | |
- * | Target Mode Management | 0xf096 | 0xf002 |
+ * | Target Mode Management | 0xf09b | 0xf002 |
* | | | 0xf046-0xf049 |
* | Target Mode Task Management | 0x1000d | |
* ----------------------------------------------------------------------
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 388d79088..9872f3429 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -259,7 +259,7 @@
#define LOOP_DOWN_TIME 255 /* 240 */
#define LOOP_DOWN_RESET (LOOP_DOWN_TIME - 30)
-#define DEFAULT_OUTSTANDING_COMMANDS 1024
+#define DEFAULT_OUTSTANDING_COMMANDS 4096
#define MIN_OUTSTANDING_COMMANDS 128
/* ISP request and response entry counts (37-65535) */
@@ -267,11 +267,13 @@
#define REQUEST_ENTRY_CNT_2200 2048 /* Number of request entries. */
#define REQUEST_ENTRY_CNT_24XX 2048 /* Number of request entries. */
#define REQUEST_ENTRY_CNT_83XX 8192 /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_83XX 4096 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/
#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */
#define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/
+#define EXTENDED_EXCH_ENTRY_CNT 32768 /* Entries for offload case */
struct req_que;
struct qla_tgt_sess;
@@ -309,6 +311,14 @@ struct srb_cmd {
/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
+struct els_logo_payload {
+ uint8_t opcode;
+ uint8_t rsvd[3];
+ uint8_t s_id[3];
+ uint8_t rsvd1[1];
+ uint8_t wwpn[WWN_SIZE];
+};
+
/*
* SRB extensions.
*/
@@ -322,6 +332,15 @@ struct srb_iocb {
uint16_t data[2];
} logio;
struct {
+#define ELS_DCMD_TIMEOUT 20
+#define ELS_DCMD_LOGO 0x5
+ uint32_t flags;
+ uint32_t els_cmd;
+ struct completion comp;
+ struct els_logo_payload *els_logo_pyld;
+ dma_addr_t els_logo_pyld_dma;
+ } els_logo;
+ struct {
/*
* Values for flags field below are as
* defined in tsk_mgmt_entry struct
@@ -382,7 +401,7 @@ struct srb_iocb {
#define SRB_FXIOCB_DCMD 10
#define SRB_FXIOCB_BCMD 11
#define SRB_ABT_CMD 12
-
+#define SRB_ELS_DCMD 13
typedef struct srb {
atomic_t ref_count;
@@ -891,6 +910,7 @@ struct mbx_cmd_32 {
#define MBC_DISABLE_VI 0x24 /* Disable VI operation. */
#define MBC_ENABLE_VI 0x25 /* Enable VI operation. */
#define MBC_GET_FIRMWARE_OPTION 0x28 /* Get Firmware Options. */
+#define MBC_GET_MEM_OFFLOAD_CNTRL_STAT 0x34 /* Memory Offload ctrl/Stat*/
#define MBC_SET_FIRMWARE_OPTION 0x38 /* Set Firmware Options. */
#define MBC_LOOP_PORT_BYPASS 0x40 /* Loop Port Bypass. */
#define MBC_LOOP_PORT_ENABLE 0x41 /* Loop Port Enable. */
@@ -2695,11 +2715,16 @@ struct isp_operations {
struct scsi_qla_host;
+
+#define QLA83XX_RSPQ_MSIX_ENTRY_NUMBER 1 /* refer to qla83xx_msix_entries */
+
struct qla_msix_entry {
int have_irq;
uint32_t vector;
uint16_t entry;
struct rsp_que *rsp;
+ struct irq_affinity_notify irq_notify;
+ int cpuid;
};
#define WATCH_INTERVAL 1 /* number of seconds */
@@ -2910,12 +2935,15 @@ struct qlt_hw_data {
uint32_t num_qfull_cmds_dropped;
spinlock_t q_full_lock;
uint32_t leak_exchg_thresh_hold;
+ spinlock_t sess_lock;
+ int rspq_vector_cpuid;
+ spinlock_t atio_lock ____cacheline_aligned;
};
#define MAX_QFULL_CMDS_ALLOC 8192
#define Q_FULL_THRESH_HOLD_PERCENT 90
#define Q_FULL_THRESH_HOLD(ha) \
- ((ha->fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
+ ((ha->cur_fw_xcb_count/100) * Q_FULL_THRESH_HOLD_PERCENT)
#define LEAK_EXCHG_THRESH_HOLD_PERCENT 75 /* 75 percent */
@@ -2962,10 +2990,12 @@ struct qla_hw_data {
uint32_t isp82xx_no_md_cap:1;
uint32_t host_shutting_down:1;
uint32_t idc_compl_status:1;
-
uint32_t mr_reset_hdlr_active:1;
uint32_t mr_intr_valid:1;
+
uint32_t fawwpn_enabled:1;
+ uint32_t exlogins_enabled:1;
+ uint32_t exchoffld_enabled:1;
/* 35 bits */
} flags;
@@ -3237,6 +3267,21 @@ struct qla_hw_data {
void *async_pd;
dma_addr_t async_pd_dma;
+#define ENABLE_EXTENDED_LOGIN BIT_7
+
+ /* Extended Logins */
+ void *exlogin_buf;
+ dma_addr_t exlogin_buf_dma;
+ int exlogin_size;
+
+#define ENABLE_EXCHANGE_OFFLD BIT_2
+
+ /* Exchange Offload */
+ void *exchoffld_buf;
+ dma_addr_t exchoffld_buf_dma;
+ int exchoffld_size;
+ int exchoffld_count;
+
void *swl;
/* These are used by mailbox operations. */
@@ -3279,8 +3324,14 @@ struct qla_hw_data {
#define RISC_START_ADDRESS_2100 0x1000
#define RISC_START_ADDRESS_2300 0x800
#define RISC_START_ADDRESS_2400 0x100000
- uint16_t fw_xcb_count;
- uint16_t fw_iocb_count;
+
+ uint16_t orig_fw_tgt_xcb_count;
+ uint16_t cur_fw_tgt_xcb_count;
+ uint16_t orig_fw_xcb_count;
+ uint16_t cur_fw_xcb_count;
+ uint16_t orig_fw_iocb_count;
+ uint16_t cur_fw_iocb_count;
+ uint16_t fw_max_fcf_count;
uint32_t fw_shared_ram_start;
uint32_t fw_shared_ram_end;
@@ -3323,6 +3374,9 @@ struct qla_hw_data {
uint32_t chain_offset;
struct dentry *dfs_dir;
struct dentry *dfs_fce;
+ struct dentry *dfs_tgt_counters;
+ struct dentry *dfs_fw_resource_cnt;
+
dma_addr_t fce_dma;
void *fce;
uint32_t fce_bufs;
@@ -3480,6 +3534,18 @@ struct qla_hw_data {
int allow_cna_fw_dump;
};
+struct qla_tgt_counters {
+ uint64_t qla_core_sbt_cmd;
+ uint64_t core_qla_que_buf;
+ uint64_t qla_core_ret_ctio;
+ uint64_t core_qla_snd_status;
+ uint64_t qla_core_ret_sta_ctio;
+ uint64_t core_qla_free_cmd;
+ uint64_t num_q_full_sent;
+ uint64_t num_alloc_iocb_failed;
+ uint64_t num_term_xchg_sent;
+};
+
/*
* Qlogic scsi host structure
*/
@@ -3595,6 +3661,10 @@ typedef struct scsi_qla_host {
atomic_t generation_tick;
/* Time when global fcport update has been scheduled */
int total_fcport_update_gen;
+ /* List of pending LOGOs, protected by tgt_mutex */
+ struct list_head logo_list;
+ /* List of pending PLOGI acks, protected by hw lock */
+ struct list_head plogi_ack_list;
uint32_t vp_abort_cnt;
@@ -3632,6 +3702,7 @@ typedef struct scsi_qla_host {
atomic_t vref_count;
struct qla8044_reset_template reset_tmplt;
+ struct qla_tgt_counters tgt_counters;
} scsi_qla_host_t;
#define SET_VP_IDX 1
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 15cf074ff..cd8b96a4b 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -13,6 +13,85 @@ static struct dentry *qla2x00_dfs_root;
static atomic_t qla2x00_dfs_root_count;
static int
+qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
+{
+ struct scsi_qla_host *vha = s->private;
+ struct qla_hw_data *ha = vha->hw;
+
+ seq_puts(s, "FW Resource count\n\n");
+ seq_printf(s, "Original TGT exchg count[%d]\n",
+ ha->orig_fw_tgt_xcb_count);
+ seq_printf(s, "current TGT exchg count[%d]\n",
+ ha->cur_fw_tgt_xcb_count);
+ seq_printf(s, "original Initiator Exchange count[%d]\n",
+ ha->orig_fw_xcb_count);
+ seq_printf(s, "Current Initiator Exchange count[%d]\n",
+ ha->cur_fw_xcb_count);
+ seq_printf(s, "Original IOCB count[%d]\n", ha->orig_fw_iocb_count);
+ seq_printf(s, "Current IOCB count[%d]\n", ha->cur_fw_iocb_count);
+ seq_printf(s, "MAX VP count[%d]\n", ha->max_npiv_vports);
+ seq_printf(s, "MAX FCF count[%d]\n", ha->fw_max_fcf_count);
+
+ return 0;
+}
+
+static int
+qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
+{
+ struct scsi_qla_host *vha = inode->i_private;
+ return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
+}
+
+static const struct file_operations dfs_fw_resource_cnt_ops = {
+ .open = qla_dfs_fw_resource_cnt_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
+qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
+{
+ struct scsi_qla_host *vha = s->private;
+
+ seq_puts(s, "Target Counters\n");
+ seq_printf(s, "qla_core_sbt_cmd = %lld\n",
+ vha->tgt_counters.qla_core_sbt_cmd);
+ seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
+ vha->tgt_counters.qla_core_ret_sta_ctio);
+ seq_printf(s, "qla_core_ret_ctio = %lld\n",
+ vha->tgt_counters.qla_core_ret_ctio);
+ seq_printf(s, "core_qla_que_buf = %lld\n",
+ vha->tgt_counters.core_qla_que_buf);
+ seq_printf(s, "core_qla_snd_status = %lld\n",
+ vha->tgt_counters.core_qla_snd_status);
+ seq_printf(s, "core_qla_free_cmd = %lld\n",
+ vha->tgt_counters.core_qla_free_cmd);
+ seq_printf(s, "num alloc iocb failed = %lld\n",
+ vha->tgt_counters.num_alloc_iocb_failed);
+ seq_printf(s, "num term exchange sent = %lld\n",
+ vha->tgt_counters.num_term_xchg_sent);
+ seq_printf(s, "num Q full sent = %lld\n",
+ vha->tgt_counters.num_q_full_sent);
+
+ return 0;
+}
+
+static int
+qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
+{
+ struct scsi_qla_host *vha = inode->i_private;
+ return single_open(file, qla_dfs_tgt_counters_show, vha);
+}
+
+static const struct file_operations dfs_tgt_counters_ops = {
+ .open = qla_dfs_tgt_counters_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int
qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
{
scsi_qla_host_t *vha = s->private;
@@ -146,6 +225,22 @@ create_dir:
atomic_inc(&qla2x00_dfs_root_count);
create_nodes:
+ ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
+ S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops);
+ if (!ha->dfs_fw_resource_cnt) {
+ ql_log(ql_log_warn, vha, 0x00fd,
+ "Unable to create debugFS fw_resource_count node.\n");
+ goto out;
+ }
+
+ ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
+ ha->dfs_dir, vha, &dfs_tgt_counters_ops);
+ if (!ha->dfs_tgt_counters) {
+ ql_log(ql_log_warn, vha, 0xd301,
+ "Unable to create debugFS tgt_counters node.\n");
+ goto out;
+ }
+
ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
&dfs_fce_ops);
if (!ha->dfs_fce) {
@@ -161,6 +256,17 @@ int
qla2x00_dfs_remove(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
+
+ if (ha->dfs_fw_resource_cnt) {
+ debugfs_remove(ha->dfs_fw_resource_cnt);
+ ha->dfs_fw_resource_cnt = NULL;
+ }
+
+ if (ha->dfs_tgt_counters) {
+ debugfs_remove(ha->dfs_tgt_counters);
+ ha->dfs_tgt_counters = NULL;
+ }
+
if (ha->dfs_fce) {
debugfs_remove(ha->dfs_fce);
ha->dfs_fce = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 7686bfe9a..0103e468e 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -44,6 +44,8 @@ extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
+extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t);
+
extern void qla2x00_update_fcports(scsi_qla_host_t *);
extern int qla2x00_abort_isp(scsi_qla_host_t *);
@@ -117,6 +119,8 @@ extern int ql2xdontresethba;
extern uint64_t ql2xmaxlun;
extern int ql2xmdcapmask;
extern int ql2xmdenable;
+extern int ql2xexlogins;
+extern int ql2xexchoffld;
extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -135,6 +139,10 @@ extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
+extern int qla2x00_set_exlogins_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exlogin_buffer(struct qla_hw_data *);
+extern int qla2x00_set_exchoffld_buffer(struct scsi_qla_host *);
+extern void qla2x00_free_exchoffld_buffer(struct qla_hw_data *);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
@@ -323,8 +331,7 @@ extern int
qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
- uint16_t *, uint16_t *, uint16_t *, uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *);
extern int
qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
@@ -766,4 +773,11 @@ extern int qla8044_abort_isp(scsi_qla_host_t *);
extern int qla8044_check_fw_alive(struct scsi_qla_host *);
extern void qlt_host_reset_handler(struct qla_hw_data *ha);
+extern int qla_get_exlogin_status(scsi_qla_host_t *, uint16_t *,
+ uint16_t *);
+extern int qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr);
+extern int qla_get_exchoffld_status(scsi_qla_host_t *, uint16_t *, uint16_t *);
+extern int qla_set_exchoffld_mem_cfg(scsi_qla_host_t *, dma_addr_t);
+extern void qlt_handle_abts_recv(struct scsi_qla_host *, response_t *);
+
#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index e197c6f39..692a7570b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1766,10 +1766,10 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req)
(ql2xmultique_tag || ql2xmaxqueues > 1)))
req->num_outstanding_cmds = DEFAULT_OUTSTANDING_COMMANDS;
else {
- if (ha->fw_xcb_count <= ha->fw_iocb_count)
- req->num_outstanding_cmds = ha->fw_xcb_count;
+ if (ha->cur_fw_xcb_count <= ha->cur_fw_iocb_count)
+ req->num_outstanding_cmds = ha->cur_fw_xcb_count;
else
- req->num_outstanding_cmds = ha->fw_iocb_count;
+ req->num_outstanding_cmds = ha->cur_fw_iocb_count;
}
req->outstanding_cmds = kzalloc(sizeof(srb_t *) *
@@ -1843,9 +1843,23 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_init, vha, 0x00ca,
"Starting firmware.\n");
+ if (ql2xexlogins)
+ ha->flags.exlogins_enabled = 1;
+
+ if (ql2xexchoffld)
+ ha->flags.exchoffld_enabled = 1;
+
rval = qla2x00_execute_fw(vha, srisc_address);
/* Retrieve firmware information. */
if (rval == QLA_SUCCESS) {
+ rval = qla2x00_set_exlogins_buffer(vha);
+ if (rval != QLA_SUCCESS)
+ goto failed;
+
+ rval = qla2x00_set_exchoffld_buffer(vha);
+ if (rval != QLA_SUCCESS)
+ goto failed;
+
enable_82xx_npiv:
fw_major_version = ha->fw_major_version;
if (IS_P3P_TYPE(ha))
@@ -1864,9 +1878,7 @@ enable_82xx_npiv:
ha->max_npiv_vports =
MIN_MULTI_ID_FABRIC - 1;
}
- qla2x00_get_resource_cnts(vha, NULL,
- &ha->fw_xcb_count, NULL, &ha->fw_iocb_count,
- &ha->max_npiv_vports, NULL);
+ qla2x00_get_resource_cnts(vha);
/*
* Allocate the array of outstanding commands
@@ -2248,7 +2260,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
if (IS_FWI2_CAPABLE(ha)) {
mid_init_cb->options = cpu_to_le16(BIT_1);
mid_init_cb->init_cb.execution_throttle =
- cpu_to_le16(ha->fw_xcb_count);
+ cpu_to_le16(ha->cur_fw_xcb_count);
/* D-Port Status */
if (IS_DPORT_CAPABLE(ha))
mid_init_cb->init_cb.firmware_options_1 |=
@@ -3053,6 +3065,26 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
atomic_set(&vha->loop_state, LOOP_READY);
ql_dbg(ql_dbg_disc, vha, 0x2069,
"LOOP READY.\n");
+
+ /*
+ * Process any ATIO queue entries that came in
+ * while we weren't online.
+ */
+ if (qla_tgt_mode_enabled(vha)) {
+ if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
+ spin_lock_irqsave(&ha->tgt.atio_lock,
+ flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(
+ &ha->tgt.atio_lock, flags);
+ } else {
+ spin_lock_irqsave(&ha->hardware_lock,
+ flags);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(
+ &ha->hardware_lock, flags);
+ }
+ }
}
}
@@ -4907,7 +4939,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
- unsigned long flags;
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) {
@@ -4929,17 +4960,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
/* Issue a marker after FW becomes ready. */
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
- vha->flags.online = 1;
-
- /*
- * Process any ATIO queue entries that came in
- * while we weren't online.
- */
- spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla_tgt_mode_enabled(vha))
- qlt_24xx_process_atio_queue(vha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index fee9eb7c8..a6b7f1588 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -258,6 +258,8 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo)
if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
(sp->type == SRB_FXIOCB_DCMD))
init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
+ if (sp->type == SRB_ELS_DCMD)
+ init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
}
static inline int
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c49df34e9..b41265a75 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1868,6 +1868,7 @@ skip_cmd_array:
}
queuing_error:
+ vha->tgt_counters.num_alloc_iocb_failed++;
return pkt;
}
@@ -2010,6 +2011,190 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
}
static void
+qla2x00_els_dcmd_sp_free(void *ptr, void *data)
+{
+ struct scsi_qla_host *vha = (scsi_qla_host_t *)ptr;
+ struct qla_hw_data *ha = vha->hw;
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ kfree(sp->fcport);
+
+ if (elsio->u.els_logo.els_logo_pyld)
+ dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+ elsio->u.els_logo.els_logo_pyld,
+ elsio->u.els_logo.els_logo_pyld_dma);
+
+ del_timer(&elsio->timer);
+ qla2x00_rel_sp(vha, sp);
+}
+
+static void
+qla2x00_els_dcmd_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags = 0;
+
+ ql_dbg(ql_dbg_io, vha, 0x3069,
+ "%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
+ sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa);
+
+ /* Abort the exchange */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ if (ha->isp_ops->abort_command(sp)) {
+ ql_dbg(ql_dbg_io, vha, 0x3070,
+ "mbx abort_command failed.\n");
+ } else {
+ ql_dbg(ql_dbg_io, vha, 0x3071,
+ "mbx abort_command success.\n");
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ complete(&lio->u.els_logo.comp);
+}
+
+static void
+qla2x00_els_dcmd_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ fc_port_t *fcport = sp->fcport;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ struct scsi_qla_host *vha = fcport->vha;
+
+ ql_dbg(ql_dbg_io, vha, 0x3072,
+ "%s hdl=%x, portid=%02x%02x%02x done\n",
+ sp->name, sp->handle, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ complete(&lio->u.els_logo.comp);
+}
+
+int
+qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
+ port_id_t remote_did)
+{
+ srb_t *sp;
+ fc_port_t *fcport = NULL;
+ struct srb_iocb *elsio = NULL;
+ struct qla_hw_data *ha = vha->hw;
+ struct els_logo_payload logo_pyld;
+ int rval = QLA_SUCCESS;
+
+ fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (!fcport) {
+ ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp) {
+ kfree(fcport);
+ ql_log(ql_log_info, vha, 0x70e6,
+ "SRB allocation failed\n");
+ return -ENOMEM;
+ }
+
+ elsio = &sp->u.iocb_cmd;
+ fcport->loop_id = 0xFFFF;
+ fcport->d_id.b.domain = remote_did.b.domain;
+ fcport->d_id.b.area = remote_did.b.area;
+ fcport->d_id.b.al_pa = remote_did.b.al_pa;
+
+ ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n",
+ fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ sp->type = SRB_ELS_DCMD;
+ sp->name = "ELS_DCMD";
+ sp->fcport = fcport;
+ qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
+ elsio->timeout = qla2x00_els_dcmd_iocb_timeout;
+ sp->done = qla2x00_els_dcmd_sp_done;
+ sp->free = qla2x00_els_dcmd_sp_free;
+
+ elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev,
+ DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma,
+ GFP_KERNEL);
+
+ if (!elsio->u.els_logo.els_logo_pyld) {
+ sp->free(vha, sp);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ memset(&logo_pyld, 0, sizeof(struct els_logo_payload));
+
+ elsio->u.els_logo.els_cmd = els_opcode;
+ logo_pyld.opcode = els_opcode;
+ logo_pyld.s_id[0] = vha->d_id.b.al_pa;
+ logo_pyld.s_id[1] = vha->d_id.b.area;
+ logo_pyld.s_id[2] = vha->d_id.b.domain;
+ host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t));
+ memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE);
+
+ memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld,
+ sizeof(struct els_logo_payload));
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ sp->free(vha, sp);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_io, vha, 0x3074,
+ "%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n",
+ sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa);
+
+ wait_for_completion(&elsio->u.els_logo.comp);
+
+ sp->free(vha, sp);
+ return rval;
+}
+
+static void
+qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
+{
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ els_iocb->entry_type = ELS_IOCB_TYPE;
+ els_iocb->entry_count = 1;
+ els_iocb->sys_define = 0;
+ els_iocb->entry_status = 0;
+ els_iocb->handle = sp->handle;
+ els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+ els_iocb->tx_dsd_count = 1;
+ els_iocb->vp_index = vha->vp_idx;
+ els_iocb->sof_type = EST_SOFI3;
+ els_iocb->rx_dsd_count = 0;
+ els_iocb->opcode = elsio->u.els_logo.els_cmd;
+
+ els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
+ els_iocb->port_id[1] = sp->fcport->d_id.b.area;
+ els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ els_iocb->control_flags = 0;
+
+ els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
+ els_iocb->tx_address[0] =
+ cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_address[1] =
+ cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
+
+ els_iocb->rx_byte_count = 0;
+ els_iocb->rx_address[0] = 0;
+ els_iocb->rx_address[1] = 0;
+ els_iocb->rx_len = 0;
+
+ sp->fcport->vha->qla_stats.control_requests++;
+}
+
+static void
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
{
struct fc_bsg_job *bsg_job = sp->u.bsg_job;
@@ -2623,6 +2808,9 @@ qla2x00_start_sp(srb_t *sp)
qlafx00_abort_iocb(sp, pkt) :
qla24xx_abort_iocb(sp, pkt);
break;
+ case SRB_ELS_DCMD:
+ qla24xx_els_logo_iocb(sp, pkt);
+ break;
default:
break;
}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 0e59731f9..4af95479a 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -18,6 +18,10 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
sts_entry_t *);
+static void qla_irq_affinity_notify(struct irq_affinity_notify *,
+ const cpumask_t *);
+static void qla_irq_affinity_release(struct kref *);
+
/**
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -1418,6 +1422,12 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
case SRB_CT_CMD:
type = "ct pass-through";
break;
+ case SRB_ELS_DCMD:
+ type = "Driver ELS logo";
+ ql_dbg(ql_dbg_user, vha, 0x5047,
+ "Completing %s: (%p) type=%d.\n", type, sp, sp->type);
+ sp->done(vha, sp, 0);
+ return;
default:
ql_dbg(ql_dbg_user, vha, 0x503e,
"Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
@@ -2542,6 +2552,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
if (!vha->flags.online)
return;
+ if (rsp->msix->cpuid != smp_processor_id()) {
+ /* if kernel does not notify qla of IRQ's CPU change,
+ * then set it here.
+ */
+ rsp->msix->cpuid = smp_processor_id();
+ ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid;
+ }
+
while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
@@ -2587,8 +2605,14 @@ process_err:
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
break;
case ABTS_RECV_24XX:
- /* ensure that the ATIO queue is empty */
- qlt_24xx_process_atio_queue(vha);
+ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
+ /* ensure that the ATIO queue is empty */
+ qlt_handle_abts_recv(vha, (response_t *)pkt);
+ break;
+ } else {
+ /* drop through */
+ qlt_24xx_process_atio_queue(vha, 1);
+ }
case ABTS_RESP_24XX:
case CTIO_TYPE7:
case NOTIFY_ACK_TYPE:
@@ -2755,13 +2779,22 @@ qla24xx_intr_handler(int irq, void *dev_id)
case INTR_RSP_QUE_UPDATE_83XX:
qla24xx_process_response_queue(vha, rsp);
break;
- case INTR_ATIO_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ case INTR_ATIO_QUE_UPDATE:{
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
break;
- case INTR_ATIO_RSP_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ }
+ case INTR_ATIO_RSP_QUE_UPDATE: {
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
qla24xx_process_response_queue(vha, rsp);
break;
+ }
default:
ql_dbg(ql_dbg_async, vha, 0x504f,
"Unrecognized interrupt type (%d).\n", stat * 0xff);
@@ -2920,13 +2953,22 @@ qla24xx_msix_default(int irq, void *dev_id)
case INTR_RSP_QUE_UPDATE_83XX:
qla24xx_process_response_queue(vha, rsp);
break;
- case INTR_ATIO_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ case INTR_ATIO_QUE_UPDATE:{
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
break;
- case INTR_ATIO_RSP_QUE_UPDATE:
- qlt_24xx_process_atio_queue(vha);
+ }
+ case INTR_ATIO_RSP_QUE_UPDATE: {
+ unsigned long flags2;
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
+ qlt_24xx_process_atio_queue(vha, 1);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
+
qla24xx_process_response_queue(vha, rsp);
break;
+ }
default:
ql_dbg(ql_dbg_async, vha, 0x5051,
"Unrecognized interrupt type (%d).\n", stat & 0xff);
@@ -2973,8 +3015,11 @@ qla24xx_disable_msix(struct qla_hw_data *ha)
for (i = 0; i < ha->msix_count; i++) {
qentry = &ha->msix_entries[i];
- if (qentry->have_irq)
+ if (qentry->have_irq) {
+ /* un-register irq cpu affinity notification */
+ irq_set_affinity_notifier(qentry->vector, NULL);
free_irq(qentry->vector, qentry->rsp);
+ }
}
pci_disable_msix(ha->pdev);
kfree(ha->msix_entries);
@@ -3037,6 +3082,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
qentry->entry = entries[i].entry;
qentry->have_irq = 0;
qentry->rsp = NULL;
+ qentry->irq_notify.notify = qla_irq_affinity_notify;
+ qentry->irq_notify.release = qla_irq_affinity_release;
+ qentry->cpuid = -1;
}
/* Enable MSI-X vectors for the base queue */
@@ -3055,6 +3103,18 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
qentry->have_irq = 1;
qentry->rsp = rsp;
rsp->msix = qentry;
+
+ /* Register for CPU affinity notification. */
+ irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);
+
+ /* Schedule work (ie. trigger a notification) to read cpu
+ * mask for this specific irq.
+ * kref_get is required because
+ * irq_affinity_notify() will do
+ * kref_put().
+ */
+ kref_get(&qentry->irq_notify.kref);
+ schedule_work(&qentry->irq_notify.work);
}
/*
@@ -3234,3 +3294,47 @@ int qla25xx_request_irq(struct rsp_que *rsp)
msix->rsp = rsp;
return ret;
}
+
+
+/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */
+static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
+ const cpumask_t *mask)
+{
+ struct qla_msix_entry *e =
+ container_of(notify, struct qla_msix_entry, irq_notify);
+ struct qla_hw_data *ha;
+ struct scsi_qla_host *base_vha;
+
+ /* user is recommended to set mask to just 1 cpu */
+ e->cpuid = cpumask_first(mask);
+
+ ha = e->rsp->hw;
+ base_vha = pci_get_drvdata(ha->pdev);
+
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host %ld : vector %d cpu %d \n", __func__,
+ base_vha->host_no, e->vector, e->cpuid);
+
+ if (e->have_irq) {
+ if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
+ (e->entry == QLA83XX_RSPQ_MSIX_ENTRY_NUMBER)) {
+ ha->tgt.rspq_vector_cpuid = e->cpuid;
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host%ld: rspq vector %d cpu %d runtime change\n",
+ __func__, base_vha->host_no, e->vector, e->cpuid);
+ }
+ }
+}
+
+static void qla_irq_affinity_release(struct kref *ref)
+{
+ struct irq_affinity_notify *notify =
+ container_of(ref, struct irq_affinity_notify, kref);
+ struct qla_msix_entry *e =
+ container_of(notify, struct qla_msix_entry, irq_notify);
+ struct scsi_qla_host *base_vha = pci_get_drvdata(e->rsp->hw->pdev);
+
+ ql_dbg(ql_dbg_init, base_vha, 0xffff,
+ "%s: host%ld: vector %d cpu %d \n", __func__,
+ base_vha->host_no, e->vector, e->cpuid);
+}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index cb11e04be..87e675830 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -489,6 +489,13 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
EXTENDED_BB_CREDITS);
} else
mcp->mb[4] = 0;
+
+ if (ha->flags.exlogins_enabled)
+ mcp->mb[4] |= ENABLE_EXTENDED_LOGIN;
+
+ if (ha->flags.exchoffld_enabled)
+ mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD;
+
mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
mcp->in_mb |= MBX_1;
} else {
@@ -521,6 +528,226 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
}
/*
+ * qla_get_exlogin_status
+ * Get extended login status
+ * uses the memory offload control/status Mailbox
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * fwopt: firmware options
+ *
+ * Returns:
+ * qla2x00 local function status
+ *
+ * Context:
+ * Kernel context.
+ */
+#define FETCH_XLOGINS_STAT 0x8
+int
+qla_get_exlogin_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+ uint16_t *ex_logins_cnt)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118f,
+ "Entered %s\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = FETCH_XLOGINS_STAT;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_10|MBX_4|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1115, "Failed=%x.\n", rval);
+ } else {
+ *buf_sz = mcp->mb[4];
+ *ex_logins_cnt = mcp->mb[10];
+
+ ql_log(ql_log_info, vha, 0x1190,
+ "buffer size 0x%x, exchange login count=%d\n",
+ mcp->mb[4], mcp->mb[10]);
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1116,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_set_exlogin_mem_cfg
+ * set extended login memory configuration
+ * Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * buffer: buffer pointer
+ * phys_addr: physical address of buffer
+ * size: size of buffer
+ * TARGET_QUEUE_LOCK must be released
+ * ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ * qla2x00 local funxtion status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+#define CONFIG_XLOGINS_MEM 0x3
+int
+qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+ int configured_count;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111a,
+ "Entered %s.\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = CONFIG_XLOGINS_MEM;
+ mcp->mb[2] = MSW(phys_addr);
+ mcp->mb[3] = LSW(phys_addr);
+ mcp->mb[6] = MSW(MSD(phys_addr));
+ mcp->mb[7] = LSW(MSD(phys_addr));
+ mcp->mb[8] = MSW(ha->exlogin_size);
+ mcp->mb[9] = LSW(ha->exlogin_size);
+ mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_11|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ ql_dbg(ql_dbg_mbx, vha, 0x111b, "Failed=%x.\n", rval);
+ } else {
+ configured_count = mcp->mb[11];
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_get_exchoffld_status
+ * Get exchange offload status
+ * uses the memory offload control/status Mailbox
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * fwopt: firmware options
+ *
+ * Returns:
+ * qla2x00 local function status
+ *
+ * Context:
+ * Kernel context.
+ */
+#define FETCH_XCHOFFLD_STAT 0x2
+int
+qla_get_exchoffld_status(scsi_qla_host_t *vha, uint16_t *buf_sz,
+ uint16_t *ex_logins_cnt)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1019,
+ "Entered %s\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = FETCH_XCHOFFLD_STAT;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_10|MBX_4|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1155, "Failed=%x.\n", rval);
+ } else {
+ *buf_sz = mcp->mb[4];
+ *ex_logins_cnt = mcp->mb[10];
+
+ ql_log(ql_log_info, vha, 0x118e,
+ "buffer size 0x%x, exchange offload count=%d\n",
+ mcp->mb[4], mcp->mb[10]);
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1156,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qla_set_exchoffld_mem_cfg
+ * Set exchange offload memory configuration
+ * Mbx needs to be issues before init_cb is set
+ *
+ * Input:
+ * ha: adapter state pointer.
+ * buffer: buffer pointer
+ * phys_addr: physical address of buffer
+ * size: size of buffer
+ * TARGET_QUEUE_LOCK must be released
+ * ADAPTER_STATE_LOCK must be release
+ *
+ * Returns:
+ * qla2x00 local funxtion status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+#define CONFIG_XCHOFFLD_MEM 0x3
+int
+qla_set_exchoffld_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1157,
+ "Entered %s.\n", __func__);
+
+ memset(mcp->mb, 0 , sizeof(mcp->mb));
+ mcp->mb[0] = MBC_GET_MEM_OFFLOAD_CNTRL_STAT;
+ mcp->mb[1] = CONFIG_XCHOFFLD_MEM;
+ mcp->mb[2] = MSW(phys_addr);
+ mcp->mb[3] = LSW(phys_addr);
+ mcp->mb[6] = MSW(MSD(phys_addr));
+ mcp->mb[7] = LSW(MSD(phys_addr));
+ mcp->mb[8] = MSW(ha->exlogin_size);
+ mcp->mb[9] = LSW(ha->exlogin_size);
+ mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_11|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ ql_dbg(ql_dbg_mbx, vha, 0x1158, "Failed=%x.\n", rval);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1192,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
* qla2x00_get_fw_version
* Get firmware version.
*
@@ -594,6 +821,16 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x112f,
"%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n",
__func__, mcp->mb[17], mcp->mb[16]);
+
+ if (ha->fw_attributes_h & 0x4)
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118d,
+ "%s: Firmware supports Extended Login 0x%x\n",
+ __func__, ha->fw_attributes_h);
+
+ if (ha->fw_attributes_h & 0x8)
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1191,
+ "%s: Firmware supports Exchange Offload 0x%x\n",
+ __func__, ha->fw_attributes_h);
}
if (IS_QLA27XX(ha)) {
@@ -2383,10 +2620,9 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma,
* Kernel context.
*/
int
-qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
- uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
- uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports, uint16_t *max_fcfs)
+qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
{
+ struct qla_hw_data *ha = vha->hw;
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
@@ -2414,19 +2650,16 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt,
mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10],
mcp->mb[11], mcp->mb[12]);
- if (cur_xchg_cnt)
- *cur_xchg_cnt = mcp->mb[3];
- if (orig_xchg_cnt)
- *orig_xchg_cnt = mcp->mb[6];
- if (cur_iocb_cnt)
- *cur_iocb_cnt = mcp->mb[7];
- if (orig_iocb_cnt)
- *orig_iocb_cnt = mcp->mb[10];
- if (vha->hw->flags.npiv_supported && max_npiv_vports)
- *max_npiv_vports = mcp->mb[11];
- if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw) ||
- IS_QLA27XX(vha->hw)) && max_fcfs)
- *max_fcfs = mcp->mb[12];
+ ha->orig_fw_tgt_xcb_count = mcp->mb[1];
+ ha->cur_fw_tgt_xcb_count = mcp->mb[2];
+ ha->cur_fw_xcb_count = mcp->mb[3];
+ ha->orig_fw_xcb_count = mcp->mb[6];
+ ha->cur_fw_iocb_count = mcp->mb[7];
+ ha->orig_fw_iocb_count = mcp->mb[10];
+ if (ha->flags.npiv_supported)
+ ha->max_npiv_vports = mcp->mb[11];
+ if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+ ha->fw_max_fcf_count = mcp->mb[12];
}
return (rval);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 38dc318c6..39f084d2b 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -221,6 +221,18 @@ MODULE_PARM_DESC(ql2xmdenable,
"0 - MiniDump disabled. "
"1 (Default) - MiniDump enabled.");
+int ql2xexlogins = 0;
+module_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexlogins,
+ "Number of extended Logins. "
+ "0 (Default)- Disabled.");
+
+int ql2xexchoffld = 0;
+module_param(ql2xexchoffld, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xexchoffld,
+ "Number of exchanges to offload. "
+ "0 (Default)- Disabled.");
+
/*
* SCSI host template entry points
*/
@@ -2330,6 +2342,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->tgt.enable_class_2 = ql2xenableclass2;
INIT_LIST_HEAD(&ha->tgt.q_full_list);
spin_lock_init(&ha->tgt.q_full_lock);
+ spin_lock_init(&ha->tgt.sess_lock);
+ spin_lock_init(&ha->tgt.atio_lock);
+
/* Clear our data area */
ha->bars = bars;
@@ -2474,7 +2489,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_83XX;
- rsp_length = RESPONSE_ENTRY_CNT_2300;
+ rsp_length = RESPONSE_ENTRY_CNT_83XX;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -2504,8 +2519,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->portnum = PCI_FUNC(ha->pdev->devfn);
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
- req_length = REQUEST_ENTRY_CNT_24XX;
- rsp_length = RESPONSE_ENTRY_CNT_2300;
+ req_length = REQUEST_ENTRY_CNT_83XX;
+ rsp_length = RESPONSE_ENTRY_CNT_83XX;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
@@ -3134,6 +3149,14 @@ qla2x00_remove_one(struct pci_dev *pdev)
base_vha->flags.online = 0;
+ /* free DMA memory */
+ if (ha->exlogin_buf)
+ qla2x00_free_exlogin_buffer(ha);
+
+ /* free DMA memory */
+ if (ha->exchoffld_buf)
+ qla2x00_free_exchoffld_buffer(ha);
+
qla2x00_destroy_deferred_work(ha);
qlt_remove_target(ha, base_vha);
@@ -3593,6 +3616,140 @@ fail:
return -ENOMEM;
}
+int
+qla2x00_set_exlogins_buffer(scsi_qla_host_t *vha)
+{
+ int rval;
+ uint16_t size, max_cnt, temp;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Return if we don't need to alloacate any extended logins */
+ if (!ql2xexlogins)
+ return QLA_SUCCESS;
+
+ ql_log(ql_log_info, vha, 0xd021, "EXLOGIN count: %d.\n", ql2xexlogins);
+ max_cnt = 0;
+ rval = qla_get_exlogin_status(vha, &size, &max_cnt);
+ if (rval != QLA_SUCCESS) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd029,
+ "Failed to get exlogin status.\n");
+ return rval;
+ }
+
+ temp = (ql2xexlogins > max_cnt) ? max_cnt : ql2xexlogins;
+ ha->exlogin_size = (size * temp);
+ ql_log(ql_log_info, vha, 0xd024,
+ "EXLOGIN: max_logins=%d, portdb=0x%x, total=%d.\n",
+ max_cnt, size, temp);
+
+ ql_log(ql_log_info, vha, 0xd025, "EXLOGIN: requested size=0x%x\n",
+ ha->exlogin_size);
+
+ /* Get consistent memory for extended logins */
+ ha->exlogin_buf = dma_alloc_coherent(&ha->pdev->dev,
+ ha->exlogin_size, &ha->exlogin_buf_dma, GFP_KERNEL);
+ if (!ha->exlogin_buf) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd02a,
+ "Failed to allocate memory for exlogin_buf_dma.\n");
+ return -ENOMEM;
+ }
+
+ /* Now configure the dma buffer */
+ rval = qla_set_exlogin_mem_cfg(vha, ha->exlogin_buf_dma);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0x00cf,
+ "Setup extended login buffer ****FAILED****.\n");
+ qla2x00_free_exlogin_buffer(ha);
+ }
+
+ return rval;
+}
+
+/*
+* qla2x00_free_exlogin_buffer
+*
+* Input:
+* ha = adapter block pointer
+*/
+void
+qla2x00_free_exlogin_buffer(struct qla_hw_data *ha)
+{
+ if (ha->exlogin_buf) {
+ dma_free_coherent(&ha->pdev->dev, ha->exlogin_size,
+ ha->exlogin_buf, ha->exlogin_buf_dma);
+ ha->exlogin_buf = NULL;
+ ha->exlogin_size = 0;
+ }
+}
+
+int
+qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha)
+{
+ int rval;
+ uint16_t size, max_cnt, temp;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Return if we don't need to alloacate any extended logins */
+ if (!ql2xexchoffld)
+ return QLA_SUCCESS;
+
+ ql_log(ql_log_info, vha, 0xd014,
+ "Exchange offload count: %d.\n", ql2xexlogins);
+
+ max_cnt = 0;
+ rval = qla_get_exchoffld_status(vha, &size, &max_cnt);
+ if (rval != QLA_SUCCESS) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd012,
+ "Failed to get exlogin status.\n");
+ return rval;
+ }
+
+ temp = (ql2xexchoffld > max_cnt) ? max_cnt : ql2xexchoffld;
+ ha->exchoffld_size = (size * temp);
+ ql_log(ql_log_info, vha, 0xd016,
+ "Exchange offload: max_count=%d, buffers=0x%x, total=%d.\n",
+ max_cnt, size, temp);
+
+ ql_log(ql_log_info, vha, 0xd017,
+ "Exchange Buffers requested size = 0x%x\n", ha->exchoffld_size);
+
+ /* Get consistent memory for extended logins */
+ ha->exchoffld_buf = dma_alloc_coherent(&ha->pdev->dev,
+ ha->exchoffld_size, &ha->exchoffld_buf_dma, GFP_KERNEL);
+ if (!ha->exchoffld_buf) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0xd013,
+ "Failed to allocate memory for exchoffld_buf_dma.\n");
+ return -ENOMEM;
+ }
+
+ /* Now configure the dma buffer */
+ rval = qla_set_exchoffld_mem_cfg(vha, ha->exchoffld_buf_dma);
+ if (rval) {
+ ql_log(ql_log_fatal, vha, 0xd02e,
+ "Setup exchange offload buffer ****FAILED****.\n");
+ qla2x00_free_exchoffld_buffer(ha);
+ }
+
+ return rval;
+}
+
+/*
+* qla2x00_free_exchoffld_buffer
+*
+* Input:
+* ha = adapter block pointer
+*/
+void
+qla2x00_free_exchoffld_buffer(struct qla_hw_data *ha)
+{
+ if (ha->exchoffld_buf) {
+ dma_free_coherent(&ha->pdev->dev, ha->exchoffld_size,
+ ha->exchoffld_buf, ha->exchoffld_buf_dma);
+ ha->exchoffld_buf = NULL;
+ ha->exchoffld_size = 0;
+ }
+}
+
/*
* qla2x00_free_fw_dump
* Frees fw dump stuff.
@@ -3772,6 +3929,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
INIT_LIST_HEAD(&vha->list);
INIT_LIST_HEAD(&vha->qla_cmd_list);
INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
+ INIT_LIST_HEAD(&vha->logo_list);
+ INIT_LIST_HEAD(&vha->plogi_ack_list);
spin_lock_init(&vha->work_lock);
spin_lock_init(&vha->cmd_list_lock);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 75514a15b..ee967becd 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -100,12 +100,12 @@ enum fcp_resp_rsp_codes {
*/
/* Predefs for callbacks handed to qla2xxx LLD */
static void qlt_24xx_atio_pkt(struct scsi_qla_host *ha,
- struct atio_from_isp *pkt);
+ struct atio_from_isp *pkt, uint8_t);
static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt);
static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
int fn, void *iocb, int flags);
static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd
- *cmd, struct atio_from_isp *atio, int ha_locked);
+ *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort);
static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
struct qla_tgt_srr_imm *imm, int ha_lock);
static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
@@ -118,10 +118,13 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha,
struct imm_ntfy_from_isp *ntfy,
uint32_t add_flags, uint16_t resp_code, int resp_code_valid,
uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan);
+static void qlt_send_term_imm_notif(struct scsi_qla_host *vha,
+ struct imm_ntfy_from_isp *imm, int ha_locked);
/*
* Global Variables
*/
static struct kmem_cache *qla_tgt_mgmt_cmd_cachep;
+static struct kmem_cache *qla_tgt_plogi_cachep;
static mempool_t *qla_tgt_mgmt_cmd_mempool;
static struct workqueue_struct *qla_tgt_wq;
static DEFINE_MUTEX(qla_tgt_mutex);
@@ -226,8 +229,8 @@ static inline void qlt_decr_num_pend_cmds(struct scsi_qla_host *vha)
spin_unlock_irqrestore(&vha->hw->tgt.q_full_lock, flags);
}
-static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
- struct atio_from_isp *atio)
+static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
+ struct atio_from_isp *atio, uint8_t ha_locked)
{
ql_dbg(ql_dbg_tgt, vha, 0xe072,
"%s: qla_target(%d): type %x ox_id %04x\n",
@@ -248,7 +251,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
atio->u.isp24.fcp_hdr.d_id[2]);
break;
}
- qlt_24xx_atio_pkt(host, atio);
+ qlt_24xx_atio_pkt(host, atio, ha_locked);
break;
}
@@ -271,7 +274,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
break;
}
}
- qlt_24xx_atio_pkt(host, atio);
+ qlt_24xx_atio_pkt(host, atio, ha_locked);
break;
}
@@ -282,7 +285,7 @@ static void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha,
break;
}
- return;
+ return false;
}
void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
@@ -389,6 +392,131 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt)
}
+/*
+ * All qlt_plogi_ack_t operations are protected by hardware_lock
+ */
+
+/*
+ * This is a zero-base ref-counting solution, since hardware_lock
+ * guarantees that ref_count is not modified concurrently.
+ * Upon successful return content of iocb is undefined
+ */
+static qlt_plogi_ack_t *
+qlt_plogi_ack_find_add(struct scsi_qla_host *vha, port_id_t *id,
+ struct imm_ntfy_from_isp *iocb)
+{
+ qlt_plogi_ack_t *pla;
+
+ list_for_each_entry(pla, &vha->plogi_ack_list, list) {
+ if (pla->id.b24 == id->b24) {
+ qlt_send_term_imm_notif(vha, &pla->iocb, 1);
+ pla->iocb = *iocb;
+ return pla;
+ }
+ }
+
+ pla = kmem_cache_zalloc(qla_tgt_plogi_cachep, GFP_ATOMIC);
+ if (!pla) {
+ ql_dbg(ql_dbg_async, vha, 0x5088,
+ "qla_target(%d): Allocation of plogi_ack failed\n",
+ vha->vp_idx);
+ return NULL;
+ }
+
+ pla->iocb = *iocb;
+ pla->id = *id;
+ list_add_tail(&pla->list, &vha->plogi_ack_list);
+
+ return pla;
+}
+
+static void qlt_plogi_ack_unref(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla)
+{
+ BUG_ON(!pla->ref_count);
+ pla->ref_count--;
+
+ if (pla->ref_count)
+ return;
+
+ ql_dbg(ql_dbg_async, vha, 0x5089,
+ "Sending PLOGI ACK to wwn %8phC s_id %02x:%02x:%02x loop_id %#04x"
+ " exch %#x ox_id %#x\n", pla->iocb.u.isp24.port_name,
+ pla->iocb.u.isp24.port_id[2], pla->iocb.u.isp24.port_id[1],
+ pla->iocb.u.isp24.port_id[0],
+ le16_to_cpu(pla->iocb.u.isp24.nport_handle),
+ pla->iocb.u.isp24.exchange_address, pla->iocb.ox_id);
+ qlt_send_notify_ack(vha, &pla->iocb, 0, 0, 0, 0, 0, 0);
+
+ list_del(&pla->list);
+ kmem_cache_free(qla_tgt_plogi_cachep, pla);
+}
+
+static void
+qlt_plogi_ack_link(struct scsi_qla_host *vha, qlt_plogi_ack_t *pla,
+ struct qla_tgt_sess *sess, qlt_plogi_link_t link)
+{
+ /* Inc ref_count first because link might already be pointing at pla */
+ pla->ref_count++;
+
+ if (sess->plogi_link[link])
+ qlt_plogi_ack_unref(vha, sess->plogi_link[link]);
+
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf097,
+ "Linking sess %p [%d] wwn %8phC with PLOGI ACK to wwn %8phC"
+ " s_id %02x:%02x:%02x, ref=%d\n", sess, link, sess->port_name,
+ pla->iocb.u.isp24.port_name, pla->iocb.u.isp24.port_id[2],
+ pla->iocb.u.isp24.port_id[1], pla->iocb.u.isp24.port_id[0],
+ pla->ref_count);
+
+ sess->plogi_link[link] = pla;
+}
+
+typedef struct {
+ /* These fields must be initialized by the caller */
+ port_id_t id;
+ /*
+ * number of cmds dropped while we were waiting for
+ * initiator to ack LOGO initialize to 1 if LOGO is
+ * triggered by a command, otherwise, to 0
+ */
+ int cmd_count;
+
+ /* These fields are used by callee */
+ struct list_head list;
+} qlt_port_logo_t;
+
+static void
+qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
+{
+ qlt_port_logo_t *tmp;
+ int res;
+
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+
+ list_for_each_entry(tmp, &vha->logo_list, list) {
+ if (tmp->id.b24 == logo->id.b24) {
+ tmp->cmd_count += logo->cmd_count;
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+ return;
+ }
+ }
+
+ list_add_tail(&logo->list, &vha->logo_list);
+
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+ res = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, logo->id);
+
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+ list_del(&logo->list);
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf098,
+ "Finished LOGO to %02x:%02x:%02x, dropped %d cmds, res = %#x\n",
+ logo->id.b.domain, logo->id.b.area, logo->id.b.al_pa,
+ logo->cmd_count, res);
+}
+
static void qlt_free_session_done(struct work_struct *work)
{
struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess,
@@ -402,14 +530,21 @@ static void qlt_free_session_done(struct work_struct *work)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf084,
"%s: se_sess %p / sess %p from port %8phC loop_id %#04x"
- " s_id %02x:%02x:%02x logout %d keep %d plogi %d\n",
+ " s_id %02x:%02x:%02x logout %d keep %d els_logo %d\n",
__func__, sess->se_sess, sess, sess->port_name, sess->loop_id,
sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
sess->logout_on_delete, sess->keep_nport_handle,
- sess->plogi_ack_needed);
+ sess->send_els_logo);
BUG_ON(!tgt);
+ if (sess->send_els_logo) {
+ qlt_port_logo_t logo;
+ logo.id = sess->s_id;
+ logo.cmd_count = 0;
+ qlt_send_first_logo(vha, &logo);
+ }
+
if (sess->logout_on_delete) {
int rc;
@@ -455,9 +590,34 @@ static void qlt_free_session_done(struct work_struct *work)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (sess->plogi_ack_needed)
- qlt_send_notify_ack(vha, &sess->tm_iocb,
- 0, 0, 0, 0, 0, 0);
+ {
+ qlt_plogi_ack_t *own =
+ sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
+ qlt_plogi_ack_t *con =
+ sess->plogi_link[QLT_PLOGI_LINK_CONFLICT];
+
+ if (con) {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf099,
+ "se_sess %p / sess %p port %8phC is gone,"
+ " %s (ref=%d), releasing PLOGI for %8phC (ref=%d)\n",
+ sess->se_sess, sess, sess->port_name,
+ own ? "releasing own PLOGI" :
+ "no own PLOGI pending",
+ own ? own->ref_count : -1,
+ con->iocb.u.isp24.port_name, con->ref_count);
+ qlt_plogi_ack_unref(vha, con);
+ } else {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09a,
+ "se_sess %p / sess %p port %8phC is gone, %s (ref=%d)\n",
+ sess->se_sess, sess, sess->port_name,
+ own ? "releasing own PLOGI" :
+ "no own PLOGI pending",
+ own ? own->ref_count : -1);
+ }
+
+ if (own)
+ qlt_plogi_ack_unref(vha, own);
+ }
list_del(&sess->sess_list_entry);
@@ -476,7 +636,7 @@ static void qlt_free_session_done(struct work_struct *work)
wake_up_all(&tgt->waitQ);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
void qlt_unreg_sess(struct qla_tgt_sess *sess)
{
struct scsi_qla_host *vha = sess->vha;
@@ -492,7 +652,7 @@ void qlt_unreg_sess(struct qla_tgt_sess *sess)
}
EXPORT_SYMBOL(qlt_unreg_sess);
-/* ha->hardware_lock supposed to be held on entry */
+
static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
{
struct qla_hw_data *ha = vha->hw;
@@ -502,12 +662,15 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
int res = 0;
struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb;
struct atio_from_isp *a = (struct atio_from_isp *)iocb;
+ unsigned long flags;
loop_id = le16_to_cpu(n->u.isp24.nport_handle);
if (loop_id == 0xFFFF) {
/* Global event */
atomic_inc(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
qlt_clear_tgt_db(vha->vha_tgt.qla_tgt);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
#if 0 /* FIXME: do we need to choose a session here? */
if (!list_empty(&ha->tgt.qla_tgt->sess_list)) {
sess = list_entry(ha->tgt.qla_tgt->sess_list.next,
@@ -534,7 +697,9 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
sess = NULL;
#endif
} else {
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
ql_dbg(ql_dbg_tgt, vha, 0xe000,
@@ -556,7 +721,7 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd)
iocb, QLA24XX_MGMT_SEND_NACK);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
bool immediate)
{
@@ -600,7 +765,7 @@ static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess,
sess->expires - jiffies);
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_clear_tgt_db(struct qla_tgt *tgt)
{
struct qla_tgt_sess *sess;
@@ -636,12 +801,12 @@ static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id,
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045,
"qla_target(%d): get_id_list() failed: %x\n",
vha->vp_idx, rc);
- res = -1;
+ res = -EBUSY;
goto out_free_id_list;
}
id_iter = (char *)gid_list;
- res = -1;
+ res = -ENOENT;
for (i = 0; i < entries; i++) {
struct gid_list_info *gid = (struct gid_list_info *)id_iter;
if ((gid->al_pa == s_id[2]) &&
@@ -660,7 +825,7 @@ out_free_id_list:
return res;
}
-/* ha->hardware_lock supposed to be held on entry */
+/* ha->tgt.sess_lock supposed to be held on entry */
static void qlt_undelete_sess(struct qla_tgt_sess *sess)
{
BUG_ON(sess->deleted != QLA_SESS_DELETION_PENDING);
@@ -678,7 +843,7 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
struct qla_tgt_sess *sess;
unsigned long flags, elapsed;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
while (!list_empty(&tgt->del_sess_list)) {
sess = list_entry(tgt->del_sess_list.next, typeof(*sess),
del_list_entry);
@@ -699,7 +864,7 @@ static void qlt_del_sess_work_fn(struct delayed_work *work)
break;
}
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
/*
@@ -717,7 +882,7 @@ static struct qla_tgt_sess *qlt_create_sess(
unsigned char be_sid[3];
/* Check to avoid double sessions */
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
list_for_each_entry(sess, &vha->vha_tgt.qla_tgt->sess_list,
sess_list_entry) {
if (!memcmp(sess->port_name, fcport->port_name, WWN_SIZE)) {
@@ -732,7 +897,7 @@ static struct qla_tgt_sess *qlt_create_sess(
/* Cannot undelete at this point */
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
- spin_unlock_irqrestore(&ha->hardware_lock,
+ spin_unlock_irqrestore(&ha->tgt.sess_lock,
flags);
return NULL;
}
@@ -749,12 +914,12 @@ static struct qla_tgt_sess *qlt_create_sess(
qlt_do_generation_tick(vha, &sess->generation);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return sess;
}
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
sess = kzalloc(sizeof(*sess), GFP_KERNEL);
if (!sess) {
@@ -799,7 +964,7 @@ static struct qla_tgt_sess *qlt_create_sess(
}
/*
* Take an extra reference to ->sess_kref here to handle qla_tgt_sess
- * access across ->hardware_lock reaquire.
+ * access across ->tgt.sess_lock reaquire.
*/
kref_get(&sess->se_sess->sess_kref);
@@ -807,11 +972,11 @@ static struct qla_tgt_sess *qlt_create_sess(
BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name));
memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name));
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list);
vha->vha_tgt.qla_tgt->sess_count++;
qlt_do_generation_tick(vha, &sess->generation);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
"qla_target(%d): %ssession for wwn %8phC (loop_id %d, "
@@ -842,23 +1007,23 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
if (qla_ini_mode_enabled(vha))
return;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (tgt->tgt_stop) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
}
sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_create_sess(vha, fcport, false);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
} else if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
/* Point of no return */
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
} else {
kref_get(&sess->se_sess->sess_kref);
@@ -887,7 +1052,7 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
sess->local = 0;
}
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
/*
@@ -899,6 +1064,7 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
{
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
struct qla_tgt_sess *sess;
+ unsigned long flags;
if (!vha->hw->tgt.tgt_ops)
return;
@@ -906,15 +1072,19 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
if (!tgt)
return;
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
if (tgt->tgt_stop) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return;
}
sess = qlt_find_sess_by_port_name(tgt, fcport->port_name);
if (!sess) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return;
}
if (max_gen - sess->generation < 0) {
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf092,
"Ignoring stale deletion request for se_sess %p / sess %p"
" for port %8phC, req_gen %d, sess_gen %d\n",
@@ -927,6 +1097,7 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
sess->local = 1;
qlt_schedule_sess_for_deletion(sess, false);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
}
static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -984,10 +1155,10 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
* Lock is needed, because we still can get an incoming packet.
*/
mutex_lock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
tgt->tgt_stop = 1;
qlt_clear_tgt_db(tgt);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
mutex_unlock(&vha->vha_tgt.tgt_mutex);
mutex_unlock(&qla_tgt_mutex);
@@ -1040,7 +1211,7 @@ void qlt_stop_phase2(struct qla_tgt *tgt)
mutex_lock(&vha->vha_tgt.tgt_mutex);
spin_lock_irqsave(&ha->hardware_lock, flags);
- while (tgt->irq_cmd_count != 0) {
+ while ((tgt->irq_cmd_count != 0) || (tgt->atio_irq_cmd_count != 0)) {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
udelay(2);
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1309,7 +1480,7 @@ static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
if (tag == cmd->atio.u.isp24.exchange_addr) {
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
spin_unlock(&vha->cmd_list_lock);
return 1;
}
@@ -1351,7 +1522,7 @@ static void abort_cmds_for_lun(struct scsi_qla_host *vha,
cmd_lun = scsilun_to_int(
(struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun);
if (cmd_key == key && cmd_lun == lun)
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
}
spin_unlock(&vha->cmd_list_lock);
}
@@ -1435,6 +1606,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
uint32_t tag = abts->exchange_addr_to_abort;
uint8_t s_id[3];
int rc;
+ unsigned long flags;
if (le32_to_cpu(abts->fcp_hdr_le.parameter) & ABTS_PARAM_ABORT_SEQ) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf053,
@@ -1462,6 +1634,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
s_id[1] = abts->fcp_hdr_le.s_id[1];
s_id[2] = abts->fcp_hdr_le.s_id[0];
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
if (!sess) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012,
@@ -1469,12 +1642,17 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
vha->vp_idx);
rc = qlt_sched_sess_work(vha->vha_tgt.qla_tgt,
QLA_TGT_SESS_WORK_ABORT, abts, sizeof(*abts));
+
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (rc != 0) {
qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED,
false);
}
return;
}
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false);
@@ -1560,15 +1738,15 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || mcmd->reset_count != ha->chip_reset) {
+ if (!vha->flags.online || mcmd->reset_count != ha->chip_reset) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
ql_dbg(ql_dbg_async, vha, 0xe100,
- "RESET-TMR active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), mcmd->reset_count,
- ha->chip_reset);
+ "RESET-TMR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ mcmd->reset_count, ha->chip_reset);
ha->tgt.tgt_ops->free_mcmd(mcmd);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return;
@@ -1578,7 +1756,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
qlt_send_notify_ack(vha, &mcmd->orig_iocb.imm_ntfy,
0, 0, 0, 0, 0, 0);
else {
- if (mcmd->se_cmd.se_tmr_req->function == TMR_ABORT_TASK)
+ if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX)
qlt_24xx_send_abts_resp(vha, &mcmd->orig_iocb.abts,
mcmd->fc_tm_rsp, false);
else
@@ -2487,7 +2665,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
/* no need to terminate. FW already freed exchange. */
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
else
- qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+ qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return 0;
}
@@ -2510,17 +2688,22 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || cmd->reset_count != ha->chip_reset) {
+ if (xmit_type == QLA_TGT_XMIT_STATUS)
+ vha->tgt_counters.core_qla_snd_status++;
+ else
+ vha->tgt_counters.core_qla_que_buf++;
+
+ if (!vha->flags.online || cmd->reset_count != ha->chip_reset) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
cmd->state = QLA_TGT_STATE_PROCESSED;
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
ql_dbg(ql_dbg_async, vha, 0xe101,
- "RESET-RSP active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), cmd->reset_count,
- ha->chip_reset);
+ "RESET-RSP online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ cmd->reset_count, ha->chip_reset);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return 0;
}
@@ -2651,18 +2834,18 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd)
spin_lock_irqsave(&ha->hardware_lock, flags);
- if (qla2x00_reset_active(vha) || (cmd->reset_count != ha->chip_reset) ||
+ if (!vha->flags.online || (cmd->reset_count != ha->chip_reset) ||
(cmd->sess && cmd->sess->deleted == QLA_SESS_DELETION_IN_PROGRESS)) {
/*
- * Either a chip reset is active or this request was from
+ * Either the port is not online or this request was from
* previous life, just abort the processing.
*/
cmd->state = QLA_TGT_STATE_NEED_DATA;
qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
ql_dbg(ql_dbg_async, vha, 0xe102,
- "RESET-XFR active/old-count/new-count = %d/%d/%d.\n",
- qla2x00_reset_active(vha), cmd->reset_count,
- ha->chip_reset);
+ "RESET-XFR online/active/old-count/new-count = %d/%d/%d/%d.\n",
+ vha->flags.online, qla2x00_reset_active(vha),
+ cmd->reset_count, ha->chip_reset);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return 0;
}
@@ -2957,12 +3140,13 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
ret = 1;
}
+ vha->tgt_counters.num_term_xchg_sent++;
pkt->entry_count = 1;
pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
ctio24 = (struct ctio7_to_24xx *)pkt;
ctio24->entry_type = CTIO_TYPE7;
- ctio24->nport_handle = cmd ? cmd->loop_id : CTIO7_NHANDLE_UNRECOGNIZED;
+ ctio24->nport_handle = CTIO7_NHANDLE_UNRECOGNIZED;
ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
ctio24->vp_index = vha->vp_idx;
ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2];
@@ -2989,7 +3173,8 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
}
static void qlt_send_term_exchange(struct scsi_qla_host *vha,
- struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
+ struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked,
+ int ul_abort)
{
unsigned long flags = 0;
int rc;
@@ -3009,8 +3194,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
qlt_alloc_qfull_cmd(vha, atio, 0, 0);
done:
- if (cmd && ((cmd->state != QLA_TGT_STATE_ABORTED) ||
- !cmd->cmd_sent_to_fw)) {
+ if (cmd && !ul_abort && !cmd->aborted) {
if (cmd->sg_mapped)
qlt_unmap_sg(vha, cmd);
vha->hw->tgt.tgt_ops->free_cmd(cmd);
@@ -3028,7 +3212,7 @@ static void qlt_init_term_exchange(struct scsi_qla_host *vha)
struct qla_tgt_cmd *cmd, *tcmd;
vha->hw->tgt.leak_exchg_thresh_hold =
- (vha->hw->fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
+ (vha->hw->cur_fw_xcb_count/100) * LEAK_EXCHG_THRESH_HOLD_PERCENT;
cmd = tcmd = NULL;
if (!list_empty(&vha->hw->tgt.q_full_list)) {
@@ -3058,7 +3242,7 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
ql_dbg(ql_dbg_tgt, vha, 0xe079,
"Chip reset due to exchange starvation: %d/%d.\n",
- total_leaked, vha->hw->fw_xcb_count);
+ total_leaked, vha->hw->cur_fw_xcb_count);
if (IS_P3P_TYPE(vha->hw))
set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
@@ -3069,21 +3253,38 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
}
-void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
+int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
{
struct qla_tgt *tgt = cmd->tgt;
struct scsi_qla_host *vha = tgt->vha;
struct se_cmd *se_cmd = &cmd->se_cmd;
+ unsigned long flags;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
"qla_target(%d): terminating exchange for aborted cmd=%p "
"(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
se_cmd->tag);
- cmd->state = QLA_TGT_STATE_ABORTED;
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
+ if (cmd->aborted) {
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ /*
+ * It's normal to see 2 calls in this path:
+ * 1) XFER Rdy completion + CMD_T_ABORT
+ * 2) TCM TMR - drain_state_list
+ */
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
+ "multiple abort. %p transport_state %x, t_state %x,"
+ " se_cmd_flags %x \n", cmd, cmd->se_cmd.transport_state,
+ cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
+ return EIO;
+ }
+ cmd->aborted = 1;
cmd->cmd_flags |= BIT_6;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
- qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
+ qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1);
+ return 0;
}
EXPORT_SYMBOL(qlt_abort_cmd);
@@ -3098,6 +3299,9 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
BUG_ON(cmd->cmd_in_wq);
+ if (cmd->sg_mapped)
+ qlt_unmap_sg(cmd->vha, cmd);
+
if (!cmd->q_full)
qlt_decr_num_pend_cmds(cmd->vha);
@@ -3215,7 +3419,7 @@ static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio,
term = 1;
if (term)
- qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+ qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
return term;
}
@@ -3300,9 +3504,6 @@ qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd)
ha->tgt.tgt_ops->handle_data(cmd);
return;
- } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
- ql_dbg(ql_dbg_io, vha, 0xff02,
- "HOST-ABORT: handle=%d, state=ABORTED.\n", handle);
} else {
ql_dbg(ql_dbg_io, vha, 0xff03,
"HOST-ABORT: handle=%d, state=BAD(%d).\n", handle,
@@ -3398,13 +3599,27 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
case CTIO_PORT_LOGGED_OUT:
case CTIO_PORT_UNAVAILABLE:
+ {
+ int logged_out =
+ (status & 0xFFFF) == CTIO_PORT_LOGGED_OUT;
+
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
- "qla_target(%d): CTIO with PORT LOGGED "
- "OUT (29) or PORT UNAVAILABLE (28) status %x "
+ "qla_target(%d): CTIO with %s status %x "
"received (state %x, se_cmd %p)\n", vha->vp_idx,
+ logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE",
status, cmd->state, se_cmd);
- break;
+ if (logged_out && cmd->sess) {
+ /*
+ * Session is already logged out, but we need
+ * to notify initiator, who's not aware of this
+ */
+ cmd->sess->logout_on_delete = 0;
+ cmd->sess->send_els_logo = 1;
+ qlt_schedule_sess_for_deletion(cmd->sess, true);
+ }
+ break;
+ }
case CTIO_SRR_RECEIVED:
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05a,
"qla_target(%d): CTIO with SRR_RECEIVED"
@@ -3454,14 +3669,14 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
}
- /* "cmd->state == QLA_TGT_STATE_ABORTED" means
+ /* "cmd->aborted" means
* cmd is already aborted/terminated, we don't
* need to terminate again. The exchange is already
* cleaned up/freed at FW level. Just cleanup at driver
* level.
*/
if ((cmd->state != QLA_TGT_STATE_NEED_DATA) &&
- (cmd->state != QLA_TGT_STATE_ABORTED)) {
+ (!cmd->aborted)) {
cmd->cmd_flags |= BIT_13;
if (qlt_term_ctio_exchange(vha, ctio, cmd, status))
return;
@@ -3479,7 +3694,7 @@ skip_term:
ha->tgt.tgt_ops->handle_data(cmd);
return;
- } else if (cmd->state == QLA_TGT_STATE_ABORTED) {
+ } else if (cmd->aborted) {
cmd->cmd_flags |= BIT_18;
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e,
"Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag);
@@ -3491,7 +3706,7 @@ skip_term:
}
if (unlikely(status != CTIO_SUCCESS) &&
- (cmd->state != QLA_TGT_STATE_ABORTED)) {
+ !cmd->aborted) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01f, "Finishing failed CTIO\n");
dump_stack();
}
@@ -3553,13 +3768,14 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
if (tgt->tgt_stop)
goto out_term;
- if (cmd->state == QLA_TGT_STATE_ABORTED) {
+ if (cmd->aborted) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
"cmd with tag %u is aborted\n",
cmd->atio.u.isp24.exchange_addr);
goto out_term;
}
+ spin_lock_init(&cmd->cmd_lock);
cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
cmd->unpacked_lun = scsilun_to_int(
@@ -3589,9 +3805,9 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
/*
* Drop extra session reference from qla_tgt_handle_cmd_for_atio*(
*/
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
out_term:
@@ -3602,12 +3818,15 @@ out_term:
*/
cmd->cmd_flags |= BIT_2;
spin_lock_irqsave(&ha->hardware_lock, flags);
- qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
+ qlt_send_term_exchange(vha, NULL, &cmd->atio, 1, 0);
qlt_decr_num_pend_cmds(vha);
percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
- ha->tgt.tgt_ops->put_sess(sess);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+ ha->tgt.tgt_ops->put_sess(sess);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
static void qlt_do_work(struct work_struct *work)
@@ -3692,10 +3911,8 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
goto out_term;
}
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has an extra creation ref. */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
if (!sess)
goto out_term;
@@ -3723,7 +3940,7 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
out_term:
spin_lock_irqsave(&ha->hardware_lock, flags);
- qlt_send_term_exchange(vha, NULL, &op->atio, 1);
+ qlt_send_term_exchange(vha, NULL, &op->atio, 1, 0);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
kfree(op);
@@ -3787,13 +4004,24 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
cmd->cmd_in_wq = 1;
cmd->cmd_flags |= BIT_0;
+ cmd->se_cmd.cpuid = ha->msix_count ?
+ ha->tgt.rspq_vector_cpuid : WORK_CPU_UNBOUND;
spin_lock(&vha->cmd_list_lock);
list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
spin_unlock(&vha->cmd_list_lock);
INIT_WORK(&cmd->work, qlt_do_work);
- queue_work(qla_tgt_wq, &cmd->work);
+ if (ha->msix_count) {
+ if (cmd->atio.u.isp24.fcp_cmnd.rddata)
+ queue_work_on(smp_processor_id(), qla_tgt_wq,
+ &cmd->work);
+ else
+ queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq,
+ &cmd->work);
+ } else {
+ queue_work(qla_tgt_wq, &cmd->work);
+ }
return 0;
}
@@ -3917,13 +4145,18 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb)
struct qla_tgt_sess *sess;
uint32_t lun, unpacked_lun;
int fn;
+ unsigned long flags;
tgt = vha->vha_tgt.qla_tgt;
lun = a->u.isp24.fcp_cmnd.lun;
fn = a->u.isp24.fcp_cmnd.task_mgmt_flags;
+
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
a->u.isp24.fcp_hdr.s_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
if (!sess) {
@@ -3987,10 +4220,14 @@ static int qlt_abort_task(struct scsi_qla_host *vha,
struct qla_hw_data *ha = vha->hw;
struct qla_tgt_sess *sess;
int loop_id;
+ unsigned long flags;
loop_id = GET_TARGET_ID(ha, (struct atio_from_isp *)iocb);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
if (sess == NULL) {
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf025,
"qla_target(%d): task abort for unexisting "
@@ -4022,15 +4259,6 @@ void qlt_logo_completion_handler(fc_port_t *fcport, int rc)
}
}
-static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
- struct imm_ntfy_from_isp *b)
-{
- struct imm_ntfy_from_isp tmp;
- memcpy(&tmp, a, sizeof(struct imm_ntfy_from_isp));
- memcpy(a, b, sizeof(struct imm_ntfy_from_isp));
- memcpy(b, &tmp, sizeof(struct imm_ntfy_from_isp));
-}
-
/*
* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list)
*
@@ -4040,11 +4268,13 @@ static void qlt_swap_imm_ntfy_iocb(struct imm_ntfy_from_isp *a,
*/
static struct qla_tgt_sess *
qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
- port_id_t port_id, uint16_t loop_id)
+ port_id_t port_id, uint16_t loop_id, struct qla_tgt_sess **conflict_sess)
{
struct qla_tgt_sess *sess = NULL, *other_sess;
uint64_t other_wwn;
+ *conflict_sess = NULL;
+
list_for_each_entry(other_sess, &tgt->sess_list, sess_list_entry) {
other_wwn = wwn_to_u64(other_sess->port_name);
@@ -4072,9 +4302,10 @@ qlt_find_sess_invalidate_other(struct qla_tgt *tgt, uint64_t wwn,
} else {
/*
* Another wwn used to have our s_id/loop_id
- * combo - kill the session, but don't log out
+ * kill the session, but don't free the loop_id
*/
- sess->logout_on_delete = 0;
+ other_sess->keep_nport_handle = 1;
+ *conflict_sess = other_sess;
qlt_schedule_sess_for_deletion(other_sess,
true);
}
@@ -4119,7 +4350,7 @@ static int abort_cmds_for_s_id(struct scsi_qla_host *vha, port_id_t *s_id)
list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
uint32_t cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
if (cmd_key == key) {
- cmd->state = QLA_TGT_STATE_ABORTED;
+ cmd->aborted = 1;
count++;
}
}
@@ -4136,12 +4367,14 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
{
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
struct qla_hw_data *ha = vha->hw;
- struct qla_tgt_sess *sess = NULL;
+ struct qla_tgt_sess *sess = NULL, *conflict_sess = NULL;
uint64_t wwn;
port_id_t port_id;
uint16_t loop_id;
uint16_t wd3_lo;
int res = 0;
+ qlt_plogi_ack_t *pla;
+ unsigned long flags;
wwn = wwn_to_u64(iocb->u.isp24.port_name);
@@ -4165,27 +4398,20 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
/* Mark all stale commands in qla_tgt_wq for deletion */
abort_cmds_for_s_id(vha, &port_id);
- if (wwn)
+ if (wwn) {
+ spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
sess = qlt_find_sess_invalidate_other(tgt, wwn,
- port_id, loop_id);
+ port_id, loop_id, &conflict_sess);
+ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+ }
- if (!sess || IS_SW_RESV_ADDR(sess->s_id)) {
+ if (IS_SW_RESV_ADDR(port_id) || (!sess && !conflict_sess)) {
res = 1;
break;
}
- if (sess->plogi_ack_needed) {
- /*
- * Initiator sent another PLOGI before last PLOGI could
- * finish. Swap plogi iocbs and terminate old one
- * without acking, new one will get acked when session
- * deletion completes.
- */
- ql_log(ql_log_warn, sess->vha, 0xf094,
- "sess %p received double plogi.\n", sess);
-
- qlt_swap_imm_ntfy_iocb(iocb, &sess->tm_iocb);
-
+ pla = qlt_plogi_ack_find_add(vha, &port_id, iocb);
+ if (!pla) {
qlt_send_term_imm_notif(vha, iocb, 1);
res = 0;
@@ -4194,13 +4420,14 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
res = 0;
- /*
- * Save immediate Notif IOCB for Ack when sess is done
- * and being deleted.
- */
- memcpy(&sess->tm_iocb, iocb, sizeof(sess->tm_iocb));
- sess->plogi_ack_needed = 1;
+ if (conflict_sess)
+ qlt_plogi_ack_link(vha, pla, conflict_sess,
+ QLT_PLOGI_LINK_CONFLICT);
+
+ if (!sess)
+ break;
+ qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN);
/*
* Under normal circumstances we want to release nport handle
* during LOGO process to avoid nport handle leaks inside FW.
@@ -4227,9 +4454,21 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
case ELS_PRLI:
wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo);
- if (wwn)
+ if (wwn) {
+ spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
sess = qlt_find_sess_invalidate_other(tgt, wwn, port_id,
- loop_id);
+ loop_id, &conflict_sess);
+ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, flags);
+ }
+
+ if (conflict_sess) {
+ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf09b,
+ "PRLI with conflicting sess %p port %8phC\n",
+ conflict_sess, conflict_sess->port_name);
+ qlt_send_term_imm_notif(vha, iocb, 1);
+ res = 0;
+ break;
+ }
if (sess != NULL) {
if (sess->deleted) {
@@ -4554,7 +4793,7 @@ out_reject:
dump_stack();
} else {
cmd->cmd_flags |= BIT_9;
- qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+ qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
@@ -4733,7 +4972,7 @@ static void qlt_prepare_srr_imm(struct scsi_qla_host *vha,
sctio, sctio->srr_id);
list_del(&sctio->srr_list_entry);
qlt_send_term_exchange(vha, sctio->cmd,
- &sctio->cmd->atio, 1);
+ &sctio->cmd->atio, 1, 0);
kfree(sctio);
}
}
@@ -4899,11 +5138,14 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
struct qla_hw_data *ha = vha->hw;
request_t *pkt;
struct qla_tgt_sess *sess = NULL;
+ unsigned long flags;
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
atio->u.isp24.fcp_hdr.s_id);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
if (!sess) {
- qlt_send_term_exchange(vha, NULL, atio, 1);
+ qlt_send_term_exchange(vha, NULL, atio, 1, 0);
return 0;
}
/* Sending marker isn't necessary, since we called from ISR */
@@ -4916,6 +5158,7 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
return -ENOMEM;
}
+ vha->tgt_counters.num_q_full_sent++;
pkt->entry_count = 1;
pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
@@ -5129,11 +5372,12 @@ qlt_chk_qfull_thresh_hold(struct scsi_qla_host *vha,
/* ha->hardware_lock supposed to be held on entry */
/* called via callback from qla2xxx */
static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
- struct atio_from_isp *atio)
+ struct atio_from_isp *atio, uint8_t ha_locked)
{
struct qla_hw_data *ha = vha->hw;
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
int rc;
+ unsigned long flags;
if (unlikely(tgt == NULL)) {
ql_dbg(ql_dbg_io, vha, 0x3064,
@@ -5145,7 +5389,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
* Otherwise, some commands can stuck.
*/
- tgt->irq_cmd_count++;
+ tgt->atio_irq_cmd_count++;
switch (atio->u.raw.entry_type) {
case ATIO_TYPE7:
@@ -5155,7 +5399,11 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
"qla_target(%d): ATIO_TYPE7 "
"received with UNKNOWN exchange address, "
"sending QUEUE_FULL\n", vha->vp_idx);
+ if (!ha_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_send_busy(vha, atio, SAM_STAT_TASK_SET_FULL);
+ if (!ha_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
break;
}
@@ -5164,7 +5412,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) {
rc = qlt_chk_qfull_thresh_hold(vha, atio);
if (rc != 0) {
- tgt->irq_cmd_count--;
+ tgt->atio_irq_cmd_count--;
return;
}
rc = qlt_handle_cmd_for_atio(vha, atio);
@@ -5173,11 +5421,20 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
}
if (unlikely(rc != 0)) {
if (rc == -ESRCH) {
+ if (!ha_locked)
+ spin_lock_irqsave
+ (&ha->hardware_lock, flags);
+
#if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
qlt_send_busy(vha, atio, SAM_STAT_BUSY);
#else
- qlt_send_term_exchange(vha, NULL, atio, 1);
+ qlt_send_term_exchange(vha, NULL, atio, 1, 0);
#endif
+
+ if (!ha_locked)
+ spin_unlock_irqrestore
+ (&ha->hardware_lock, flags);
+
} else {
if (tgt->tgt_stop) {
ql_dbg(ql_dbg_tgt, vha, 0xe059,
@@ -5189,7 +5446,13 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
"qla_target(%d): Unable to send "
"command to target, sending BUSY "
"status.\n", vha->vp_idx);
+ if (!ha_locked)
+ spin_lock_irqsave(
+ &ha->hardware_lock, flags);
qlt_send_busy(vha, atio, SAM_STAT_BUSY);
+ if (!ha_locked)
+ spin_unlock_irqrestore(
+ &ha->hardware_lock, flags);
}
}
}
@@ -5206,7 +5469,12 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
break;
}
ql_dbg(ql_dbg_tgt, vha, 0xe02e, "%s", "IMMED_NOTIFY ATIO");
+
+ if (!ha_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)atio);
+ if (!ha_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
break;
}
@@ -5217,7 +5485,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
break;
}
- tgt->irq_cmd_count--;
+ tgt->atio_irq_cmd_count--;
}
/* ha->hardware_lock supposed to be held on entry */
@@ -5277,7 +5545,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
#if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
qlt_send_busy(vha, atio, 0);
#else
- qlt_send_term_exchange(vha, NULL, atio, 1);
+ qlt_send_term_exchange(vha, NULL, atio, 1, 0);
#endif
} else {
if (tgt->tgt_stop) {
@@ -5286,7 +5554,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
"command to target, sending TERM "
"EXCHANGE for rsp\n");
qlt_send_term_exchange(vha, NULL,
- atio, 1);
+ atio, 1, 0);
} else {
ql_dbg(ql_dbg_tgt, vha, 0xe060,
"qla_target(%d): Unable to send "
@@ -5534,12 +5802,16 @@ static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *vha,
int rc, global_resets;
uint16_t loop_id = 0;
+ mutex_lock(&vha->vha_tgt.tgt_mutex);
+
retry:
global_resets =
atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
rc = qla24xx_get_loop_id(vha, s_id, &loop_id);
if (rc != 0) {
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
if ((s_id[0] == 0xFF) &&
(s_id[1] == 0xFC)) {
/*
@@ -5550,17 +5822,27 @@ retry:
"Unable to find initiator with S_ID %x:%x:%x",
s_id[0], s_id[1], s_id[2]);
} else
- ql_dbg(ql_dbg_tgt_mgt, vha, 0xf071,
+ ql_log(ql_log_info, vha, 0xf071,
"qla_target(%d): Unable to find "
"initiator with S_ID %x:%x:%x",
vha->vp_idx, s_id[0], s_id[1],
s_id[2]);
+
+ if (rc == -ENOENT) {
+ qlt_port_logo_t logo;
+ sid_to_portid(s_id, &logo.id);
+ logo.cmd_count = 1;
+ qlt_send_first_logo(vha, &logo);
+ }
+
return NULL;
}
fcport = qlt_get_port_database(vha, loop_id);
- if (!fcport)
+ if (!fcport) {
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
return NULL;
+ }
if (global_resets !=
atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) {
@@ -5575,6 +5857,8 @@ retry:
sess = qlt_create_sess(vha, fcport, true);
+ mutex_unlock(&vha->vha_tgt.tgt_mutex);
+
kfree(fcport);
return sess;
}
@@ -5585,15 +5869,15 @@ static void qlt_abort_work(struct qla_tgt *tgt,
struct scsi_qla_host *vha = tgt->vha;
struct qla_hw_data *ha = vha->hw;
struct qla_tgt_sess *sess = NULL;
- unsigned long flags;
+ unsigned long flags = 0, flags2 = 0;
uint32_t be_s_id;
uint8_t s_id[3];
int rc;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
if (tgt->tgt_stop)
- goto out_term;
+ goto out_term2;
s_id[0] = prm->abts.fcp_hdr_le.s_id[2];
s_id[1] = prm->abts.fcp_hdr_le.s_id[1];
@@ -5602,41 +5886,47 @@ static void qlt_abort_work(struct qla_tgt *tgt,
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
(unsigned char *)&be_s_id);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has got an extra creation ref */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags2);
if (!sess)
- goto out_term;
+ goto out_term2;
} else {
if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
sess = NULL;
- goto out_term;
+ goto out_term2;
}
kref_get(&sess->se_sess->sess_kref);
}
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
if (tgt->tgt_stop)
goto out_term;
rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess);
if (rc != 0)
goto out_term;
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
return;
+out_term2:
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
out_term:
qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2);
}
static void qlt_tmr_work(struct qla_tgt *tgt,
@@ -5653,7 +5943,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
int fn;
void *iocb;
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (tgt->tgt_stop)
goto out_term;
@@ -5661,14 +5951,12 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id;
sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id);
if (!sess) {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
- mutex_lock(&vha->vha_tgt.tgt_mutex);
sess = qlt_make_local_sess(vha, s_id);
/* sess has got an extra creation ref */
- mutex_unlock(&vha->vha_tgt.tgt_mutex);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
if (!sess)
goto out_term;
} else {
@@ -5690,14 +5978,14 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
goto out_term;
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
return;
out_term:
- qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1);
+ qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
if (sess)
ha->tgt.tgt_ops->put_sess(sess);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}
static void qlt_sess_work_fn(struct work_struct *work)
@@ -6002,6 +6290,7 @@ qlt_enable_vha(struct scsi_qla_host *vha)
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
unsigned long flags;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+ int rspq_ent = QLA83XX_RSPQ_MSIX_ENTRY_NUMBER;
if (!tgt) {
ql_dbg(ql_dbg_tgt, vha, 0xe069,
@@ -6020,6 +6309,17 @@ qlt_enable_vha(struct scsi_qla_host *vha)
qla24xx_disable_vp(vha);
qla24xx_enable_vp(vha);
} else {
+ if (ha->msix_entries) {
+ ql_dbg(ql_dbg_tgt, vha, 0xffff,
+ "%s: host%ld : vector %d cpu %d\n",
+ __func__, vha->host_no,
+ ha->msix_entries[rspq_ent].vector,
+ ha->msix_entries[rspq_ent].cpuid);
+
+ ha->tgt.rspq_vector_cpuid =
+ ha->msix_entries[rspq_ent].cpuid;
+ }
+
set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
qla2xxx_wake_dpc(base_vha);
qla2x00_wait_for_hba_online(base_vha);
@@ -6131,7 +6431,7 @@ qlt_init_atio_q_entries(struct scsi_qla_host *vha)
* @ha: SCSI driver HA context
*/
void
-qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
+qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked)
{
struct qla_hw_data *ha = vha->hw;
struct atio_from_isp *pkt;
@@ -6144,7 +6444,8 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha)
pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr;
cnt = pkt->u.raw.entry_count;
- qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt);
+ qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt,
+ ha_locked);
for (i = 0; i < cnt; i++) {
ha->tgt.atio_ring_index++;
@@ -6265,10 +6566,21 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha,
{
struct qla_hw_data *ha = vha->hw;
+ if (!QLA_TGT_MODE_ENABLED())
+ return;
+
if (ha->tgt.node_name_set) {
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
+
+ /* disable ZIO at start time. */
+ if (!vha->flags.init_done) {
+ uint32_t tmp;
+ tmp = le32_to_cpu(icb->firmware_options_2);
+ tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+ icb->firmware_options_2 = cpu_to_le32(tmp);
+ }
}
void
@@ -6359,6 +6671,15 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha,
memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE);
icb->firmware_options_1 |= cpu_to_le32(BIT_14);
}
+
+ /* disable ZIO at start time. */
+ if (!vha->flags.init_done) {
+ uint32_t tmp;
+ tmp = le32_to_cpu(icb->firmware_options_2);
+ tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+ icb->firmware_options_2 = cpu_to_le32(tmp);
+ }
+
}
void
@@ -6428,16 +6749,59 @@ qla83xx_msix_atio_q(int irq, void *dev_id)
ha = rsp->hw;
vha = pci_get_drvdata(ha->pdev);
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
- qlt_24xx_process_atio_queue(vha);
- qla24xx_process_response_queue(vha, rsp);
+ qlt_24xx_process_atio_queue(vha, 0);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
return IRQ_HANDLED;
}
+static void
+qlt_handle_abts_recv_work(struct work_struct *work)
+{
+ struct qla_tgt_sess_op *op = container_of(work,
+ struct qla_tgt_sess_op, work);
+ scsi_qla_host_t *vha = op->vha;
+ struct qla_hw_data *ha = vha->hw;
+ unsigned long flags;
+
+ if (qla2x00_reset_active(vha) || (op->chip_reset != ha->chip_reset))
+ return;
+
+ spin_lock_irqsave(&ha->tgt.atio_lock, flags);
+ qlt_24xx_process_atio_queue(vha, 0);
+ spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ qlt_response_pkt_all_vps(vha, (response_t *)&op->atio);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void
+qlt_handle_abts_recv(struct scsi_qla_host *vha, response_t *pkt)
+{
+ struct qla_tgt_sess_op *op;
+
+ op = kzalloc(sizeof(*op), GFP_ATOMIC);
+
+ if (!op) {
+ /* do not reach for ATIO queue here. This is best effort err
+ * recovery at this point.
+ */
+ qlt_response_pkt_all_vps(vha, pkt);
+ return;
+ }
+
+ memcpy(&op->atio, pkt, sizeof(*pkt));
+ op->vha = vha;
+ op->chip_reset = vha->hw->chip_reset;
+ INIT_WORK(&op->work, qlt_handle_abts_recv_work);
+ queue_work(qla_tgt_wq, &op->work);
+ return;
+}
+
int
qlt_mem_alloc(struct qla_hw_data *ha)
{
@@ -6532,13 +6896,25 @@ int __init qlt_init(void)
return -ENOMEM;
}
+ qla_tgt_plogi_cachep = kmem_cache_create("qla_tgt_plogi_cachep",
+ sizeof(qlt_plogi_ack_t),
+ __alignof__(qlt_plogi_ack_t),
+ 0, NULL);
+
+ if (!qla_tgt_plogi_cachep) {
+ ql_log(ql_log_fatal, NULL, 0xe06d,
+ "kmem_cache_create for qla_tgt_plogi_cachep failed\n");
+ ret = -ENOMEM;
+ goto out_mgmt_cmd_cachep;
+ }
+
qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab,
mempool_free_slab, qla_tgt_mgmt_cmd_cachep);
if (!qla_tgt_mgmt_cmd_mempool) {
ql_log(ql_log_fatal, NULL, 0xe06e,
"mempool_create for qla_tgt_mgmt_cmd_mempool failed\n");
ret = -ENOMEM;
- goto out_mgmt_cmd_cachep;
+ goto out_plogi_cachep;
}
qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0);
@@ -6555,6 +6931,8 @@ int __init qlt_init(void)
out_cmd_mempool:
mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+out_plogi_cachep:
+ kmem_cache_destroy(qla_tgt_plogi_cachep);
out_mgmt_cmd_cachep:
kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
return ret;
@@ -6567,5 +6945,6 @@ void qlt_exit(void)
destroy_workqueue(qla_tgt_wq);
mempool_destroy(qla_tgt_mgmt_cmd_mempool);
+ kmem_cache_destroy(qla_tgt_plogi_cachep);
kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep);
}
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index bca584ae4..22a6a767f 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -787,7 +787,7 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
#define QLA_TGT_STATE_NEED_DATA 1 /* target needs data to continue */
#define QLA_TGT_STATE_DATA_IN 2 /* Data arrived + target processing */
#define QLA_TGT_STATE_PROCESSED 3 /* target done processing */
-#define QLA_TGT_STATE_ABORTED 4 /* Command aborted */
+
/* Special handles */
#define QLA_TGT_NULL_HANDLE 0
@@ -835,6 +835,7 @@ struct qla_tgt {
* HW lock.
*/
int irq_cmd_count;
+ int atio_irq_cmd_count;
int datasegs_per_cmd, datasegs_per_cont, sg_tablesize;
@@ -883,6 +884,7 @@ struct qla_tgt {
struct qla_tgt_sess_op {
struct scsi_qla_host *vha;
+ uint32_t chip_reset;
struct atio_from_isp atio;
struct work_struct work;
struct list_head cmd_list;
@@ -896,6 +898,19 @@ enum qla_sess_deletion {
QLA_SESS_DELETION_IN_PROGRESS = 2,
};
+typedef enum {
+ QLT_PLOGI_LINK_SAME_WWN,
+ QLT_PLOGI_LINK_CONFLICT,
+ QLT_PLOGI_LINK_MAX
+} qlt_plogi_link_t;
+
+typedef struct {
+ struct list_head list;
+ struct imm_ntfy_from_isp iocb;
+ port_id_t id;
+ int ref_count;
+} qlt_plogi_ack_t;
+
/*
* Equivilant to IT Nexus (Initiator-Target)
*/
@@ -907,8 +922,8 @@ struct qla_tgt_sess {
unsigned int deleted:2;
unsigned int local:1;
unsigned int logout_on_delete:1;
- unsigned int plogi_ack_needed:1;
unsigned int keep_nport_handle:1;
+ unsigned int send_els_logo:1;
unsigned char logout_completed;
@@ -925,11 +940,39 @@ struct qla_tgt_sess {
uint8_t port_name[WWN_SIZE];
struct work_struct free_work;
- union {
- struct imm_ntfy_from_isp tm_iocb;
- };
+ qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
};
+typedef enum {
+ /*
+ * BIT_0 - Atio Arrival / schedule to work
+ * BIT_1 - qlt_do_work
+ * BIT_2 - qlt_do work failed
+ * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
+ * BIT_4 - read respond/tcm_qla2xx_queue_data_in
+ * BIT_5 - status respond / tcm_qla2xx_queue_status
+ * BIT_6 - tcm request to abort/Term exchange.
+ * pre_xmit_response->qlt_send_term_exchange
+ * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
+ * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
+ * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
+ * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
+
+ * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
+ * BIT_13 - Bad completion -
+ * qlt_ctio_do_completion --> qlt_term_ctio_exchange
+ * BIT_14 - Back end data received/sent.
+ * BIT_15 - SRR prepare ctio
+ * BIT_16 - complete free
+ * BIT_17 - flush - qlt_abort_cmd_on_host_reset
+ * BIT_18 - completion w/abort status
+ * BIT_19 - completion w/unknown status
+ * BIT_20 - tcm_qla2xxx_free_cmd
+ */
+ CMD_FLAG_DATA_WORK = BIT_11,
+ CMD_FLAG_DATA_WORK_FREE = BIT_21,
+} cmd_flags_t;
+
struct qla_tgt_cmd {
struct se_cmd se_cmd;
struct qla_tgt_sess *sess;
@@ -939,6 +982,7 @@ struct qla_tgt_cmd {
/* Sense buffer that will be mapped into outgoing status */
unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
+ spinlock_t cmd_lock;
/* to save extra sess dereferences */
unsigned int conf_compl_supported:1;
unsigned int sg_mapped:1;
@@ -949,6 +993,7 @@ struct qla_tgt_cmd {
unsigned int term_exchg:1;
unsigned int cmd_sent_to_fw:1;
unsigned int cmd_in_wq:1;
+ unsigned int aborted:1;
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
@@ -972,30 +1017,8 @@ struct qla_tgt_cmd {
uint64_t jiffies_at_alloc;
uint64_t jiffies_at_free;
- /* BIT_0 - Atio Arrival / schedule to work
- * BIT_1 - qlt_do_work
- * BIT_2 - qlt_do work failed
- * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
- * BIT_4 - read respond/tcm_qla2xx_queue_data_in
- * BIT_5 - status respond / tcm_qla2xx_queue_status
- * BIT_6 - tcm request to abort/Term exchange.
- * pre_xmit_response->qlt_send_term_exchange
- * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
- * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
- * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
- * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
- * BIT_11 - Data actually going to TCM : tcm_qla2xx_handle_data_work
- * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
- * BIT_13 - Bad completion -
- * qlt_ctio_do_completion --> qlt_term_ctio_exchange
- * BIT_14 - Back end data received/sent.
- * BIT_15 - SRR prepare ctio
- * BIT_16 - complete free
- * BIT_17 - flush - qlt_abort_cmd_on_host_reset
- * BIT_18 - completion w/abort status
- * BIT_19 - completion w/unknown status
- */
- uint32_t cmd_flags;
+
+ cmd_flags_t cmd_flags;
};
struct qla_tgt_sess_work_param {
@@ -1120,13 +1143,21 @@ static inline uint32_t sid_to_key(const uint8_t *s_id)
return key;
}
+static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
+{
+ memset(p, 0, sizeof(*p));
+ p->b.domain = s_id[0];
+ p->b.area = s_id[1];
+ p->b.al_pa = s_id[2];
+}
+
/*
* Exported symbols from qla_target.c LLD logic used by qla2xxx code..
*/
extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
-extern void qlt_abort_cmd(struct qla_tgt_cmd *);
+extern int qlt_abort_cmd(struct qla_tgt_cmd *);
extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
@@ -1135,7 +1166,7 @@ extern void qlt_enable_vha(struct scsi_qla_host *);
extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
extern void qlt_rff_id(struct scsi_qla_host *, struct ct_sns_req *);
extern void qlt_init_atio_q_entries(struct scsi_qla_host *);
-extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *);
+extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *, uint8_t);
extern void qlt_24xx_config_rings(struct scsi_qla_host *);
extern void qlt_24xx_config_nvram_stage1(struct scsi_qla_host *,
struct nvram_24xx *);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 81af294f1..1808a01cf 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -284,6 +284,7 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
WARN_ON(cmd->cmd_flags & BIT_16);
+ cmd->vha->tgt_counters.qla_core_ret_sta_ctio++;
cmd->cmd_flags |= BIT_16;
transport_generic_free_cmd(&cmd->se_cmd, 0);
}
@@ -295,9 +296,14 @@ static void tcm_qla2xxx_complete_free(struct work_struct *work)
*/
static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
{
+ cmd->vha->tgt_counters.core_qla_free_cmd++;
cmd->cmd_in_wq = 1;
+
+ BUG_ON(cmd->cmd_flags & BIT_20);
+ cmd->cmd_flags |= BIT_20;
+
INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
- queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+ queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
}
/*
@@ -342,9 +348,9 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess)
BUG_ON(!sess);
vha = sess->vha;
- spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
target_sess_cmd_list_set_waiting(se_sess);
- spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
return 1;
}
@@ -358,9 +364,9 @@ static void tcm_qla2xxx_close_session(struct se_session *se_sess)
BUG_ON(!sess);
vha = sess->vha;
- spin_lock_irqsave(&vha->hw->hardware_lock, flags);
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
qlt_unreg_sess(sess);
- spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
}
static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess)
@@ -372,6 +378,20 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
{
struct qla_tgt_cmd *cmd = container_of(se_cmd,
struct qla_tgt_cmd, se_cmd);
+
+ if (cmd->aborted) {
+ /* Cmd can loop during Q-full. tcm_qla2xxx_aborted_task
+ * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+ * already kick start the free.
+ */
+ pr_debug("write_pending aborted cmd[%p] refcount %d "
+ "transport_state %x, t_state %x, se_cmd_flags %x\n",
+ cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+ cmd->se_cmd.transport_state,
+ cmd->se_cmd.t_state,
+ cmd->se_cmd.se_cmd_flags);
+ return 0;
+ }
cmd->cmd_flags |= BIT_3;
cmd->bufflen = se_cmd->data_length;
cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -403,7 +423,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd)
se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
- 3 * HZ);
+ 50);
return 0;
}
spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
@@ -442,6 +462,9 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
if (bidi)
flags |= TARGET_SCF_BIDI_OP;
+ if (se_cmd->cpuid != WORK_CPU_UNBOUND)
+ flags |= TARGET_SCF_USE_CPUID;
+
sess = cmd->sess;
if (!sess) {
pr_err("Unable to locate struct qla_tgt_sess from qla_tgt_cmd\n");
@@ -454,6 +477,7 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
return -EINVAL;
}
+ cmd->vha->tgt_counters.qla_core_sbt_cmd++;
return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0],
cmd->unpacked_lun, data_length, fcp_task_attr,
data_dir, flags);
@@ -462,13 +486,26 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
{
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+ unsigned long flags;
/*
* Ensure that the complete FCP WRITE payload has been received.
* Otherwise return an exception via CHECK_CONDITION status.
*/
cmd->cmd_in_wq = 0;
- cmd->cmd_flags |= BIT_11;
+
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
+ cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
+ if (cmd->aborted) {
+ cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+ tcm_qla2xxx_free_cmd(cmd);
+ return;
+ }
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+ cmd->vha->tgt_counters.qla_core_ret_ctio++;
if (!cmd->write_data_transferred) {
/*
* Check if se_cmd has already been aborted via LUN_RESET, and
@@ -500,7 +537,7 @@ static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
cmd->cmd_flags |= BIT_10;
cmd->cmd_in_wq = 1;
INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work);
- queue_work(tcm_qla2xxx_free_wq, &cmd->work);
+ queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
}
static void tcm_qla2xxx_handle_dif_work(struct work_struct *work)
@@ -542,6 +579,20 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
struct qla_tgt_cmd *cmd = container_of(se_cmd,
struct qla_tgt_cmd, se_cmd);
+ if (cmd->aborted) {
+ /* Cmd can loop during Q-full. tcm_qla2xxx_aborted_task
+ * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+ * already kick start the free.
+ */
+ pr_debug("queue_data_in aborted cmd[%p] refcount %d "
+ "transport_state %x, t_state %x, se_cmd_flags %x\n",
+ cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+ cmd->se_cmd.transport_state,
+ cmd->se_cmd.t_state,
+ cmd->se_cmd.se_cmd_flags);
+ return 0;
+ }
+
cmd->cmd_flags |= BIT_4;
cmd->bufflen = se_cmd->data_length;
cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -633,17 +684,40 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
qlt_xmit_tm_rsp(mcmd);
}
+
+#define DATA_WORK_NOT_FREE(_flags) \
+ (( _flags & (CMD_FLAG_DATA_WORK|CMD_FLAG_DATA_WORK_FREE)) == \
+ CMD_FLAG_DATA_WORK)
static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
{
struct qla_tgt_cmd *cmd = container_of(se_cmd,
struct qla_tgt_cmd, se_cmd);
- qlt_abort_cmd(cmd);
+ unsigned long flags;
+
+ if (qlt_abort_cmd(cmd))
+ return;
+
+ spin_lock_irqsave(&cmd->cmd_lock, flags);
+ if ((cmd->state == QLA_TGT_STATE_NEW)||
+ ((cmd->state == QLA_TGT_STATE_DATA_IN) &&
+ DATA_WORK_NOT_FREE(cmd->cmd_flags)) ) {
+
+ cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ /* Cmd have not reached firmware.
+ * Use this trigger to free it. */
+ tcm_qla2xxx_free_cmd(cmd);
+ return;
+ }
+ spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+ return;
+
}
static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
struct tcm_qla2xxx_nacl *, struct qla_tgt_sess *);
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess)
{
@@ -697,13 +771,13 @@ static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess)
if (!sess)
return;
- assert_spin_locked(&sess->vha->hw->hardware_lock);
+ assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
}
static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess)
{
- assert_spin_locked(&sess->vha->hw->hardware_lock);
+ assert_spin_locked(&sess->vha->hw->tgt.sess_lock);
target_sess_cmd_list_set_waiting(sess->se_sess);
}
@@ -1077,7 +1151,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
scsi_qla_host_t *vha,
@@ -1116,7 +1190,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_set_sess_by_s_id(
struct tcm_qla2xxx_lport *lport,
@@ -1182,7 +1256,7 @@ static void tcm_qla2xxx_set_sess_by_s_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
scsi_qla_host_t *vha,
@@ -1221,7 +1295,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
}
/*
- * Expected to be called with struct qla_hw_data->hardware_lock held
+ * Expected to be called with struct qla_hw_data->tgt.sess_lock held
*/
static void tcm_qla2xxx_set_sess_by_loop_id(
struct tcm_qla2xxx_lport *lport,
@@ -1285,7 +1359,7 @@ static void tcm_qla2xxx_set_sess_by_loop_id(
}
/*
- * Should always be called with qla_hw_data->hardware_lock held.
+ * Should always be called with qla_hw_data->tgt.sess_lock held.
*/
static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *lport,
struct tcm_qla2xxx_nacl *nacl, struct qla_tgt_sess *sess)
@@ -1353,7 +1427,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
struct qla_tgt_sess *sess = qla_tgt_sess;
unsigned char port_name[36];
unsigned long flags;
- int num_tags = (ha->fw_xcb_count) ? ha->fw_xcb_count :
+ int num_tags = (ha->cur_fw_xcb_count) ? ha->cur_fw_xcb_count :
TCM_QLA2XXX_DEFAULT_TAGS;
lport = vha->vha_tgt.target_lport_ptr;
@@ -1401,12 +1475,12 @@ static int tcm_qla2xxx_check_initiator_node_acl(
* And now setup the new se_nacl and session pointers into our HW lport
* mappings for fabric S_ID and LOOP_ID.
*/
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, se_sess,
qla_tgt_sess, s_id);
tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl, se_sess,
qla_tgt_sess, loop_id);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
/*
* Finally register the new FC Nexus with TCM
*/
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index d07fb653f..b1bf42b93 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -782,7 +782,7 @@ void scsi_attach_vpd(struct scsi_device *sdev)
int vpd_len = SCSI_VPD_PG_LEN;
int pg80_supported = 0;
int pg83_supported = 0;
- unsigned char *vpd_buf;
+ unsigned char __rcu *vpd_buf, *orig_vpd_buf = NULL;
if (sdev->skip_vpd_pages)
return;
@@ -828,8 +828,16 @@ retry_pg80:
kfree(vpd_buf);
goto retry_pg80;
}
+ mutex_lock(&sdev->inquiry_mutex);
+ orig_vpd_buf = sdev->vpd_pg80;
sdev->vpd_pg80_len = result;
- sdev->vpd_pg80 = vpd_buf;
+ rcu_assign_pointer(sdev->vpd_pg80, vpd_buf);
+ mutex_unlock(&sdev->inquiry_mutex);
+ synchronize_rcu();
+ if (orig_vpd_buf) {
+ kfree(orig_vpd_buf);
+ orig_vpd_buf = NULL;
+ }
vpd_len = SCSI_VPD_PG_LEN;
}
@@ -849,8 +857,14 @@ retry_pg83:
kfree(vpd_buf);
goto retry_pg83;
}
+ mutex_lock(&sdev->inquiry_mutex);
+ orig_vpd_buf = sdev->vpd_pg83;
sdev->vpd_pg83_len = result;
- sdev->vpd_pg83 = vpd_buf;
+ rcu_assign_pointer(sdev->vpd_pg83, vpd_buf);
+ mutex_unlock(&sdev->inquiry_mutex);
+ synchronize_rcu();
+ if (orig_vpd_buf)
+ kfree(orig_vpd_buf);
}
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index d09d60293..f3d69a98c 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -129,7 +129,7 @@ static const char *scsi_debug_version_date = "20141022";
#define DEF_NO_LUN_0 0
#define DEF_NUM_PARTS 0
#define DEF_OPTS 0
-#define DEF_OPT_BLKS 64
+#define DEF_OPT_BLKS 1024
#define DEF_PHYSBLK_EXP 0
#define DEF_PTYPE 0
#define DEF_REMOVABLE false
@@ -679,7 +679,7 @@ static void *fake_store(unsigned long long lba)
static struct sd_dif_tuple *dif_store(sector_t sector)
{
- sector = do_div(sector, sdebug_store_sectors);
+ sector = sector_div(sector, sdebug_store_sectors);
return dif_storep + sector;
}
@@ -2781,7 +2781,7 @@ static unsigned long lba_to_map_index(sector_t lba)
lba += scsi_debug_unmap_granularity -
scsi_debug_unmap_alignment;
}
- do_div(lba, scsi_debug_unmap_granularity);
+ sector_div(lba, scsi_debug_unmap_granularity);
return lba;
}
@@ -4140,7 +4140,7 @@ MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
-MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
+MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
@@ -4847,10 +4847,10 @@ static int __init scsi_debug_init(void)
/* play around with geometry, don't waste too much on track 0 */
sdebug_heads = 8;
sdebug_sectors_per = 32;
- if (scsi_debug_dev_size_mb >= 16)
- sdebug_heads = 32;
- else if (scsi_debug_dev_size_mb >= 256)
+ if (scsi_debug_dev_size_mb >= 256)
sdebug_heads = 64;
+ else if (scsi_debug_dev_size_mb >= 16)
+ sdebug_heads = 32;
sdebug_cylinders_per = (unsigned long)sdebug_capacity /
(sdebug_sectors_per * sdebug_heads);
if (sdebug_cylinders_per >= 1024) {
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index da2e068ee..bbfbfd9e5 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -206,6 +206,7 @@ static struct {
{"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
{"Marvell", "Console", NULL, BLIST_SKIP_VPD_PAGES},
+ {"Marvell", "91xx Config", "1.01", BLIST_SKIP_VPD_PAGES},
{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
{"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index e7649ed3f..54d446c9f 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -153,76 +153,11 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev)
module_put(sdev->handler->module);
}
-/*
- * Functions for sysfs attribute 'dh_state'
- */
-static ssize_t
-store_dh_state(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_device_handler *scsi_dh;
- int err = -EINVAL;
-
- if (sdev->sdev_state == SDEV_CANCEL ||
- sdev->sdev_state == SDEV_DEL)
- return -ENODEV;
-
- if (!sdev->handler) {
- /*
- * Attach to a device handler
- */
- scsi_dh = scsi_dh_lookup(buf);
- if (!scsi_dh)
- return err;
- err = scsi_dh_handler_attach(sdev, scsi_dh);
- } else {
- if (!strncmp(buf, "detach", 6)) {
- /*
- * Detach from a device handler
- */
- sdev_printk(KERN_WARNING, sdev,
- "can't detach handler %s.\n",
- sdev->handler->name);
- err = -EINVAL;
- } else if (!strncmp(buf, "activate", 8)) {
- /*
- * Activate a device handler
- */
- if (sdev->handler->activate)
- err = sdev->handler->activate(sdev, NULL, NULL);
- else
- err = 0;
- }
- }
-
- return err<0?err:count;
-}
-
-static ssize_t
-show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
-
- if (!sdev->handler)
- return snprintf(buf, 20, "detached\n");
-
- return snprintf(buf, 20, "%s\n", sdev->handler->name);
-}
-
-static struct device_attribute scsi_dh_state_attr =
- __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
- store_dh_state);
-
int scsi_dh_add_device(struct scsi_device *sdev)
{
struct scsi_device_handler *devinfo = NULL;
const char *drv;
- int err;
-
- err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
- if (err)
- return err;
+ int err = 0;
drv = scsi_dh_find_driver(sdev);
if (drv)
@@ -238,11 +173,6 @@ void scsi_dh_release_device(struct scsi_device *sdev)
scsi_dh_handler_detach(sdev);
}
-void scsi_dh_remove_device(struct scsi_device *sdev)
-{
- device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
-}
-
/*
* scsi_register_device_handler - register a device handler personality
* module.
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index dd8ad2a44..8c6e31874 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -23,6 +23,7 @@
#include <linux/scatterlist.h>
#include <linux/blk-mq.h>
#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -1343,6 +1344,7 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret)
switch (ret) {
case BLKPREP_KILL:
+ case BLKPREP_INVALID:
req->errors = DID_NO_CONNECT << 16;
/* release the command and kill it */
if (req->special) {
@@ -3154,3 +3156,190 @@ void sdev_enable_disk_events(struct scsi_device *sdev)
atomic_dec(&sdev->disk_events_disable_depth);
}
EXPORT_SYMBOL(sdev_enable_disk_events);
+
+/**
+ * scsi_vpd_lun_id - return a unique device identification
+ * @sdev: SCSI device
+ * @id: buffer for the identification
+ * @id_len: length of the buffer
+ *
+ * Copies a unique device identification into @id based
+ * on the information in the VPD page 0x83 of the device.
+ * The string will be formatted as a SCSI name string.
+ *
+ * Returns the length of the identification or error on failure.
+ * If the identifier is longer than the supplied buffer the actual
+ * identifier length is returned and the buffer is not zero-padded.
+ */
+int scsi_vpd_lun_id(struct scsi_device *sdev, char *id, size_t id_len)
+{
+ u8 cur_id_type = 0xff;
+ u8 cur_id_size = 0;
+ unsigned char *d, *cur_id_str;
+ unsigned char __rcu *vpd_pg83;
+ int id_size = -EINVAL;
+
+ rcu_read_lock();
+ vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+ if (!vpd_pg83) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+
+ /*
+ * Look for the correct descriptor.
+ * Order of preference for lun descriptor:
+ * - SCSI name string
+ * - NAA IEEE Registered Extended
+ * - EUI-64 based 16-byte
+ * - EUI-64 based 12-byte
+ * - NAA IEEE Registered
+ * - NAA IEEE Extended
+ * as longer descriptors reduce the likelyhood
+ * of identification clashes.
+ */
+
+ /* The id string must be at least 20 bytes + terminating NULL byte */
+ if (id_len < 21) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ memset(id, 0, id_len);
+ d = vpd_pg83 + 4;
+ while (d < vpd_pg83 + sdev->vpd_pg83_len) {
+ /* Skip designators not referring to the LUN */
+ if ((d[1] & 0x30) != 0x00)
+ goto next_desig;
+
+ switch (d[1] & 0xf) {
+ case 0x2:
+ /* EUI-64 */
+ if (cur_id_size > d[3])
+ break;
+ /* Prefer NAA IEEE Registered Extended */
+ if (cur_id_type == 0x3 &&
+ cur_id_size == d[3])
+ break;
+ cur_id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ switch (cur_id_size) {
+ case 8:
+ id_size = snprintf(id, id_len,
+ "eui.%8phN",
+ cur_id_str);
+ break;
+ case 12:
+ id_size = snprintf(id, id_len,
+ "eui.%12phN",
+ cur_id_str);
+ break;
+ case 16:
+ id_size = snprintf(id, id_len,
+ "eui.%16phN",
+ cur_id_str);
+ break;
+ default:
+ cur_id_size = 0;
+ break;
+ }
+ break;
+ case 0x3:
+ /* NAA */
+ if (cur_id_size > d[3])
+ break;
+ cur_id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ switch (cur_id_size) {
+ case 8:
+ id_size = snprintf(id, id_len,
+ "naa.%8phN",
+ cur_id_str);
+ break;
+ case 16:
+ id_size = snprintf(id, id_len,
+ "naa.%16phN",
+ cur_id_str);
+ break;
+ default:
+ cur_id_size = 0;
+ break;
+ }
+ break;
+ case 0x8:
+ /* SCSI name string */
+ if (cur_id_size + 4 > d[3])
+ break;
+ /* Prefer others for truncated descriptor */
+ if (cur_id_size && d[3] > id_len)
+ break;
+ cur_id_size = id_size = d[3];
+ cur_id_str = d + 4;
+ cur_id_type = d[1] & 0xf;
+ if (cur_id_size >= id_len)
+ cur_id_size = id_len - 1;
+ memcpy(id, cur_id_str, cur_id_size);
+ /* Decrease priority for truncated descriptor */
+ if (cur_id_size != id_size)
+ cur_id_size = 6;
+ break;
+ default:
+ break;
+ }
+next_desig:
+ d += d[3] + 4;
+ }
+ rcu_read_unlock();
+
+ return id_size;
+}
+EXPORT_SYMBOL(scsi_vpd_lun_id);
+
+/*
+ * scsi_vpd_tpg_id - return a target port group identifier
+ * @sdev: SCSI device
+ *
+ * Returns the Target Port Group identifier from the information
+ * froom VPD page 0x83 of the device.
+ *
+ * Returns the identifier or error on failure.
+ */
+int scsi_vpd_tpg_id(struct scsi_device *sdev, int *rel_id)
+{
+ unsigned char *d;
+ unsigned char __rcu *vpd_pg83;
+ int group_id = -EAGAIN, rel_port = -1;
+
+ rcu_read_lock();
+ vpd_pg83 = rcu_dereference(sdev->vpd_pg83);
+ if (!vpd_pg83) {
+ rcu_read_unlock();
+ return -ENXIO;
+ }
+
+ d = sdev->vpd_pg83 + 4;
+ while (d < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
+ switch (d[1] & 0xf) {
+ case 0x4:
+ /* Relative target port */
+ rel_port = get_unaligned_be16(&d[6]);
+ break;
+ case 0x5:
+ /* Target port group */
+ group_id = get_unaligned_be16(&d[6]);
+ break;
+ default:
+ break;
+ }
+ d += d[3] + 4;
+ }
+ rcu_read_unlock();
+
+ if (group_id >= 0 && rel_id && rel_port != -1)
+ *rel_id = rel_port;
+
+ return group_id;
+}
+EXPORT_SYMBOL(scsi_vpd_tpg_id);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 4d01cdb1b..27b4d0a6a 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -174,12 +174,11 @@ extern struct async_domain scsi_sd_probe_domain;
#ifdef CONFIG_SCSI_DH
int scsi_dh_add_device(struct scsi_device *sdev);
void scsi_dh_release_device(struct scsi_device *sdev);
-void scsi_dh_remove_device(struct scsi_device *sdev);
#else
static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; }
static inline void scsi_dh_release_device(struct scsi_device *sdev) { }
-static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
#endif
+static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
/*
* internal scsi timeout functions: for use by mid-layer and transport
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 054923e33..6a820668d 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -236,6 +236,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
INIT_LIST_HEAD(&sdev->starved_entry);
INIT_LIST_HEAD(&sdev->event_list);
spin_lock_init(&sdev->list_lock);
+ mutex_init(&sdev->inquiry_mutex);
INIT_WORK(&sdev->event_work, scsi_evt_thread);
INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue);
@@ -1519,6 +1520,9 @@ EXPORT_SYMBOL(scsi_add_device);
void scsi_rescan_device(struct device *dev)
{
device_lock(dev);
+
+ scsi_attach_vpd(to_scsi_device(dev));
+
if (dev->driver && try_module_get(dev->driver->owner)) {
struct scsi_driver *drv = to_scsi_driver(dev->driver);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index c8115b4fe..00bc7218a 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -17,6 +17,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dh.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_driver.h>
@@ -760,11 +761,15 @@ show_vpd_##_page(struct file *filp, struct kobject *kobj, \
{ \
struct device *dev = container_of(kobj, struct device, kobj); \
struct scsi_device *sdev = to_scsi_device(dev); \
+ int ret; \
if (!sdev->vpd_##_page) \
return -EINVAL; \
- return memory_read_from_buffer(buf, count, &off, \
- sdev->vpd_##_page, \
+ rcu_read_lock(); \
+ ret = memory_read_from_buffer(buf, count, &off, \
+ rcu_dereference(sdev->vpd_##_page), \
sdev->vpd_##_page##_len); \
+ rcu_read_unlock(); \
+ return ret; \
} \
static struct bin_attribute dev_attr_vpd_##_page = { \
.attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \
@@ -901,6 +906,76 @@ static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
sdev_store_queue_depth);
static ssize_t
+sdev_show_wwid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ ssize_t count;
+
+ count = scsi_vpd_lun_id(sdev, buf, PAGE_SIZE);
+ if (count > 0) {
+ buf[count] = '\n';
+ count++;
+ }
+ return count;
+}
+static DEVICE_ATTR(wwid, S_IRUGO, sdev_show_wwid, NULL);
+
+#ifdef CONFIG_SCSI_DH
+static ssize_t
+sdev_show_dh_state(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->handler)
+ return snprintf(buf, 20, "detached\n");
+
+ return snprintf(buf, 20, "%s\n", sdev->handler->name);
+}
+
+static ssize_t
+sdev_store_dh_state(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int err = -EINVAL;
+
+ if (sdev->sdev_state == SDEV_CANCEL ||
+ sdev->sdev_state == SDEV_DEL)
+ return -ENODEV;
+
+ if (!sdev->handler) {
+ /*
+ * Attach to a device handler
+ */
+ err = scsi_dh_attach(sdev->request_queue, buf);
+ } else if (!strncmp(buf, "activate", 8)) {
+ /*
+ * Activate a device handler
+ */
+ if (sdev->handler->activate)
+ err = sdev->handler->activate(sdev, NULL, NULL);
+ else
+ err = 0;
+ } else if (!strncmp(buf, "detach", 6)) {
+ /*
+ * Detach from a device handler
+ */
+ sdev_printk(KERN_WARNING, sdev,
+ "can't detach handler %s.\n",
+ sdev->handler->name);
+ err = -EINVAL;
+ }
+
+ return err < 0 ? err : count;
+}
+
+static DEVICE_ATTR(dh_state, S_IRUGO | S_IWUSR, sdev_show_dh_state,
+ sdev_store_dh_state);
+#endif
+
+static ssize_t
sdev_show_queue_ramp_up_period(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -969,6 +1044,10 @@ static struct attribute *scsi_sdev_attrs[] = {
&dev_attr_modalias.attr,
&dev_attr_queue_depth.attr,
&dev_attr_queue_type.attr,
+ &dev_attr_wwid.attr,
+#ifdef CONFIG_SCSI_DH
+ &dev_attr_dh_state.attr,
+#endif
&dev_attr_queue_ramp_up_period.attr,
REF_EVT(media_change),
REF_EVT(inquiry_change_reported),
@@ -1058,11 +1137,12 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
}
error = scsi_dh_add_device(sdev);
- if (error) {
+ if (error)
+ /*
+ * device_handler is optional, so any error can be ignored
+ */
sdev_printk(KERN_INFO, sdev,
"failed to add device handler: %d\n", error);
- return error;
- }
device_enable_async_suspend(&sdev->sdev_dev);
error = device_add(&sdev->sdev_dev);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 24eaaf66a..8a8822641 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2586,7 +2586,7 @@ fc_rport_final_delete(struct work_struct *work)
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
- put_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_put(shost); /* for fc_host->rport list */
put_device(dev); /* for self-reference */
}
@@ -2650,7 +2650,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
else
rport->scsi_target_id = -1;
list_add_tail(&rport->peers, &fc_host->rports);
- get_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_get(shost); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -2685,7 +2685,7 @@ delete_rport:
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&rport->peers);
- put_device(&shost->shost_gendev); /* for fc_host->rport list */
+ scsi_host_put(shost); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(dev->parent);
kfree(rport);
@@ -3383,7 +3383,7 @@ fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev,
fc_host->npiv_vports_inuse++;
vport->number = fc_host->next_vport_number++;
list_add_tail(&vport->peers, &fc_host->vports);
- get_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_get(shost); /* for fc_host->vport list */
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -3441,7 +3441,7 @@ delete_vport:
transport_destroy_device(dev);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&vport->peers);
- put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_put(shost); /* for fc_host->vport list */
fc_host->npiv_vports_inuse--;
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(dev->parent);
@@ -3504,7 +3504,7 @@ fc_vport_terminate(struct fc_vport *vport)
vport->flags |= FC_VPORT_DELETED;
list_del(&vport->peers);
fc_host->npiv_vports_inuse--;
- put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ scsi_host_put(shost); /* for fc_host->vport list */
}
spin_unlock_irqrestore(shost->host_lock, flags);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 30d26e345..80520e2f0 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -341,6 +341,22 @@ static int do_sas_phy_delete(struct device *dev, void *data)
}
/**
+ * is_sas_attached - check if device is SAS attached
+ * @sdev: scsi device to check
+ *
+ * returns true if the device is SAS attached
+ */
+int is_sas_attached(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost = sdev->host;
+
+ return shost->transportt->host_attrs.ac.class ==
+ &sas_host_class.class;
+}
+EXPORT_SYMBOL(is_sas_attached);
+
+
+/**
* sas_remove_children - tear down a devices SAS data structures
* @dev: device belonging to the sas object
*
@@ -367,6 +383,20 @@ void sas_remove_host(struct Scsi_Host *shost)
EXPORT_SYMBOL(sas_remove_host);
/**
+ * sas_get_address - return the SAS address of the device
+ * @sdev: scsi device
+ *
+ * Returns the SAS address of the scsi device
+ */
+u64 sas_get_address(struct scsi_device *sdev)
+{
+ struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
+
+ return rdev->rphy.identify.sas_address;
+}
+EXPORT_SYMBOL(sas_get_address);
+
+/**
* sas_tlr_supported - checking TLR bit in vpd 0x90
* @sdev: scsi device struct
*
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index bb669d32c..d749da765 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -761,7 +761,7 @@ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd)
break;
default:
- ret = BLKPREP_KILL;
+ ret = BLKPREP_INVALID;
goto out;
}
@@ -839,7 +839,7 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd)
int ret;
if (sdkp->device->no_write_same)
- return BLKPREP_KILL;
+ return BLKPREP_INVALID;
BUG_ON(bio_offset(bio) || bio_iovec(bio).bv_len != sdp->sector_size);
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 044d06410..53ef1cb64 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -34,6 +34,8 @@
#include <scsi/scsi_driver.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_sas.h>
+
struct ses_device {
unsigned char *page1;
unsigned char *page1_types;
@@ -579,31 +581,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
static void ses_match_to_enclosure(struct enclosure_device *edev,
struct scsi_device *sdev)
{
- unsigned char *desc;
struct efd efd = {
.addr = 0,
};
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
- if (!sdev->vpd_pg83_len)
- return;
-
- desc = sdev->vpd_pg83 + 4;
- while (desc < sdev->vpd_pg83 + sdev->vpd_pg83_len) {
- enum scsi_protocol proto = desc[0] >> 4;
- u8 code_set = desc[0] & 0x0f;
- u8 piv = desc[1] & 0x80;
- u8 assoc = (desc[1] & 0x30) >> 4;
- u8 type = desc[1] & 0x0f;
- u8 len = desc[3];
-
- if (piv && code_set == 1 && assoc == 1
- && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8)
- efd.addr = get_unaligned_be64(&desc[4]);
+ if (is_sas_attached(sdev))
+ efd.addr = sas_get_address(sdev);
- desc += len + 4;
- }
if (efd.addr) {
efd.dev = &sdev->sdev_gendev;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index b6486b5d8..8c732c8de 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -148,8 +148,6 @@ struct scsi_tape {
int tape_type;
int long_timeout; /* timeout for commands known to take long time */
- unsigned long max_pfn; /* the maximum page number reachable by the HBA */
-
/* Mode characteristics */
struct st_modedef modes[ST_NBR_MODES];
int current_mode;
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 3fba42ad9..292c04eec 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -41,6 +41,8 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_transport.h>
/*
* All wire protocol details (storage protocol between the guest and the host)
@@ -92,9 +94,8 @@ enum vstor_packet_operation {
*/
struct hv_fc_wwn_packet {
- bool primary_active;
- u8 reserved1;
- u8 reserved2;
+ u8 primary_active;
+ u8 reserved1[3];
u8 primary_port_wwn[8];
u8 primary_node_wwn[8];
u8 secondary_port_wwn[8];
@@ -164,6 +165,26 @@ static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE;
*/
static int vmstor_proto_version;
+#define STORVSC_LOGGING_NONE 0
+#define STORVSC_LOGGING_ERROR 1
+#define STORVSC_LOGGING_WARN 2
+
+static int logging_level = STORVSC_LOGGING_ERROR;
+module_param(logging_level, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(logging_level,
+ "Logging level, 0 - None, 1 - Error (default), 2 - Warning.");
+
+static inline bool do_logging(int level)
+{
+ return logging_level >= level;
+}
+
+#define storvsc_log(dev, level, fmt, ...) \
+do { \
+ if (do_logging(level)) \
+ dev_warn(&(dev)->device, fmt, ##__VA_ARGS__); \
+} while (0)
+
struct vmscsi_win8_extension {
/*
* The following were added in Windows 8
@@ -370,7 +391,7 @@ module_param(storvsc_ringbuffer_size, int, S_IRUGO);
MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)");
module_param(storvsc_vcpus_per_sub_channel, int, S_IRUGO);
-MODULE_PARM_DESC(vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
+MODULE_PARM_DESC(storvsc_vcpus_per_sub_channel, "Ratio of VCPUs to subchannels");
/*
* Timeout in seconds for all devices managed by this driver.
*/
@@ -378,6 +399,9 @@ static int storvsc_timeout = 180;
static int msft_blist_flags = BLIST_TRY_VPD_PAGES;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct scsi_transport_template *fc_transport_template;
+#endif
static void storvsc_on_channel_callback(void *context);
@@ -437,6 +461,11 @@ struct storvsc_device {
/* Used for vsc/vsp channel reset process */
struct storvsc_cmd_request init_request;
struct storvsc_cmd_request reset_request;
+ /*
+ * Currently active port and node names for FC devices.
+ */
+ u64 node_name;
+ u64 port_name;
};
struct hv_host_device {
@@ -449,19 +478,18 @@ struct hv_host_device {
struct storvsc_scan_work {
struct work_struct work;
struct Scsi_Host *host;
- uint lun;
+ u8 lun;
+ u8 tgt_id;
};
static void storvsc_device_scan(struct work_struct *work)
{
struct storvsc_scan_work *wrk;
- uint lun;
struct scsi_device *sdev;
wrk = container_of(work, struct storvsc_scan_work, work);
- lun = wrk->lun;
- sdev = scsi_device_lookup(wrk->host, 0, 0, lun);
+ sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
if (!sdev)
goto done;
scsi_rescan_device(&sdev->sdev_gendev);
@@ -512,7 +540,7 @@ static void storvsc_remove_lun(struct work_struct *work)
if (!scsi_host_get(wrk->host))
goto done;
- sdev = scsi_device_lookup(wrk->host, 0, 0, wrk->lun);
+ sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
if (sdev) {
scsi_remove_device(sdev);
@@ -676,29 +704,36 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns)
vmbus_are_subchannels_present(device->channel);
}
-static int storvsc_channel_init(struct hv_device *device)
+static void cache_wwn(struct storvsc_device *stor_device,
+ struct vstor_packet *vstor_packet)
{
- struct storvsc_device *stor_device;
- struct storvsc_cmd_request *request;
- struct vstor_packet *vstor_packet;
- int ret, t, i;
- int max_chns;
- bool process_sub_channels = false;
+ /*
+ * Cache the currently active port and node ww names.
+ */
+ if (vstor_packet->wwn_packet.primary_active) {
+ stor_device->node_name =
+ wwn_to_u64(vstor_packet->wwn_packet.primary_node_wwn);
+ stor_device->port_name =
+ wwn_to_u64(vstor_packet->wwn_packet.primary_port_wwn);
+ } else {
+ stor_device->node_name =
+ wwn_to_u64(vstor_packet->wwn_packet.secondary_node_wwn);
+ stor_device->port_name =
+ wwn_to_u64(vstor_packet->wwn_packet.secondary_port_wwn);
+ }
+}
- stor_device = get_out_stor_device(device);
- if (!stor_device)
- return -ENODEV;
- request = &stor_device->init_request;
+static int storvsc_execute_vstor_op(struct hv_device *device,
+ struct storvsc_cmd_request *request,
+ bool status_check)
+{
+ struct vstor_packet *vstor_packet;
+ int ret, t;
+
vstor_packet = &request->vstor_packet;
- /*
- * Now, initiate the vsc/vsp initialization protocol on the open
- * channel
- */
- memset(request, 0, sizeof(struct storvsc_cmd_request));
init_completion(&request->wait_event);
- vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
vstor_packet->flags = REQUEST_COMPLETION_FLAG;
ret = vmbus_sendpacket(device->channel, vstor_packet,
@@ -708,27 +743,56 @@ static int storvsc_channel_init(struct hv_device *device)
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
if (ret != 0)
- goto cleanup;
+ return ret;
t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ if (t == 0)
+ return -ETIMEDOUT;
+
+ if (!status_check)
+ return ret;
if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ vstor_packet->status != 0)
+ return -EINVAL;
+
+ return ret;
+}
+
+static int storvsc_channel_init(struct hv_device *device, bool is_fc)
+{
+ struct storvsc_device *stor_device;
+ struct storvsc_cmd_request *request;
+ struct vstor_packet *vstor_packet;
+ int ret, i;
+ int max_chns;
+ bool process_sub_channels = false;
+ stor_device = get_out_stor_device(device);
+ if (!stor_device)
+ return -ENODEV;
+
+ request = &stor_device->init_request;
+ vstor_packet = &request->vstor_packet;
+
+ /*
+ * Now, initiate the vsc/vsp initialization protocol on the open
+ * channel
+ */
+ memset(request, 0, sizeof(struct storvsc_cmd_request));
+ vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION;
+ ret = storvsc_execute_vstor_op(device, request, true);
+ if (ret)
+ return ret;
+ /*
+ * Query host supported protocol version.
+ */
for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) {
/* reuse the packet for version range supported */
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation =
VSTOR_OPERATION_QUERY_PROTOCOL_VERSION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
vstor_packet->version.major_minor =
vmstor_protocols[i].protocol_version;
@@ -737,26 +801,12 @@ static int storvsc_channel_init(struct hv_device *device)
* The revision number is only used in Windows; set it to 0.
*/
vstor_packet->version.revision = 0;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ ret = storvsc_execute_vstor_op(device, request, false);
if (ret != 0)
- goto cleanup;
+ return ret;
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO) {
- ret = -EINVAL;
- goto cleanup;
- }
+ if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO)
+ return -EINVAL;
if (vstor_packet->status == 0) {
vmstor_proto_version =
@@ -772,37 +822,15 @@ static int storvsc_channel_init(struct hv_device *device)
}
}
- if (vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ if (vstor_packet->status != 0)
+ return -EINVAL;
memset(vstor_packet, 0, sizeof(struct vstor_packet));
vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
+ ret = storvsc_execute_vstor_op(device, request, true);
if (ret != 0)
- goto cleanup;
-
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
-
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+ return ret;
/*
* Check to see if multi-channel support is there.
@@ -818,37 +846,34 @@ static int storvsc_channel_init(struct hv_device *device)
stor_device->max_transfer_bytes =
vstor_packet->storage_channel_properties.max_transfer_bytes;
- memset(vstor_packet, 0, sizeof(struct vstor_packet));
- vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
- vstor_packet->flags = REQUEST_COMPLETION_FLAG;
-
- ret = vmbus_sendpacket(device->channel, vstor_packet,
- (sizeof(struct vstor_packet) -
- vmscsi_size_delta),
- (unsigned long)request,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ if (!is_fc)
+ goto done;
+ /*
+ * For FC devices retrieve FC HBA data.
+ */
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_FCHBA_DATA;
+ ret = storvsc_execute_vstor_op(device, request, true);
if (ret != 0)
- goto cleanup;
+ return ret;
- t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
- if (t == 0) {
- ret = -ETIMEDOUT;
- goto cleanup;
- }
+ /*
+ * Cache the currently active port and node ww names.
+ */
+ cache_wwn(stor_device, vstor_packet);
- if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO ||
- vstor_packet->status != 0) {
- ret = -EINVAL;
- goto cleanup;
- }
+done:
+
+ memset(vstor_packet, 0, sizeof(struct vstor_packet));
+ vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION;
+ ret = storvsc_execute_vstor_op(device, request, true);
+ if (ret != 0)
+ return ret;
if (process_sub_channels)
handle_multichannel_storage(device, max_chns);
-
-cleanup:
return ret;
}
@@ -915,24 +940,22 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
wrk->host = host;
wrk->lun = vm_srb->lun;
+ wrk->tgt_id = vm_srb->target_id;
INIT_WORK(&wrk->work, process_err_fn);
schedule_work(&wrk->work);
}
-static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
+static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request,
+ struct storvsc_device *stor_dev)
{
struct scsi_cmnd *scmnd = cmd_request->cmd;
- struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
struct scsi_sense_hdr sense_hdr;
struct vmscsi_request *vm_srb;
struct Scsi_Host *host;
- struct storvsc_device *stor_dev;
- struct hv_device *dev = host_dev->dev;
u32 payload_sz = cmd_request->payload_sz;
void *payload = cmd_request->payload;
- stor_dev = get_in_stor_device(dev);
host = stor_dev->host;
vm_srb = &cmd_request->vstor_packet.vm_srb;
@@ -941,7 +964,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
if (scmnd->result) {
if (scsi_normalize_sense(scmnd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE, &sense_hdr))
+ SCSI_SENSE_BUFFERSIZE, &sense_hdr) &&
+ do_logging(STORVSC_LOGGING_ERROR))
scsi_print_sense_hdr(scmnd->device, "storvsc",
&sense_hdr);
}
@@ -961,14 +985,13 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
kfree(payload);
}
-static void storvsc_on_io_completion(struct hv_device *device,
+static void storvsc_on_io_completion(struct storvsc_device *stor_device,
struct vstor_packet *vstor_packet,
struct storvsc_cmd_request *request)
{
- struct storvsc_device *stor_device;
struct vstor_packet *stor_pkt;
+ struct hv_device *device = stor_device->device;
- stor_device = hv_get_drvdata(device);
stor_pkt = &request->vstor_packet;
/*
@@ -995,6 +1018,13 @@ static void storvsc_on_io_completion(struct hv_device *device,
stor_pkt->vm_srb.sense_info_length =
vstor_packet->vm_srb.sense_info_length;
+ if (vstor_packet->vm_srb.scsi_status != 0 ||
+ vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS)
+ storvsc_log(device, STORVSC_LOGGING_WARN,
+ "cmd 0x%x scsi status 0x%x srb status 0x%x\n",
+ stor_pkt->vm_srb.cdb[0],
+ vstor_packet->vm_srb.scsi_status,
+ vstor_packet->vm_srb.srb_status);
if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) {
/* CHECK_CONDITION */
@@ -1002,6 +1032,10 @@ static void storvsc_on_io_completion(struct hv_device *device,
SRB_STATUS_AUTOSENSE_VALID) {
/* autosense data available */
+ storvsc_log(device, STORVSC_LOGGING_WARN,
+ "stor pkt %p autosense data valid - len %d\n",
+ request, vstor_packet->vm_srb.sense_info_length);
+
memcpy(request->cmd->sense_buffer,
vstor_packet->vm_srb.sense_data,
vstor_packet->vm_srb.sense_info_length);
@@ -1012,7 +1046,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
stor_pkt->vm_srb.data_transfer_length =
vstor_packet->vm_srb.data_transfer_length;
- storvsc_command_completion(request);
+ storvsc_command_completion(request, stor_device);
if (atomic_dec_and_test(&stor_device->num_outstanding_req) &&
stor_device->drain_notify)
@@ -1021,21 +1055,19 @@ static void storvsc_on_io_completion(struct hv_device *device,
}
-static void storvsc_on_receive(struct hv_device *device,
+static void storvsc_on_receive(struct storvsc_device *stor_device,
struct vstor_packet *vstor_packet,
struct storvsc_cmd_request *request)
{
struct storvsc_scan_work *work;
- struct storvsc_device *stor_device;
switch (vstor_packet->operation) {
case VSTOR_OPERATION_COMPLETE_IO:
- storvsc_on_io_completion(device, vstor_packet, request);
+ storvsc_on_io_completion(stor_device, vstor_packet, request);
break;
case VSTOR_OPERATION_REMOVE_DEVICE:
case VSTOR_OPERATION_ENUMERATE_BUS:
- stor_device = get_in_stor_device(device);
work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC);
if (!work)
return;
@@ -1045,6 +1077,13 @@ static void storvsc_on_receive(struct hv_device *device,
schedule_work(&work->work);
break;
+ case VSTOR_OPERATION_FCHBA_DATA:
+ cache_wwn(stor_device, vstor_packet);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_host_node_name(stor_device->host) = stor_device->node_name;
+ fc_host_port_name(stor_device->host) = stor_device->port_name;
+#endif
+ break;
default:
break;
}
@@ -1088,7 +1127,7 @@ static void storvsc_on_channel_callback(void *context)
vmscsi_size_delta));
complete(&request->wait_event);
} else {
- storvsc_on_receive(device,
+ storvsc_on_receive(stor_device,
(struct vstor_packet *)packet,
request);
}
@@ -1100,7 +1139,8 @@ static void storvsc_on_channel_callback(void *context)
return;
}
-static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
+static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size,
+ bool is_fc)
{
struct vmstorage_channel_properties props;
int ret;
@@ -1117,7 +1157,7 @@ static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size)
if (ret != 0)
return ret;
- ret = storvsc_channel_init(device);
+ ret = storvsc_channel_init(device, is_fc);
return ret;
}
@@ -1542,6 +1582,7 @@ static int storvsc_probe(struct hv_device *device,
struct Scsi_Host *host;
struct hv_host_device *host_dev;
bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
+ bool is_fc = ((dev_id->driver_data == SFC_GUID) ? true : false);
int target = 0;
struct storvsc_device *stor_device;
int max_luns_per_target;
@@ -1599,7 +1640,7 @@ static int storvsc_probe(struct hv_device *device,
hv_set_drvdata(device, stor_device);
stor_device->port_number = host->host_no;
- ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size);
+ ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size, is_fc);
if (ret)
goto err_out1;
@@ -1611,6 +1652,9 @@ static int storvsc_probe(struct hv_device *device,
host->max_lun = STORVSC_FC_MAX_LUNS_PER_TARGET;
host->max_id = STORVSC_FC_MAX_TARGETS;
host->max_channel = STORVSC_FC_MAX_CHANNELS - 1;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ host->transportt = fc_transport_template;
+#endif
break;
case SCSI_GUID:
@@ -1650,6 +1694,12 @@ static int storvsc_probe(struct hv_device *device,
goto err_out2;
}
}
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (host->transportt == fc_transport_template) {
+ fc_host_node_name(host) = stor_device->node_name;
+ fc_host_port_name(host) = stor_device->port_name;
+ }
+#endif
return 0;
err_out2:
@@ -1675,6 +1725,10 @@ static int storvsc_remove(struct hv_device *dev)
struct storvsc_device *stor_device = hv_get_drvdata(dev);
struct Scsi_Host *host = stor_device->host;
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (host->transportt == fc_transport_template)
+ fc_remove_host(host);
+#endif
scsi_remove_host(host);
storvsc_dev_remove(dev);
scsi_host_put(host);
@@ -1689,8 +1743,16 @@ static struct hv_driver storvsc_drv = {
.remove = storvsc_remove,
};
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+static struct fc_function_template fc_transport_functions = {
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+};
+#endif
+
static int __init storvsc_drv_init(void)
{
+ int ret;
/*
* Divide the ring buffer data size (which is 1 page less
@@ -1705,12 +1767,33 @@ static int __init storvsc_drv_init(void)
vmscsi_size_delta,
sizeof(u64)));
- return vmbus_driver_register(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_transport_template = fc_attach_transport(&fc_transport_functions);
+ if (!fc_transport_template)
+ return -ENODEV;
+
+ /*
+ * Install Hyper-V specific timeout handler.
+ */
+ fc_transport_template->eh_timed_out = storvsc_eh_timed_out;
+#endif
+
+ ret = vmbus_driver_register(&storvsc_drv);
+
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ if (ret)
+ fc_release_transport(fc_transport_template);
+#endif
+
+ return ret;
}
static void __exit storvsc_drv_exit(void)
{
vmbus_driver_unregister(&storvsc_drv);
+#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
+ fc_release_transport(fc_transport_template);
+#endif
}
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 22a42836d..b9de487bb 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -53,13 +53,12 @@
#define NCR5380_queue_command sun3scsi_queue_command
#define NCR5380_bus_reset sun3scsi_bus_reset
#define NCR5380_abort sun3scsi_abort
-#define NCR5380_show_info sun3scsi_show_info
#define NCR5380_info sun3scsi_info
#define NCR5380_dma_read_setup(instance, data, count) \
- sun3scsi_dma_setup(data, count, 0)
+ sun3scsi_dma_setup(instance, data, count, 0)
#define NCR5380_dma_write_setup(instance, data, count) \
- sun3scsi_dma_setup(data, count, 1)
+ sun3scsi_dma_setup(instance, data, count, 1)
#define NCR5380_dma_residual(instance) \
sun3scsi_dma_residual(instance)
#define NCR5380_dma_xfer_len(instance, cmd, phase) \
@@ -86,10 +85,6 @@ module_param(setup_use_tagged_queuing, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-/* #define RESET_BOOT */
-
-#define AFTER_RESET_DELAY (HZ/2)
-
/* ms to wait after hitting dma regs */
#define SUN3_DMA_DELAY 10
@@ -100,11 +95,10 @@ static struct scsi_cmnd *sun3_dma_setup_done;
static unsigned char *sun3_scsi_regp;
static volatile struct sun3_dma_regs *dregs;
static struct sun3_udc_regs *udc_regs;
-static unsigned char *sun3_dma_orig_addr = NULL;
-static unsigned long sun3_dma_orig_count = 0;
-static int sun3_dma_active = 0;
-static unsigned long last_residual = 0;
-static struct Scsi_Host *default_instance;
+static unsigned char *sun3_dma_orig_addr;
+static unsigned long sun3_dma_orig_count;
+static int sun3_dma_active;
+static unsigned long last_residual;
/*
* NCR 5380 register access functions
@@ -144,50 +138,12 @@ static inline void sun3_udc_write(unsigned short val, unsigned char reg)
}
#endif
-#ifdef RESET_BOOT
-static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
-{
- unsigned long end;
-
- /*
- * Do a SCSI reset to clean up the bus during initialization. No
- * messing with the queues, interrupts, or locks necessary here.
- */
-
- printk( "Sun3 SCSI: resetting the SCSI bus..." );
-
- /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-// sun3_disable_irq( IRQ_SUN3_SCSI );
-
- /* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
-
- /* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
-
- /* The min. reset hold time is 25us, so 40us should be enough */
- udelay( 50 );
-
- /* reset RST and interrupt */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
- for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
- barrier();
-
- /* switch on SCSI IRQ again */
-// sun3_enable_irq( IRQ_SUN3_SCSI );
-
- printk( " done\n" );
-}
-#endif
-
// safe bits for the CSR
#define CSR_GOOD 0x060f
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
+static irqreturn_t scsi_sun3_intr(int irq, void *dev)
{
+ struct Scsi_Host *instance = dev;
unsigned short csr = dregs->csr;
int handled = 0;
@@ -196,46 +152,24 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
#endif
if(csr & ~CSR_GOOD) {
- if(csr & CSR_DMA_BUSERR) {
- printk("scsi%d: bus error in dma\n", default_instance->host_no);
- }
-
- if(csr & CSR_DMA_CONFLICT) {
- printk("scsi%d: dma conflict\n", default_instance->host_no);
- }
+ if (csr & CSR_DMA_BUSERR)
+ shost_printk(KERN_ERR, instance, "bus error in DMA\n");
+ if (csr & CSR_DMA_CONFLICT)
+ shost_printk(KERN_ERR, instance, "DMA conflict\n");
handled = 1;
}
if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
- NCR5380_intr(irq, dummy);
+ NCR5380_intr(irq, dev);
handled = 1;
}
return IRQ_RETVAL(handled);
}
-/*
- * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk;
- * reentering NCR5380_print_status seems to have ugly side effects
- */
-
-/* this doesn't seem to get used at all -- sam */
-#if 0
-void sun3_sun3_debug (void)
-{
- unsigned long flags;
-
- if (default_instance) {
- local_irq_save(flags);
- NCR5380_print_status(default_instance);
- local_irq_restore(flags);
- }
-}
-#endif
-
-
/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
-static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
+static unsigned long sun3scsi_dma_setup(struct Scsi_Host *instance,
+ void *data, unsigned long count, int write_flag)
{
void *addr;
@@ -287,10 +221,9 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
dregs->csr |= CSR_FIFO;
if(dregs->fifo_count != count) {
- printk("scsi%d: fifo_mismatch %04x not %04x\n",
- default_instance->host_no, dregs->fifo_count,
- (unsigned int) count);
- NCR5380_dprint(NDEBUG_DMA, default_instance);
+ shost_printk(KERN_ERR, instance, "FIFO mismatch %04x not %04x\n",
+ dregs->fifo_count, (unsigned int) count);
+ NCR5380_dprint(NDEBUG_DMA, instance);
}
/* setup udc */
@@ -325,21 +258,6 @@ static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int wri
}
-#ifndef SUN3_SCSI_VME
-static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
-{
- unsigned short resid;
-
- dregs->udc_addr = 0x32;
- udelay(SUN3_DMA_DELAY);
- resid = dregs->udc_data;
- udelay(SUN3_DMA_DELAY);
- resid *= 2;
-
- return (unsigned long) resid;
-}
-#endif
-
static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
{
return last_residual;
@@ -437,7 +355,10 @@ static int sun3scsi_dma_finish(int write_flag)
}
}
- count = sun3scsi_dma_count(default_instance);
+ dregs->udc_addr = 0x32;
+ udelay(SUN3_DMA_DELAY);
+ count = 2 * dregs->udc_data;
+ udelay(SUN3_DMA_DELAY);
fifo = dregs->fifo_count;
last_residual = fifo;
@@ -502,17 +423,17 @@ static int sun3scsi_dma_finish(int write_flag)
static struct scsi_host_template sun3_scsi_template = {
.module = THIS_MODULE,
.proc_name = DRV_MODULE_NAME,
- .show_info = sun3scsi_show_info,
.name = SUN3_SCSI_NAME,
.info = sun3scsi_info,
.queuecommand = sun3scsi_queue_command,
- .eh_abort_handler = sun3scsi_abort,
- .eh_bus_reset_handler = sun3scsi_bus_reset,
+ .eh_abort_handler = sun3scsi_abort,
+ .eh_bus_reset_handler = sun3scsi_bus_reset,
.can_queue = 16,
.this_id = 7,
.sg_tablesize = SG_NONE,
.cmd_per_lun = 2,
- .use_clustering = DISABLE_CLUSTERING
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
};
static int __init sun3_scsi_probe(struct platform_device *pdev)
@@ -591,7 +512,6 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
error = -ENOMEM;
goto fail_alloc;
}
- default_instance = instance;
instance->io_port = (unsigned long)ioaddr;
instance->irq = irq->start;
@@ -600,7 +520,9 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
#endif
- NCR5380_init(instance, host_flags);
+ error = NCR5380_init(instance, host_flags);
+ if (error)
+ goto fail_init;
error = request_irq(instance->irq, scsi_sun3_intr, 0,
"NCR5380", instance);
@@ -631,9 +553,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev)
dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
#endif
-#ifdef RESET_BOOT
- sun3_scsi_reset_boot(instance);
-#endif
+ NCR5380_maybe_reset_bus(instance);
error = scsi_add_host(instance, NULL);
if (error)
@@ -649,6 +569,7 @@ fail_host:
free_irq(instance->irq, instance);
fail_irq:
NCR5380_exit(instance);
+fail_init:
scsi_host_put(instance);
fail_alloc:
if (udc_regs)
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 87828acbf..4615fda60 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -68,14 +68,11 @@
* 15 9-11
*/
-#include <linux/signal.h>
#include <linux/io.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
-#include <linux/stat.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/delay.h>
#include <scsi/scsi_host.h>
#include "t128.h"
@@ -126,7 +123,7 @@ static struct signature {
static int __init t128_setup(char *str)
{
- static int commandline_current = 0;
+ static int commandline_current;
int i;
int ints[10];
@@ -165,7 +162,7 @@ __setup("t128=", t128_setup);
static int __init t128_detect(struct scsi_host_template *tpnt)
{
- static int current_override = 0, current_base = 0;
+ static int current_override, current_base;
struct Scsi_Host *instance;
unsigned long base;
void __iomem *p;
@@ -182,9 +179,8 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
base = 0;
} else
for (; !base && (current_base < NO_BASES); ++current_base) {
-#if (TDEBUG & TDEBUG_INIT)
- printk("scsi-t128 : probing address %08x\n", bases[current_base].address);
-#endif
+ dprintk(NDEBUG_INIT, "t128: probing address 0x%08x\n",
+ bases[current_base].address);
if (bases[current_base].noauto)
continue;
p = ioremap(bases[current_base].address, 0x2000);
@@ -195,17 +191,13 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
signatures[sig].string,
strlen(signatures[sig].string))) {
base = bases[current_base].address;
-#if (TDEBUG & TDEBUG_INIT)
- printk("scsi-t128 : detected board.\n");
-#endif
+ dprintk(NDEBUG_INIT, "t128: detected board\n");
goto found;
}
iounmap(p);
}
-#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
- printk("scsi-t128 : base = %08x\n", (unsigned int) base);
-#endif
+ dprintk(NDEBUG_INIT, "t128: base = 0x%08x\n", (unsigned int)base);
if (!base)
break;
@@ -213,12 +205,15 @@ static int __init t128_detect(struct scsi_host_template *tpnt)
found:
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
if(instance == NULL)
- break;
-
+ goto out_unmap;
+
instance->base = base;
((struct NCR5380_hostdata *)instance->hostdata)->base = p;
- NCR5380_init(instance, 0);
+ if (NCR5380_init(instance, 0))
+ goto out_unregister;
+
+ NCR5380_maybe_reset_bus(instance);
if (overrides[current_override].irq != IRQ_AUTO)
instance->irq = overrides[current_override].irq;
@@ -242,27 +237,30 @@ found:
printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
}
-#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
- printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
-#endif
+ dprintk(NDEBUG_INIT, "scsi%d: irq = %d\n",
+ instance->host_no, instance->irq);
++current_override;
++count;
}
return count;
+
+out_unregister:
+ scsi_unregister(instance);
+out_unmap:
+ iounmap(p);
+ return count;
}
static int t128_release(struct Scsi_Host *shost)
{
- NCR5380_local_declare();
- NCR5380_setup(shost);
+ struct NCR5380_hostdata *hostdata = shost_priv(shost);
+
if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
scsi_unregister(shost);
- iounmap(base);
+ iounmap(hostdata->base);
return 0;
}
@@ -308,14 +306,14 @@ static int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev,
* timeout.
*/
-static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
- int len) {
- NCR5380_local_declare();
- void __iomem *reg;
+static inline int
+NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ void __iomem *reg, *base = hostdata->base;
unsigned char *d = dst;
register int i = len;
- NCR5380_setup(instance);
reg = base + T_DATA_REG_OFFSET;
#if 0
@@ -354,14 +352,14 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
* timeout.
*/
-static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
- int len) {
- NCR5380_local_declare();
- void __iomem *reg;
+static inline int
+NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ void __iomem *reg, *base = hostdata->base;
unsigned char *s = src;
register int i = len;
- NCR5380_setup(instance);
reg = base + T_DATA_REG_OFFSET;
#if 0
@@ -392,21 +390,23 @@ MODULE_LICENSE("GPL");
#include "NCR5380.c"
static struct scsi_host_template driver_template = {
- .name = "Trantor T128/T128F/T228",
- .detect = t128_detect,
- .release = t128_release,
- .proc_name = "t128",
- .show_info = t128_show_info,
- .write_info = t128_write_info,
- .info = t128_info,
- .queuecommand = t128_queue_command,
- .eh_abort_handler = t128_abort,
- .eh_bus_reset_handler = t128_bus_reset,
- .bios_param = t128_biosparam,
- .can_queue = CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
- .use_clustering = DISABLE_CLUSTERING,
+ .name = "Trantor T128/T128F/T228",
+ .detect = t128_detect,
+ .release = t128_release,
+ .proc_name = "t128",
+ .show_info = t128_show_info,
+ .write_info = t128_write_info,
+ .info = t128_info,
+ .queuecommand = t128_queue_command,
+ .eh_abort_handler = t128_abort,
+ .eh_bus_reset_handler = t128_bus_reset,
+ .bios_param = t128_biosparam,
+ .can_queue = 32,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 2,
+ .use_clustering = DISABLE_CLUSTERING,
+ .cmd_size = NCR5380_CMD_SIZE,
+ .max_sectors = 128,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index 2c7371454..dd16d8549 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -23,10 +23,6 @@
#ifndef T128_H
#define T128_H
-#define TDEBUG 0
-#define TDEBUG_INIT 0x1
-#define TDEBUG_TRANSFER 0x2
-
/*
* The trantor boards are memory mapped. They use an NCR5380 or
* equivalent (my sample board had part second sourced from ZILOG).
@@ -71,44 +67,18 @@
#define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 32
-#endif
-
#define NCR5380_implementation_fields \
void __iomem *base
-#define NCR5380_local_declare() \
- void __iomem *base
-
-#define NCR5380_setup(instance) \
- base = ((struct NCR5380_hostdata *)(instance->hostdata))->base
+#define T128_address(reg) \
+ (((struct NCR5380_hostdata *)shost_priv(instance))->base + T_5380_OFFSET + ((reg) * 0x20))
-#define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20))
-
-#if !(TDEBUG & TDEBUG_TRANSFER)
#define NCR5380_read(reg) readb(T128_address(reg))
#define NCR5380_write(reg, value) writeb((value),(T128_address(reg)))
-#else
-#define NCR5380_read(reg) \
- (((unsigned char) printk("scsi%d : read register %d at address %08x\n"\
- , instance->hostno, (reg), T128_address(reg))), readb(T128_address(reg)))
-
-#define NCR5380_write(reg, value) { \
- printk("scsi%d : write %02x to register %d at address %08x\n", \
- instance->hostno, (value), (reg), T128_address(reg)); \
- writeb((value), (T128_address(reg))); \
-}
-#endif
+
+#define NCR5380_dma_xfer_len(instance, cmd, phase) (cmd->transfersize)
#define NCR5380_intr t128_intr
-#define do_NCR5380_intr do_t128_intr
#define NCR5380_queue_command t128_queue_command
#define NCR5380_abort t128_abort
#define NCR5380_bus_reset t128_bus_reset
@@ -121,5 +91,4 @@
#define T128_IRQS 0xc4a8
-#endif /* ndef ASM */
#endif /* T128_H */
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 9714f2a8b..d2a7b127b 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -333,7 +333,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
err = ufshcd_init(hba, mmio_base, irq);
if (err) {
- dev_err(dev, "Intialization failed\n");
+ dev_err(dev, "Initialization failed\n");
goto out_disable_rpm;
}
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 0f133c181..6164634af 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -349,9 +349,9 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx,
* Map all data buffers for a command into PCI space and
* setup the scatter/gather list if needed.
*/
-static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
- struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
- struct PVSCSIRingReqDesc *e)
+static int pvscsi_map_buffers(struct pvscsi_adapter *adapter,
+ struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd,
+ struct PVSCSIRingReqDesc *e)
{
unsigned count;
unsigned bufflen = scsi_bufflen(cmd);
@@ -360,18 +360,30 @@ static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
e->dataLen = bufflen;
e->dataAddr = 0;
if (bufflen == 0)
- return;
+ return 0;
sg = scsi_sglist(cmd);
count = scsi_sg_count(cmd);
if (count != 0) {
int segs = scsi_dma_map(cmd);
- if (segs > 1) {
+
+ if (segs == -ENOMEM) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map cmd sglist for DMA.\n");
+ return -ENOMEM;
+ } else if (segs > 1) {
pvscsi_create_sg(ctx, sg, segs);
e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST;
ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl,
SGL_SIZE, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(adapter->dev, ctx->sglPA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map ctx sglist for DMA.\n");
+ scsi_dma_unmap(cmd);
+ ctx->sglPA = 0;
+ return -ENOMEM;
+ }
e->dataAddr = ctx->sglPA;
} else
e->dataAddr = sg_dma_address(sg);
@@ -382,8 +394,15 @@ static void pvscsi_map_buffers(struct pvscsi_adapter *adapter,
*/
ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen,
cmd->sc_data_direction);
+ if (pci_dma_mapping_error(adapter->dev, ctx->dataPA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map direct data buffer for DMA.\n");
+ return -ENOMEM;
+ }
e->dataAddr = ctx->dataPA;
}
+
+ return 0;
}
static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter,
@@ -690,6 +709,12 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer,
SCSI_SENSE_BUFFERSIZE,
PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(adapter->dev, ctx->sensePA)) {
+ scmd_printk(KERN_ERR, cmd,
+ "vmw_pvscsi: Failed to map sense buffer for DMA.\n");
+ ctx->sensePA = 0;
+ return -ENOMEM;
+ }
e->senseAddr = ctx->sensePA;
e->senseLen = SCSI_SENSE_BUFFERSIZE;
} else {
@@ -711,7 +736,15 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
else
e->flags = 0;
- pvscsi_map_buffers(adapter, ctx, cmd, e);
+ if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) {
+ if (cmd->sense_buffer) {
+ pci_unmap_single(adapter->dev, ctx->sensePA,
+ SCSI_SENSE_BUFFERSIZE,
+ PCI_DMA_FROMDEVICE);
+ ctx->sensePA = 0;
+ }
+ return -ENOMEM;
+ }
e->context = pvscsi_map_context(adapter, ctx);
diff --git a/drivers/scsi/vmw_pvscsi.h b/drivers/scsi/vmw_pvscsi.h
index ee16f0c5c..12712c92f 100644
--- a/drivers/scsi/vmw_pvscsi.h
+++ b/drivers/scsi/vmw_pvscsi.h
@@ -26,7 +26,7 @@
#include <linux/types.h>
-#define PVSCSI_DRIVER_VERSION_STRING "1.0.5.0-k"
+#define PVSCSI_DRIVER_VERSION_STRING "1.0.6.0-k"
#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128