linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / message / fusion / mptscsih.c
index 30524dc..4fee6be 100644 (file)
@@ -66,7 +66,6 @@
 
 #include "mptbase.h"
 #include "mptscsih.h"
-#include "lsi/mpi_log_sas.h"
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #define my_NAME                "Fusion MPT SCSI Host driver"
@@ -115,6 +114,21 @@ typedef struct _internal_cmd {
        u8              rsvd;
 } INTERNAL_CMD;
 
+typedef struct _negoparms {
+       u8 width;
+       u8 offset;
+       u8 factor;
+       u8 flags;
+} NEGOPARMS;
+
+typedef struct _dv_parameters {
+       NEGOPARMS        max;
+       NEGOPARMS        now;
+       u8               cmd;
+       u8               id;
+       u16              pad1;
+} DVPARAMETERS;
+
 /*
  *  Other private/forward protos...
  */
@@ -128,19 +142,35 @@ static void       mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
 static void    mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
 static int     mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
 static int     mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
-static int     SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
+static u32     SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
 
 static int     mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
 
 int            mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
 int            mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 
-static void    mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
-static void    mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
+static void    mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen);
+static void    mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, char byte56);
+static void    mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
+static void    mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc);
+static int     mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags);
 static int     mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
 int            mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 static int     mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
 static void    mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
+static void    mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
+static int     mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
+
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+static int     mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
+static void    mptscsih_domainValidation(void *hd);
+static void    mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
+static int     mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target);
+static void    mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
+static void    mptscsih_fillbuf(char *buffer, int size, int index, int width);
+static void    mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id);
+static void    mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc);
+#endif
 
 void           mptscsih_remove(struct pci_dev *);
 void           mptscsih_shutdown(struct pci_dev *);
@@ -151,6 +181,16 @@ int                mptscsih_resume(struct pci_dev *pdev);
 
 #define SNS_LEN(scp)   sizeof((scp)->sense_buffer)
 
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+/*
+ * Domain Validation task structure
+ */
+static DEFINE_SPINLOCK(dvtaskQ_lock);
+static int dvtaskQ_active = 0;
+static int dvtaskQ_release = 0;
+static struct work_struct      dvTaskQ_task;
+#endif
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptscsih_add_sge - Place a simple SGE at address pAddr.
@@ -498,34 +538,6 @@ nextSGEset:
        return SUCCESS;
 } /* mptscsih_AddSGE() */
 
-static void
-mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
-    U32 SlotStatus)
-{
-       MPT_FRAME_HDR *mf;
-       SEPRequest_t     *SEPMsg;
-
-       if (ioc->bus_type == FC)
-               return;
-
-       if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
-               dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
-                   ioc->name,__FUNCTION__));
-               return;
-       }
-
-       SEPMsg = (SEPRequest_t *)mf;
-       SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
-       SEPMsg->Bus = vtarget->bus_id;
-       SEPMsg->TargetID = vtarget->target_id;
-       SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
-       SEPMsg->SlotStatus = SlotStatus;
-       devtverboseprintk((MYIOC_s_WARN_FMT
-           "Sending SEP cmd=%x id=%d bus=%d\n",
-           ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus));
-       mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
-}
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     mptscsih_io_done - Main SCSI IO callback routine registered to
@@ -549,8 +561,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        SCSIIORequest_t *pScsiReq;
        SCSIIOReply_t   *pScsiReply;
        u16              req_idx, req_idx_MR;
-       VirtDevice       *vdev;
-       VirtTarget       *vtarget;
 
        hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
 
@@ -569,7 +579,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        }
 
        sc = hd->ScsiLookup[req_idx];
-       hd->ScsiLookup[req_idx] = NULL;
        if (sc == NULL) {
                MPIHeader_t *hdr = (MPIHeader_t *)mf;
 
@@ -585,12 +594,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                return 1;
        }
 
-       if ((unsigned char *)mf != sc->host_scribble) {
-               mptscsih_freeChainBuffers(ioc, req_idx);
-               return 1;
-       }
-
-       sc->host_scribble = NULL;
        sc->result = DID_OK << 16;              /* Set default reply as OK */
        pScsiReq = (SCSIIORequest_t *) mf;
        pScsiReply = (SCSIIOReply_t *) mr;
@@ -670,50 +673,23 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 
                case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:       /* 0x0043 */
                        /* Spoof to SCSI Selection Timeout! */
-                       if (ioc->bus_type != FC)
-                               sc->result = DID_NO_CONNECT << 16;
-                       /* else fibre, just stall until rescan event */
-                       else
-                               sc->result = DID_REQUEUE << 16;
+                       sc->result = DID_NO_CONNECT << 16;
 
                        if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
                                hd->sel_timeout[pScsiReq->TargetID]++;
-
-                       vdev = sc->device->hostdata;
-                       if (!vdev)
-                               break;
-                       vtarget = vdev->vtarget;
-                       if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
-                               mptscsih_issue_sep_command(ioc, vtarget,
-                                   MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
-                               vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
-                       }
                        break;
 
-               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
-                       if ( ioc->bus_type == SAS ) {
-                               u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
-                               if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
-                                       u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
-                                       log_info &=SAS_LOGINFO_MASK;
-                                       if (log_info == SAS_LOGINFO_NEXUS_LOSS) {
-                                               sc->result = (DID_BUS_BUSY << 16);
-                                               break;
-                                       }
-                               }
-                       }
-
-                       /*
-                        * Allow non-SAS & non-NEXUS_LOSS to drop into below code
-                        */
-
                case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:        /* 0x0048 */
+               case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:         /* 0x004B */
                case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
                        /* Linux handles an unsolicited DID_RESET better
                         * than an unsolicited DID_ABORT.
                         */
                        sc->result = DID_RESET << 16;
 
+                       /* GEM Workaround. */
+                       if (ioc->bus_type == SPI)
+                               mptscsih_no_negotiate(hd, sc);
                        break;
 
                case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:      /* 0x0049 */
@@ -722,7 +698,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                sc->result=DID_SOFT_ERROR << 16;
                        else /* Sufficient data transfer occurred */
                                sc->result = (DID_OK << 16) | scsi_status;
-                       dreplyprintk((KERN_NOTICE
+                       dreplyprintk((KERN_NOTICE 
                            "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
                        break;
 
@@ -848,6 +824,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                sc->request_bufflen, sc->sc_data_direction);
        }
 
+       hd->ScsiLookup[req_idx] = NULL;
+
        sc->scsi_done(sc);              /* Issue the command callback */
 
        /* Free Chain buffers */
@@ -889,17 +867,9 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
                        dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
                                        mf, SCpnt));
 
-                       /* Free Chain buffers */
-                       mptscsih_freeChainBuffers(ioc, ii);
-
-                       /* Free Message frames */
-                       mpt_free_msg_frame(ioc, mf);
-
-                       if ((unsigned char *)mf != SCpnt->host_scribble)
-                               continue;
-
                        /* Set status, free OS resources (SG DMA buffers)
                         * Do OS callback
+                        * Free driver resources (chain, msg buffers)
                         */
                        if (SCpnt->use_sg) {
                                pci_unmap_sg(ioc->pcidev,
@@ -915,6 +885,12 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
                        SCpnt->result = DID_RESET << 16;
                        SCpnt->host_scribble = NULL;
 
+                       /* Free Chain buffers */
+                       mptscsih_freeChainBuffers(ioc, ii);
+
+                       /* Free Message frames */
+                       mpt_free_msg_frame(ioc, mf);
+
                        SCpnt->scsi_done(SCpnt);        /* Issue the command callback */
                }
        }
@@ -945,17 +921,17 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
        struct scsi_cmnd *sc;
 
        dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
-                       vdevice->vtarget->target_id, vdevice->lun, max));
+                       vdevice->target_id, vdevice->lun, max));
 
        for (ii=0; ii < max; ii++) {
                if ((sc = hd->ScsiLookup[ii]) != NULL) {
 
                        mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
-                       if (mf == NULL)
-                               continue;
+
                        dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
                                        hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
-                       if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
+
+                       if ((mf->TargetID != ((u8)vdevice->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
                                continue;
 
                        /* Cleanup
@@ -963,8 +939,6 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
                        hd->ScsiLookup[ii] = NULL;
                        mptscsih_freeChainBuffers(hd->ioc, ii);
                        mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
-                       if ((unsigned char *)mf != sc->host_scribble)
-                               continue;
                        if (sc->use_sg) {
                                pci_unmap_sg(hd->ioc->pcidev,
                                (struct scatterlist *) sc->request_buffer,
@@ -1031,6 +1005,10 @@ mptscsih_remove(struct pci_dev *pdev)
        MPT_ADAPTER             *ioc = pci_get_drvdata(pdev);
        struct Scsi_Host        *host = ioc->sh;
        MPT_SCSI_HOST           *hd;
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+       int                     count;
+       unsigned long           flags;
+#endif 
        int sz1;
 
        if(!host) {
@@ -1043,6 +1021,25 @@ mptscsih_remove(struct pci_dev *pdev)
        if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
                return;
 
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+       /* Check DV thread active */
+       count = 10 * HZ;
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       if (dvtaskQ_active) {
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+               while(dvtaskQ_active && --count)
+                       schedule_timeout_interruptible(1);
+       } else {
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+       }
+       if (!count)
+               printk(KERN_ERR MYNAM ": ERROR - DV thread still active!\n");
+#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
+       else
+               printk(KERN_ERR MYNAM ": DV thread orig %d, count %d\n", 10 * HZ, count);
+#endif
+#endif
+
        mptscsih_shutdown(pdev);
 
        sz1=0;
@@ -1130,6 +1127,21 @@ mptscsih_resume(struct pci_dev *pdev)
        if(!hd)
                return 0;
 
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+       {
+       unsigned long lflags;
+       spin_lock_irqsave(&dvtaskQ_lock, lflags);
+       if (!dvtaskQ_active) {
+               dvtaskQ_active = 1;
+               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+               INIT_WORK(&dvTaskQ_task,
+                 mptscsih_domainValidation, (void *) hd);
+               schedule_work(&dvTaskQ_task);
+       } else {
+               spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+       }
+       }
+#endif
        return 0;
 }
 
@@ -1305,14 +1317,6 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
                return SCSI_MLQUEUE_HOST_BUSY;
        }
 
-       if ((hd->ioc->bus_type == SPI) &&
-           vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT &&
-           mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) {
-               SCpnt->result = DID_NO_CONNECT << 16;
-               done(SCpnt);
-               return 0;
-       }
-
        /*
         *  Put together a MPT SCSI request...
         */
@@ -1356,13 +1360,10 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 
        /* Use the above information to set up the message frame
         */
-       pScsiReq->TargetID = (u8) vdev->vtarget->target_id;
-       pScsiReq->Bus = vdev->vtarget->bus_id;
+       pScsiReq->TargetID = (u8) vdev->target_id;
+       pScsiReq->Bus = vdev->bus_id;
        pScsiReq->ChainOffset = 0;
-       if (vdev->vtarget->tflags &  MPT_TARGET_FLAGS_RAID_COMPONENT)
-               pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
-       else
-               pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
+       pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
        pScsiReq->CDBLength = SCpnt->cmd_len;
        pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
        pScsiReq->Reserved = 0;
@@ -1407,8 +1408,51 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
                        goto fail;
        }
 
-       SCpnt->host_scribble = (unsigned char *)mf;
        hd->ScsiLookup[my_idx] = SCpnt;
+       SCpnt->host_scribble = NULL;
+
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+       if (hd->ioc->bus_type == SPI) {
+               int dvStatus = hd->ioc->spi_data.dvStatus[vdev->target_id];
+               int issueCmd = 1;
+
+               if (dvStatus || hd->ioc->spi_data.forceDv) {
+
+                       if ((dvStatus & MPT_SCSICFG_NEED_DV) ||
+                               (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) {
+                               unsigned long lflags;
+                               /* Schedule DV if necessary */
+                               spin_lock_irqsave(&dvtaskQ_lock, lflags);
+                               if (!dvtaskQ_active) {
+                                       dvtaskQ_active = 1;
+                                       spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+                                       INIT_WORK(&dvTaskQ_task, mptscsih_domainValidation, (void *) hd);
+
+                                       schedule_work(&dvTaskQ_task);
+                               } else {
+                                       spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
+                               }
+                               hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV;
+                       }
+
+                       /* Trying to do DV to this target, extend timeout.
+                        * Wait to issue until flag is clear
+                        */
+                       if (dvStatus & MPT_SCSICFG_DV_PENDING) {
+                               mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ);
+                               issueCmd = 0;
+                       }
+
+                       /* Set the DV flags.
+                        */
+                       if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
+                               mptscsih_set_dvflags(hd, SCpnt);
+
+                       if (!issueCmd)
+                               goto fail;
+               }
+       }
+#endif
 
        mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
        dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
@@ -1595,12 +1639,6 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in
                rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
        }
 
-       /*
-        * Check IOCStatus from TM reply message
-        */
-        if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS)
-               rc = FAILED;
-
        dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
 
        return rc;
