diff options
Diffstat (limited to 'drivers/message/fusion/mptscsih.c')
-rw-r--r-- | drivers/message/fusion/mptscsih.c | 994 |
1 files changed, 500 insertions, 494 deletions
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index b7b9846ff3fd..cdac5578fdf2 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -150,28 +150,29 @@ static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 tar 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, int bus_id, int target_id, u8 lun, char *data, int dlen); -static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); -static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); +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, int target_id); +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 int mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum); +static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice); +static void mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget); +static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id); static struct work_struct mptscsih_persistTask; #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 int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id); 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 *); @@ -627,7 +628,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n" "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n" "resid=%d bufflen=%d xfer_cnt=%d\n", - ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], + ioc->id, sc->device->id, sc->device->lun, status, scsi_state, scsi_status, sc->resid, sc->request_bufflen, xfer_cnt)); @@ -641,7 +642,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) pScsiReply->ResponseInfo) { printk(KERN_NOTICE "ha=%d id=%d lun=%d: " "FCP_ResponseInfo=%08xh\n", - ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], + ioc->id, sc->device->id, sc->device->lun, le32_to_cpu(pScsiReply->ResponseInfo)); } @@ -677,8 +678,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) sc->result = DID_RESET << 16; /* GEM Workaround. */ - if (ioc->bus_type == SCSI) - mptscsih_no_negotiate(hd, sc->device->id); + if (ioc->bus_type == SPI) + mptscsih_no_negotiate(hd, sc); break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ @@ -892,16 +893,16 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) * when a lun is disable by mid-layer. * Do NOT access the referenced scsi_cmnd structure or * members. Will cause either a paging or NULL ptr error. - * @hd: Pointer to a SCSI HOST structure - * @target: target id - * @lun: lun + * (BUT, BUT, BUT, the code does reference it! - mdr) + * @hd: Pointer to a SCSI HOST structure + * @vdevice: per device private data * * Returns: None. * * Called from slave_destroy. */ static void -mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun) +mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice) { SCSIIORequest_t *mf = NULL; int ii; @@ -909,7 +910,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun) struct scsi_cmnd *sc; dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", - target, lun, max)); + vdevice->target_id, vdevice->lun, max)); for (ii=0; ii < max; ii++) { if ((sc = hd->ScsiLookup[ii]) != NULL) { @@ -919,7 +920,7 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun) 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)target)) || (mf->LUN[1] != ((u8) lun))) + if ((mf->TargetID != ((u8)vdevice->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun))) continue; /* Cleanup @@ -993,8 +994,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) { @@ -1075,11 +1078,6 @@ mptscsih_shutdown(struct pci_dev *pdev) hd = (MPT_SCSI_HOST *)host->hostdata; - /* Flush the cache of this adapter - */ - if(hd != NULL) - mptscsih_synchronize_cache(hd, 0); - } #ifdef CONFIG_PM @@ -1286,7 +1284,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; - VirtDevice *pTarget = SCpnt->device->hostdata; + VirtDevice *vdev = SCpnt->device->hostdata; int lun; u32 datalen; u32 scsictl; @@ -1341,8 +1339,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) /* Default to untagged. Once a target structure has been allocated, * use the Inquiry data to determine if device supports tagged. */ - if (pTarget - && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) + if (vdev + && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; } else { @@ -1351,8 +1349,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) /* Use the above information to set up the message frame */ - pScsiReq->TargetID = (u8) pTarget->target_id; - pScsiReq->Bus = pTarget->bus_id; + pScsiReq->TargetID = (u8) vdev->target_id; + pScsiReq->Bus = vdev->bus_id; pScsiReq->ChainOffset = 0; pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; pScsiReq->CDBLength = SCpnt->cmd_len; @@ -1403,8 +1401,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) SCpnt->host_scribble = NULL; #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION - if (hd->ioc->bus_type == SCSI) { - int dvStatus = hd->ioc->spi_data.dvStatus[pTarget->target_id]; + 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) { @@ -1437,7 +1435,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) /* Set the DV flags. */ if (dvStatus & MPT_SCSICFG_DV_NOT_DONE) - mptscsih_set_dvflags(hd, pScsiReq); + mptscsih_set_dvflags(hd, SCpnt); if (!issueCmd) goto fail; @@ -1741,6 +1739,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) u32 ctx2abort; int scpnt_idx; int retval; + VirtDevice *vdev; /* If we can't locate our host adapter structure, return FAILED status. */ @@ -1790,8 +1789,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) hd->abortSCpnt = SCpnt; + vdev = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, + vdev->bus_id, vdev->target_id, vdev->lun, ctx2abort, 2 /* 2 second timeout */); printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n", @@ -1822,6 +1822,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; int retval; + VirtDevice *vdev; /* If we can't locate our host adapter structure, return FAILED status. */ @@ -1839,8 +1840,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) hd->ioc->name, SCpnt); scsi_print_command(SCpnt); + vdev = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - SCpnt->device->channel, SCpnt->device->id, + vdev->bus_id, vdev->target_id, 0, 0, 5 /* 5 second timeout */); printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n", @@ -1871,6 +1873,7 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; int retval; + VirtDevice *vdev; /* If we can't locate our host adapter structure, return FAILED status. */ @@ -1888,8 +1891,9 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt) if (hd->timeouts < -1) hd->timeouts++; + vdev = SCpnt->device->hostdata; retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */); + vdev->bus_id, 0, 0, 0, 5 /* 5 second timeout */); printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n", hd->ioc->name, @@ -2151,51 +2155,70 @@ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * OS entry point to allow host driver to alloc memory + * for each scsi target. Called once per device the bus scan. + * Return non-zero if allocation fails. + */ +int +mptscsih_target_alloc(struct scsi_target *starget) +{ + VirtTarget *vtarget; + + vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); + if (!vtarget) + return -ENOMEM; + starget->hostdata = vtarget; + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * OS entry point to allow host driver to alloc memory * for each scsi device. Called once per device the bus scan. * Return non-zero if allocation fails. - * Init memory once per id (not LUN). */ int -mptscsih_slave_alloc(struct scsi_device *device) +mptscsih_slave_alloc(struct scsi_device *sdev) { - struct Scsi_Host *host = device->host; + struct Scsi_Host *host = sdev->host; MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + VirtTarget *vtarget; VirtDevice *vdev; - uint target = device->id; - - if (hd == NULL) - return -ENODEV; + struct scsi_target *starget; - if ((vdev = hd->Targets[target]) != NULL) - goto out; - - vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL); + vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); if (!vdev) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", hd->ioc->name, sizeof(VirtDevice)); return -ENOMEM; } - memset(vdev, 0, sizeof(VirtDevice)); - vdev->tflags = MPT_TARGET_FLAGS_Q_YES; vdev->ioc_id = hd->ioc->id; - vdev->target_id = device->id; - vdev->bus_id = device->channel; - vdev->raidVolume = 0; - hd->Targets[device->id] = vdev; - if (hd->ioc->bus_type == SCSI) { - if (hd->ioc->raid_data.isRaid & (1 << device->id)) { - vdev->raidVolume = 1; - ddvtprintk((KERN_INFO - "RAID Volume @ id %d\n", device->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) { + hd->Targets[sdev->id] = vtarget; + vtarget->ioc_id = hd->ioc->id; + vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; + vtarget->target_id = sdev->id; + vtarget->bus_id = sdev->channel; + 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; } - } else { - vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; } - - out: - vdev->num_luns++; - device->hostdata = vdev; + vtarget->num_luns++; return 0; } @@ -2204,40 +2227,52 @@ mptscsih_slave_alloc(struct scsi_device *device) * Called if no device present or device being unloaded */ void -mptscsih_slave_destroy(struct scsi_device *device) +mptscsih_target_destroy(struct scsi_target *starget) { - struct Scsi_Host *host = device->host; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; - VirtDevice *vdev; - uint target = device->id; - uint lun = device->lun; - - if (hd == NULL) - return; - - mptscsih_search_running_cmds(hd, target, lun); - - vdev = hd->Targets[target]; - vdev->luns[0] &= ~(1 << lun); - if (--vdev->num_luns) - return; - - kfree(hd->Targets[target]); - hd->Targets[target] = NULL; - - if (hd->ioc->bus_type == SCSI) { - if (mptscsih_is_phys_disk(hd->ioc, target)) { - hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3; - } else { - hd->ioc->spi_data.dvStatus[target] = - MPT_SCSICFG_NEGOTIATE; + if (starget->hostdata) + kfree(starget->hostdata); + starget->hostdata = NULL; +} - if (!hd->negoNvram) { - hd->ioc->spi_data.dvStatus[target] |= - MPT_SCSICFG_DV_NOT_DONE; +/* + * OS entry point to allow for host driver to free allocated memory + * Called if no device present or device being unloaded + */ +void +mptscsih_slave_destroy(struct scsi_device *sdev) +{ + struct Scsi_Host *host = sdev->host; + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + VirtTarget *vtarget; + VirtDevice *vdevice; + struct scsi_target *starget; + + starget = scsi_target(sdev); + vtarget = starget->hostdata; + vdevice = sdev->hostdata; + + mptscsih_search_running_cmds(hd, vdevice); + vtarget->luns[0] &= ~(1 << vdevice->lun); + vtarget->num_luns--; + if (vtarget->num_luns == 0) { + mptscsih_negotiate_to_asyn_narrow(hd, vtarget); + 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); + kfree(vdevice); + sdev->hostdata = NULL; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2251,22 +2286,21 @@ mptscsih_slave_destroy(struct scsi_device *device) int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; - VirtDevice *pTarget; - int max_depth; - int tagged; - - if (hd == NULL) - return 0; - if (!(pTarget = hd->Targets[sdev->id])) - return 0; - - if (hd->ioc->bus_type == SCSI) { - if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { - if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata; + VirtTarget *vtarget; + struct scsi_target *starget; + int max_depth; + int tagged; + + starget = scsi_target(sdev); + vtarget = starget->hostdata; + + if (hd->ioc->bus_type == SPI) { + if (vtarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { + if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)) max_depth = 1; - else if (((pTarget->inq_data[0] & 0x1f) == 0x00) && - (pTarget->minSyncFactor <= MPT_ULTRA160 )) + 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; @@ -2295,64 +2329,58 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth) * Return non-zero if fails. */ int -mptscsih_slave_configure(struct scsi_device *device) +mptscsih_slave_configure(struct scsi_device *sdev) { - struct Scsi_Host *sh = device->host; - VirtDevice *pTarget; + struct Scsi_Host *sh = sdev->host; + VirtTarget *vtarget; + VirtDevice *vdevice; + struct scsi_target *starget; MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata; + int indexed_lun, lun_index; - if ((hd == NULL) || (hd->Targets == NULL)) { - return 0; - } + starget = scsi_target(sdev); + vtarget = starget->hostdata; + vdevice = sdev->hostdata; dsprintk((MYIOC_s_INFO_FMT "device @ %p, id=%d, LUN=%d, channel=%d\n", - hd->ioc->name, device, device->id, device->lun, device->channel)); - dsprintk((MYIOC_s_INFO_FMT - "sdtr %d wdtr %d ppr %d inq length=%d\n", - hd->ioc->name, device->sdtr, device->wdtr, - device->ppr, device->inquiry_len)); - - if (device->id > sh->max_id) { + hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel)); + if (hd->ioc->bus_type == SPI) + dsprintk((MYIOC_s_INFO_FMT + "sdtr %d wdtr %d ppr %d inq length=%d\n", + hd->ioc->name, sdev->sdtr, sdev->wdtr, + sdev->ppr, sdev->inquiry_len)); + + if (sdev->id > sh->max_id) { /* error case, should never happen */ - scsi_adjust_queue_depth(device, 0, 1); - goto slave_configure_exit; - } - - pTarget = hd->Targets[device->id]; - - if (pTarget == NULL) { - /* Driver doesn't know about this device. - * Kernel may generate a "Dummy Lun 0" which - * may become a real Lun if a - * "scsi add-single-device" command is executed - * while the driver is active (hot-plug a - * device). LSI Raid controllers need - * queue_depth set to DEV_HIGH for this reason. - */ - scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, - MPT_SCSI_CMD_PER_DEV_HIGH); + scsi_adjust_queue_depth(sdev, 0, 1); goto slave_configure_exit; } - mptscsih_initTarget(hd, device->channel, device->id, device->lun, - device->inquiry, device->inquiry_len ); - mptscsih_change_queue_depth(device, MPT_SCSI_CMD_PER_DEV_HIGH); + vdevice->configured_lun=1; + 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->lun, sdev->inquiry, + sdev->inquiry_len ); + mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH); dsprintk((MYIOC_s_INFO_FMT "Queue depth=%d, tflags=%x\n", - hd->ioc->name, device->queue_depth, pTarget->tflags)); + hd->ioc->name, sdev->queue_depth, vtarget->tflags)); - dsprintk((MYIOC_s_INFO_FMT - "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n", - hd->ioc->name, pTarget->negoFlags, pTarget->maxOffset, pTarget->minSyncFactor)); + if (hd->ioc->bus_type == SPI) + dsprintk((MYIOC_s_INFO_FMT + "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n", + hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset, + vtarget->minSyncFactor)); slave_configure_exit: dsprintk((MYIOC_s_INFO_FMT "tagged %d, simple %d, ordered %d\n", - hd->ioc->name,device->tagged_supported, device->simple_tags, - device->ordered_tags)); + hd->ioc->name,sdev->tagged_supported, sdev->simple_tags, + sdev->ordered_tags)); return 0; } @@ -2370,16 +2398,14 @@ slave_configure_exit: static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply) { - VirtDevice *target; + VirtDevice *vdev; SCSIIORequest_t *pReq; u32 sense_count = le32_to_cpu(pScsiReply->SenseCount); - int index; /* Get target structure */ pReq = (SCSIIORequest_t *) mf; - index = (int) pReq->TargetID; - target = hd->Targets[index]; + vdev = sc->device->hostdata; if (sense_count) { u8 *sense_data; @@ -2393,7 +2419,7 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR /* Log SMART data (asc = 0x5D, non-IM case only) if required. */ if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) { - if ((sense_data[12] == 0x5D) && (target->raidVolume == 0)) { + if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) { int idx; MPT_ADAPTER *ioc = hd->ioc; @@ -2403,7 +2429,7 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR ioc->events[idx].data[0] = (pReq->LUN[1] << 24) || (MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA << 16) || - (pReq->Bus << 8) || pReq->TargetID; + (sc->device->channel << 8) || sc->device->id; ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12]; @@ -2503,9 +2529,9 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) /* 2. Chain Buffer initialization */ - /* 4. Renegotiate to all devices, if SCSI + /* 4. Renegotiate to all devices, if SPI */ - if (ioc->bus_type == SCSI) { + 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); } @@ -2532,13 +2558,25 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) hd->cmdPtr = NULL; } - /* 7. Set flag to force DV and re-read IOC Page 3 + /* 7. SPI: Set flag to force DV and re-read IOC Page 3 */ - if (ioc->bus_type == SCSI) { + 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)); } @@ -2562,6 +2600,8 @@ 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; devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", ioc->name, event)); @@ -2576,18 +2616,25 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) break; case MPI_EVENT_IOC_BUS_RESET: /* 04 */ case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1)) + if (hd && (ioc->bus_type == SPI) && (hd->soft_resets < -1)) hd->soft_resets++; break; case MPI_EVENT_LOGOUT: /* 09 */ /* FIXME! */ 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; + /* * CHECKME! Don't think we need to do * anything for these, but... */ - case MPI_EVENT_RESCAN: /* 06 */ case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ /* @@ -2597,11 +2644,11 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) case MPI_EVENT_INTEGRATED_RAID: /* 0B */ { +#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION pMpiEventDataRaid_t pRaidEventData = (pMpiEventDataRaid_t) pEvReply->Data; -#ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION /* Domain Validation Needed */ - if (ioc->bus_type == SCSI && + if (ioc->bus_type == SPI && pRaidEventData->ReasonCode == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum); @@ -2632,8 +2679,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) /* * mptscsih_initTarget - Target, LUN alloc/free functionality. * @hd: Pointer to MPT_SCSI_HOST structure - * @bus_id: Bus number (?) - * @target_id: SCSI target id + * @vtarget: per target private data * @lun: SCSI LUN id * @data: Pointer to data * @dlen: Number of INQUIRY bytes @@ -2646,15 +2692,14 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) * */ static void -mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen) +mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, u8 lun, char *data, int dlen) { - int indexed_lun, lun_index; - VirtDevice *vdev; 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, bus_id, target_id, lun, hd)); + 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 @@ -2674,75 +2719,68 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * if (data[0] & 0xe0) return; - if ((vdev = hd->Targets[target_id]) == NULL) { + if (vtarget == NULL) return; - } - lun_index = (lun >> 5); /* 32 luns per lun_index */ - indexed_lun = (lun % 32); - vdev->luns[lun_index] |= (1 << indexed_lun); - - if (hd->ioc->bus_type == SCSI) { - if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { - /* Treat all Processors as SAF-TE if - * command line option is set */ - vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; - mptscsih_writeIOCPage4(hd, target_id, bus_id); - }else if ((data[0] == TYPE_PROCESSOR) && - !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { - if ( dlen > 49 ) { - vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; - if ( data[44] == 'S' && - data[45] == 'A' && - data[46] == 'F' && - data[47] == '-' && - data[48] == 'T' && - data[49] == 'E' ) { - vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; - mptscsih_writeIOCPage4(hd, target_id, bus_id); - } + if (data) + vtarget->type = data[0]; + + if (hd->ioc->bus_type != SPI) + return; + + 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 ((data[0] == TYPE_PROCESSOR) && + !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { + 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); } } - if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { - if ( dlen > 8 ) { - memcpy (vdev->inq_data, data, 8); - } else { - memcpy (vdev->inq_data, data, dlen); - } + } + 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; - /* If have not done DV, set the DV flag. + 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 */ - pSpi = &hd->ioc->spi_data; - if ((data[0] == TYPE_TAPE) || (data[0] == TYPE_PROCESSOR)) { - if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE) - pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV; + data_56 = data[56]; + vtarget->tflags |= MPT_TARGET_FLAGS_VALID_56; } - - vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; - - - data_56 = 0x0F; /* Default to full capabilities if Inq data length is < 57 */ - if (dlen > 56) { - if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { - /* Update the target capabilities - */ - data_56 = data[56]; - vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; - } - } - mptscsih_setTargetNegoParms(hd, vdev, 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 ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { - /* Update the target capabilities - */ - data_56 = data[56]; - vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; - mptscsih_setTargetNegoParms(hd, vdev, data_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); } } } @@ -2755,12 +2793,12 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * * */ static void -mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) +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; - VirtDevice *vdev; + VirtTarget *vtarget; int ii; u8 width = MPT_NARROW; u8 factor = MPT_ASYNC; @@ -2905,9 +2943,9 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id)); for (ii = 0; ii < id; ii++) { - if ( (vdev = hd->Targets[ii]) ) { - vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; - mptscsih_writeSDP1(hd, 0, ii, vdev->negoFlags); + if ( (vtarget = hd->Targets[ii]) ) { + vtarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + mptscsih_writeSDP1(hd, 0, ii, vtarget->negoFlags); } } } @@ -2926,105 +2964,17 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* 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, SCSIIORequest_t *pReq) -{ - 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, pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0])); - - if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0)) - return; - - cmd = pReq->CDB[0]; - - if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) { - pSpi = &ioc->spi_data; - if ((ioc->raid_data.isRaid & (1 << pReq->TargetID)) && 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[pReq->TargetID] |= MPT_SCSICFG_NEED_DV; - ddvtprintk(("NEED_DV set for visible disk id %d\n", pReq->TargetID)); - } -} - -/* 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)); - } - } -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * 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, int target_id) +mptscsih_no_negotiate(MPT_SCSI_HOST *hd, struct scsi_cmnd *sc) { + VirtDevice *vdev; - if ((hd->Targets) && (hd->Targets[target_id] == NULL)) - hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO; - + if ((vdev = sc->device->hostdata) != NULL) + hd->ioc->spi_data.dvStatus[vdev->target_id] |= MPT_SCSICFG_BLK_NEGO; return; } @@ -3100,7 +3050,7 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) MPT_ADAPTER *ioc = hd->ioc; Config_t *pReq; SCSIDevicePage1_t *pData; - VirtDevice *pTarget=NULL; + VirtTarget *vtarget=NULL; MPT_FRAME_HDR *mf; dma_addr_t dataDma; u16 req_idx; @@ -3180,11 +3130,11 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) /* If id is not a raid volume, get the updated * transmission settings from the target structure. */ - if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { - width = pTarget->maxWidth; - factor = pTarget->minSyncFactor; - offset = pTarget->maxOffset; - negoFlags = pTarget->negoFlags; + 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 @@ -3904,149 +3854,137 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks. - * @hd: Pointer to MPT_SCSI_HOST structure - * @portnum: IOC port number + * 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. * - * Return: 0 on completion */ -static int -mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) +static void +mptscsih_negotiate_to_asyn_narrow(MPT_SCSI_HOST *hd, VirtTarget *vtarget) { MPT_ADAPTER *ioc= hd->ioc; - VirtDevice *pTarget; - SCSIDevicePage1_t *pcfg1Data = NULL; - INTERNAL_CMD iocmd; + SCSIDevicePage1_t *pcfg1Data; CONFIGPARMS cfg; - dma_addr_t cfg1_dma_addr = -1; - ConfigPageHeader_t header1; - int bus = 0; - int id = 0; - int lun; - int indexed_lun, lun_index; - int hostId = ioc->pfacts[portnum].PortSCSIID; - int max_id; - int requested, configuration, data; - int doConfig = 0; + dma_addr_t cfg1_dma_addr; + ConfigPageHeader_t header; + int id; + int requested, configuration, data,i; u8 flags, factor; - max_id = ioc->sh->max_id - 1; - - /* Following parameters will not change - * in this routine. - */ - iocmd.cmd = SYNCHRONIZE_CACHE; - iocmd.flags = 0; - iocmd.physDiskNum = -1; - iocmd.data = NULL; - iocmd.data_dma = -1; - iocmd.size = 0; - iocmd.rsvd = iocmd.rsvd2 = 0; - - /* No SCSI hosts - */ - if (hd->Targets == NULL) - return 0; - - /* Skip the host - */ - if (id == hostId) - id++; - - /* Write SDP1 for all SCSI devices - * Alloc memory and set up config buffer - */ - if (ioc->bus_type == SCSI) { - if (ioc->spi_data.sdp1length > 0) { - pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev, - ioc->spi_data.sdp1length * 4, &cfg1_dma_addr); - - if (pcfg1Data != NULL) { - doConfig = 1; - header1.PageVersion = ioc->spi_data.sdp1version; - header1.PageLength = ioc->spi_data.sdp1length; - header1.PageNumber = 1; - header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; - cfg.cfghdr.hdr = &header1; - cfg.physAddr = cfg1_dma_addr; - cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; - cfg.dir = 1; - cfg.timeout = 0; - } - } - } + if (ioc->bus_type != SPI) + return; - /* loop through all devices on this port - */ - while (bus < MPT_MAX_BUS) { - iocmd.bus = bus; - iocmd.id = id; - pTarget = hd->Targets[(int)id]; + if (!ioc->spi_data.sdp1length) + return; - if (doConfig) { + pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev, + ioc->spi_data.sdp1length * 4, &cfg1_dma_addr); - /* Set the negotiation flags */ - if (pTarget && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { - flags = pTarget->negoFlags; - } else { - 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 (pcfg1Data == NULL) + return; - if (data & MPT_NVRAM_WIDE_DISABLE) - flags |= MPT_TARGET_NO_NEGO_WIDE; + 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; - factor = (data & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT; - if ((factor == 0) || (factor == MPT_ASYNC)) - flags |= MPT_TARGET_NO_NEGO_SYNC; - } + 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; } - - /* Force to async, narrow */ mptscsih_setDevicePage1Flags(0, MPT_ASYNC, 0, &requested, - &configuration, flags); + &configuration, flags); dnegoprintk(("syncronize cache: 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 = (bus<<8) | id; + 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(("syncronize cache: 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 target Ptr NULL or if this target is NOT a disk, skip. - */ - if ((pTarget) && (pTarget->inq_data[0] == TYPE_DISK)){ - for (lun=0; lun <= MPT_LAST_LUN; lun++) { - /* If LUN present, issue the command - */ - lun_index = (lun >> 5); /* 32 luns per lun_index */ - indexed_lun = (lun % 32); - if (pTarget->luns[lun_index] & (1<<indexed_lun)) { - iocmd.lun = lun; - (void) mptscsih_do_cmd(hd, &iocmd); - } - } - } + if (pcfg1Data) + pci_free_consistent(ioc->pcidev, header.PageLength * 4, pcfg1Data, cfg1_dma_addr); +} - /* get next relevant device */ - id++; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mptscsih_synchronize_cache - Send SYNCHRONIZE_CACHE to all disks. + * @hd: Pointer to a SCSI HOST structure + * @vtarget: per device private data + * @lun: lun + * + * Uses the ISR, but with special processing. + * MUST be single-threaded. + * + */ +static void +mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice) +{ + INTERNAL_CMD iocmd; - if (id == hostId) - id++; + /* Following parameters will not change + * in this routine. + */ + iocmd.cmd = SYNCHRONIZE_CACHE; + iocmd.flags = 0; + iocmd.physDiskNum = -1; + iocmd.data = NULL; + iocmd.data_dma = -1; + iocmd.size = 0; + iocmd.rsvd = iocmd.rsvd2 = 0; + iocmd.bus = vdevice->bus_id; + iocmd.id = vdevice->target_id; + iocmd.lun = (u8)vdevice->lun; - if (id > max_id) { - id = 0; - bus++; - } - } + 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 (pcfg1Data) { - pci_free_consistent(ioc->pcidev, header1.PageLength * 4, pcfg1Data, cfg1_dma_addr); + 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; @@ -4101,8 +4039,8 @@ mptscsih_domainValidation(void *arg) msleep(250); - /* DV only to SCSI adapters */ - if (ioc->bus_type != SCSI) + /* DV only to SPI adapters */ + if (ioc->bus_type != SPI) continue; /* Make sure everything looks ok */ @@ -4205,32 +4143,12 @@ mptscsih_domainValidation(void *arg) return; } -/* Search IOC page 3 to determine if this is hidden physical disk - */ -/* 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; -} - /* Write SDP1 if no QAS has been enabled */ static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id) { - VirtDevice *pTarget; + VirtTarget *vtarget; int ii; if (hd->Targets == NULL) @@ -4243,11 +4161,11 @@ mptscsih_qas_check(MPT_SCSI_HOST *hd, int id) if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0) continue; - pTarget = hd->Targets[ii]; + vtarget = hd->Targets[ii]; - if ((pTarget != NULL) && (!pTarget->raidVolume)) { - if ((pTarget->negoFlags & hd->ioc->spi_data.noQas) == 0) { - pTarget->negoFlags |= hd->ioc->spi_data.noQas; + 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); } @@ -4287,7 +4205,7 @@ static int mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) { MPT_ADAPTER *ioc = hd->ioc; - VirtDevice *pTarget; + VirtTarget *vtarget; SCSIDevicePage1_t *pcfg1Data; SCSIDevicePage0_t *pcfg0Data; u8 *pbuf1; @@ -4358,12 +4276,12 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) iocmd.physDiskNum = -1; iocmd.rsvd = iocmd.rsvd2 = 0; - pTarget = hd->Targets[id]; + vtarget = hd->Targets[id]; /* Use tagged commands if possible. */ - if (pTarget) { - if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) + if (vtarget) { + if (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES) iocmd.flags |= MPT_ICFLAG_TAGGED_CMD; else { if (hd->ioc->facts.FWVersion.Word < 0x01000600) @@ -4579,7 +4497,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) /* Reset the size for disks */ inq0 = (*pbuf1) & 0x1F; - if ((inq0 == 0) && pTarget && !pTarget->raidVolume) { + if ((inq0 == 0) && vtarget && !vtarget->raidVolume) { sz = 0x40; iocmd.size = sz; } @@ -4589,8 +4507,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) */ if (inq0 == TYPE_PROCESSOR) { mptscsih_initTarget(hd, - bus, - id, + vtarget, lun, pbuf1, sz); @@ -4604,22 +4521,22 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) goto target_done; if (sz == 0x40) { - if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A) - && (pTarget->minSyncFactor > 0x09)) { + if ((vtarget->maxWidth == 1) && (vtarget->maxOffset) && (nfactor < 0x0A) + && (vtarget->minSyncFactor > 0x09)) { if ((pbuf1[56] & 0x04) == 0) ; else if ((pbuf1[56] & 0x01) == 1) { - pTarget->minSyncFactor = + vtarget->minSyncFactor = nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320; } else { - pTarget->minSyncFactor = + vtarget->minSyncFactor = nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160; } - dv.max.factor = pTarget->minSyncFactor; + dv.max.factor = vtarget->minSyncFactor; if ((pbuf1[56] & 0x02) == 0) { - pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + 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", @@ -4702,8 +4619,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) "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, - bus, - id, + vtarget, lun, pbuf1, sz); @@ -5204,7 +5120,7 @@ target_done: static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) { - VirtDevice *pTarget; + VirtTarget *vtarget; SCSIDevicePage0_t *pPage0; SCSIDevicePage1_t *pPage1; int val = 0, data, configuration; @@ -5224,11 +5140,11 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) * already throttled back. */ negoFlags = hd->ioc->spi_data.noQas; - if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) { - width = pTarget->maxWidth; - offset = pTarget->maxOffset; - factor = pTarget->minSyncFactor; - negoFlags |= pTarget->negoFlags; + 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]; @@ -5430,11 +5346,11 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) * or overwrite nvram (phys disks only). */ - if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume ) { - pTarget->maxWidth = dv->now.width; - pTarget->maxOffset = dv->now.offset; - pTarget->minSyncFactor = dv->now.factor; - pTarget->negoFlags = dv->now.flags; + 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 @@ -5588,6 +5504,94 @@ mptscsih_fillbuf(char *buffer, int size, int index, int width) 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); @@ -5599,7 +5603,9 @@ EXPORT_SYMBOL(mptscsih_resume); EXPORT_SYMBOL(mptscsih_proc_info); EXPORT_SYMBOL(mptscsih_info); EXPORT_SYMBOL(mptscsih_qcmd); +EXPORT_SYMBOL(mptscsih_target_alloc); EXPORT_SYMBOL(mptscsih_slave_alloc); +EXPORT_SYMBOL(mptscsih_target_destroy); EXPORT_SYMBOL(mptscsih_slave_destroy); EXPORT_SYMBOL(mptscsih_slave_configure); EXPORT_SYMBOL(mptscsih_abort); |