diff -uprN a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c --- a/drivers/scsi/arcmsr/arcmsr_attr.c 2013-02-08 13:57:56.091899027 +0800 +++ b/drivers/scsi/arcmsr/arcmsr_attr.c 2013-02-08 13:58:11.070196747 +0800 @@ -72,40 +72,82 @@ arcmsr_sysfs_iop_message_read(struct fil (struct AdapterControlBlock *)host->hostdata; uint8_t *pQbuffer,*ptmpQbuffer; int32_t allxfer_len = 0; + unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* do message unit read. */ ptmpQbuffer = (uint8_t *)buf; - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) - && (allxfer_len < 1031)) { + spin_lock_irqsave(&acb->rqbuffer_lock, flags); + 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; + int32_t data_len_residual, 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 = readl(&prbuffer->data_len); - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = - readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; + iop_data = (uint8_t __iomem *)prbuffer->data; + data_len_residual = data_len = readl(&prbuffer->data_len); + if (data_len > 0) { + temp = vaddr = kmalloc(data_len, GFP_ATOMIC); + do { + memcpy(temp, iop_data, 4); + temp += 4; + iop_data += 4; + data_len_residual -= 4; + } while (data_len_residual > 0); + pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex]; + temp = vaddr; + 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); return (allxfer_len); } @@ -122,6 +164,7 @@ arcmsr_sysfs_iop_message_write(struct fi (struct AdapterControlBlock *)host->hostdata; int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; uint8_t *pQbuffer, *ptmpuserbuffer; + unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -130,10 +173,12 @@ arcmsr_sysfs_iop_message_write(struct fi /* do message unit write. */ ptmpuserbuffer = (uint8_t *)buf; user_len = (int32_t)count; + spin_lock_irqsave(&acb->wqbuffer_lock, flags); wqbuf_lastindex = acb->wqbuf_lastindex; wqbuf_firstindex = acb->wqbuf_firstindex; if (wqbuf_lastindex != wqbuf_firstindex) { arcmsr_post_ioctldata2iop(acb); + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); return 0; /*need retry*/ } else { my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) @@ -155,8 +200,10 @@ arcmsr_sysfs_iop_message_write(struct fi ~ACB_F_MESSAGE_WQBUFFER_CLEARED; arcmsr_post_ioctldata2iop(acb); } + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); return count; } else { + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); return 0; /*need retry*/ } } @@ -174,6 +221,7 @@ arcmsr_sysfs_iop_message_clear(struct fi struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata; uint8_t *pQbuffer; + unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -186,10 +234,14 @@ arcmsr_sysfs_iop_message_clear(struct fi (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); + spin_lock_irqsave(&acb->rqbuffer_lock, flags); acb->rqbuf_firstindex = 0; acb->rqbuf_lastindex = 0; + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); + spin_lock_irqsave(&acb->wqbuffer_lock, flags); acb->wqbuf_firstindex = 0; acb->wqbuf_lastindex = 0; + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); pQbuffer = acb->rqbuffer; memset(pQbuffer, 0, sizeof (struct QBUFFER)); pQbuffer = acb->wqbuffer; diff -uprN a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h --- a/drivers/scsi/arcmsr/arcmsr.h 2013-02-08 13:57:56.460908463 +0800 +++ b/drivers/scsi/arcmsr/arcmsr.h 2013-02-08 13:58:11.430206075 +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 2013-02-08 13:57:56.797912198 +0800 +++ b/drivers/scsi/arcmsr/arcmsr_hba.c 2013-02-08 13:58:11.776204212 +0800 @@ -768,18 +768,18 @@ arcmsr_message_isr_bh_fn(struct work_str (diff & 0x01) == 1) { scsi_add_device(acb->host, 0, target, lun); - } else if ((temp & 0x01) == 0 - && (diff & 0x01) == 1) { - psdev = - scsi_device_lookup(acb->host, - 0, target, lun); - if (psdev != NULL) { - scsi_remove_device(psdev); - scsi_device_put(psdev); + } else if ((temp & 0x01) == 0 + && (diff & 0x01) == 1) { + psdev = + scsi_device_lookup(acb->host, + 0, target, lun); + if (psdev != NULL) { + scsi_remove_device(psdev); + scsi_device_put(psdev); + } } - } - temp >>= 1; - diff >>= 1; + temp >>= 1; + diff >>= 1; } } devicemap++; @@ -813,20 +813,20 @@ arcmsr_message_isr_bh_fn(struct work_str lun < ARCMSR_MAX_TARGETLUN; lun++) { if ((temp & 0x01) == 1 && - (diff & 0x01) == 1) { + (diff & 0x01) == 1) { scsi_add_device(acb->host, 0, target, lun); } else if ((temp & 0x01) == 0 - && (diff & 0x01) == 1) { + && (diff & 0x01) == 1) { psdev = scsi_device_lookup(acb->host, 0, target, lun); if (psdev != NULL) { scsi_remove_device(psdev); scsi_device_put(psdev); } - } - temp >>= 1; - diff >>= 1; + } + temp >>= 1; + diff >>= 1; } } devicemap++; @@ -869,10 +869,10 @@ arcmsr_message_isr_bh_fn(struct work_str if (psdev != NULL) { scsi_remove_device(psdev); scsi_device_put(psdev); + } } - } - temp >>= 1; - diff >>= 1; + temp >>= 1; + diff >>= 1; } } devicemap++; @@ -915,10 +915,10 @@ arcmsr_message_isr_bh_fn(struct work_str if (psdev != NULL) { scsi_remove_device(psdev); scsi_device_put(psdev); + } } - } - temp >>= 1; - diff >>= 1; + temp >>= 1; + diff >>= 1; } } devicemap++; @@ -981,8 +981,8 @@ arcmsr_resume(struct pci_dev *pdev) error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (error) { pr_warn("scsi%d: No suitable DMA mask available\n", - host->host_no); - goto controller_unregister; + host->host_no); + goto controller_unregister; } } pci_set_master(pdev); @@ -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 = - readl(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 = - readl(pmu->outboundlist_copy_pointer); + pmu->done_qbuffer[0].addressLow + 1; doneq_index = pmu->doneq_index; } pmu->postq_index = 0; @@ -2004,12 +2001,14 @@ arcmsr_iop_message_read(struct AdapterCo case ACB_ADAPTER_TYPE_C: { struct MessageUnit_C __iomem *reg = acb->pmuC; writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); + /*readl(®->inbound_doorbell);*/ } break; case ACB_ADAPTER_TYPE_D: { struct MessageUnit_D __iomem *reg = acb->pmuD; writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ, reg->inbound_doorbell); + /*readl(reg->inbound_doorbell);*/ break; } } @@ -2127,36 +2126,61 @@ struct QBUFFER __iomem void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) { - uint8_t __iomem *iop_data; - struct QBUFFER __iomem *prbuffer; - struct QBUFFER *pQbuffer; - int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; + uint8_t __iomem *iop_data, *pQbuffer, *vaddr, *temp; + int32_t buf_empty_len, data_len, data_len_residual; + uint32_t rqbuf_firstindex, rqbuf_lastindex; unsigned long flags; - + struct QBUFFER __iomem *prbuffer; spin_lock_irqsave(&acb->rqbuffer_lock, flags); rqbuf_lastindex = acb->rqbuf_lastindex; rqbuf_firstindex = acb->rqbuf_firstindex; prbuffer = arcmsr_get_iop_rqbuffer(acb); iop_data = (uint8_t __iomem *)prbuffer->data; - iop_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--; + data_len_residual = data_len = readl(&prbuffer->data_len); + buf_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & + (ARCMSR_MAX_QBUFFER - 1); + if (buf_empty_len >= data_len) { + if (data_len > 0) { + temp = vaddr = kmalloc(data_len, GFP_ATOMIC); + if (!vaddr) { + goto leave; + } + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + while (data_len_residual >= 4) { + memcpy(temp, iop_data, 4); + temp += 4; + iop_data += 4; + data_len_residual -= 4; + } + if ((data_len_residual > 0) && + (data_len_residual < 4)) { + memcpy(temp, iop_data, data_len_residual); + } + pQbuffer = &acb->rqbuffer[rqbuf_lastindex]; + temp = vaddr; + 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); } else { acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; } + leave: spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); } @@ -2164,7 +2188,6 @@ void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) { unsigned long flags; - spin_lock_irqsave(&acb->wqbuffer_lock, flags); acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { @@ -2176,18 +2199,113 @@ arcmsr_iop2drv_data_read_handle(struct A acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); pwbuffer = arcmsr_get_iop_wqbuffer(acb); iop_data = (uint8_t __iomem *)pwbuffer->data; - - while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && - (allxfer_len < 124)) { - pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex]; - memcpy(iop_data, pQbuffer, 1); - acb->wqbuf_firstindex++; - acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; + if (acb->wqbuf_firstindex > acb->wqbuf_lastindex) { + if ((ARCMSR_MAX_QBUFFER - acb->wqbuf_firstindex) >= 4) { + do { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_firstindex]; + if (acb->wqbuf_firstindex + 4 + > ARCMSR_MAX_QBUFFER) { + memcpy(iop_data, pQbuffer, + ARCMSR_MAX_QBUFFER + - acb->wqbuf_firstindex); + iop_data += ARCMSR_MAX_QBUFFER + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex += 4; + acb->wqbuf_firstindex %= + ARCMSR_MAX_QBUFFER; + memcpy(iop_data, + &acb->wqbuffer[0], + acb->wqbuf_firstindex); + iop_data += + acb->wqbuf_firstindex; + } else { + if ((acb->wqbuf_lastindex + - acb->wqbuf_firstindex) > 4) { + memcpy(iop_data, + pQbuffer, 4); + acb->wqbuf_firstindex + += 4; + acb->wqbuf_firstindex + %= ARCMSR_MAX_QBUFFER; + iop_data += 4; + } else { + memcpy(iop_data, pQbuffer, + acb->wqbuf_lastindex + - acb->wqbuf_firstindex); + allxfer_len += + acb->wqbuf_lastindex - + acb->wqbuf_firstindex; + acb->wqbuf_firstindex = + acb->wqbuf_lastindex; + break; + } + } + allxfer_len += 4; + } while ((acb->wqbuf_firstindex != + acb->wqbuf_lastindex) && (allxfer_len < 124)); + } else { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_firstindex]; + memcpy(iop_data, pQbuffer, ARCMSR_MAX_QBUFFER + - acb->wqbuf_firstindex); + iop_data += ARCMSR_MAX_QBUFFER + - acb->wqbuf_firstindex; + allxfer_len = ARCMSR_MAX_QBUFFER + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex = 0; + do { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_firstindex]; + if ((acb->wqbuf_lastindex - + acb->wqbuf_firstindex) > 4) { + memcpy(iop_data, pQbuffer, 4); + acb->wqbuf_firstindex += 4; + acb->wqbuf_firstindex %= + ARCMSR_MAX_QBUFFER; + iop_data += 4; + } else { + memcpy(iop_data, pQbuffer, + acb->wqbuf_lastindex - + acb->wqbuf_firstindex); + allxfer_len += + acb->wqbuf_lastindex + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex = + acb->wqbuf_lastindex; + break; + } + allxfer_len += 4; + } while ((acb->wqbuf_firstindex != + acb->wqbuf_lastindex) && (allxfer_len < 124)); + } + } else { + do { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_firstindex]; + if ((acb->wqbuf_lastindex - + acb->wqbuf_firstindex) > 4) { + memcpy(iop_data, pQbuffer, 4); + acb->wqbuf_firstindex += 4; + acb->wqbuf_firstindex %= + ARCMSR_MAX_QBUFFER; + iop_data += 4; + } else { + memcpy(iop_data, pQbuffer, + acb->wqbuf_lastindex - + acb->wqbuf_firstindex); + allxfer_len += acb->wqbuf_lastindex + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex = + acb->wqbuf_lastindex; + break; + } + allxfer_len += 4; + } while ((acb->wqbuf_firstindex != + acb->wqbuf_lastindex) && (allxfer_len < 124)); } - pwbuffer->data_len = allxfer_len; - arcmsr_iop_message_wrote(acb); + writel(allxfer_len, &pwbuffer->data_len); + arcmsr_iop_message_wrote(acb);/*notice IOP the message has been written*/ } if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) { acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; @@ -2200,7 +2318,6 @@ arcmsr_hbaA_doorbell_isr(struct AdapterC { uint32_t outbound_doorbell; struct MessageUnit_A __iomem *reg = acb->pmuA; - outbound_doorbell = readl(®->outbound_doorbell); do { writel(outbound_doorbell, ®->outbound_doorbell); @@ -2223,7 +2340,6 @@ arcmsr_hbaC_doorbell_isr(struct AdapterC uint32_t outbound_doorbell; struct MessageUnit_C __iomem *reg = (struct MessageUnit_C *)pACB->pmuC; - outbound_doorbell = readl(®->outbound_doorbell); do { if (outbound_doorbell & @@ -2255,10 +2371,6 @@ arcmsr_hbaD_doorbell_isr(struct AdapterC (struct MessageUnit_D *)pACB->pmuD; outbound_doorbell = readl(pmu->outbound_doorbell); - if (unlikely(!outbound_doorbell)) { - arcmsr_iop2drv_data_wrote_handle(pACB); - arcmsr_iop2drv_data_read_handle(pACB); - } do { writel(outbound_doorbell, pmu->outbound_doorbell); if (outbound_doorbell & @@ -2367,28 +2479,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 = readl(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); @@ -2399,12 +2513,13 @@ arcmsr_hbaD_postqueue_isr(struct Adapter arcmsr_drain_donequeue(acb, ccb, error); writel(doneq_index, pmu->outboundlist_read_pointer); - } while ((doneq_index & 0xFF) != - (outbound_write_pointer & 0xFF)); + } while ((doneq_index & 0xFFF) != + (outbound_write_pointer & 0xFFF)); } writel(ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR, pmu->outboundlist_interrupt_cause); readl(pmu->outboundlist_interrupt_cause); + spin_unlock_irqrestore(&acb->doneq_lock, flags); } static void @@ -2457,7 +2572,6 @@ arcmsr_hbaA_handle_isr(struct AdapterCon } do { writel(outbound_intstatus, ®->outbound_intstatus); - readl(®->outbound_intstatus); if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) arcmsr_hbaA_doorbell_isr(acb); if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) @@ -2597,29 +2711,131 @@ arcmsr_iop_parking(struct AdapterControl void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) { - uint8_t __iomem *iop_data; - uint8_t *pQbuffer; - int32_t wqbuf_firstindex, wqbuf_lastindex; - int32_t allxfer_len = 0; - struct QBUFFER __iomem *pwbuffer; - pwbuffer = arcmsr_get_iop_wqbuffer(acb); - iop_data = (uint8_t __iomem *)pwbuffer->data; if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); - wqbuf_firstindex = acb->wqbuf_firstindex; - wqbuf_lastindex = acb->wqbuf_lastindex; - while ((wqbuf_firstindex != wqbuf_lastindex) - && (allxfer_len < 124)) { - pQbuffer = &acb->wqbuffer[wqbuf_firstindex]; - memcpy(iop_data, pQbuffer, 1); - wqbuf_firstindex++; - wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; - } - acb->wqbuf_firstindex = wqbuf_firstindex; - pwbuffer->data_len = allxfer_len; - arcmsr_iop_message_wrote(acb); + if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { + uint8_t *pQbuffer; + uint8_t __iomem *iop_data; + int32_t allxfer_len = 0; + struct QBUFFER __iomem *pwbuffer; + acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); + pwbuffer = arcmsr_get_iop_wqbuffer(acb); + iop_data = (uint8_t __iomem *)pwbuffer->data; + if (acb->wqbuf_firstindex > acb->wqbuf_lastindex) { + if ((ARCMSR_MAX_QBUFFER - + acb->wqbuf_firstindex) >= 4) { + do { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_firstindex]; + if (acb->wqbuf_firstindex + 4 > + ARCMSR_MAX_QBUFFER) { + memcpy(iop_data, pQbuffer, + ARCMSR_MAX_QBUFFER - acb->wqbuf_firstindex); + iop_data += ARCMSR_MAX_QBUFFER + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex += 4; + acb->wqbuf_firstindex %= + ARCMSR_MAX_QBUFFER; + memcpy(iop_data, + &acb->wqbuffer[0], + acb->wqbuf_firstindex); + iop_data += + acb->wqbuf_firstindex; + } else { + if ((acb->wqbuf_lastindex - + acb->wqbuf_firstindex) > 4) { + memcpy(iop_data, + pQbuffer, 4); + acb->wqbuf_firstindex + += 4; + acb->wqbuf_firstindex + %= ARCMSR_MAX_QBUFFER; + iop_data += 4; + } else { + memcpy(iop_data, + pQbuffer, + acb->wqbuf_lastindex + - acb->wqbuf_firstindex); + allxfer_len += + acb->wqbuf_lastindex + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex + = acb->wqbuf_lastindex; + break; + } + } + allxfer_len += 4; + } while ((acb->wqbuf_firstindex != + acb->wqbuf_lastindex) && + (allxfer_len < 124)); + } else { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_firstindex]; + memcpy(iop_data, pQbuffer, + ARCMSR_MAX_QBUFFER - + acb->wqbuf_firstindex); + iop_data += ARCMSR_MAX_QBUFFER + - acb->wqbuf_firstindex; + allxfer_len = ARCMSR_MAX_QBUFFER + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex = 0; + do { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_firstindex]; + if ((acb->wqbuf_lastindex - + acb->wqbuf_firstindex) > 4) { + memcpy(iop_data, + pQbuffer, 4); + acb->wqbuf_firstindex + += 4; + acb->wqbuf_firstindex + %= ARCMSR_MAX_QBUFFER; + iop_data += 4; + } else { + memcpy(iop_data, pQbuffer, + acb->wqbuf_lastindex + - acb->wqbuf_firstindex); + allxfer_len += + acb->wqbuf_lastindex + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex = + acb->wqbuf_lastindex; + break; + } + allxfer_len += 4; + } while ((acb->wqbuf_firstindex + != acb->wqbuf_lastindex) && + (allxfer_len < 124)); + } + } else { + do { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_firstindex]; + if ((acb->wqbuf_lastindex - + acb->wqbuf_firstindex) > 4) { + memcpy(iop_data, + pQbuffer, 4); + acb->wqbuf_firstindex + += 4; + acb->wqbuf_firstindex + %= ARCMSR_MAX_QBUFFER; + iop_data += 4; + } else { + memcpy(iop_data, pQbuffer, + acb->wqbuf_lastindex - + acb->wqbuf_firstindex); + allxfer_len += acb->wqbuf_lastindex + - acb->wqbuf_firstindex; + acb->wqbuf_firstindex = + acb->wqbuf_lastindex; + break; + } + allxfer_len += 4; + } while ((acb->wqbuf_firstindex != + acb->wqbuf_lastindex) && (allxfer_len < 124)); + } + writel(allxfer_len, &pwbuffer->data_len); + arcmsr_iop_message_wrote(acb); + } } } @@ -2627,74 +2843,155 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd) { - struct CMD_MESSAGE_FIELD *pcmdmessagefld; - int retvalue = 0, transfer_len = 0; char *buffer; + unsigned short use_sg; + int retvalue = 0, transfer_len = 0; + unsigned long flags; + struct CMD_MESSAGE_FIELD *pcmdmessagefld; + uint32_t controlcode = (uint32_t)cmd->cmnd[5] << 24 | + (uint32_t)cmd->cmnd[6] << 16 | + (uint32_t)cmd->cmnd[7] << 8 | + (uint32_t)cmd->cmnd[8]; struct scatterlist *sg; - uint32_t controlcode = (uint32_t)cmd->cmnd[5] << 24 - |(uint32_t)cmd->cmnd[6] << 16 - |(uint32_t)cmd->cmnd[7] << 8 - | (uint32_t)cmd->cmnd[8]; + + use_sg = scsi_sg_count(cmd); sg = scsi_sglist(cmd); buffer = kmap_atomic(sg_page(sg)) + sg->offset; - if (scsi_sg_count(cmd) > 1) { + if (use_sg > 1) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } transfer_len += sg->length; - if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { retvalue = ARCMSR_MESSAGE_FAIL; + printk("%s: ARCMSR_MESSAGE_FAIL!\n", __func__); goto message_out; } pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)buffer; switch (controlcode) { - case ARCMSR_MESSAGE_READ_RQBUFFER: { unsigned char *ver_addr; uint8_t *pQbuffer, *ptmpQbuffer; - int32_t allxfer_len = 0; - unsigned long flags; - + uint32_t allxfer_len = 0; ver_addr = kmalloc(1032, GFP_ATOMIC); if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; + printk("%s: memory not enough!\n", __func__); goto message_out; } 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_residual, data_len, rqbuf_lastindex; + rqbuf_lastindex = acb->rqbuf_lastindex; prbuffer = arcmsr_get_iop_rqbuffer(acb); - iop_data = prbuffer->data; - iop_len = readl(&prbuffer->data_len); - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = - readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; + iop_data = (uint8_t __iomem *)prbuffer->data; + data_len_residual = data_len = readl(&prbuffer->data_len); + if (data_len > 0) { + temp = vaddr = kmalloc(data_len, GFP_ATOMIC); + if (!vaddr) { + goto leave; + } + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + while (data_len_residual >= 4) { + memcpy(temp, iop_data, 4); + temp += 4; + iop_data += 4; + data_len_residual -= 4; + } + if ((data_len_residual > 0) && + (data_len_residual < 4)) { + memcpy(temp, iop_data, + data_len_residual); + } + pQbuffer = + &acb->rqbuffer[acb->rqbuf_lastindex]; + temp = vaddr; + 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); } - arcmsr_iop_message_read(acb); } + leave: spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); - memcpy(pcmdmessagefld->messagedatabuffer, - ver_addr, allxfer_len); + memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len); pcmdmessagefld->cmdmessage.Length = allxfer_len; if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = @@ -2704,26 +3001,23 @@ arcmsr_iop_message_xfer(struct AdapterCo ARCMSR_MESSAGE_RETURNCODE_OK; } kfree(ver_addr); - } break; - + } case ARCMSR_MESSAGE_WRITE_WQBUFFER: { unsigned char *ver_addr; int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; uint8_t *pQbuffer, *ptmpuserbuffer; - unsigned long flags; - ver_addr = kmalloc(1032, GFP_ATOMIC); if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } if (acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; } else { - pcmdmessagefld->cmdmessage.ReturnCode = + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } ptmpuserbuffer = ver_addr; @@ -2735,28 +3029,39 @@ arcmsr_iop_message_xfer(struct AdapterCo wqbuf_firstindex = acb->wqbuf_firstindex; if (wqbuf_lastindex != wqbuf_firstindex) { struct SENSE_DATA *sensebuffer = - (struct SENSE_DATA *)cmd->sense_buffer; + (struct SENSE_DATA *)cmd->sense_buffer; arcmsr_post_ioctldata2iop(acb); /* has error report sensedata */ - sensebuffer->ErrorCode = 0x70; + sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; sensebuffer->SenseKey = ILLEGAL_REQUEST; sensebuffer->AdditionalSenseLength = 0x0A; sensebuffer->AdditionalSenseCode = 0x20; sensebuffer->Valid = 1; retvalue = ARCMSR_MESSAGE_FAIL; } else { - my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); + my_empty_len = (wqbuf_firstindex - wqbuf_lastindex - 1) + & (ARCMSR_MAX_QBUFFER - 1); if (my_empty_len >= user_len) { while (user_len > 0) { - pQbuffer = - &acb->wqbuffer[acb->wqbuf_lastindex]; - memcpy(pQbuffer, ptmpuserbuffer, 1); - acb->wqbuf_lastindex++; - acb->wqbuf_lastindex %= - ARCMSR_MAX_QBUFFER; - ptmpuserbuffer++; - user_len--; + pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex]; + if ((acb->wqbuf_lastindex + user_len) + > ARCMSR_MAX_QBUFFER) { + memcpy(pQbuffer, ptmpuserbuffer, + ARCMSR_MAX_QBUFFER - + acb->wqbuf_lastindex); + ptmpuserbuffer += (ARCMSR_MAX_QBUFFER + - acb->wqbuf_lastindex); + user_len -= (ARCMSR_MAX_QBUFFER + - acb->wqbuf_lastindex); + acb->wqbuf_lastindex = 0; + } else { + memcpy(pQbuffer, ptmpuserbuffer, + user_len); + acb->wqbuf_lastindex += user_len; + acb->wqbuf_lastindex %= + ARCMSR_MAX_QBUFFER; + user_len = 0; + } } if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { @@ -2765,24 +3070,26 @@ arcmsr_iop_message_xfer(struct AdapterCo arcmsr_post_ioctldata2iop(acb); } } else { - /* has error report sensedata */ struct SENSE_DATA *sensebuffer = - (struct SENSE_DATA *)cmd->sense_buffer; - sensebuffer->ErrorCode = 0x70; + (struct SENSE_DATA *)cmd->sense_buffer; + /* has error report sensedata */ + sensebuffer->ErrorCode = + SCSI_SENSE_CURRENT_ERRORS; sensebuffer->SenseKey = ILLEGAL_REQUEST; sensebuffer->AdditionalSenseLength = 0x0A; sensebuffer->AdditionalSenseCode = 0x20; sensebuffer->Valid = 1; retvalue = ARCMSR_MESSAGE_FAIL; } - } - spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); - kfree(ver_addr); } + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); + kfree(ver_addr); break; - + } case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { uint8_t *pQbuffer = acb->rqbuffer; + + spin_lock_irqsave(&acb->rqbuffer_lock, flags); if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; arcmsr_iop_message_read(acb); @@ -2791,6 +3098,7 @@ arcmsr_iop_message_xfer(struct AdapterCo acb->rqbuf_firstindex = 0; acb->rqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; @@ -2798,9 +3106,8 @@ arcmsr_iop_message_xfer(struct AdapterCo pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } - } break; - + } case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { uint8_t *pQbuffer = acb->wqbuffer; if (acb->fw_flag == FW_DEADLOCK) { @@ -2810,39 +3117,40 @@ arcmsr_iop_message_xfer(struct AdapterCo pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } - + spin_lock_irqsave(&acb->wqbuffer_lock, flags); if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; arcmsr_iop_message_read(acb); } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED | - ACB_F_MESSAGE_WQBUFFER_READED); + acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | + ACB_F_MESSAGE_WQBUFFER_READED); acb->wqbuf_firstindex = 0; acb->wqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - } + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); break; - + } case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { uint8_t *pQbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; arcmsr_iop_message_read(acb); } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED - | ACB_F_MESSAGE_RQBUFFER_CLEARED - | ACB_F_MESSAGE_WQBUFFER_READED); + spin_lock_irqsave(&acb->rqbuffer_lock, flags); + acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; acb->rqbuf_firstindex = 0; acb->rqbuf_lastindex = 0; - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; pQbuffer = acb->rqbuffer; memset(pQbuffer, 0, sizeof(struct QBUFFER)); + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); + spin_lock_irqsave(&acb->wqbuffer_lock, flags); + acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | + ACB_F_MESSAGE_WQBUFFER_READED); + acb->wqbuf_firstindex = 0; + acb->wqbuf_lastindex = 0; pQbuffer = acb->wqbuffer; memset(pQbuffer, 0, sizeof(struct QBUFFER)); + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; @@ -2850,9 +3158,8 @@ arcmsr_iop_message_xfer(struct AdapterCo pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } - } break; - + } case ARCMSR_MESSAGE_RETURN_CODE_3F: { if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = @@ -2862,7 +3169,7 @@ arcmsr_iop_message_xfer(struct AdapterCo ARCMSR_MESSAGE_RETURNCODE_3F; } break; - } + } case ARCMSR_MESSAGE_SAY_HELLO: { int8_t *hello_string = "Hello! I am ARCMSR"; if (acb->fw_flag == FW_DEADLOCK) { @@ -2872,33 +3179,42 @@ arcmsr_iop_message_xfer(struct AdapterCo pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } - memcpy(pcmdmessagefld->messagedatabuffer, hello_string - , (int16_t)strlen(hello_string)); - } + memcpy(pcmdmessagefld->messagedatabuffer, + hello_string, (int16_t)strlen(hello_string)); break; - - case ARCMSR_MESSAGE_SAY_GOODBYE: + } + case ARCMSR_MESSAGE_SAY_GOODBYE: { if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + } else { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; } arcmsr_iop_parking(acb); break; - - case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: + } + case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: { if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + } else { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; } arcmsr_flush_adapter_cache(acb); break; - + } default: retvalue = ARCMSR_MESSAGE_FAIL; + printk("unknown controlcode(%d)\n", __LINE__); } message_out: - sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset); + if (use_sg) { + struct scatterlist *sg; + sg = scsi_sglist(cmd); + kunmap_atomic(buffer - sg->offset); + } return retvalue; } @@ -2930,7 +3246,6 @@ arcmsr_handle_virtual_command(struct Ada unsigned char inqdata[36]; char *buffer; struct scatterlist *sg; - if (cmd->device->lun) { cmd->result = (DID_TIME_OUT << 16); cmd->scsi_done(cmd); @@ -2949,14 +3264,11 @@ arcmsr_handle_virtual_command(struct Ada strncpy(&inqdata[16], "RAID controller ", 16); /* Product Identification */ strncpy(&inqdata[32], "R001", 4); /* Product Revision */ - sg = scsi_sglist(cmd); buffer = kmap_atomic(sg_page(sg)) + sg->offset; - memcpy(buffer, inqdata, sizeof(inqdata)); sg = scsi_sglist(cmd); kunmap_atomic(buffer - sg->offset); - cmd->scsi_done(cmd); } break; @@ -3611,19 +3923,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 = - readl(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; @@ -3636,17 +3950,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) { @@ -3673,6 +3997,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; } @@ -3805,7 +4130,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; writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); writel(cdb_phyaddr_hi32, rwbuffer++); @@ -3849,7 +4174,8 @@ arcmsr_wait_firmware_ready(struct Adapte } break; case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + struct MessageUnit_C *reg = + (struct MessageUnit_C *)acb->pmuC; do { firmware_state = readl(®->outbound_msgaddr1); } while ((firmware_state &