@@ -1721,12 +1759,12 @@ int
 mptscsih_abort(struct scsi_cmnd * SCpnt)
 {
        MPT_SCSI_HOST   *hd;
+       MPT_ADAPTER     *ioc;
        MPT_FRAME_HDR   *mf;
        u32              ctx2abort;
        int              scpnt_idx;
        int              retval;
        VirtDevice       *vdev;
-       ulong            sn = SCpnt->serial_number;
 
        /* If we can't locate our host adapter structure, return FAILED status.
         */
@@ -1739,6 +1777,14 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
                return FAILED;
        }
 
+       ioc = hd->ioc;
+       if (hd->resetPending) {
+               return FAILED;
+       }
+
+       if (hd->timeouts < -1)
+               hd->timeouts++;
+
        /* Find this command
         */
        if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
@@ -1752,13 +1798,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
                return SUCCESS;
        }
 
-       if (hd->resetPending) {
-               return FAILED;
-       }
-
-       if (hd->timeouts < -1)
-               hd->timeouts++;
-
        printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
               hd->ioc->name, SCpnt);
        scsi_print_command(SCpnt);
@@ -1777,13 +1816,8 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 
        vdev = SCpnt->device->hostdata;
        retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
-               vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
-               ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
-
-       if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
-           SCpnt->serial_number == sn) {
-               retval = FAILED;
-       }
+               vdev->bus_id, vdev->target_id, vdev->lun,
+               ctx2abort, mptscsih_get_tm_timeout(ioc));
 
        printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
                hd->ioc->name,
@@ -1833,7 +1867,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
 
        vdev = SCpnt->device->hostdata;
        retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-               vdev->vtarget->bus_id, vdev->vtarget->target_id,
+               vdev->bus_id, vdev->target_id,
                0, 0, mptscsih_get_tm_timeout(hd->ioc));
 
        printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
@@ -1884,7 +1918,7 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
 
        vdev = SCpnt->device->hostdata;
        retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
-               vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
+               vdev->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
 
        printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
                hd->ioc->name,
@@ -2000,7 +2034,7 @@ mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
                        break;
                }
                spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
-               msleep(250);
+               msleep_interruptible(250);
        } while (--loop_count);
 
        return status;
@@ -2101,7 +2135,6 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
                DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
 
                iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-               hd->tm_iocstatus = iocstatus;
                dtmprintk((MYIOC_s_WARN_FMT "  SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
                        ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
                /* Error?  (anything non-zero?) */
@@ -2185,42 +2218,6 @@ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
        return 0;
 }
 
-/* Search IOC page 3 to determine if this is hidden physical disk
- *
- */
-int
-mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
-{
-       int i;
-
-       if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
-               return 0;
-       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
-                if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
-                        return 1;
-        }
-        return 0;
-}
-EXPORT_SYMBOL(mptscsih_is_phys_disk);
-
-int
-mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
-{
-       int i;
-
-       if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
-               return -ENXIO;
-
-       for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
-               if (physdiskid ==
-                   hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
-                       return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
-       }
-
-       return -ENXIO;
-}
-EXPORT_SYMBOL(mptscsih_raid_id_to_num);
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *     OS entry point to allow host driver to alloc memory
@@ -2236,7 +2233,6 @@ mptscsih_target_alloc(struct scsi_target *starget)
        if (!vtarget)
                return -ENOMEM;
        starget->hostdata = vtarget;
-       vtarget->starget = starget;
        return 0;
 }
 
@@ -2262,12 +2258,14 @@ mptscsih_slave_alloc(struct scsi_device *sdev)
                return -ENOMEM;
        }
 
+       vdev->ioc_id = hd->ioc->id;
+       vdev->target_id = sdev->id;
+       vdev->bus_id = sdev->channel;
        vdev->lun = sdev->lun;
        sdev->hostdata = vdev;
 
        starget = scsi_target(sdev);
        vtarget = starget->hostdata;
-
        vdev->vtarget = vtarget;
 
        if (vtarget->num_luns == 0) {
@@ -2276,11 +2274,14 @@ mptscsih_slave_alloc(struct scsi_device *sdev)
                vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
                vtarget->target_id = sdev->id;
                vtarget->bus_id = sdev->channel;
-               if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
-                   hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
-                       vtarget->raidVolume = 1;
-                       ddvtprintk((KERN_INFO
+               if (hd->ioc->bus_type == SPI) {
+                       if (hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
+                               vtarget->raidVolume = 1;
+                               ddvtprintk((KERN_INFO
                                    "RAID Volume @ id %d\n", sdev->id));
+                       }
+               } else {
+                       vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
                }
        }
        vtarget->num_luns++;
@@ -2320,6 +2321,19 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
        vtarget->luns[0] &= ~(1 << vdevice->lun);
        vtarget->num_luns--;
        if (vtarget->num_luns == 0) {
+               mptscsih_negotiate_to_asyn_narrow(hd, vdevice);
+               if (hd->ioc->bus_type == SPI) {
+                       if (mptscsih_is_phys_disk(hd->ioc, vtarget->target_id)) {
+                               hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3;
+                       } else {
+                               hd->ioc->spi_data.dvStatus[vtarget->target_id] =
+                                       MPT_SCSICFG_NEGOTIATE;
+                               if (!hd->negoNvram) {
+                                       hd->ioc->spi_data.dvStatus[vtarget->target_id] |=
+                                               MPT_SCSICFG_DV_NOT_DONE;
+                               }
+                       }
+               }
                hd->Targets[sdev->id] = NULL;
        }
        mptscsih_synchronize_cache(hd, vdevice);
@@ -2348,13 +2362,18 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
        vtarget = starget->hostdata;
 
        if (hd->ioc->bus_type == SPI) {
-               if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+               if (vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
+                       if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+                               max_depth = 1;
+                       else if (((vtarget->inq_data[0] & 0x1f) == 0x00) &&
+                                (vtarget->minSyncFactor <= MPT_ULTRA160 ))
+                               max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
+                       else
+                               max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
+               } else {
+                       /* error case - No Inq. Data */
                        max_depth = 1;
-               else if (sdev->type == TYPE_DISK &&
-                        vtarget->minSyncFactor <= MPT_ULTRA160)
-                       max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
-               else
-                       max_depth = MPT_SCSI_CMD_PER_DEV_LOW;
+               }
        } else
                max_depth = MPT_SCSI_CMD_PER_DEV_HIGH;
 
@@ -2408,7 +2427,8 @@ mptscsih_slave_configure(struct scsi_device *sdev)
        lun_index = (vdevice->lun >> 5);  /* 32 luns per lun_index */
        indexed_lun = (vdevice->lun % 32);
        vtarget->luns[lun_index] |= (1 << indexed_lun);
-       mptscsih_initTarget(hd, vtarget, sdev);
+       mptscsih_initTarget(hd, vtarget, sdev->lun, sdev->inquiry,
+           sdev->inquiry_len );
        mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
 
        dsprintk((MYIOC_s_INFO_FMT
@@ -2480,13 +2500,6 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
                                ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
 
                                ioc->eventContext++;
-                               if (hd->ioc->pcidev->vendor ==
-                                   PCI_VENDOR_ID_IBM) {
-                                       mptscsih_issue_sep_command(hd->ioc,
-                                           vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
-                                       vdev->vtarget->tflags |=
-                                           MPT_TARGET_FLAGS_LED_ON;
-                               }
                        }
                }
        } else {
@@ -2495,7 +2508,7 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
        }
 }
 
-static int
+static u32
 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
 {
        MPT_SCSI_HOST *hd;
@@ -2584,6 +2597,10 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 
                /* 4. Renegotiate to all devices, if SPI
                 */
+               if (ioc->bus_type == SPI) {
+                       dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n"));
+                       mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM);
+               }
 
                /* 5. Enable new commands to be posted
                 */
@@ -2607,6 +2624,25 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
                        hd->cmdPtr = NULL;
                }
 
+               /* 7. SPI: Set flag to force DV and re-read IOC Page 3
+                */
+               if (ioc->bus_type == SPI) {
+                       ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
+                       ddvtprintk(("Set reload IOC Pg3 Flag\n"));
+               }
+
+               /* 7. FC: Rescan for blocked rports which might have returned.
+                */
+               else if (ioc->bus_type == FC) {
+                       int work_count;
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+                       work_count = ++ioc->fc_rescan_work_count;
+                       spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+                       if (work_count == 1)
+                               schedule_work(&ioc->fc_rescan_work);
+               }
                dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
 
        }
@@ -2620,8 +2656,10 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
        MPT_SCSI_HOST *hd;
        u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+       int work_count;
+       unsigned long flags;
 
-       devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+       devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
                        ioc->name, event));
 
        if (ioc->sh == NULL ||
@@ -2642,6 +2680,11 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                break;
 
        case MPI_EVENT_RESCAN:                          /* 06 */
+               spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+               work_count = ++ioc->fc_rescan_work_count;
+               spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+               if (work_count == 1)
+                       schedule_work(&ioc->fc_rescan_work);
                break;
 
                /*
@@ -2656,7 +2699,18 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                break;
 
        case MPI_EVENT_INTEGRATED_RAID:                 /* 0B */
+       {
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+               pMpiEventDataRaid_t pRaidEventData =
+                   (pMpiEventDataRaid_t) pEvReply->Data;
+               /* Domain Validation Needed */
+               if (ioc->bus_type == SPI &&
+                   pRaidEventData->ReasonCode ==
+                   MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED)
+                       mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum);
+#endif
                break;
+       }
 
        case MPI_EVENT_NONE:                            /* 00 */
        case MPI_EVENT_LOG_DATA:                        /* 01 */
@@ -2675,7 +2729,9 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
  *     mptscsih_initTarget - Target, LUN alloc/free functionality.
  *     @hd: Pointer to MPT_SCSI_HOST structure
  *     @vtarget: per target private data
- *     @sdev: SCSI device
+ *     @lun: SCSI LUN id
+ *     @data: Pointer to data
+ *     @dlen: Number of INQUIRY bytes
  *
  *     NOTE: It's only SAFE to call this routine if data points to
  *     sane & valid STANDARD INQUIRY data!
@@ -2685,46 +2741,98 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
  *
  */
 static void
-mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
-                   struct scsi_device *sdev)
+mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen)
 {
+       SpiCfgData      *pSpi;
+       char            data_56;
+       int             inq_len;
+
        dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
                hd->ioc->name, vtarget->bus_id, vtarget->target_id, lun, hd));
 
+       /*
+        * If the peripheral qualifier filter is enabled then if the target reports a 0x1
+        * (i.e. The targer is capable of supporting the specified peripheral device type
+        * on this logical unit; however, the physical device is not currently connected
+        * to this logical unit) it will be converted to a 0x3 (i.e. The target is not
+        * capable of supporting a physical device on this logical unit). This is to work
+        * around a bug in th emid-layer in some distributions in which the mid-layer will
+        * continue to try to communicate to the LUN and evntually create a dummy LUN.
+       */
+       if (hd->mpt_pq_filter && dlen && (data[0] & 0xE0))
+               data[0] |= 0x40;
+
        /* Is LUN supported? If so, upper 2 bits will be 0
        * in first byte of inquiry data.
        */
-       if (sdev->inq_periph_qual != 0)
+       if (data[0] & 0xe0)
                return;
 
        if (vtarget == NULL)
                return;
 
-       vtarget->type = sdev->type;
+       if (data)
+               vtarget->type = data[0];
 
        if (hd->ioc->bus_type != SPI)
                return;
 
-       if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
+       if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
                /* Treat all Processors as SAF-TE if
                 * command line option is set */
                vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
                mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
