Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
authorLinus Torvalds <torvalds@woody.osdl.org>
Wed, 6 Dec 2006 00:09:46 +0000 (16:09 -0800)
committerLinus Torvalds <torvalds@woody.osdl.org>
Wed, 6 Dec 2006 00:09:46 +0000 (16:09 -0800)
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (73 commits)
  [SCSI] aic79xx: Add ASC-29320LPE ids to driver
  [SCSI] stex: version update
  [SCSI] stex: change wait loop code
  [SCSI] stex: add new device type support
  [SCSI] stex: update device id info
  [SCSI] stex: adjust default queue length
  [SCSI] stex: add value check in hard reset routine
  [SCSI] stex: fix controller_info command handling
  [SCSI] stex: fix biosparam calculation
  [SCSI] megaraid: fix MMIO casts
  [SCSI] tgt: fix undefined flush_dcache_page() problem
  [SCSI] libsas: better error handling in sas_expander.c
  [SCSI] lpfc 8.1.11 : Change version number to 8.1.11
  [SCSI] lpfc 8.1.11 : Misc Fixes
  [SCSI] lpfc 8.1.11 : Add soft_wwnn sysfs attribute, rename soft_wwn_enable
  [SCSI] lpfc 8.1.11 : Removed decoding of PCI Subsystem Id
  [SCSI] lpfc 8.1.11 : Add MSI (Message Signalled Interrupts) support
  [SCSI] lpfc 8.1.11 : Adjust LOG_FCP logging
  [SCSI] lpfc 8.1.11 : Fix Memory leaks
  [SCSI] lpfc 8.1.11 : Fix lpfc_multi_ring_support
  ...

83 files changed:
Documentation/kernel-parameters.txt
Documentation/scsi/scsi_mid_low_api.txt
block/scsi_ioctl.c
drivers/scsi/53c700.c
drivers/scsi/BusLogic.c
drivers/scsi/Kconfig
drivers/scsi/Makefile
drivers/scsi/NCR53c406a.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commsup.c
drivers/scsi/aha1740.c
drivers/scsi/aic7xxx/aic79xx_osm_pci.c
drivers/scsi/aic7xxx/aic79xx_pci.c
drivers/scsi/aic7xxx/aic79xx_pci.h
drivers/scsi/aic94xx/aic94xx_init.c
drivers/scsi/aic94xx/aic94xx_scb.c
drivers/scsi/fd_mcs.c
drivers/scsi/hosts.c
drivers/scsi/ibmvscsi/Makefile
drivers/scsi/ibmvscsi/ibmvstgt.c [new file with mode: 0644]
drivers/scsi/initio.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/ips.c
drivers/scsi/ips.h
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_init.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/libsrp.c [new file with mode: 0644]
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_logmsg.h
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid.c
drivers/scsi/megaraid.h
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/ncr53c8xx.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla4xxx/ql4_dbg.c
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_fw.h
drivers/scsi/qla4xxx/ql4_glbl.h
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_inline.h
drivers/scsi/qla4xxx/ql4_iocb.c
drivers/scsi/qla4xxx/ql4_isr.c
drivers/scsi/qla4xxx/ql4_nvram.c
drivers/scsi/qla4xxx/ql4_nvram.h
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qla4xxx/ql4_version.h
drivers/scsi/scsi.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_tgt_if.c [new file with mode: 0644]
drivers/scsi/scsi_tgt_lib.c [new file with mode: 0644]
drivers/scsi/scsi_tgt_priv.h [new file with mode: 0644]
drivers/scsi/scsi_wait_scan.c [new file with mode: 0644]
drivers/scsi/sd.c
drivers/scsi/st.c
drivers/scsi/stex.c
drivers/scsi/t128.h
include/scsi/libsas.h
include/scsi/libsrp.h [new file with mode: 0644]
include/scsi/scsi_cmnd.h
include/scsi/scsi_device.h
include/scsi/scsi_host.h
include/scsi/scsi_tgt.h [new file with mode: 0644]
include/scsi/scsi_tgt_if.h [new file with mode: 0644]
include/scsi/scsi_transport_sas.h

index 15e4fed127f69bd3200d2a8ae1e59832570def7e..2e1898e4e8fd38e67ac9913480178454b094355e 100644 (file)
@@ -1416,6 +1416,11 @@ and is between 256 and 4096 characters. It is defined in the file
 
        scsi_logging=   [SCSI]
 
+       scsi_mod.scan=  [SCSI] sync (default) scans SCSI busses as they are
+                       discovered.  async scans them in kernel threads,
+                       allowing boot to proceed.  none ignores them, expecting
+                       user space to do the scan.
+
        selinux         [SELINUX] Disable or enable SELinux at boot time.
                        Format: { "0" | "1" }
                        See security/selinux/Kconfig help text.
index 75a535a975c361986b40aa881cda3a49997455ae..6f70f2b9327e1f0db7bc05bdbf2d6ce3b2fcbdcf 100644 (file)
@@ -375,7 +375,6 @@ Summary:
    scsi_add_device - creates new scsi device (lu) instance
    scsi_add_host - perform sysfs registration and set up transport class
    scsi_adjust_queue_depth - change the queue depth on a SCSI device
-   scsi_assign_lock - replace default host_lock with given lock
    scsi_bios_ptable - return copy of block device's partition table
    scsi_block_requests - prevent further commands being queued to given host
    scsi_deactivate_tcq - turn off tag command queueing
@@ -488,20 +487,6 @@ void scsi_adjust_queue_depth(struct scsi_device * sdev, int tagged,
                              int tags)
 
 
-/**
- * scsi_assign_lock - replace default host_lock with given lock
- * @shost: a pointer to a scsi host instance
- * @lock: pointer to lock to replace host_lock for this host
- *
- *      Returns nothing
- *
- *      Might block: no
- *
- *      Defined in: include/scsi/scsi_host.h .
- **/
-void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock)
-
-
 /**
  * scsi_bios_ptable - return copy of block device's partition table
  * @dev:        pointer to block device
@@ -1366,17 +1351,11 @@ Locks
 Each struct Scsi_Host instance has a spin_lock called struct 
 Scsi_Host::default_lock which is initialized in scsi_host_alloc() [found in 
 hosts.c]. Within the same function the struct Scsi_Host::host_lock pointer
-is initialized to point at default_lock with the scsi_assign_lock() function.
-Thereafter lock and unlock operations performed by the mid level use the
-struct Scsi_Host::host_lock pointer.
-
-LLDs can override the use of struct Scsi_Host::default_lock by
-using scsi_assign_lock(). The earliest opportunity to do this would
-be in the detect() function after it has invoked scsi_register(). It
-could be replaced by a coarser grain lock (e.g. per driver) or a
-lock of equal granularity (i.e. per host). Using finer grain locks 
-(e.g. per SCSI device) may be possible by juggling locks in
-queuecommand().
+is initialized to point at default_lock.  Thereafter lock and unlock
+operations performed by the mid level use the struct Scsi_Host::host_lock
+pointer.  Previously drivers could override the host_lock pointer but
+this is not allowed anymore.
+
 
 Autosense
 =========
index 5493c2fbbab177335814a24362b95763eb5dc820..b3e210723a71f637605852b7d8136ef594af95d2 100644 (file)
@@ -277,7 +277,7 @@ static int sg_io(struct file *file, request_queue_t *q,
        if (rq->bio)
                blk_queue_bounce(q, &rq->bio);
 
-       rq->timeout = (hdr->timeout * HZ) / 1000;
+       rq->timeout = jiffies_to_msecs(hdr->timeout);
        if (!rq->timeout)
                rq->timeout = q->sg_timeout;
        if (!rq->timeout)
index 562432d017b0c39cc74704031bb4dc1a46df30d8..335a25540c08687b5c171aa74ec7124c7465cace 100644 (file)
@@ -622,8 +622,10 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
                        dma_unmap_single(hostdata->dev, slot->dma_handle, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
                        /* restore the old result if the request sense was
                         * successful */
-                       if(result == 0)
+                       if (result == 0)
                                result = cmnd[7];
+                       /* restore the original length */
+                       SCp->cmd_len = cmnd[8];
                } else
                        NCR_700_unmap(hostdata, SCp, slot);
 
@@ -1007,6 +1009,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
                                 * of the command */
                                cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
                                cmnd[7] = hostdata->status[0];
+                               cmnd[8] = SCp->cmd_len;
+                               SCp->cmd_len = 6; /* command length for
+                                                  * REQUEST_SENSE */
                                slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE);
                                slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
                                slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
index cdd03372478617f3e13a2220cc715fb836f7d0b7..3075204915c867b532509788e18668393840dd0b 100644 (file)
@@ -2186,21 +2186,21 @@ static int __init BusLogic_init(void)
 
        if (BusLogic_ProbeOptions.NoProbe)
                return -ENODEV;
-       BusLogic_ProbeInfoList = (struct BusLogic_ProbeInfo *)
-           kmalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_ATOMIC);
+       BusLogic_ProbeInfoList =
+           kzalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_KERNEL);
        if (BusLogic_ProbeInfoList == NULL) {
                BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL);
                return -ENOMEM;
        }
-       memset(BusLogic_ProbeInfoList, 0, BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo));
-       PrototypeHostAdapter = (struct BusLogic_HostAdapter *)
-           kmalloc(sizeof(struct BusLogic_HostAdapter), GFP_ATOMIC);
+
+       PrototypeHostAdapter =
+           kzalloc(sizeof(struct BusLogic_HostAdapter), GFP_KERNEL);
        if (PrototypeHostAdapter == NULL) {
                kfree(BusLogic_ProbeInfoList);
                BusLogic_Error("BusLogic: Unable to allocate Prototype " "Host Adapter\n", NULL);
                return -ENOMEM;
        }
-       memset(PrototypeHostAdapter, 0, sizeof(struct BusLogic_HostAdapter));
+
 #ifdef MODULE
        if (BusLogic != NULL)
                BusLogic_Setup(BusLogic);
index 9540eb8efdcbfc5b6db2051470bf9a203112fe59..69569096dae537f164d52df669510de68bf866a8 100644 (file)
@@ -29,6 +29,13 @@ config SCSI
          However, do not compile this as a module if your root file system
          (the one containing the directory /) is located on a SCSI device.
 
+config SCSI_TGT
+       tristate "SCSI target support"
+       depends on SCSI && EXPERIMENTAL
+       ---help---
+         If you want to use SCSI target mode drivers enable this option.
+         If you choose M, the module will be called scsi_tgt.
+
 config SCSI_NETLINK
        bool
        default n
@@ -216,6 +223,23 @@ config SCSI_LOGGING
          there should be no noticeable performance impact as long as you have
          logging turned off.
 
+config SCSI_SCAN_ASYNC
+       bool "Asynchronous SCSI scanning"
+       depends on SCSI
+       help
+         The SCSI subsystem can probe for devices while the rest of the
+         system continues booting, and even probe devices on different
+         busses in parallel, leading to a significant speed-up.
+         If you have built SCSI as modules, enabling this option can
+         be a problem as the devices may not have been found by the
+         time your system expects them to have been.  You can load the
+         scsi_wait_scan module to ensure that all scans have completed.
+         If you build your SCSI drivers into the kernel, then everything
+         will work fine if you say Y here.
+
+         You can override this choice by specifying scsi_mod.scan="sync"
+         or "async" on the kernel's command line.
+
 menu "SCSI Transports"
        depends on SCSI
 
@@ -797,6 +821,20 @@ config SCSI_IBMVSCSI
          To compile this driver as a module, choose M here: the
          module will be called ibmvscsic.
 
+config SCSI_IBMVSCSIS
+       tristate "IBM Virtual SCSI Server support"
+       depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP
+       help
+         This is the SRP target driver for IBM pSeries virtual environments.
+
+         The userspace component needed to initialize the driver and
+         documentation can be found:
+
+         http://stgt.berlios.de/
+
+         To compile this driver as a module, choose M here: the
+         module will be called ibmvstgt.
+
 config SCSI_INITIO
        tristate "Initio 9100U(W) support"
        depends on PCI && SCSI
@@ -944,8 +982,13 @@ config SCSI_STEX
        tristate "Promise SuperTrak EX Series support"
        depends on PCI && SCSI
        ---help---
-         This driver supports Promise SuperTrak EX8350/8300/16350/16300
-         Storage controllers.
+         This driver supports Promise SuperTrak EX series storage controllers.
+
+         Promise provides Linux RAID configuration utility for these
+         controllers. Please visit <http://www.promise.com> to download.
+
+         To compile this driver as a module, choose M here: the
+         module will be called stex.
 
 config SCSI_SYM53C8XX_2
        tristate "SYM53C8XX Version 2 SCSI support"
@@ -1026,6 +1069,7 @@ config SCSI_IPR
 config SCSI_IPR_TRACE
        bool "enable driver internal trace"
        depends on SCSI_IPR
+       default y
        help
          If you say Y here, the driver will trace all commands issued
          to the adapter. Performance impact is minimal. Trace can be
@@ -1034,6 +1078,7 @@ config SCSI_IPR_TRACE
 config SCSI_IPR_DUMP
        bool "enable adapter dump support"
        depends on SCSI_IPR
+       default y
        help
          If you say Y here, the driver will support adapter crash dump.
          If you enable this support, the iprdump daemon can be used
@@ -1734,6 +1779,16 @@ config ZFCP
           called zfcp. If you want to compile it as a module, say M here
           and read <file:Documentation/modules.txt>.
 
+config SCSI_SRP
+       tristate "SCSI RDMA Protocol helper library"
+       depends on SCSI && PCI
+       select SCSI_TGT
+       help
+         If you wish to use SRP target drivers, say Y.
+
+         To compile this driver as a module, choose M here: the
+         module will be called libsrp.
+
 endmenu
 
 source "drivers/scsi/pcmcia/Kconfig"
index bcca39c3bcbf33096bb3fdc5c9a493996c2c9492..bd7c9888f7f40ca31052e1fa62796fbb08fb9e37 100644 (file)
@@ -21,6 +21,7 @@ CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
 subdir-$(CONFIG_PCMCIA)                += pcmcia
 
 obj-$(CONFIG_SCSI)             += scsi_mod.o
+obj-$(CONFIG_SCSI_TGT)         += scsi_tgt.o
 
 obj-$(CONFIG_RAID_ATTRS)       += raid_class.o
 
@@ -125,7 +126,9 @@ obj-$(CONFIG_SCSI_FCAL)             += fcal.o
 obj-$(CONFIG_SCSI_LASI700)     += 53c700.o lasi700.o
 obj-$(CONFIG_SCSI_NSP32)       += nsp32.o
 obj-$(CONFIG_SCSI_IPR)         += ipr.o
+obj-$(CONFIG_SCSI_SRP)         += libsrp.o
 obj-$(CONFIG_SCSI_IBMVSCSI)    += ibmvscsi/
+obj-$(CONFIG_SCSI_IBMVSCSIS)   += ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)      += hptiop.o
 obj-$(CONFIG_SCSI_STEX)                += stex.o
 
@@ -141,6 +144,8 @@ obj-$(CONFIG_CHR_DEV_SCH)   += ch.o
 # This goes last, so that "real" scsi devices probe earlier
 obj-$(CONFIG_SCSI_DEBUG)       += scsi_debug.o
 
+obj-$(CONFIG_SCSI)             += scsi_wait_scan.o
+
 scsi_mod-y                     += scsi.o hosts.o scsi_ioctl.o constants.o \
                                   scsicam.o scsi_error.o scsi_lib.o \
                                   scsi_scan.o scsi_sysfs.o \
@@ -149,6 +154,8 @@ scsi_mod-$(CONFIG_SCSI_NETLINK)     += scsi_netlink.o
 scsi_mod-$(CONFIG_SYSCTL)      += scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)        += scsi_proc.o
 
+scsi_tgt-y                     += scsi_tgt_lib.o scsi_tgt_if.o
+
 sd_mod-objs    := sd.o
 sr_mod-objs    := sr.o sr_ioctl.o sr_vendor.o
 ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
index d4613815f685d26115808d1887223e3c8d7b2e96..8578555d58fd08f79a4515af12c7f9e990d8cdd4 100644 (file)
@@ -220,9 +220,11 @@ static void *addresses[] = {
 static unsigned short ports[] = { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 };
 #define PORT_COUNT ARRAY_SIZE(ports)
 
+#ifndef MODULE
 /* possible interrupt channels */
 static unsigned short intrs[] = { 10, 11, 12, 15 };
 #define INTR_COUNT ARRAY_SIZE(intrs)
+#endif /* !MODULE */
 
 /* signatures for NCR 53c406a based controllers */
 #if USE_BIOS
@@ -605,6 +607,7 @@ static int NCR53c406a_release(struct Scsi_Host *shost)
        return 0;
 }
 
+#ifndef MODULE
 /* called from init/main.c */
 static int __init NCR53c406a_setup(char *str)
 {
@@ -661,6 +664,8 @@ static int __init NCR53c406a_setup(char *str)
 
 __setup("ncr53c406a=", NCR53c406a_setup);
 
+#endif /* !MODULE */
+
 static const char *NCR53c406a_info(struct Scsi_Host *SChost)
 {
        DEB(printk("NCR53c406a_info called\n"));
index eb3ed91bac796674a3ab0ce485282bcec7ab8490..4f8b4c53d435867da99381898093ab5cc393dec5 100644 (file)
@@ -11,8 +11,8 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2409
-# define AAC_DRIVER_BRANCH "-mh2"
+# define AAC_DRIVER_BUILD 2423
+# define AAC_DRIVER_BRANCH "-mh3"
 #endif
 #define MAXIMUM_NUM_CONTAINERS 32
 
index 19e42ac07cb228dd09dc771ec9a85f6513f877fd..4893a6d06a332ac6f32500f3e0ebc3a1a7183838 100644 (file)
@@ -518,6 +518,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
                         */
                        unsigned long count = 36000000L; /* 3 minutes */
                        while (down_trylock(&fibptr->event_wait)) {
+                               int blink;
                                if (--count == 0) {
                                        spin_lock_irqsave(q->lock, qflags);
                                        q->numpending--;
@@ -530,6 +531,14 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
                                        }
                                        return -ETIMEDOUT;
                                }
+                               if ((blink = aac_adapter_check_health(dev)) > 0) {
+                                       if (wait == -1) {
+                                               printk(KERN_ERR "aacraid: aac_fib_send: adapter blinkLED 0x%x.\n"
+                                                 "Usually a result of a serious unrecoverable hardware problem\n",
+                                                 blink);
+                                       }
+                                       return -EFAULT;
+                               }
                                udelay(5);
                        }
                } else if (down_interruptible(&fibptr->event_wait)) {
@@ -1093,6 +1102,20 @@ static int _aac_reset_adapter(struct aac_dev *aac)
                goto out;
        }
 
+       /*
+        *      Loop through the fibs, close the synchronous FIBS
+        */
+       for (index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
+               struct fib *fib = &aac->fibs[index];
+               if (!(fib->hw_fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
+                 (fib->hw_fib->header.XferState & cpu_to_le32(ResponseExpected))) {
+                       unsigned long flagv;
+                       spin_lock_irqsave(&fib->event_lock, flagv);
+                       up(&fib->event_wait);
+                       spin_unlock_irqrestore(&fib->event_lock, flagv);
+                       schedule();
+               }
+       }
        index = aac->cardtype;
 
        /*
index c3c38a7e8d32d091a3bbd7ee925d7e81bc1492d2..d7af9c63a04d66d2f4dd2536725c39a901fe7d6f 100644 (file)
@@ -586,7 +586,7 @@ static struct scsi_host_template aha1740_template = {
 
 static int aha1740_probe (struct device *dev)
 {
-       int slotbase;
+       int slotbase, rc;
        unsigned int irq_level, irq_type, translation;
        struct Scsi_Host *shpnt;
        struct aha1740_hostdata *host;
@@ -641,10 +641,16 @@ static int aha1740_probe (struct device *dev)
        }
 
        eisa_set_drvdata (edev, shpnt);
-       scsi_add_host (shpnt, dev); /* XXX handle failure */
+
+       rc = scsi_add_host (shpnt, dev);
+       if (rc)
+               goto err_irq;
+
        scsi_scan_host (shpnt);
        return 0;
 
+ err_irq:
+       free_irq(irq_level, shpnt);
  err_unmap:
        dma_unmap_single (&edev->dev, host->ecb_dma_addr,
                          sizeof (host->ecb), DMA_BIDIRECTIONAL);
index 2001fe890e71651ed36eb5cdc701fcf28ee74e02..1a3ab6aa856bb158e79574a4856e8374bbeb5127 100644 (file)
@@ -62,6 +62,7 @@ static struct pci_device_id ahd_linux_pci_id_table[] = {
        /* aic7901 based controllers */
        ID(ID_AHA_29320A),
        ID(ID_AHA_29320ALP),
+       ID(ID_AHA_29320LPE),
        /* aic7902 based controllers */
        ID(ID_AHA_29320),
        ID(ID_AHA_29320B),
index c07735819cd1d1aba2f3cabe9085d9d4e0dc6414..2cf7bb3123f099c732ba665c514b085ee0eb60e1 100644 (file)
@@ -109,7 +109,13 @@ static struct ahd_pci_identity ahd_pci_ident_table [] =
        {
                ID_AHA_29320ALP,
                ID_ALL_MASK,
-               "Adaptec 29320ALP Ultra320 SCSI adapter",
+               "Adaptec 29320ALP PCIx Ultra320 SCSI adapter",
+               ahd_aic7901_setup
+       },
+       {
+               ID_AHA_29320LPE,
+               ID_ALL_MASK,
+               "Adaptec 29320LPE PCIe Ultra320 SCSI adapter",
                ahd_aic7901_setup
        },
        /* aic7901A based controllers */
index da45153668c7589587c4a3a831125c26d24db66d..16b7c70a673cecd7efca7b224fe10cc44f72ebf8 100644 (file)
@@ -51,6 +51,7 @@
 #define ID_AIC7901                     0x800F9005FFFF9005ull
 #define ID_AHA_29320A                  0x8000900500609005ull
 #define ID_AHA_29320ALP                        0x8017900500449005ull
+#define ID_AHA_29320LPE                        0x8017900500459005ull
 
 #define ID_AIC7901A                    0x801E9005FFFF9005ull
 #define ID_AHA_29320LP                 0x8014900500449005ull
index 57c5ba4043f29f99c9410ce039114bc2edc94134..42302ef05ee56579777d2854e7d6e0c6942dfdf2 100644 (file)
@@ -724,6 +724,15 @@ static void asd_free_queues(struct asd_ha_struct *asd_ha)
 
        list_for_each_safe(pos, n, &pending) {
                struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list);
+               /*
+                * Delete unexpired ascb timers.  This may happen if we issue
+                * a CONTROL PHY scb to an adapter and rmmod before the scb
+                * times out.  Apparently we don't wait for the CONTROL PHY
+                * to complete, so it doesn't matter if we kill the timer.
+                */
+               del_timer_sync(&ascb->timer);
+               WARN_ON(ascb->scb->header.opcode != CONTROL_PHY);
+
                list_del_init(pos);
                ASD_DPRINTK("freeing from pending\n");
                asd_ascb_free(ascb);
index b15caf1c8fa21c2ffed74c9b1d2ed73259133ae3..14d5d8c2ee1334f1a62b4c2016960209d20892c4 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/pci.h>
+#include <scsi/scsi_host.h>
 
 #include "aic94xx.h"
 #include "aic94xx_reg.h"
@@ -412,6 +413,39 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
        }
 }
 
+/* hard reset a phy later */
+static void do_phy_reset_later(void *data)
+{
+       struct sas_phy *sas_phy = data;
+       int error;
+
+       ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__,
+                   sas_phy->identify.phy_identifier);
+       /* Reset device port */
+       error = sas_phy_reset(sas_phy, 1);
+       if (error)
+               ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n",
+                           __FUNCTION__, sas_phy->identify.phy_identifier, error);
+}
+
+static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost)
+{
+       INIT_WORK(&sas_phy->reset_work, do_phy_reset_later, sas_phy);
+       queue_work(shost->work_q, &sas_phy->reset_work);
+}
+
+/* start up the ABORT TASK tmf... */
+static void task_kill_later(struct asd_ascb *ascb)
+{
+       struct asd_ha_struct *asd_ha = ascb->ha;
+       struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+       struct Scsi_Host *shost = sas_ha->core.shost;
+       struct sas_task *task = ascb->uldd_task;
+
+       INIT_WORK(&task->abort_work, (void (*)(void *))sas_task_abort, task);
+       queue_work(shost->work_q, &task->abort_work);
+}
+
 static void escb_tasklet_complete(struct asd_ascb *ascb,
                                  struct done_list_struct *dl)
 {
@@ -439,6 +473,74 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
                            ascb->scb->header.opcode);
        }
 
+       /* Catch these before we mask off the sb_opcode bits */
+       switch (sb_opcode) {
+       case REQ_TASK_ABORT: {
+               struct asd_ascb *a, *b;
+               u16 tc_abort;
+
+               tc_abort = *((u16*)(&dl->status_block[1]));
+               tc_abort = le16_to_cpu(tc_abort);
+
+               ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
+                           __FUNCTION__, dl->status_block[3]);
+
+               /* Find the pending task and abort it. */
+               list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list)
+                       if (a->tc_index == tc_abort) {
+                               task_kill_later(a);
+                               break;
+                       }
+               goto out;
+       }
+       case REQ_DEVICE_RESET: {
+               struct Scsi_Host *shost = sas_ha->core.shost;
+               struct sas_phy *dev_phy;
+               struct asd_ascb *a;
+               u16 conn_handle;
+
+               conn_handle = *((u16*)(&dl->status_block[1]));
+               conn_handle = le16_to_cpu(conn_handle);
+
+               ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
+                           dl->status_block[3]);
+
+               /* Kill all pending tasks and reset the device */
+               dev_phy = NULL;
+               list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
+                       struct sas_task *task;
+                       struct domain_device *dev;
+                       u16 x;
+
+                       task = a->uldd_task;
+                       if (!task)
+                               continue;
+                       dev = task->dev;
+
+                       x = (unsigned long)dev->lldd_dev;
+                       if (x == conn_handle) {
+                               dev_phy = dev->port->phy;
+                               task_kill_later(a);
+                       }
+               }
+
+               /* Reset device port */
+               if (!dev_phy) {
+                       ASD_DPRINTK("%s: No pending commands; can't reset.\n",
+                                   __FUNCTION__);
+                       goto out;
+               }
+               phy_reset_later(dev_phy, shost);
+               goto out;
+       }
+       case SIGNAL_NCQ_ERROR:
+               ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__);
+               goto out;
+       case CLEAR_NCQ_ERROR:
+               ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__);
+               goto out;
+       }
+
        sb_opcode &= ~DL_PHY_MASK;
 
        switch (sb_opcode) {
@@ -469,22 +571,6 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
                asd_deform_port(asd_ha, phy);
                sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
                break;
-       case REQ_TASK_ABORT:
-               ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__,
-                           phy_id);
-               break;
-       case REQ_DEVICE_RESET:
-               ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__,
-                           phy_id);
-               break;
-       case SIGNAL_NCQ_ERROR:
-               ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__,
-                           phy_id);
-               break;
-       case CLEAR_NCQ_ERROR:
-               ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__,
-                           phy_id);
-               break;
        default:
                ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
                            phy_id, sb_opcode);
