Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3525

kernel-2.6.18-194.11.1.el5.src.rpm

From: Tomas Henzl <thenzl@redhat.com>
Date: Fri, 31 Jul 2009 17:27:50 +0300
Subject: [scsi] mptfusion: revert to pci_map
Message-id: 4A72FF66.2060301@redhat.com
O-Subject: [RHEL5.4 PATCH] revert to pci_map
Bugzilla: 514049
RH-Acked-by: Mike Christie <mchristi@redhat.com>
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>

This resolves bz#514049

Description of problem: a system panics and system doesn't boot when
ETERNUSmpd is installed. Eternum is closed-source multipath driver.
http://solutions.us.fujitsu.com/www/content/products/storage/ETERNUS/software.php

----------2.6.18-128.el5
  /* Map the data portion, if any.
   * sges_left  = 0 if no data transfer.
   */
  if ( (sges_left = scsi_sg_count(SCpnt)) ) {
          sges_left = pci_map_sg(ioc->pcidev,
                          scsi_sglist(SCpnt),
                          scsi_sg_count(SCpnt),
                          SCpnt->sc_data_direction);
          if (sges_left == 0)
                  return FAILED;
  } else if (SCpnt->request_bufflen) {
         SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
                               SCpnt->request_buffer,
                               SCpnt->request_bufflen,
                               SCpnt->sc_data_direction);
         dsgprintk(ioc,printk(MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
                         ioc->name, SCpnt, SCpnt->request_bufflen));
         ioc->add_sge((char *) &pReq->SGL,
                0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
                 SCpnt->SCp.dma_handle);

         return SUCCESS;
  }
----------

----------2.6.18-155.el5
/* Map the data portion, if any.
  * sges_left  = 0 if no data transfer.
  */
sges_left = scsi_dma_map(SCpnt);
if (sges_left < 0)
	return FAILED;
----------

ETERNUSmpd issues a command when a system boots, and the
command goes through mptscsih_AddSGE() in mptscsih.c.
This command has no scatter/gather entry, so, in the
above part, sges_left is set to 0, and a value is setup
in SCpnt->request_bufflen.
On kernel 2.6.18-128.el5, fusion returns a response to
ETERNUSmpd's command ("else if" part).
However, on kernel 2.6.18-155.el5, fusion continues its
process without returning a response to ETERNUSmpd's command.
As a result of it, ETERNUSmpd didn't run normally and the
system panicked.
----------

Patch itself reverts calls to scsi_map(unmap) to approximately
what we used to have in the previous version.

I only compile/boot tested this on i686, PAE, x86_64.
I can't verify that this resolves the issue, I asked the reporter
to do this, I'll then post the results.

http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1912689

Tomas

diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 6479dc6..fefcaf3 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -200,9 +200,26 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
 	/* Map the data portion, if any.
 	 * sges_left  = 0 if no data transfer.
 	 */
-	sges_left = scsi_dma_map(SCpnt);
-	if (sges_left < 0)
-		return FAILED;
+	if ( (sges_left = scsi_sg_count(SCpnt)) ) {
+		sges_left = pci_map_sg(ioc->pcidev,
+				scsi_sglist(SCpnt),
+				scsi_sg_count(SCpnt),
+				SCpnt->sc_data_direction);
+		if (sges_left == 0)
+			return FAILED;
+	} else if (SCpnt->request_bufflen) {
+		SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
+				      SCpnt->request_buffer,
+				      SCpnt->request_bufflen,
+				      SCpnt->sc_data_direction);
+		dsgprintk(ioc,printk(MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
+				ioc->name, SCpnt, SCpnt->request_bufflen));
+		ioc->add_sge((char *) &pReq->SGL,
+			0xD1000000|sgdir|SCpnt->request_bufflen,
+			SCpnt->SCp.dma_handle);
+
+		return SUCCESS;
+	}
 
 	/* Handle the SG case.
 	 */
@@ -883,7 +900,13 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 	} /* end of address reply case */
 
 	/* Unmap the DMA buffers, if any. */
-	scsi_dma_unmap(sc);
+	if (sc->use_sg) {
+		pci_unmap_sg(ioc->pcidev, scsi_sglist(sc),
+				scsi_sg_count(sc), sc->sc_data_direction);
+	} else if (sc->request_bufflen) {
+		pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
+				sc->request_bufflen, sc->sc_data_direction);
+	}
 
 	sc->scsi_done(sc);		/* Issue the command callback */
 
@@ -924,7 +947,17 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
 		mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
 		if ((unsigned char *)mf != sc->host_scribble)
 			continue;
-		scsi_dma_unmap(sc);
+		if (sc->use_sg) {
+			pci_unmap_sg(ioc->pcidev,
+				scsi_sglist(sc),
+				scsi_sg_count(sc),
+				sc->sc_data_direction);
+		} else if (sc->request_bufflen) {
+			pci_unmap_single(ioc->pcidev,
+				sc->SCp.dma_handle,
+				sc->request_bufflen,
+				sc->sc_data_direction);
+		}
 		sc->result = DID_RESET << 16;
 		sc->host_scribble = NULL;
 		sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
@@ -985,7 +1018,17 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
 			spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
 			mptscsih_freeChainBuffers(ioc, ii);
 			mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
-			scsi_dma_unmap(sc);
+			if (sc->use_sg) {
+				pci_unmap_sg(hd->ioc->pcidev,
+				(struct scatterlist *) sc->request_buffer,
+					sc->use_sg,
+					sc->sc_data_direction);
+			} else if (sc->request_bufflen) {
+				pci_unmap_single(hd->ioc->pcidev,
+					sc->SCp.dma_handle,
+					sc->request_bufflen,
+					sc->sc_data_direction);
+			}
 			sc->host_scribble = NULL;
 			sc->result = DID_NO_CONNECT << 16;
 			sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"