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++);