@@ -504,7 +590,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 
                break;
        }
-
+out:
        asd_invalidate_edb(ascb, edb);
 }
 
index ef8285c326e42f67547a390a397d01ab1d34ef21..668569e8856bdb635ad90d9aaa718abcedf0b754 100644 (file)
@@ -294,6 +294,7 @@ static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL };
 static int user_fifo_count = 0;
 static int user_fifo_size = 0;
 
+#ifndef MODULE
 static int __init fd_mcs_setup(char *str)
 {
        static int done_setup = 0;
@@ -311,6 +312,7 @@ static int __init fd_mcs_setup(char *str)
 }
 
 __setup("fd_mcs=", fd_mcs_setup);
+#endif /* !MODULE */
 
 static void print_banner(struct Scsi_Host *shpnt)
 {
index 68ef1636678dfe21189a39ebb10accba5068e70e..38c3a291efacd532cfdba99d7e7c291fc8de0395 100644 (file)
@@ -263,6 +263,10 @@ static void scsi_host_dev_release(struct device *dev)
                kthread_stop(shost->ehandler);
        if (shost->work_q)
                destroy_workqueue(shost->work_q);
+       if (shost->uspace_req_q) {
+               kfree(shost->uspace_req_q->queuedata);
+               scsi_free_queue(shost->uspace_req_q);
+       }
 
        scsi_destroy_command_freelist(shost);
        if (shost->bqt)
@@ -301,8 +305,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        if (!shost)
                return NULL;
 
-       spin_lock_init(&shost->default_lock);
-       scsi_assign_lock(shost, &shost->default_lock);
+       shost->host_lock = &shost->default_lock;
+       spin_lock_init(shost->host_lock);
        shost->shost_state = SHOST_CREATED;
        INIT_LIST_HEAD(&shost->__devices);
        INIT_LIST_HEAD(&shost->__targets);
index 4e247b6b8700b9b6c0d3195e83b0c2e4f7eeeeb6..6ac0633d5452af8c36a0683653485980335950e3 100644 (file)
@@ -3,3 +3,5 @@ obj-$(CONFIG_SCSI_IBMVSCSI)     += ibmvscsic.o
 ibmvscsic-y                    += ibmvscsi.o
 ibmvscsic-$(CONFIG_PPC_ISERIES)        += iseries_vscsi.o 
 ibmvscsic-$(CONFIG_PPC_PSERIES)        += rpa_vscsi.o 
+
+obj-$(CONFIG_SCSI_IBMVSCSIS)   += ibmvstgt.o
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
new file mode 100644 (file)
index 0000000..0e74174
--- /dev/null
@@ -0,0 +1,958 @@
+/*
+ * IBM eServer i/pSeries Virtual SCSI Target Driver
+ * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.
+ *                        Santiago Leon (santil@us.ibm.com) IBM Corp.
+ *                        Linda Xie (lxie@us.ibm.com) IBM Corp.
+ *
+ * Copyright (C) 2005-2006 FUJITA Tomonori <tomof@acm.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/libsrp.h>
+#include <asm/hvcall.h>
+#include <asm/iommu.h>
+#include <asm/prom.h>
+#include <asm/vio.h>
+
+#include "ibmvscsi.h"
+
+#define        INITIAL_SRP_LIMIT       16
+#define        DEFAULT_MAX_SECTORS     512
+
+#define        TGT_NAME        "ibmvstgt"
+
+/*
+ * Hypervisor calls.
+ */
+#define h_copy_rdma(l, sa, sb, da, db) \
+                       plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db)
+#define h_send_crq(ua, l, h) \
+                       plpar_hcall_norets(H_SEND_CRQ, ua, l, h)
+#define h_reg_crq(ua, tok, sz)\
+                       plpar_hcall_norets(H_REG_CRQ, ua, tok, sz);
+#define h_free_crq(ua) \
+                       plpar_hcall_norets(H_FREE_CRQ, ua);
+
+/* tmp - will replace with SCSI logging stuff */
+#define eprintk(fmt, args...)                                  \
+do {                                                           \
+       printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
+} while (0)
+/* #define dprintk eprintk */
+#define dprintk(fmt, args...)
+
+struct vio_port {
+       struct vio_dev *dma_dev;
+
+       struct crq_queue crq_queue;
+       struct work_struct crq_work;
+
+       unsigned long liobn;
+       unsigned long riobn;
+};
+
+static struct workqueue_struct *vtgtd;
+
+/*
+ * These are fixed for the system and come from the Open Firmware device tree.
+ * We just store them here to save getting them every time.
+ */
+static char system_id[64] = "";
+static char partition_name[97] = "UNKNOWN";
+static unsigned int partition_number = -1;
+
+static struct vio_port *target_to_port(struct srp_target *target)
+{
+       return (struct vio_port *) target->ldata;
+}
+
+static inline union viosrp_iu *vio_iu(struct iu_entry *iue)
+{
+       return (union viosrp_iu *) (iue->sbuf->buf);
+}
+
+static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format)
+{
+       struct srp_target *target = iue->target;
+       struct vio_port *vport = target_to_port(target);
+       long rc, rc1;
+       union {
+               struct viosrp_crq cooked;
+               uint64_t raw[2];
+       } crq;
+
+       /* First copy the SRP */
+       rc = h_copy_rdma(length, vport->liobn, iue->sbuf->dma,
+                        vport->riobn, iue->remote_token);
+
+       if (rc)
+               eprintk("Error %ld transferring data\n", rc);
+
+       crq.cooked.valid = 0x80;
+       crq.cooked.format = format;
+       crq.cooked.reserved = 0x00;
+       crq.cooked.timeout = 0x00;
+       crq.cooked.IU_length = length;
+       crq.cooked.IU_data_ptr = vio_iu(iue)->srp.rsp.tag;
+
+       if (rc == 0)
+               crq.cooked.status = 0x99;       /* Just needs to be non-zero */
+       else
+               crq.cooked.status = 0x00;
+
+       rc1 = h_send_crq(vport->dma_dev->unit_address, crq.raw[0], crq.raw[1]);
+
+       if (rc1) {
+               eprintk("%ld sending response\n", rc1);
+               return rc1;
+       }
+
+       return rc;
+}
+
+#define SRP_RSP_SENSE_DATA_LEN 18
+
+static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
+                   unsigned char status, unsigned char asc)
+{
+       union viosrp_iu *iu = vio_iu(iue);
+       uint64_t tag = iu->srp.rsp.tag;
+
+       /* If the linked bit is on and status is good */
+       if (test_bit(V_LINKED, &iue->flags) && (status == NO_SENSE))
+               status = 0x10;
+
+       memset(iu, 0, sizeof(struct srp_rsp));
+       iu->srp.rsp.opcode = SRP_RSP;
+       iu->srp.rsp.req_lim_delta = 1;
+       iu->srp.rsp.tag = tag;
+
+       if (test_bit(V_DIOVER, &iue->flags))
+               iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
+
+       iu->srp.rsp.data_in_res_cnt = 0;
+       iu->srp.rsp.data_out_res_cnt = 0;
+
+       iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID;
+
+       iu->srp.rsp.resp_data_len = 0;
+       iu->srp.rsp.status = status;
+       if (status) {
+               uint8_t *sense = iu->srp.rsp.data;
+
+               if (sc) {
+                       iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+                       iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE;
+                       memcpy(sense, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+               } else {
+                       iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION;
+                       iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+                       iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN;
+
+                       /* Valid bit and 'current errors' */
+                       sense[0] = (0x1 << 7 | 0x70);
+                       /* Sense key */
+                       sense[2] = status;
+                       /* Additional sense length */
+                       sense[7] = 0xa; /* 10 bytes */
+                       /* Additional sense code */
+                       sense[12] = asc;
+               }
+       }
+
+       send_iu(iue, sizeof(iu->srp.rsp) + SRP_RSP_SENSE_DATA_LEN,
+               VIOSRP_SRP_FORMAT);
+
+       return 0;
+}
+
+static void handle_cmd_queue(struct srp_target *target)
+{
+       struct Scsi_Host *shost = target->shost;
+       struct iu_entry *iue;
+       struct srp_cmd *cmd;
+       unsigned long flags;
+       int err;
+
+retry:
+       spin_lock_irqsave(&target->lock, flags);
+
+       list_for_each_entry(iue, &target->cmd_queue, ilist) {
+               if (!test_and_set_bit(V_FLYING, &iue->flags)) {
+                       spin_unlock_irqrestore(&target->lock, flags);
+                       cmd = iue->sbuf->buf;
+                       err = srp_cmd_queue(shost, cmd, iue, 0);
+                       if (err) {
+                               eprintk("cannot queue cmd %p %d\n", cmd, err);
+                               srp_iu_put(iue);
+                       }
+                       goto retry;
+               }
+       }
+
+       spin_unlock_irqrestore(&target->lock, flags);
+}
+
+static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
+                        struct srp_direct_buf *md, int nmd,
+                        enum dma_data_direction dir, unsigned int rest)
+{
+       struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+       struct srp_target *target = iue->target;
+       struct vio_port *vport = target_to_port(target);
+       dma_addr_t token;
+       long err;
+       unsigned int done = 0;
+       int i, sidx, soff;
+
+       sidx = soff = 0;
+       token = sg_dma_address(sg + sidx);
+
+       for (i = 0; i < nmd && rest; i++) {
+               unsigned int mdone, mlen;
+
+               mlen = min(rest, md[i].len);
+               for (mdone = 0; mlen;) {
+                       int slen = min(sg_dma_len(sg + sidx) - soff, mlen);
+
+                       if (dir == DMA_TO_DEVICE)
+                               err = h_copy_rdma(slen,
+                                                 vport->riobn,
+                                                 md[i].va + mdone,
+                                                 vport->liobn,
+                                                 token + soff);
+                       else
+                               err = h_copy_rdma(slen,
+                                                 vport->liobn,
+                                                 token + soff,
+                                                 vport->riobn,
+                                                 md[i].va + mdone);
+
+                       if (err != H_SUCCESS) {
+                               eprintk("rdma error %d %d\n", dir, slen);
+                               goto out;
+                       }
+
+                       mlen -= slen;
+                       mdone += slen;
+                       soff += slen;
+                       done += slen;
+
+                       if (soff == sg_dma_len(sg + sidx)) {
+                               sidx++;
+                               soff = 0;
+                               token = sg_dma_address(sg + sidx);
+
+                               if (sidx > nsg) {
+                                       eprintk("out of sg %p %d %d\n",
+                                               iue, sidx, nsg);
+                                       goto out;
+                               }
+                       }
+               };
+
+               rest -= mlen;
+       }
+out:
+
+       return 0;
+}
+
+static int ibmvstgt_transfer_data(struct scsi_cmnd *sc,
+                                 void (*done)(struct scsi_cmnd *))
+{
+       struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+       int err;
+
+       err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
+
+       done(sc);
+
+       return err;
+}
+
+static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
+                            void (*done)(struct scsi_cmnd *))
+{
+       unsigned long flags;
+       struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+       struct srp_target *target = iue->target;
+
+       dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+
+       spin_lock_irqsave(&target->lock, flags);
+       list_del(&iue->ilist);
+       spin_unlock_irqrestore(&target->lock, flags);
+
+       if (sc->result != SAM_STAT_GOOD) {
+               eprintk("operation failed %p %d %x\n",
+                       iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
+               send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
+       } else
+               send_rsp(iue, sc, NO_SENSE, 0x00);
+
+       done(sc);
+       srp_iu_put(iue);
+       return 0;
+}
+
+int send_adapter_info(struct iu_entry *iue,
+                     dma_addr_t remote_buffer, uint16_t length)
+{
+       struct srp_target *target = iue->target;
+       struct vio_port *vport = target_to_port(target);
+       struct Scsi_Host *shost = target->shost;
+       dma_addr_t data_token;
+       struct mad_adapter_info_data *info;
+       int err;
+
+       info = dma_alloc_coherent(target->dev, sizeof(*info), &data_token,
+                                 GFP_KERNEL);
+       if (!info) {
+               eprintk("bad dma_alloc_coherent %p\n", target);
+               return 1;
+       }
+
+       /* Get remote info */
+       err = h_copy_rdma(sizeof(*info), vport->riobn, remote_buffer,
+                         vport->liobn, data_token);
+       if (err == H_SUCCESS) {
+               dprintk("Client connect: %s (%d)\n",
+                       info->partition_name, info->partition_number);
+       }
+
+       memset(info, 0, sizeof(*info));
+
+       strcpy(info->srp_version, "16.a");
+       strncpy(info->partition_name, partition_name,
+               sizeof(info->partition_name));
+       info->partition_number = partition_number;
+       info->mad_version = 1;
+       info->os_type = 2;
+       info->port_max_txu[0] = shost->hostt->max_sectors << 9;
+
+       /* Send our info to remote */
+       err = h_copy_rdma(sizeof(*info), vport->liobn, data_token,
+                         vport->riobn, remote_buffer);
+
+       dma_free_coherent(target->dev, sizeof(*info), info, data_token);
+
+       if (err != H_SUCCESS) {
+               eprintk("Error sending adapter info %d\n", err);
+               return 1;
+       }
+
+       return 0;
+}
+
+static void process_login(struct iu_entry *iue)
+{
+       union viosrp_iu *iu = vio_iu(iue);
+       struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+       uint64_t tag = iu->srp.rsp.tag;
+
+       /* TODO handle case that requested size is wrong and
+        * buffer format is wrong
+        */
+       memset(iu, 0, sizeof(struct srp_login_rsp));
+       rsp->opcode = SRP_LOGIN_RSP;
+       rsp->req_lim_delta = INITIAL_SRP_LIMIT;
+       rsp->tag = tag;
+       rsp->max_it_iu_len = sizeof(union srp_iu);
+       rsp->max_ti_iu_len = sizeof(union srp_iu);
+       /* direct and indirect */
+       rsp->buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
+
+       send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+}
+
+static inline void queue_cmd(struct iu_entry *iue)
+{
+       struct srp_target *target = iue->target;
+       unsigned long flags;
+
+       spin_lock_irqsave(&target->lock, flags);
+       list_add_tail(&iue->ilist, &target->cmd_queue);
+       spin_unlock_irqrestore(&target->lock, flags);
+}
+
+static int process_tsk_mgmt(struct iu_entry *iue)
+{
+       union viosrp_iu *iu = vio_iu(iue);
+       int fn;
+
+       dprintk("%p %u\n", iue, iu->srp.tsk_mgmt.tsk_mgmt_func);
+
+       switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
+       case SRP_TSK_ABORT_TASK:
+               fn = ABORT_TASK;
+               break;
+       case SRP_TSK_ABORT_TASK_SET:
+               fn = ABORT_TASK_SET;
+               break;
+       case SRP_TSK_CLEAR_TASK_SET:
+               fn = CLEAR_TASK_SET;
+               break;
+       case SRP_TSK_LUN_RESET:
+               fn = LOGICAL_UNIT_RESET;
+               break;
+       case SRP_TSK_CLEAR_ACA:
+               fn = CLEAR_ACA;
+               break;
+       default:
+               fn = 0;
+       }
+       if (fn)
+               scsi_tgt_tsk_mgmt_request(iue->target->shost, fn,
+                                         iu->srp.tsk_mgmt.task_tag,
+                                         (struct scsi_lun *) &iu->srp.tsk_mgmt.lun,
+                                         iue);
+       else
+               send_rsp(iue, NULL, ILLEGAL_REQUEST, 0x20);
+
+       return !fn;
+}
+
+static int process_mad_iu(struct iu_entry *iue)
+{
+       union viosrp_iu *iu = vio_iu(iue);
+       struct viosrp_adapter_info *info;
+       struct viosrp_host_config *conf;
+
+       switch (iu->mad.empty_iu.common.type) {
+       case VIOSRP_EMPTY_IU_TYPE:
+               eprintk("%s\n", "Unsupported EMPTY MAD IU");
+               break;
+       case VIOSRP_ERROR_LOG_TYPE:
+               eprintk("%s\n", "Unsupported ERROR LOG MAD IU");
+               iu->mad.error_log.common.status = 1;
+               send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT);
+               break;
+       case VIOSRP_ADAPTER_INFO_TYPE:
+               info = &iu->mad.adapter_info;
+               info->common.status = send_adapter_info(iue, info->buffer,
+                                                       info->common.length);
+               send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT);
+               break;
+       case VIOSRP_HOST_CONFIG_TYPE:
+               conf = &iu->mad.host_config;
+               conf->common.status = 1;
+               send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT);
+               break;
+       default:
+               eprintk("Unknown type %u\n", iu->srp.rsp.opcode);
+       }
+
+       return 1;
+}
+
+static int process_srp_iu(struct iu_entry *iue)
+{
+       union viosrp_iu *iu = vio_iu(iue);
+       int done = 1;
+       u8 opcode = iu->srp.rsp.opcode;
+
+       switch (opcode) {
+       case SRP_LOGIN_REQ:
+               process_login(iue);
+               break;
+       case SRP_TSK_MGMT:
+               done = process_tsk_mgmt(iue);
+               break;
+       case SRP_CMD:
+               queue_cmd(iue);
+               done = 0;
+               break;
+       case SRP_LOGIN_RSP:
+       case SRP_I_LOGOUT:
+       case SRP_T_LOGOUT:
+       case SRP_RSP:
+       case SRP_CRED_REQ:
+       case SRP_CRED_RSP:
+       case SRP_AER_REQ:
+       case SRP_AER_RSP:
+               eprintk("Unsupported type %u\n", opcode);
+               break;
+       default:
+               eprintk("Unknown type %u\n", opcode);
+       }
+
+       return done;
+}
+
+static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
+{
+       struct vio_port *vport = target_to_port(target);
+       struct iu_entry *iue;
+       long err, done;
+
+       iue = srp_iu_get(target);
+       if (!iue) {
+               eprintk("Error getting IU from pool, %p\n", target);
+               return;
+       }
+
+       iue->remote_token = crq->IU_data_ptr;
+
+       err = h_copy_rdma(crq->IU_length, vport->riobn,
+                         iue->remote_token, vport->liobn, iue->sbuf->dma);
+
+       if (err != H_SUCCESS) {
+               eprintk("%ld transferring data error %p\n", err, iue);
+               done = 1;
+               goto out;
+       }
+
+       if (crq->format == VIOSRP_MAD_FORMAT)
+               done = process_mad_iu(iue);
+       else
+               done = process_srp_iu(iue);
+out:
+       if (done)
+               srp_iu_put(iue);
+}
+
+static irqreturn_t ibmvstgt_interrupt(int irq, void *data)
+{
+       struct srp_target *target = (struct srp_target *) data;
+       struct vio_port *vport = target_to_port(target);
+
+       vio_disable_interrupts(vport->dma_dev);
+       queue_work(vtgtd, &vport->crq_work);
+
+       return IRQ_HANDLED;
+}
+
+static int crq_queue_create(struct crq_queue *queue, struct srp_target *target)
+{
+       int err;
+       struct vio_port *vport = target_to_port(target);
+
+       queue->msgs = (struct viosrp_crq *) get_zeroed_page(GFP_KERNEL);
+       if (!queue->msgs)
+               goto malloc_failed;
+       queue->size = PAGE_SIZE / sizeof(*queue->msgs);
+
+       queue->msg_token = dma_map_single(target->dev, queue->msgs,
+                                         queue->size * sizeof(*queue->msgs),
+                                         DMA_BIDIRECTIONAL);
+
+       if (dma_mapping_error(queue->msg_token))
+               goto map_failed;
+
+       err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token,
+                       PAGE_SIZE);
+
+       /* If the adapter was left active for some reason (like kexec)
+        * try freeing and re-registering
+        */
+       if (err == H_RESOURCE) {
+           do {
+               err = h_free_crq(vport->dma_dev->unit_address);
+           } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+           err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token,
+                           PAGE_SIZE);
+       }
+
+       if (err != H_SUCCESS && err != 2) {
+               eprintk("Error 0x%x opening virtual adapter\n", err);
+               goto reg_crq_failed;
+       }
+
+       err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt,
+                         SA_INTERRUPT, "ibmvstgt", target);
+       if (err)
+               goto req_irq_failed;
+
+       vio_enable_interrupts(vport->dma_dev);
+
+       h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000, 0);
+
+       queue->cur = 0;
+       spin_lock_init(&queue->lock);
+
+       return 0;
+
+req_irq_failed:
+       do {
+               err = h_free_crq(vport->dma_dev->unit_address);
+       } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+reg_crq_failed:
+       dma_unmap_single(target->dev, queue->msg_token,
+                        queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+map_failed:
+       free_page((unsigned long) queue->msgs);
+
+malloc_failed:
+       return -ENOMEM;
+}
+
+static void crq_queue_destroy(struct srp_target *target)
+{
+       struct vio_port *vport = target_to_port(target);
+       struct crq_queue *queue = &vport->crq_queue;
+       int err;
+
+       free_irq(vport->dma_dev->irq, target);
+       do {
+               err = h_free_crq(vport->dma_dev->unit_address);
+       } while (err == H_BUSY || H_IS_LONG_BUSY(err));
+
+       dma_unmap_single(target->dev, queue->msg_token,
+                        queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+
+       free_page((unsigned long) queue->msgs);
+}
+
+static void process_crq(struct viosrp_crq *crq,        struct srp_target *target)
+{
+       struct vio_port *vport = target_to_port(target);
+       dprintk("%x %x\n", crq->valid, crq->format);
+
+       switch (crq->valid) {
+       case 0xC0:
+               /* initialization */
+               switch (crq->format) {
+               case 0x01:
+                       h_send_crq(vport->dma_dev->unit_address,
+                                  0xC002000000000000, 0);
+                       break;
+               case 0x02:
+                       break;
+               default:
+                       eprintk("Unknown format %u\n", crq->format);
+               }
+               break;
+       case 0xFF:
+               /* transport event */
+               break;
+       case 0x80:
+               /* real payload */
+               switch (crq->format) {
+               case VIOSRP_SRP_FORMAT:
+               case VIOSRP_MAD_FORMAT:
+                       process_iu(crq, target);
+                       break;
+               case VIOSRP_OS400_FORMAT:
+               case VIOSRP_AIX_FORMAT:
+               case VIOSRP_LINUX_FORMAT:
+               case VIOSRP_INLINE_FORMAT:
+                       eprintk("Unsupported format %u\n", crq->format);
+                       break;
+               default:
+                       eprintk("Unknown format %u\n", crq->format);
+               }
+               break;
+       default:
+               eprintk("unknown message type 0x%02x!?\n", crq->valid);
+       }
+}
+
+static inline struct viosrp_crq *next_crq(struct crq_queue *queue)
+{
+       struct viosrp_crq *crq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&queue->lock, flags);
+       crq = &queue->msgs[queue->cur];
+       if (crq->valid & 0x80) {
+               if (++queue->cur == queue->size)
+                       queue->cur = 0;
+       } else
+               crq = NULL;
+       spin_unlock_irqrestore(&queue->lock, flags);
+
+       return crq;
+}
+
+static void handle_crq(void *data)
+{
+       struct srp_target *target = (struct srp_target *) data;
+       struct vio_port *vport = target_to_port(target);
+       struct viosrp_crq *crq;
+       int done = 0;
+
+       while (!done) {
+               while ((crq = next_crq(&vport->crq_queue)) != NULL) {
+                       process_crq(crq, target);
+                       crq->valid = 0x00;
+               }
+
+               vio_enable_interrupts(vport->dma_dev);
+
+               crq = next_crq(&vport->crq_queue);
+               if (crq) {
+                       vio_disable_interrupts(vport->dma_dev);
+                       process_crq(crq, target);
+                       crq->valid = 0x00;
+               } else
+                       done = 1;
+       }
+
+       handle_cmd_queue(target);
+}
+
+
+static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc)
+{
+       unsigned long flags;
+       struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
+       struct srp_target *target = iue->target;
+
+       dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+
+       spin_lock_irqsave(&target->lock, flags);
+       list_del(&iue->ilist);
+       spin_unlock_irqrestore(&target->lock, flags);
+
+       srp_iu_put(iue);
+
+       return 0;
+}
+
+static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
+{
+       struct iu_entry *iue = (struct iu_entry *) ((void *) mid);
+       union viosrp_iu *iu = vio_iu(iue);
+       unsigned char status, asc;
+
+       eprintk("%p %d\n", iue, result);
+       status = NO_SENSE;
+       asc = 0;
+
+       switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
+       case SRP_TSK_ABORT_TASK:
+               asc = 0x14;
+               if (result)
+                       status = ABORTED_COMMAND;
+               break;
+       default:
+               break;
+       }
+
+       send_rsp(iue, NULL, status, asc);
+       srp_iu_put(iue);
+
+       return 0;
+}
+
+static ssize_t system_id_show(struct class_device *cdev, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
+}
+
+static ssize_t partition_number_show(struct class_device *cdev, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%x\n", partition_number);
+}
+
+static ssize_t unit_address_show(struct class_device *cdev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct srp_target *target = host_to_srp_target(shost);
+       struct vio_port *vport = target_to_port(target);
+       return snprintf(buf, PAGE_SIZE, "%x\n", vport->dma_dev->unit_address);
+}
+
+static CLASS_DEVICE_ATTR(system_id, S_IRUGO, system_id_show, NULL);
+static CLASS_DEVICE_ATTR(partition_number, S_IRUGO, partition_number_show, NULL);
+static CLASS_DEVICE_ATTR(unit_address, S_IRUGO, unit_address_show, NULL);
+
+static struct class_device_attribute *ibmvstgt_attrs[] = {
+       &class_device_attr_system_id,
+       &class_device_attr_partition_number,
+       &class_device_attr_unit_address,
+       NULL,
+};
+
+static struct scsi_host_template ibmvstgt_sht = {
+       .name                   = TGT_NAME,
+       .module                 = THIS_MODULE,
+       .can_queue              = INITIAL_SRP_LIMIT,
+       .sg_tablesize           = SG_ALL,
+       .use_clustering         = DISABLE_CLUSTERING,
+       .max_sectors            = DEFAULT_MAX_SECTORS,
+       .transfer_response      = ibmvstgt_cmd_done,
+       .transfer_data          = ibmvstgt_transfer_data,
+       .eh_abort_handler       = ibmvstgt_eh_abort_handler,
+       .tsk_mgmt_response      = ibmvstgt_tsk_mgmt_response,
+       .shost_attrs            = ibmvstgt_attrs,
+       .proc_name              = TGT_NAME,
+};
+
+static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
+{
+       struct Scsi_Host *shost;
+       struct srp_target *target;
+       struct vio_port *vport;
+       unsigned int *dma, dma_size;
+       int err = -ENOMEM;
+
+       vport = kzalloc(sizeof(struct vio_port), GFP_KERNEL);
+       if (!vport)
+               return err;
+       shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target));
+       if (!shost)
+               goto free_vport;
+       err = scsi_tgt_alloc_queue(shost);
+       if (err)
+               goto put_host;
+
+       target = host_to_srp_target(shost);
+       target->shost = shost;
+       vport->dma_dev = dev;
+       target->ldata = vport;
+       err = srp_target_alloc(target, &dev->dev, INITIAL_SRP_LIMIT,
+                              SRP_MAX_IU_LEN);
+       if (err)
+               goto put_host;
+
+       dma = (unsigned int *) vio_get_attribute(dev, "ibm,my-dma-window",
+                                                &dma_size);
+       if (!dma || dma_size != 40) {
+               eprintk("Couldn't get window property %d\n", dma_size);
+               err = -EIO;
+               goto free_srp_target;
+       }
+       vport->liobn = dma[0];
+       vport->riobn = dma[5];
+
+       INIT_WORK(&vport->crq_work, handle_crq, target);
+
+       err = crq_queue_create(&vport->crq_queue, target);
+       if (err)
+               goto free_srp_target;
+
+       err = scsi_add_host(shost, target->dev);
+       if (err)
+               goto destroy_queue;
+       return 0;
+
+destroy_queue:
+       crq_queue_destroy(target);
+free_srp_target:
+       srp_target_free(target);
+put_host:
+       scsi_host_put(shost);
+free_vport:
+       kfree(vport);
+       return err;
+}
+
+static int ibmvstgt_remove(struct vio_dev *dev)
+{
+       struct srp_target *target = (struct srp_target *) dev->dev.driver_data;
+       struct Scsi_Host *shost = target->shost;
+       struct vio_port *vport = target->ldata;
+
+       crq_queue_destroy(target);
+       scsi_remove_host(shost);
+       scsi_tgt_free_queue(shost);
+       srp_target_free(target);
+       kfree(vport);
+       scsi_host_put(shost);
+       return 0;
+}
+
+static struct vio_device_id ibmvstgt_device_table[] __devinitdata = {
+       {"v-scsi-host", "IBM,v-scsi-host"},
+       {"",""}
+};
+
+MODULE_DEVICE_TABLE(vio, ibmvstgt_device_table);
+
+static struct vio_driver ibmvstgt_driver = {
+       .id_table = ibmvstgt_device_table,
+       .probe = ibmvstgt_probe,
+       .remove = ibmvstgt_remove,
+       .driver = {
+               .name = "ibmvscsis",
+               .owner = THIS_MODULE,
+       }
+};
+
+static int get_system_info(void)
+{
+       struct device_node *rootdn;
+       const char *id, *model, *name;
+       unsigned int *num;
+
+       rootdn = find_path_device("/");
+       if (!rootdn)
+               return -ENOENT;
+
+       model = get_property(rootdn, "model", NULL);
+       id = get_property(rootdn, "system-id", NULL);
+       if (model && id)
+               snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
+
+       name = get_property(rootdn, "ibm,partition-name", NULL);
+       if (name)
+               strncpy(partition_name, name, sizeof(partition_name));
+
+       num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL);
+       if (num)
+               partition_number = *num;
+
+       return 0;
+}
+
+static int ibmvstgt_init(void)
+{
+       int err = -ENOMEM;
+
+       printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n");
+
+       vtgtd = create_workqueue("ibmvtgtd");
+       if (!vtgtd)
+               return err;
+
+       err = get_system_info();
+       if (err)
+               goto destroy_wq;
+
+       err = vio_register_driver(&ibmvstgt_driver);
+       if (err)
+               goto destroy_wq;
+
+       return 0;
+
+destroy_wq:
+       destroy_workqueue(vtgtd);
+       return err;
+}
+
+static void ibmvstgt_exit(void)
+{
+       printk("Unregister IBM virtual SCSI driver\n");
+
+       destroy_workqueue(vtgtd);
+       vio_unregister_driver(&ibmvstgt_driver);
+}
+
+MODULE_DESCRIPTION("IBM Virtual SCSI Target");
+MODULE_AUTHOR("Santiago Leon");
+MODULE_LICENSE("GPL");
+
+module_init(ibmvstgt_init);
+module_exit(ibmvstgt_exit);
index afed293dd7b99137bc4f57ee8819fc1248fbeec6..f160357e37a6f065b18f68cc1df2cc463455bbd4 100644 (file)
@@ -170,7 +170,7 @@ static int setup_debug = 0;
 static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
 
 /* PCI Devices supported by this driver */
