extractedLnx/linux-2.6.8/drivers/message/fusion/mptscsih.c_mptscsih_doDv.c
static int
mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id)
{
MPT_ADAPTER *ioc = hd->ioc;
VirtDevice *pTarget;
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);
if ((!dv.max.width) && (!dv.max.offset))
return 0;
/* Prep SCSI IO structure
*/
iocmd.id = id;
iocmd.bus = bus;
iocmd.lun = lun;
iocmd.flags = 0;
iocmd.physDiskNum = -1;
iocmd.rsvd = iocmd.rsvd2 = 0;
pTarget = hd->Targets[id];
if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
/* Another GEM workaround. Check peripheral device type,
* if PROCESSOR, quit DV.
*/
if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
return 0;
}
}
/* Use tagged commands if possible.
*/
if (pTarget) {
if (pTarget->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.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.hdr to force config page write
*/
{
ScsiCfgData *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.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->spi_data.pIocPg3) {
/* Searc IOC page 3 for matching id
*/
Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk;
int numPDisk = ioc->spi_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->spi_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_STD_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.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 = CMD_RequestSense;
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 = CMD_Inquiry;
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;
rc = hd->pLocal->completion;
if (rc == MPT_SCANDV_GOOD) {
if (hd->pLocal->scsiStatus == STS_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) && pTarget && !pTarget->raidVolume) {
sz = 0x40;
iocmd.size = sz;
}
/* Another GEM workaround. Check peripheral device type,
* if PROCESSOR, quit DV.
*/
if (((pbuf1[0] & 0x1F) == 0x03) || ((pbuf1[0] & 0x1F) > 0x08))
goto target_done;
if (mptscsih_do_cmd(hd, &iocmd) < 0)
goto target_done;
if (sz == 0x40) {
if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A)
&& (pTarget->minSyncFactor > 0x09)) {
if ((pbuf1[56] & 0x04) == 0)
;
else if ((pbuf1[56] & 0x01) == 1) {
pTarget->minSyncFactor =
nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320;
} else {
pTarget->minSyncFactor =
nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160;
}
dv.max.factor = pTarget->minSyncFactor;
if ((pbuf1[56] & 0x02) == 0) {
pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS;
}
}
}
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 = CMD_Inquiry;
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 {
/* 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.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
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))
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));
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.hdr = &header1;
cfg.physAddr = cfg1_dma_addr;
cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
cfg.dir = 1;
iocmd.cmd = CMD_TestUnitReady;
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 == SK_UNIT_ATTENTION)
notDone++; /* repeat */
else if ((skey == SK_NOT_READY) &&
(asc == 0x04)&&(ascq == 0x01)) {
/* wait then repeat */
mdelay (2000);
notDone++;
} else if ((skey == SK_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 = CMD_ReadBuffer;
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];
} 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 == SK_ILLEGAL_REQUEST) {
notDone = 0;
} else if (skey == SK_UNIT_ATTENTION) {
notDone++; /* repeat */
} else if ((skey == SK_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 = CMD_TestUnitReady;
iocmd.data_dma = -1;
iocmd.data = NULL;
iocmd.size = 0;
if (mptscsih_do_cmd(hd, &iocmd) < 0)
goto target_done;
iocmd.cmd = CMD_Release6;
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;
repeat = 5;
while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) {
iocmd.cmd = CMD_Reserve6;
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 == SK_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;
}
}
}
mptscsih_fillbuf(pbuf1, sz, patt, 1);
iocmd.cmd = CMD_WriteBuffer;
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 == SK_UNIT_ATTENTION) {
patt = -1;
continue;
} else if (skey == SK_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 = CMD_ReadBuffer;
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 == SK_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 = CMD_Release6;
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.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;
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.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.\n",
ioc->name));
return retcode;
}
Generated by GNU enscript 1.6.4.