Skip to content

Commit

Permalink
[SCSI] mpt fusion: Fixing 1078 data corruption issue for 36GB memory …
Browse files Browse the repository at this point in the history
…region

The reason for this change is there is a data corruption when four different
physical memory regions in the 36GB to 37GB region are
accessed. This is only affecting 1078.

The solution is we need to use different addressing when filling in
the scatter gather table for the effected memory regions.  So instead
of snooping on all four different memory holes, we treat any physical
addresses in the 36GB address with the same algorithm.

The fix is explained below
1) Ensure that the message frames are NOT located in the trouble
region. There is no remapping available for message frames, they must
be allocated outside the problem region.
2) Ensure that Sense buffers are NOT in the trouble region. There is
no remapping available.
3) Walk through the SGE entries and if any are inside the trouble region
   then they need to be remapped as discussed below.
	1) Set the Local Address bit in the SGE Flags field.
  	MPI_SGE_FLAGS_LOCAL_ADDRESS
  	2) Ensure we are using 64-bit SGEs
  	3) Set MSb (Bit 63) of the 64-bit address, this will indicate buffer
	location is Host Memory.

Signed-off-by: Kashyap Desai <kadesai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
  • Loading branch information
Kashyap, Desai authored and James Bottomley committed Jun 9, 2009
1 parent 238ddbb commit 14d0f0b
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 188 deletions.
287 changes: 237 additions & 50 deletions drivers/message/fusion/mptbase.c

Large diffs are not rendered by default.

35 changes: 22 additions & 13 deletions drivers/message/fusion/mptbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
#endif

#define MPT_LINUX_VERSION_COMMON "3.04.07"
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.07"
#define MPT_LINUX_VERSION_COMMON "3.04.08"
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.08"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"

#define show_mptmod_ver(s,ver) \
Expand Down Expand Up @@ -134,6 +134,7 @@

#define MPT_COALESCING_TIMEOUT 0x10


/*
* SCSI transfer rate defines.
*/
Expand Down Expand Up @@ -564,6 +565,10 @@ struct mptfc_rport_info
u8 flags;
};

typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr);
typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length,
dma_addr_t dma_addr);