-static struct pci_device_id i91u_pci_devices[] __devinitdata = {
+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},
index 2dde821025f3a1d98cc676bc7a09db1d93c441c9..2d83fbb806a5dde949e08d90c8f58ea8a7b353dc 100644 (file)
@@ -79,7 +79,6 @@
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_transport.h>
 #include "ipr.h"
 
 /*
@@ -98,7 +97,7 @@ static DEFINE_SPINLOCK(ipr_driver_lock);
 
 /* This table describes the differences between DMA controller chips */
 static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
-       { /* Gemstone, Citrine, and Obsidian */
+       { /* Gemstone, Citrine, Obsidian, and Obsidian-E */
                .mailbox = 0x0042C,
                .cache_line_size = 0x20,
                {
@@ -135,6 +134,7 @@ static const struct ipr_chip_t ipr_chip[] = {
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, &ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] },
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] }
 };
@@ -1249,19 +1249,23 @@ static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg,
 
 /**
  * ipr_log_hex_data - Log additional hex IOA error data.
+ * @ioa_cfg:   ioa config struct
  * @data:              IOA error data
  * @len:               data length
  *
  * Return value:
  *     none
  **/
-static void ipr_log_hex_data(u32 *data, int len)
+static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, u32 *data, int len)
 {
        int i;
 
        if (len == 0)
                return;
 
+       if (ioa_cfg->log_level <= IPR_DEFAULT_LOG_LEVEL)
+               len = min_t(int, len, IPR_DEFAULT_MAX_ERROR_DUMP);
+
        for (i = 0; i < len / 4; i += 4) {
                ipr_err("%08X: %08X %08X %08X %08X\n", i*4,
                        be32_to_cpu(data[i]),
@@ -1290,7 +1294,7 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
        ipr_err("%s\n", error->failure_reason);
        ipr_err("Remote Adapter VPD:\n");
        ipr_log_ext_vpd(&error->vpd);
-       ipr_log_hex_data(error->data,
+       ipr_log_hex_data(ioa_cfg, error->data,
                         be32_to_cpu(hostrcb->hcam.length) -
                         (offsetof(struct ipr_hostrcb_error, u) +
                          offsetof(struct ipr_hostrcb_type_17_error, data)));
@@ -1315,12 +1319,225 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
        ipr_err("%s\n", error->failure_reason);
        ipr_err("Remote Adapter VPD:\n");
        ipr_log_vpd(&error->vpd);
-       ipr_log_hex_data(error->data,
+       ipr_log_hex_data(ioa_cfg, error->data,
                         be32_to_cpu(hostrcb->hcam.length) -
                         (offsetof(struct ipr_hostrcb_error, u) +
                          offsetof(struct ipr_hostrcb_type_07_error, data)));
 }
 
+static const struct {
+       u8 active;
+       char *desc;
+} path_active_desc[] = {
+       { IPR_PATH_NO_INFO, "Path" },
+       { IPR_PATH_ACTIVE, "Active path" },
+       { IPR_PATH_NOT_ACTIVE, "Inactive path" }
+};
+
+static const struct {
+       u8 state;
+       char *desc;
+} path_state_desc[] = {
+       { IPR_PATH_STATE_NO_INFO, "has no path state information available" },
+       { IPR_PATH_HEALTHY, "is healthy" },
+       { IPR_PATH_DEGRADED, "is degraded" },
+       { IPR_PATH_FAILED, "is failed" }
+};
+
+/**
+ * ipr_log_fabric_path - Log a fabric path error
+ * @hostrcb:   hostrcb struct
+ * @fabric:            fabric descriptor
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb,
+                               struct ipr_hostrcb_fabric_desc *fabric)
+{
+       int i, j;
+       u8 path_state = fabric->path_state;
+       u8 active = path_state & IPR_PATH_ACTIVE_MASK;
+       u8 state = path_state & IPR_PATH_STATE_MASK;
+
+       for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) {
+               if (path_active_desc[i].active != active)
+                       continue;
+
+               for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) {
+                       if (path_state_desc[j].state != state)
+                               continue;
+
+                       if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) {
+                               ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n",
+                                            path_active_desc[i].desc, path_state_desc[j].desc,
+                                            fabric->ioa_port);
+                       } else if (fabric->cascaded_expander == 0xff) {
+                               ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n",
+                                            path_active_desc[i].desc, path_state_desc[j].desc,
+                                            fabric->ioa_port, fabric->phy);
+                       } else if (fabric->phy == 0xff) {
+                               ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n",
+                                            path_active_desc[i].desc, path_state_desc[j].desc,
+                                            fabric->ioa_port, fabric->cascaded_expander);
+                       } else {
+                               ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n",
+                                            path_active_desc[i].desc, path_state_desc[j].desc,
+                                            fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
+                       }
+                       return;
+               }
+       }
+
+       ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state,
+               fabric->ioa_port, fabric->cascaded_expander, fabric->phy);
+}
+
+static const struct {
+       u8 type;
+       char *desc;
+} path_type_desc[] = {
+       { IPR_PATH_CFG_IOA_PORT, "IOA port" },
+       { IPR_PATH_CFG_EXP_PORT, "Expander port" },
+       { IPR_PATH_CFG_DEVICE_PORT, "Device port" },
+       { IPR_PATH_CFG_DEVICE_LUN, "Device LUN" }
+};
+
+static const struct {
+       u8 status;
+       char *desc;
+} path_status_desc[] = {
+       { IPR_PATH_CFG_NO_PROB, "Functional" },
+       { IPR_PATH_CFG_DEGRADED, "Degraded" },
+       { IPR_PATH_CFG_FAILED, "Failed" },
+       { IPR_PATH_CFG_SUSPECT, "Suspect" },
+       { IPR_PATH_NOT_DETECTED, "Missing" },
+       { IPR_PATH_INCORRECT_CONN, "Incorrectly connected" }
+};
+
+static const char *link_rate[] = {
+       "unknown",
+       "disabled",
+       "phy reset problem",
+       "spinup hold",
+       "port selector",
+       "unknown",
+       "unknown",
+       "unknown",
+       "1.5Gbps",
+       "3.0Gbps",
+       "unknown",
+       "unknown",
+       "unknown",
+       "unknown",
+       "unknown",
+       "unknown"
+};
+
+/**
+ * ipr_log_path_elem - Log a fabric path element.
+ * @hostrcb:   hostrcb struct
+ * @cfg:               fabric path element struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb,
+                             struct ipr_hostrcb_config_element *cfg)
+{
+       int i, j;
+       u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK;
+       u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK;
+
+       if (type == IPR_PATH_CFG_NOT_EXIST)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) {
+               if (path_type_desc[i].type != type)
+                       continue;
+
+               for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) {
+                       if (path_status_desc[j].status != status)
+                               continue;
+
+                       if (type == IPR_PATH_CFG_IOA_PORT) {
+                               ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n",
+                                            path_status_desc[j].desc, path_type_desc[i].desc,
+                                            cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                            be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                       } else {
+                               if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) {
+                                       ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n",
+                                                    path_status_desc[j].desc, path_type_desc[i].desc,
+                                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                               } else if (cfg->cascaded_expander == 0xff) {
+                                       ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, "
+                                                    "WWN=%08X%08X\n", path_status_desc[j].desc,
+                                                    path_type_desc[i].desc, cfg->phy,
+                                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                               } else if (cfg->phy == 0xff) {
+                                       ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, "
+                                                    "WWN=%08X%08X\n", path_status_desc[j].desc,
+                                                    path_type_desc[i].desc, cfg->cascaded_expander,
+                                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                               } else {
+                                       ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s "
+                                                    "WWN=%08X%08X\n", path_status_desc[j].desc,
+                                                    path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy,
+                                                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                                                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+                               }
+                       }
+                       return;
+               }
+       }
+
+       ipr_hcam_err(hostrcb, "Path element=%02X: Cascade=%d Phy=%d Link rate=%s "
+                    "WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy,
+                    link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
+                    be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
+}
+
+/**
+ * ipr_log_fabric_error - Log a fabric error.
+ * @ioa_cfg:   ioa config struct
+ * @hostrcb:   hostrcb struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg,
+                                struct ipr_hostrcb *hostrcb)
+{
+       struct ipr_hostrcb_type_20_error *error;
+       struct ipr_hostrcb_fabric_desc *fabric;
+       struct ipr_hostrcb_config_element *cfg;
+       int i, add_len;
+
+       error = &hostrcb->hcam.u.error.u.type_20_error;
+       error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+       ipr_hcam_err(hostrcb, "%s\n", error->failure_reason);
+
+       add_len = be32_to_cpu(hostrcb->hcam.length) -
+               (offsetof(struct ipr_hostrcb_error, u) +
+                offsetof(struct ipr_hostrcb_type_20_error, desc));
+
+       for (i = 0, fabric = error->desc; i < error->num_entries; i++) {
+               ipr_log_fabric_path(hostrcb, fabric);
+               for_each_fabric_cfg(fabric, cfg)
+                       ipr_log_path_elem(hostrcb, cfg);
+
+               add_len -= be16_to_cpu(fabric->length);
+               fabric = (struct ipr_hostrcb_fabric_desc *)
+                       ((unsigned long)fabric + be16_to_cpu(fabric->length));
+       }
+
+       ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len);
+}
+
 /**
  * ipr_log_generic_error - Log an adapter error.
  * @ioa_cfg:   ioa config struct
@@ -1332,7 +1549,7 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
 static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,
                                  struct ipr_hostrcb *hostrcb)
 {
-       ipr_log_hex_data(hostrcb->hcam.u.raw.data,
+       ipr_log_hex_data(ioa_cfg, hostrcb->hcam.u.raw.data,
                         be32_to_cpu(hostrcb->hcam.length));
 }
 
@@ -1394,13 +1611,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
        if (!ipr_error_table[error_index].log_hcam)
                return;
 
-       if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {
-               ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,
-                          "%s\n", ipr_error_table[error_index].error);
-       } else {
-               dev_err(&ioa_cfg->pdev->dev, "%s\n",
-                       ipr_error_table[error_index].error);
-       }
+       ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error);
 
        /* Set indication we have logged an error */
        ioa_cfg->errors_logged++;
@@ -1437,6 +1648,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
        case IPR_HOST_RCB_OVERLAY_ID_17:
                ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb);
                break;
+       case IPR_HOST_RCB_OVERLAY_ID_20:
+               ipr_log_fabric_error(ioa_cfg, hostrcb);
+               break;
        case IPR_HOST_RCB_OVERLAY_ID_1:
        case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
        default:
@@ -2969,7 +3183,6 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg)
        struct ipr_dump *dump;
        unsigned long lock_flags = 0;
 
-       ENTER;
        dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL);
 
        if (!dump) {
@@ -2996,7 +3209,6 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg)
        }
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 
-       LEAVE;
        return 0;
 }
 
@@ -3573,6 +3785,12 @@ static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
 
        ENTER;
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       }
+
        res = sata_port->res;
        if (res) {
                rc = ipr_device_reset(ioa_cfg, res);
@@ -3636,6 +3854,10 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
                if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
                        if (ipr_cmd->scsi_cmd)
                                ipr_cmd->done = ipr_scsi_eh_done;
+                       if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
+                               ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
+                               ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
+                       }
                }
        }
 
@@ -3770,7 +3992,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd)
         */
        if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead)
                return FAILED;
-       if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res)))
+       if (!res || !ipr_is_gscsi(res))
                return FAILED;
 
        list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
@@ -4615,7 +4837,7 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
  * Return value:
  *     0 on success / other on failure
  **/
-int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 {
        struct ipr_resource_entry *res;
 
@@ -4648,40 +4870,6 @@ static const char * ipr_ioa_info(struct Scsi_Host *host)
        return buffer;
 }
 
-/**
- * ipr_scsi_timed_out - Handle scsi command timeout
- * @scsi_cmd:  scsi command struct
- *
- * Return value:
- *     EH_NOT_HANDLED
- **/
-enum scsi_eh_timer_return ipr_scsi_timed_out(struct scsi_cmnd *scsi_cmd)
-{
-       struct ipr_ioa_cfg *ioa_cfg;
-       struct ipr_cmnd *ipr_cmd;
-       unsigned long flags;
-
-       ENTER;
-       spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags);
-       ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
-
-       list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
-               if (ipr_cmd->qc && ipr_cmd->qc->scsicmd == scsi_cmd) {
-                       ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
-                       ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
-                       break;
-               }
-       }
-
-       spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags);
-       LEAVE;
-       return EH_NOT_HANDLED;
-}
-
-static struct scsi_transport_template ipr_transport_template = {
-       .eh_timed_out = ipr_scsi_timed_out
-};
-
 static struct scsi_host_template driver_template = {
        .module = THIS_MODULE,
        .name = "IPR",
@@ -4776,6 +4964,12 @@ static void ipr_ata_post_internal(struct ata_queued_cmd *qc)
        unsigned long flags;
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+       while(ioa_cfg->in_reset_reload) {
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+               wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+               spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+       }
+
        list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
                if (ipr_cmd->qc == qc) {
                        ipr_device_reset(ioa_cfg, sata_port->res);
@@ -6832,6 +7026,7 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
 
                ioa_cfg->hostrcb[i]->hostrcb_dma =
                        ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam);
+               ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg;
                list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q);
        }
 
@@ -7017,7 +7212,6 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
 
        ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
        memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
-       host->transportt = &ipr_transport_template;
        ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
                      sata_port_info.flags, &ipr_sata_ops);
 
@@ -7351,12 +7545,24 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
              0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
+             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A,
              0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
              0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
+             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8,
+             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7,
+             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780,
                0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
@@ -7366,6 +7572,9 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F,
                0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+       { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
+               PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F,
+               0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
        { }
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
index 6d035283af0843f00a54caa75fa7ee94d19c86f0..9f62a1d4d5118b0e197d15ea44d2ba07ff5f9424 100644 (file)
@@ -37,8 +37,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.2.0"
-#define IPR_DRIVER_DATE "(September 25, 2006)"
+#define IPR_DRIVER_VERSION "2.3.0"
+#define IPR_DRIVER_DATE "(November 8, 2006)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -54,6 +54,8 @@
  */
 #define IPR_NUM_BASE_CMD_BLKS                          100
 
+#define PCI_DEVICE_ID_IBM_OBSIDIAN_E   0x0339
+
 #define IPR_SUBS_DEV_ID_2780   0x0264
 #define IPR_SUBS_DEV_ID_5702   0x0266
 #define IPR_SUBS_DEV_ID_5703   0x0278
 #define IPR_SUBS_DEV_ID_571F   0x02D5
 #define IPR_SUBS_DEV_ID_572A   0x02C1
 #define IPR_SUBS_DEV_ID_572B   0x02C2
+#define IPR_SUBS_DEV_ID_572F   0x02C3
 #define IPR_SUBS_DEV_ID_575B   0x030D
+#define IPR_SUBS_DEV_ID_575C   0x0338
+#define IPR_SUBS_DEV_ID_57B7   0x0360
+#define IPR_SUBS_DEV_ID_57B8   0x02C2
 
 #define IPR_NAME                               "ipr"
 
 #define IPR_IOASC_IOA_WAS_RESET                        0x10000001
 #define IPR_IOASC_PCI_ACCESS_ERROR                     0x10000002
 
+#define IPR_DEFAULT_MAX_ERROR_DUMP                     984
 #define IPR_NUM_LOG_HCAMS                              2
 #define IPR_NUM_CFG_CHG_HCAMS                          2
 #define IPR_NUM_HCAMS  (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS)
@@ -731,6 +738,64 @@ struct ipr_hostrcb_type_17_error {
        u32 data[476];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_hostrcb_config_element {
+       u8 type_status;
+#define IPR_PATH_CFG_TYPE_MASK 0xF0
+#define IPR_PATH_CFG_NOT_EXIST 0x00
+#define IPR_PATH_CFG_IOA_PORT          0x10
+#define IPR_PATH_CFG_EXP_PORT          0x20
+#define IPR_PATH_CFG_DEVICE_PORT       0x30
+#define IPR_PATH_CFG_DEVICE_LUN        0x40
+
+#define IPR_PATH_CFG_STATUS_MASK       0x0F
+#define IPR_PATH_CFG_NO_PROB           0x00
+#define IPR_PATH_CFG_DEGRADED          0x01
+#define IPR_PATH_CFG_FAILED            0x02
+#define IPR_PATH_CFG_SUSPECT           0x03
+#define IPR_PATH_NOT_DETECTED          0x04
+#define IPR_PATH_INCORRECT_CONN        0x05
+
+       u8 cascaded_expander;
+       u8 phy;
+       u8 link_rate;
+#define IPR_PHY_LINK_RATE_MASK 0x0F
+
+       __be32 wwid[2];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_fabric_desc {
+       __be16 length;
+       u8 ioa_port;
+       u8 cascaded_expander;
+       u8 phy;
+       u8 path_state;
+#define IPR_PATH_ACTIVE_MASK           0xC0
+#define IPR_PATH_NO_INFO               0x00
+#define IPR_PATH_ACTIVE                        0x40
+#define IPR_PATH_NOT_ACTIVE            0x80
+
+#define IPR_PATH_STATE_MASK            0x0F
+#define IPR_PATH_STATE_NO_INFO 0x00
+#define IPR_PATH_HEALTHY               0x01
+#define IPR_PATH_DEGRADED              0x02
+#define IPR_PATH_FAILED                        0x03
+
+       __be16 num_entries;
+       struct ipr_hostrcb_config_element elem[1];
+}__attribute__((packed, aligned (4)));
+
+#define for_each_fabric_cfg(fabric, cfg) \
+               for (cfg = (fabric)->elem; \
+                       cfg < ((fabric)->elem + be16_to_cpu((fabric)->num_entries)); \
+                       cfg++)
+
+struct ipr_hostrcb_type_20_error {
+       u8 failure_reason[64];
+       u8 reserved[3];
+       u8 num_entries;
+       struct ipr_hostrcb_fabric_desc desc[1];
+}__attribute__((packed, aligned (4)));
+
 struct ipr_hostrcb_error {
        __be32 failing_dev_ioasc;
        struct ipr_res_addr failing_dev_res_addr;
@@ -747,6 +812,7 @@ struct ipr_hostrcb_error {
                struct ipr_hostrcb_type_13_error type_13_error;
                struct ipr_hostrcb_type_14_error type_14_error;
                struct ipr_hostrcb_type_17_error type_17_error;
+               struct ipr_hostrcb_type_20_error type_20_error;
        } u;
 }__attribute__((packed, aligned (4)));
 
@@ -786,6 +852,7 @@ struct ipr_hcam {
 #define IPR_HOST_RCB_OVERLAY_ID_14                             0x14
 #define IPR_HOST_RCB_OVERLAY_ID_16                             0x16
 #define IPR_HOST_RCB_OVERLAY_ID_17                             0x17
+#define IPR_HOST_RCB_OVERLAY_ID_20                             0x20
 #define IPR_HOST_RCB_OVERLAY_ID_DEFAULT                        0xFF
 
        u8 reserved1[3];
@@ -805,6 +872,7 @@ struct ipr_hostrcb {
        struct ipr_hcam hcam;
        dma_addr_t hostrcb_dma;
        struct list_head queue;
+       struct ipr_ioa_cfg *ioa_cfg;
 };
 
 /* IPR smart dump table structures */
@@ -1283,6 +1351,17 @@ struct ipr_ucode_image_header {
        }                                                               \
 }
 
+#define ipr_hcam_err(hostrcb, fmt, ...)                                        \
+{                                                                                                      \
+       if (ipr_is_device(&(hostrcb)->hcam.u.error.failing_dev_res_addr)) {             \
+               ipr_ra_err((hostrcb)->ioa_cfg,                                                  \
+                               (hostrcb)->hcam.u.error.failing_dev_res_addr,                   \
+                               fmt, ##__VA_ARGS__);                                                    \
+       } else {                                                                                        \
+               dev_err(&(hostrcb)->ioa_cfg->pdev->dev, fmt, ##__VA_ARGS__);            \
+       }                                                                                               \
+}
+
 #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
        __FILE__, __FUNCTION__, __LINE__)
 
index f06a06ae6092fc3e0bc7cf05d00188596886cced..8b704f73055a43d075762bb1f1e4dd84fbd39b2a 100644 (file)
@@ -5001,7 +5001,7 @@ ips_init_copperhead(ips_ha_t * ha)
                                break;
 
                        /* Delay for 1 Second */
-                       msleep(IPS_ONE_SEC);
+                       MDELAY(IPS_ONE_SEC);
                }
 
                if (j >= 45)
@@ -5027,7 +5027,7 @@ ips_init_copperhead(ips_ha_t * ha)
                                break;
 
                        /* Delay for 1 Second */
-                       msleep(IPS_ONE_SEC);
+                       MDELAY(IPS_ONE_SEC);
                }
 
                if (j >= 240)
@@ -5045,7 +5045,7 @@ ips_init_copperhead(ips_ha_t * ha)
                        break;
 
                /* Delay for 1 Second */
-               msleep(IPS_ONE_SEC);
+               MDELAY(IPS_ONE_SEC);
        }
 
        if (i >= 240)
@@ -5095,7 +5095,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
                                break;
 
                        /* Delay for 1 Second */
-                       msleep(IPS_ONE_SEC);
+                       MDELAY(IPS_ONE_SEC);
                }
 
                if (j >= 45)
@@ -5121,7 +5121,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
                                break;
 
                        /* Delay for 1 Second */
