mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 5/5]  arcmsr: Modify ARC-1214 IO Behavior
@ 2012-11-15  7:33 NickCheng
  0 siblings, 0 replies; 3+ messages in thread
From: NickCheng @ 2012-11-15  7:33 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-kernel, jejb

[-- Attachment #1: Type: text/plain, Size: 166 bytes --]

From: Nick Cheng <nick.cheng@areca.com.tw>

Modify ARC-1214 IO behavior to make up for HW seldom malfunction.
Signed-off-by: Nick Cheng <nick.cheng@areca.com.tw>
---

[-- Attachment #2: patch5 --]
[-- Type: application/octet-stream, Size: 16628 bytes --]

diff -uprN a//drivers/scsi/arcmsr/arcmsr.h b//drivers/scsi/arcmsr/arcmsr.h
--- a//drivers/scsi/arcmsr/arcmsr.h	2012-11-15 12:12:19.035557259 +0800
+++ b//drivers/scsi/arcmsr/arcmsr.h	2012-11-15 15:04:34.291456858 +0800
@@ -63,6 +63,7 @@ struct device_attribute;
 #define ARCMSR_DEFAULT_SG_ENTRIES		38
 #define ARCMSR_MAX_HBB_POSTQUEUE		264
 #define ARCMSR_MAX_ARC1214_POSTQUEUE		256
+#define ARCMSR_MAX_ARC1214_DONEQUEUE		257
 #define ARCMSR_MAX_XFER_LEN			0x26000
 #define ARCMSR_CDB_SG_PAGE_LENGTH		256
 #define ARCMST_NUM_MSIX_VECTORS		4
@@ -175,8 +176,8 @@ struct  SG64ENTRY
 */
 struct QBUFFER
 {
-	uint32_t data_len;
-	uint8_t data[124];
+	uint32_t __iomem data_len;
+	uint8_t __iomem data[124];
 };
 /*
 *******************************************************************************
@@ -565,7 +566,7 @@ struct OutBound_SRB {
 
 struct MessageUnit_D {
  	struct InBound_SRB post_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE];
-   	struct OutBound_SRB done_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE];
+   	struct OutBound_SRB done_qbuffer[ARCMSR_MAX_ARC1214_DONEQUEUE];
 	u16 postq_index;
 	u16 doneq_index;
 	u32 __iomem *chip_id;			//0x00004
@@ -618,6 +619,7 @@ struct AdapterControlBlock
 	spinlock_t eh_lock;
 	spinlock_t ccblist_lock;
 	spinlock_t postq_lock;
+	spinlock_t doneq_lock;
 	spinlock_t rqbuffer_lock;
 	spinlock_t wqbuffer_lock;
 	union {
@@ -671,15 +673,15 @@ struct AdapterControlBlock
 	unsigned int uncache_size;
 	uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
 	/* data collection buffer for read from 80331 */
-	int32_t rqbuf_firstindex;
+	uint32_t rqbuf_firstindex;
 	/* first of read buffer  */
-	int32_t rqbuf_lastindex;
+	uint32_t rqbuf_lastindex;
 	/* last of read buffer   */
 	uint8_t wqbuffer[ARCMSR_MAX_QBUFFER];
 	/* data collection buffer for write to 80331  */
-	int32_t wqbuf_firstindex;
+	uint32_t wqbuf_firstindex;
 	/* first of write buffer */
-	int32_t wqbuf_lastindex;
+	uint32_t wqbuf_lastindex;
 	/* last of write buffer  */
 	uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
 	/* id0 ..... id15, lun0...lun7 */
diff -uprN a//drivers/scsi/arcmsr/arcmsr_hba.c b//drivers/scsi/arcmsr/arcmsr_hba.c
--- a//drivers/scsi/arcmsr/arcmsr_hba.c	2012-11-15 12:12:40.851557048 +0800
+++ b//drivers/scsi/arcmsr/arcmsr_hba.c	2012-11-15 15:04:34.319456858 +0800
@@ -1106,6 +1106,7 @@ static int arcmsr_probe(struct pci_dev *
 	spin_lock_init(&acb->eh_lock);
 	spin_lock_init(&acb->ccblist_lock);
 	spin_lock_init(&acb->postq_lock);
+	spin_lock_init(&acb->doneq_lock);
 	spin_lock_init(&acb->rqbuffer_lock);
 	spin_lock_init(&acb->wqbuffer_lock);
 	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
@@ -1247,6 +1248,7 @@ arcmsr_hbaB_abort_allcmd(struct AdapterC
 	}
 	return true;
 }
+
 static uint8_t
 arcmsr_hbaC_abort_allcmd(struct AdapterControlBlock *pACB)
 {
@@ -1261,6 +1263,7 @@ arcmsr_hbaC_abort_allcmd(struct AdapterC
 	}
 	return true;
 }
+
 static uint8_t
 arcmsr_hbaD_abort_allcmd(struct AdapterControlBlock *pACB)
 {
@@ -1274,6 +1277,7 @@ arcmsr_hbaD_abort_allcmd(struct AdapterC
 	}
 	return true;
 }
+
 static uint8_t
 arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
 {
@@ -1554,29 +1558,29 @@ arcmsr_done4abort_postqueue(struct Adapt
 		uint32_t doneq_index, index_stripped, addressLow, residual;
 		bool error;
 		struct CommandControlBlock *pCCB;
-		outbound_write_pointer = ioread32(pmu->outboundlist_copy_pointer);
+		outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
 		doneq_index = pmu->doneq_index;
 		residual = atomic_read(&acb->ccboutstandingcount);
 		for (i = 0; i < residual; i++) {
-			while ((doneq_index & 0xFF) != (outbound_write_pointer & 0xFF)) {
+			while ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
 				if (doneq_index & 0x4000) {
-					index_stripped = doneq_index & 0xFF;
+					index_stripped = doneq_index & 0xFFF;
 					index_stripped += 1;
 					index_stripped %=
-					ARCMSR_MAX_ARC1214_POSTQUEUE;
+					ARCMSR_MAX_ARC1214_DONEQUEUE;
 					pmu->doneq_index = index_stripped ?
-					(index_stripped | 0x4000) : index_stripped;
+					(index_stripped | 0x4000) : (index_stripped + 1);
 				} else {
 					index_stripped = doneq_index;
 					index_stripped += 1;
 					index_stripped %=
-					ARCMSR_MAX_ARC1214_POSTQUEUE;
+					ARCMSR_MAX_ARC1214_DONEQUEUE;
 					pmu->doneq_index =
-					index_stripped ? index_stripped : (index_stripped | 0x4000);
+					index_stripped ? index_stripped : ((index_stripped | 0x4000) + 1);
 				}
 				doneq_index = pmu->doneq_index;
 				addressLow =
-				pmu->done_qbuffer[doneq_index & 0xFF].addressLow;
+				pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
 				ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
 				pARCMSR_CDB = (struct  ARCMSR_CDB *)
 				(acb->vir2phy_offset + ccb_cdb_phy);
@@ -1591,7 +1595,7 @@ arcmsr_done4abort_postqueue(struct Adapt
 			}
 			mdelay(10);
 			outbound_write_pointer =
-				ioread32(pmu->outboundlist_copy_pointer);
+				pmu->done_qbuffer[0].addressLow + 1;
 			doneq_index = pmu->doneq_index;
 		}
 		pmu->postq_index = 0;
@@ -2148,10 +2152,9 @@ struct QBUFFER __iomem
 void
 arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
 {
-	uint8_t __iomem *iop_data;
+	uint8_t __iomem *iop_data, *pQbuffer, *vaddr, *temp;
 	struct QBUFFER __iomem *prbuffer;
-	struct QBUFFER *pQbuffer;
-	int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+	int32_t my_empty_len, data_len, rqbuf_firstindex, rqbuf_lastindex;
 	unsigned long flags;
 
 	spin_lock_irqsave(&acb->rqbuffer_lock, flags);
@@ -2159,22 +2162,33 @@ arcmsr_iop2drv_data_wrote_handle(struct
 	rqbuf_firstindex = acb->rqbuf_firstindex;
 	prbuffer = arcmsr_get_iop_rqbuffer(acb);
 	iop_data = (uint8_t __iomem *)prbuffer->data;
-	iop_len = prbuffer->data_len;
+	data_len = prbuffer->data_len;
 	my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) &
 	(ARCMSR_MAX_QBUFFER - 1);
 
-	if (my_empty_len >= iop_len) {
-		while (iop_len > 0) {
-			pQbuffer = (struct QBUFFER *)
-			&acb->rqbuffer[rqbuf_lastindex];
-			memcpy(pQbuffer, iop_data, 1);
-			rqbuf_lastindex++;
-			rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-			iop_data++;
-			iop_len--;
+	if (my_empty_len >= data_len) {
+		if (data_len > 0) {
+			temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+			memcpy(vaddr, iop_data, data_len);
+			smp_mb();
+			pQbuffer = &acb->rqbuffer[rqbuf_lastindex];
+			if ((rqbuf_lastindex + data_len)
+			> ARCMSR_MAX_QBUFFER) {
+				memcpy(pQbuffer, temp, ARCMSR_MAX_QBUFFER
+				- rqbuf_lastindex);
+				temp += (ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+				rqbuf_lastindex = (rqbuf_lastindex + data_len)
+				% ARCMSR_MAX_QBUFFER;
+				memcpy(&acb->rqbuffer[0], temp, rqbuf_lastindex);
+			} else {
+				memcpy(pQbuffer, temp, data_len);
+				rqbuf_lastindex = (rqbuf_lastindex + data_len)
+				% ARCMSR_MAX_QBUFFER;
+			}
+			kfree(vaddr);
 		}
-		acb->rqbuf_lastindex = rqbuf_lastindex;
-		arcmsr_iop_message_read(acb);
+        		acb->rqbuf_lastindex = rqbuf_lastindex;
+		arcmsr_iop_message_read(acb);/*notice IOP the message is read*/
 	} else {
 		acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
 	}
@@ -2238,6 +2252,7 @@ arcmsr_hbaA_doorbell_isr(struct AdapterC
 	(ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK
 	| ARCMSR_OUTBOUND_IOP331_DATA_READ_OK));
 }
+
 static void
 arcmsr_hbaC_doorbell_isr(struct AdapterControlBlock *pACB)
 {
@@ -2392,28 +2407,30 @@ arcmsr_hbaD_postqueue_isr(struct Adapter
 	struct MessageUnit_D __iomem *pmu;
 	struct ARCMSR_CDB *arcmsr_cdb;
 	struct CommandControlBlock *ccb;
+	unsigned long flags;
 
+	spin_lock_irqsave(&acb->doneq_lock, flags);
 	pmu = (struct MessageUnit_D *)acb->pmuD;
-	outbound_write_pointer = ioread32(pmu->outboundlist_copy_pointer);
+	outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
 	doneq_index = pmu->doneq_index;
-	if ((doneq_index & 0xFF) != (outbound_write_pointer & 0xFF)) {
+	if ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
 		do {
 			if (doneq_index & 0x4000) {
-				index_stripped = doneq_index & 0xFF;
+				index_stripped = doneq_index & 0xFFF;
 				index_stripped += 1;
-				index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
+				index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
 				pmu->doneq_index = index_stripped
-				? (index_stripped | 0x4000) : index_stripped;
+				? (index_stripped | 0x4000) : (index_stripped + 1);
 			} else {
 				index_stripped = doneq_index;
 				index_stripped += 1;
-				index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
+				index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
 				pmu->doneq_index = index_stripped
-				? index_stripped : (index_stripped | 0x4000);
+				? index_stripped : ((index_stripped | 0x4000) + 1);
 			}
 			doneq_index = pmu->doneq_index;
 			addressLow =
-			pmu->done_qbuffer[doneq_index & 0xFF].addressLow;
+			pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
 			ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
 			arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
 				+ ccb_cdb_phy);
@@ -2424,12 +2441,13 @@ arcmsr_hbaD_postqueue_isr(struct Adapter
 			arcmsr_drain_donequeue(acb, ccb, error);
 			iowrite32(doneq_index,
 				pmu->outboundlist_read_pointer);
-		} while ((doneq_index & 0xFF) !=
-		(outbound_write_pointer & 0xFF));
+		} while ((doneq_index & 0xFFF) !=
+		(outbound_write_pointer & 0xFFF));
 	}
 	iowrite32(ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR,
 		pmu->outboundlist_interrupt_cause);
 	ioread32(pmu->outboundlist_interrupt_cause);
+	spin_unlock_irqrestore(&acb->doneq_lock, flags);
 }
 
 static void
@@ -2440,6 +2458,7 @@ arcmsr_hbaA_message_isr(struct AdapterCo
 	iowrite32(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, &reg->outbound_intstatus);
 	schedule_work(&acb->arcmsr_do_message_isr_bh);
 }
+
 static void
 arcmsr_hbaB_message_isr(struct AdapterControlBlock *acb)
 {
@@ -2694,33 +2713,96 @@ arcmsr_iop_message_xfer(struct AdapterCo
 		}
 		ptmpQbuffer = ver_addr;
 		spin_lock_irqsave(&acb->rqbuffer_lock, flags);
-		while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
-			&& (allxfer_len < 1031)) {
+		if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) {
 			pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
-			memcpy(ptmpQbuffer, pQbuffer, 1);
-			acb->rqbuf_firstindex++;
-			acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-			ptmpQbuffer++;
-			allxfer_len++;
+			if (acb->rqbuf_firstindex > acb->rqbuf_lastindex) {
+				if ((ARCMSR_MAX_QBUFFER -
+					acb->rqbuf_firstindex) >= 1032) {
+					memcpy(ptmpQbuffer, pQbuffer, 1032);
+					acb->rqbuf_firstindex += 1032;
+					allxfer_len = 1032;
+				} else {
+					if (((ARCMSR_MAX_QBUFFER -
+						acb->rqbuf_firstindex)
+						+ acb->rqbuf_lastindex) > 1032) {
+						memcpy(ptmpQbuffer, pQbuffer,
+						ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						ptmpQbuffer += ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex;
+						memcpy(ptmpQbuffer, acb->rqbuffer,
+						1032 - (ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex));
+						acb->rqbuf_firstindex = 1032 -
+						(ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						allxfer_len = 1032;
+					} else {
+						memcpy(ptmpQbuffer, pQbuffer,
+						ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						ptmpQbuffer += ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex;
+						memcpy(ptmpQbuffer, acb->rqbuffer,
+						acb->rqbuf_lastindex);
+						allxfer_len = ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex
+						+ acb->rqbuf_lastindex;
+						acb->rqbuf_firstindex =
+						acb->rqbuf_lastindex;
+					}
+				}
+			} else {
+				if ((acb->rqbuf_lastindex
+				- acb->rqbuf_firstindex) > 1032) {
+					memcpy(ptmpQbuffer,
+					pQbuffer, 1032);
+					acb->rqbuf_firstindex += 1032;
+					allxfer_len = 1032;
+				} else {
+					memcpy(ptmpQbuffer,
+					pQbuffer,
+					acb->rqbuf_lastindex
+					- acb->rqbuf_firstindex);
+					allxfer_len = acb->rqbuf_lastindex
+					- acb->rqbuf_firstindex;
+					acb->rqbuf_firstindex
+					= acb->rqbuf_lastindex;
+				}
+			}
 		}
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
-
 			struct QBUFFER __iomem *prbuffer;
-			uint8_t __iomem *iop_data;
-			int32_t iop_len;
-
-			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+			uint8_t __iomem *iop_data, *vaddr, *temp;
+        			uint32_t data_len, rqbuf_lastindex;
+        			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+			rqbuf_lastindex = acb->rqbuf_lastindex;
 			prbuffer = arcmsr_get_iop_rqbuffer(acb);
-			iop_data = prbuffer->data;
-			iop_len = ioread32(&prbuffer->data_len);
-			while (iop_len > 0) {
-				acb->rqbuffer[acb->rqbuf_lastindex] =
-				ioread8(iop_data);
-				acb->rqbuf_lastindex++;
-				acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-				iop_data++;
-				iop_len--;
+			iop_data = (uint8_t __iomem *)prbuffer->data;
+			data_len = ioread32(&prbuffer->data_len);
+			if (data_len > 0) {
+				temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+				memcpy(vaddr, iop_data, data_len);
+				smp_mb();
+				pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex];
+				if ((rqbuf_lastindex + data_len) >
+					ARCMSR_MAX_QBUFFER) {
+					memcpy(pQbuffer, temp,
+					ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+					temp += (ARCMSR_MAX_QBUFFER
+					- rqbuf_lastindex);
+					rqbuf_lastindex = (rqbuf_lastindex
+					+ data_len) % ARCMSR_MAX_QBUFFER;
+					memcpy(&acb->rqbuffer[0],
+					temp, rqbuf_lastindex);
+				} else {
+					memcpy(pQbuffer, temp, data_len);
+					rqbuf_lastindex = (rqbuf_lastindex +
+					data_len) % ARCMSR_MAX_QBUFFER;
+				}
+				kfree(vaddr);
 			}
+			acb->rqbuf_lastindex = rqbuf_lastindex;
 			arcmsr_iop_message_read(acb);
 		}
 		spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
@@ -3641,19 +3723,21 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
 {
 	bool error;
 	uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb, ccb_cdb_phy;
-	int rtn, index, outbound_write_pointer;
+	int rtn, doneq_index, index_stripped, outbound_write_pointer;
+	unsigned long flags;
 	struct ARCMSR_CDB *arcmsr_cdb;
 	struct CommandControlBlock *pCCB;
-	struct MessageUnit_D __iomem *reg =
+	struct MessageUnit_D __iomem *pmu =
 		(struct MessageUnit_D *)acb->pmuD;
 
+	spin_lock_irqsave(&acb->doneq_lock, flags);
 	polling_hbaD_ccb_retry:
 	poll_count++;
 	while (1) {
 		outbound_write_pointer =
-			ioread32(reg->outboundlist_copy_pointer);
-		index = reg->doneq_index;
-		if ((outbound_write_pointer & 0xFF) == index) {
+		pmu->done_qbuffer[0].addressLow + 1;
+		doneq_index = pmu->doneq_index;
+		if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
 			if (poll_ccb_done) {
 				rtn = SUCCESS;
 				break;
@@ -3666,17 +3750,27 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
 				goto polling_hbaD_ccb_retry;
 			}
 		}
-		flag_ccb = reg->done_qbuffer[index].addressLow;
+		if (doneq_index & 0x4000) {
+			index_stripped = doneq_index & 0xFFF;
+			index_stripped += 1;
+			index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+			pmu->doneq_index = index_stripped ? (index_stripped | 0x4000)
+				: (index_stripped + 1);
+		} else {
+			index_stripped = doneq_index;
+			index_stripped += 1;
+			index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+			pmu->doneq_index = index_stripped ? index_stripped :
+				((index_stripped | 0x4000) + 1);
+		}
+		doneq_index = pmu->doneq_index;
+		flag_ccb = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
 		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
 		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset +
 			ccb_cdb_phy);
 		pCCB = container_of(arcmsr_cdb,
 			struct CommandControlBlock, arcmsr_cdb);
 		poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
-		index++;
-		index %= ARCMSR_MAX_ARC1214_POSTQUEUE;
-		reg->doneq_index = index;
-		/* check if command done with no error*/
 		if ((pCCB->acb != acb) ||
 		(pCCB->startdone != ARCMSR_CCB_START)) {
 			if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
@@ -3703,6 +3797,7 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
 		? true : false;
 		arcmsr_report_ccb_state(acb, pCCB, error);
 	}
+	spin_unlock_irqrestore(&acb->doneq_lock, flags);
 	return rtn;
 }
 
@@ -3838,7 +3933,7 @@ arcmsr_iop_confirm(struct AdapterControl
 		struct MessageUnit_D *reg =
 			(struct MessageUnit_D *)acb->pmuD;
 		reg->postq_index = 0;
-		reg->doneq_index = 0x40FF;
+		reg->doneq_index = 0;
 		rwbuffer = reg->msgcode_rwbuffer;
 		iowrite32(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
 		iowrite32(cdb_phyaddr_hi32, rwbuffer++);

^ permalink raw reply	[flat|nested] 3+ messages in thread
* [PATCH 5/5]  arcmsr: Modify ARC-1214 IO Behavior
@ 2012-11-16 11:56 NickCheng
  2012-11-30  9:18 ` James Bottomley
  0 siblings, 1 reply; 3+ messages in thread
From: NickCheng @ 2012-11-16 11:56 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-kernel, jejb

[-- Attachment #1: Type: text/plain, Size: 166 bytes --]

From: Nick Cheng <nick.cheng@areca.com.tw>

Modify ARC-1214 IO behavior to make up for HW seldom malfunction.
Signed-off-by: Nick Cheng <nick.cheng@areca.com.tw>
---

[-- Attachment #2: patch5 --]
[-- Type: application/octet-stream, Size: 15110 bytes --]

diff -uprN a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
--- a/drivers/scsi/arcmsr/arcmsr.h	2012-11-16 18:07:40.052372519 +0800
+++ b/drivers/scsi/arcmsr/arcmsr.h	2012-11-16 18:52:25.840453468 +0800
@@ -63,6 +63,7 @@ struct device_attribute;
 #define ARCMSR_DEFAULT_SG_ENTRIES		38
 #define ARCMSR_MAX_HBB_POSTQUEUE		264
 #define ARCMSR_MAX_ARC1214_POSTQUEUE		256
+#define ARCMSR_MAX_ARC1214_DONEQUEUE		257
 #define ARCMSR_MAX_XFER_LEN			0x26000
 #define ARCMSR_CDB_SG_PAGE_LENGTH		256
 #define ARCMST_NUM_MSIX_VECTORS		4
@@ -564,7 +565,7 @@ struct OutBound_SRB {
 
 struct MessageUnit_D {
 	struct InBound_SRB post_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE];
-	struct OutBound_SRB done_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE];
+	struct OutBound_SRB done_qbuffer[ARCMSR_MAX_ARC1214_DONEQUEUE];
 	u16 postq_index;
 	u16 doneq_index;
 	u32 __iomem *chip_id;			/*0x00004*/
@@ -617,6 +618,7 @@ struct AdapterControlBlock
 	spinlock_t eh_lock;
 	spinlock_t ccblist_lock;
 	spinlock_t postq_lock;
+	spinlock_t doneq_lock;
 	spinlock_t rqbuffer_lock;
 	spinlock_t wqbuffer_lock;
 	union {
@@ -670,15 +672,15 @@ struct AdapterControlBlock
 	unsigned int uncache_size;
 	uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
 	/* data collection buffer for read from 80331 */
-	int32_t rqbuf_firstindex;
+	uint32_t rqbuf_firstindex;
 	/* first of read buffer  */
-	int32_t rqbuf_lastindex;
+	uint32_t rqbuf_lastindex;
 	/* last of read buffer   */
 	uint8_t wqbuffer[ARCMSR_MAX_QBUFFER];
 	/* data collection buffer for write to 80331  */
-	int32_t wqbuf_firstindex;
+	uint32_t wqbuf_firstindex;
 	/* first of write buffer */
-	int32_t wqbuf_lastindex;
+	uint32_t wqbuf_lastindex;
 	/* last of write buffer  */
 	uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
 	/* id0 ..... id15, lun0...lun7 */
diff -uprN a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
--- a/drivers/scsi/arcmsr/arcmsr_hba.c	2012-11-16 18:07:40.072372510 +0800
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c	2012-11-16 18:52:25.840453468 +0800
@@ -1097,6 +1097,7 @@ static int arcmsr_probe(struct pci_dev *
 	spin_lock_init(&acb->eh_lock);
 	spin_lock_init(&acb->ccblist_lock);
 	spin_lock_init(&acb->postq_lock);
+	spin_lock_init(&acb->doneq_lock);
 	spin_lock_init(&acb->rqbuffer_lock);
 	spin_lock_init(&acb->wqbuffer_lock);
 	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
@@ -1541,33 +1542,29 @@ arcmsr_done4abort_postqueue(struct Adapt
 		uint32_t doneq_index, index_stripped, addressLow, residual;
 		bool error;
 		struct CommandControlBlock *pCCB;
-		outbound_write_pointer =
-			ioread32(pmu->outboundlist_copy_pointer);
+		outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
 		doneq_index = pmu->doneq_index;
 		residual = atomic_read(&acb->ccboutstandingcount);
 		for (i = 0; i < residual; i++) {
-			while ((doneq_index & 0xFF) !=
-				(outbound_write_pointer & 0xFF)) {
+			while ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
 				if (doneq_index & 0x4000) {
-					index_stripped = doneq_index & 0xFF;
+					index_stripped = doneq_index & 0xFFF;
 					index_stripped += 1;
 					index_stripped %=
-					ARCMSR_MAX_ARC1214_POSTQUEUE;
+					ARCMSR_MAX_ARC1214_DONEQUEUE;
 					pmu->doneq_index = index_stripped ?
-					(index_stripped | 0x4000) :
-					index_stripped;
+					(index_stripped | 0x4000) : (index_stripped + 1);
 				} else {
 					index_stripped = doneq_index;
 					index_stripped += 1;
 					index_stripped %=
-					ARCMSR_MAX_ARC1214_POSTQUEUE;
+					ARCMSR_MAX_ARC1214_DONEQUEUE;
 					pmu->doneq_index =
-					index_stripped ? index_stripped :
-					(index_stripped | 0x4000);
+					index_stripped ? index_stripped : ((index_stripped | 0x4000) + 1);
 				}
 				doneq_index = pmu->doneq_index;
 				addressLow =
-				pmu->done_qbuffer[doneq_index & 0xFF].addressLow;
+				pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
 				ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
 				pARCMSR_CDB = (struct  ARCMSR_CDB *)
 				(acb->vir2phy_offset + ccb_cdb_phy);
@@ -1582,7 +1579,7 @@ arcmsr_done4abort_postqueue(struct Adapt
 			}
 			mdelay(10);
 			outbound_write_pointer =
-				ioread32(pmu->outboundlist_copy_pointer);
+				pmu->done_qbuffer[0].addressLow + 1;
 			doneq_index = pmu->doneq_index;
 		}
 		pmu->postq_index = 0;
@@ -2135,10 +2132,9 @@ struct QBUFFER __iomem
 void
 arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
 {
-	uint8_t __iomem *iop_data;
+	uint8_t __iomem *iop_data, *pQbuffer, *vaddr, *temp;
 	struct QBUFFER __iomem *prbuffer;
-	struct QBUFFER *pQbuffer;
-	int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+	int32_t my_empty_len, data_len, rqbuf_firstindex, rqbuf_lastindex;
 	unsigned long flags;
 
 	spin_lock_irqsave(&acb->rqbuffer_lock, flags);
@@ -2146,19 +2142,30 @@ arcmsr_iop2drv_data_wrote_handle(struct
 	rqbuf_firstindex = acb->rqbuf_firstindex;
 	prbuffer = arcmsr_get_iop_rqbuffer(acb);
 	iop_data = (uint8_t __iomem *)prbuffer->data;
-	iop_len = prbuffer->data_len;
+	data_len = prbuffer->data_len;
 	my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) &
 	(ARCMSR_MAX_QBUFFER - 1);
 
-	if (my_empty_len >= iop_len) {
-		while (iop_len > 0) {
-			pQbuffer = (struct QBUFFER *)
-			&acb->rqbuffer[rqbuf_lastindex];
-			memcpy(pQbuffer, iop_data, 1);
-			rqbuf_lastindex++;
-			rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-			iop_data++;
-			iop_len--;
+	if (my_empty_len >= data_len) {
+		if (data_len > 0) {
+			temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+			memcpy(vaddr, iop_data, data_len);
+			smp_mb();
+			pQbuffer = &acb->rqbuffer[rqbuf_lastindex];
+			if ((rqbuf_lastindex + data_len)
+			> ARCMSR_MAX_QBUFFER) {
+				memcpy(pQbuffer, temp, ARCMSR_MAX_QBUFFER
+				- rqbuf_lastindex);
+				temp += (ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+				rqbuf_lastindex = (rqbuf_lastindex + data_len)
+				% ARCMSR_MAX_QBUFFER;
+				memcpy(&acb->rqbuffer[0], temp, rqbuf_lastindex);
+			} else {
+				memcpy(pQbuffer, temp, data_len);
+				rqbuf_lastindex = (rqbuf_lastindex + data_len)
+				% ARCMSR_MAX_QBUFFER;
+			}
+			kfree(vaddr);
 		}
 		acb->rqbuf_lastindex = rqbuf_lastindex;
 		arcmsr_iop_message_read(acb);
@@ -2379,28 +2386,30 @@ arcmsr_hbaD_postqueue_isr(struct Adapter
 	struct MessageUnit_D __iomem *pmu;
 	struct ARCMSR_CDB *arcmsr_cdb;
 	struct CommandControlBlock *ccb;
+	unsigned long flags;
 
+	spin_lock_irqsave(&acb->doneq_lock, flags);
 	pmu = (struct MessageUnit_D *)acb->pmuD;
-	outbound_write_pointer = ioread32(pmu->outboundlist_copy_pointer);
+	outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
 	doneq_index = pmu->doneq_index;
-	if ((doneq_index & 0xFF) != (outbound_write_pointer & 0xFF)) {
+	if ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
 		do {
 			if (doneq_index & 0x4000) {
-				index_stripped = doneq_index & 0xFF;
+				index_stripped = doneq_index & 0xFFF;
 				index_stripped += 1;
-				index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
+				index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
 				pmu->doneq_index = index_stripped
-				? (index_stripped | 0x4000) : index_stripped;
+				? (index_stripped | 0x4000) : (index_stripped + 1);
 			} else {
 				index_stripped = doneq_index;
 				index_stripped += 1;
-				index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
+				index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
 				pmu->doneq_index = index_stripped
-				? index_stripped : (index_stripped | 0x4000);
+				? index_stripped : ((index_stripped | 0x4000) + 1);
 			}
 			doneq_index = pmu->doneq_index;
 			addressLow =
-			pmu->done_qbuffer[doneq_index & 0xFF].addressLow;
+			pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
 			ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
 			arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
 				+ ccb_cdb_phy);
@@ -2411,12 +2420,13 @@ arcmsr_hbaD_postqueue_isr(struct Adapter
 			arcmsr_drain_donequeue(acb, ccb, error);
 			iowrite32(doneq_index,
 				pmu->outboundlist_read_pointer);
-		} while ((doneq_index & 0xFF) !=
-		(outbound_write_pointer & 0xFF));
+		} while ((doneq_index & 0xFFF) !=
+		(outbound_write_pointer & 0xFFF));
 	}
 	iowrite32(ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR,
 		pmu->outboundlist_interrupt_cause);
 	ioread32(pmu->outboundlist_interrupt_cause);
+	spin_unlock_irqrestore(&acb->doneq_lock, flags);
 }
 
 static void
@@ -2675,33 +2685,96 @@ arcmsr_iop_message_xfer(struct AdapterCo
 		}
 		ptmpQbuffer = ver_addr;
 		spin_lock_irqsave(&acb->rqbuffer_lock, flags);
-		while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
-			&& (allxfer_len < 1031)) {
+		if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) {
 			pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
-			memcpy(ptmpQbuffer, pQbuffer, 1);
-			acb->rqbuf_firstindex++;
-			acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-			ptmpQbuffer++;
-			allxfer_len++;
+			if (acb->rqbuf_firstindex > acb->rqbuf_lastindex) {
+				if ((ARCMSR_MAX_QBUFFER -
+					acb->rqbuf_firstindex) >= 1032) {
+					memcpy(ptmpQbuffer, pQbuffer, 1032);
+					acb->rqbuf_firstindex += 1032;
+					allxfer_len = 1032;
+				} else {
+					if (((ARCMSR_MAX_QBUFFER -
+						acb->rqbuf_firstindex)
+						+ acb->rqbuf_lastindex) > 1032) {
+						memcpy(ptmpQbuffer, pQbuffer,
+						ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						ptmpQbuffer += ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex;
+						memcpy(ptmpQbuffer, acb->rqbuffer,
+						1032 - (ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex));
+						acb->rqbuf_firstindex = 1032 -
+						(ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						allxfer_len = 1032;
+					} else {
+						memcpy(ptmpQbuffer, pQbuffer,
+						ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						ptmpQbuffer += ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex;
+						memcpy(ptmpQbuffer, acb->rqbuffer,
+						acb->rqbuf_lastindex);
+						allxfer_len = ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex
+						+ acb->rqbuf_lastindex;
+						acb->rqbuf_firstindex =
+						acb->rqbuf_lastindex;
+					}
+				}
+			} else {
+				if ((acb->rqbuf_lastindex
+				- acb->rqbuf_firstindex) > 1032) {
+					memcpy(ptmpQbuffer,
+					pQbuffer, 1032);
+					acb->rqbuf_firstindex += 1032;
+					allxfer_len = 1032;
+				} else {
+					memcpy(ptmpQbuffer,
+					pQbuffer,
+					acb->rqbuf_lastindex
+					- acb->rqbuf_firstindex);
+					allxfer_len = acb->rqbuf_lastindex
+					- acb->rqbuf_firstindex;
+					acb->rqbuf_firstindex
+					= acb->rqbuf_lastindex;
+				}
+			}
 		}
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
-
 			struct QBUFFER __iomem *prbuffer;
-			uint8_t __iomem *iop_data;
-			int32_t iop_len;
-
+			uint8_t __iomem *iop_data, *vaddr, *temp;
+			uint32_t data_len, rqbuf_lastindex;
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+			rqbuf_lastindex = acb->rqbuf_lastindex;
 			prbuffer = arcmsr_get_iop_rqbuffer(acb);
-			iop_data = prbuffer->data;
-			iop_len = ioread32(&prbuffer->data_len);
-			while (iop_len > 0) {
-				acb->rqbuffer[acb->rqbuf_lastindex] =
-				ioread8(iop_data);
-				acb->rqbuf_lastindex++;
-				acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-				iop_data++;
-				iop_len--;
+			iop_data = (uint8_t __iomem *)prbuffer->data;
+			data_len = ioread32(&prbuffer->data_len);
+			if (data_len > 0) {
+				temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+				memcpy(vaddr, iop_data, data_len);
+				smp_mb();
+				pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex];
+				if ((rqbuf_lastindex + data_len) >
+					ARCMSR_MAX_QBUFFER) {
+					memcpy(pQbuffer, temp,
+					ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+					temp += (ARCMSR_MAX_QBUFFER
+					- rqbuf_lastindex);
+					rqbuf_lastindex = (rqbuf_lastindex
+					+ data_len) % ARCMSR_MAX_QBUFFER;
+					memcpy(&acb->rqbuffer[0],
+					temp, rqbuf_lastindex);
+				} else {
+					memcpy(pQbuffer, temp, data_len);
+					rqbuf_lastindex = (rqbuf_lastindex +
+					data_len) % ARCMSR_MAX_QBUFFER;
+				}
+				kfree(vaddr);
 			}
+			acb->rqbuf_lastindex = rqbuf_lastindex;
 			arcmsr_iop_message_read(acb);
 		}
 		spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
@@ -3623,19 +3696,21 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
 {
 	bool error;
 	uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb, ccb_cdb_phy;
-	int rtn, index, outbound_write_pointer;
+	int rtn, doneq_index, index_stripped, outbound_write_pointer;
+	unsigned long flags;
 	struct ARCMSR_CDB *arcmsr_cdb;
 	struct CommandControlBlock *pCCB;
-	struct MessageUnit_D __iomem *reg =
+	struct MessageUnit_D __iomem *pmu =
 		(struct MessageUnit_D *)acb->pmuD;
 
+	spin_lock_irqsave(&acb->doneq_lock, flags);
 	polling_hbaD_ccb_retry:
 	poll_count++;
 	while (1) {
 		outbound_write_pointer =
-			ioread32(reg->outboundlist_copy_pointer);
-		index = reg->doneq_index;
-		if ((outbound_write_pointer & 0xFF) == index) {
+		pmu->done_qbuffer[0].addressLow + 1;
+		doneq_index = pmu->doneq_index;
+		if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
 			if (poll_ccb_done) {
 				rtn = SUCCESS;
 				break;
@@ -3648,17 +3723,27 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
 				goto polling_hbaD_ccb_retry;
 			}
 		}
-		flag_ccb = reg->done_qbuffer[index].addressLow;
+		if (doneq_index & 0x4000) {
+			index_stripped = doneq_index & 0xFFF;
+			index_stripped += 1;
+			index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+			pmu->doneq_index = index_stripped ? (index_stripped | 0x4000)
+				: (index_stripped + 1);
+		} else {
+			index_stripped = doneq_index;
+			index_stripped += 1;
+			index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+			pmu->doneq_index = index_stripped ? index_stripped :
+				((index_stripped | 0x4000) + 1);
+		}
+		doneq_index = pmu->doneq_index;
+		flag_ccb = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
 		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
 		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset +
 			ccb_cdb_phy);
 		pCCB = container_of(arcmsr_cdb,
 			struct CommandControlBlock, arcmsr_cdb);
 		poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
-		index++;
-		index %= ARCMSR_MAX_ARC1214_POSTQUEUE;
-		reg->doneq_index = index;
-		/* check if command done with no error*/
 		if ((pCCB->acb != acb) ||
 		(pCCB->startdone != ARCMSR_CCB_START)) {
 			if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
@@ -3685,6 +3770,7 @@ arcmsr_hbaD_polling_ccbdone(struct Adapt
 		? true : false;
 		arcmsr_report_ccb_state(acb, pCCB, error);
 	}
+	spin_unlock_irqrestore(&acb->doneq_lock, flags);
 	return rtn;
 }
 
@@ -3817,7 +3903,7 @@ arcmsr_iop_confirm(struct AdapterControl
 		struct MessageUnit_D *reg =
 			(struct MessageUnit_D *)acb->pmuD;
 		reg->postq_index = 0;
-		reg->doneq_index = 0x40FF;
+		reg->doneq_index = 0;
 		rwbuffer = reg->msgcode_rwbuffer;
 		iowrite32(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
 		iowrite32(cdb_phyaddr_hi32, rwbuffer++);

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-11-30  9:18 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-15  7:33 [PATCH 5/5] arcmsr: Modify ARC-1214 IO Behavior NickCheng
2012-11-16 11:56 NickCheng
2012-11-30  9:18 ` James Bottomley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®