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