-                       msleep(IPS_ONE_SEC);
+                       MDELAY(IPS_ONE_SEC);
                }
 
                if (j >= 240)
@@ -5139,7 +5139,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
                        break;
 
                /* Delay for 1 Second */
-               msleep(IPS_ONE_SEC);
+               MDELAY(IPS_ONE_SEC);
        }
 
        if (i >= 240)
@@ -5191,7 +5191,7 @@ ips_init_morpheus(ips_ha_t * ha)
                        break;
 
                /* Delay for 1 Second */
-               msleep(IPS_ONE_SEC);
+               MDELAY(IPS_ONE_SEC);
        }
 
        if (i >= 45) {
@@ -5217,7 +5217,7 @@ ips_init_morpheus(ips_ha_t * ha)
                        if (Post != 0x4F00)
                                break;
                        /* Delay for 1 Second */
-                       msleep(IPS_ONE_SEC);
+                       MDELAY(IPS_ONE_SEC);
                }
 
                if (i >= 120) {
@@ -5247,7 +5247,7 @@ ips_init_morpheus(ips_ha_t * ha)
                        break;
 
                /* Delay for 1 Second */
-               msleep(IPS_ONE_SEC);
+               MDELAY(IPS_ONE_SEC);
        }
 
        if (i >= 240) {
@@ -5307,12 +5307,12 @@ ips_reset_copperhead(ips_ha_t * ha)
                outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
 
                /* Delay for 1 Second */
-               msleep(IPS_ONE_SEC);
+               MDELAY(IPS_ONE_SEC);
 
                outb(0, ha->io_addr + IPS_REG_SCPR);
 
                /* Delay for 1 Second */
-               msleep(IPS_ONE_SEC);
+               MDELAY(IPS_ONE_SEC);
 
                if ((*ha->func.init) (ha))
                        break;
@@ -5352,12 +5352,12 @@ ips_reset_copperhead_memio(ips_ha_t * ha)
                writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
 
                /* Delay for 1 Second */
-               msleep(IPS_ONE_SEC);
+               MDELAY(IPS_ONE_SEC);
 
                writeb(0, ha->mem_ptr + IPS_REG_SCPR);
 
                /* Delay for 1 Second */
-               msleep(IPS_ONE_SEC);
+               MDELAY(IPS_ONE_SEC);
 
                if ((*ha->func.init) (ha))
                        break;
@@ -5398,7 +5398,7 @@ ips_reset_morpheus(ips_ha_t * ha)
                writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
 
                /* Delay for 5 Seconds */
-               msleep(5 * IPS_ONE_SEC);
+               MDELAY(5 * IPS_ONE_SEC);
 
                /* Do a PCI config read to wait for adapter */
                pci_read_config_byte(ha->pcidev, 4, &junk);
index 34680f3dd4523e10662aa03f6605478c2a72b262..b726dcc424b190f214d571a828339c125f28c6c4 100644 (file)
@@ -51,6 +51,7 @@
    #define _IPS_H_
 
 #include <linux/version.h>
+#include <linux/nmi.h>
    #include <asm/uaccess.h>
    #include <asm/io.h>
 
             dev_printk(level , &((pcidev)->dev) , format , ## arg)
    #endif
 
-   #ifndef MDELAY
-      #define MDELAY mdelay
-   #endif
+   #define MDELAY(n)                   \
+       do {                            \
+               mdelay(n);              \
+               touch_nmi_watchdog();   \
+       } while (0)
 
    #ifndef min
       #define min(x,y) ((x) < (y) ? x : y)
index e34a934354978ba4541e97e0d8739c402ea1f1e7..d31e6fa466f79668f151c0d0c301bbccf27c848f 100644 (file)
@@ -597,10 +597,15 @@ static struct domain_device *sas_ex_discover_end_dev(
        child->iproto = phy->attached_iproto;
        memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
        sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
-       phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
-       BUG_ON(!phy->port);
-       /* FIXME: better error handling*/
-       BUG_ON(sas_port_add(phy->port) != 0);
+       if (!phy->port) {
+               phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
+               if (unlikely(!phy->port))
+                       goto out_err;
+               if (unlikely(sas_port_add(phy->port) != 0)) {
+                       sas_port_free(phy->port);
+                       goto out_err;
+               }
+       }
        sas_ex_get_linkrate(parent, child, phy);
 
        if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
@@ -615,8 +620,7 @@ static struct domain_device *sas_ex_discover_end_dev(
                        SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
                                    "0x%x\n", SAS_ADDR(parent->sas_addr),
                                    phy_id, res);
-                       kfree(child);
-                       return NULL;
+                       goto out_free;
                }
                memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
                       sizeof(struct dev_to_host_fis));
@@ -627,14 +631,14 @@ static struct domain_device *sas_ex_discover_end_dev(
                                    "%016llx:0x%x returned 0x%x\n",
                                    SAS_ADDR(child->sas_addr),
                                    SAS_ADDR(parent->sas_addr), phy_id, res);
-                       kfree(child);
-                       return NULL;
+                       goto out_free;
                }
        } else if (phy->attached_tproto & SAS_PROTO_SSP) {
                child->dev_type = SAS_END_DEV;
                rphy = sas_end_device_alloc(phy->port);
                /* FIXME: error handling */
-               BUG_ON(!rphy);
+               if (unlikely(!rphy))
+                       goto out_free;
                child->tproto = phy->attached_tproto;
                sas_init_dev(child);
 
@@ -651,9 +655,7 @@ static struct domain_device *sas_ex_discover_end_dev(
                                    "at %016llx:0x%x returned 0x%x\n",
                                    SAS_ADDR(child->sas_addr),
                                    SAS_ADDR(parent->sas_addr), phy_id, res);
-                       /* FIXME: this kfrees list elements without removing them */
-                       //kfree(child);
-                       return NULL;
+                       goto out_list_del;
                }
        } else {
                SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
@@ -663,6 +665,16 @@ static struct domain_device *sas_ex_discover_end_dev(
 
        list_add_tail(&child->siblings, &parent_ex->children);
        return child;
+
+ out_list_del:
+       list_del(&child->dev_list_node);
+       sas_rphy_free(rphy);
+ out_free:
+       sas_port_delete(phy->port);
+ out_err:
+       phy->port = NULL;
+       kfree(child);
+       return NULL;
 }
 
 static struct domain_device *sas_ex_discover_expander(
index c836a237fb7955b6e53a88b0916d7ad551b0b75a..0fb347b4b1a221f308d612d2dcab256f77ce81eb 100644 (file)
@@ -112,6 +112,8 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
                }
        }
 
+       INIT_LIST_HEAD(&sas_ha->eh_done_q);
+
        return 0;
 
 Undo_ports:
@@ -142,7 +144,7 @@ static int sas_get_linkerrors(struct sas_phy *phy)
        return sas_smp_get_phy_events(phy);
 }
 
-static int sas_phy_reset(struct sas_phy *phy, int hard_reset)
+int sas_phy_reset(struct sas_phy *phy, int hard_reset)
 {
        int ret;
        enum phy_func reset_type;
index e46e79355b776ec98a407962694a8e3756414571..e064aac06b90950b3e0e5e671a6840e49e0858b2 100644 (file)
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_sas.h>
 #include "../scsi_sas_internal.h"
+#include "../scsi_transport_api.h"
 
 #include <linux/err.h>
 #include <linux/blkdev.h>
@@ -46,6 +48,7 @@ static void sas_scsi_task_done(struct sas_task *task)
 {
        struct task_status_struct *ts = &task->task_status;
        struct scsi_cmnd *sc = task->uldd_task;
+       struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(sc->device->host);
        unsigned ts_flags = task->task_state_flags;
        int hs = 0, stat = 0;
 
@@ -116,7 +119,7 @@ static void sas_scsi_task_done(struct sas_task *task)
        sas_free_task(task);
        /* This is very ugly but this is how SCSI Core works. */
        if (ts_flags & SAS_TASK_STATE_ABORTED)
-               scsi_finish_command(sc);
+               scsi_eh_finish_cmd(sc, &sas_ha->eh_done_q);
        else
                sc->scsi_done(sc);
 }
@@ -307,6 +310,15 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
                spin_unlock_irqrestore(&core->task_queue_lock, flags);
        }
 
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) {
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+               SAS_DPRINTK("%s: task 0x%p already aborted\n",
+                           __FUNCTION__, task);
+               return TASK_IS_ABORTED;
+       }
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
+
        for (i = 0; i < 5; i++) {
                SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
                res = si->dft->lldd_abort_task(task);
@@ -409,13 +421,16 @@ Again:
        SAS_DPRINTK("going over list...\n");
        list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
                struct sas_task *task = TO_SAS_TASK(cmd);
+               list_del_init(&cmd->eh_entry);
 
+               if (!task) {
+                       SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__);
+                       continue;
+               }
                SAS_DPRINTK("trying to find task 0x%p\n", task);
-               list_del_init(&cmd->eh_entry);
                res = sas_scsi_find_task(task);
 
                cmd->eh_eflags = 0;
-               shost->host_failed--;
 
                switch (res) {
                case TASK_IS_DONE:
@@ -491,6 +506,7 @@ Again:
                }
        }
 out:
+       scsi_eh_flush_done_q(&ha->eh_done_q);
        SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
        return;
 clear_q:
@@ -508,12 +524,18 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
        unsigned long flags;
 
        if (!task) {
-               SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
+               SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n",
                            cmd, task);
                return EH_HANDLED;
        }
 
        spin_lock_irqsave(&task->task_state_lock, flags);
+       if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) {
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+               SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: "
+                           "EH_NOT_HANDLED\n", cmd, task);
+               return EH_NOT_HANDLED;
+       }
        if (task->task_state_flags & SAS_TASK_STATE_DONE) {
                spin_unlock_irqrestore(&task->task_state_lock, flags);
                SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
@@ -777,6 +799,64 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
        spin_unlock_irqrestore(&core->task_queue_lock, flags);
 }
 
+static int do_sas_task_abort(struct sas_task *task)
+{
+       struct scsi_cmnd *sc = task->uldd_task;
+       struct sas_internal *si =
+               to_sas_internal(task->dev->port->ha->core.shost->transportt);
+       unsigned long flags;
+       int res;
+
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+               spin_unlock_irqrestore(&task->task_state_lock, flags);
+               SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__,
+                           task);
+               return 0;
+       }
+
+       task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED;
+       if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+               task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+       if (!si->dft->lldd_abort_task)
+               return -ENODEV;
+
+       res = si->dft->lldd_abort_task(task);
+       if ((task->task_state_flags & SAS_TASK_STATE_DONE) ||
+           (res == TMF_RESP_FUNC_COMPLETE))
+       {
+               /* SMP commands don't have scsi_cmds(?) */
+               if (!sc) {
+                       task->task_done(task);
+                       return 0;
+               }
+               scsi_req_abort_cmd(sc);
+               scsi_schedule_eh(sc->device->host);
+               return 0;
+       }
+
+       spin_lock_irqsave(&task->task_state_lock, flags);
+       task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED;
+       if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+               task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
+       spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+       return -EAGAIN;
+}
+
+void sas_task_abort(struct sas_task *task)
+{
+       int i;
+
+       for (i = 0; i < 5; i++)
+               if (!do_sas_task_abort(task))
+                       return;
+
+       SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__);
+}
+
 EXPORT_SYMBOL_GPL(sas_queuecommand);
 EXPORT_SYMBOL_GPL(sas_target_alloc);
 EXPORT_SYMBOL_GPL(sas_slave_configure);
@@ -784,3 +864,5 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy);
 EXPORT_SYMBOL_GPL(sas_change_queue_depth);
 EXPORT_SYMBOL_GPL(sas_change_queue_type);
 EXPORT_SYMBOL_GPL(sas_bios_param);
+EXPORT_SYMBOL_GPL(sas_task_abort);
+EXPORT_SYMBOL_GPL(sas_phy_reset);
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
new file mode 100644 (file)
index 0000000..89403b0
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * SCSI RDAM Protocol lib functions
+ *
+ * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/err.h>
+#include <linux/kfifo.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_tgt.h>
+#include <scsi/srp.h>
+#include <scsi/libsrp.h>
+
+enum srp_task_attributes {
+       SRP_SIMPLE_TASK = 0,
+       SRP_HEAD_TASK = 1,
+       SRP_ORDERED_TASK = 2,
+       SRP_ACA_TASK = 4
+};
+
+/* tmp - will replace with SCSI logging stuff */
+#define eprintk(fmt, args...)                                  \
+do {                                                           \
+       printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);  \
+} while (0)
+/* #define dprintk eprintk */
+#define dprintk(fmt, args...)
+
+static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
+                            struct srp_buf **ring)
+{
+       int i;
+       struct iu_entry *iue;
+
+       q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
+       if (!q->pool)
+               return -ENOMEM;
+       q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
+       if (!q->items)
+               goto free_pool;
+
+       spin_lock_init(&q->lock);
+       q->queue = kfifo_init((void *) q->pool, max * sizeof(void *),
+                             GFP_KERNEL, &q->lock);
+       if (IS_ERR(q->queue))
+               goto free_item;
+
+       for (i = 0, iue = q->items; i < max; i++) {
+               __kfifo_put(q->queue, (void *) &iue, sizeof(void *));
+               iue->sbuf = ring[i];
+               iue++;
+       }
+       return 0;
+
+free_item:
+       kfree(q->items);
+free_pool:
+       kfree(q->pool);
+       return -ENOMEM;
+}
+
+static void srp_iu_pool_free(struct srp_queue *q)
+{
+       kfree(q->items);
+       kfree(q->pool);
+}
+
+static struct srp_buf **srp_ring_alloc(struct device *dev,
+                                      size_t max, size_t size)
+{
+       int i;
+       struct srp_buf **ring;
+
+       ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
+       if (!ring)
+               return NULL;
+
+       for (i = 0; i < max; i++) {
+               ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL);
+               if (!ring[i])
+                       goto out;
+               ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
+                                                 GFP_KERNEL);
+               if (!ring[i]->buf)
+                       goto out;
+       }
+       return ring;
+
+out:
+       for (i = 0; i < max && ring[i]; i++) {
+               if (ring[i]->buf)
+                       dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
+               kfree(ring[i]);
+       }
+       kfree(ring);
+
+       return NULL;
+}
+
+static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max,
+                         size_t size)
+{
+       int i;
+
+       for (i = 0; i < max; i++) {
+               dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
+               kfree(ring[i]);
+       }
+}
+
+int srp_target_alloc(struct srp_target *target, struct device *dev,
+                    size_t nr, size_t iu_size)
+{
+       int err;
+
+       spin_lock_init(&target->lock);
+       INIT_LIST_HEAD(&target->cmd_queue);
+
+       target->dev = dev;
+       target->dev->driver_data = target;
+
+       target->srp_iu_size = iu_size;
+       target->rx_ring_size = nr;
+       target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
+       if (!target->rx_ring)
+               return -ENOMEM;
+       err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
+       if (err)
+               goto free_ring;
+
+       return 0;
+
+free_ring:
+       srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(srp_target_alloc);
+
+void srp_target_free(struct srp_target *target)
+{
+       srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
+                     target->srp_iu_size);
+       srp_iu_pool_free(&target->iu_queue);
+}
+EXPORT_SYMBOL_GPL(srp_target_free);
+
+struct iu_entry *srp_iu_get(struct srp_target *target)
+{
+       struct iu_entry *iue = NULL;
+
+       kfifo_get(target->iu_queue.queue, (void *) &iue, sizeof(void *));
+       if (!iue)
+               return iue;
+       iue->target = target;
+       INIT_LIST_HEAD(&iue->ilist);
+       iue->flags = 0;
+       return iue;
+}
+EXPORT_SYMBOL_GPL(srp_iu_get);
+
+void srp_iu_put(struct iu_entry *iue)
+{
+       kfifo_put(iue->target->iu_queue.queue, (void *) &iue, sizeof(void *));
+}
+EXPORT_SYMBOL_GPL(srp_iu_put);
+
+static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
+                          enum dma_data_direction dir, srp_rdma_t rdma_io,
+                          int dma_map, int ext_desc)
+{
+       struct iu_entry *iue = NULL;
+       struct scatterlist *sg = NULL;
+       int err, nsg = 0, len;
+
+       if (dma_map) {
+               iue = (struct iu_entry *) sc->SCp.ptr;
+               sg = sc->request_buffer;
+
+               dprintk("%p %u %u %d\n", iue, sc->request_bufflen,
+                       md->len, sc->use_sg);
+
+               nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg,
+                                DMA_BIDIRECTIONAL);
+               if (!nsg) {
+                       printk("fail to map %p %d\n", iue, sc->use_sg);
+                       return 0;
+               }
+               len = min(sc->request_bufflen, md->len);
+       } else
+               len = md->len;
+
+       err = rdma_io(sc, sg, nsg, md, 1, dir, len);
+
+       if (dma_map)
+               dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+       return err;
+}
+
+static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
+                            struct srp_indirect_buf *id,
+                            enum dma_data_direction dir, srp_rdma_t rdma_io,
+                            int dma_map, int ext_desc)
+{
+       struct iu_entry *iue = NULL;
+       struct srp_direct_buf *md = NULL;
+       struct scatterlist dummy, *sg = NULL;
+       dma_addr_t token = 0;
+       long err;
+       unsigned int done = 0;
+       int nmd, nsg = 0, len;
+
+       if (dma_map || ext_desc) {
+               iue = (struct iu_entry *) sc->SCp.ptr;
+               sg = sc->request_buffer;
+
+               dprintk("%p %u %u %d %d\n",
+                       iue, sc->request_bufflen, id->len,
+                       cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
+       }
+
+       nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
+
+       if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
+           (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) {
+               md = &id->desc_list[0];
+               goto rdma;
+       }
+
+       if (ext_desc && dma_map) {
+               md = dma_alloc_coherent(iue->target->dev, id->table_desc.len,
+                               &token, GFP_KERNEL);
+               if (!md) {
+                       eprintk("Can't get dma memory %u\n", id->table_desc.len);
+                       return -ENOMEM;
+               }
+
+               sg_init_one(&dummy, md, id->table_desc.len);
+               sg_dma_address(&dummy) = token;
+               err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
+                             id->table_desc.len);
+               if (err < 0) {
+                       eprintk("Error copying indirect table %ld\n", err);
+                       goto free_mem;
+               }
+       } else {
+               eprintk("This command uses external indirect buffer\n");
+               return -EINVAL;
+       }
+
+rdma:
+       if (dma_map) {
+               nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
+               if (!nsg) {
+                       eprintk("fail to map %p %d\n", iue, sc->use_sg);
+                       goto free_mem;
+               }
+               len = min(sc->request_bufflen, id->len);
+       } else
+               len = id->len;
+
+       err = rdma_io(sc, sg, nsg, md, nmd, dir, len);
+
+       if (dma_map)
+               dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
+
+free_mem:
+       if (token && dma_map)
+               dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
+
+       return done;
+}
+
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+       int size = 0;
+       u8 fmt = cmd->buf_fmt >> 4;
+
+       switch (fmt) {
+       case SRP_NO_DATA_DESC:
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               size = sizeof(struct srp_direct_buf);
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               size = sizeof(struct srp_indirect_buf) +
+                       sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
+               break;
+       default:
+               eprintk("client error. Invalid data_out_format %x\n", fmt);
+               break;
+       }
+       return size;
+}
+
+/*
+ * TODO: this can be called multiple times for a single command if it
+ * has very long data.
+ */
+int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
+                     srp_rdma_t rdma_io, int dma_map, int ext_desc)
+{
+       struct srp_direct_buf *md;
+       struct srp_indirect_buf *id;
+       enum dma_data_direction dir;
+       int offset, err = 0;
+       u8 format;
+
+       offset = cmd->add_cdb_len * 4;
+
+       dir = srp_cmd_direction(cmd);
+       if (dir == DMA_FROM_DEVICE)
+               offset += data_out_desc_size(cmd);
+
+       if (dir == DMA_TO_DEVICE)
+               format = cmd->buf_fmt >> 4;
+       else
+               format = cmd->buf_fmt & ((1U << 4) - 1);
+
+       switch (format) {
+       case SRP_NO_DATA_DESC:
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               md = (struct srp_direct_buf *)
+                       (cmd->add_data + offset);
+               err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc);
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               id = (struct srp_indirect_buf *)
+                       (cmd->add_data + offset);
+               err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map,
+                                       ext_desc);
+               break;
+       default:
+               eprintk("Unknown format %d %x\n", dir, format);
+               break;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(srp_transfer_data);
+
+static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
+{
+       struct srp_direct_buf *md;
+       struct srp_indirect_buf *id;
+       int len = 0, offset = cmd->add_cdb_len * 4;
+       u8 fmt;
+
+       if (dir == DMA_TO_DEVICE)
+               fmt = cmd->buf_fmt >> 4;
+       else {
+               fmt = cmd->buf_fmt & ((1U << 4) - 1);
+               offset += data_out_desc_size(cmd);
+       }
+
+       switch (fmt) {
+       case SRP_NO_DATA_DESC:
+               break;
+       case SRP_DATA_DESC_DIRECT:
+               md = (struct srp_direct_buf *) (cmd->add_data + offset);
+               len = md->len;
+               break;
+       case SRP_DATA_DESC_INDIRECT:
+               id = (struct srp_indirect_buf *) (cmd->add_data + offset);
+               len = id->len;
+               break;
+       default:
+               eprintk("invalid data format %x\n", fmt);
+               break;
+       }
+       return len;
+}
+
+int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
+                 u64 addr)
+{
+       enum dma_data_direction dir;
+       struct scsi_cmnd *sc;
+       int tag, len, err;
+
+       switch (cmd->task_attr) {
+       case SRP_SIMPLE_TASK:
+               tag = MSG_SIMPLE_TAG;
+               break;
+       case SRP_ORDERED_TASK:
+               tag = MSG_ORDERED_TAG;
+               break;
+       case SRP_HEAD_TASK:
+               tag = MSG_HEAD_TAG;
+               break;
+       default:
+               eprintk("Task attribute %d not supported\n", cmd->task_attr);
+               tag = MSG_ORDERED_TAG;
+       }
+
+       dir = srp_cmd_direction(cmd);
+       len = vscsis_data_length(cmd, dir);
+
+       dprintk("%p %x %lx %d %d %d %llx\n", info, cmd->cdb[0],
+               cmd->lun, dir, len, tag, (unsigned long long) cmd->tag);
+
+       sc = scsi_host_get_command(shost, dir, GFP_KERNEL);
+       if (!sc)
+               return -ENOMEM;
+
+       sc->SCp.ptr = info;
+       memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE);
+       sc->request_bufflen = len;
+       sc->request_buffer = (void *) (unsigned long) addr;
+       sc->tag = tag;
+       err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag);
+       if (err)
+               scsi_host_put_command(shost, sc);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(srp_cmd_queue);
+
+MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions");
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_LICENSE("GPL");
index 3f7f5f8abd7517524b330ac2cd98c13f3444999a..a7de0bca5bdd31efd19b2683e95feaa39e7aadcd 100644 (file)
@@ -296,13 +296,17 @@ struct lpfc_hba {
        uint32_t cfg_cr_delay;
        uint32_t cfg_cr_count;
        uint32_t cfg_multi_ring_support;
+       uint32_t cfg_multi_ring_rctl;
+       uint32_t cfg_multi_ring_type;
        uint32_t cfg_fdmi_on;
        uint32_t cfg_discovery_threads;
        uint32_t cfg_max_luns;
        uint32_t cfg_poll;
        uint32_t cfg_poll_tmo;
+       uint32_t cfg_use_msi;
        uint32_t cfg_sg_seg_cnt;
        uint32_t cfg_sg_dma_buf_size;
+       uint64_t cfg_soft_wwnn;
        uint64_t cfg_soft_wwpn;
 
        uint32_t dev_loss_tmo_changed;
@@ -355,7 +359,7 @@ struct lpfc_hba {
 #define VPD_PORT            0x8         /* valid vpd port data */
 #define VPD_MASK            0xf         /* mask for any vpd data */
 
-       uint8_t soft_wwpn_enable;
+       uint8_t soft_wwn_enable;
 
        struct timer_list fcp_poll_timer;
        struct timer_list els_tmofunc;
index 2a4e02e7a39211d83960c8522417d1b89f2d9be4..f247e786af99487cda664cae44193adec19af7b3 100644 (file)
@@ -552,10 +552,10 @@ static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
 static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
 
 
-static char *lpfc_soft_wwpn_key = "C99G71SL8032A";
+static char *lpfc_soft_wwn_key = "C99G71SL8032A";
 
 static ssize_t
-lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf,
+lpfc_soft_wwn_enable_store(struct class_device *cdev, const char *buf,
                                size_t count)
 {
        struct Scsi_Host *host = class_to_shost(cdev);
@@ -579,15 +579,15 @@ lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf,
        if (buf[cnt-1] == '\n')
                cnt--;
 
-       if ((cnt != strlen(lpfc_soft_wwpn_key)) ||
-           (strncmp(buf, lpfc_soft_wwpn_key, strlen(lpfc_soft_wwpn_key)) != 0))
+       if ((cnt != strlen(lpfc_soft_wwn_key)) ||
+           (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0))
                return -EINVAL;
 
-       phba->soft_wwpn_enable = 1;
+       phba->soft_wwn_enable = 1;
        return count;
 }
-static CLASS_DEVICE_ATTR(lpfc_soft_wwpn_enable, S_IWUSR, NULL,
-                               lpfc_soft_wwpn_enable_store);
+static CLASS_DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL,
+                               lpfc_soft_wwn_enable_store);
 
 static ssize_t
 lpfc_soft_wwpn_show(struct class_device *cdev, char *buf)
@@ -613,12 +613,12 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
        if (buf[cnt-1] == '\n')
                cnt--;
 
-       if (!phba->soft_wwpn_enable || (cnt < 16) || (cnt > 18) ||
+       if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) ||
            ((cnt == 17) && (*buf++ != 'x')) ||
            ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
                return -EINVAL;
 
-       phba->soft_wwpn_enable = 0;
+       phba->soft_wwn_enable = 0;
 
        memset(wwpn, 0, sizeof(wwpn));
 
@@ -639,6 +639,8 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
        }
        phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
        fc_host_port_name(host) = phba->cfg_soft_wwpn;
+       if (phba->cfg_soft_wwnn)
+               fc_host_node_name(host) = phba->cfg_soft_wwnn;
 
        dev_printk(KERN_NOTICE, &phba->pcidev->dev,
                   "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
@@ -664,6 +666,66 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
 static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
                         lpfc_soft_wwpn_show, lpfc_soft_wwpn_store);
 