/*
* Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
*/
Expand Down Expand Up @@ -600,6 +605,10 @@ typedef struct _MPT_ADAPTER
int reply_depth; /* Num Allocated reply frames */
int reply_sz; /* Reply frame size */
int num_chain; /* Number of chain buffers */
MPT_ADD_SGE add_sge; /* Pointer to add_sge
function */
MPT_ADD_CHAIN add_chain; /* Pointer to add_chain
function */
/* Pool of buffers for chaining. ReqToChain
* and ChainToChain track index of chain buffers.
* ChainBuffer (DMA) virt/phys addresses.
Expand Down Expand Up @@ -711,12 +720,15 @@ typedef struct _MPT_ADAPTER
struct workqueue_struct *fc_rescan_work_q;
struct scsi_cmnd **ScsiLookup;
spinlock_t scsi_lookup_lock;

u64 dma_mask;
char reset_work_q_name[20];
struct workqueue_struct *reset_work_q;
struct delayed_work fault_reset_work;
spinlock_t fault_reset_work_lock;

u8 sg_addr_size;
u8 SGE_size;

} MPT_ADAPTER;

/*
Expand Down Expand Up @@ -753,13 +765,14 @@ typedef struct _mpt_sge {
dma_addr_t Address;
} MptSge_t;

#define mpt_addr_size() \
((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SGE_FLAGS_64_BIT_ADDRESSING : \
MPI_SGE_FLAGS_32_BIT_ADDRESSING)

#define mpt_msg_flags() \
((sizeof(dma_addr_t) == sizeof(u64)) ? MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32)
#define mpt_msg_flags(ioc) \
(ioc->sg_addr_size == sizeof(u64)) ? \
MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_64 : \
MPI_SCSIIO_MSGFLGS_SENSE_WIDTH_32

#define MPT_SGE_FLAGS_64_BIT_ADDRESSING \
(MPI_SGE_FLAGS_64_BIT_ADDRESSING << MPI_SGE_FLAGS_SHIFT)

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
Expand Down Expand Up @@ -909,7 +922,6 @@ extern MPT_FRAME_HDR *mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc);
extern void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
extern void mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
extern void mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
extern void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);

extern int mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
Expand Down Expand Up @@ -959,7 +971,6 @@ extern int mpt_fwfault_debug;
#define MPT_SGE_FLAGS_END_OF_BUFFER (0x40000000)
#define MPT_SGE_FLAGS_LOCAL_ADDRESS (0x08000000)
#define MPT_SGE_FLAGS_DIRECTION (0x04000000)
#define MPT_SGE_FLAGS_ADDRESSING (mpt_addr_size() << MPI_SGE_FLAGS_SHIFT)
#define MPT_SGE_FLAGS_END_OF_LIST (0x01000000)

#define MPT_SGE_FLAGS_TRANSACTION_ELEMENT (0x00000000)
Expand All @@ -972,14 +983,12 @@ extern int mpt_fwfault_debug;
MPT_SGE_FLAGS_END_OF_BUFFER | \
MPT_SGE_FLAGS_END_OF_LIST | \
MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
MPT_SGE_FLAGS_ADDRESSING | \
MPT_TRANSFER_IOC_TO_HOST)
#define MPT_SGE_FLAGS_SSIMPLE_WRITE \
(MPT_SGE_FLAGS_LAST_ELEMENT | \
MPT_SGE_FLAGS_END_OF_BUFFER | \
MPT_SGE_FLAGS_END_OF_LIST | \
MPT_SGE_FLAGS_SIMPLE_ELEMENT | \
MPT_SGE_FLAGS_ADDRESSING | \
MPT_TRANSFER_HOST_TO_IOC)

/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
Expand Down
37 changes: 19 additions & 18 deletions drivers/message/fusion/mptctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -841,8 +841,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
* 96 8
* 64 4
*/
maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) - sizeof(FWDownloadTCSGE_t))
/ (sizeof(dma_addr_t) + sizeof(u32));
maxfrags = (iocp->req_sz - sizeof(MPIHeader_t) -
sizeof(FWDownloadTCSGE_t))
/ iocp->SGE_size;
if (numfrags > maxfrags) {
ret = -EMLINK;
goto fwdl_out;
Expand Down Expand Up @@ -870,7 +871,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
if (nib == 0 || nib == 3) {
;
} else if (sgIn->Address) {
mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
iocp->add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
n++;
if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
Expand All @@ -882,7 +883,7 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
}
sgIn++;
bl++;
sgOut += (sizeof(dma_addr_t) + sizeof(u32));
sgOut += iocp->SGE_size;
}

DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
Expand Down Expand Up @@ -1003,7 +1004,7 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
*
*/
sgl = sglbuf;
sg_spill = ((ioc->req_sz - sge_offset)/(sizeof(dma_addr_t) + sizeof(u32))) - 1;
sg_spill = ((ioc->req_sz - sge_offset)/ioc->SGE_size) - 1;
while (bytes_allocd < bytes) {
this_alloc = min(alloc_sz, bytes-bytes_allocd);
buflist[buflist_ent].len = this_alloc;
Expand All @@ -1024,8 +1025,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
dma_addr_t dma_addr;

bytes_allocd += this_alloc;
sgl->FlagsLength = (0x10000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|this_alloc);
dma_addr = pci_map_single(ioc->pcidev, buflist[buflist_ent].kptr, this_alloc, dir);
sgl->FlagsLength = (0x10000000|sgdir|this_alloc);
dma_addr = pci_map_single(ioc->pcidev,
buflist[buflist_ent].kptr, this_alloc, dir);
sgl->Address = dma_addr;

fragcnt++;
Expand Down Expand Up @@ -1799,9 +1801,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
*/
sz = karg.dataSgeOffset * 4;
if (karg.dataInSize > 0)
sz += sizeof(dma_addr_t) + sizeof(u32);
sz += ioc->SGE_size;
if (karg.dataOutSize > 0)
sz += sizeof(dma_addr_t) + sizeof(u32);
sz += ioc->SGE_size;

if (sz > ioc->req_sz) {
printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
Expand Down Expand Up @@ -1893,7 +1895,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
}

pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
pScsiReq->MsgFlags |= mpt_msg_flags();
pScsiReq->MsgFlags |= mpt_msg_flags(ioc);


/* verify that app has not requested
Expand Down Expand Up @@ -1979,7 +1981,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
int dataSize;

pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
pScsiReq->MsgFlags |= mpt_msg_flags();
pScsiReq->MsgFlags |= mpt_msg_flags(ioc);


/* verify that app has not requested
Expand Down Expand Up @@ -2123,8 +2125,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
if (karg.dataInSize > 0) {
flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_DIRECTION |
mpt_addr_size() )
MPI_SGE_FLAGS_DIRECTION)
<< MPI_SGE_FLAGS_SHIFT;
} else {
flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE;
Expand All @@ -2141,8 +2142,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
/* Set up this SGE.
* Copy to MF and to sglbuf
*/
mpt_add_sge(psge, flagsLength, dma_addr_out);
psge += (sizeof(u32) + sizeof(dma_addr_t));
ioc->add_sge(psge, flagsLength, dma_addr_out);
psge += ioc->SGE_size;

/* Copy user data to kernel space.
*/
Expand Down Expand Up @@ -2175,13 +2176,13 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
/* Set up this SGE
* Copy to MF and to sglbuf
*/
mpt_add_sge(psge, flagsLength, dma_addr_in);
ioc->add_sge(psge, flagsLength, dma_addr_in);
}
}
} else {
/* Add a NULL SGE
*/
mpt_add_sge(psge, flagsLength, (dma_addr_t) -1);
ioc->add_sge(psge, flagsLength, (dma_addr_t) -1);
}

ioc->ioctl->wait_done = 0;
Expand Down Expand Up @@ -2498,7 +2499,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma);
if (!pbuf)
goto out;
mpt_add_sge((char *)&IstwiRWRequest->SGL,
ioc->add_sge((char *)&IstwiRWRequest->SGL,
(MPT_SGE_FLAGS_SSIMPLE_READ|4), buf_dma);

ioc->ioctl->wait_done = 0;
Expand Down
3 changes: 3 additions & 0 deletions drivers/message/fusion/mptdebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#define MPT_DEBUG_FC 0x00080000
#define MPT_DEBUG_SAS 0x00100000
#define MPT_DEBUG_SAS_WIDE 0x00200000
#define MPT_DEBUG_36GB_MEM 0x00400000

/*
* CONFIG_FUSION_LOGGING - enabled in Kconfig
Expand Down Expand Up @@ -135,6 +136,8 @@
#define dsaswideprintk(IOC, CMD) \
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)

#define d36memprintk(IOC, CMD) \
MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_36GB_MEM)


/*
Expand Down
10 changes: 4 additions & 6 deletions drivers/message/fusion/mptfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1251,17 +1251,15 @@ mptfc_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) {
Expand Down
18 changes: 8 additions & 10 deletions drivers/message/fusion/mptsas.c
Original file line number Diff line number Diff line change
Expand Up @@ -1319,15 +1319,15 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
/* request */
flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_DIRECTION |
mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
MPI_SGE_FLAGS_DIRECTION)
<< MPI_SGE_FLAGS_SHIFT;
flagsLength |= (req->data_len - 4);

dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
req->data_len, PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_out)
goto put_mf;
mpt_add_sge(psge, flagsLength, dma_addr_out);
ioc->add_sge(psge, flagsLength, dma_addr_out);
psge += (sizeof(u32) + sizeof(dma_addr_t));

/* response */
Expand All @@ -1337,7 +1337,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
rsp->data_len, PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_in)
goto unmap;
mpt_add_sge(psge, flagsLength, dma_addr_in);
ioc->add_sge(psge, flagsLength, dma_addr_in);

mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);

Expand Down Expand Up @@ -3211,17 +3211,15 @@ mptsas_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) {
Expand Down
Loading

0 comments on commit 14d0f0b

Please sign in to comment.