From 44e7d4f0b98d887c1a887f29edad1e255fde39a3 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Thu, 2 Aug 2012 18:36:31 +0200
Subject: [PATCH 2/2] hptrr(4): avoid exessively fragmented bufs.

---
 sys/dev/raid/hptrr/hptrr_osm_bsd.c |   83 +++++++++++++++++++++++++-----------
 sys/dev/raid/hptrr/os_bsd.h        |    6 +++
 2 files changed, 64 insertions(+), 25 deletions(-)

diff --git a/sys/dev/raid/hptrr/hptrr_osm_bsd.c b/sys/dev/raid/hptrr/hptrr_osm_bsd.c
index 167ccda..0240384 100644
--- a/sys/dev/raid/hptrr/hptrr_osm_bsd.c
+++ b/sys/dev/raid/hptrr/hptrr_osm_bsd.c
@@ -462,14 +462,19 @@ static void os_cmddone(PCOMMAND pCmd)
 		break;
 	}
 
-	if (pCmd->flags.data_in) {
-		bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_POSTREAD);
-	}
-	else if (pCmd->flags.data_out) {
-		bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_POSTWRITE);
-	}
+	if (!ext->buf_used) {
+		if (pCmd->flags.data_in) {
+			bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_POSTREAD);
+		}
+		else if (pCmd->flags.data_out) {
+			bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_POSTWRITE);
+		}
 
-	bus_dmamap_unload(ext->vbus_ext->io_dmat, ext->dma_map);
+		bus_dmamap_unload(ext->vbus_ext->io_dmat, ext->dma_map);
+	} else {
+		if (pCmd->flags.data_in)
+			bcopy(ext->buf, ccb->csio.data_ptr, ccb->csio.dxfer_len);
+	}
 
 	cmdext_put(ext);
 	ldm_free_cmds(pCmd);
@@ -531,11 +536,13 @@ static void hpt_io_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs
 	}
 	psg[-1].eot = 1;
 
-	if (pCmd->flags.data_in) {
-		bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_PREREAD);
-	}
-	else if (pCmd->flags.data_out) {
-		bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_PREWRITE);
+	if (!ext->buf_used) {
+		if (pCmd->flags.data_in) {
+			bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_PREREAD);
+		}
+		else if (pCmd->flags.data_out) {
+			bus_dmamap_sync(ext->vbus_ext->io_dmat, ext->dma_map, BUS_DMASYNC_PREWRITE);
+		}
 	}
 
 	callout_reset(&ext->ccb->ccb_h.timeout_ch, HPT_OSM_TIMEOUT, hpt_timeout, pCmd);
@@ -741,19 +748,38 @@ static void hpt_scsi_io(PVBUS_EXT vbus_ext, union ccb *ccb)
 		else {
 			int error;
 			pCmd->flags.physical_sg = 1;
-			error = bus_dmamap_load(vbus_ext->io_dmat,
-						ext->dma_map,
-						ccb->csio.data_ptr, ccb->csio.dxfer_len,
-						hpt_io_dmamap_callback, pCmd,
-					BUS_DMA_WAITOK
-					);
-			KdPrint(("bus_dmamap_load return %d", error));
-			if (error && error!=EINPROGRESS) {
-				os_printk("bus_dmamap_load error %d", error);
-				cmdext_put(ext);
-				ldm_free_cmds(pCmd);
-				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-				xpt_done(ccb);
+
+			if (ccb->csio.dxfer_len > 0x20000)
+				panic("grrr, too large again\n");
+
+			if (ccb->csio.dxfer_len > 0x10000) {
+				bus_dma_segment_t segs[2];
+
+				if (pCmd->flags.data_out)
+					bcopy(ccb->csio.data_ptr, ext->buf, ccb->csio.dxfer_len);
+
+				segs[0].ds_addr = ext->buf_paddr;
+				segs[0].ds_len = 0x10000;
+				segs[1].ds_addr = ext->buf_paddr + 0x10000;
+				segs[1].ds_len = ccb->csio.dxfer_len - 0x10000;
+				ext->buf_used = 1;
+				hpt_io_dmamap_callback(pCmd, segs, 2, 0);
+			} else {
+				ext->buf_used = 0;
+				error = bus_dmamap_load(vbus_ext->io_dmat,
+							ext->dma_map,
+							ccb->csio.data_ptr, ccb->csio.dxfer_len,
+							hpt_io_dmamap_callback, pCmd,
+						BUS_DMA_WAITOK
+						);
+				KdPrint(("bus_dmamap_load return %d", error));
+				if (error && error!=EINPROGRESS) {
+					os_printk("bus_dmamap_load error %d", error);
+					cmdext_put(ext);
+					ldm_free_cmds(pCmd);
+					ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+					xpt_done(ccb);
+				}
 			}
 		}
 		return;
@@ -1067,6 +1093,13 @@ static void hpt_final_init(void *dummy)
 			ext->next = vbus_ext->cmdext_list;
 			vbus_ext->cmdext_list = ext;
 
+			ext->buf = bus_dmamem_coherent_any(NULL, 4, 0x20000, BUS_DMA_WAITOK,
+					&ext->buf_dtag, &ext->buf_dmap, &ext->buf_paddr);
+			if (ext->buf == NULL) {
+				os_printk("Can't create buffer");
+				return;
+			}
+
 			if (bus_dmamap_create(vbus_ext->io_dmat, 0, &ext->dma_map)) {
 				os_printk("Can't create dma map(%d)", i);
 				return ;
diff --git a/sys/dev/raid/hptrr/os_bsd.h b/sys/dev/raid/hptrr/os_bsd.h
index 5703387..7227185 100644
--- a/sys/dev/raid/hptrr/os_bsd.h
+++ b/sys/dev/raid/hptrr/os_bsd.h
@@ -155,6 +155,12 @@ typedef struct _os_cmdext {
 	struct _os_cmdext *next;
 	union ccb         *ccb;
 	bus_dmamap_t       dma_map;
+
+	int		   buf_used;
+	bus_dma_tag_t	   buf_dtag;
+	bus_dmamap_t	   buf_dmap;
+	bus_addr_t	   buf_paddr;
+	void		  *buf;
 	SG                 psg[os_max_sg_descriptors];
 }
 OS_CMDEXT, *POS_CMDEXT;
-- 
1.7.10.5