+static ssize_t
+lpfc_soft_wwnn_show(struct class_device *cdev, char *buf)
+{
+       struct Scsi_Host *host = class_to_shost(cdev);
+       struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+       return snprintf(buf, PAGE_SIZE, "0x%llx\n",
+                       (unsigned long long)phba->cfg_soft_wwnn);
+}
+
+
+static ssize_t
+lpfc_soft_wwnn_store(struct class_device *cdev, const char *buf, size_t count)
+{
+       struct Scsi_Host *host = class_to_shost(cdev);
+       struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+       unsigned int i, j, cnt=count;
+       u8 wwnn[8];
+
+       /* count may include a LF at end of string */
+       if (buf[cnt-1] == '\n')
+               cnt--;
+
+       if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) ||
+           ((cnt == 17) && (*buf++ != 'x')) ||
+           ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+               return -EINVAL;
+
+       /*
+        * Allow wwnn to be set many times, as long as the enable is set.
+        * However, once the wwpn is set, everything locks.
+        */
+
+       memset(wwnn, 0, sizeof(wwnn));
+
+       /* Validate and store the new name */
+       for (i=0, j=0; i < 16; i++) {
+               if ((*buf >= 'a') && (*buf <= 'f'))
+                       j = ((j << 4) | ((*buf++ -'a') + 10));
+               else if ((*buf >= 'A') && (*buf <= 'F'))
+                       j = ((j << 4) | ((*buf++ -'A') + 10));
+               else if ((*buf >= '0') && (*buf <= '9'))
+                       j = ((j << 4) | (*buf++ -'0'));
+               else
+                       return -EINVAL;
+               if (i % 2) {
+                       wwnn[i/2] = j & 0xff;
+                       j = 0;
+               }
+       }
+       phba->cfg_soft_wwnn = wwn_to_u64(wwnn);
+
+       dev_printk(KERN_NOTICE, &phba->pcidev->dev,
+                  "lpfc%d: soft_wwnn set. Value will take effect upon "
+                  "setting of the soft_wwpn\n", phba->brd_no);
+
+       return count;
+}
+static CLASS_DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\
+                        lpfc_soft_wwnn_show, lpfc_soft_wwnn_store);
+
 
 static int lpfc_poll = 0;
 module_param(lpfc_poll, int, 0);
@@ -802,12 +864,11 @@ static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
 # LOG_MBOX                      0x4        Mailbox events
 # LOG_INIT                      0x8        Initialization events
 # LOG_LINK_EVENT                0x10       Link events
-# LOG_IP                        0x20       IP traffic history
 # LOG_FCP                       0x40       FCP traffic history
 # LOG_NODE                      0x80       Node table events
 # LOG_MISC                      0x400      Miscellaneous events
 # LOG_SLI                       0x800      SLI events
-# LOG_CHK_COND                  0x1000     FCP Check condition flag
+# LOG_FCP_ERROR                 0x1000     Only log FCP errors
 # LOG_LIBDFC                    0x2000     LIBDFC events
 # LOG_ALL_MSG                   0xffff     LOG all messages
 */
@@ -915,6 +976,22 @@ LPFC_ATTR_RW(cr_count, 1, 1, 255, "A count of I/O completions after which an "
 LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary "
                "SLI rings to spread IOCB entries across");
 
+/*
+# lpfc_multi_ring_rctl:  If lpfc_multi_ring_support is enabled, this
+# identifies what rctl value to configure the additional ring for.
+# Value range is [1,0xff]. Default value is 4 (Unsolicated Data).
+*/
+LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1,
+            255, "Identifies RCTL for additional ring configuration");
+
+/*
+# lpfc_multi_ring_type:  If lpfc_multi_ring_support is enabled, this
+# identifies what type value to configure the additional ring for.
+# Value range is [1,0xff]. Default value is 5 (LLC/SNAP).
+*/
+LPFC_ATTR_R(multi_ring_type, FC_LLC_SNAP, 1,
+            255, "Identifies TYPE for additional ring configuration");
+
 /*
 # lpfc_fdmi_on: controls FDMI support.
 #       0 = no FDMI support
@@ -946,6 +1023,15 @@ LPFC_ATTR_R(max_luns, 255, 0, 65535,
 LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
             "Milliseconds driver will wait between polling FCP ring");
 
+/*
+# lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that
+#              support this feature
+#       0  = MSI disabled (default)
+#       1  = MSI enabled
+# Value range is [0,1]. Default value is 0.
+*/
+LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
+
 
 struct class_device_attribute *lpfc_host_attrs[] = {
        &class_device_attr_info,
@@ -974,6 +1060,8 @@ struct class_device_attribute *lpfc_host_attrs[] = {
        &class_device_attr_lpfc_cr_delay,
        &class_device_attr_lpfc_cr_count,
        &class_device_attr_lpfc_multi_ring_support,
+       &class_device_attr_lpfc_multi_ring_rctl,
+       &class_device_attr_lpfc_multi_ring_type,
        &class_device_attr_lpfc_fdmi_on,
        &class_device_attr_lpfc_max_luns,
        &class_device_attr_nport_evt_cnt,
@@ -982,8 +1070,10 @@ struct class_device_attribute *lpfc_host_attrs[] = {
        &class_device_attr_issue_reset,
        &class_device_attr_lpfc_poll,
        &class_device_attr_lpfc_poll_tmo,
+       &class_device_attr_lpfc_use_msi,
+       &class_device_attr_lpfc_soft_wwnn,
        &class_device_attr_lpfc_soft_wwpn,
-       &class_device_attr_lpfc_soft_wwpn_enable,
+       &class_device_attr_lpfc_soft_wwn_enable,
        NULL,
 };
 
@@ -1771,6 +1861,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_cr_delay_init(phba, lpfc_cr_delay);
        lpfc_cr_count_init(phba, lpfc_cr_count);
        lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support);
+       lpfc_multi_ring_rctl_init(phba, lpfc_multi_ring_rctl);
+       lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type);
        lpfc_lun_queue_depth_init(phba, lpfc_lun_queue_depth);
        lpfc_fcp_class_init(phba, lpfc_fcp_class);
        lpfc_use_adisc_init(phba, lpfc_use_adisc);
@@ -1782,9 +1874,11 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
        lpfc_max_luns_init(phba, lpfc_max_luns);
        lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
+       lpfc_use_msi_init(phba, lpfc_use_msi);
        lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
        lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
        phba->cfg_poll = lpfc_poll;
+       phba->cfg_soft_wwnn = 0L;
        phba->cfg_soft_wwpn = 0L;
 
        /*
index 3add7c237859d66347ff5ea69d19a3969d3da72e..a51a41b7f15d55566277619d8be5e64d06b31324 100644 (file)
@@ -558,6 +558,14 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        return;
 }
 
+static void
+lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+                        struct lpfc_iocbq * rspiocb)
+{
+       lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+       return;
+}
+
 void
 lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp)
 {
@@ -629,6 +637,8 @@ lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
                bpl->tus.f.bdeSize = RNN_REQUEST_SZ;
        else if (cmdcode == SLI_CTNS_RSNN_NN)
                bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
+       else if (cmdcode == SLI_CTNS_RFF_ID)
+               bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
        else
                bpl->tus.f.bdeSize = 0;
        bpl->tus.w = le32_to_cpu(bpl->tus.w);
@@ -660,6 +670,17 @@ lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
                cmpl = lpfc_cmpl_ct_cmd_rft_id;
                break;
 
+       case SLI_CTNS_RFF_ID:
+               CtReq->CommandResponse.bits.CmdRsp =
+                       be16_to_cpu(SLI_CTNS_RFF_ID);
+               CtReq->un.rff.PortId = be32_to_cpu(phba->fc_myDID);
+               CtReq->un.rff.feature_res = 0;
+               CtReq->un.rff.feature_tgt = 0;
+               CtReq->un.rff.type_code = FC_FCP_DATA;
+               CtReq->un.rff.feature_init = 1;
+               cmpl = lpfc_cmpl_ct_cmd_rff_id;
+               break;
+
        case SLI_CTNS_RNN_ID:
                CtReq->CommandResponse.bits.CmdRsp =
                    be16_to_cpu(SLI_CTNS_RNN_ID);
@@ -934,7 +955,8 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
                        ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
                        ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION);
                        sprintf(ae->un.OsNameVersion, "%s %s %s",
-                               init_utsname()->sysname, init_utsname()->release,
+                               init_utsname()->sysname,
+                               init_utsname()->release,
                                init_utsname()->version);
                        len = strlen(ae->un.OsNameVersion);
                        len += (len & 3) ? (4 - (len & 3)) : 4;
index 71864cdc6c71a432803a1ed9183489223e362eb7..a5f33a0dd4e7b79fb204cff5553d04c71c76177e 100644 (file)
@@ -243,6 +243,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
                struct serv_parm *sp, IOCB_t *irsp)
 {
        LPFC_MBOXQ_t *mbox;
+       struct lpfc_dmabuf *mp;
        int rc;
 
        spin_lock_irq(phba->host->host_lock);
@@ -307,10 +308,14 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
 
        rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
        if (rc == MBX_NOT_FINISHED)
-               goto fail_free_mbox;
+               goto fail_issue_reg_login;
 
        return 0;
 
+ fail_issue_reg_login:
+       mp = (struct lpfc_dmabuf *) mbox->context1;
+       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+       kfree(mp);
  fail_free_mbox:
        mempool_free(mbox, phba->mbox_mem_pool);
  fail:
@@ -657,6 +662,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
        uint8_t name[sizeof (struct lpfc_name)];
        uint32_t rc;
 
+       /* Fabric nodes can have the same WWPN so we don't bother searching
+        * by WWPN.  Just return the ndlp that was given to us.
+        */
+       if (ndlp->nlp_type & NLP_FABRIC)
+               return ndlp;
+
        lp = (uint32_t *) prsp->virt;
        sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
        memset(name, 0, sizeof (struct lpfc_name));
@@ -1122,7 +1133,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                                                mempool_free(mbox,
                                                     phba->mbox_mem_pool);
                                                lpfc_disc_flush_list(phba);
-                                               psli->ring[(psli->ip_ring)].
+                                               psli->ring[(psli->extra_ring)].
                                                    flag &=
                                                    ~LPFC_STOP_IOCB_EVENT;
                                                psli->ring[(psli->fcp_ring)].
@@ -1851,6 +1862,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        IOCB_t *irsp;
        struct lpfc_nodelist *ndlp;
        LPFC_MBOXQ_t *mbox = NULL;
+       struct lpfc_dmabuf *mp;
 
        irsp = &rspiocb->iocb;
 
@@ -1862,6 +1874,11 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
        /* Check to see if link went down during discovery */
        if ((lpfc_els_chk_latt(phba)) || !ndlp) {
                if (mbox) {
+                       mp = (struct lpfc_dmabuf *) mbox->context1;
+                       if (mp) {
+                               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                               kfree(mp);
+                       }
                        mempool_free( mbox, phba->mbox_mem_pool);
                }
                goto out;
@@ -1893,9 +1910,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                        }
                        /* NOTE: we should have messages for unsuccessful
                           reglogin */
-                       mempool_free( mbox, phba->mbox_mem_pool);
                } else {
-                       mempool_free( mbox, phba->mbox_mem_pool);
                        /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
                        if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
                              ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
@@ -1907,6 +1922,12 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
                                }
                        }
                }