-       }else if ((sdev->type == TYPE_PROCESSOR) &&
+       }else if ((data[0] == TYPE_PROCESSOR) &&
                !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
-               if (sdev->inquiry_len > 49 ) {
-                       if (sdev->inquiry[44] == 'S' &&
-                           sdev->inquiry[45] == 'A' &&
-                           sdev->inquiry[46] == 'F' &&
-                           sdev->inquiry[47] == '-' &&
-                           sdev->inquiry[48] == 'T' &&
-                           sdev->inquiry[49] == 'E' ) {
+               if ( dlen > 49 ) {
+                       vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+                       if ( data[44] == 'S' &&
+                            data[45] == 'A' &&
+                            data[46] == 'F' &&
+                            data[47] == '-' &&
+                            data[48] == 'T' &&
+                            data[49] == 'E' ) {
                                vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
                                mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
                        }
                }
        }
-       mptscsih_setTargetNegoParms(hd, vtarget, sdev);
+       if (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+               inq_len = dlen < 8 ? dlen : 8;
+               memcpy (vtarget->inq_data, data, inq_len);
+               /* If have not done DV, set the DV flag.
+                */
+               pSpi = &hd->ioc->spi_data;
+               if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) {
+                       if (pSpi->dvStatus[vtarget->target_id] & MPT_SCSICFG_DV_NOT_DONE)
+                               pSpi->dvStatus[vtarget->target_id] |= MPT_SCSICFG_NEED_DV;
+               }
+               vtarget->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY;
+
+               data_56 = 0x0F;  /* Default to full capabilities if Inq data length is < 57 */
+               if (dlen > 56) {
+                       if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
+                       /* Update the target capabilities
+                        */
+                               data_56 = data[56];
+                               vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
+                       }
+               }
+               mptscsih_setTargetNegoParms(hd, vtarget, data_56);
+       } else {
+               /* Initial Inquiry may not request enough data bytes to
+                * obtain byte 57.  DV will; if target doesn't return
+                * at least 57 bytes, data[56] will be zero. */
+               if (dlen > 56) {
+                       if ( (!(vtarget->tflags & MPT_TARGET_FLAGS_VALID_56))) {
+                       /* Update the target capabilities
+                        */
+                               data_56 = data[56];
+                               vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56;
+                               mptscsih_setTargetNegoParms(hd, vtarget, data_56);
+                       }
+               }
+       }
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2734,51 +2842,66 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
  *
  */
 static void
-mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
-                           struct scsi_device *sdev)
+mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target, char byte56)
 {
        SpiCfgData *pspi_data = &hd->ioc->spi_data;
        int  id = (int) target->target_id;
        int  nvram;
+       VirtTarget      *vtarget;
+       int ii;
        u8 width = MPT_NARROW;
        u8 factor = MPT_ASYNC;
        u8 offset = 0;
-       u8 nfactor;
+       u8 version, nfactor;
        u8 noQas = 1;
 
        target->negoFlags = pspi_data->noQas;
 
-       /* noQas == 0 => device supports QAS. */
+       /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine
+        * support. If available, default QAS to off and allow enabling.
+        * If not available, default QAS to on, turn off for non-disks.
+        */
 
-       if (sdev->scsi_level < SCSI_2) {
+       /* Set flags based on Inquiry data
+        */
+       version = target->inq_data[2] & 0x07;
+       if (version < 2) {
                width = 0;
                factor = MPT_ULTRA2;
                offset = pspi_data->maxSyncOffset;
                target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
        } else {
-               if (scsi_device_wide(sdev)) {
+               if (target->inq_data[7] & 0x20) {
                        width = 1;
                }
 
-               if (scsi_device_sync(sdev)) {
+               if (target->inq_data[7] & 0x10) {
                        factor = pspi_data->minSyncFactor;
-                       if (!scsi_device_dt(sdev))
+                       if (target->tflags & MPT_TARGET_FLAGS_VALID_56) {
+                               /* bits 2 & 3 show Clocking support */
+                               if ((byte56 & 0x0C) == 0)
                                        factor = MPT_ULTRA2;
-                       else {
-                               if (!scsi_device_ius(sdev) &&
-                                   !scsi_device_qas(sdev))
-                                       factor = MPT_ULTRA160;
                                else {
-                                       factor = MPT_ULTRA320;
-                                       if (scsi_device_qas(sdev)) {
-                                               ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
-                                               noQas = 0;
+                                       if ((byte56 & 0x03) == 0)
+                                               factor = MPT_ULTRA160;
+                                       else {
+                                               factor = MPT_ULTRA320;
+                                               if (byte56 & 0x02)
+                                               {
+                                                       ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", byte56, id));
+                                                       noQas = 0;
+                                               }
+                                               if (target->inq_data[0] == TYPE_TAPE) {
+                                                       if (byte56 & 0x01)
+                                                               target->negoFlags |= MPT_TAPE_NEGO_IDP;
+                                               }
                                        }
-                                       if (sdev->type == TYPE_TAPE &&
-                                           scsi_device_ius(sdev))
-                                               target->negoFlags |= MPT_TAPE_NEGO_IDP;
                                }
+                       } else {
+                               ddvtprintk((KERN_INFO "Enabling QAS on id=%d due to ~TARGET_FLAGS_VALID_56!\n", id));
+                               noQas = 0;
                        }
+
                        offset = pspi_data->maxSyncOffset;
 
                        /* If RAID, never disable QAS
@@ -2796,7 +2919,7 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
                }
        }
 
-       if (!sdev->tagged_supported) {
+       if ( (target->inq_data[7] & 0x02) == 0) {
                target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
        }
 
@@ -2854,92 +2977,374 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
        if ( factor > MPT_ULTRA320 )
                noQas = 0;
 
-       if (noQas && (pspi_data->noQas == 0)) {
-               pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
-               target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
-
-               /* Disable QAS in a mixed configuration case
-                */
+       /* GEM, processor WORKAROUND
+        */
+       if ((target->inq_data[0] == TYPE_PROCESSOR) || (target->inq_data[0] > 0x08)) {
+               target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
+               pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO;
+       } else {
+               if (noQas && (pspi_data->noQas == 0)) {
+                       pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
+                       target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+
+                       /* Disable QAS in a mixed configuration case
+                       */
+
+                       ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
+                       for (ii = 0; ii < id; ii++) {
+                               if ( (vtarget = hd->Targets[ii]) ) {
+                                       vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+                                       mptscsih_writeSDP1(hd, 0, ii, vtarget->negoFlags);
+                               }
+                       }
+               }
+       }
 
-               ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
+       /* Write SDP1 on this I/O to this target */
+       if (pspi_data->dvStatus[id] & MPT_SCSICFG_NEGOTIATE) {
+               ddvtprintk((KERN_INFO "MPT_SCSICFG_NEGOTIATE on id=%d!\n", id));
+               mptscsih_writeSDP1(hd, 0, id, hd->negoNvram);
+               pspi_data->dvStatus[id] &= ~MPT_SCSICFG_NEGOTIATE;
+       } else if (pspi_data->dvStatus[id] & MPT_SCSICFG_BLK_NEGO) {
+               ddvtprintk((KERN_INFO "MPT_SCSICFG_BLK_NEGO on id=%d!\n", id));
+               mptscsih_writeSDP1(hd, 0, id, MPT_SCSICFG_BLK_NEGO);
+               pspi_data->dvStatus[id] &= ~MPT_SCSICFG_BLK_NEGO;
        }
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ * If no Target, bus reset on 1st I/O. Set the flag to
+ * prevent any future negotiations to this device.
+ */
+static void
+mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
+{
+       VirtDevice      *vdev;
+
+       if ((vdev = sc->device->hostdata) != NULL)
+               hd->ioc->spi_data.dvStatus[vdev->target_id] |= MPT_SCSICFG_BLK_NEGO;
+       return;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  SCSI Config Page functionality ...
  */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_setDevicePage1Flags  - add Requested and Configuration fields flags
+ *     based on width, factor and offset parameters.
+ *     @width: bus width
+ *     @factor: sync factor
+ *     @offset: sync offset
+ *     @requestedPtr: pointer to requested values (updated)
+ *     @configurationPtr: pointer to configuration values (updated)
+ *     @flags: flags to block WDTR or SDTR negotiation
+ *
+ *     Return: None.
+ *
+ *     Remark: Called by writeSDP1 and _dv_params
+ */
+static void
+mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags)
+{
+       u8 nowide = flags & MPT_TARGET_NO_NEGO_WIDE;
+       u8 nosync = flags & MPT_TARGET_NO_NEGO_SYNC;
+
+       *configurationPtr = 0;
+       *requestedPtr = width ? MPI_SCSIDEVPAGE1_RP_WIDE : 0;
+       *requestedPtr |= (offset << 16) | (factor << 8);
+
+       if (width && offset && !nowide && !nosync) {
+               if (factor < MPT_ULTRA160) {
+                       *requestedPtr |= (MPI_SCSIDEVPAGE1_RP_IU + MPI_SCSIDEVPAGE1_RP_DT);
+                       if ((flags & MPT_TARGET_NO_NEGO_QAS) == 0)
+                               *requestedPtr |= MPI_SCSIDEVPAGE1_RP_QAS;
+                       if (flags & MPT_TAPE_NEGO_IDP)
+                               *requestedPtr |= 0x08000000;
+               } else if (factor < MPT_ULTRA2) {
+                       *requestedPtr |= MPI_SCSIDEVPAGE1_RP_DT;
+               }
+       }
+
+       if (nowide)
+               *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED;
+
+       if (nosync)
+               *configurationPtr |= MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED;
+
+       return;
+}
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*     mptscsih_writeIOCPage4  - write IOC Page 4
- *     @hd: Pointer to a SCSI Host Structure
- *     @target_id: write IOC Page4 for this ID & Bus
+/*     mptscsih_writeSDP1  - write SCSI Device Page 1
+ *     @hd: Pointer to a SCSI Host Strucutre
+ *     @portnum: IOC port number
+ *     @target_id: writeSDP1 for single ID
+ *     @flags: MPT_SCSICFG_ALL_IDS, MPT_SCSICFG_USE_NVRAM, MPT_SCSICFG_BLK_NEGO
  *
- *     Return: -EAGAIN if unable to obtain a Message Frame
+ *     Return: -EFAULT if read of config page header fails
  *             or 0 if success.
  *
+ *     Remark: If a target has been found, the settings from the
+ *             target structure are used, else the device is set
+ *             to async/narrow.
+ *
+ *     Remark: Called during init and after a FW reload.
  *     Remark: We do not wait for a return, write pages sequentially.
  */
 static int
-mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
+mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags)
 {
        MPT_ADAPTER             *ioc = hd->ioc;
        Config_t                *pReq;
-       IOCPage4_t              *IOCPage4Ptr;
+       SCSIDevicePage1_t       *pData;
+       VirtTarget              *vtarget=NULL;
        MPT_FRAME_HDR           *mf;
        dma_addr_t               dataDma;
        u16                      req_idx;
        u32                      frameOffset;
-       u32                      flagsLength;
-       int                      ii;
+       u32                      requested, configuration, flagsLength;
+       int                      ii, nvram;
+       int                      id = 0, maxid = 0;
+       u8                       width;
+       u8                       factor;
+       u8                       offset;
+       u8                       bus = 0;
+       u8                       negoFlags;
+       u8                       maxwidth, maxoffset, maxfactor;
+
+       if (ioc->spi_data.sdp1length == 0)
+               return 0;
 
-       /* Get a MF for this command.
-        */
-       if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
-               dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
-                                       ioc->name));
-               return -EAGAIN;
+       if (flags & MPT_SCSICFG_ALL_IDS) {
+               id = 0;
+               maxid = ioc->sh->max_id - 1;
+       } else if (ioc->sh) {
+               id = target_id;
+               maxid = min_t(int, id, ioc->sh->max_id - 1);
        }
 
-       /* Set the request and the data pointers.
-        * Place data at end of MF.
-        */
-       pReq = (Config_t *)mf;
-
-       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
-       frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
+       for (; id <= maxid; id++) {
 
-       /* Complete the request frame (same for all requests).
-        */
-       pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
-       pReq->Reserved = 0;
-       pReq->ChainOffset = 0;
-       pReq->Function = MPI_FUNCTION_CONFIG;
-       pReq->ExtPageLength = 0;
-       pReq->ExtPageType = 0;
-       pReq->MsgFlags = 0;
-       for (ii=0; ii < 8; ii++) {
-               pReq->Reserved2[ii] = 0;
-       }
+               if (id == ioc->pfacts[portnum].PortSCSIID)
+                       continue;
 
-               IOCPage4Ptr = ioc->spi_data.pIocPg4;
-               dataDma = ioc->spi_data.IocPg4_dma;
-               ii = IOCPage4Ptr->ActiveSEP++;
-               IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
-               IOCPage4Ptr->SEP[ii].SEPBus = bus;
-               pReq->Header = IOCPage4Ptr->Header;
-       pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
+               /* Use NVRAM to get adapter and target maximums
+                * Data over-riden by target structure information, if present
+                */
+               maxwidth = ioc->spi_data.maxBusWidth;
+               maxoffset = ioc->spi_data.maxSyncOffset;
+               maxfactor = ioc->spi_data.minSyncFactor;
+               if (ioc->spi_data.nvram && (ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                       nvram = ioc->spi_data.nvram[id];
+
+                       if (maxwidth)
+                               maxwidth = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+                       if (maxoffset > 0) {
+                               maxfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+                               if (maxfactor == 0) {
+                                       /* Key for async */
+                                       maxfactor = MPT_ASYNC;
+                                       maxoffset = 0;
+                               } else if (maxfactor < ioc->spi_data.minSyncFactor) {
+                                       maxfactor = ioc->spi_data.minSyncFactor;
+                               }
+                       } else
+                               maxfactor = MPT_ASYNC;
+               }
 
-       /* Add a SGE to the config request.
-        */
-       flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
-               (IOCPage4Ptr->Header.PageLength + ii) * 4;
+               /* Set the negotiation flags.
+                */
+               negoFlags = ioc->spi_data.noQas;
+               if (!maxwidth)
+                       negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
 
-       mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+               if (!maxoffset)
+                       negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
 
-       dinitprintk((MYIOC_s_INFO_FMT
+               if (flags & MPT_SCSICFG_USE_NVRAM) {
+                       width = maxwidth;
+                       factor = maxfactor;
+                       offset = maxoffset;
+               } else {
+                       width = 0;
+                       factor = MPT_ASYNC;
+                       offset = 0;
+                       //negoFlags = 0;
+                       //negoFlags = MPT_TARGET_NO_NEGO_SYNC;
+               }
+
+               /* If id is not a raid volume, get the updated
+                * transmission settings from the target structure.
+                */
+               if (hd->Targets && (vtarget = hd->Targets[id]) && !vtarget->raidVolume) {
+                       width = vtarget->maxWidth;
+                       factor = vtarget->minSyncFactor;
+                       offset = vtarget->maxOffset;
+                       negoFlags = vtarget->negoFlags;
+               }
+
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+               /* Force to async and narrow if DV has not been executed
+                * for this ID
+                */
+               if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
+                       width = 0;
+                       factor = MPT_ASYNC;
+                       offset = 0;
+               }
+#endif
+
+               if (flags & MPT_SCSICFG_BLK_NEGO)
+                       negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC;
+
+               mptscsih_setDevicePage1Flags(width, factor, offset,
+                                       &requested, &configuration, negoFlags);
+               dnegoprintk(("writeSDP1: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
+                       target_id, width, factor, offset, negoFlags, requested, configuration));
+
+               /* Get a MF for this command.
+                */
+               if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
+                       dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n",
+                               ioc->name));
+                       return -EAGAIN;
+               }
+
+               ddvprintk((MYIOC_s_INFO_FMT "WriteSDP1 (mf=%p, id=%d, req=0x%x, cfg=0x%x)\n",
+                       hd->ioc->name, mf, id, requested, configuration));
+
+
+               /* Set the request and the data pointers.
+                * Request takes: 36 bytes (32 bit SGE)
+                * SCSI Device Page 1 requires 16 bytes
+                * 40 + 16 <= size of SCSI IO Request = 56 bytes
+                * and MF size >= 64 bytes.
+                * Place data at end of MF.
+                */
+               pReq = (Config_t *)mf;
+
+               req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+               frameOffset = ioc->req_sz - sizeof(SCSIDevicePage1_t);
+
+               pData = (SCSIDevicePage1_t *)((u8 *) mf + frameOffset);
+               dataDma = ioc->req_frames_dma + (req_idx * ioc->req_sz) + frameOffset;
+
+               /* Complete the request frame (same for all requests).
+                */
+               pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               pReq->Reserved = 0;
+               pReq->ChainOffset = 0;
+               pReq->Function = MPI_FUNCTION_CONFIG;
+               pReq->ExtPageLength = 0;
+               pReq->ExtPageType = 0;
+               pReq->MsgFlags = 0;
+               for (ii=0; ii < 8; ii++) {
+                       pReq->Reserved2[ii] = 0;
+               }
+               pReq->Header.PageVersion = ioc->spi_data.sdp1version;
+               pReq->Header.PageLength = ioc->spi_data.sdp1length;
+               pReq->Header.PageNumber = 1;
+               pReq->Header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+               pReq->PageAddress = cpu_to_le32(id | (bus << 8 ));
+
+               /* Add a SGE to the config request.
+                */
+               flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | ioc->spi_data.sdp1length * 4;
+
+               mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+
+               /* Set up the common data portion
+                */
+               pData->Header.PageVersion = pReq->Header.PageVersion;
+               pData->Header.PageLength = pReq->Header.PageLength;
+               pData->Header.PageNumber = pReq->Header.PageNumber;
+               pData->Header.PageType = pReq->Header.PageType;
+               pData->RequestedParameters = cpu_to_le32(requested);
+               pData->Reserved = 0;
+               pData->Configuration = cpu_to_le32(configuration);
+
+               dprintk((MYIOC_s_INFO_FMT
+                       "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n",
+                               ioc->name, id, (id | (bus<<8)),
+                               requested, configuration));
+
+               mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
+       }
+
+       return 0;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_writeIOCPage4  - write IOC Page 4
+ *     @hd: Pointer to a SCSI Host Structure
+ *     @target_id: write IOC Page4 for this ID & Bus
+ *
+ *     Return: -EAGAIN if unable to obtain a Message Frame
+ *             or 0 if success.
+ *
+ *     Remark: We do not wait for a return, write pages sequentially.
+ */
+static int
+mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
+{
+       MPT_ADAPTER             *ioc = hd->ioc;
+       Config_t                *pReq;
+       IOCPage4_t              *IOCPage4Ptr;
+       MPT_FRAME_HDR           *mf;
+       dma_addr_t               dataDma;
+       u16                      req_idx;
+       u32                      frameOffset;
+       u32                      flagsLength;
+       int                      ii;
+
+       /* Get a MF for this command.
+        */
+       if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
+               dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
+                                       ioc->name));
+               return -EAGAIN;
+       }
+
+       /* Set the request and the data pointers.
+        * Place data at end of MF.
+        */
+       pReq = (Config_t *)mf;
+
+       req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+       frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
+
+       /* Complete the request frame (same for all requests).
+        */
+       pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+       pReq->Reserved = 0;
+       pReq->ChainOffset = 0;
+       pReq->Function = MPI_FUNCTION_CONFIG;
+       pReq->ExtPageLength = 0;
+       pReq->ExtPageType = 0;
+       pReq->MsgFlags = 0;
+       for (ii=0; ii < 8; ii++) {
+               pReq->Reserved2[ii] = 0;
+       }
+
+               IOCPage4Ptr = ioc->spi_data.pIocPg4;
+               dataDma = ioc->spi_data.IocPg4_dma;
+               ii = IOCPage4Ptr->ActiveSEP++;
+               IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
+               IOCPage4Ptr->SEP[ii].SEPBus = bus;
+               pReq->Header = IOCPage4Ptr->Header;
+       pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
+
+       /* Add a SGE to the config request.
+        */
+       flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
+               (IOCPage4Ptr->Header.PageLength + ii) * 4;
+
+       mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+
+       dinitprintk((MYIOC_s_INFO_FMT
                "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
                        ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
 
@@ -3060,7 +3465,6 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                                        completionCode = MPT_SCANDV_GOOD;
                                else
                                        completionCode = MPT_SCANDV_SOME_ERROR;
-                               memcpy(hd->pLocal->sense, pr, sizeof(hd->pLocal->sense));
 
                        } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
                                u8              *sense_data;
@@ -3174,6 +3578,78 @@ mptscsih_timer_expired(unsigned long data)
        return;
 }
 
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_do_raid - Format and Issue a RAID volume request message.
+ *     @hd: Pointer to scsi host structure
+ *     @action: What do be done.
+ *     @id: Logical target id.
+ *     @bus: Target locations bus.
+ *
+ *     Returns: < 0 on a fatal error
+ *             0 on success
+ *
+ *     Remark: Wait to return until reply processed by the ISR.
+ */
+static int
+mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io)
+{
+       MpiRaidActionRequest_t  *pReq;
+       MPT_FRAME_HDR           *mf;
+       int                     in_isr;
+
+       in_isr = in_interrupt();
+       if (in_isr) {
+               dprintk((MYIOC_s_WARN_FMT "Internal raid request not allowed in ISR context!\n",
+                                       hd->ioc->name));
+               return -EPERM;
+       }
+
+       /* Get and Populate a free Frame
+        */
+       if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
+               ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+                                       hd->ioc->name));
+               return -EAGAIN;
+       }
+       pReq = (MpiRaidActionRequest_t *)mf;
+       pReq->Action = action;
+       pReq->Reserved1 = 0;
+       pReq->ChainOffset = 0;
+       pReq->Function = MPI_FUNCTION_RAID_ACTION;
+       pReq->VolumeID = io->id;
+       pReq->VolumeBus = io->bus;
+       pReq->PhysDiskNum = io->physDiskNum;
+       pReq->MsgFlags = 0;
+       pReq->Reserved2 = 0;
+       pReq->ActionDataWord = 0; /* Reserved for this action */
+       //pReq->ActionDataSGE = 0;
+
+       mpt_add_sge((char *)&pReq->ActionDataSGE,
+               MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
+
+       ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
+                       hd->ioc->name, action, io->id));
+
+       hd->pLocal = NULL;
+       hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
+       hd->scandv_wait_done = 0;
+
+       /* Save cmd pointer, for resource free if timeout or
+        * FW reload occurs
+        */
+       hd->cmdPtr = mf;
+
+       add_timer(&hd->timer);
+       mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
+       wait_event(hd->scandv_waitq, hd->scandv_wait_done);
+
+       if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD))
+               return -1;
+
+       return 0;
+}
+#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -3425,6 +3901,93 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
        return rc;
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_negotiate_to_asyn_narrow - Restore devices to default state
+ *     @hd: Pointer to a SCSI HOST structure
+ *     @vtarget: per device private data
+ *
+ *     Uses the ISR, but with special processing.
+ *     MUST be single-threaded.
+ *
+ */
+static void
+mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
+{
+       VirtTarget              *vtarget = vdevice->vtarget;
+       MPT_ADAPTER             *ioc= hd->ioc;
+       SCSIDevicePage1_t       *pcfg1Data;
+       CONFIGPARMS              cfg;
+       dma_addr_t               cfg1_dma_addr;
+       ConfigPageHeader_t       header;
+       int                      id;
+       int                      requested, configuration, data,i;
+       u8                       flags, factor;
+
+       if ((ioc->bus_type != SPI) ||
+               (!vdevice->configured_lun))
+               return;
+
+       if (!ioc->spi_data.sdp1length)
+               return;
+
+       pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev,
+                ioc->spi_data.sdp1length * 4, &cfg1_dma_addr);
+
+       if (pcfg1Data == NULL)
+               return;
+
+       header.PageVersion = ioc->spi_data.sdp1version;
+       header.PageLength = ioc->spi_data.sdp1length;
+       header.PageNumber = 1;
+       header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+       cfg.cfghdr.hdr = &header;
+       cfg.physAddr = cfg1_dma_addr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+       cfg.dir = 1;
+       cfg.timeout = 0;
+
+       if (vtarget->raidVolume && ioc->raid_data.pIocPg3) {
+               for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+                       id = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID;
+                       flags = hd->ioc->spi_data.noQas;
+                       if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                               data = hd->ioc->spi_data.nvram[id];
+                               if (data & MPT_NVRAM_WIDE_DISABLE)
+                                       flags |= MPT_TARGET_NO_NEGO_WIDE;
+                               factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
+                               if ((factor == 0) || (factor == MPT_ASYNC))
+                                       flags |= MPT_TARGET_NO_NEGO_SYNC;
+                       }
+                       mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
+                               &configuration, flags);
+                       dnegoprintk(("nego asyn narrow: id=%d width=0 factor=MPT_ASYNC "
+                               "offset=0 negoFlags=%x request=%x config=%x\n",
+                               id, flags, requested, configuration));
+                       pcfg1Data->RequestedParameters = cpu_to_le32(requested);
+                       pcfg1Data->Reserved = 0;
+                       pcfg1Data->Configuration = cpu_to_le32(configuration);
+                       cfg.pageAddr = (vtarget->bus_id<<8) | id;
+                       mpt_config(hd->ioc, &cfg);
+               }
+       } else {
+               flags = vtarget->negoFlags;
+               mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested,
+                               &configuration, flags);
+               dnegoprintk(("nego asyn narrow: id=%d width=0 factor=MPT_ASYNC "
+                       "offset=0 negoFlags=%x request=%x config=%x\n",
+                       vtarget->target_id, flags, requested, configuration));
+               pcfg1Data->RequestedParameters = cpu_to_le32(requested);
+               pcfg1Data->Reserved = 0;
+               pcfg1Data->Configuration = cpu_to_le32(configuration);
+               cfg.pageAddr = (vtarget->bus_id<<8) | vtarget->target_id;
+               mpt_config(hd->ioc, &cfg);
+       }
+
+       if (pcfg1Data)
+               pci_free_consistent(ioc->pcidev, header.PageLength * 4, pcfg1Data, cfg1_dma_addr);
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *     mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks.
@@ -3451,15 +4014,1637 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
        iocmd.data_dma = -1;
        iocmd.size = 0;
        iocmd.rsvd = iocmd.rsvd2 = 0;
-       iocmd.bus = vdevice->vtarget->bus_id;
-       iocmd.id = vdevice->vtarget->target_id;
+       iocmd.bus = vdevice->bus_id;
+       iocmd.id = vdevice->target_id;
        iocmd.lun = (u8)vdevice->lun;
 
