aboutsummaryrefslogtreecommitdiff
path: root/drivers/message/fusion/mptspi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/message/fusion/mptspi.c')
-rw-r--r--drivers/message/fusion/mptspi.c160
1 files changed, 93 insertions, 67 deletions
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 25bcfcf36f2..49d11338294 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -3,7 +3,7 @@
* For use with LSI PCI chip/adapter(s)
* running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Corporation
+ * Copyright (c) 1999-2008 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -46,6 +46,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/kdev_t.h>
@@ -209,6 +210,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
target->maxOffset = offset;
target->maxWidth = width;
+ spi_min_period(scsi_target(sdev)) = factor;
+ spi_max_offset(scsi_target(sdev)) = offset;
+ spi_max_width(scsi_target(sdev)) = width;
+
target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
/* Disable unused features.
@@ -300,7 +305,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
(IOCPage4Ptr->Header.PageLength + ii) * 4;
- mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+ ioc->add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
@@ -447,6 +452,7 @@ static int mptspi_target_alloc(struct scsi_target *starget)
spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
spi_offset(starget) = 0;
+ spi_period(starget) = 0xFF;
mptspi_write_width(starget, 0);
return 0;
@@ -556,6 +562,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
cfg.dir = 0;
cfg.pageAddr = starget->id;
+ cfg.timeout = 60;
if (mpt_config(ioc, &cfg)) {
starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
@@ -613,19 +620,24 @@ static void mptspi_read_parameters(struct scsi_target *starget)
spi_width(starget) = (nego & MPI_SCSIDEVPAGE0_NP_WIDE) ? 1 : 0;
}
-static int
+int
mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
{
+ MPT_ADAPTER *ioc = hd->ioc;
MpiRaidActionRequest_t *pReq;
MPT_FRAME_HDR *mf;
- MPT_ADAPTER *ioc = hd->ioc;
+ int ret;
+ unsigned long timeleft;
+
+ mutex_lock(&ioc->internal_cmds.mutex);
/* Get and Populate a free Frame
*/
if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
- ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
- ioc->name));
- return -EAGAIN;
+ dfailprintk(hd->ioc, printk(MYIOC_s_WARN_FMT
+ "%s: no msg frames!\n", ioc->name, __func__));
+ ret = -EAGAIN;
+ goto out;
}
pReq = (MpiRaidActionRequest_t *)mf;
if (quiesce)
@@ -642,29 +654,36 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
pReq->Reserved2 = 0;
pReq->ActionDataWord = 0; /* Reserved for this action */
- mpt_add_sge((char *)&pReq->ActionDataSGE,
+ ioc->add_sge((char *)&pReq->ActionDataSGE,
MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
ioc->name, pReq->Action, channel, 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);
+ INITIALIZE_MGMT_STATUS(ioc->internal_cmds.status)
mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
- wait_event(hd->scandv_waitq, hd->scandv_wait_done);
+ timeleft = wait_for_completion_timeout(&ioc->internal_cmds.done, 10*HZ);
+ if (!(ioc->internal_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+ ret = -ETIME;
+ dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: TIMED OUT!\n",
+ ioc->name, __func__));
+ if (ioc->internal_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
+ goto out;
+ if (!timeleft) {
+ printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
+ ioc->name, __func__);
+ mpt_HardResetHandler(ioc, CAN_SLEEP);
+ mpt_free_msg_frame(ioc, mf);
+ }
+ goto out;
+ }
- if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
- return -1;
+ ret = ioc->internal_cmds.completion_code;
- return 0;
+ out:
+ CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
+ mutex_unlock(&ioc->internal_cmds.mutex);
+ return ret;
}
static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
@@ -761,29 +780,29 @@ static int mptspi_slave_configure(struct scsi_device *sdev)
}
static int
-mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+mptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
{
- struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
VirtDevice *vdevice = SCpnt->device->hostdata;
MPT_ADAPTER *ioc = hd->ioc;
if (!vdevice || !vdevice->vtarget) {
SCpnt->result = DID_NO_CONNECT << 16;
- done(SCpnt);
+ SCpnt->scsi_done(SCpnt);
return 0;
}
if (SCpnt->device->channel == 1 &&
mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) {
SCpnt->result = DID_NO_CONNECT << 16;
- done(SCpnt);
+ SCpnt->scsi_done(SCpnt);
return 0;
}
if (spi_dv_pending(scsi_target(SCpnt->device)))
ddvprintk(ioc, scsi_print_command(SCpnt));
- return mptscsih_qcmd(SCpnt,done);
+ return mptscsih_qcmd(SCpnt);
}
static void mptspi_slave_destroy(struct scsi_device *sdev)
@@ -810,7 +829,7 @@ static void mptspi_slave_destroy(struct scsi_device *sdev)
static struct scsi_host_template mptspi_driver_template = {
.module = THIS_MODULE,
.proc_name = "mptspi",
- .proc_info = mptscsih_proc_info,
+ .show_info = mptscsih_show_info,
.name = "MPT SPI Host",
.info = mptscsih_info,
.queuecommand = mptspi_qcmd,
@@ -846,6 +865,10 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
struct _x_config_parms cfg;
struct _CONFIG_PAGE_HEADER hdr;
int err = -EBUSY;
+ u32 nego_parms;
+ u32 period;
+ struct scsi_device *sdev;
+ int i;
/* don't allow updating nego parameters on RAID devices */
if (starget->channel == 0 &&
@@ -883,6 +906,24 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
pg1->Header.PageNumber = hdr.PageNumber;
pg1->Header.PageType = hdr.PageType;
+ nego_parms = le32_to_cpu(pg1->RequestedParameters);
+ period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >>
+ MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD;
+ if (period == 8) {
+ /* Turn on inline data padding for TAPE when running U320 */
+ for (i = 0 ; i < 16; i++) {
+ sdev = scsi_device_lookup_by_target(starget, i);
+ if (sdev && sdev->type == TYPE_TAPE) {
+ sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT
+ "IDP:ON\n", ioc->name);
+ nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP;
+ pg1->RequestedParameters =
+ cpu_to_le32(nego_parms);
+ break;
+ }
+ }
+ }
+
mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
if (mpt_config(ioc, &cfg)) {
@@ -1138,6 +1179,9 @@ mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+ if (ioc->bus_type != SPI)
+ return 0;
+
if (hd && event == MPI_EVENT_INTEGRATED_RAID) {
int reason
= (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
@@ -1266,13 +1310,20 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
static int
mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
- struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
int rc;
rc = mptscsih_ioc_reset(ioc, reset_phase);
+ if ((ioc->bus_type != SPI) || (!rc))
+ return rc;
+
+ /* only try to do a renegotiation if we're properly set up
+ * if we get an ioc fault on bringup, ioc->sh will be NULL */
+ if (reset_phase == MPT_IOC_POST_RESET &&
+ ioc->sh) {
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
- if (reset_phase == MPT_IOC_POST_RESET)
mptspi_dv_renegotiate(hd);
+ }
return rc;
}
@@ -1417,17 +1468,15 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
* A slightly different algorithm is required for
* 64bit SGEs.
*/
- scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
- if (sizeof(dma_addr_t) == sizeof(u64)) {
+ scale = ioc->req_sz/ioc->SGE_size;
+ if (ioc->sg_addr_size == sizeof(u64)) {
numSGE = (scale - 1) *
(ioc->facts.MaxChainDepth-1) + scale +
- (ioc->req_sz - 60) / (sizeof(dma_addr_t) +
- sizeof(u32));
+ (ioc->req_sz - 60) / ioc->SGE_size;
} else {
numSGE = 1 + (scale - 1) *
(ioc->facts.MaxChainDepth-1) + scale +
- (ioc->req_sz - 64) / (sizeof(dma_addr_t) +
- sizeof(u32));
+ (ioc->req_sz - 64) / ioc->SGE_size;
}
if (numSGE < sh->sg_tablesize) {
@@ -1456,39 +1505,13 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
ioc->name, ioc->ScsiLookup));
- /* Clear the TM flags
- */
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- hd->resetPending = 0;
- hd->abortSCpnt = NULL;
-
- /* Clear the pointer used to store
- * single-threaded commands, i.e., those
- * issued during a bus scan, dv and
- * configuration pages.
- */
- hd->cmdPtr = NULL;
-
- /* Initialize this SCSI Hosts' timers
- * To use, set the timer expires field
- * and add_timer
- */
- init_timer(&hd->timer);
- hd->timer.data = (unsigned long) hd;
- hd->timer.function = mptscsih_timer_expired;
-
ioc->spi_data.Saf_Te = mpt_saf_te;
-
- hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"saf_te %x\n",
ioc->name,
mpt_saf_te));
ioc->spi_data.noQas = 0;
- init_waitqueue_head(&hd->scandv_waitq);
- hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
hd->spi_pending = 0;
@@ -1508,7 +1531,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
* issue internal bus reset
*/
if (ioc->spi_data.bus_reset)
- mptscsih_TMHandler(hd,
+ mptscsih_IssueTaskMgmt(hd,
MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
0, 0, 0, 0, 5);
@@ -1525,7 +1548,7 @@ static struct pci_driver mptspi_driver = {
.name = "mptspi",
.id_table = mptspi_pci_table,
.probe = mptspi_probe,
- .remove = __devexit_p(mptscsih_remove),
+ .remove = mptscsih_remove,
.shutdown = mptscsih_shutdown,
#ifdef CONFIG_PM
.suspend = mptscsih_suspend,
@@ -1550,9 +1573,12 @@ mptspi_init(void)
if (!mptspi_transport_template)
return -ENODEV;
- mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER);
- mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);
- mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);
+ mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER,
+ "mptscsih_io_done");
+ mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER,
+ "mptscsih_taskmgmt_complete");
+ mptspiInternalCtx = mpt_register(mptscsih_scandv_complete,
+ MPTSPI_DRIVER, "mptscsih_scandv_complete");
mpt_event_register(mptspiDoneCtx, mptspi_event_process);
mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);