+               mp = (struct lpfc_dmabuf *) mbox->context1;
+               if (mp) {
+                       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                       kfree(mp);
+               }
+               mempool_free(mbox, phba->mbox_mem_pool);
        }
 out:
        if (ndlp) {
@@ -2644,6 +2665,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
                        ndlp->nlp_type |= NLP_FABRIC;
                        ndlp->nlp_prev_state = ndlp->nlp_state;
                        ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
+                       lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
                        lpfc_issue_els_plogi(phba, NameServer_DID, 0);
                        /* Wait for NameServer login cmpl before we can
                           continue */
@@ -3039,7 +3061,7 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
        /* FARP-REQ received from DID <did> */
        lpfc_printf_log(phba,
                         KERN_INFO,
-                        LOG_IP,
+                        LOG_ELS,
                         "%d:0601 FARP-REQ received from DID x%x\n",
                         phba->brd_no, did);
 
@@ -3101,7 +3123,7 @@ lpfc_els_rcv_farpr(struct lpfc_hba * phba,
        /* FARP-RSP received from DID <did> */
        lpfc_printf_log(phba,
                         KERN_INFO,
-                        LOG_IP,
+                        LOG_ELS,
                         "%d:0600 FARP-RSP received from DID x%x\n",
                         phba->brd_no, did);
 
index 19c79a0549a7718cbf4560d3818c23e81c059579..c39564e85e944f62ebed5d8b3d41a6f75daf4ff7 100644 (file)
@@ -525,7 +525,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        psli = &phba->sli;
        mb = &pmb->mb;
        /* Since we don't do discovery right now, turn these off here */
-       psli->ring[psli->ip_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
+       psli->ring[psli->extra_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
        psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
        psli->ring[psli->next_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
 
@@ -641,7 +641,7 @@ out:
        if (rc == MBX_NOT_FINISHED) {
                mempool_free(pmb, phba->mbox_mem_pool);
                lpfc_disc_flush_list(phba);
-               psli->ring[(psli->ip_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
+               psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
                psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
                psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
                phba->hba_state = LPFC_HBA_READY;
@@ -672,6 +672,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 
        memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt,
               sizeof (struct serv_parm));
+       if (phba->cfg_soft_wwnn)
+               u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn);
        if (phba->cfg_soft_wwpn)
                u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
        memcpy((uint8_t *) & phba->fc_nodename,
@@ -696,7 +698,7 @@ out:
                    == MBX_NOT_FINISHED) {
                        mempool_free( pmb, phba->mbox_mem_pool);
                        lpfc_disc_flush_list(phba);
-                       psli->ring[(psli->ip_ring)].flag &=
+                       psli->ring[(psli->extra_ring)].flag &=
                            ~LPFC_STOP_IOCB_EVENT;
                        psli->ring[(psli->fcp_ring)].flag &=
                            ~LPFC_STOP_IOCB_EVENT;
@@ -715,6 +717,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
 {
        int i;
        LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox;
+       struct lpfc_dmabuf *mp;
+       int rc;
+
        sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
        cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 
@@ -793,16 +798,27 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
        if (sparam_mbox) {
                lpfc_read_sparam(phba, sparam_mbox);
                sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
-               lpfc_sli_issue_mbox(phba, sparam_mbox,
+               rc = lpfc_sli_issue_mbox(phba, sparam_mbox,
                                                (MBX_NOWAIT | MBX_STOP_IOCB));
+               if (rc == MBX_NOT_FINISHED) {
+                       mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
+                       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                       kfree(mp);
+                       mempool_free(sparam_mbox, phba->mbox_mem_pool);
+                       if (cfglink_mbox)
+                               mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+                       return;
+               }
        }
 
        if (cfglink_mbox) {
                phba->hba_state = LPFC_LOCAL_CFG_LINK;
                lpfc_config_link(phba, cfglink_mbox);
                cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
-               lpfc_sli_issue_mbox(phba, cfglink_mbox,
+               rc = lpfc_sli_issue_mbox(phba, cfglink_mbox,
                                                (MBX_NOWAIT | MBX_STOP_IOCB));
+               if (rc == MBX_NOT_FINISHED)
+                       mempool_free(cfglink_mbox, phba->mbox_mem_pool);
        }
 }
 
@@ -1067,6 +1083,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
                lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RNN_ID);
                lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RSNN_NN);
                lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFT_ID);
+               lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFF_ID);
        }
 
        phba->fc_ns_retry = 0;
@@ -1423,7 +1440,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
                        if (iocb->context1 == (uint8_t *) ndlp)
                                return 1;
                }
-       } else if (pring->ringno == psli->ip_ring) {
+       } else if (pring->ringno == psli->extra_ring) {
 
        } else if (pring->ringno == psli->fcp_ring) {
                /* Skip match check if waiting to relogin to FCP target */
@@ -1680,112 +1697,38 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
 struct lpfc_nodelist *
 lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
 {
-       struct lpfc_nodelist *ndlp, *next_ndlp;
+       struct lpfc_nodelist *ndlp;
+       struct list_head *lists[]={&phba->fc_nlpunmap_list,
+                                  &phba->fc_nlpmap_list,
+                                  &phba->fc_plogi_list,
+                                  &phba->fc_adisc_list,
+                                  &phba->fc_reglogin_list,
+                                  &phba->fc_prli_list,
+                                  &phba->fc_npr_list,
+                                  &phba->fc_unused_list};
+       uint32_t search[]={NLP_SEARCH_UNMAPPED,
+                          NLP_SEARCH_MAPPED,
+                          NLP_SEARCH_PLOGI,
+                          NLP_SEARCH_ADISC,
+                          NLP_SEARCH_REGLOGIN,
+                          NLP_SEARCH_PRLI,
+                          NLP_SEARCH_NPR,
+                          NLP_SEARCH_UNUSED};
+       int i;
        uint32_t data1;
 
        spin_lock_irq(phba->host->host_lock);
-       if (order & NLP_SEARCH_UNMAPPED) {
-               list_for_each_entry_safe(ndlp, next_ndlp,
-                                        &phba->fc_nlpunmap_list, nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               /* FIND node DID unmapped */
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0929 FIND node DID unmapped"
-                                               " Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
-
-       if (order & NLP_SEARCH_MAPPED) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
-                                       nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               /* FIND node DID mapped */
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0930 FIND node DID mapped "
-                                               "Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
-
-       if (order & NLP_SEARCH_PLOGI) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
-                                       nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               /* LOG change to PLOGI */
-                               /* FIND node DID plogi */
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0908 FIND node DID plogi "
-                                               "Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
-
-       if (order & NLP_SEARCH_ADISC) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-                                       nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               /* LOG change to ADISC */
-                               /* FIND node DID adisc */
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0931 FIND node DID adisc "
-                                               "Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
-
-       if (order & NLP_SEARCH_REGLOGIN) {
-               list_for_each_entry_safe(ndlp, next_ndlp,
-                                        &phba->fc_reglogin_list, nlp_listp) {
+       for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
+               if (!(order & search[i]))
+                       continue;
+               list_for_each_entry(ndlp, lists[i], nlp_listp) {
                        if (lpfc_matchdid(phba, ndlp, did)) {
-
                                data1 = (((uint32_t) ndlp->nlp_state << 24) |
                                         ((uint32_t) ndlp->nlp_xri << 16) |
                                         ((uint32_t) ndlp->nlp_type << 8) |
                                         ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               /* LOG change to REGLOGIN */
-                               /* FIND node DID reglogin */
                                lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0901 FIND node DID reglogin"
+                                               "%d:0929 FIND node DID "
                                                " Data: x%p x%x x%x x%x\n",
                                                phba->brd_no,
                                                ndlp, ndlp->nlp_DID,
@@ -1795,86 +1738,12 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
                        }
                }
        }
-
-       if (order & NLP_SEARCH_PRLI) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
-                                       nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               /* LOG change to PRLI */
-                               /* FIND node DID prli */
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0902 FIND node DID prli "
-                                               "Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
-
-       if (order & NLP_SEARCH_NPR) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
-                                       nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               /* LOG change to NPR */
-                               /* FIND node DID npr */
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0903 FIND node DID npr "
-                                               "Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
-
-       if (order & NLP_SEARCH_UNUSED) {
-               list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
-                                       nlp_listp) {
-                       if (lpfc_matchdid(phba, ndlp, did)) {
-
-                               data1 = (((uint32_t) ndlp->nlp_state << 24) |
-                                        ((uint32_t) ndlp->nlp_xri << 16) |
-                                        ((uint32_t) ndlp->nlp_type << 8) |
-                                        ((uint32_t) ndlp->nlp_rpi & 0xff));
-                               /* LOG change to UNUSED */
-                               /* FIND node DID unused */
-                               lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-                                               "%d:0905 FIND node DID unused "
-                                               "Data: x%p x%x x%x x%x\n",
-                                               phba->brd_no,
-                                               ndlp, ndlp->nlp_DID,
-                                               ndlp->nlp_flag, data1);
-                               spin_unlock_irq(phba->host->host_lock);
-                               return ndlp;
-                       }
-               }
-       }
-
        spin_unlock_irq(phba->host->host_lock);
 
        /* FIND node did <did> NOT FOUND */
-       lpfc_printf_log(phba,
-                       KERN_INFO,
-                       LOG_NODE,
+       lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
                        "%d:0932 FIND node did x%x NOT FOUND Data: x%x\n",
                        phba->brd_no, did, order);
-
-       /* no match found */
        return NULL;
 }
 
@@ -2036,7 +1905,7 @@ lpfc_disc_start(struct lpfc_hba * phba)
                        if (rc == MBX_NOT_FINISHED) {
                                mempool_free( mbox, phba->mbox_mem_pool);
                                lpfc_disc_flush_list(phba);
-                               psli->ring[(psli->ip_ring)].flag &=
+                               psli->ring[(psli->extra_ring)].flag &=
                                        ~LPFC_STOP_IOCB_EVENT;
                                psli->ring[(psli->fcp_ring)].flag &=
                                        ~LPFC_STOP_IOCB_EVENT;
@@ -2415,7 +2284,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
 
        if (clrlaerr) {
                lpfc_disc_flush_list(phba);
-               psli->ring[(psli->ip_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
+               psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
                psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
                psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
                phba->hba_state = LPFC_HBA_READY;
index eedf98801366790ee7ff1e496754b00b8e593d5b..f79cb61369065007a88ca4dccb6e50c2bb1ec174 100644 (file)
 #define FCELSSIZE             1024     /* maximum ELS transfer size */
 
 #define LPFC_FCP_RING            0     /* ring 0 for FCP initiator commands */
-#define LPFC_IP_RING             1     /* ring 1 for IP commands */
+#define LPFC_EXTRA_RING          1     /* ring 1 for other protocols */
 #define LPFC_ELS_RING            2     /* ring 2 for ELS commands */
 #define LPFC_FCP_NEXT_RING       3
 
 #define SLI2_IOCB_CMD_R0_ENTRIES    172        /* SLI-2 FCP command ring entries */
 #define SLI2_IOCB_RSP_R0_ENTRIES    134        /* SLI-2 FCP response ring entries */
-#define SLI2_IOCB_CMD_R1_ENTRIES      4        /* SLI-2 IP command ring entries */
-#define SLI2_IOCB_RSP_R1_ENTRIES      4        /* SLI-2 IP response ring entries */
+#define SLI2_IOCB_CMD_R1_ENTRIES      4        /* SLI-2 extra command ring entries */
+#define SLI2_IOCB_RSP_R1_ENTRIES      4        /* SLI-2 extra response ring entries */
 #define SLI2_IOCB_CMD_R1XTRA_ENTRIES 36        /* SLI-2 extra FCP cmd ring entries */
 #define SLI2_IOCB_RSP_R1XTRA_ENTRIES 52        /* SLI-2 extra FCP rsp ring entries */
 #define SLI2_IOCB_CMD_R2_ENTRIES     20        /* SLI-2 ELS command ring entries */
@@ -121,6 +121,20 @@ struct lpfc_sli_ct_request {
 
                        uint32_t rsvd[7];
                } rft;
+               struct rff {
+                       uint32_t PortId;
+                       uint8_t reserved[2];
+#ifdef __BIG_ENDIAN_BITFIELD
+                       uint8_t feature_res:6;
+                       uint8_t feature_init:1;
+                       uint8_t feature_tgt:1;
+#else  /*  __LITTLE_ENDIAN_BITFIELD */
+                       uint8_t feature_tgt:1;
+                       uint8_t feature_init:1;
+                       uint8_t feature_res:6;
+#endif
+                       uint8_t type_code;     /* type=8 for FCP */
+               } rff;
                struct rnn {
                        uint32_t PortId;        /* For RNN_ID requests */
                        uint8_t wwnn[8];
@@ -136,6 +150,7 @@ struct lpfc_sli_ct_request {
 #define  SLI_CT_REVISION        1
 #define  GID_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 260)
 #define  RFT_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 228)
+#define  RFF_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 235)
 #define  RNN_REQUEST_SZ         (sizeof(struct lpfc_sli_ct_request) - 252)
 #define  RSNN_REQUEST_SZ        (sizeof(struct lpfc_sli_ct_request))
 
@@ -225,6 +240,7 @@ struct lpfc_sli_ct_request {
 #define  SLI_CTNS_RNN_ID      0x0213
 #define  SLI_CTNS_RCS_ID      0x0214
 #define  SLI_CTNS_RFT_ID      0x0217
+#define  SLI_CTNS_RFF_ID      0x021F
 #define  SLI_CTNS_RSPN_ID     0x0218
 #define  SLI_CTNS_RPT_ID      0x021A
 #define  SLI_CTNS_RIP_NN      0x0235
@@ -1089,12 +1105,6 @@ typedef struct {
 #define PCI_DEVICE_ID_ZEPHYR_SCSP   0xfe11
 #define PCI_DEVICE_ID_ZEPHYR_DCSP   0xfe12
 
-#define PCI_SUBSYSTEM_ID_LP11000S      0xfc11
-#define PCI_SUBSYSTEM_ID_LP11002S      0xfc12
-#define PCI_SUBSYSTEM_ID_LPE11000S     0xfc21
-#define PCI_SUBSYSTEM_ID_LPE11002S     0xfc22
-#define PCI_SUBSYSTEM_ID_LPE11010S     0xfc2A
-
 #define JEDEC_ID_ADDRESS            0x0080001c
 #define FIREFLY_JEDEC_ID            0x1ACC
 #define SUPERFLY_JEDEC_ID           0x0020
@@ -1284,6 +1294,10 @@ typedef struct {         /* FireFly BIU registers */
 #define CMD_FCP_IREAD_CX        0x1B
 #define CMD_FCP_ICMND_CR        0x1C
 #define CMD_FCP_ICMND_CX        0x1D
+#define CMD_FCP_TSEND_CX        0x1F
+#define CMD_FCP_TRECEIVE_CX     0x21
+#define CMD_FCP_TRSP_CX                0x23
+#define CMD_FCP_AUTO_TRSP_CX    0x29
 
 #define CMD_ADAPTER_MSG         0x20
 #define CMD_ADAPTER_DUMP        0x22
@@ -1310,6 +1324,9 @@ typedef struct {          /* FireFly BIU registers */
 #define CMD_FCP_IREAD64_CX      0x9B
 #define CMD_FCP_ICMND64_CR      0x9C
 #define CMD_FCP_ICMND64_CX      0x9D
+#define CMD_FCP_TSEND64_CX      0x9F
+#define CMD_FCP_TRECEIVE64_CX   0xA1
+#define CMD_FCP_TRSP64_CX       0xA3
 
 #define CMD_GEN_REQUEST64_CR    0xC2
 #define CMD_GEN_REQUEST64_CX    0xC3
index a5723ad0a0992c9026e759c7a5899cac4f51ea96..afca45cdbcefa0b29356ec8267697c8c029be4ef 100644 (file)
@@ -268,6 +268,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
        kfree(mp);
        pmb->context1 = NULL;
 
+       if (phba->cfg_soft_wwnn)
+               u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn);
        if (phba->cfg_soft_wwpn)
                u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
        memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName,
@@ -349,8 +351,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
        phba->hba_state = LPFC_LINK_DOWN;
 
        /* Only process IOCBs on ring 0 till hba_state is READY */
-       if (psli->ring[psli->ip_ring].cmdringaddr)
-               psli->ring[psli->ip_ring].flag |= LPFC_STOP_IOCB_EVENT;
+       if (psli->ring[psli->extra_ring].cmdringaddr)
+               psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT;
        if (psli->ring[psli->fcp_ring].cmdringaddr)
                psli->ring[psli->fcp_ring].flag |= LPFC_STOP_IOCB_EVENT;
        if (psli->ring[psli->next_ring].cmdringaddr)
@@ -517,7 +519,8 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
        struct lpfc_sli_ring  *pring;
        uint32_t event_data;
 
-       if (phba->work_hs & HS_FFER6) {
+       if (phba->work_hs & HS_FFER6 ||
+           phba->work_hs & HS_FFER5) {
                /* Re-establishing Link */
                lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
                                "%d:1301 Re-establishing Link "
@@ -611,7 +614,7 @@ lpfc_handle_latt(struct lpfc_hba * phba)
        pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
        rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
        if (rc == MBX_NOT_FINISHED)
-               goto lpfc_handle_latt_free_mp;
+               goto lpfc_handle_latt_free_mbuf;
 
        /* Clear Link Attention in HA REG */
        spin_lock_irq(phba->host->host_lock);
@@ -621,6 +624,8 @@ lpfc_handle_latt(struct lpfc_hba * phba)
 
        return;
 
+lpfc_handle_latt_free_mbuf:
+       lpfc_mbuf_free(phba, mp->virt, mp->phys);
 lpfc_handle_latt_free_mp:
        kfree(mp);
 lpfc_handle_latt_free_pmb:
@@ -802,19 +807,13 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
 {
        lpfc_vpd_t *vp;
        uint16_t dev_id = phba->pcidev->device;
-       uint16_t dev_subid = phba->pcidev->subsystem_device;
-       uint8_t hdrtype;
        int max_speed;
-       char * ports;
        struct {
                char * name;
                int    max_speed;
-               char * ports;
                char * bus;
-       } m = {"<Unknown>", 0, "", ""};
+       } m = {"<Unknown>", 0, ""};
 
-       pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
-       ports = (hdrtype == 0x80) ? "2-port " : "";
        if (mdp && mdp[0] != '\0'
                && descp && descp[0] != '\0')
                return;
@@ -834,130 +833,93 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
 
        switch (dev_id) {
        case PCI_DEVICE_ID_FIREFLY:
-               m = (typeof(m)){"LP6000", max_speed, "", "PCI"};
+               m = (typeof(m)){"LP6000", max_speed, "PCI"};
                break;
        case PCI_DEVICE_ID_SUPERFLY:
                if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3)
-                       m = (typeof(m)){"LP7000", max_speed, "", "PCI"};
+                       m = (typeof(m)){"LP7000", max_speed,  "PCI"};
                else
-                       m = (typeof(m)){"LP7000E", max_speed, "", "PCI"};
+                       m = (typeof(m)){"LP7000E", max_speed, "PCI"};
                break;
        case PCI_DEVICE_ID_DRAGONFLY:
-               m = (typeof(m)){"LP8000", max_speed, "", "PCI"};
+               m = (typeof(m)){"LP8000", max_speed, "PCI"};
                break;
        case PCI_DEVICE_ID_CENTAUR:
                if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID)
-                       m = (typeof(m)){"LP9002", max_speed, "", "PCI"};
+                       m = (typeof(m)){"LP9002", max_speed, "PCI"};
                else
-                       m = (typeof(m)){"LP9000", max_speed, "", "PCI"};
+                       m = (typeof(m)){"LP9000", max_speed, "PCI"};
                break;
        case PCI_DEVICE_ID_RFLY:
-               m = (typeof(m)){"LP952", max_speed, "", "PCI"};
+               m = (typeof(m)){"LP952", max_speed, "PCI"};
                break;
        case PCI_DEVICE_ID_PEGASUS:
-               m = (typeof(m)){"LP9802", max_speed, "", "PCI-X"};
+               m = (typeof(m)){"LP9802", max_speed, "PCI-X"};
                break;
        case PCI_DEVICE_ID_THOR:
-               if (hdrtype == 0x80)
-                       m = (typeof(m)){"LP10000DC",
-                                       max_speed, ports, "PCI-X"};
-               else
-                       m = (typeof(m)){"LP10000",
-                                       max_speed, ports, "PCI-X"};
+               m = (typeof(m)){"LP10000", max_speed, "PCI-X"};
                break;
        case PCI_DEVICE_ID_VIPER:
-               m = (typeof(m)){"LPX1000", max_speed, "", "PCI-X"};
+               m = (typeof(m)){"LPX1000", max_speed,  "PCI-X"};
                break;
        case PCI_DEVICE_ID_PFLY:
-               m = (typeof(m)){"LP982", max_speed, "", "PCI-X"};
+               m = (typeof(m)){"LP982", max_speed, "PCI-X"};
                break;
        case PCI_DEVICE_ID_TFLY:
-               if (hdrtype == 0x80)
-                       m = (typeof(m)){"LP1050DC", max_speed, ports, "PCI-X"};
-               else
-                       m = (typeof(m)){"LP1050", max_speed, ports, "PCI-X"};
+               m = (typeof(m)){"LP1050", max_speed, "PCI-X"};
                break;
        case PCI_DEVICE_ID_HELIOS:
-               if (hdrtype == 0x80)
-                       m = (typeof(m)){"LP11002", max_speed, ports, "PCI-X2"};
-               else
-                       m = (typeof(m)){"LP11000", max_speed, ports, "PCI-X2"};
+               m = (typeof(m)){"LP11000", max_speed, "PCI-X2"};
                break;
        case PCI_DEVICE_ID_HELIOS_SCSP:
-               m = (typeof(m)){"LP11000-SP", max_speed, ports, "PCI-X2"};
+               m = (typeof(m)){"LP11000-SP", max_speed, "PCI-X2"};
                break;
        case PCI_DEVICE_ID_HELIOS_DCSP:
-               m = (typeof(m)){"LP11002-SP", max_speed, ports, "PCI-X2"};
+               m = (typeof(m)){"LP11002-SP", max_speed, "PCI-X2"};
                break;
        case PCI_DEVICE_ID_NEPTUNE:
-               if (hdrtype == 0x80)
-                       m = (typeof(m)){"LPe1002", max_speed, ports, "PCIe"};
-               else
-                       m = (typeof(m)){"LPe1000", max_speed, ports, "PCIe"};
+               m = (typeof(m)){"LPe1000", max_speed, "PCIe"};
                break;
        case PCI_DEVICE_ID_NEPTUNE_SCSP:
-               m = (typeof(m)){"LPe1000-SP", max_speed, ports, "PCIe"};
+               m = (typeof(m)){"LPe1000-SP", max_speed, "PCIe"};
                break;
        case PCI_DEVICE_ID_NEPTUNE_DCSP:
-               m = (typeof(m)){"LPe1002-SP", max_speed, ports, "PCIe"};
+               m = (typeof(m)){"LPe1002-SP", max_speed, "PCIe"};
                break;
        case PCI_DEVICE_ID_BMID:
-               m = (typeof(m)){"LP1150", max_speed, ports, "PCI-X2"};
+               m = (typeof(m)){"LP1150", max_speed, "PCI-X2"};
                break;
        case PCI_DEVICE_ID_BSMB:
-               m = (typeof(m)){"LP111", max_speed, ports, "PCI-X2"};
+               m = (typeof(m)){"LP111", max_speed, "PCI-X2"};
                break;
        case PCI_DEVICE_ID_ZEPHYR:
-               if (hdrtype == 0x80)
-                       m = (typeof(m)){"LPe11002", max_speed, ports, "PCIe"};
-               else
-                       m = (typeof(m)){"LPe11000", max_speed, ports, "PCIe"};
+               m = (typeof(m)){"LPe11000", max_speed, "PCIe"};
                break;
        case PCI_DEVICE_ID_ZEPHYR_SCSP:
-               m = (typeof(m)){"LPe11000", max_speed, ports, "PCIe"};
+               m = (typeof(m)){"LPe11000", max_speed, "PCIe"};
                break;
        case PCI_DEVICE_ID_ZEPHYR_DCSP:
-               m = (typeof(m)){"LPe11002-SP", max_speed, ports, "PCIe"};
+               m = (typeof(m)){"LPe11002-SP", max_speed, "PCIe"};
                break;
        case PCI_DEVICE_ID_ZMID:
-               m = (typeof(m)){"LPe1150", max_speed, ports, "PCIe"};
+               m = (typeof(m)){"LPe1150", max_speed, "PCIe"};
                break;
        case PCI_DEVICE_ID_ZSMB:
-               m = (typeof(m)){"LPe111", max_speed, ports, "PCIe"};
+               m = (typeof(m)){"LPe111", max_speed, "PCIe"};
                break;
        case PCI_DEVICE_ID_LP101:
-               m = (typeof(m)){"LP101", max_speed, ports, "PCI-X"};
+               m = (typeof(m)){"LP101", max_speed, "PCI-X"};
                break;
        case PCI_DEVICE_ID_LP10000S:
-               m = (typeof(m)){"LP10000-S", max_speed, ports, "PCI"};
+               m = (typeof(m)){"LP10000-S", max_speed, "PCI"};
                break;
        case PCI_DEVICE_ID_LP11000S:
+               m = (typeof(m)){"LP11000-S", max_speed,
+                       "PCI-X2"};
+               break;
        case PCI_DEVICE_ID_LPE11000S:
-               switch (dev_subid) {
-               case PCI_SUBSYSTEM_ID_LP11000S:
-                       m = (typeof(m)){"LP11000-S", max_speed,
-                                       ports, "PCI-X2"};
-                       break;
-               case PCI_SUBSYSTEM_ID_LP11002S:
-                       m = (typeof(m)){"LP11002-S", max_speed,
-                                       ports, "PCI-X2"};
-                       break;
-               case PCI_SUBSYSTEM_ID_LPE11000S:
-                       m = (typeof(m)){"LPe11000-S", max_speed,
-                                       ports, "PCIe"};
-                       break;
-               case PCI_SUBSYSTEM_ID_LPE11002S:
-                       m = (typeof(m)){"LPe11002-S", max_speed,
-                                       ports, "PCIe"};
-                       break;
-               case PCI_SUBSYSTEM_ID_LPE11010S:
-                       m = (typeof(m)){"LPe11010-S", max_speed,
-                                       "10-port ", "PCIe"};
-                       break;
-               default:
-                       m = (typeof(m)){ NULL };
-                       break;
-               }
+               m = (typeof(m)){"LPe11000-S", max_speed,
+                       "PCIe"};
                break;
        default:
                m = (typeof(m)){ NULL };
@@ -968,8 +930,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
                snprintf(mdp, 79,"%s", m.name);
        if (descp && descp[0] == '\0')
                snprintf(descp, 255,
-                        "Emulex %s %dGb %s%s Fibre Channel Adapter",
-                        m.name, m.max_speed, m.ports, m.bus);
+                        "Emulex %s %dGb %s Fibre Channel Adapter",
+                        m.name, m.max_speed, m.bus);
 }
 
 /**************************************************/
@@ -1651,6 +1613,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        if (error)
                goto out_remove_host;
 
+       if (phba->cfg_use_msi) {
+               error = pci_enable_msi(phba->pcidev);
+               if (error)
+                       lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "%d:0452 "
+                                       "Enable MSI failed, continuing with "
+                                       "IRQ\n", phba->brd_no);
+       }
+
        error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
                                                        LPFC_DRIVER_NAME, phba);
        if (error) {
@@ -1730,6 +1700,7 @@ out_free_irq:
        lpfc_stop_timer(phba);
        phba->work_hba_events = 0;
        free_irq(phba->pcidev->irq, phba);
+       pci_disable_msi(phba->pcidev);
 out_free_sysfs_attr:
        lpfc_free_sysfs_attr(phba);
 out_remove_host:
@@ -1796,6 +1767,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 
        /* Release the irq reservation */
        free_irq(phba->pcidev->irq, phba);
+       pci_disable_msi(phba->pcidev);
 
        lpfc_cleanup(phba, 0);
        lpfc_stop_timer(phba);
index 62c8ca862e9ec2666decc907d26018a4f3dc83d8..438cbcd9eb136cf4a391ee49387ba3f8f38bea81 100644 (file)
@@ -28,7 +28,7 @@
 #define LOG_NODE                      0x80     /* Node table events */
 #define LOG_MISC                      0x400    /* Miscellaneous events */
 #define LOG_SLI                       0x800    /* SLI events */
-#define LOG_CHK_COND                  0x1000   /* FCP Check condition flag */
+#define LOG_FCP_ERROR                 0x1000   /* log errors, not underruns */
 #define LOG_LIBDFC                    0x2000   /* Libdfc events */
 #define LOG_ALL_MSG                   0xffff   /* LOG all messages */
 
index d5f415007db29dc8335983241bada27bdf2f656b..0c7e731dc45a6cdba715693d4c72ae0526920a7b 100644 (file)
@@ -739,7 +739,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
                            uint32_t evt)
 {
        struct lpfc_iocbq *cmdiocb, *rspiocb;
-       struct lpfc_dmabuf *pcmd, *prsp;
+       struct lpfc_dmabuf *pcmd, *prsp, *mp;
        uint32_t *lp;
        IOCB_t *irsp;
        struct serv_parm *sp;
@@ -829,6 +829,9 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
                                      NLP_REGLOGIN_LIST);
                        return ndlp->nlp_state;
                }
+               mp = (struct lpfc_dmabuf *)mbox->context1;
+               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+               kfree(mp);
                mempool_free(mbox, phba->mbox_mem_pool);
        } else {
                mempool_free(mbox, phba->mbox_mem_pool);
@@ -1620,8 +1623,8 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
         * or discovery in progress for this node. Starting discovery
         * here will affect the counting of discovery threads.
         */
-       if ((!(ndlp->nlp_flag & NLP_DELAY_TMO)) &&
-               (ndlp->nlp_flag & NLP_NPR_2B_DISC)){
+       if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+               !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
                if (ndlp->nlp_flag & NLP_NPR_ADISC) {
                        ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
                        ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
index 97ae98dc95d04f9d13d55a2da8bbc8c51447f564..c3e68e0d8f7445e426fa0ee28cc35ab5903c37cc 100644 (file)
@@ -297,8 +297,10 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
        uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm;
        uint32_t resp_info = fcprsp->rspStatus2;
        uint32_t scsi_status = fcprsp->rspStatus3;
+       uint32_t *lp;
        uint32_t host_status = DID_OK;
        uint32_t rsplen = 0;
+       uint32_t logit = LOG_FCP | LOG_FCP_ERROR;
 
        /*
         *  If this is a task management command, there is no
@@ -310,10 +312,25 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
                goto out;
        }
 
-       lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-                       "%d:0730 FCP command failed: RSP "
-                       "Data: x%x x%x x%x x%x x%x x%x\n",
-                       phba->brd_no, resp_info, scsi_status,
+       if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) {
+               uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen);
+               if (snslen > SCSI_SENSE_BUFFERSIZE)
+                       snslen = SCSI_SENSE_BUFFERSIZE;
+
+               if (resp_info & RSP_LEN_VALID)
+                 rsplen = be32_to_cpu(fcprsp->rspRspLen);
+               memcpy(cmnd->sense_buffer, &fcprsp->rspInfo0 + rsplen, snslen);
+       }
+       lp = (uint32_t *)cmnd->sense_buffer;
+
+       if (!scsi_status && (resp_info & RESID_UNDER))
+               logit = LOG_FCP;
+
+       lpfc_printf_log(phba, KERN_WARNING, logit,
+                       "%d:0730 FCP command x%x failed: x%x SNS x%x x%x "
+                       "Data: x%x x%x x%x x%x x%x\n",
+                       phba->brd_no, cmnd->cmnd[0], scsi_status,
+                       be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
                        be32_to_cpu(fcprsp->rspResId),
                        be32_to_cpu(fcprsp->rspSnsLen),
                        be32_to_cpu(fcprsp->rspRspLen),
@@ -328,14 +345,6 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
                }
        }
 
-       if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) {
-               uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen);
-               if (snslen > SCSI_SENSE_BUFFERSIZE)
-                       snslen = SCSI_SENSE_BUFFERSIZE;
-
-               memcpy(cmnd->sense_buffer, &fcprsp->rspInfo0 + rsplen, snslen);
-       }
-
        cmnd->resid = 0;
        if (resp_info & RESID_UNDER) {
                cmnd->resid = be32_to_cpu(fcprsp->rspResId);
@@ -378,7 +387,7 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
         */
        } else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
                        (cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
-               lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
+               lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
                        "%d:0734 FCP Read Check Error Data: "
                        "x%x x%x x%x x%x\n", phba->brd_no,
                        be32_to_cpu(fcpcmd->fcpDl),
@@ -670,6 +679,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
        struct lpfc_iocbq *iocbqrsp;
        int ret;
 
+       if (!rdata->pnode)
+               return FAILED;
+
        lpfc_cmd->rdata = rdata;
        ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun,
                                           FCP_TARGET_RESET);
@@ -976,20 +988,34 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
 
        lpfc_block_error_handler(cmnd);
        spin_lock_irq(shost->host_lock);
+       loopcnt = 0;
        /*
         * If target is not in a MAPPED state, delay the reset until
         * target is rediscovered or devloss timeout expires.
         */
        while ( 1 ) {
                if (!pnode)
-                       break;
+                       return FAILED;
 
                if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
                        spin_unlock_irq(phba->host->host_lock);
                        schedule_timeout_uninterruptible(msecs_to_jiffies(500));
                        spin_lock_irq(phba->host->host_lock);
+                       loopcnt++;
+                       rdata = cmnd->device->hostdata;
+                       if (!rdata ||
+                               (loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) {
+                               lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+                                       "%d:0721 LUN Reset rport failure:"
+                                       " cnt x%x rdata x%p\n",
+                                       phba->brd_no, loopcnt, rdata);
+                               goto out;
+                       }
+                       pnode = rdata->pnode;
+                       if (!pnode)
+                               return FAILED;
                }
-               if ((pnode) && (pnode->nlp_state == NLP_STE_MAPPED_NODE))
+               if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
                        break;
        }
 
index 582f5ea4e84e3c7b9f00c59ae58f5fab2af41925..a4128e19338af4e74e843cfcc1588c74eadde0fe 100644 (file)
@@ -117,6 +117,10 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        case CMD_FCP_IREAD_CX:
        case CMD_FCP_ICMND_CR:
        case CMD_FCP_ICMND_CX:
+       case CMD_FCP_TSEND_CX:
+       case CMD_FCP_TRSP_CX:
+       case CMD_FCP_TRECEIVE_CX:
+       case CMD_FCP_AUTO_TRSP_CX:
        case CMD_ADAPTER_MSG:
        case CMD_ADAPTER_DUMP:
        case CMD_XMIT_SEQUENCE64_CR:
@@ -131,6 +135,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
        case CMD_FCP_IREAD64_CX:
        case CMD_FCP_ICMND64_CR:
        case CMD_FCP_ICMND64_CX:
+       case CMD_FCP_TSEND64_CX:
+       case CMD_FCP_TRSP64_CX:
+       case CMD_FCP_TRECEIVE64_CX:
        case CMD_GEN_REQUEST64_CR:
        case CMD_GEN_REQUEST64_CX:
        case CMD_XMIT_ELS_RSP64_CX:
@@ -1098,6 +1105,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
                lpfc_sli_pcimem_bcopy((uint32_t *) entry,
                                      (uint32_t *) &rspiocbq.iocb,
                                      sizeof (IOCB_t));
+               INIT_LIST_HEAD(&(rspiocbq.list));
                irsp = &rspiocbq.iocb;
 
                type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK);
@@ -1149,6 +1157,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
                                }
                        }
                        break;
+               case LPFC_UNSOL_IOCB:
+                       spin_unlock_irqrestore(phba->host->host_lock, iflag);
+                       lpfc_sli_process_unsol_iocb(phba, pring, &rspiocbq);
+                       spin_lock_irqsave(phba->host->host_lock, iflag);
+                       break;
                default:
                        if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
                                char adaptermsg[LPFC_MAX_ADPTMSG];
@@ -2472,13 +2485,17 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
        psli = &phba->sli;
 
        /* Adjust cmd/rsp ring iocb entries more evenly */
+
+       /* Take some away from the FCP ring */
        pring = &psli->ring[psli->fcp_ring];
        pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES;
        pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES;
        pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES;
        pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES;
 
-       pring = &psli->ring[1];
+       /* and give them to the extra ring */
+       pring = &psli->ring[psli->extra_ring];
+
        pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES;
        pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
        pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
@@ -2488,8 +2505,8 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
        pring->iotag_max = 4096;
        pring->num_mask = 1;
        pring->prt[0].profile = 0;      /* Mask 0 */
-       pring->prt[0].rctl = FC_UNSOL_DATA;
-       pring->prt[0].type = 5;
+       pring->prt[0].rctl = phba->cfg_multi_ring_rctl;
+       pring->prt[0].type = phba->cfg_multi_ring_type;
        pring->prt[0].lpfc_sli_rcv_unsol_event = NULL;
        return 0;
 }
@@ -2505,7 +2522,7 @@ lpfc_sli_setup(struct lpfc_hba *phba)
        psli->sli_flag = 0;
        psli->fcp_ring = LPFC_FCP_RING;
        psli->next_ring = LPFC_FCP_NEXT_RING;
-       psli->ip_ring = LPFC_IP_RING;
+       psli->extra_ring = LPFC_EXTRA_RING;
 
        psli->iocbq_lookup = NULL;
        psli->iocbq_lookup_len = 0;
@@ -2528,7 +2545,7 @@ lpfc_sli_setup(struct lpfc_hba *phba)
                        pring->fast_iotag = pring->iotag_max;
                        pring->num_mask = 0;
                        break;
-               case LPFC_IP_RING:      /* ring 1 - IP */
+               case LPFC_EXTRA_RING:   /* ring 1 - EXTRA */
                        /* numCiocb and numRiocb are used in config_port */
                        pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES;
                        pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES;
@@ -3238,6 +3255,21 @@ lpfc_intr_handler(int irq, void *dev_id)
                lpfc_sli_handle_fast_ring_event(phba,
                                                &phba->sli.ring[LPFC_FCP_RING],
                                                status);
+
+       if (phba->cfg_multi_ring_support == 2) {
+               /*
+                * Process all events on extra ring.  Take the optimized path
+                * for extra ring IO.  Any other IO is slow path and is handled
+                * by the worker thread.
+                */
+               status = (ha_copy & (HA_RXMASK  << (4*LPFC_EXTRA_RING)));
+               status >>= (4*LPFC_EXTRA_RING);
+               if (status & HA_RXATT) {
+                       lpfc_sli_handle_fast_ring_event(phba,
+                                       &phba->sli.ring[LPFC_EXTRA_RING],
+                                       status);
+               }
+       }
        return IRQ_HANDLED;
 
 } /* lpfc_intr_handler */
index e26de6809358a8529b5df6b2a3e88611be709cbd..a43549959dc7bb45bd9ebabcd8121afdcf201a00 100644 (file)
@@ -198,7 +198,7 @@ struct lpfc_sli {
        int fcp_ring;           /* ring used for FCP initiator commands */
        int next_ring;
 
-       int ip_ring;            /* ring used for IP network drv cmds */
+       int extra_ring;         /* extra ring used for other protocols */
 
        struct lpfc_sli_stat slistat;   /* SLI statistical info */
        struct list_head mboxq;
index ac417908b4071378c2b1d8497d2e2be88c34447b..a61ef3d1e7f1b08090403de95e4547246c65420f 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.1.10"
+#define LPFC_DRIVER_VERSION "8.1.11"
 
 #define LPFC_DRIVER_NAME "lpfc"
 
index 86099fde1b2a6bc13866835757861e74d1b41d07..77d9d3804ccfd02094a4aba9054081c233ed8427 100644 (file)
@@ -73,10 +73,10 @@ static unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT;
 module_param(max_mbox_busy_wait, ushort, 0);
 MODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)");
 
-#define RDINDOOR(adapter)              readl((adapter)->base + 0x20)
-#define RDOUTDOOR(adapter)             readl((adapter)->base + 0x2C)
-#define WRINDOOR(adapter,value)                writel(value, (adapter)->base + 0x20)
-#define WROUTDOOR(adapter,value)       writel(value, (adapter)->base + 0x2C)
+#define RDINDOOR(adapter)      readl((adapter)->mmio_base + 0x20)
+#define RDOUTDOOR(adapter)     readl((adapter)->mmio_base + 0x2C)
+#define WRINDOOR(adapter,value)         writel(value, (adapter)->mmio_base + 0x20)
+#define WROUTDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x2C)
 
 /*
  * Global variables
@@ -1386,7 +1386,8 @@ megaraid_isr_memmapped(int irq, void *devp)
 
                handled = 1;
 
-               while( RDINDOOR(adapter) & 0x02 ) cpu_relax();
+               while( RDINDOOR(adapter) & 0x02 )
+                       cpu_relax();
 
                mega_cmd_done(adapter, completed, nstatus, status);
 
@@ -4668,6 +4669,8 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                host->host_no, mega_baseport, irq);
 
        adapter->base = mega_baseport;
+       if (flag & BOARD_MEMMAP)
+               adapter->mmio_base = (void __iomem *) mega_baseport;
 
        INIT_LIST_HEAD(&adapter->free_list);
        INIT_LIST_HEAD(&adapter->pending_list);
index 66529f11d23cca784e73c0cf1738d62c0f43e4c2..c6e74643abe29be7f7d52ad29b7fd8634c548c4d 100644 (file)
@@ -801,7 +801,8 @@ typedef struct {
                                   clustering is available */
        u32     flag;
 
-       unsigned long   base;
+       unsigned long           base;
+       void __iomem            *mmio_base;
 
        /* mbox64 with mbox not aligned on 16-byte boundry */
        mbox64_t        *una_mbox64;
index 7e4262f2af96dd000940ae1000a1d6319f826ef8..046223b4ae5747255082cc1747a3afaa5a02afc1 100644 (file)
@@ -517,7 +517,7 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
  * Returns the number of frames required for numnber of sge's (sge_count)
  */
 
-u32 megasas_get_frame_count(u8 sge_count)
+static u32 megasas_get_frame_count(u8 sge_count)
 {
        int num_cnt;
        int sge_bytes;
@@ -1733,7 +1733,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
  *
  * Tasklet to complete cmds
  */
-void megasas_complete_cmd_dpc(unsigned long instance_addr)
+static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 {
        u32 producer;
        u32 consumer;
index adb8eb4f5fd1a566a484f63dcf2bcf1a9ed8cfd0..bbf521cbc55d135747965d5390d17d70c312343b 100644 (file)
@@ -589,10 +589,12 @@ static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd)
 static struct ncr_driver_setup
        driver_setup                    = SCSI_NCR_DRIVER_SETUP;
 
+#ifndef MODULE
 #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 static struct ncr_driver_setup
        driver_safe_setup __initdata    = SCSI_NCR_DRIVER_SAFE_SETUP;
 #endif
+#endif /* !MODULE */
 
 #define initverbose (driver_setup.verbose)
 #define bootverbose (np->verbose)
@@ -641,6 +643,13 @@ static struct ncr_driver_setup
 #define OPT_IARB               26
 #endif
 
+#ifdef MODULE
+#define        ARG_SEP ' '
+#else
+#define        ARG_SEP ','
+#endif
+
+#ifndef MODULE
 static char setup_token[] __initdata = 
        "tags:"   "mpar:"
        "spar:"   "disc:"
@@ -660,12 +669,6 @@ static char setup_token[] __initdata =
 #endif
        ;       /* DONNOT REMOVE THIS ';' */
 
-#ifdef MODULE
-#define        ARG_SEP ' '
-#else
-#define        ARG_SEP ','
-#endif
-
 static int __init get_setup_token(char *p)
 {
        char *cur = setup_token;
@@ -682,7 +685,6 @@ static int __init get_setup_token(char *p)
        return 0;
 }
 
-
 static int __init sym53c8xx__setup(char *str)
 {
 #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
@@ -804,6 +806,7 @@ static int __init sym53c8xx__setup(char *str)
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
        return 1;
 }
+#endif /* !MODULE */
 
 /*===================================================================
 **
@@ -8321,12 +8324,12 @@ char *ncr53c8xx;        /* command line passed by insmod */
 module_param(ncr53c8xx, charp, 0);
 #endif
 
+#ifndef MODULE
 static int __init ncr53c8xx_setup(char *str)
 {
        return sym53c8xx__setup(str);
 }
 
-#ifndef MODULE
 __setup("ncr53c8xx=", ncr53c8xx_setup);
 #endif
 
index 285c8e8ff1a09658ddeb65c07348899da9aa316f..7b18a6c7b7eb0de125e2cd7bfb2581c786378de5 100644 (file)
@@ -390,7 +390,7 @@ static struct sysfs_entry {
        { "optrom_ctl", &sysfs_optrom_ctl_attr, },
        { "vpd", &sysfs_vpd_attr, 1 },
        { "sfp", &sysfs_sfp_attr, 1 },
-       { 0 },
+       { NULL },
 };
 
 void
index 08cb5e3fb55319d7eba7965f5863872aac1193f1..a823f0bc519dbf8e7c921d2fb3924a94f1aebab8 100644 (file)
@@ -59,9 +59,6 @@ int
 qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 {
        int     rval;
-       uint8_t restart_risc = 0;
-       uint8_t retry;
-       uint32_t wait_time;
 
        /* Clear adapter flags. */
        ha->flags.online = 0;
@@ -104,87 +101,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
 
        qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
 
-       retry = 10;
-       /*
-        * Try to configure the loop.
-        */
-       do {
-               restart_risc = 0;
-
-               /* If firmware needs to be loaded */
-               if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
-                       if ((rval = ha->isp_ops.chip_diag(ha)) == QLA_SUCCESS) {
-                               rval = qla2x00_setup_chip(ha);
-                       }
-               }
-
-               if (rval == QLA_SUCCESS &&
-                   (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) {
-check_fw_ready_again:
-                       /*
-                        * Wait for a successful LIP up to a maximum
-                        * of (in seconds): RISC login timeout value,
-                        * RISC retry count value, and port down retry
-                        * value OR a minimum of 4 seconds OR If no
-                        * cable, only 5 seconds.
-                        */
-                       rval = qla2x00_fw_ready(ha);
-                       if (rval == QLA_SUCCESS) {
-                               clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-
-                               /* Issue a marker after FW becomes ready. */
-                               qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-
-                               /*
-                                * Wait at most MAX_TARGET RSCNs for a stable
-                                * link.
-                                */
-                               wait_time = 256;
-                               do {
-                                       clear_bit(LOOP_RESYNC_NEEDED,
-                                           &ha->dpc_flags);
-                                       rval = qla2x00_configure_loop(ha);
-
-                                       if (test_and_clear_bit(ISP_ABORT_NEEDED,
-                                           &ha->dpc_flags)) {
-                                               restart_risc = 1;
-                                               break;
-                                       }
-
-                                       /*
-                                        * If loop state change while we were
-                                        * discoverying devices then wait for
-                                        * LIP to complete
-                                        */
-
-                                       if (atomic_read(&ha->loop_state) !=
-                                           LOOP_READY && retry--) {
-                                               goto check_fw_ready_again;
-                                       }
-                                       wait_time--;
-                               } while (!atomic_read(&ha->loop_down_timer) &&
-                                   retry &&
-                                   wait_time &&
-                                   (test_bit(LOOP_RESYNC_NEEDED,
-                                       &ha->dpc_flags)));
-
-                               if (wait_time == 0)
-                                       rval = QLA_FUNCTION_FAILED;
-                       } else if (ha->device_flags & DFLG_NO_CABLE)
-                               /* If no cable, then all is good. */
-                               rval = QLA_SUCCESS;
-               }
-       } while (restart_risc && retry--);
-
-       if (rval == QLA_SUCCESS) {
-               clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-               qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
-               ha->marker_needed = 0;
-
-               ha->flags.online = 1;
-       } else {
-               DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+       if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
+               rval = ha->isp_ops.chip_diag(ha);
+               if (rval)
+                       return (rval);
+               rval = qla2x00_setup_chip(ha);
+               if (rval)
+                       return (rval);
        }
+       rval = qla2x00_init_rings(ha);
 
        return (rval);
 }
@@ -2208,8 +2133,7 @@ qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
 
        atomic_set(&fcport->state, FCS_ONLINE);
 
-       if (ha->flags.init_done)
-               qla2x00_reg_remote_port(ha, fcport);
+       qla2x00_reg_remote_port(ha, fcport);
 }
 
 void
index 208607be78c7267a5770974b8d4be12d4b839b87..cbe0cad83b685c67d245049188519c83cefdf718 100644 (file)
@@ -95,6 +95,8 @@ MODULE_PARM_DESC(ql2xqfullrampup,
  */
 static int qla2xxx_slave_configure(struct scsi_device * device);
 static int qla2xxx_slave_alloc(struct scsi_device *);
+static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
+static void qla2xxx_scan_start(struct Scsi_Host *);
 static void qla2xxx_slave_destroy(struct scsi_device *);
 static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
                void (*fn)(struct scsi_cmnd *));
@@ -124,6 +126,8 @@ static struct scsi_host_template qla2x00_driver_template = {
 
        .slave_alloc            = qla2xxx_slave_alloc,
        .slave_destroy          = qla2xxx_slave_destroy,
+       .scan_finished          = qla2xxx_scan_finished,
+       .scan_start             = qla2xxx_scan_start,
        .change_queue_depth     = qla2x00_change_queue_depth,
        .change_queue_type      = qla2x00_change_queue_type,
        .this_id                = -1,
@@ -287,7 +291,7 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str)
        return str;
 }
 
-char *
+static char *
 qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str)
 {
        char un_str[10];
@@ -325,7 +329,7 @@ qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str)
        return (str);
 }
 
-char *
+static char *
 qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
 {
        sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
@@ -634,7 +638,7 @@ qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
 * Note:
 *    Only return FAILED if command not returned by firmware.
 **************************************************************************/
-int
+static int
 qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
@@ -771,7 +775,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
 *    SUCCESS/FAILURE (defined as macro in scsi.h).
 *
 **************************************************************************/
-int
+static int
 qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
@@ -902,7 +906,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
 *    SUCCESS/FAILURE (defined as macro in scsi.h).
 *
 **************************************************************************/
-int
+static int
 qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
@@ -963,7 +967,7 @@ eh_bus_reset_done:
 *
 * Note:
 **************************************************************************/
-int
+static int
 qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
        scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
@@ -1366,6 +1370,29 @@ qla24xx_disable_intrs(scsi_qla_host_t *ha)
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+static void
+qla2xxx_scan_start(struct Scsi_Host *shost)
+{
+       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+       set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+       set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+       set_bit(RSCN_UPDATE, &ha->dpc_flags);
+}
+
+static int
+qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+       scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+
+       if (!ha->host)
+               return 1;
+       if (time > ha->loop_reset_delay * HZ)
+               return 1;
+
+       return atomic_read(&ha->loop_state) == LOOP_READY;
+}
+
 /*
  * PCI driver interface
  */
@@ -1377,10 +1404,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        struct Scsi_Host *host;
        scsi_qla_host_t *ha;
        unsigned long   flags = 0;
-       unsigned long   wait_switch = 0;
        char pci_info[20];
        char fw_str[30];
-       fc_port_t *fcport;
        struct scsi_host_template *sht;
 
        if (pci_enable_device(pdev))
@@ -1631,30 +1656,19 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ha->isp_ops.enable_intrs(ha);
 
-       /* v2.19.5b6 */
-       /*
-        * Wait around max loop_reset_delay secs for the devices to come
-        * on-line. We don't want Linux scanning before we are ready.
-        *
-        */
-       for (wait_switch = jiffies + (ha->loop_reset_delay * HZ);
-           time_before(jiffies,wait_switch) &&
-            !(ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES))
-            && (ha->device_flags & SWITCH_FOUND) ;) {
-
-               qla2x00_check_fabric_devices(ha);
-
-               msleep(10);
-       }
-
        pci_set_drvdata(pdev, ha);
+
        ha->flags.init_done = 1;
+       ha->flags.online = 1;
+
        num_hosts++;
 
        ret = scsi_add_host(host, &pdev->dev);
        if (ret)
                goto probe_failed;
 
+       scsi_scan_host(host);
+
        qla2x00_alloc_sysfs_attr(ha);
 
        qla2x00_init_host_attr(ha);
@@ -1669,10 +1683,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
            ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
            ha->isp_ops.fw_version_str(ha, fw_str));
 