-       if ((vdevice->vtarget->type == TYPE_DISK) &&
+       if ((vdevice->vtarget->type & TYPE_DISK) &&
            (vdevice->configured_lun))
                mptscsih_do_cmd(hd, &iocmd);
 }
 
+/* Search IOC page 3 to determine if this is hidden physical disk
+ */
+static int
+mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
+{
+       int i;
+
+       if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
+               return 0;
+
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
+                       return 1;
+       }
+
+       return 0;
+}
+
+#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_domainValidation - Top level handler for domain validation.
+ *     @hd: Pointer to MPT_SCSI_HOST structure.
+ *
+ *     Uses the ISR, but with special processing.
+ *     Called from schedule, should not be in interrupt mode.
+ *     While thread alive, do dv for all devices needing dv
+ *
+ *     Return: None.
+ */
+static void
+mptscsih_domainValidation(void *arg)
+{
+       MPT_SCSI_HOST           *hd;
+       MPT_ADAPTER             *ioc;
+       unsigned long            flags;
+       int                      id, maxid, dvStatus, did;
+       int                      ii, isPhysDisk;
+
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       dvtaskQ_active = 1;
+       if (dvtaskQ_release) {
+               dvtaskQ_active = 0;
+               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+       /* For this ioc, loop through all devices and do dv to each device.
+        * When complete with this ioc, search through the ioc list, and
+        * for each scsi ioc found, do dv for all devices. Exit when no
+        * device needs dv.
+        */
+       did = 1;
+       while (did) {
+               did = 0;
+               list_for_each_entry(ioc, &ioc_list, list) {
+                       spin_lock_irqsave(&dvtaskQ_lock, flags);
+                       if (dvtaskQ_release) {
+                               dvtaskQ_active = 0;
+                               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                               return;
+                       }
+                       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+                       msleep(250);
+
+                       /* DV only to SPI adapters */
+                       if (ioc->bus_type != SPI)
+                               continue;
+
+                       /* Make sure everything looks ok */
+                       if (ioc->sh == NULL)
+                               continue;
+
+                       hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+                       if (hd == NULL)
+                               continue;
+
+                       if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) {
+                               mpt_read_ioc_pg_3(ioc);
+                               if (ioc->raid_data.pIocPg3) {
+                                       Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk;
+                                       int             numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
+
+                                       while (numPDisk) {
+                                               if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE)
+                                                       ioc->spi_data.dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+
+                                               pPDisk++;
+                                               numPDisk--;
+                                       }
+                               }
+                               ioc->spi_data.forceDv &= ~MPT_SCSICFG_RELOAD_IOC_PG3;
+                       }
+
+                       maxid = min_t(int, ioc->sh->max_id, MPT_MAX_SCSI_DEVICES);
+
+                       for (id = 0; id < maxid; id++) {
+                               spin_lock_irqsave(&dvtaskQ_lock, flags);
+                               if (dvtaskQ_release) {
+                                       dvtaskQ_active = 0;
+                                       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                                       return;
+                               }
+                               spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+                               dvStatus = hd->ioc->spi_data.dvStatus[id];
+
+                               if (dvStatus & MPT_SCSICFG_NEED_DV) {
+                                       did++;
+                                       hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
+                                       hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
+
+                                       msleep(250);
+
+                                       /* If hidden phys disk, block IO's to all
+                                        *      raid volumes
+                                        * else, process normally
+                                        */
+                                       isPhysDisk = mptscsih_is_phys_disk(ioc, id);
+                                       if (isPhysDisk) {
+                                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                                       if (hd->ioc->raid_data.isRaid & (1 << ii)) {
+                                                               hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING;
+                                                       }
+                                               }
+                                       }
+
+                                       if(mpt_alt_ioc_wait(hd->ioc)!=0) {
+                                               ddvprintk((MYIOC_s_WARN_FMT "alt_ioc busy!\n",
+                                                   hd->ioc->name));
+                                               continue;
+                                       }
+
+                                       if (mptscsih_doDv(hd, 0, id) == 1) {
+                                               /* Untagged device was busy, try again
+                                                */
+                                               hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
+                                               hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+                                       } else {
+                                               /* DV is complete. Clear flags.
+                                                */
+                                               hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
+                                       }
+
+                                       spin_lock(&hd->ioc->initializing_hba_lock);
+                                       hd->ioc->initializing_hba_lock_flag=0;
+                                       spin_unlock(&hd->ioc->initializing_hba_lock);
+
+                                       if (isPhysDisk) {
+                                               for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+                                                       if (hd->ioc->raid_data.isRaid & (1 << ii)) {
+                                                               hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING;
+                                                       }
+                                               }
+                                       }
+
+                                       if (hd->ioc->spi_data.noQas)
+                                               mptscsih_qas_check(hd, id);
+                               }
+                       }
+               }
+       }
+
+       spin_lock_irqsave(&dvtaskQ_lock, flags);
+       dvtaskQ_active = 0;
+       spin_unlock_irqrestore(&dvtaskQ_lock, flags);
+
+       return;
+}
+
+/* Write SDP1 if no QAS has been enabled
+ */
+static void
+mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
+{
+       VirtTarget *vtarget;
+       int ii;
+
+       if (hd->Targets == NULL)
+               return;
+
+       for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+               if (ii == id)
+                       continue;
+
+               if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
+                       continue;
+
+               vtarget = hd->Targets[ii];
+
+               if ((vtarget != NULL) && (!vtarget->raidVolume)) {
+                       if ((vtarget->negoFlags & hd->ioc->spi_data.noQas) == 0) {
+                               vtarget->negoFlags |= hd->ioc->spi_data.noQas;
+                               dnegoprintk(("writeSDP1: id=%d flags=0\n", id));
+                               mptscsih_writeSDP1(hd, 0, ii, 0);
+                       }
+               } else {
+                       if (mptscsih_is_phys_disk(hd->ioc, ii) == 1) {
+                               dnegoprintk(("writeSDP1: id=%d SCSICFG_USE_NVRAM\n", id));
+                               mptscsih_writeSDP1(hd, 0, ii, MPT_SCSICFG_USE_NVRAM);
+                       }
+               }
+       }
+       return;
+}
+
+
+
+#define MPT_GET_NVRAM_VALS     0x01
+#define MPT_UPDATE_MAX         0x02
+#define MPT_SET_MAX            0x04
+#define MPT_SET_MIN            0x08
+#define MPT_FALLBACK           0x10
+#define MPT_SAVE               0x20
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptscsih_doDv - Perform domain validation to a target.
+ *     @hd: Pointer to MPT_SCSI_HOST structure.
+ *     @portnum: IOC port number.
+ *     @target: Physical ID of this target
+ *
+ *     Uses the ISR, but with special processing.
+ *     MUST be single-threaded.
+ *     Test will exit if target is at async & narrow.
+ *
+ *     Return: None.
+ */
+static int
+mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
+{
+       MPT_ADAPTER             *ioc = hd->ioc;
+       VirtTarget              *vtarget;
+       SCSIDevicePage1_t       *pcfg1Data;
+       SCSIDevicePage0_t       *pcfg0Data;
+       u8                      *pbuf1;
+       u8                      *pbuf2;
+       u8                      *pDvBuf;
+       dma_addr_t               dvbuf_dma = -1;
+       dma_addr_t               buf1_dma = -1;
+       dma_addr_t               buf2_dma = -1;
+       dma_addr_t               cfg1_dma_addr = -1;
+       dma_addr_t               cfg0_dma_addr = -1;
+       ConfigPageHeader_t       header1;
+       ConfigPageHeader_t       header0;
+       DVPARAMETERS             dv;
+       INTERNAL_CMD             iocmd;
+       CONFIGPARMS              cfg;
+       int                      dv_alloc = 0;
+       int                      rc, sz = 0;
+       int                      bufsize = 0;
+       int                      dataBufSize = 0;
+       int                      echoBufSize = 0;
+       int                      notDone;
+       int                      patt;
+       int                      repeat;
+       int                      retcode = 0;
+       int                      nfactor =  MPT_ULTRA320;
+       char                     firstPass = 1;
+       char                     doFallback = 0;
+       char                     readPage0;
+       char                     bus, lun;
+       char                     inq0 = 0;
+
+       if (ioc->spi_data.sdp1length == 0)
+               return 0;
+
+       if (ioc->spi_data.sdp0length == 0)
+               return 0;
+
+       /* If multiple buses are used, require that the initiator
+        * id be the same on all buses.
+        */
+       if (id == ioc->pfacts[0].PortSCSIID)
+               return 0;
+
+       lun = 0;
+       bus = (u8) bus_number;
+       ddvtprintk((MYIOC_s_NOTE_FMT
+                       "DV started: bus=%d, id=%d dv @ %p\n",
+                       ioc->name, bus, id, &dv));
+
+       /* Prep DV structure
+        */
+       memset (&dv, 0, sizeof(DVPARAMETERS));
+       dv.id = id;
+
+       /* Populate tmax with the current maximum
+        * transfer parameters for this target.
+        * Exit if narrow and async.
+        */
+       dv.cmd = MPT_GET_NVRAM_VALS;
+       mptscsih_dv_parms(hd, &dv, NULL);
+
+       /* Prep SCSI IO structure
+        */
+       iocmd.id = id;
+       iocmd.bus = bus;
+       iocmd.lun = lun;
+       iocmd.flags = 0;
+       iocmd.physDiskNum = -1;
+       iocmd.rsvd = iocmd.rsvd2 = 0;
+
+       vtarget = hd->Targets[id];
+
+       /* Use tagged commands if possible.
+        */
+       if (vtarget) {
+               if (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+                       iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
+               else {
+                       if (hd->ioc->facts.FWVersion.Word < 0x01000600)
+                               return 0;
+
+                       if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+                               (hd->ioc->facts.FWVersion.Word < 0x01010B00))
+                               return 0;
+               }
+       }
+
+       /* Prep cfg structure
+        */
+       cfg.pageAddr = (bus<<8) | id;
+       cfg.cfghdr.hdr = NULL;
+
+       /* Prep SDP0 header
+        */
+       header0.PageVersion = ioc->spi_data.sdp0version;
+       header0.PageLength = ioc->spi_data.sdp0length;
+       header0.PageNumber = 0;
+       header0.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+       /* Prep SDP1 header
+        */
+       header1.PageVersion = ioc->spi_data.sdp1version;
+       header1.PageLength = ioc->spi_data.sdp1length;
+       header1.PageNumber = 1;
+       header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+       if (header0.PageLength & 1)
+               dv_alloc = (header0.PageLength * 4) + 4;
+
+       dv_alloc +=  (2048 + (header1.PageLength * 4));
+
+       pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
+       if (pDvBuf == NULL)
+               return 0;
+
+       sz = 0;
+       pbuf1 = (u8 *)pDvBuf;
+       buf1_dma = dvbuf_dma;
+       sz +=1024;
+
+       pbuf2 = (u8 *) (pDvBuf + sz);
+       buf2_dma = dvbuf_dma + sz;
+       sz +=1024;
+
+       pcfg0Data = (SCSIDevicePage0_t *) (pDvBuf + sz);
+       cfg0_dma_addr = dvbuf_dma + sz;
+       sz += header0.PageLength * 4;
+
+       /* 8-byte alignment
+        */
+       if (header0.PageLength & 1)
+               sz += 4;
+
+       pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz);
+       cfg1_dma_addr = dvbuf_dma + sz;
+
+       /* Skip this ID? Set cfg.cfghdr.hdr to force config page write
+        */
+       {
+               SpiCfgData *pspi_data = &hd->ioc->spi_data;
+               if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                       /* Set the factor from nvram */
+                       nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8;
+                       if (nfactor < pspi_data->minSyncFactor )
+                               nfactor = pspi_data->minSyncFactor;
+
+                       if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) ||
+                               (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) {
+
+                               ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n",
+                                       ioc->name, bus, id, lun));
+
+                               dv.cmd = MPT_SET_MAX;
+                               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+                               cfg.cfghdr.hdr = &header1;
+
+                               /* Save the final negotiated settings to
+                                * SCSI device page 1.
+                                */
+                               cfg.physAddr = cfg1_dma_addr;
+                               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+                               cfg.dir = 1;
+                               mpt_config(hd->ioc, &cfg);
+                               goto target_done;
+                       }
+               }
+       }
+
+       /* Finish iocmd inititialization - hidden or visible disk? */
+       if (ioc->raid_data.pIocPg3) {
+               /* Search IOC page 3 for matching id
+                */
+               Ioc3PhysDisk_t *pPDisk =  ioc->raid_data.pIocPg3->PhysDisk;
+               int             numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
+
+               while (numPDisk) {
+                       if (pPDisk->PhysDiskID == id) {
+                               /* match */
+                               iocmd.flags |= MPT_ICFLAG_PHYS_DISK;
+                               iocmd.physDiskNum = pPDisk->PhysDiskNum;
+
+                               /* Quiesce the IM
+                                */
+                               if (mptscsih_do_raid(hd, MPI_RAID_ACTION_QUIESCE_PHYS_IO, &iocmd) < 0) {
+                                       ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+                                       goto target_done;
+                               }
+                               break;
+                       }
+                       pPDisk++;
+                       numPDisk--;
+               }
+       }
+
+       /* RAID Volume ID's may double for a physical device. If RAID but
+        * not a physical ID as well, skip DV.
+        */
+       if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK))
+               goto target_done;
+
+
+       /* Basic Test.
+        * Async & Narrow - Inquiry
+        * Async & Narrow - Inquiry
+        * Maximum transfer rate - Inquiry
+        * Compare buffers:
+        *      If compare, test complete.
+        *      If miscompare and first pass, repeat
+        *      If miscompare and not first pass, fall back and repeat
+        */
+       hd->pLocal = NULL;
+       readPage0 = 0;
+       sz = SCSI_MAX_INQUIRY_BYTES;
+       rc = MPT_SCANDV_GOOD;
+       while (1) {
+               ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id));
+               retcode = 0;
+               dv.cmd = MPT_SET_MIN;
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+               cfg.cfghdr.hdr = &header1;
+               cfg.physAddr = cfg1_dma_addr;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               cfg.dir = 1;
+               if (mpt_config(hd->ioc, &cfg) != 0)
+                       goto target_done;
+
+               /* Wide - narrow - wide workaround case
+                */
+               if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) {
+                       /* Send an untagged command to reset disk Qs corrupted
+                        * when a parity error occurs on a Request Sense.
+                        */
+                       if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) ||
+                               ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+                               (hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
+
+                               iocmd.cmd = REQUEST_SENSE;
+                               iocmd.data_dma = buf1_dma;
+                               iocmd.data = pbuf1;
+                               iocmd.size = 0x12;
+                               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                                       goto target_done;
+                               else {
+                                       if (hd->pLocal == NULL)
+                                               goto target_done;
+                                       rc = hd->pLocal->completion;
+                                       if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
+                                               dv.max.width = 0;
+                                               doFallback = 0;
+                                       } else
+                                               goto target_done;
+                               }
+                       } else
+                               goto target_done;
+               }
+
+               iocmd.cmd = INQUIRY;
+               iocmd.data_dma = buf1_dma;
+               iocmd.data = pbuf1;
+               iocmd.size = sz;
+               memset(pbuf1, 0x00, sz);
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else {
+                       if (hd->pLocal == NULL)
+                               goto target_done;
+                       rc = hd->pLocal->completion;
+                       if (rc == MPT_SCANDV_GOOD) {
+                               if (hd->pLocal->scsiStatus == SAM_STAT_BUSY) {
+                                       if ((iocmd.flags & MPT_ICFLAG_TAGGED_CMD) == 0)
+                                               retcode = 1;
+                                       else
+                                               retcode = 0;
+
+                                       goto target_done;
+                               }
+                       } else if  (rc == MPT_SCANDV_SENSE) {
+                               ;
+                       } else {
+                               /* If first command doesn't complete
+                                * with a good status or with a check condition,
+                                * exit.
+                                */
+                               goto target_done;
+                       }
+               }
+
+               /* Reset the size for disks
+                */
+               inq0 = (*pbuf1) & 0x1F;
+               if ((inq0 == 0) && vtarget && !vtarget->raidVolume) {
+                       sz = 0x40;
+                       iocmd.size = sz;
+               }
+
+               /* Another GEM workaround. Check peripheral device type,
+                * if PROCESSOR, quit DV.
+                */
+               if (inq0 == TYPE_PROCESSOR) {
+                       mptscsih_initTarget(hd,
+                               vtarget,
+                               lun,
+                               pbuf1,
+                               sz);
+                       goto target_done;
+               }
+
+               if (inq0 > 0x08)
+                       goto target_done;
+
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+
+               if (sz == 0x40) {
+                       if ((vtarget->maxWidth == 1) && (vtarget->maxOffset) && (nfactor < 0x0A)
+                               && (vtarget->minSyncFactor > 0x09)) {
+                               if ((pbuf1[56] & 0x04) == 0)
+                                       ;
+                               else if ((pbuf1[56] & 0x01) == 1) {
+                                       vtarget->minSyncFactor =
+                                           nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
+                               } else {
+                                       vtarget->minSyncFactor =
+                                           nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
+                               }
+
+                               dv.max.factor = vtarget->minSyncFactor;
+
+                               if ((pbuf1[56] & 0x02) == 0) {
+                                       vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+                                       hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
+                                       ddvprintk((MYIOC_s_NOTE_FMT
+                                           "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n",
+                                           ioc->name, id, pbuf1[56]));
+                               }
+                       }
+               }
+
+               if (doFallback)
+                       dv.cmd = MPT_FALLBACK;
+               else
+                       dv.cmd = MPT_SET_MAX;
+
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+               if (mpt_config(hd->ioc, &cfg) != 0)
+                       goto target_done;
+
+               if ((!dv.now.width) && (!dv.now.offset))
+                       goto target_done;
+
+               iocmd.cmd = INQUIRY;
+               iocmd.data_dma = buf2_dma;
+               iocmd.data = pbuf2;
+               iocmd.size = sz;
+               memset(pbuf2, 0x00, sz);
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       /* Save the return code.
+                        * If this is the first pass,
+                        * read SCSI Device Page 0
+                        * and update the target max parameters.
+                        */
+                       rc = hd->pLocal->completion;
+                       doFallback = 0;
+                       if (rc == MPT_SCANDV_GOOD) {
+                               if (!readPage0) {
+                                       u32 sdp0_info;
+                                       u32 sdp0_nego;
+
+                                       cfg.cfghdr.hdr = &header0;
+                                       cfg.physAddr = cfg0_dma_addr;
+                                       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+                                       cfg.dir = 0;
+
+                                       if (mpt_config(hd->ioc, &cfg) != 0)
+                                               goto target_done;
+
+                                       sdp0_info = le32_to_cpu(pcfg0Data->Information) & 0x0E;
+                                       sdp0_nego = (le32_to_cpu(pcfg0Data->NegotiatedParameters) & 0xFF00 ) >> 8;
+
+                                       /* Quantum and Fujitsu workarounds.
+                                        * Quantum: PPR U320 -> PPR reply with Ultra2 and wide
+                                        * Fujitsu: PPR U320 -> Msg Reject and Ultra2 and wide
+                                        * Resetart with a request for U160.
+                                        */
+                                       if ((dv.now.factor == MPT_ULTRA320) && (sdp0_nego == MPT_ULTRA2)) {
+                                                       doFallback = 1;
+                                       } else {
+                                               dv.cmd = MPT_UPDATE_MAX;
+                                               mptscsih_dv_parms(hd, &dv, (void *)pcfg0Data);
+                                               /* Update the SCSI device page 1 area
+                                                */
+                                               pcfg1Data->RequestedParameters = pcfg0Data->NegotiatedParameters;
+                                               readPage0 = 1;
+                                       }
+                               }
+
+                               /* Quantum workaround. Restart this test will the fallback
+                                * flag set.
+                                */
+                               if (doFallback == 0) {
+                                       if (memcmp(pbuf1, pbuf2, sz) != 0) {
+                                               if (!firstPass)
+                                                       doFallback = 1;
+                                       } else {
+                                               ddvprintk((MYIOC_s_NOTE_FMT
+                                                   "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id));
+                                               hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE;
+                                               mptscsih_initTarget(hd,
+                                                       vtarget,
+                                                       lun,
+                                                       pbuf1,
+                                                       sz);
+                                               break;  /* test complete */
+                                       }
+                               }
+
+
+                       } else if (rc == MPT_SCANDV_ISSUE_SENSE)
+                               doFallback = 1; /* set fallback flag */
+                       else if ((rc == MPT_SCANDV_DID_RESET) ||
+                                (rc == MPT_SCANDV_SENSE) ||
+                                (rc == MPT_SCANDV_FALLBACK))
+                               doFallback = 1; /* set fallback flag */
+                       else
+                               goto target_done;
+
+                       firstPass = 0;
+               }
+       }
+       ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id));
+
+       if (ioc->spi_data.mpt_dv == 0)
+               goto target_done;
+
+       inq0 = (*pbuf1) & 0x1F;
+
+       /* Continue only for disks
+        */
+       if (inq0 != 0)
+               goto target_done;
+
+       if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY )
+               goto target_done;
+
+       /* Start the Enhanced Test.
+        * 0) issue TUR to clear out check conditions
+        * 1) read capacity of echo (regular) buffer
+        * 2) reserve device
+        * 3) do write-read-compare data pattern test
+        * 4) release
+        * 5) update nego parms to target struct
+        */
+       cfg.cfghdr.hdr = &header1;
+       cfg.physAddr = cfg1_dma_addr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+       cfg.dir = 1;
+
+       iocmd.cmd = TEST_UNIT_READY;
+       iocmd.data_dma = -1;
+       iocmd.data = NULL;
+       iocmd.size = 0;
+       notDone = 1;
+       while (notDone) {
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+
+               if (hd->pLocal == NULL)
+                       goto target_done;
+
+               rc = hd->pLocal->completion;
+               if (rc == MPT_SCANDV_GOOD)
+                       notDone = 0;
+               else if (rc == MPT_SCANDV_SENSE) {
+                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                       u8 asc = hd->pLocal->sense[12];
+                       u8 ascq = hd->pLocal->sense[13];
+                       ddvprintk((MYIOC_s_INFO_FMT
+                               "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                               ioc->name, skey, asc, ascq));
+
+                       if (skey == UNIT_ATTENTION)
+                               notDone++; /* repeat */
+                       else if ((skey == NOT_READY) &&
+                                       (asc == 0x04)&&(ascq == 0x01)) {
+                               /* wait then repeat */
+                               mdelay (2000);
+                               notDone++;
+                       } else if ((skey == NOT_READY) && (asc == 0x3A)) {
+                               /* no medium, try read test anyway */
+                               notDone = 0;
+                       } else {
+                               /* All other errors are fatal.
+                                */
+                               ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
+                                               ioc->name));
+                               goto target_done;
+                       }
+               } else
+                       goto target_done;
+       }
+
+       iocmd.cmd = READ_BUFFER;
+       iocmd.data_dma = buf1_dma;
+       iocmd.data = pbuf1;
+       iocmd.size = 4;
+       iocmd.flags |= MPT_ICFLAG_BUF_CAP;
+
+       dataBufSize = 0;
+       echoBufSize = 0;
+       for (patt = 0; patt < 2; patt++) {
+               if (patt == 0)
+                       iocmd.flags |= MPT_ICFLAG_ECHO;
+               else
+                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+
+               notDone = 1;
+               while (notDone) {
+                       bufsize = 0;
+
+                       /* If not ready after 8 trials,
+                        * give up on this device.
+                        */
+                       if (notDone > 8)
+                               goto target_done;
+
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               ddvprintk(("ReadBuffer Comp Code %d", rc));
+                               ddvprintk(("  buff: %0x %0x %0x %0x\n",
+                                       pbuf1[0], pbuf1[1], pbuf1[2], pbuf1[3]));
+
+                               if (rc == MPT_SCANDV_GOOD) {
+                                       notDone = 0;
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               bufsize =  ((pbuf1[2] & 0x1F) <<8) | pbuf1[3];
+                                               if (pbuf1[0] & 0x01)
+                                                       iocmd.flags |= MPT_ICFLAG_EBOS;
+                                       } else {
+                                               bufsize =  pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3];
+                                       }
+                               } else if (rc == MPT_SCANDV_SENSE) {
+                                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                                       u8 asc = hd->pLocal->sense[12];
+                                       u8 ascq = hd->pLocal->sense[13];
+                                       ddvprintk((MYIOC_s_INFO_FMT
+                                               "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                                               ioc->name, skey, asc, ascq));
+                                       if (skey == ILLEGAL_REQUEST) {
+                                               notDone = 0;
+                                       } else if (skey == UNIT_ATTENTION) {
+                                               notDone++; /* repeat */
+                                       } else if ((skey == NOT_READY) &&
+                                               (asc == 0x04)&&(ascq == 0x01)) {
+                                               /* wait then repeat */
+                                               mdelay (2000);
+                                               notDone++;
+                                       } else {
+                                               /* All other errors are fatal.
+                                                */
+                                               ddvprintk((MYIOC_s_INFO_FMT "DV: fatal error.",
+                                                       ioc->name));
+                                               goto target_done;
+                                       }
+                               } else {
+                                       /* All other errors are fatal
+                                        */
+                                       goto target_done;
+                               }
+                       }
+               }
+
+               if (iocmd.flags & MPT_ICFLAG_ECHO)
+                       echoBufSize = bufsize;
+               else
+                       dataBufSize = bufsize;
+       }
+       sz = 0;
+       iocmd.flags &= ~MPT_ICFLAG_BUF_CAP;
+
+       /* Use echo buffers if possible,
+        * Exit if both buffers are 0.
+        */
+       if (echoBufSize > 0) {
+               iocmd.flags |= MPT_ICFLAG_ECHO;
+               if (dataBufSize > 0)
+                       bufsize = min(echoBufSize, dataBufSize);
+               else
+                       bufsize = echoBufSize;
+       } else if (dataBufSize == 0)
+               goto target_done;
+
+       ddvprintk((MYIOC_s_INFO_FMT "%s Buffer Capacity %d\n", ioc->name,
+               (iocmd.flags & MPT_ICFLAG_ECHO) ? "Echo" : " ", bufsize));
+
+       /* Data buffers for write-read-compare test max 1K.
+        */
+       sz = min(bufsize, 1024);
+
+       /* --- loop ----
+        * On first pass, always issue a reserve.
+        * On additional loops, only if a reset has occurred.
+        * iocmd.flags indicates if echo or regular buffer
+        */
+       for (patt = 0; patt < 4; patt++) {
+               ddvprintk(("Pattern %d\n", patt));
+               if ((iocmd.flags & MPT_ICFLAG_RESERVED) && (iocmd.flags & MPT_ICFLAG_DID_RESET)) {
+                       iocmd.cmd = TEST_UNIT_READY;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+
+                       iocmd.cmd = RELEASE;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               ddvprintk(("Release rc %d\n", rc));
+                               if (rc == MPT_SCANDV_GOOD)
+                                       iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+                               else
+                                       goto target_done;
+                       }
+                       iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+               }
+               iocmd.flags &= ~MPT_ICFLAG_DID_RESET;
+
+               if (iocmd.flags & MPT_ICFLAG_EBOS)
+                       goto skip_Reserve;
+
+               repeat = 5;
+               while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
+                       iocmd.cmd = RESERVE;
+                       iocmd.data_dma = -1;
+                       iocmd.data = NULL;
+                       iocmd.size = 0;
+                       if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                               goto target_done;
+                       else if (hd->pLocal == NULL)
+                               goto target_done;
+                       else {
+                               rc = hd->pLocal->completion;
+                               if (rc == MPT_SCANDV_GOOD) {
+                                       iocmd.flags |= MPT_ICFLAG_RESERVED;
+                               } else if (rc == MPT_SCANDV_SENSE) {
+                                       /* Wait if coming ready
+                                        */
+                                       u8 skey = hd->pLocal->sense[2] & 0x0F;
+                                       u8 asc = hd->pLocal->sense[12];
+                                       u8 ascq = hd->pLocal->sense[13];
+                                       ddvprintk((MYIOC_s_INFO_FMT
+                                               "DV: Reserve Failed: ", ioc->name));
+                                       ddvprintk(("SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n",
+                                                       skey, asc, ascq));
+
+                                       if ((skey == NOT_READY) && (asc == 0x04)&&
+                                                                       (ascq == 0x01)) {
+                                               /* wait then repeat */
+                                               mdelay (2000);
+                                               notDone++;
+                                       } else {
+                                               ddvprintk((MYIOC_s_INFO_FMT
+                                                       "DV: Reserved Failed.", ioc->name));
+                                               goto target_done;
+                                       }
+                               } else {
+                                       ddvprintk((MYIOC_s_INFO_FMT "DV: Reserved Failed.",
+                                                        ioc->name));
+                                       goto target_done;
+                               }
+                       }
+               }
+
+skip_Reserve:
+               mptscsih_fillbuf(pbuf1, sz, patt, 1);
+               iocmd.cmd = WRITE_BUFFER;
+               iocmd.data_dma = buf1_dma;
+               iocmd.data = pbuf1;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       rc = hd->pLocal->completion;
+                       if (rc == MPT_SCANDV_GOOD)
+                               ;               /* Issue read buffer */
+                       else if (rc == MPT_SCANDV_DID_RESET) {
+                               /* If using echo buffers, reset to data buffers.
+                                * Else do Fallback and restart
+                                * this test (re-issue reserve
+                                * because of bus reset).
+                                */
+                               if ((iocmd.flags & MPT_ICFLAG_ECHO) && (dataBufSize >= bufsize)) {
+                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                               } else {
+                                       dv.cmd = MPT_FALLBACK;
+                                       mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                                       if (mpt_config(hd->ioc, &cfg) != 0)
+                                               goto target_done;
+
+                                       if ((!dv.now.width) && (!dv.now.offset))
+                                               goto target_done;
+                               }
+
+                               iocmd.flags |= MPT_ICFLAG_DID_RESET;
+                               patt = -1;
+                               continue;
+                       } else if (rc == MPT_SCANDV_SENSE) {
+                               /* Restart data test if UA, else quit.
+                                */
+                               u8 skey = hd->pLocal->sense[2] & 0x0F;
+                               ddvprintk((MYIOC_s_INFO_FMT
+                                       "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
+                                       hd->pLocal->sense[12], hd->pLocal->sense[13]));
+                               if (skey == UNIT_ATTENTION) {
+                                       patt = -1;
+                                       continue;
+                               } else if (skey == ILLEGAL_REQUEST) {
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               if (dataBufSize >= bufsize) {
+                                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                                                       patt = -1;
+                                                       continue;
+                                               }
+                                       }
+                                       goto target_done;
+                               }
+                               else
+                                       goto target_done;
+                       } else {
+                               /* fatal error */
+                               goto target_done;
+                       }
+               }
+
+               iocmd.cmd = READ_BUFFER;
+               iocmd.data_dma = buf2_dma;
+               iocmd.data = pbuf2;
+               iocmd.size = sz;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       goto target_done;
+               else if (hd->pLocal == NULL)
+                       goto target_done;
+               else {
+                       rc = hd->pLocal->completion;
+                       if (rc == MPT_SCANDV_GOOD) {
+                                /* If buffers compare,
+                                 * go to next pattern,
+                                 * else, do a fallback and restart
+                                 * data transfer test.
+                                 */
+                               if (memcmp (pbuf1, pbuf2, sz) == 0) {
+                                       ; /* goto next pattern */
+                               } else {
+                                       /* Miscompare with Echo buffer, go to data buffer,
+                                        * if that buffer exists.
+                                        * Miscompare with Data buffer, check first 4 bytes,
+                                        * some devices return capacity. Exit in this case.
+                                        */
+                                       if (iocmd.flags & MPT_ICFLAG_ECHO) {
+                                               if (dataBufSize >= bufsize)
+                                                       iocmd.flags &= ~MPT_ICFLAG_ECHO;
+                                               else
+                                                       goto target_done;
+                                       } else {
+                                               if (dataBufSize == (pbuf2[1]<<16 | pbuf2[2]<<8 | pbuf2[3])) {
+                                                       /* Argh. Device returning wrong data.
+                                                        * Quit DV for this device.
+                                                        */
+                                                       goto target_done;
+                                               }
+
+                                               /* Had an actual miscompare. Slow down.*/
+                                               dv.cmd = MPT_FALLBACK;
+                                               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                                               if (mpt_config(hd->ioc, &cfg) != 0)
+                                                       goto target_done;
+
+                                               if ((!dv.now.width) && (!dv.now.offset))
+                                                       goto target_done;
+                                       }
+
+                                       patt = -1;
+                                       continue;
+                               }
+                       } else if (rc == MPT_SCANDV_DID_RESET) {
+                               /* Do Fallback and restart
+                                * this test (re-issue reserve
+                                * because of bus reset).
+                                */
+                               dv.cmd = MPT_FALLBACK;
+                               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+                               if (mpt_config(hd->ioc, &cfg) != 0)
+                                        goto target_done;
+
+                               if ((!dv.now.width) && (!dv.now.offset))
+                                       goto target_done;
+
+                               iocmd.flags |= MPT_ICFLAG_DID_RESET;
+                               patt = -1;
+                               continue;
+                       } else if (rc == MPT_SCANDV_SENSE) {
+                               /* Restart data test if UA, else quit.
+                                */
+                               u8 skey = hd->pLocal->sense[2] & 0x0F;
+                               ddvprintk((MYIOC_s_INFO_FMT
+                                       "SenseKey:ASC:ASCQ = (%x:%02x:%02x)\n", ioc->name, skey,
+                                       hd->pLocal->sense[12], hd->pLocal->sense[13]));
+                               if (skey == UNIT_ATTENTION) {
+                                       patt = -1;
+                                       continue;
+                               }
+                               else
+                                       goto target_done;
+                       } else {
+                               /* fatal error */
+                               goto target_done;
+                       }
+               }
+
+       } /* --- end of patt loop ---- */
+
+target_done:
+       if (iocmd.flags & MPT_ICFLAG_RESERVED) {
+               iocmd.cmd = RELEASE;
+               iocmd.data_dma = -1;
+               iocmd.data = NULL;
+               iocmd.size = 0;
+               if (mptscsih_do_cmd(hd, &iocmd) < 0)
+                       printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
+                                       ioc->name, id);
+               else if (hd->pLocal) {
+                       if (hd->pLocal->completion == MPT_SCANDV_GOOD)
+                               iocmd.flags &= ~MPT_ICFLAG_RESERVED;
+               } else {
+                       printk(MYIOC_s_INFO_FMT "DV: Release failed. id %d",
+                                               ioc->name, id);
+               }
+       }
+
+
+       /* Set if cfg1_dma_addr contents is valid
+        */
+       if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){
+               /* If disk, not U320, disable QAS
+                */
+               if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) {
+                       hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
+                       ddvprintk((MYIOC_s_NOTE_FMT
+                           "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor));
+               }
+
+               dv.cmd = MPT_SAVE;
+               mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
+
+               /* Double writes to SDP1 can cause problems,
+                * skip save of the final negotiated settings to
+                * SCSI device page 1.
+                *
+               cfg.cfghdr.hdr = &header1;
+               cfg.physAddr = cfg1_dma_addr;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+               cfg.dir = 1;
+               mpt_config(hd->ioc, &cfg);
+                */
+       }
+
+       /* If this is a RAID Passthrough, enable internal IOs
+        */
+       if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
+               if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
+                       ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
+       }
+
+       /* Done with the DV scan of the current target
+        */
+       if (pDvBuf)
+               pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma);
+
+       ddvtprintk((MYIOC_s_INFO_FMT "DV Done id=%d\n",
+                       ioc->name, id));
+
+       return retcode;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_dv_parms - perform a variety of operations on the
+ *     parameters used for negotiation.
+ *     @hd: Pointer to a SCSI host.
+ *     @dv: Pointer to a structure that contains the maximum and current
+ *             negotiated parameters.
+ */
+static void
+mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage)
+{
+       VirtTarget              *vtarget;
+       SCSIDevicePage0_t       *pPage0;
+       SCSIDevicePage1_t       *pPage1;
+       int                     val = 0, data, configuration;
+       u8                      width = 0;
+       u8                      offset = 0;
+       u8                      factor = 0;
+       u8                      negoFlags = 0;
+       u8                      cmd = dv->cmd;
+       u8                      id = dv->id;
+
+       switch (cmd) {
+       case MPT_GET_NVRAM_VALS:
+               ddvprintk((MYIOC_s_NOTE_FMT "Getting NVRAM: ",
+                                                        hd->ioc->name));
+               /* Get the NVRAM values and save in tmax
+                * If not an LVD bus, the adapter minSyncFactor has been
+                * already throttled back.
+                */
+               negoFlags = hd->ioc->spi_data.noQas;
+               if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume) {
+                       width = vtarget->maxWidth;
+                       offset = vtarget->maxOffset;
+                       factor = vtarget->minSyncFactor;
+                       negoFlags |= vtarget->negoFlags;
+               } else {
+                       if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+                               data = hd->ioc->spi_data.nvram[id];
+                               width = data & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+                               if ((offset = hd->ioc->spi_data.maxSyncOffset) == 0)
+                                       factor = MPT_ASYNC;
+                               else {
+                                       factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
+                                       if ((factor == 0) || (factor == MPT_ASYNC)){
+                                               factor = MPT_ASYNC;
+                                               offset = 0;
+                                       }
+                               }
+                       } else {
+                               width = MPT_NARROW;
+                               offset = 0;
+                               factor = MPT_ASYNC;
+                       }
+
+                       /* Set the negotiation flags */
+                       if (!width)
+                               negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+                       if (!offset)
+                               negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+               }
+
+               /* limit by adapter capabilities */
+               width = min(width, hd->ioc->spi_data.maxBusWidth);
+               offset = min(offset, hd->ioc->spi_data.maxSyncOffset);
+               factor = max(factor, hd->ioc->spi_data.minSyncFactor);
+
+               /* Check Consistency */
+               if (offset && (factor < MPT_ULTRA2) && !width)
+                       factor = MPT_ULTRA2;
+
+               dv->max.width = width;
+               dv->max.offset = offset;
+               dv->max.factor = factor;
+               dv->max.flags = negoFlags;
+               ddvprintk((" id=%d width=%d factor=%x offset=%x flags=%x\n",
+                               id, width, factor, offset, negoFlags));
+               break;
+
+       case MPT_UPDATE_MAX:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Updating with SDP0 Data: ", hd->ioc->name));
+               /* Update tmax values with those from Device Page 0.*/
+               pPage0 = (SCSIDevicePage0_t *) pPage;
+               if (pPage0) {
+                       val = le32_to_cpu(pPage0->NegotiatedParameters);
+                       dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0;
+                       dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16;
+                       dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
+               }
+
+               dv->now.width = dv->max.width;
+               dv->now.offset = dv->max.offset;
+               dv->now.factor = dv->max.factor;
+               ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x\n",
+                               id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
+               break;
+
+       case MPT_SET_MAX:
+               ddvprintk((MYIOC_s_NOTE_FMT "Setting Max: ",
+                                                               hd->ioc->name));
+               /* Set current to the max values. Update the config page.*/
+               dv->now.width = dv->max.width;
+               dv->now.offset = dv->max.offset;
+               dv->now.factor = dv->max.factor;
+               dv->now.flags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (dv->now.width, dv->now.factor,
+                               dv->now.offset, &val, &configuration, dv->now.flags);
+                       dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
+                               id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
+                       pPage1->RequestedParameters = cpu_to_le32(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = cpu_to_le32(configuration);
+               }
+
+               ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n",
+                               id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration));
+               break;
+
+       case MPT_SET_MIN:
+               ddvprintk((MYIOC_s_NOTE_FMT "Setting Min: ",
+                                                               hd->ioc->name));
+               /* Set page to asynchronous and narrow
+                * Do not update now, breaks fallback routine. */
+               width = MPT_NARROW;
+               offset = 0;
+               factor = MPT_ASYNC;
+               negoFlags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (width, factor,
+                               offset, &val, &configuration, negoFlags);
+                       dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n",
+                               id, width, factor, offset, negoFlags, val, configuration));
+                       pPage1->RequestedParameters = cpu_to_le32(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = cpu_to_le32(configuration);
+               }
+               ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n",
+                               id, width, factor, offset, val, configuration, negoFlags));
+               break;
+
+       case MPT_FALLBACK:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Fallback: Start: offset %d, factor %x, width %d \n",
+                               hd->ioc->name, dv->now.offset,
+                               dv->now.factor, dv->now.width));
+               width = dv->now.width;
+               offset = dv->now.offset;
+               factor = dv->now.factor;
+               if ((offset) && (dv->max.width)) {
+                       if (factor < MPT_ULTRA160)
+                               factor = MPT_ULTRA160;
+                       else if (factor < MPT_ULTRA2) {
+                               factor = MPT_ULTRA2;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_ULTRA2) && width) {
+                               factor = MPT_ULTRA2;
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_ULTRA) {
+                               factor = MPT_ULTRA;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_ULTRA) && width) {
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_FAST) {
+                               factor = MPT_FAST;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_FAST) && width) {
+                               factor = MPT_FAST;
+                               width = MPT_NARROW;
+                       } else if (factor < MPT_SCSI) {
+                               factor = MPT_SCSI;
+                               width = MPT_WIDE;
+                       } else if ((factor == MPT_SCSI) && width) {
+                               factor = MPT_SCSI;
+                               width = MPT_NARROW;
+                       } else {
+                               factor = MPT_ASYNC;
+                               offset = 0;
+                       }
+
+               } else if (offset) {
+                       width = MPT_NARROW;
+                       if (factor < MPT_ULTRA)
+                               factor = MPT_ULTRA;
+                       else if (factor < MPT_FAST)
+                               factor = MPT_FAST;
+                       else if (factor < MPT_SCSI)
+                               factor = MPT_SCSI;
+                       else {
+                               factor = MPT_ASYNC;
+                               offset = 0;
+                       }
+
+               } else {
+                       width = MPT_NARROW;
+                       factor = MPT_ASYNC;
+               }
+               dv->max.flags |= MPT_TARGET_NO_NEGO_QAS;
+               dv->max.flags &= ~MPT_TAPE_NEGO_IDP;
+
+               dv->now.width = width;
+               dv->now.offset = offset;
+               dv->now.factor = factor;
+               dv->now.flags = dv->max.flags;
+
+               pPage1 = (SCSIDevicePage1_t *)pPage;
+               if (pPage1) {
+                       mptscsih_setDevicePage1Flags (width, factor, offset, &val,
+                                               &configuration, dv->now.flags);
+                       dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n",
+                            id, width, offset, factor, dv->now.flags, val, configuration));
+
+                       pPage1->RequestedParameters = cpu_to_le32(val);
+                       pPage1->Reserved = 0;
+                       pPage1->Configuration = cpu_to_le32(configuration);
+               }
+
+               ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n",
+                            id, dv->now.offset, dv->now.factor, dv->now.width, val, configuration));
+               break;
+
+       case MPT_SAVE:
+               ddvprintk((MYIOC_s_NOTE_FMT
+                       "Saving to Target structure: ", hd->ioc->name));
+               ddvprintk(("id=%d width=%x factor=%x offset=%d flags=%x\n",
+                            id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags));
+
+               /* Save these values to target structures
+                * or overwrite nvram (phys disks only).
+                */
+
+               if ((hd->Targets)&&((vtarget = hd->Targets[(int)id]) != NULL) && !vtarget->raidVolume ) {
+                       vtarget->maxWidth = dv->now.width;
+                       vtarget->maxOffset = dv->now.offset;
+                       vtarget->minSyncFactor = dv->now.factor;
+                       vtarget->negoFlags = dv->now.flags;
+               } else {
+                       /* Preserv all flags, use
+                        * read-modify-write algorithm
+                        */
+                       if (hd->ioc->spi_data.nvram) {
+                               data = hd->ioc->spi_data.nvram[id];
+
+                               if (dv->now.width)
+                                       data &= ~MPT_NVRAM_WIDE_DISABLE;
+                               else
+                                       data |= MPT_NVRAM_WIDE_DISABLE;
+
+                               if (!dv->now.offset)
+                                       factor = MPT_ASYNC;
+
+                               data &= ~MPT_NVRAM_SYNC_MASK;
+                               data |= (dv->now.factor << MPT_NVRAM_SYNC_SHIFT) & MPT_NVRAM_SYNC_MASK;
+
+                               hd->ioc->spi_data.nvram[id] = data;
+                       }
+               }
+               break;
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*     mptscsih_fillbuf - fill a buffer with a special data pattern
+ *             cleanup. For bus scan only.
+ *
+ *     @buffer: Pointer to data buffer to be filled.
+ *     @size: Number of bytes to fill
+ *     @index: Pattern index
+ *     @width: bus width, 0 (8 bits) or 1 (16 bits)
+ */
+static void
+mptscsih_fillbuf(char *buffer, int size, int index, int width)
+{
+       char *ptr = buffer;
+       int ii;
+       char byte;
+       short val;
+
+       switch (index) {
+       case 0:
+
+               if (width) {
+                       /* Pattern:  0000 FFFF 0000 FFFF
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x02)
+                                       *ptr = 0xFF;
+                               else
+                                       *ptr = 0x00;
+                       }
+               } else {
+                       /* Pattern:  00 FF 00 FF
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x01)
+                                       *ptr = 0xFF;
+                               else
+                                       *ptr = 0x00;
+                       }
+               }
+               break;
+
+       case 1:
+               if (width) {
+                       /* Pattern:  5555 AAAA 5555 AAAA 5555
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x02)
+                                       *ptr = 0xAA;
+                               else
+                                       *ptr = 0x55;
+                       }
+               } else {
+                       /* Pattern:  55 AA 55 AA 55
+                        */
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               if (ii & 0x01)
+                                       *ptr = 0xAA;
+                               else
+                                       *ptr = 0x55;
+                       }
+               }
+               break;
+
+       case 2:
+               /* Pattern:  00 01 02 03 04 05
+                * ... FE FF 00 01..
+                */
+               for (ii=0; ii < size; ii++, ptr++)
+                       *ptr = (char) ii;
+               break;
+
+       case 3:
+               if (width) {
+                       /* Wide Pattern:  FFFE 0001 FFFD 0002
+                        * ...  4000 DFFF 8000 EFFF
+                        */
+                       byte = 0;
+                       for (ii=0; ii < size/2; ii++) {
+                               /* Create the base pattern
+                                */
+                               val = (1 << byte);
+                               /* every 64 (0x40) bytes flip the pattern
+                                * since we fill 2 bytes / iteration,
+                                * test for ii = 0x20
+                                */
+                               if (ii & 0x20)
+                                       val = ~(val);
+
+                               if (ii & 0x01) {
+                                       *ptr = (char)( (val & 0xFF00) >> 8);
+                                       ptr++;
+                                       *ptr = (char)(val & 0xFF);
+                                       byte++;
+                                       byte &= 0x0F;
+                               } else {
+                                       val = ~val;
+                                       *ptr = (char)( (val & 0xFF00) >> 8);
+                                       ptr++;
+                                       *ptr = (char)(val & 0xFF);
+                               }
+
+                               ptr++;
+                       }
+               } else {
+                       /* Narrow Pattern:  FE 01 FD 02 FB 04
+                        * .. 7F 80 01 FE 02 FD ...  80 7F
+                        */
+                       byte = 0;
+                       for (ii=0; ii < size; ii++, ptr++) {
+                               /* Base pattern - first 32 bytes
+                                */
+                               if (ii & 0x01) {
+                                       *ptr = (1 << byte);
+                                       byte++;
+                                       byte &= 0x07;
+                               } else {
+                                       *ptr = (char) (~(1 << byte));
+                               }
+
+                               /* Flip the pattern every 32 bytes
+                                */
+                               if (ii & 0x20)
+                                       *ptr = ~(*ptr);
+                       }
+               }
+               break;
+       }
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
+ * Else set the NEED_DV flag after Read Capacity Issued (disks)
+ * or Mode Sense (cdroms).
+ *
+ * Tapes, initTarget will set this flag on completion of Inquiry command.
+ * Called only if DV_NOT_DONE flag is set
+ */
+static void
+mptscsih_set_dvflags(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc)
+{
+       MPT_ADAPTER     *ioc = hd->ioc;
+       u8 cmd;
+       SpiCfgData      *pSpi;
+
+       ddvtprintk((MYIOC_s_NOTE_FMT
+               " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n",
+               hd->ioc->name, sc->device->id, sc->device->lun , hd->negoNvram, sc->cmnd[0]));
+
+       if ((sc->device->lun != 0) || (hd->negoNvram != 0))
+               return;
+
+       cmd = sc->cmnd[0];
+
+       if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) {
+               pSpi = &ioc->spi_data;
+               if ((ioc->raid_data.isRaid & (1 << sc->device->id)) && ioc->raid_data.pIocPg3) {
+                       /* Set NEED_DV for all hidden disks
+                        */
+                       Ioc3PhysDisk_t *pPDisk =  ioc->raid_data.pIocPg3->PhysDisk;
+                       int             numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
+
+                       while (numPDisk) {
+                               pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV;
+                               ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID));
+                               pPDisk++;
+                               numPDisk--;
+                       }
+               }
+               pSpi->dvStatus[sc->device->id] |= MPT_SCSICFG_NEED_DV;
+               ddvtprintk(("NEED_DV set for visible disk id %d\n", sc->device->id));
+       }
+}
+
+/* mptscsih_raid_set_dv_flags()
+ *
+ * New or replaced disk. Set DV flag and schedule DV.
+ */
+static void
+mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id)
+{
+       MPT_ADAPTER     *ioc = hd->ioc;
+       SpiCfgData      *pSpi = &ioc->spi_data;
+       Ioc3PhysDisk_t  *pPDisk;
+       int              numPDisk;
+
+       if (hd->negoNvram != 0)
+               return;
+
+       ddvtprintk(("DV requested for phys disk id %d\n", id));
+       if (ioc->raid_data.pIocPg3) {
+               pPDisk =  ioc->raid_data.pIocPg3->PhysDisk;
+               numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks;
+               while (numPDisk) {
+                       if (id == pPDisk->PhysDiskNum) {
+                               pSpi->dvStatus[pPDisk->PhysDiskID] =
+                                   (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE);
+                               pSpi->forceDv = MPT_SCSICFG_NEED_DV;
+                               ddvtprintk(("NEED_DV set for phys disk id %d\n",
+                                   pPDisk->PhysDiskID));
+                               break;
+                       }
+                       pPDisk++;
+                       numPDisk--;
+               }
+
+               if (numPDisk == 0) {
+                       /* The physical disk that needs DV was not found
+                        * in the stored IOC Page 3. The driver must reload
+                        * this page. DV routine will set the NEED_DV flag for
+                        * all phys disks that have DV_NOT_DONE set.
+                        */
+                       pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
+                       ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id));
+               }
+       }
+}
+#endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */
+
 EXPORT_SYMBOL(mptscsih_remove);
 EXPORT_SYMBOL(mptscsih_shutdown);
 #ifdef CONFIG_PM