-       /* Go with fc_rport registration. */
-       list_for_each_entry(fcport, &ha->fcports, list)
-               qla2x00_reg_remote_port(ha, fcport);
-
        return 0;
 
 probe_failed:
index c71dbd5bd5433e78cf8bc4fe2746253f89f4520a..15390ad87456399a774ac65e25a5f519216adf15 100644 (file)
@@ -449,7 +449,7 @@ nvram_data_to_access_addr(uint32_t naddr)
        return FARX_ACCESS_NVRAM_DATA | naddr;
 }
 
-uint32_t
+static uint32_t
 qla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr)
 {
        int rval;
@@ -490,7 +490,7 @@ qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
        return dwptr;
 }
 
-int
+static int
 qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data)
 {
        int rval;
@@ -512,7 +512,7 @@ qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data)
        return rval;
 }
 
-void
+static void
 qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
     uint8_t *flash_id)
 {
@@ -537,7 +537,7 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
        }
 }
 
-int
+static int
 qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
     uint32_t dwords)
 {
index 752031fadfef56c2ee5f0617af4ab07d30750df2..7b4e077a39c18c770bbd42a80c7696ea83066e8e 100644 (file)
@@ -71,7 +71,7 @@ void __dump_registers(struct scsi_qla_host *ha)
                       readw(&ha->reg->u1.isp4010.nvram));
        }
 
-       else if (is_qla4022(ha)) {
+       else if (is_qla4022(ha) | is_qla4032(ha)) {
                printk(KERN_INFO "0x%02X intr_mask       = 0x%08X\n",
                       (uint8_t) offsetof(struct isp_reg,
                                          u1.isp4022.intr_mask),
@@ -119,7 +119,7 @@ void __dump_registers(struct scsi_qla_host *ha)
                       readw(&ha->reg->u2.isp4010.port_err_status));
        }
 
-       else if (is_qla4022(ha)) {
+       else if (is_qla4022(ha) | is_qla4032(ha)) {
                printk(KERN_INFO "Page 0 Registers:\n");
                printk(KERN_INFO "0x%02X ext_hw_conf     = 0x%08X\n",
                       (uint8_t) offsetof(struct isp_reg,
index a7f6c7b1c59004835e953b6fbbee4f2034025af3..4249e52a559290a7713dc22af921933ef7b4d5f3 100644 (file)
 
 #ifndef PCI_DEVICE_ID_QLOGIC_ISP4022
 #define PCI_DEVICE_ID_QLOGIC_ISP4022   0x4022
-#endif                         /*  */
+#endif
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP4032
+#define PCI_DEVICE_ID_QLOGIC_ISP4032   0x4032
+#endif
 
 #define QLA_SUCCESS                    0
 #define QLA_ERROR                      1
@@ -277,7 +281,6 @@ struct scsi_qla_host {
 #define AF_INTERRUPTS_ON             6 /* 0x00000040 Not Used */
 #define AF_GET_CRASH_RECORD          7 /* 0x00000080 */
 #define AF_LINK_UP                   8 /* 0x00000100 */
-#define AF_TOPCAT_CHIP_PRESENT       9 /* 0x00000200 */
 #define AF_IRQ_ATTACHED                     10 /* 0x00000400 */
 #define AF_ISNS_CMD_IN_PROCESS      12 /* 0x00001000 */
 #define AF_ISNS_CMD_DONE            13 /* 0x00002000 */
@@ -317,16 +320,17 @@ struct scsi_qla_host {
        /* NVRAM registers */
        struct eeprom_data *nvram;
        spinlock_t hardware_lock ____cacheline_aligned;
-       spinlock_t list_lock;
        uint32_t   eeprom_cmd_data;
 
        /* Counters for general statistics */
+       uint64_t isr_count;
        uint64_t adapter_error_count;
        uint64_t device_error_count;
        uint64_t total_io_count;
        uint64_t total_mbytes_xferred;
        uint64_t link_failure_count;
        uint64_t invalid_crc_count;
+       uint32_t bytes_xfered;
        uint32_t spurious_int_count;
        uint32_t aborted_io_count;
        uint32_t io_timeout_count;
@@ -438,6 +442,11 @@ static inline int is_qla4022(struct scsi_qla_host *ha)
        return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022;
 }
 
+static inline int is_qla4032(struct scsi_qla_host *ha)
+{
+       return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032;
+}
+
 static inline int adapter_up(struct scsi_qla_host *ha)
 {
        return (test_bit(AF_ONLINE, &ha->flags) != 0) &&
@@ -451,58 +460,58 @@ static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost)
 
 static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha)
 {
-       return (is_qla4022(ha) ?
-               &ha->reg->u1.isp4022.semaphore :
-               &ha->reg->u1.isp4010.nvram);
+       return (is_qla4010(ha) ?
+               &ha->reg->u1.isp4010.nvram :
+               &ha->reg->u1.isp4022.semaphore);
 }
 
 static inline void __iomem* isp_nvram(struct scsi_qla_host *ha)
 {
-       return (is_qla4022(ha) ?
-               &ha->reg->u1.isp4022.nvram :
-               &ha->reg->u1.isp4010.nvram);
+       return (is_qla4010(ha) ?
+               &ha->reg->u1.isp4010.nvram :
+               &ha->reg->u1.isp4022.nvram);
 }
 
 static inline void __iomem* isp_ext_hw_conf(struct scsi_qla_host *ha)
 {
-       return (is_qla4022(ha) ?
-               &ha->reg->u2.isp4022.p0.ext_hw_conf :
-               &ha->reg->u2.isp4010.ext_hw_conf);
+       return (is_qla4010(ha) ?
+               &ha->reg->u2.isp4010.ext_hw_conf :
+               &ha->reg->u2.isp4022.p0.ext_hw_conf);
 }
 
 static inline void __iomem* isp_port_status(struct scsi_qla_host *ha)
 {
-       return (is_qla4022(ha) ?
-               &ha->reg->u2.isp4022.p0.port_status :
-               &ha->reg->u2.isp4010.port_status);
+       return (is_qla4010(ha) ?
+               &ha->reg->u2.isp4010.port_status :
+               &ha->reg->u2.isp4022.p0.port_status);
 }
 
 static inline void __iomem* isp_port_ctrl(struct scsi_qla_host *ha)
 {
-       return (is_qla4022(ha) ?
-               &ha->reg->u2.isp4022.p0.port_ctrl :
-               &ha->reg->u2.isp4010.port_ctrl);
+       return (is_qla4010(ha) ?
+               &ha->reg->u2.isp4010.port_ctrl :
+               &ha->reg->u2.isp4022.p0.port_ctrl);
 }
 
 static inline void __iomem* isp_port_error_status(struct scsi_qla_host *ha)
 {
-       return (is_qla4022(ha) ?
-               &ha->reg->u2.isp4022.p0.port_err_status :
-               &ha->reg->u2.isp4010.port_err_status);
+       return (is_qla4010(ha) ?
+               &ha->reg->u2.isp4010.port_err_status :
+               &ha->reg->u2.isp4022.p0.port_err_status);
 }
 
 static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha)
 {
-       return (is_qla4022(ha) ?
-               &ha->reg->u2.isp4022.p0.gp_out :
-               &ha->reg->u2.isp4010.gp_out);
+       return (is_qla4010(ha) ?
+               &ha->reg->u2.isp4010.gp_out :
+               &ha->reg->u2.isp4022.p0.gp_out);
 }
 
 static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha)
 {
-       return (is_qla4022(ha) ?
-               offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2 :
-               offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2);
+       return (is_qla4010(ha) ?
+               offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2 :
+               offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2);
 }
 
 int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
@@ -511,59 +520,59 @@ int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
 
 static inline int ql4xxx_lock_flash(struct scsi_qla_host *a)
 {
-       if (is_qla4022(a))
+       if (is_qla4010(a))
+               return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK,
+                                          QL4010_FLASH_SEM_BITS);
+       else
                return ql4xxx_sem_spinlock(a, QL4022_FLASH_SEM_MASK,
                                           (QL4022_RESOURCE_BITS_BASE_CODE |
                                            (a->mac_index)) << 13);
-       else
-               return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK,
-                                          QL4010_FLASH_SEM_BITS);
 }
 
 static inline void ql4xxx_unlock_flash(struct scsi_qla_host *a)
 {
-       if (is_qla4022(a))
-               ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK);
-       else
+       if (is_qla4010(a))
                ql4xxx_sem_unlock(a, QL4010_FLASH_SEM_MASK);
+       else
+               ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK);
 }
 
 static inline int ql4xxx_lock_nvram(struct scsi_qla_host *a)
 {
-       if (is_qla4022(a))
+       if (is_qla4010(a))
+               return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK,
+                                          QL4010_NVRAM_SEM_BITS);
+       else
                return ql4xxx_sem_spinlock(a, QL4022_NVRAM_SEM_MASK,
                                           (QL4022_RESOURCE_BITS_BASE_CODE |
                                            (a->mac_index)) << 10);
-       else
-               return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK,
-                                          QL4010_NVRAM_SEM_BITS);
 }
 
 static inline void ql4xxx_unlock_nvram(struct scsi_qla_host *a)
 {
-       if (is_qla4022(a))
-               ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK);
-       else
+       if (is_qla4010(a))
                ql4xxx_sem_unlock(a, QL4010_NVRAM_SEM_MASK);
+       else
+               ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK);
 }
 
 static inline int ql4xxx_lock_drvr(struct scsi_qla_host *a)
 {
-       if (is_qla4022(a))
+       if (is_qla4010(a))
+               return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK,
+                                      QL4010_DRVR_SEM_BITS);
+       else
                return ql4xxx_sem_lock(a, QL4022_DRVR_SEM_MASK,
                                       (QL4022_RESOURCE_BITS_BASE_CODE |
                                        (a->mac_index)) << 1);
-       else
-               return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK,
-                                      QL4010_DRVR_SEM_BITS);
 }
 
 static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a)
 {
-       if (is_qla4022(a))
-               ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK);
-       else
+       if (is_qla4010(a))
                ql4xxx_sem_unlock(a, QL4010_DRVR_SEM_MASK);
+       else
+               ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK);
 }
 
 /*---------------------------------------------------------------------------*/
index 427489de64bcdcb6c05929f0781e1a26b13a8ac4..4eea8c571916f49293c7fb1205c5ac4137acf03b 100644 (file)
@@ -296,7 +296,6 @@ static inline uint32_t clr_rmask(uint32_t val)
 /*  ISP Semaphore definitions */
 
 /*  ISP General Purpose Output definitions */
-#define GPOR_TOPCAT_RESET                      0x00000004
 
 /*  shadow registers (DMA'd from HA to system memory.  read only) */
 struct shadow_regs {
@@ -339,10 +338,13 @@ union external_hw_config_reg {
 /*  Mailbox command definitions */
 #define MBOX_CMD_ABOUT_FW                      0x0009
 #define MBOX_CMD_LUN_RESET                     0x0016
+#define MBOX_CMD_GET_MANAGEMENT_DATA           0x001E
 #define MBOX_CMD_GET_FW_STATUS                 0x001F
 #define MBOX_CMD_SET_ISNS_SERVICE              0x0021
 #define ISNS_DISABLE                           0
 #define ISNS_ENABLE                            1
+#define MBOX_CMD_COPY_FLASH                    0x0024
+#define MBOX_CMD_WRITE_FLASH                   0x0025
 #define MBOX_CMD_READ_FLASH                    0x0026
 #define MBOX_CMD_CLEAR_DATABASE_ENTRY          0x0031
 #define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT                0x0056
@@ -360,10 +362,13 @@ union external_hw_config_reg {
 #define DDB_DS_SESSION_FAILED                  0x06
 #define DDB_DS_LOGIN_IN_PROCESS                        0x07
 #define MBOX_CMD_GET_FW_STATE                  0x0069
+#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A
+#define MBOX_CMD_RESTORE_FACTORY_DEFAULTS      0x0087
 
 /* Mailbox 1 */
 #define FW_STATE_READY                         0x0000
 #define FW_STATE_CONFIG_WAIT                   0x0001
+#define FW_STATE_WAIT_LOGIN                    0x0002
 #define FW_STATE_ERROR                         0x0004
 #define FW_STATE_DHCP_IN_PROGRESS              0x0008
 
index 1b221ff0f6f7276ea57392953aa35e6ef30d86dd..2122967bbf0b1a56d9bd28819745bb99aea4882a 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __QLA4x_GBL_H
 #define        __QLA4x_GBL_H
 
+int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a);
 int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
 int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
 int qla4xxx_initialize_adapter(struct scsi_qla_host * ha,
@@ -75,4 +76,4 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
 extern int ql4xextended_error_logging;
 extern int ql4xdiscoverywait;
 extern int ql4xdontresethba;
-#endif                         /* _QLA4x_GBL_H */
+#endif /* _QLA4x_GBL_H */
index bb3a1c11f44c9089e9ab1d0fa5074d4f5294301b..cc210f297a78a22e6bf3269ab275964051d48b38 100644 (file)
@@ -259,10 +259,16 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
                              "seconds expired= %d\n", ha->host_no, __func__,
                              ha->firmware_state, ha->addl_fw_state,
                              timeout_count));
+               if (is_qla4032(ha) &&
+                       !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) &&
+                       (timeout_count < ADAPTER_INIT_TOV - 5)) {
+                       break;
+               }
+
                msleep(1000);
        }                       /* end of for */
 
-       if (timeout_count <= 0)
+       if (timeout_count == 0)
                DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n",
                              ha->host_no, __func__));
 
@@ -806,32 +812,6 @@ int qla4xxx_relogin_device(struct scsi_qla_host *ha,
        return QLA_SUCCESS;
 }
 
-/**
- * qla4010_get_topcat_presence - check if it is QLA4040 TopCat Chip
- * @ha: Pointer to host adapter structure.
- *
- **/
-static int qla4010_get_topcat_presence(struct scsi_qla_host *ha)
-{
-       unsigned long flags;
-       uint16_t topcat;
-
-       if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS)
-               return QLA_ERROR;
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       topcat = rd_nvram_word(ha, offsetof(struct eeprom_data,
-                                           isp4010.topcat));
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-       if ((topcat & TOPCAT_MASK) == TOPCAT_PRESENT)
-               set_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags);
-       else
-               clear_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags);
-       ql4xxx_unlock_nvram(ha);
-       return QLA_SUCCESS;
-}
-
-
 static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
 {
        unsigned long flags;
@@ -866,7 +846,7 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
                /* set defaults */
                if (is_qla4010(ha))
                        extHwConfig.Asuint32_t = 0x1912;
-               else if (is_qla4022(ha))
+               else if (is_qla4022(ha) | is_qla4032(ha))
                        extHwConfig.Asuint32_t = 0x0023;
        }
        DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n",
@@ -927,7 +907,7 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
        writel(jiffies, &ha->reg->mailbox[7]);
-       if (is_qla4022(ha))
+       if (is_qla4022(ha) | is_qla4032(ha))
                writel(set_rmask(NVR_WRITE_ENABLE),
                       &ha->reg->u1.isp4022.nvram);
 
@@ -978,7 +958,7 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
        return status;
 }
 
-static int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
+int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
 {
 #define QL4_LOCK_DRVR_WAIT     300
 #define QL4_LOCK_DRVR_SLEEP    100
@@ -1018,12 +998,7 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
        int soft_reset = 1;
        int config_chip = 0;
 
-       if (is_qla4010(ha)){
-               if (qla4010_get_topcat_presence(ha) != QLA_SUCCESS)
-                       return QLA_ERROR;
-       }
-
-       if (is_qla4022(ha))
+       if (is_qla4022(ha) | is_qla4032(ha))
                ql4xxx_set_mac_number(ha);
 
        if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
index 0d61797af7dadbe2a9d55d032d9ae5c71988ee38..6375eb017dd3c115f9fd21d59747359a4edb9ab4 100644 (file)
@@ -38,7 +38,7 @@ qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index)
 static inline void
 __qla4xxx_enable_intrs(struct scsi_qla_host *ha)
 {
-       if (is_qla4022(ha)) {
+       if (is_qla4022(ha) | is_qla4032(ha)) {
                writel(set_rmask(IMR_SCSI_INTR_ENABLE),
                       &ha->reg->u1.isp4022.intr_mask);
                readl(&ha->reg->u1.isp4022.intr_mask);
@@ -52,7 +52,7 @@ __qla4xxx_enable_intrs(struct scsi_qla_host *ha)
 static inline void
 __qla4xxx_disable_intrs(struct scsi_qla_host *ha)
 {
-       if (is_qla4022(ha)) {
+       if (is_qla4022(ha) | is_qla4032(ha)) {
                writel(clr_rmask(IMR_SCSI_INTR_ENABLE),
                       &ha->reg->u1.isp4022.intr_mask);
                readl(&ha->reg->u1.isp4022.intr_mask);
index c0a254b89a3008e645b212ae848e06e982ccb3fc..d41ce380eedcbd298185a15db290cb15c946b00a 100644 (file)
@@ -294,6 +294,12 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
                        cmd_entry->control_flags = CF_WRITE;
                else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
                        cmd_entry->control_flags = CF_READ;
+
+               ha->bytes_xfered += cmd->request_bufflen;
+               if (ha->bytes_xfered & ~0xFFFFF){
+                       ha->total_mbytes_xferred += ha->bytes_xfered >> 20;
+                       ha->bytes_xfered &= 0xFFFFF;
+               }
        }
 
        /* Set tagged queueing control flags */
index 1e283321a59d2482fcf3b81d4b9c6672a83b46f5..ef975e0dc87fb9a5eef9082dbece9fab735710fa 100644 (file)
@@ -627,6 +627,7 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
 
+       ha->isr_count++;
        /*
         * Repeatedly service interrupts up to a maximum of
         * MAX_REQS_SERVICED_PER_INTR
index e3957ca5b645ba6d57cffaa93cab0ce0f0675a78..58afd135aa1de2a32bd565940e371d309200fe3f 100644 (file)
@@ -7,15 +7,22 @@
 
 #include "ql4_def.h"
 
+static inline void eeprom_cmd(uint32_t cmd, struct scsi_qla_host *ha)
+{
+       writel(cmd, isp_nvram(ha));
+       readl(isp_nvram(ha));
+       udelay(1);
+}
+
 static inline int eeprom_size(struct scsi_qla_host *ha)
 {
-       return is_qla4022(ha) ? FM93C86A_SIZE_16 : FM93C66A_SIZE_16;
+       return is_qla4010(ha) ? FM93C66A_SIZE_16 : FM93C86A_SIZE_16;
 }
 
 static inline int eeprom_no_addr_bits(struct scsi_qla_host *ha)
 {
-       return is_qla4022(ha) ? FM93C86A_NO_ADDR_BITS_16 :
-               FM93C56A_NO_ADDR_BITS_16;
+       return is_qla4010(ha) ? FM93C56A_NO_ADDR_BITS_16 :
+               FM93C86A_NO_ADDR_BITS_16 ;
 }
 
 static inline int eeprom_no_data_bits(struct scsi_qla_host *ha)
@@ -28,8 +35,7 @@ static int fm93c56a_select(struct scsi_qla_host * ha)
        DEBUG5(printk(KERN_ERR "fm93c56a_select:\n"));
 
        ha->eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000;
-       writel(ha->eeprom_cmd_data, isp_nvram(ha));
-       readl(isp_nvram(ha));
+       eeprom_cmd(ha->eeprom_cmd_data, ha);
        return 1;
 }
 
@@ -41,12 +47,13 @@ static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr)
        int previousBit;
 
        /* Clock in a zero, then do the start bit. */
-       writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, isp_nvram(ha));
-       writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
-              AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
-       writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
-              AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
-       readl(isp_nvram(ha));
+       eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, ha);
+
+       eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+              AUBURN_EEPROM_CLK_RISE, ha);
+       eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+              AUBURN_EEPROM_CLK_FALL, ha);
+
        mask = 1 << (FM93C56A_CMD_BITS - 1);
 
        /* Force the previous data bit to be different. */
@@ -60,14 +67,14 @@ static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr)
                         * If the bit changed, then change the DO state to
                         * match.
                         */
-                       writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha));
+                       eeprom_cmd(ha->eeprom_cmd_data | dataBit, ha);
                        previousBit = dataBit;
                }
-               writel(ha->eeprom_cmd_data | dataBit |
-                      AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
-               writel(ha->eeprom_cmd_data | dataBit |
-                      AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
-               readl(isp_nvram(ha));
+               eeprom_cmd(ha->eeprom_cmd_data | dataBit |
+                      AUBURN_EEPROM_CLK_RISE, ha);
+               eeprom_cmd(ha->eeprom_cmd_data | dataBit |
+                      AUBURN_EEPROM_CLK_FALL, ha);
+
                cmd = cmd << 1;
        }
        mask = 1 << (eeprom_no_addr_bits(ha) - 1);
@@ -82,14 +89,15 @@ static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr)
                         * If the bit changed, then change the DO state to
                         * match.
                         */
-                       writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha));
+                       eeprom_cmd(ha->eeprom_cmd_data | dataBit, ha);
+
                        previousBit = dataBit;
                }
-               writel(ha->eeprom_cmd_data | dataBit |
-                      AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
-               writel(ha->eeprom_cmd_data | dataBit |
-                      AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
-               readl(isp_nvram(ha));
+               eeprom_cmd(ha->eeprom_cmd_data | dataBit |
+                      AUBURN_EEPROM_CLK_RISE, ha);
+               eeprom_cmd(ha->eeprom_cmd_data | dataBit |
+                      AUBURN_EEPROM_CLK_FALL, ha);
+
                addr = addr << 1;
        }
        return 1;
@@ -98,8 +106,7 @@ static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr)
 static int fm93c56a_deselect(struct scsi_qla_host * ha)
 {
        ha->eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000;
-       writel(ha->eeprom_cmd_data, isp_nvram(ha));
-       readl(isp_nvram(ha));
+       eeprom_cmd(ha->eeprom_cmd_data, ha);
        return 1;
 }
 
@@ -112,12 +119,13 @@ static int fm93c56a_datain(struct scsi_qla_host * ha, unsigned short *value)
        /* Read the data bits
         * The first bit is a dummy.  Clock right over it. */
        for (i = 0; i < eeprom_no_data_bits(ha); i++) {
-               writel(ha->eeprom_cmd_data |
-                      AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
-               writel(ha->eeprom_cmd_data |
-                      AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
-               dataBit =
-                       (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+               eeprom_cmd(ha->eeprom_cmd_data |
+                      AUBURN_EEPROM_CLK_RISE, ha);
+               eeprom_cmd(ha->eeprom_cmd_data |
+                      AUBURN_EEPROM_CLK_FALL, ha);
+
+               dataBit = (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+
                data = (data << 1) | dataBit;
        }
 
index 08e2aed8c6cc20bdec0eea8fc219e5824081a40e..b47b4fc59d834e1492adf5642b005764cb9f95fc 100644 (file)
@@ -134,9 +134,7 @@ struct eeprom_data {
                        u16 phyConfig;  /* x36 */
 #define         PHY_CONFIG_PHY_ADDR_MASK             0x1f
 #define         PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20
-                       u16 topcat;     /* x38 */
-#define TOPCAT_PRESENT         0x0100
-#define TOPCAT_MASK            0xFF00
+                       u16 reserved_56;        /* x38 */
 
 #define EEPROM_UNUSED_1_SIZE   2
                        u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */
index 5b8db6109536d26392603d3b635fd48b56ebf473..db9d88e7bee79f909356e3298e4eeafbc14a4805 100644 (file)
@@ -708,10 +708,10 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
 }
 
 /**
- * qla4010_soft_reset - performs soft reset.
+ * qla4xxx_soft_reset - performs soft reset.
  * @ha: Pointer to host adapter structure.
  **/
-static int qla4010_soft_reset(struct scsi_qla_host *ha)
+int qla4xxx_soft_reset(struct scsi_qla_host *ha)
 {
        uint32_t max_wait_time;
        unsigned long flags = 0;
@@ -816,29 +816,6 @@ static int qla4010_soft_reset(struct scsi_qla_host *ha)
        return status;
 }
 
-/**
- * qla4xxx_topcat_reset - performs hard reset of TopCat Chip.
- * @ha: Pointer to host adapter structure.
- **/
-static int qla4xxx_topcat_reset(struct scsi_qla_host *ha)
-{
-       unsigned long flags;
-
-       ql4xxx_lock_nvram(ha);
-       spin_lock_irqsave(&ha->hardware_lock, flags);
-       writel(set_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha));
-       readl(isp_gp_out(ha));
-       mdelay(1);
-
-       writel(clr_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha));
-       readl(isp_gp_out(ha));
-       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       mdelay(2523);
-
-       ql4xxx_unlock_nvram(ha);
-       return QLA_SUCCESS;
-}
-
 /**
  * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S.
  * @ha: Pointer to host adapter structure.
@@ -866,26 +843,6 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
 
 }
 
-/**
- * qla4xxx_hard_reset - performs HBA Hard Reset
- * @ha: Pointer to host adapter structure.
- **/
-static int qla4xxx_hard_reset(struct scsi_qla_host *ha)
-{
-       /* The QLA4010 really doesn't have an equivalent to a hard reset */
-       qla4xxx_flush_active_srbs(ha);
-       if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) {
-               int status = QLA_ERROR;
-
-               if ((qla4010_soft_reset(ha) == QLA_SUCCESS) &&
-                   (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) &&
-                   (qla4010_soft_reset(ha) == QLA_SUCCESS))
-                       status = QLA_SUCCESS;
-               return status;
-       } else
-               return qla4010_soft_reset(ha);
-}
-
 /**
  * qla4xxx_recover_adapter - recovers adapter after a fatal error
  * @ha: Pointer to host adapter structure.
@@ -919,18 +876,11 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
        if (status == QLA_SUCCESS) {
                DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
                              ha->host_no, __func__));
-               status = qla4xxx_soft_reset(ha);
-       }
-       /* FIXMEkaren: Do we want to keep interrupts enabled and process
-          AENs after soft reset */
-
-       /* If firmware (SOFT) reset failed, or if all outstanding
-        * commands have not returned, then do a HARD reset.
-        */
-       if (status == QLA_ERROR) {
-               DEBUG2(printk("scsi%ld: %s - Performing hard reset..\n",
-                             ha->host_no, __func__));
-               status = qla4xxx_hard_reset(ha);
+               qla4xxx_flush_active_srbs(ha);
+               if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+                       status = qla4xxx_soft_reset(ha);
+               else
+                       status = QLA_ERROR;
        }
 
        /* Flush any pending ddb changed AENs */
@@ -1016,13 +966,9 @@ static void qla4xxx_do_dpc(void *data)
        struct scsi_qla_host *ha = (struct scsi_qla_host *) data;
        struct ddb_entry *ddb_entry, *dtemp;
 
-       DEBUG2(printk("scsi%ld: %s: DPC handler waking up.\n",
-                     ha->host_no, __func__));
-
-       DEBUG2(printk("scsi%ld: %s: ha->flags = 0x%08lx\n",
-                     ha->host_no, __func__, ha->flags));
-       DEBUG2(printk("scsi%ld: %s: ha->dpc_flags = 0x%08lx\n",
-                     ha->host_no, __func__, ha->dpc_flags));
+       DEBUG2(printk("scsi%ld: %s: DPC handler waking up."
+               "flags = 0x%08lx, dpc_flags = 0x%08lx\n",
+               ha->host_no, __func__, ha->flags, ha->dpc_flags));
 
        /* Initialization not yet finished. Don't do anything yet. */
        if (!test_bit(AF_INIT_DONE, &ha->flags))
@@ -1032,16 +978,8 @@ static void qla4xxx_do_dpc(void *data)
            test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
            test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
            test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) {
-               if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags))
-                       /*
-                        * dg 09/23 Never initialize ddb list
-                        * once we up and running
-                        * qla4xxx_recover_adapter(ha,
-                        *    REBUILD_DDB_LIST);
-                        */
-                       qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
-
-               if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
+               if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
+                       test_bit(DPC_RESET_HA, &ha->dpc_flags))
                        qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
 
                if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
@@ -1122,7 +1060,8 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
                destroy_workqueue(ha->dpc_thread);
 
        /* Issue Soft Reset to put firmware in unknown state */
-       qla4xxx_soft_reset(ha);
+       if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS)
+               qla4xxx_soft_reset(ha);
 
        /* Remove timer thread, if present */
        if (ha->timer_active)
@@ -1261,7 +1200,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
        init_waitqueue_head(&ha->mailbox_wait_queue);
 
        spin_lock_init(&ha->hardware_lock);
-       spin_lock_init(&ha->list_lock);
 
        /* Allocate dma buffers */
        if (qla4xxx_mem_alloc(ha)) {
@@ -1467,27 +1405,6 @@ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t in
        return srb;
 }
 
-/**
- * qla4xxx_soft_reset - performs a SOFT RESET of hba.
- * @ha: Pointer to host adapter structure.
- **/
-int qla4xxx_soft_reset(struct scsi_qla_host *ha)
-{
-
-       DEBUG2(printk(KERN_WARNING "scsi%ld: %s: chip reset!\n", ha->host_no,
-                     __func__));
-       if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) {
-               int status = QLA_ERROR;
-
-               if ((qla4010_soft_reset(ha) == QLA_SUCCESS) &&
-                   (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) &&
-                   (qla4010_soft_reset(ha) == QLA_SUCCESS) )
-                       status = QLA_SUCCESS;
-               return status;
-       } else
-               return qla4010_soft_reset(ha);
-}
-
 /**
  * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
  * @ha: actual ha whose done queue will contain the comd returned by firmware.
@@ -1686,6 +1603,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = {
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
        },
+       {
+               .vendor         = PCI_VENDOR_ID_QLOGIC,
+               .device         = PCI_DEVICE_ID_QLOGIC_ISP4032,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+       },
        {0, 0},
 };
 MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
index b3fe7e68988e6378e3c033a9535dc49523353c01..454e19c8ad685f1e7d44543c2f0f419d75b1f5be 100644 (file)
@@ -5,9 +5,4 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION "5.00.05b9-k"
-
-#define QL4_DRIVER_MAJOR_VER   5
-#define QL4_DRIVER_MINOR_VER   0
-#define QL4_DRIVER_PATCH_VER   5
-#define QL4_DRIVER_BETA_VER    9
+#define QLA4XXX_DRIVER_VERSION "5.00.07-k"
index c59f31533ab4d2b0d072ead30c61a4a7ea6b199e..fafc00deaadea6fab42609d673b03aa6c8f4e7ee 100644 (file)
@@ -156,8 +156,7 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
 
 static DEFINE_MUTEX(host_cmd_pool_mutex);
 
-static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
-                                           gfp_t gfp_mask)
+struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
 {
        struct scsi_cmnd *cmd;
 
@@ -178,6 +177,7 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
 
        return cmd;
 }
+EXPORT_SYMBOL_GPL(__scsi_get_command);
 
 /*
  * Function:   scsi_get_command()
@@ -214,9 +214,29 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
                put_device(&dev->sdev_gendev);
 
        return cmd;
-}                              
+}
 EXPORT_SYMBOL(scsi_get_command);
 
+void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
+                       struct device *dev)
+{
+       unsigned long flags;
+
+       /* changing locks here, don't need to restore the irq state */
+       spin_lock_irqsave(&shost->free_list_lock, flags);
+       if (unlikely(list_empty(&shost->free_list))) {
+               list_add(&cmd->list, &shost->free_list);
+               cmd = NULL;
+       }
+       spin_unlock_irqrestore(&shost->free_list_lock, flags);
+
+       if (likely(cmd != NULL))
+               kmem_cache_free(shost->cmd_pool->slab, cmd);
+
+       put_device(dev);
+}
+EXPORT_SYMBOL(__scsi_put_command);
+
 /*
  * Function:   scsi_put_command()
  *
@@ -231,26 +251,15 @@ EXPORT_SYMBOL(scsi_get_command);
 void scsi_put_command(struct scsi_cmnd *cmd)
 {
        struct scsi_device *sdev = cmd->device;
-       struct Scsi_Host *shost = sdev->host;
        unsigned long flags;
-       
+
        /* serious error if the command hasn't come from a device list */
        spin_lock_irqsave(&cmd->device->list_lock, flags);
        BUG_ON(list_empty(&cmd->list));
        list_del_init(&cmd->list);
-       spin_unlock(&cmd->device->list_lock);
-       /* changing locks here, don't need to restore the irq state */
-       spin_lock(&shost->free_list_lock);
-       if (unlikely(list_empty(&shost->free_list))) {
-               list_add(&cmd->list, &shost->free_list);
-               cmd = NULL;
-       }
-       spin_unlock_irqrestore(&shost->free_list_lock, flags);
-
-       if (likely(cmd != NULL))
-               kmem_cache_free(shost->cmd_pool->slab, cmd);
+       spin_unlock_irqrestore(&cmd->device->list_lock, flags);
 
-       put_device(&sdev->sdev_gendev);
+       __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev);
 }
 EXPORT_SYMBOL(scsi_put_command);
 
@@ -871,9 +880,9 @@ EXPORT_SYMBOL(scsi_device_get);
  */
 void scsi_device_put(struct scsi_device *sdev)
 {
+#ifdef CONFIG_MODULE_UNLOAD
        struct module *module = sdev->host->hostt->module;
 
-#ifdef CONFIG_MODULE_UNLOAD
        /* The module refcount will be zero if scsi_device_get()
         * was called from a module removal routine */
        if (module && module_refcount(module) != 0)
index aff1b0cfd4b25bfcdf2ceda22e6d522969d7ab9b..2ecb6ff42444697d9aa866de4bb00c0d707880b5 100644 (file)
@@ -453,9 +453,18 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
 }
 
 /**
- * scsi_send_eh_cmnd  - send a cmd to a device as part of error recovery.
- * @scmd:      SCSI Cmd to send.
- * @timeout:   Timeout for cmd.
+ * scsi_send_eh_cmnd  - submit a scsi command as part of error recory
+ * @scmd:       SCSI command structure to hijack
+ * @cmnd:       CDB to send
+ * @cmnd_size:  size in bytes of @cmnd
+ * @timeout:    timeout for this request
+ * @copy_sense: request sense data if set to 1
+ *
+ * This function is used to send a scsi command down to a target device
+ * as part of the error recovery process.  If @copy_sense is 0 the command
+ * sent must be one that does not transfer any data.  If @copy_sense is 1
+ * the command must be REQUEST_SENSE and this functions copies out the
+ * sense buffer it got into @scmd->sense_buffer.
  *
  * Return value:
  *    SUCCESS or FAILED or NEEDS_RETRY
@@ -469,6 +478,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
        DECLARE_COMPLETION_ONSTACK(done);
        unsigned long timeleft;
        unsigned long flags;
+       struct scatterlist sgl;
        unsigned char old_cmnd[MAX_COMMAND_SIZE];
        enum dma_data_direction old_data_direction;
        unsigned short old_use_sg;
@@ -500,19 +510,24 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
                if (shost->hostt->unchecked_isa_dma)
                        gfp_mask |= __GFP_DMA;
 
-               scmd->sc_data_direction = DMA_FROM_DEVICE;
-               scmd->request_bufflen = 252;
-               scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask);
-               if (!scmd->request_buffer)
+               sgl.page = alloc_page(gfp_mask);
+               if (!sgl.page)
                        return FAILED;
+               sgl.offset = 0;
+               sgl.length = 252;
+
+               scmd->sc_data_direction = DMA_FROM_DEVICE;
+               scmd->request_bufflen = sgl.length;
+               scmd->request_buffer = &sgl;
+               scmd->use_sg = 1;
        } else {
                scmd->request_buffer = NULL;
                scmd->request_bufflen = 0;
                scmd->sc_data_direction = DMA_NONE;
+               scmd->use_sg = 0;
        }
 
        scmd->underflow = 0;
-       scmd->use_sg = 0;
        scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
 
        if (sdev->scsi_level <= SCSI_2)
@@ -583,7 +598,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
                        memcpy(scmd->sense_buffer, scmd->request_buffer,
                               sizeof(scmd->sense_buffer));
                }
-               kfree(scmd->request_buffer);
+               __free_page(sgl.page);
        }
 
 
index 3ac4890ce086cfab2ff6519c1f9858760b764de5..fb616c69151f69a3d6697658de3bbc87827729b6 100644 (file)
@@ -704,7 +704,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
        return NULL;
 }
 
-static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
 {
        struct scsi_host_sg_pool *sgp;
        struct scatterlist *sgl;
@@ -745,7 +745,9 @@ static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_m
        return sgl;
 }
 
-static void scsi_free_sgtable(struct scatterlist *sgl, int index)
+EXPORT_SYMBOL(scsi_alloc_sgtable);
+
+void scsi_free_sgtable(struct scatterlist *sgl, int index)
 {
        struct scsi_host_sg_pool *sgp;
 
@@ -755,6 +757,8 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index)
        mempool_free(sgl, sgp->pool);
 }
 
+EXPORT_SYMBOL(scsi_free_sgtable);
+
 /*
  * Function:    scsi_release_buffers()
  *
@@ -996,25 +1000,14 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
        int                count;
 
        /*
-        * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer
-        */
-       if (blk_pc_request(req) && !req->bio) {
-               cmd->request_bufflen = req->data_len;
-               cmd->request_buffer = req->data;
-               req->buffer = req->data;
-               cmd->use_sg = 0;
-               return 0;
-       }
-
-       /*
-        * we used to not use scatter-gather for single segment request,
+        * We used to not use scatter-gather for single segment request,
         * but now we do (it makes highmem I/O easier to support without
         * kmapping pages)
         */
        cmd->use_sg = req->nr_phys_segments;
 
        /*
-        * if sg table allocation fails, requeue request later.
+        * If sg table allocation fails, requeue request later.
         */
        sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
        if (unlikely(!sgpnt)) {
@@ -1022,24 +1015,21 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
                return BLKPREP_DEFER;
        }
 
+       req->buffer = NULL;
        cmd->request_buffer = (char *) sgpnt;
-       cmd->request_bufflen = req->nr_sectors << 9;
        if (blk_pc_request(req))
                cmd->request_bufflen = req->data_len;
-       req->buffer = NULL;
+       else
+               cmd->request_bufflen = req->nr_sectors << 9;
 
        /* 
         * Next, walk the list, and fill in the addresses and sizes of
         * each segment.
         */
        count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
-
-       /*
-        * mapped well, send it off
-        */
        if (likely(count <= cmd->use_sg)) {
                cmd->use_sg = count;
-               return 0;
+               return BLKPREP_OK;
        }
 
        printk(KERN_ERR "Incorrect number of segments after building list\n");
@@ -1069,6 +1059,27 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
        return -EOPNOTSUPP;
 }
 
+static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
+               struct request *req)
+{
+       struct scsi_cmnd *cmd;
+
+       if (!req->special) {
+               cmd = scsi_get_command(sdev, GFP_ATOMIC);
+               if (unlikely(!cmd))
+                       return NULL;
+               req->special = cmd;
+       } else {
+               cmd = req->special;
+       }
+
+       /* pull a tag out of the request if we have one */
+       cmd->tag = req->tag;
+       cmd->request = req;
+
+       return cmd;
+}
+
 static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
 {
        BUG_ON(!blk_pc_request(cmd->request));
@@ -1081,9 +1092,37 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
        scsi_io_completion(cmd, cmd->request_bufflen);
 }
 
-static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
+static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
 {
-       struct request *req = cmd->request;
+       struct scsi_cmnd *cmd;
+
+       cmd = scsi_get_cmd_from_req(sdev, req);
+       if (unlikely(!cmd))
+               return BLKPREP_DEFER;
+
+       /*
+        * BLOCK_PC requests may transfer data, in which case they must
+        * a bio attached to them.  Or they might contain a SCSI command
+        * that does not transfer data, in which case they may optionally
+        * submit a request without an attached bio.
+        */
+       if (req->bio) {
+               int ret;
+
+               BUG_ON(!req->nr_phys_segments);
+
+               ret = scsi_init_io(cmd);
+               if (unlikely(ret))
+                       return ret;
+       } else {
+               BUG_ON(req->data_len);
+               BUG_ON(req->data);
+
+               cmd->request_bufflen = 0;
+               cmd->request_buffer = NULL;
+               cmd->use_sg = 0;
+               req->buffer = NULL;
+       }
 
        BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
        memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
@@ -1099,154 +1138,138 @@ static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
        cmd->allowed = req->retries;
        cmd->timeout_per_command = req->timeout;
        cmd->done = scsi_blk_pc_done;
+       return BLKPREP_OK;
 }
 
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+/*
+ * Setup a REQ_TYPE_FS command.  These are simple read/write request
+ * from filesystems that still need to be translated to SCSI CDBs from
+ * the ULD.
+ */
+static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
 {
-       struct scsi_device *sdev = q->queuedata;
        struct scsi_cmnd *cmd;
-       int specials_only = 0;
+       struct scsi_driver *drv;
+       int ret;
 
        /*
-        * Just check to see if the device is online.  If it isn't, we
-        * refuse to process any commands.  The device must be brought
-        * online before trying any recovery commands
+        * Filesystem requests must transfer data.
         */
-       if (unlikely(!scsi_device_online(sdev))) {
-               sdev_printk(KERN_ERR, sdev,
-                           "rejecting I/O to offline device\n");
-               goto kill;
-       }
-       if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
-               /* OK, we're not in a running state don't prep
-                * user commands */
-               if (sdev->sdev_state == SDEV_DEL) {
-                       /* Device is fully deleted, no commands
-                        * at all allowed down */
-                       sdev_printk(KERN_ERR, sdev,
-                                   "rejecting I/O to dead device\n");
-                       goto kill;
-               }
-               /* OK, we only allow special commands (i.e. not
-                * user initiated ones */
-               specials_only = sdev->sdev_state;
+       BUG_ON(!req->nr_phys_segments);
+
+       cmd = scsi_get_cmd_from_req(sdev, req);
+       if (unlikely(!cmd))
+               return BLKPREP_DEFER;
+
+       ret = scsi_init_io(cmd);
+       if (unlikely(ret))
+               return ret;
+
+