From: "erich" I had modify the architecture of arcmsr apply on linux standard list and delete some source code comment in arcmsr.c. This new code had ran on my testing platform (x86_64 dual real processor),(i386 single processor) two days. And today I transfer this code into ARECA TESTING GROUP for more test. ** 1.20.00.09 9/12/2005 Erich Chen bug fix with abort command handling,firmware version check ** and firmware update notify for hardware bug fix ** 1.20.00.10 9/23/2005 Erich Chen enhance sysfs function for change driver's max tag Q number. ** add DMA_64BIT_MASK for backward compatible with all 2.6.x ** add some useful message for abort command ** add ioctl code 'ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE' ** customer can send this command for sync raid volume data ** 1.20.00.11 9/29/2005 Erich Chen by comment of Arjan van de Ven fix incorrect msleep redefine ** cast off sizeof(dma_addr_t) condition for 64bit pci_set_dma_mask ** 1.20.00.12 9/30/2005 Erich Chen bug fix with 64bit platform's ccbs using if over 4G system memory ** change 64bit pci_set_consistent_dma_mask into 32bit ** increcct adapter count if adapter initialize fail. ** miss edit at arcmsr_build_ccb.... ** psge += sizeof(struct _SG64ENTRY *) => psge += sizeof(struct _SG64ENTRY) ** 64 bits sg entry would be incorrectly calculated ** thanks Kornel Wieliczek give me kindly notify and detail description ** 1.20.00.13 11/15/2005 Erich Chen scheduling pending ccb with FIFO ** change the architecture of arcmsr command queue list ** for linux standard list ** enable usage of pci message signal interrupt Signed-off-by: Andrew Morton --- drivers/scsi/Kconfig | 28 drivers/scsi/arcmsr/arcmsr.c | 1151 ++++++++++--------------------- drivers/scsi/arcmsr/arcmsr.h | 112 +-- drivers/scsi/arcmsr/arcmsr.txt | 95 +- 4 files changed, 506 insertions(+), 880 deletions(-) diff -puN drivers/scsi/arcmsr/arcmsr.c~areca-raid-linux-scsi-driver-updates drivers/scsi/arcmsr/arcmsr.c --- devel/drivers/scsi/arcmsr/arcmsr.c~areca-raid-linux-scsi-driver-updates 2006-01-03 23:21:16.000000000 -0800 +++ devel-akpm/drivers/scsi/arcmsr/arcmsr.c 2006-01-03 23:21:16.000000000 -0800 @@ -64,7 +64,7 @@ ** 1.20.00.06 3/12/2005 Erich Chen fix with arcmsr_pci_unmap_dma "unsigned long" cast, ** modify PCCB POOL allocated by "dma_alloc_coherent" ** (Kornel Wieliczek's comment) -** 1.20.00.07 3/23/2005 Erich Chen bug fix with arcmsr_scsi_host_template_init ocur segmentation fault, +** 1.20.00.07 3/23/2005 Erich Chen bug fix with arcmsr_scsi_host_template_init occur segmentation fault, ** if RAID adapter does not on PCI slot and modprobe/rmmod this driver twice. ** bug fix enormous stack usage (Adrian Bunk's comment) ** 1.20.00.08 6/23/2005 Erich Chen bug fix with abort command,in case of heavy loading when sata cable @@ -85,6 +85,10 @@ ** psge += sizeof(struct _SG64ENTRY *) => psge += sizeof(struct _SG64ENTRY) ** 64 bits sg entry would be incorrectly calculated ** thanks Kornel Wieliczek give me kindly notify and detail description +** 1.20.00.13 11/15/2005 Erich Chen scheduling pending ccb with FIFO +** change the architecture of arcmsr command queue list +** for linux standard list +** enable usage of pci message signal interrupt ****************************************************************************************** */ #include @@ -106,6 +110,7 @@ #include #include #include +#include #include "arcmsr.h" MODULE_AUTHOR("Erich Chen "); @@ -116,7 +121,7 @@ MODULE_LICENSE("Dual BSD/GPL"); ********************************************************************************** ********************************************************************************** */ -static u_int8_t arcmsr_adapterCnt = 0; +static uint8_t arcmsr_adapterCnt = 0; static struct _HCBARC arcmsr_host_control_block; /* ********************************************************************************** @@ -148,7 +153,7 @@ static void arcmsr_pcidev_disattach(stru static void arcmsr_iop_init(struct _ACB *pACB); static void arcmsr_free_ccb_pool(struct _ACB *pACB); static irqreturn_t arcmsr_interrupt(struct _ACB *pACB); -static u_int8_t arcmsr_wait_msgint_ready(struct _ACB *pACB); +static uint8_t arcmsr_wait_msgint_ready(struct _ACB *pACB); static const char *arcmsr_info(struct Scsi_Host *); /* ********************************************************************************** @@ -166,7 +171,6 @@ static ssize_t arcmsr_show_firmware_info len = snprintf(buf, PAGE_SIZE, "=================================\n" "Firmware Version: %s\n" - "%s" "Adapter Model: %s\n" "Reguest Lenth: %4d\n" "Numbers of Queue: %4d\n" @@ -174,12 +178,10 @@ static ssize_t arcmsr_show_firmware_info "IDE Channels: %4d\n" "=================================\n", pACB->firm_version, - (strncmp(pACB->firm_version, "V1.37", 5) < - 0) ? - " PLEASE UPDATE RAID FIRMWARE VERSION EQUAL OR MORE THAN 'V1.37'\n" - : "", pACB->firm_model, pACB->firm_request_len, - pACB->firm_numbers_queue, pACB->firm_sdram_size, - pACB->firm_ide_channels); + pACB->firm_model, + pACB->firm_request_len, + pACB->firm_numbers_queue, + pACB->firm_sdram_size, pACB->firm_ide_channels); spin_unlock_irqrestore(pACB->host->host_lock, flags); return len; } @@ -206,8 +208,8 @@ static ssize_t arcmsr_show_driver_state( ARCMSR_DRIVER_VERSION, atomic_read(&pACB->ccboutstandingcount), ARCMSR_MAX_OUTSTANDING_CMD, - atomic_read(&pACB->ccbwait2gocount), - ARCMSR_MAX_FREECCB_NUM - ARCMSR_MAX_OUTSTANDING_CMD, + atomic_read(&pACB->ccbpendingcount), + ARCMSR_MAX_PENDING_CMD, ARCMSR_MAX_SG_ENTRIES, ARCMSR_MAX_XFER_SECTORS, pACB->num_resets, pACB->num_aborts); @@ -304,6 +306,8 @@ static struct pci_device_id arcmsr_devic PCI_ANY_ID,.subdevice = PCI_ANY_ID,}, {.vendor = PCIVendorIDARECA,.device = PCIDeviceIDARC1270,.subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID,}, + {.vendor = PCIVendorIDARECA,.device = PCI_ANY_ID,.subvendor = + PCI_ANY_ID,.subdevice = PCI_ANY_ID,}, {0, 0}, /* Terminating entry */ }; @@ -326,6 +330,7 @@ static irqreturn_t arcmsr_do_interrupt(i struct _HCBARC *pHCBARC = &arcmsr_host_control_block; struct _ACB *pACB; struct _ACB *pACBtmp; + unsigned long flags; int i = 0; pACB = (struct _ACB *)dev_id; @@ -337,9 +342,9 @@ static irqreturn_t arcmsr_do_interrupt(i if (!pACBtmp) { return IRQ_NONE; } - spin_lock_irq(&pACB->isr_lockunlock); + spin_lock_irqsave(pACB->host->host_lock, flags); handle_state = arcmsr_interrupt(pACB); - spin_unlock_irq(&pACB->isr_lockunlock); + spin_unlock_irqrestore(pACB->host->host_lock, flags); return (handle_state); } @@ -351,8 +356,19 @@ static int arcmsr_bios_param(struct scsi struct block_device *bdev, sector_t capacity, int *geom) { - int heads, sectors, cylinders, total_capacity; + int ret, heads, sectors, cylinders, total_capacity; + unsigned char *buffer; /* return copy of block device's partition table */ + buffer = scsi_bios_ptable(bdev); + if (buffer) { + ret = + scsi_partsize(buffer, capacity, &geom[2], &geom[0], + &geom[1]); + kfree(buffer); + if (ret != -1) { + return (ret); + } + } total_capacity = capacity; heads = 64; sectors = 32; @@ -381,7 +397,7 @@ static int __devinit arcmsr_device_probe uint8_t bus, dev_fun; if (pci_enable_device(pPCI_DEV)) { - printk("arcmsr%d adapter probe: pci_enable_device error \n", + printk("arcmsr%d: adapter probe: pci_enable_device error \n", arcmsr_adapterCnt); return -ENODEV; } @@ -389,7 +405,7 @@ static int __devinit arcmsr_device_probe if ((host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct _ACB))) == 0) { - printk("arcmsr%d adapter probe: scsi_host_alloc error \n", + printk("arcmsr%d: adapter probe: scsi_host_alloc error \n", arcmsr_adapterCnt); return -ENODEV; } @@ -416,11 +432,10 @@ static int __devinit arcmsr_device_probe dev_fun = pPCI_DEV->devfn; pACB = (struct _ACB *)host->hostdata; memset(pACB, 0, sizeof(struct _ACB)); - spin_lock_init(&pACB->isr_lockunlock); - spin_lock_init(&pACB->wait2go_lockunlock); - spin_lock_init(&pACB->qbuffer_lockunlock); - spin_lock_init(&pACB->ccb_doneindex_lockunlock); - spin_lock_init(&pACB->ccb_startindex_lockunlock); + spin_lock_init(&pACB->qbuffer_lock); + spin_lock_init(&pACB->pending_list_lock); + spin_lock_init(&pACB->working_list_lock); + spin_lock_init(&pACB->done_list_lock); pACB->pPCI_DEV = pPCI_DEV; pACB->host = host; host->max_sectors = ARCMSR_MAX_XFER_SECTORS; @@ -428,7 +443,7 @@ static int __devinit arcmsr_device_probe host->max_id = ARCMSR_MAX_TARGETID; /*16:8 */ host->max_cmd_len = 16; /*this is issue of 64bit LBA ,over 2T byte */ host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES; - host->can_queue = ARCMSR_MAX_OUTSTANDING_CMD; /* max simultaneous cmds */ + host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; host->this_id = ARCMSR_SCSI_INITIATOR_ID; host->unique_id = (bus << 8) | dev_fun; @@ -437,37 +452,40 @@ static int __devinit arcmsr_device_probe host->irq = pPCI_DEV->irq; pci_set_master(pPCI_DEV); if (arcmsr_initialize(pACB, pPCI_DEV)) { - printk("arcmsr%d initialize got error \n", arcmsr_adapterCnt); + printk("arcmsr%d: initialize got error \n", arcmsr_adapterCnt); pHCBARC->adapterCnt = arcmsr_adapterCnt; pHCBARC->pACB[arcmsr_adapterCnt] = NULL; + scsi_remove_host(host); scsi_host_put(host); return -ENODEV; } if (pci_request_regions(pPCI_DEV, "arcmsr")) { - printk("arcmsr%d adapter probe: pci_request_regions failed \n", + printk("arcmsr%d: adapter probe: pci_request_regions failed \n", arcmsr_adapterCnt--); pHCBARC->adapterCnt = arcmsr_adapterCnt; arcmsr_pcidev_disattach(pACB); - scsi_host_put(host); return -ENODEV; } +#ifdef CONFIG_PCI_MSI + if (pci_enable_msi(pPCI_DEV) == 0) { + pACB->acb_flags |= ACB_F_HAVE_MSI; + } +#endif if (request_irq (pPCI_DEV->irq, arcmsr_do_interrupt, SA_INTERRUPT | SA_SHIRQ, "arcmsr", pACB)) { - printk("arcmsr%d request IRQ=%d failed !\n", + printk("arcmsr%d: request IRQ=%d failed !\n", arcmsr_adapterCnt--, pPCI_DEV->irq); pHCBARC->adapterCnt = arcmsr_adapterCnt; arcmsr_pcidev_disattach(pACB); - scsi_host_put(host); return -ENODEV; } arcmsr_iop_init(pACB); if (scsi_add_host(host, &pPCI_DEV->dev)) { - printk("arcmsr%d scsi_add_host got error \n", + printk("arcmsr%d: scsi_add_host got error \n", arcmsr_adapterCnt--); pHCBARC->adapterCnt = arcmsr_adapterCnt; arcmsr_pcidev_disattach(pACB); - scsi_host_put(host); return -ENODEV; } pHCBARC->adapterCnt = arcmsr_adapterCnt; @@ -483,17 +501,11 @@ static int __devinit arcmsr_device_probe static void arcmsr_device_remove(struct pci_dev *pPCI_DEV) { struct Scsi_Host *host = pci_get_drvdata(pPCI_DEV); - struct _HCBARC *pHCBARC = &arcmsr_host_control_block; struct _ACB *pACB = (struct _ACB *)host->hostdata; + struct _HCBARC *pHCBARC = &arcmsr_host_control_block; int i; - /* Flush cache to disk */ - /* Free irq,otherwise extra interrupt is generated */ - /* Issue a blocking(interrupts disabled) command to the card */ arcmsr_pcidev_disattach(pACB); - scsi_remove_host(host); - scsi_host_put(host); - pci_set_drvdata(pPCI_DEV, NULL); /*if this is last pACB */ for (i = 0; i < ARCMSR_MAX_ADAPTER; i++) { if (pHCBARC->pACB[i] != NULL) { @@ -670,36 +682,38 @@ static int arcmsr_fops_ioctl(struct inod static void arcmsr_flush_adapter_cache(struct _ACB *pACB) { writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &pACB->pmu->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) { + printk("arcmsr%d: wait 'flush adapter cache' timeout \n", + pACB->adapter_index); + } return; } /* ********************************************************************** -** Q back this CCB into ACB ArrayCCB ********************************************************************** */ -static void arcmsr_ccb_complete(struct _CCB *pCCB) +static void arcmsr_ccb_complete(struct _CCB *pCCB, int stand_flag) { - unsigned long flag; + unsigned long flags; struct _ACB *pACB = pCCB->pACB; struct scsi_cmnd *pcmd = pCCB->pcmd; arcmsr_pci_unmap_dma(pCCB); - spin_lock_irqsave(&pACB->ccb_doneindex_lockunlock, flag); - atomic_dec(&pACB->ccboutstandingcount); + spin_lock_irqsave(&pACB->done_list_lock, flags); + if (stand_flag == 1) { + atomic_dec(&pACB->ccboutstandingcount); + } pCCB->startdone = ARCMSR_CCB_DONE; pCCB->ccb_flags = 0; - pACB->pccbringQ[pACB->ccb_doneindex] = pCCB; - pACB->ccb_doneindex++; - pACB->ccb_doneindex %= ARCMSR_MAX_FREECCB_NUM; - spin_unlock_irqrestore(&pACB->ccb_doneindex_lockunlock, flag); + list_add_tail(&pCCB->list, &pACB->ccb_free_list); + spin_unlock_irqrestore(&pACB->done_list_lock, flags); pcmd->scsi_done(pcmd); return; } /* ********************************************************************** -** if scsi error do auto request sense ********************************************************************** */ static void arcmsr_report_sense_info(struct _CCB *pCCB) @@ -729,22 +743,14 @@ static void arcmsr_report_sense_info(str ** to insert pCCB into tail of pACB wait exec ccbQ ********************************************************************* */ -static void arcmsr_queue_wait2go_ccb(struct _ACB *pACB, struct _CCB *pCCB) +static void arcmsr_queue_pendingccb(struct _ACB *pACB, struct _CCB *pCCB) { - unsigned long flag; - int i = 0; + unsigned long flags; - spin_lock_irqsave(&pACB->wait2go_lockunlock, flag); - while (1) { - if (pACB->pccbwait2go[i] == NULL) { - pACB->pccbwait2go[i] = pCCB; - atomic_inc(&pACB->ccbwait2gocount); - spin_unlock_irqrestore(&pACB->wait2go_lockunlock, flag); - return; - } - i++; - i %= ARCMSR_MAX_OUTSTANDING_CMD; - } + spin_lock_irqsave(&pACB->pending_list_lock, flags); + list_add_tail(&pCCB->list, &pACB->ccb_pending_list); + atomic_inc(&pACB->ccbpendingcount); + spin_unlock_irqrestore(&pACB->pending_list_lock, flags); return; } @@ -754,9 +760,12 @@ static void arcmsr_queue_wait2go_ccb(str */ static void arcmsr_abort_allcmd(struct _ACB *pACB) { - printk - ("arcmsr_abort_allcmd: try to abort all outstanding command............\n"); writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &pACB->pmu->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) { + printk + ("arcmsr%d: wait 'abort all outstanding command' timeout \n", + pACB->adapter_index); + } return; } @@ -764,7 +773,7 @@ static void arcmsr_abort_allcmd(struct _ ********************************************************************** ********************************************************************** */ -static u_int8_t arcmsr_wait_msgint_ready(struct _ACB *pACB) +static uint8_t arcmsr_wait_msgint_ready(struct _ACB *pACB) { uint32_t Index; uint8_t Retries = 0x00; @@ -782,6 +791,27 @@ static u_int8_t arcmsr_wait_msgint_ready } /* +************************************************************************** +************************************************************************** +*/ +static struct _CCB *arcmsr_get_pendingccb(struct _ACB *pACB) +{ + unsigned long flags; + struct list_head *head = &pACB->ccb_pending_list; + struct _CCB *pCCB = NULL; + + if (spin_trylock_irqsave(&pACB->pending_list_lock, flags)) { + if (!list_empty(head)) { + pCCB = list_entry(head->next, struct _CCB, list); + atomic_dec(&pACB->ccbpendingcount); + list_del(head->next); + } + spin_unlock_irqrestore(&pACB->pending_list_lock, flags); + } + return (pCCB); +} + +/* **************************************************************************** ** Routine Description: Reset 80331 iop. ** Arguments: @@ -795,17 +825,14 @@ static void arcmsr_iop_reset(struct _ACB int i = 0; if (atomic_read(&pACB->ccboutstandingcount) != 0) { + /* talk to iop 331 outstanding command aborted */ + arcmsr_abort_allcmd(pACB); + msleep_interruptible(3000); /* wait for 3 sec for all command aborted */ /* disable all outbound interrupt */ intmask_org = readl(&pACB->pmu->outbound_intmask); writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, &pACB->pmu->outbound_intmask); - /* talk to iop 331 outstanding command aborted */ - arcmsr_abort_allcmd(pACB); - if (arcmsr_wait_msgint_ready(pACB)) { - printk - ("arcmsr_iop_reset: wait 'abort all outstanding command' timeout................. \n"); - } - /*clear all outbound posted Q */ + /* clear all outbound posted Q */ for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) { readl(&pACB->pmu->outbound_queueport); } @@ -814,31 +841,33 @@ static void arcmsr_iop_reset(struct _ACB if (pCCB->startdone == ARCMSR_CCB_START) { pCCB->startdone = ARCMSR_CCB_ABORTED; pCCB->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } } /* enable all outbound interrupt */ mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); + ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); writel(intmask_org & mask, &pACB->pmu->outbound_intmask); /* post abort all outstanding command message to RAID controller */ } - i = 0; - while (atomic_read(&pACB->ccbwait2gocount) != 0) { - pCCB = pACB->pccbwait2go[i]; + while (atomic_read(&pACB->ccbpendingcount) != 0) { + pCCB = arcmsr_get_pendingccb(pACB); if (pCCB != NULL) { - pACB->pccbwait2go[i] = NULL; + printk + ("arcmsr%d:iop reset abort command ccbpendingcount=%d \n", + pACB->adapter_index, + atomic_read(&pACB->ccbpendingcount)); pCCB->startdone = ARCMSR_CCB_ABORTED; pCCB->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); - atomic_dec(&pACB->ccbwait2gocount); + arcmsr_ccb_complete(pCCB, 0); + atomic_dec(&pACB->ccbpendingcount); + } else { + break; } - i++; - i %= ARCMSR_MAX_OUTSTANDING_CMD; } atomic_set(&pACB->ccboutstandingcount, 0); + atomic_set(&pACB->ccbpendingcount, 0); return; } @@ -938,13 +967,6 @@ static void arcmsr_build_ccb(struct _ACB /* ************************************************************************** -** arcmsr_post_ccb - Send a protocol specific ARC send postcard to a AIOC . -** handle: Handle of registered ARC protocol driver -** adapter_id: AIOC unique identifier(integer) -** pPOSTCARD_SEND: Pointer to ARC send postcard -** -** This routine posts a ARC send postcard to the request post FIFO of a -** specific ARC adapter. ************************************************************************** */ static void arcmsr_post_ccb(struct _ACB *pACB, struct _CCB *pCCB) @@ -968,57 +990,52 @@ static void arcmsr_post_ccb(struct _ACB ************************************************************************** ************************************************************************** */ -static void arcmsr_post_wait2go_ccb(struct _ACB *pACB) +static void arcmsr_post_pendingccb(struct _ACB *pACB) { - unsigned long flag; struct _CCB *pCCB; - int i = 0; - spin_lock_irqsave(&pACB->wait2go_lockunlock, flag); - while ((atomic_read(&pACB->ccbwait2gocount) > 0) + while ((atomic_read(&pACB->ccbpendingcount) > 0) && (atomic_read(&pACB->ccboutstandingcount) < ARCMSR_MAX_OUTSTANDING_CMD)) { - pCCB = pACB->pccbwait2go[i]; - if (pCCB != NULL) { - pACB->pccbwait2go[i] = NULL; - arcmsr_post_ccb(pACB, pCCB); - atomic_dec(&pACB->ccbwait2gocount); + pCCB = arcmsr_get_pendingccb(pACB); + if (pCCB == NULL) { + break; } - i++; - i %= ARCMSR_MAX_OUTSTANDING_CMD; + arcmsr_post_ccb(pACB, pCCB); } - spin_unlock_irqrestore(&pACB->wait2go_lockunlock, flag); return; } /* ********************************************************************** -** Function: arcmsr_post_Qbuffer -** Output: ********************************************************************** */ static void arcmsr_post_Qbuffer(struct _ACB *pACB) { uint8_t *pQbuffer; - PQBUFFER pwbuffer = (PQBUFFER) & pACB->pmu->ioctl_wbuffer; + struct _QBUFFER *pwbuffer = + (struct _QBUFFER *)&pACB->pmu->ioctl_wbuffer; uint8_t *iop_data = (uint8_t *) pwbuffer->data; int32_t allxfer_len = 0; - while ((pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) - && (allxfer_len < 124)) { - pQbuffer = &pACB->wqbuffer[pACB->wqbuf_firstindex]; - memcpy(iop_data, pQbuffer, 1); - pACB->wqbuf_firstindex++; - pACB->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ - iop_data++; - allxfer_len++; + if (pACB->acb_flags & ACB_F_IOCTL_WQBUFFER_READED) { + pACB->acb_flags &= (~ACB_F_IOCTL_WQBUFFER_READED); + while ((pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) + && (allxfer_len < 124)) { + pQbuffer = &pACB->wqbuffer[pACB->wqbuf_firstindex]; + memcpy(iop_data, pQbuffer, 1); + pACB->wqbuf_firstindex++; + pACB->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ + iop_data++; + allxfer_len++; + } + pwbuffer->data_len = allxfer_len; + /* + ** push inbound doorbell and wait reply at hwinterrupt routine for next Qbuffer post + */ + writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, + &pACB->pmu->inbound_doorbell); } - pwbuffer->data_len = allxfer_len; - /* - ** push inbound doorbell and wait reply at hwinterrupt routine for next Qbuffer post - */ - writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, - &pACB->pmu->inbound_doorbell); return; } @@ -1028,9 +1045,13 @@ static void arcmsr_post_Qbuffer(struct _ */ static void arcmsr_stop_adapter_bgrb(struct _ACB *pACB) { - pACB->acb_flags |= ACB_F_MSG_STOP_BGRB; pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &pACB->pmu->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) { + printk + ("arcmsr%d: wait 'stop adapter background rebulid' timeout \n", + pACB->adapter_index); + } return; } @@ -1048,21 +1069,6 @@ static void arcmsr_free_ccb_pool(struct /* ********************************************************************** -** Function: arcmsr_interrupt -** Output: void -** DID_OK 0x00 // NO error -** DID_NO_CONNECT 0x01 // Couldn't connect before timeout period -** DID_BUS_BUSY 0x02 // BUS stayed busy through time out period -** DID_TIME_OUT 0x03 // TIMED OUT for other reason -** DID_BAD_TARGET 0x04 // BAD target. -** DID_ABORT 0x05 // Told to abort for some other reason -** DID_PARITY 0x06 // Parity error -** DID_ERROR 0x07 // Internal error -** DID_RESET 0x08 // Reset by somebody. -** DID_BAD_INTR 0x09 // Got an interrupt we weren't expecting. -** DID_PASSTHROUGH 0x0a // Force command past mid-layer -** DID_SOFT_ERROR 0x0b // The low level driver just wish a retry -** DRIVER_OK 0x00 // Driver status ********************************************************************** */ static irqreturn_t arcmsr_interrupt(struct _ACB *pACB) @@ -1070,31 +1076,20 @@ static irqreturn_t arcmsr_interrupt(stru struct _CCB *pCCB; uint32_t flag_ccb, outbound_intstatus, outbound_doorbell; - /* - ********************************************* - ** check outbound intstatus 檢察有無郵差按門鈴 - ********************************************* - */ outbound_intstatus = readl(&pACB->pmu->outbound_intstatus) & pACB->outbound_int_enable; - writel(outbound_intstatus, &pACB->pmu->outbound_intstatus); /*clear interrupt */ + writel(outbound_intstatus, &pACB->pmu->outbound_intstatus); if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { - /* - ********************************************* - ** DOORBELL 叮噹! 是否有郵件要簽收 - ********************************************* - */ outbound_doorbell = readl(&pACB->pmu->outbound_doorbell); - writel(outbound_doorbell, &pACB->pmu->outbound_doorbell); /*clear interrupt */ + writel(outbound_doorbell, &pACB->pmu->outbound_doorbell); if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { - PQBUFFER prbuffer = - (PQBUFFER) & pACB->pmu->ioctl_rbuffer; + struct _QBUFFER *prbuffer = + (struct _QBUFFER *)&pACB->pmu->ioctl_rbuffer; uint8_t *iop_data = (uint8_t *) prbuffer->data; uint8_t *pQbuffer; int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; - /*check this iop data if overflow my rqbuffer */ rqbuf_lastindex = pACB->rqbuf_lastindex; rqbuf_firstindex = pACB->rqbuf_firstindex; iop_len = prbuffer->data_len; @@ -1108,28 +1103,29 @@ static irqreturn_t arcmsr_interrupt(stru rqbuf_lastindex]; memcpy(pQbuffer, iop_data, 1); pACB->rqbuf_lastindex++; - pACB->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ + pACB->rqbuf_lastindex %= + ARCMSR_MAX_QBUFFER; iop_data++; iop_len--; } - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &pACB->pmu->inbound_doorbell); /*signature, let IOP331 know data has been readed */ + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + &pACB->pmu->inbound_doorbell); } else { pACB->acb_flags |= ACB_F_IOPDATA_OVERFLOW; } } if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { - /* - ********************************************* - ** 看看是否還有郵件要順道寄出 - ********************************************* - */ + pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_READED; if (pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) { uint8_t *pQbuffer; - PQBUFFER pwbuffer = - (PQBUFFER) & pACB->pmu->ioctl_wbuffer; + struct _QBUFFER *pwbuffer = + (struct _QBUFFER *)&pACB->pmu-> + ioctl_wbuffer; uint8_t *iop_data = (uint8_t *) pwbuffer->data; int32_t allxfer_len = 0; + pACB->acb_flags &= + (~ACB_F_IOCTL_WQBUFFER_READED); while ((pACB->wqbuf_firstindex != pACB->wqbuf_lastindex) && (allxfer_len < 124)) { @@ -1138,17 +1134,16 @@ static irqreturn_t arcmsr_interrupt(stru wqbuf_firstindex]; memcpy(iop_data, pQbuffer, 1); pACB->wqbuf_firstindex++; - pACB->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ + pACB->wqbuf_firstindex %= + ARCMSR_MAX_QBUFFER; iop_data++; allxfer_len++; } pwbuffer->data_len = allxfer_len; - /* - ** push inbound doorbell tell iop driver data write ok and wait reply on next hwinterrupt for next Qbuffer post - */ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, &pACB->pmu->inbound_doorbell); - } else { + } + if (pACB->wqbuf_firstindex == pACB->wqbuf_lastindex) { pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_CLEARED; } } @@ -1172,16 +1167,12 @@ static irqreturn_t arcmsr_interrupt(stru || (pCCB->startdone != ARCMSR_CCB_START)) { if (pCCB->startdone == ARCMSR_CCB_ABORTED) { printk - ("arcmsr%d scsi id=%d lun=%d ccb='0x%p' isr command abort successfully \n", - pACB->adapter_index, - pCCB->pcmd->device->id, - pCCB->pcmd->device->lun, pCCB); - pCCB->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); + ("arcmsr%d: ccb='0x%p' isr got aborted command \n", + pACB->adapter_index, pCCB); continue; } printk - ("arcmsr%d isr and getting an illegal ccb command done acb='0x%p' ccb='0x%p' ccbacb='0x%p' startdone=0x%x ccboutstandingcount=%d \n", + ("arcmsr%d: isr get an illegal ccb command done acb='0x%p' ccb='0x%p' ccbacb='0x%p' startdone=0x%x ccboutstandingcount=%d \n", pACB->adapter_index, pACB, pCCB, pCCB->pACB, pCCB->startdone, atomic_read(&pACB->ccboutstandingcount)); @@ -1195,7 +1186,7 @@ static irqreturn_t arcmsr_interrupt(stru ARECA_RAID_GOOD; } pCCB->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } else { switch (pCCB->arcmsr_cdb.DeviceStatus) { case ARCMSR_DEV_SELECT_TIMEOUT: @@ -1204,7 +1195,7 @@ static irqreturn_t arcmsr_interrupt(stru ARECA_RAID_GONE; pCCB->pcmd->result = DID_TIME_OUT << 16; - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } break; case ARCMSR_DEV_ABORTED: @@ -1214,7 +1205,7 @@ static irqreturn_t arcmsr_interrupt(stru ARECA_RAID_GONE; pCCB->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } break; case SCSISTAT_CHECK_CONDITION: @@ -1222,19 +1213,18 @@ static irqreturn_t arcmsr_interrupt(stru pACB->devstate[id][lun] = ARECA_RAID_GOOD; arcmsr_report_sense_info(pCCB); - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } break; default: - /* error occur Q all error ccb to errorccbpending Q */ printk - ("arcmsr%d scsi id=%d lun=%d isr get command error done, but got unknow DeviceStatus=0x%x \n", + ("arcmsr%d: scsi id=%d lun=%d isr get command error done, but got unknow DeviceStatus=0x%x \n", pACB->adapter_index, id, lun, pCCB->arcmsr_cdb.DeviceStatus); pACB->devstate[id][lun] = ARECA_RAID_GONE; pCCB->pcmd->result = DID_NO_CONNECT << 16; /*unknow error or crc error just for retry */ - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); break; } } @@ -1244,9 +1234,7 @@ static irqreturn_t arcmsr_interrupt(stru /*it must be share irq */ return IRQ_NONE; } - if (atomic_read(&pACB->ccbwait2gocount) != 0) { - arcmsr_post_wait2go_ccb(pACB); /*try to post all pending ccb */ - } + arcmsr_post_pendingccb(pACB); /*try to post all pending ccb */ return IRQ_HANDLED; } @@ -1261,17 +1249,7 @@ static void arcmsr_iop_parking(struct _A if (pACB->acb_flags & ACB_F_MSG_START_BGRB) { pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; arcmsr_stop_adapter_bgrb(pACB); - if (arcmsr_wait_msgint_ready(pACB)) { - printk - ("arcmsr%d wait 'stop adapter rebulid' timeout \n", - pACB->adapter_index); - } arcmsr_flush_adapter_cache(pACB); - if (arcmsr_wait_msgint_ready(pACB)) { - printk - ("arcmsr%d wait 'stop adapter rebulid' timeout \n", - pACB->adapter_index); - } } } } @@ -1284,13 +1262,15 @@ static int arcmsr_iop_ioctlcmd(struct _A { struct _CMD_IOCTL_FIELD *pcmdioctlfld; dma_addr_t cmd_handle; + unsigned long flag; int retvalue = 0; - /* Only let one of these through at a time */ + spin_lock_irqsave(&pACB->qbuffer_lock, flag); pcmdioctlfld = pci_alloc_consistent(pACB->pPCI_DEV, sizeof(struct _CMD_IOCTL_FIELD), &cmd_handle); if (pcmdioctlfld == NULL) { + spin_unlock_irqrestore(&pACB->qbuffer_lock, flag); return -ENOMEM; } if (copy_from_user(pcmdioctlfld, arg, sizeof(struct _CMD_IOCTL_FIELD)) @@ -1305,7 +1285,6 @@ static int arcmsr_iop_ioctlcmd(struct _A switch (ioctl_cmd) { case ARCMSR_IOCTL_READ_RQBUFFER: { - unsigned long flag; unsigned long *ver_addr; dma_addr_t buf_handle; uint8_t *pQbuffer, *ptmpQbuffer; @@ -1319,41 +1298,40 @@ static int arcmsr_iop_ioctlcmd(struct _A goto ioctl_out; } ptmpQbuffer = (uint8_t *) ver_addr; - spin_lock_irqsave(&pACB->qbuffer_lockunlock, flag); while ((pACB->rqbuf_firstindex != pACB->rqbuf_lastindex) && (allxfer_len < 1031)) { - /*copy READ QBUFFER to srb */ pQbuffer = &pACB->rqbuffer[pACB->rqbuf_firstindex]; memcpy(ptmpQbuffer, pQbuffer, 1); pACB->rqbuf_firstindex++; - pACB->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ + pACB->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; ptmpQbuffer++; allxfer_len++; } if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - PQBUFFER prbuffer = - (PQBUFFER) & pACB->pmu->ioctl_rbuffer; + struct _QBUFFER *prbuffer = + (struct _QBUFFER *)&pACB->pmu-> + ioctl_rbuffer; uint8_t *pQbuffer; uint8_t *iop_data = (uint8_t *) prbuffer->data; int32_t iop_len; pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; iop_len = (int32_t) prbuffer->data_len; - /*this iop data does no chance to make me overflow again here, so just do it */ while (iop_len > 0) { pQbuffer = &pACB->rqbuffer[pACB-> rqbuf_lastindex]; memcpy(pQbuffer, iop_data, 1); pACB->rqbuf_lastindex++; - pACB->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ + pACB->rqbuf_lastindex %= + ARCMSR_MAX_QBUFFER; iop_data++; iop_len--; } - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &pACB->pmu->inbound_doorbell); /*signature, let IOP331 know data has been readed */ + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + &pACB->pmu->inbound_doorbell); } - spin_unlock_irqrestore(&pACB->qbuffer_lockunlock, flag); memcpy(pcmdioctlfld->ioctldatabuffer, (uint8_t *) ver_addr, allxfer_len); pcmdioctlfld->cmdioctl.Length = allxfer_len; @@ -1370,7 +1348,6 @@ static int arcmsr_iop_ioctlcmd(struct _A break; case ARCMSR_IOCTL_WRITE_WQBUFFER: { - unsigned long flag; unsigned long *ver_addr; dma_addr_t buf_handle; int32_t my_empty_len, user_len, wqbuf_firstindex, @@ -1388,39 +1365,43 @@ static int arcmsr_iop_ioctlcmd(struct _A user_len = pcmdioctlfld->cmdioctl.Length; memcpy(ptmpuserbuffer, pcmdioctlfld->ioctldatabuffer, user_len); - /*check if data xfer length of this request will overflow my array qbuffer */ - spin_lock_irqsave(&pACB->qbuffer_lockunlock, flag); wqbuf_lastindex = pACB->wqbuf_lastindex; wqbuf_firstindex = pACB->wqbuf_firstindex; - my_empty_len = - (wqbuf_firstindex - wqbuf_lastindex - - 1) & (ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= user_len) { - while (user_len > 0) { - /*copy srb data to wqbuffer */ - pQbuffer = - &pACB->wqbuffer[pACB-> - wqbuf_lastindex]; - memcpy(pQbuffer, ptmpuserbuffer, 1); - pACB->wqbuf_lastindex++; - pACB->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; /*if last index number set it to 0 */ - ptmpuserbuffer++; - user_len--; - } - /*post fist Qbuffer */ - if (pACB-> - acb_flags & ACB_F_IOCTL_WQBUFFER_CLEARED) { - pACB->acb_flags &= - ~ACB_F_IOCTL_WQBUFFER_CLEARED; - arcmsr_post_Qbuffer(pACB); - } - pcmdioctlfld->cmdioctl.ReturnCode = - ARCMSR_IOCTL_RETURNCODE_OK; - } else { + if (wqbuf_lastindex != wqbuf_firstindex) { + arcmsr_post_Qbuffer(pACB); pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_ERROR; + } else { + my_empty_len = + (wqbuf_firstindex - wqbuf_lastindex - + 1) & (ARCMSR_MAX_QBUFFER - 1); + if (my_empty_len >= user_len) { + while (user_len > 0) { + pQbuffer = + &pACB->wqbuffer[pACB-> + wqbuf_lastindex]; + memcpy(pQbuffer, ptmpuserbuffer, + 1); + pACB->wqbuf_lastindex++; + pACB->wqbuf_lastindex %= + ARCMSR_MAX_QBUFFER; + ptmpuserbuffer++; + user_len--; + } + if (pACB-> + acb_flags & + ACB_F_IOCTL_WQBUFFER_CLEARED) { + pACB->acb_flags &= + ~ACB_F_IOCTL_WQBUFFER_CLEARED; + arcmsr_post_Qbuffer(pACB); + } + pcmdioctlfld->cmdioctl.ReturnCode = + ARCMSR_IOCTL_RETURNCODE_OK; + } else { + pcmdioctlfld->cmdioctl.ReturnCode = + ARCMSR_IOCTL_RETURNCODE_ERROR; + } } - spin_unlock_irqrestore(&pACB->qbuffer_lockunlock, flag); if (copy_to_user (arg, pcmdioctlfld, sizeof(struct _CMD_IOCTL_FIELD)) != 0) { @@ -1432,20 +1413,17 @@ static int arcmsr_iop_ioctlcmd(struct _A break; case ARCMSR_IOCTL_CLEAR_RQBUFFER: { - unsigned long flag; uint8_t *pQbuffer = pACB->rqbuffer; if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) { pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &pACB->pmu->inbound_doorbell); /*signature, let IOP331 know data has been readed */ + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + &pACB->pmu->inbound_doorbell); } pACB->acb_flags |= ACB_F_IOCTL_RQBUFFER_CLEARED; - spin_lock_irqsave(&pACB->qbuffer_lockunlock, flag); pACB->rqbuf_firstindex = 0; pACB->rqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - spin_unlock_irqrestore(&pACB->qbuffer_lockunlock, flag); - /*report success */ pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK; if (copy_to_user @@ -1457,20 +1435,19 @@ static int arcmsr_iop_ioctlcmd(struct _A break; case ARCMSR_IOCTL_CLEAR_WQBUFFER: { - unsigned long flag; uint8_t *pQbuffer = pACB->wqbuffer; if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) { pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &pACB->pmu->inbound_doorbell); /*signature, let IOP331 know data has been readed */ + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + &pACB->pmu->inbound_doorbell); } - pACB->acb_flags |= ACB_F_IOCTL_WQBUFFER_CLEARED; - spin_lock_irqsave(&pACB->qbuffer_lockunlock, flag); + pACB->acb_flags |= + (ACB_F_IOCTL_WQBUFFER_CLEARED | + ACB_F_IOCTL_WQBUFFER_READED); pACB->wqbuf_firstindex = 0; pACB->wqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - spin_unlock_irqrestore(&pACB->qbuffer_lockunlock, flag); - /*report success */ pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK; if (copy_to_user @@ -1482,17 +1459,17 @@ static int arcmsr_iop_ioctlcmd(struct _A break; case ARCMSR_IOCTL_CLEAR_ALLQBUFFER: { - unsigned long flag; uint8_t *pQbuffer; if (pACB->acb_flags & ACB_F_IOPDATA_OVERFLOW) { pACB->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &pACB->pmu->inbound_doorbell); /*signature, let IOP331 know data has been readed */ + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + &pACB->pmu->inbound_doorbell); } pACB->acb_flags |= (ACB_F_IOCTL_WQBUFFER_CLEARED | - ACB_F_IOCTL_RQBUFFER_CLEARED); - spin_lock_irqsave(&pACB->qbuffer_lockunlock, flag); + ACB_F_IOCTL_RQBUFFER_CLEARED | + ACB_F_IOCTL_WQBUFFER_READED); pACB->rqbuf_firstindex = 0; pACB->rqbuf_lastindex = 0; pACB->wqbuf_firstindex = 0; @@ -1501,8 +1478,6 @@ static int arcmsr_iop_ioctlcmd(struct _A memset(pQbuffer, 0, sizeof(struct _QBUFFER)); pQbuffer = pACB->wqbuffer; memset(pQbuffer, 0, sizeof(struct _QBUFFER)); - spin_unlock_irqrestore(&pACB->qbuffer_lockunlock, flag); - /*report success */ pcmdioctlfld->cmdioctl.ReturnCode = ARCMSR_IOCTL_RETURNCODE_OK; if (copy_to_user @@ -1546,11 +1521,6 @@ static int arcmsr_iop_ioctlcmd(struct _A case ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE: { arcmsr_flush_adapter_cache(pACB); - if (arcmsr_wait_msgint_ready(pACB)) { - printk - ("arcmsr%d ioctl flush cache wait 'flush adapter cache' timeout \n", - pACB->adapter_index); - } } break; default: @@ -1559,85 +1529,12 @@ static int arcmsr_iop_ioctlcmd(struct _A ioctl_out: pci_free_consistent(pACB->pPCI_DEV, sizeof(struct _CMD_IOCTL_FIELD), pcmdioctlfld, cmd_handle); + spin_unlock_irqrestore(&pACB->qbuffer_lock, flag); return retvalue; } /* ************************************************************************ -** arcmsr_ioctl -** Performs ioctl requests not satified by the upper levels. -** copy_from_user(to,from,n) -** copy_to_user(to,from,n) -** -** The scsi_device struct contains what we know about each given scsi -** device. -** -** FIXME(eric) - one of the great regrets that I have is that I failed to define -** these structure elements as something like sdev_foo instead of foo. This would -** make it so much easier to grep through sources and so forth. I propose that -** all new elements that get added to these structures follow this convention. -** As time goes on and as people have the stomach for it, it should be possible to -** go back and retrofit at least some of the elements here with with the prefix. -** -** -**struct scsi_device { -** %% private: %% -** %% -** %% This information is private to the scsi mid-layer. Wrapping it in a -** %% struct private is a way of marking it in a sort of C++ type of way. -** %% -** -** struct scsi_device *next; %% Used for linked list %% -** struct scsi_device *prev; %% Used for linked list %% -** wait_queue_head_t scpnt_wait; %% Used to wait if device is busy %% -** struct Scsi_Host *host; -** request_queue_t request_queue; -** atomic_t device_active; %% commands checked out for device %% -** volatile unsigned short device_busy; %% commands actually active on low-level %% -** int (*scsi_init_io_fn) (struct scsi_cmnd *); %% Used to initialize new request %% -** struct scsi_cmnd *device_queue; %% queue of SCSI Command structures %% -** -** %% public: %% -** -** unsigned int id, lun, channel; -** unsigned int manufacturer; %% Manufacturer of device, for using vendor-specific cmd's %% -** unsigned sector_size; %% size in bytes %% -** int attached; %% # of high level drivers attached to this %% -** int access_count; %% Count of open channels/mounts %% -** void *hostdata; %% available to low-level driver %% -** devfs_handle_t de; %% directory for the device %% -** char type; -** char scsi_level; -** char vendor[8], model[16], rev[4]; -** unsigned char current_tag; %% current tag %% -** unsigned char sync_min_period; %% Not less than this period %% -** unsigned char sync_max_offset; %% Not greater than this offset %% -** unsigned char queue_depth; %% How deep a queue to use %% -** unsigned online:1; -** unsigned writeable:1; -** unsigned removable:1; -** unsigned random:1; -** unsigned has_cmdblocks:1; -** unsigned changed:1; %% Data invalid due to media change %% -** unsigned busy:1; %% Used to prevent races %% -** unsigned lockable:1; %% Able to prevent media removal %% -** unsigned borken:1; %% Tell the Seagate driver to be painfully slow on this device %% -** unsigned tagged_supported:1; %% Supports SCSI-II tagged queuing %% -** unsigned tagged_queue:1; %% SCSI-II tagged queuing enabled %% -** unsigned disconnect:1; %% can disconnect %% -** unsigned soft_reset:1; %% Uses soft reset option %% -** unsigned sync:1; %% Negotiate for sync transfers %% -** unsigned wide:1; %% Negotiate for WIDE transfers %% -** unsigned single_lun:1; %% Indicates we should only allow I/O to one of the luns for the device at a time. %% -** unsigned was_reset:1; %% There was a bus reset on the bus for this device %% -** unsigned expecting_cc_ua:1; %% Expecting a CHECK_CONDITION/UNIT_ATTN because we did a bus reset. %% -** unsigned device_blocked:1; %% Device returned QUEUE_FULL. %% -** unsigned ten:1; %% support ten byte read / write %% -** unsigned remap:1; %% support remapping %% -** unsigned starved:1; %% unable to process commands because host busy %% -** int allow_revalidate; %% Flag to allow revalidate to succeed in sd_open -**}; -** ************************************************************************ */ static int arcmsr_ioctl(struct scsi_device *dev, int ioctl_cmd, void *arg) @@ -1669,170 +1566,21 @@ static int arcmsr_ioctl(struct scsi_devi */ static struct _CCB *arcmsr_get_freeccb(struct _ACB *pACB) { - struct _CCB *pCCB; - unsigned long flag; - int ccb_startindex, ccb_doneindex; - - spin_lock_irqsave(&pACB->ccb_startindex_lockunlock, flag); - ccb_doneindex = pACB->ccb_doneindex; - ccb_startindex = pACB->ccb_startindex; - pCCB = pACB->pccbringQ[ccb_startindex]; - ccb_startindex++; - ccb_startindex %= ARCMSR_MAX_FREECCB_NUM; - if (ccb_doneindex != ccb_startindex) { - pACB->ccb_startindex = ccb_startindex; - } else { - pCCB = NULL; + unsigned long flags; + struct list_head *head = &pACB->ccb_free_list; + struct _CCB *pCCB = NULL; + + spin_lock_irqsave(&pACB->working_list_lock, flags); + if (!list_empty(head)) { + pCCB = list_entry(head->next, struct _CCB, list); + list_del(head->next); } - spin_unlock_irqrestore(&pACB->ccb_startindex_lockunlock, flag); + spin_unlock_irqrestore(&pACB->working_list_lock, flags); return (pCCB); } /* *********************************************************************** -** -** struct scsi_cmnd { -** int sc_magic; -** // private: // -** // -** // This information is private to the scsi mid-layer. Wrapping it in a -** // struct private is a way of marking it in a sort of C++ type of way. -** // -** struct Scsi_Host *host; -** unsigned short state; -** unsigned short owner; -** struct scsi_device *device; -** Scsi_Request *sc_request; -** struct scsi_cmnd *next; -** struct scsi_cmnd *reset_chain; -** -** int eh_state; // Used for state tracking in error handlr -** void (*done) (struct scsi_cmnd *); -** // Mid-level done function -** // -** // A SCSI Command is assigned a nonzero serial_number when internal_cmnd -** // passes it to the driver's queue command function. The serial_number -** // is cleared when scsi_done is entered indicating that the command has -** // been completed. If a timeout occurs,the serial number at the moment -** // of timeout is copied into serial_number_at_timeout. By subsequently -** // comparing the serial_number and serial_number_at_timeout fields -** // during abort or reset processing,we can detect whether the command -** // has already completed. This also detects cases where the command has -** // completed and the SCSI Command structure has already being reused -** // for another command,so that we can avoid incorrectly aborting or -** // resetting the new command. -** // -** -** unsigned long serial_number; -** unsigned long serial_number_at_timeout; -** -** int retries; -** int allowed; -** int timeout_per_command; -** int timeout_total; -** int timeout; -** -** // -** // We handle the timeout differently if it happens when a reset, -** // abort,etc are in process. -** // -** unsigned volatile char internal_timeout; -** struct scsi_cmnd *bh_next; -** // To enumerate the commands waiting to be processed. -** -** // public: // -** -** unsigned int target; -** unsigned int lun; -** unsigned int channel; -** unsigned char cmd_len; -** unsigned char old_cmd_len; -** unsigned char sc_data_direction; -** unsigned char sc_old_data_direction; -** // These elements define the operation we are about to perform -** unsigned char cmnd[MAX_COMMAND_SIZE]; -** unsigned request_bufflen; -** // Actual request size -** -** struct timer_list eh_timeout; -** // Used to time out the command. -** void *request_buffer; -** // Actual requested buffer -** // These elements define the operation we ultimately want to perform -** unsigned char data_cmnd[MAX_COMMAND_SIZE]; -** unsigned short old_use_sg; -** // We save use_sg here when requesting sense info -** unsigned short use_sg; -** // Number of pieces of scatter-gather -** unsigned short sglist_len; -** // size of malloc'd scatter-gather list -** unsigned short abort_reason; -** // If the mid-level code requests an abort,this is the reason. -** unsigned bufflen; -** // Size of data buffer -** void *buffer; -** // Data buffer -** unsigned underflow; -** // Return error if less than this amount is transferred -** unsigned old_underflow; -** // save underflow here when reusing the command for error handling -** -** unsigned transfersize; -** // How much we are guaranteed to transfer with each SCSI transfer -** // (ie,between disconnect/reconnects. Probably==sector size -** int resid; -** // Number of bytes requested to be transferred -** // less actual number transferred (0 if not supported) -** struct request request; -** // A copy of the command we are working on -** unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; -** // obtained by REQUEST SENSE when CHECK CONDITION is received on original command (auto-sense) -** unsigned flags; -** // Used to indicate that a command which has timed out also -** // completed normally. Typically the completion function will -** // do nothing but set this flag in this instance because the -** // timeout handler is already running. -** unsigned done_late:1; -** // Low-level done function - can be used by low-level driver to point -** // to completion function. Not used by mid/upper level code. -** void (*scsi_done) (struct scsi_cmnd *); -** // The following fields can be written to by the host specific code. -** // Everything else should be left alone. -** Scsi_Pointer SCp; -** // Scratchpad used by some host adapters -** unsigned char *host_scribble; -** // The host adapter is allowed to -** // call scsi_malloc and get some memory -** // and hang it here. The host adapter -** // is also expected to call scsi_free -** // to release this memory. (The memory -** // obtained by scsi_malloc is guaranteed -** // to be at an address < 16Mb). -** int result; -** // Status code from lower level driver -** unsigned char tag; -** // SCSI-II queued command tag -** unsigned long pid; -** // Process ID,starts at 0 -** }; -** -** The scsi_cmnd structure is used by scsi.c internally, -** and for communication -** with low level drivers that support multiple outstanding commands. -** -**typedef struct scsi_pointer -**{ -** char * ptr; // data pointer -** int this_residual; // left in this buffer -** struct scatterlist *buffer; // which buffer -** int buffers_residual; // how many buffers left -** -** volatile int Status; -** volatile int Message; -** volatile int have_data_in; -** volatile int sent_command; -** volatile int phase; -**} Scsi_Pointer; *********************************************************************** */ static int arcmsr_queue_command(struct scsi_cmnd *cmd, @@ -1855,7 +1603,7 @@ static int arcmsr_queue_command(struct s return (0); } if (pACB->acb_flags & ACB_F_BUS_RESET) { - printk("arcmsr%d bus reset and return busy \n", + printk("arcmsr%d: bus reset and return busy \n", pACB->adapter_index); cmd->result = (DID_BUS_BUSY << 16); cmd->scsi_done(cmd); @@ -1867,60 +1615,49 @@ static int arcmsr_queue_command(struct s block_cmd = cmd->cmnd[0] & 0x0f; if (block_cmd == 0x08 || block_cmd == 0x0a) { printk - ("arcmsr%d block 'read/write' command with gone raid volume Cmd=%2x,TargetId=%d,Lun=%d \n", + ("arcmsr%d: block 'read/write' command with gone raid volume Cmd=%2x,TargetId=%d,Lun=%d \n", pACB->adapter_index, cmd->cmnd[0], target, lun); cmd->result = (DID_NO_CONNECT << 16); cmd->scsi_done(cmd); return (0); } } + arcmsr_post_pendingccb(pACB); if ((pCCB = arcmsr_get_freeccb(pACB)) != NULL) { arcmsr_build_ccb(pACB, pCCB, cmd); if (atomic_read(&pACB->ccboutstandingcount) < ARCMSR_MAX_OUTSTANDING_CMD) { - /* - ****************************************************************** - ** and we can make sure there were no pending ccb in this duration - ****************************************************************** - */ arcmsr_post_ccb(pACB, pCCB); - } else { - /* - ****************************************************************** - ** Q of ccbwaitexec will be post out when any outstanding command complete - ****************************************************************** - */ - arcmsr_queue_wait2go_ccb(pACB, pCCB); + return (0); } - } else { - printk - ("arcmsr%d 'out of ccbs resource' ccb outstanding=%d pending=%d \n", - pACB->adapter_index, - atomic_read(&pACB->ccboutstandingcount), - atomic_read(&pACB->ccbwait2gocount)); - cmd->result = (DID_BUS_BUSY << 16); - cmd->scsi_done(cmd); + arcmsr_queue_pendingccb(pACB, pCCB); + return (0); } + printk + ("arcmsr%d: 'out of ccbs resource' ccb outstanding=%d pending=%d \n", + pACB->adapter_index, atomic_read(&pACB->ccboutstandingcount), + atomic_read(&pACB->ccbpendingcount)); + cmd->result = (DID_BUS_BUSY << 16); + cmd->scsi_done(cmd); return (0); } /* ********************************************************************** -** get firmware miscellaneous data ********************************************************************** */ static void arcmsr_get_firmware_spec(struct _ACB *pACB) { char *acb_firm_model = pACB->firm_model; char *acb_firm_version = pACB->firm_version; - char *iop_firm_model = (char *)(&pACB->pmu->message_rbuffer[15]); /*firm_model,15,60-67 */ - char *iop_firm_version = (char *)(&pACB->pmu->message_rbuffer[17]); /*firm_version,17,68-83 */ + char *iop_firm_model = (char *)(&pACB->pmu->message_rwbuffer[15]); /*firm_model,15,60-67 */ + char *iop_firm_version = (char *)(&pACB->pmu->message_rwbuffer[17]); /*firm_version,17,68-83 */ int count; writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &pACB->pmu->inbound_msgaddr0); if (arcmsr_wait_msgint_ready(pACB)) { printk - ("arcmsr%d wait 'get adapter firmware miscellaneous data' timeout \n", + ("arcmsr%d: wait 'get adapter firmware miscellaneous data' timeout \n", pACB->adapter_index); } count = 8; @@ -1939,31 +1676,26 @@ static void arcmsr_get_firmware_spec(str } printk("ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", pACB->adapter_index, pACB->firm_version); - if (strncmp(pACB->firm_version, "V1.37", 5) < 0) { - printk - ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); - printk - ("!!!!!! PLEASE UPDATE RAID FIRMWARE VERSION EQUAL OR MORE THAN 'V1.37' !!!!!!\n"); - printk - ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); - } - pACB->firm_request_len = readl(&pACB->pmu->message_rbuffer[1]); /*firm_request_len,1,04-07 */ - pACB->firm_numbers_queue = readl(&pACB->pmu->message_rbuffer[2]); /*firm_numbers_queue,2,08-11 */ - pACB->firm_sdram_size = readl(&pACB->pmu->message_rbuffer[3]); /*firm_sdram_size,3,12-15 */ - pACB->firm_ide_channels = readl(&pACB->pmu->message_rbuffer[4]); /*firm_ide_channels,4,16-19 */ + pACB->firm_request_len = readl(&pACB->pmu->message_rwbuffer[1]); /*firm_request_len,1,04-07 */ + pACB->firm_numbers_queue = readl(&pACB->pmu->message_rwbuffer[2]); /*firm_numbers_queue,2,08-11 */ + pACB->firm_sdram_size = readl(&pACB->pmu->message_rwbuffer[3]); /*firm_sdram_size,3,12-15 */ + pACB->firm_ide_channels = readl(&pACB->pmu->message_rwbuffer[4]); /*firm_ide_channels,4,16-19 */ return; } /* ********************************************************************** -** start background rebulid ********************************************************************** */ static void arcmsr_start_adapter_bgrb(struct _ACB *pACB) { pACB->acb_flags |= ACB_F_MSG_START_BGRB; - pACB->acb_flags &= ~ACB_F_MSG_STOP_BGRB; writel(ARCMSR_INBOUND_MESG0_START_BGRB, &pACB->pmu->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) { + printk + ("arcmsr%d: wait 'start adapter background rebulid' timeout \n", + pACB->adapter_index); + } return; } @@ -1996,24 +1728,23 @@ static void arcmsr_polling_ccbdone(struc goto polling_ccb_retry; } } - /* check ifcommand done with no error */ pCCB = (struct _CCB *)(pACB->vir2phy_offset + (flag_ccb << 5)); /*frame must be 32 bytes aligned */ if ((pCCB->pACB != pACB) || (pCCB->startdone != ARCMSR_CCB_START)) { if ((pCCB->startdone == ARCMSR_CCB_ABORTED) && (pCCB == poll_ccb)) { printk - ("arcmsr%d scsi id=%d lun=%d ccb='0x%p' poll command abort successfully \n", + ("arcmsr%d: scsi id=%d lun=%d ccb='0x%p' poll command abort successfully \n", pACB->adapter_index, pCCB->pcmd->device->id, pCCB->pcmd->device->lun, pCCB); pCCB->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); poll_ccb_done = 1; continue; } printk - ("arcmsr%d polling and getting an illegal ccb command done ccb='0x%p' ccboutstandingcount=%d \n", + ("arcmsr%d: polling get an illegal ccb command done ccb='0x%p' ccboutstandingcount=%d \n", pACB->adapter_index, pCCB, atomic_read(&pACB->ccboutstandingcount)); continue; @@ -2025,7 +1756,7 @@ static void arcmsr_polling_ccbdone(struc pACB->devstate[id][lun] = ARECA_RAID_GOOD; } pCCB->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } else { switch (pCCB->arcmsr_cdb.DeviceStatus) { case ARCMSR_DEV_SELECT_TIMEOUT: @@ -2033,7 +1764,7 @@ static void arcmsr_polling_ccbdone(struc pACB->devstate[id][lun] = ARECA_RAID_GONE; pCCB->pcmd->result = DID_TIME_OUT << 16; - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } break; case ARCMSR_DEV_ABORTED: @@ -2043,7 +1774,7 @@ static void arcmsr_polling_ccbdone(struc ARECA_RAID_GONE; pCCB->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } break; case SCSISTAT_CHECK_CONDITION: @@ -2051,28 +1782,26 @@ static void arcmsr_polling_ccbdone(struc pACB->devstate[id][lun] = ARECA_RAID_GOOD; arcmsr_report_sense_info(pCCB); - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); } break; default: - /* error occur Q all error ccb to errorccbpending Q */ printk - ("arcmsr%d scsi id=%d lun=%d polling and getting command error done, but got unknow DeviceStatus=0x%x \n", + ("arcmsr%d: scsi id=%d lun=%d polling and getting command error done, but got unknow DeviceStatus=0x%x \n", pACB->adapter_index, id, lun, pCCB->arcmsr_cdb.DeviceStatus); pACB->devstate[id][lun] = ARECA_RAID_GONE; pCCB->pcmd->result = DID_BAD_TARGET << 16; /*unknow error or crc error just for retry */ - arcmsr_ccb_complete(pCCB); + arcmsr_ccb_complete(pCCB, 1); break; } } - } /*drain reply FIFO */ + } return; } /* ********************************************************************** -** start background rebulid ********************************************************************** */ static void arcmsr_iop_init(struct _ACB *pACB) @@ -2082,27 +1811,18 @@ static void arcmsr_iop_init(struct _ACB do { firmware_state = readl(&pACB->pmu->outbound_msgaddr1); } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0); - intmask_org = readl(&pACB->pmu->outbound_intmask); /*change "disable iop interrupt" to arcmsr_initialize */ + intmask_org = + readl(&pACB->pmu-> + outbound_intmask) | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; arcmsr_get_firmware_spec(pACB); - /*start background rebuild */ arcmsr_start_adapter_bgrb(pACB); - if (arcmsr_wait_msgint_ready(pACB)) { - printk - ("arcmsr%d wait 'start adapter background rebulid' timeout \n", - pACB->adapter_index); - } - /* clear Qbuffer if door bell ringed */ outbound_doorbell = readl(&pACB->pmu->outbound_doorbell); - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { - writel(outbound_doorbell, &pACB->pmu->outbound_doorbell); /*clear interrupt */ - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - &pACB->pmu->inbound_doorbell); - } - /* enable outbound Post Queue,outbound message0,outbell doorbell Interrupt */ + writel(outbound_doorbell, &pACB->pmu->outbound_doorbell); /*clear interrupt */ + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, + &pACB->pmu->inbound_doorbell); mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); + ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); writel(intmask_org & mask, &pACB->pmu->outbound_intmask); pACB->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; pACB->acb_flags |= ACB_F_IOP_INITED; @@ -2119,31 +1839,29 @@ static int arcmsr_bus_reset(struct scsi_ int retry = 0; pACB = (struct _ACB *)cmd->device->host->hostdata; - printk("arcmsr%d bus reset ..... \n", pACB->adapter_index); + printk("arcmsr%d: bus reset ..... \n", pACB->adapter_index); pACB->num_resets++; pACB->acb_flags |= ACB_F_BUS_RESET; while (atomic_read(&pACB->ccboutstandingcount) != 0 && retry < 400) { - printk - ("arcmsr%d bus reset wait ccb outstanding command count equal to zero \n", - pACB->adapter_index); - msleep_interruptible(25); + arcmsr_interrupt(pACB); + msleep(25); retry++; } arcmsr_iop_reset(pACB); pACB->acb_flags &= ~ACB_F_BUS_RESET; - return SUCCESS; + return (SUCCESS); } /* ***************************************************************************************** ***************************************************************************************** */ -static int arcmsr_seek_cmd2abort(struct scsi_cmnd *pabortcmd) +static int arcmsr_seek_cmd2abort(struct scsi_cmnd *abortcmd) { - struct _ACB *pACB = (struct _ACB *)pabortcmd->device->host->hostdata; + struct _ACB *pACB = (struct _ACB *)abortcmd->device->host->hostdata; struct _CCB *pCCB; uint32_t intmask_org, mask; - int i = 0; + int i = 0, pendingcount; pACB->num_aborts++; /* @@ -2159,13 +1877,13 @@ static int arcmsr_seek_cmd2abort(struct for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { pCCB = pACB->pccb_pool[i]; if (pCCB->startdone == ARCMSR_CCB_START) { - if (pCCB->pcmd == pabortcmd) { + if (pCCB->pcmd == abortcmd) { pCCB->startdone = ARCMSR_CCB_ABORTED; printk - ("arcmsr%d scsi id=%d lun=%d abort ccb '0x%p' outstanding command \n", + ("arcmsr%d: scsi id=%d lun=%d abort ccb '0x%p' outstanding command \n", pACB->adapter_index, - pabortcmd->device->id, - pabortcmd->device->lun, pCCB); + abortcmd->device->id, + abortcmd->device->lun, pCCB); goto abort_outstanding_cmd; } } @@ -2177,41 +1895,40 @@ static int arcmsr_seek_cmd2abort(struct ** if command found then remove,abort it and free this CCB ********************************************************** */ - if (atomic_read(&pACB->ccbwait2gocount) != 0) { - for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) { - pCCB = pACB->pccbwait2go[i]; - if (pCCB != NULL) { - if (pCCB->pcmd == pabortcmd) { - printk - ("arcmsr%d scsi id=%d lun=%d abort ccb '0x%p' pending command \n", - pACB->adapter_index, - pabortcmd->device->id, - pabortcmd->device->lun, pCCB); - pACB->pccbwait2go[i] = NULL; - pCCB->startdone = ARCMSR_CCB_ABORTED; - pCCB->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); - atomic_dec(&pACB->ccbwait2gocount); - return (SUCCESS); - } + pendingcount = atomic_read(&pACB->ccbpendingcount); + if (pendingcount > 0) { + do { + pCCB = arcmsr_get_pendingccb(pACB); + if (pCCB == NULL) { + break; } - } + if (pCCB->pcmd == abortcmd) { + printk + ("arcmsr%d: scsi id=%d lun=%d abort ccb '0x%p' pending command \n", + pACB->adapter_index, abortcmd->device->id, + abortcmd->device->lun, pCCB); + pCCB->startdone = ARCMSR_CCB_ABORTED; + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 0); + return (SUCCESS); + } else { + arcmsr_queue_pendingccb(pACB, pCCB); + } + } while (pendingcount--); } return (SUCCESS); abort_outstanding_cmd: + msleep_interruptible(3000); /*wait for 3 sec for all command done */ /* disable all outbound interrupt */ intmask_org = readl(&pACB->pmu->outbound_intmask); writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, &pACB->pmu->outbound_intmask); - /* do not talk to iop 331 abort command */ arcmsr_polling_ccbdone(pACB, pCCB); /* enable all outbound interrupt */ mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); + ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); writel(intmask_org & mask, &pACB->pmu->outbound_intmask); - atomic_set(&pACB->ccboutstandingcount, 0); return (SUCCESS); } @@ -2224,7 +1941,7 @@ static int arcmsr_cmd_abort(struct scsi_ struct _ACB *pACB = (struct _ACB *)cmd->device->host->hostdata; int error; - printk("arcmsr%d abort device command of scsi id=%d lun=%d \n", + printk("arcmsr%d: abort device command of scsi id=%d lun=%d \n", pACB->adapter_index, cmd->device->id, cmd->device->lun); /* ************************************************ @@ -2234,7 +1951,7 @@ static int arcmsr_cmd_abort(struct scsi_ */ error = arcmsr_seek_cmd2abort(cmd); if (error != SUCCESS) { - printk("arcmsr%d abort command failed scsi id=%d lun=%d \n", + printk("arcmsr%d: abort command failed scsi id=%d lun=%d \n", pACB->adapter_index, cmd->device->id, cmd->device->lun); } return (error); @@ -2242,52 +1959,6 @@ static int arcmsr_cmd_abort(struct scsi_ /* ********************************************************************* -** arcmsr_info() -**struct pci_dev { -** struct list_head global_list; ## node in list of all PCI devices ## -** struct list_head bus_list; ## node in per-bus list ## -** struct pci_bus *bus; ## bus this device is on ## -** struct pci_bus *subordinate; ## bus this device bridges to ## -** void *sysdata; ## hook for sys-specific extension ## -** struct proc_dir_entry *procent; ## device entry in /proc/bus/pci ## -** unsigned int devfn; ## encoded device & function index ## -** unsigned short vendor; -** unsigned short device; -** unsigned short subsystem_vendor; -** unsigned short subsystem_device; -** unsigned int class; ## 3 bytes: (base,sub,prog-if) ## -** u8 hdr_type; ## PCI header type (`multi' flag masked out) ## -** u8 rom_base_reg; ## which config register controls the ROM ## -** -** struct pci_driver *driver; ## which driver has allocated this device ## -** void *driver_data; ## data private to the driver ## -** u64 dma_mask; ## Mask of the bits of bus address this device implements. Normally this is -** ## 0xffffffff. You only need to change this if your device has broken DMA -** ## or supports 64-bit transfers. -** u32 current_state; ## Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional, and D3 being off. ## -** unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE]; ## device is compatible with these IDs ## -** unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE]; -** ## -** ##Instead of touching interrupt line and base address registers -** ##directly, use the values stored here. They might be different! -** ## -** unsigned int irq; -** struct resource resource[DEVICE_COUNT_RESOURCE]; ## I/O and memory regions + expansion ROMs ## -** struct resource dma_resource[DEVICE_COUNT_DMA]; -** struct resource irq_resource[DEVICE_COUNT_IRQ]; -** char name[90]; ## device name ## -** char slot_name[8]; ## slot name ## -** u32 saved_state[16]; ## for saving the config space before suspend ## -** int active; ## ISAPnP: device is active ## -** int ro; ## ISAPnP: read only ## -** unsigned short regs; ## ISAPnP: supported registers ## -** ## These fields are used by common fixups ## -** unsigned short transparent:1; ## Transparent PCI bridge ## -** int (*prepare)(struct pci_dev *dev); ## ISAPnP hooks ## -** int (*activate)(struct pci_dev *dev); -** int (*deactivate)(struct pci_dev *dev); -**}; -** ********************************************************************* */ static const char *arcmsr_info(struct Scsi_Host *host) @@ -2369,6 +2040,13 @@ static const char *arcmsr_info(struct Sc ARCMSR_DRIVER_VERSION); break; } + default: + { + sprintf(buf, + "ARECA SATA RAID CONTROLLER (RAID6-ENGINE Inside)\n %s", + ARCMSR_DRIVER_VERSION); + break; + } } return buf; } @@ -2379,7 +2057,7 @@ static const char *arcmsr_info(struct Sc */ static int arcmsr_initialize(struct _ACB *pACB, struct pci_dev *pPCI_DEV) { - uint32_t intmask_org, page_base, page_offset, mem_base_start; + uint32_t intmask_org, ccb_phyaddr_hi32; dma_addr_t dma_coherent_handle, dma_addr; struct _HCBARC *pHCBARC = &arcmsr_host_control_block; uint8_t pcicmd; @@ -2388,66 +2066,32 @@ static int arcmsr_initialize(struct _ACB int i, j; struct _CCB *pccb_tmp; - /* Enable Busmaster/Mem */ pci_read_config_byte(pPCI_DEV, PCI_COMMAND, &pcicmd); pci_write_config_byte(pPCI_DEV, PCI_COMMAND, pcicmd | PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); - mem_base_start = (uint32_t) pci_resource_start(pPCI_DEV, 0); - page_base = mem_base_start & PAGE_MASK; - page_offset = mem_base_start - page_base; - page_remapped = ioremap(page_base, page_offset + 0x1FFF); + page_remapped = + ioremap(pci_resource_start(pPCI_DEV, 0), + pci_resource_len(pPCI_DEV, 0)); if (page_remapped == NULL) { - printk("arcmsr%d memory mapping region fail \n", + printk("arcmsr%d: memory mapping region fail \n", arcmsr_adapterCnt); return (ENXIO); } - pACB->pmu = (struct _MU *)(page_remapped + page_offset); + pACB->pmu = (struct _MU *)(page_remapped); pACB->acb_flags |= - (ACB_F_IOCTL_WQBUFFER_CLEARED | ACB_F_IOCTL_RQBUFFER_CLEARED); + (ACB_F_IOCTL_WQBUFFER_CLEARED | ACB_F_IOCTL_RQBUFFER_CLEARED | + ACB_F_IOCTL_WQBUFFER_READED); pACB->acb_flags &= ~ACB_F_SCSISTOPADAPTER; pACB->irq = pPCI_DEV->irq; - /* - ******************************************************************************* - ** Allocate the PCCB memory - ****************************************************** - ** Using large dma-coherent buffers - ** ------------------------------------------ - ** void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag) - ** void *pci_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_handle) - ** Consistent memory is memory for which a write by either the device or - ** the processor can immediately be read by the processor or device - ** without having to worry about caching effects. - ** This routine allocates a region of bytes of consistent memory. - ** it also returns a which may be cast to an unsigned - ** integer the same width as the bus and used as the physical address - ** base of the region. - ** Returns: a pointer to the allocated region (in the processor's virtual - ** address space) or NULL if the allocation failed. - ** Note: consistent memory can be expensive on some platforms, and the - ** minimum allocation length may be as big as a page, so you should - ** consolidate your requests for consistent memory as much as possible. - ** The simplest way to do that is to use the dma_pool calls (see below). - ** The flag parameter (dma_alloc_coherent only) allows the caller to - ** specify the GFP_ flags (see kmalloc) for the allocation (the - ** implementation may chose to ignore flags that affect the location of - ** the returned memory, like GFP_DMA). For pci_alloc_consistent, you - ** must assume GFP_ATOMIC behaviour. - ** void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr dma_addr_t dma_handle) - ** void pci_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr dma_addr_t dma_handle) - ** Free the region of consistent memory you previously allocated. dev, - ** size and dma_handle must all be the same as those passed into the - ** consistent allocate. cpu_addr must be the virtual address returned by - ** the consistent allocate - ****************************************************************************** - */ - /* Attempt to claim larger area for request queue pCCB). */ + INIT_LIST_HEAD(&pACB->ccb_free_list); + INIT_LIST_HEAD(&pACB->ccb_pending_list); dma_coherent = dma_alloc_coherent(&pPCI_DEV->dev, ARCMSR_MAX_FREECCB_NUM * sizeof(struct _CCB) + 0x20, &dma_coherent_handle, GFP_KERNEL); if (dma_coherent == NULL) { - printk("arcmsr%d dma_alloc_coherent got error \n", + printk("arcmsr%d: dma_alloc_coherent got error \n", arcmsr_adapterCnt); return -ENOMEM; } @@ -2469,17 +2113,13 @@ static int arcmsr_initialize(struct _ACB for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { pccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; pccb_tmp->pACB = pACB; - pACB->pccbringQ[i] = pACB->pccb_pool[i] = pccb_tmp; + pACB->pccb_pool[i] = pccb_tmp; + list_add_tail(&pccb_tmp->list, &pACB->ccb_free_list); dma_addr = dma_addr + sizeof(struct _CCB); pccb_tmp++; } pACB->vir2phy_offset = (unsigned long)pccb_tmp - (unsigned long)dma_addr; - /* - ******************************************************************** - ** init raid volume state - ******************************************************************** - */ for (i = 0; i < ARCMSR_MAX_TARGETID; i++) { for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) { pACB->devstate[i][j] = ARECA_RAID_GOOD; @@ -2491,9 +2131,21 @@ static int arcmsr_initialize(struct _ACB ** if pccb_tmp.HighPart is not zero ******************************************************************** */ + ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16); + if (ccb_phyaddr_hi32 != 0) { + writel(ARCMSR_SIGNATURE_SET_CONFIG, + &pACB->pmu->message_rwbuffer[0]); + writel(ccb_phyaddr_hi32, &pACB->pmu->message_rwbuffer[1]); + writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, + &pACB->pmu->inbound_msgaddr0); + if (arcmsr_wait_msgint_ready(pACB)) { + printk + ("arcmsr%d: 'set ccb high part physical address' timeout \n", + arcmsr_adapterCnt); + } + } pACB->adapter_index = arcmsr_adapterCnt; pHCBARC->pACB[arcmsr_adapterCnt] = pACB; - /* disable iop all outbound interrupt */ intmask_org = readl(&pACB->pmu->outbound_intmask); writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, &pACB->pmu->outbound_intmask); @@ -2516,79 +2168,72 @@ static int arcmsr_set_info(char *buffer, */ static void arcmsr_pcidev_disattach(struct _ACB *pACB) { + struct pci_dev *pPCI_DEV; struct _CCB *pCCB; struct _HCBARC *pHCBARC = &arcmsr_host_control_block; - uint32_t intmask_org, mask; - int i = 0; + struct Scsi_Host *host; + uint32_t intmask_org; + int i = 0, poll_count = 0, have_msi = 0; - /* disable all outbound interrupt */ + arcmsr_stop_adapter_bgrb(pACB); + arcmsr_flush_adapter_cache(pACB); intmask_org = readl(&pACB->pmu->outbound_intmask); writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, &pACB->pmu->outbound_intmask); - /* stop adapter background rebuild */ - arcmsr_stop_adapter_bgrb(pACB); - if (arcmsr_wait_msgint_ready(pACB)) { - printk - ("arcmsr%d pcidev disattach wait 'stop adapter rebulid' timeout \n", - pACB->adapter_index); - } - arcmsr_flush_adapter_cache(pACB); - if (arcmsr_wait_msgint_ready(pACB)) { - printk - ("arcmsr%d pcidev disattach wait 'flush adapter cache' timeout \n", - pACB->adapter_index); - } - /* abort all outstanding command */ pACB->acb_flags |= ACB_F_SCSISTOPADAPTER; pACB->acb_flags &= ~ACB_F_IOP_INITED; if (atomic_read(&pACB->ccboutstandingcount) != 0) { - /* disable all outbound interrupt */ - intmask_org = readl(&pACB->pmu->outbound_intmask); - writel(intmask_org | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, - &pACB->pmu->outbound_intmask); - /* talk to iop 331 outstanding command aborted */ - arcmsr_abort_allcmd(pACB); - if (arcmsr_wait_msgint_ready(pACB)) { - printk - ("arcmsr%d pcidev disattach wait 'abort all outstanding command' timeout \n", - pACB->adapter_index); - } - /*clear all outbound posted Q */ - for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) { - readl(&pACB->pmu->outbound_queueport); - } - for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - pCCB = pACB->pccb_pool[i]; - if (pCCB->startdone == ARCMSR_CCB_START) { - pCCB->startdone = ARCMSR_CCB_ABORTED; + while (atomic_read(&pACB->ccboutstandingcount) != 0 + && (poll_count < 256)) { + arcmsr_interrupt(pACB); + msleep(25); + poll_count++; + } + if (atomic_read(&pACB->ccboutstandingcount) != 0) { + arcmsr_abort_allcmd(pACB); + for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) { + readl(&pACB->pmu->outbound_queueport); + } + for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + pCCB = pACB->pccb_pool[i]; + if (pCCB->startdone == ARCMSR_CCB_START) { + pCCB->startdone = ARCMSR_CCB_ABORTED; + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 1); + } } } - /* enable all outbound interrupt */ - mask = - ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); - writel(intmask_org & mask, &pACB->pmu->outbound_intmask); - atomic_set(&pACB->ccboutstandingcount, 0); } - if (atomic_read(&pACB->ccbwait2gocount) != 0) { /*remove first wait2go ccb and abort it */ - for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) { - pCCB = pACB->pccbwait2go[i]; - if (pCCB != NULL) { - pACB->pccbwait2go[i] = NULL; - pCCB->startdone = ARCMSR_CCB_ABORTED; - pCCB->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); - atomic_dec(&pACB->ccbwait2gocount); - } + while (atomic_read(&pACB->ccbpendingcount) != 0) { + pCCB = arcmsr_get_pendingccb(pACB); + if (pCCB != NULL) { + pCCB->startdone = ARCMSR_CCB_ABORTED; + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB, 0); + atomic_dec(&pACB->ccbpendingcount); + } else { + break; } } - free_irq(pACB->pPCI_DEV->irq, pACB); - pci_release_regions(pACB->pPCI_DEV); + if ((pACB->acb_flags & ACB_F_HAVE_MSI) != 0) { + have_msi = 1; + } + host = pACB->host; + pPCI_DEV = pACB->pPCI_DEV; iounmap(pACB->pmu); arcmsr_free_ccb_pool(pACB); - pHCBARC->pACB[pACB->adapter_index] = 0; /* clear record */ - arcmsr_adapterCnt--; + pHCBARC->pACB[pACB->adapter_index] = NULL; + scsi_remove_host(host); + scsi_host_put(host); + free_irq(pPCI_DEV->irq, pACB); +#ifdef CONFIG_PCI_MSI + if (have_msi == 1) { + pci_disable_msi(pPCI_DEV); + } +#endif + pci_release_regions(pPCI_DEV); + pci_disable_device(pPCI_DEV); + pci_set_drvdata(pPCI_DEV, NULL); return; } @@ -2601,7 +2246,6 @@ static int arcmsr_halt_notify(struct not { struct _ACB *pACB; struct _HCBARC *pHCBARC = &arcmsr_host_control_block; - struct Scsi_Host *host; int i; if ((event != SYS_RESTART) && (event != SYS_HALT) @@ -2613,13 +2257,7 @@ static int arcmsr_halt_notify(struct not if (pACB == NULL) { continue; } - /* Flush cache to disk */ - /* Free irq,otherwise extra interrupt is generated */ - /* Issue a blocking(interrupts disabled) command to the card */ - host = pACB->host; arcmsr_pcidev_disattach(pACB); - scsi_remove_host(host); - scsi_host_put(host); } unregister_chrdev(pHCBARC->arcmsr_major_number, "arcmsr"); unregister_reboot_notifier(&arcmsr_event_notifier); @@ -2691,15 +2329,10 @@ static int arcmsr_release(struct Scsi_Ho if (match == 0xff) { return -ENXIO; } - /* Flush cache to disk */ - /* Free irq,otherwise extra interrupt is generated */ - /* Issue a blocking(interrupts disabled) command to the card */ arcmsr_pcidev_disattach(pACB); - scsi_unregister(host); - /*if this is last pACB */ for (i = 0; i < ARCMSR_MAX_ADAPTER; i++) { if (pHCBARC->pACB[i] != NULL) { - return (0); /* this is not last adapter's release */ + return (0); } } unregister_chrdev(pHCBARC->arcmsr_major_number, "arcmsr"); diff -puN drivers/scsi/arcmsr/arcmsr.h~areca-raid-linux-scsi-driver-updates drivers/scsi/arcmsr/arcmsr.h --- devel/drivers/scsi/arcmsr/arcmsr.h~areca-raid-linux-scsi-driver-updates 2006-01-03 23:21:16.000000000 -0800 +++ devel-akpm/drivers/scsi/arcmsr/arcmsr.h 2006-01-03 23:21:16.000000000 -0800 @@ -46,27 +46,24 @@ #include /* ********************************************************************************** -** ********************************************************************************** */ #define ARCMSR_MAX_OUTSTANDING_CMD 256 +#define ARCMSR_MAX_PENDING_CMD 64 #define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.12" -#define ARCMSR_SCSI_INITIATOR_ID 16 +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.13" +#define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_DEV_SECTOR_SIZE 512 #define ARCMSR_MAX_XFER_SECTORS 256 -#define ARCMSR_MAX_XFER_LEN ARCMSR_MAX_XFER_SECTORS * ARCMSR_DEV_SECTOR_SIZE /*128k */ -#define ARCMSR_MAX_TARGETID 16 /*16 max target id + 1 */ -#define ARCMSR_MAX_TARGETLUN 8 /*8 */ -#define ARCMSR_MAX_CHIPTYPE_NUM 4 -#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD /* if eq. 256 will get kernel panic at 2.2.x */ -#define ARCMSR_MAX_DPC 16 /* defer procedure call */ +#define ARCMSR_MAX_XFER_LEN ARCMSR_MAX_XFER_SECTORS * ARCMSR_DEV_SECTOR_SIZE /* 128k */ +#define ARCMSR_MAX_TARGETID 16 /* 16 max target id + 1 */ +#define ARCMSR_MAX_TARGETLUN 8 /* 8 */ +#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_FREECCB_NUM #define ARCMSR_MAX_QBUFFER 4096 /* ioctl QBUFFER */ #define ARCMSR_MAX_SG_ENTRIES 38 /* max 38 */ #define ARCMSR_MAX_ADAPTER 4 /* ********************************************************************************** -** ********************************************************************************** */ #define PCIVendorIDARECA 0x17D3 /* Vendor ID */ @@ -82,7 +79,6 @@ #define PCIDeviceIDARC1270 0x1270 /* Device ID */ /* ********************************************************************************** -**((unsigned long)addr & 0xffff) ********************************************************************************** */ #define dma_addr_hi32(addr) (uint32_t) ((addr>>16)>>16) @@ -107,14 +103,13 @@ typedef struct _CMD_IO_CONTROL { } CMD_IO_CONTROL, *PCMD_IO_CONTROL; /* ************************************************************************************************************ -** ************************************************************************************************************ */ typedef struct _CMD_IOCTL_FIELD { CMD_IO_CONTROL cmdioctl; /*ioctl header */ uint8_t ioctldatabuffer[1032]; /*areca gui program does not accept more than 1031 byte */ } CMD_IOCTL_FIELD, *PCMD_IOCTL_FIELD; -/*error code for StorPortLogError,ScsiPortLogError*/ + #define ARCMSR_IOP_ERROR_ILLEGALPCI 0x0001 #define ARCMSR_IOP_ERROR_VENDORID 0x0002 #define ARCMSR_IOP_ERROR_DEVICEID 0x0002 @@ -175,7 +170,6 @@ typedef struct _SGENTRY_UNION { } SGENTRY_UNION, PSGENTRY_UNION; /* ********************************** -** ********************************** */ typedef struct _QBUFFER { @@ -213,8 +207,8 @@ typedef struct _FIRMWARE_INFO { ** 3. Index Memory Usage ** offset 0xf00 : for RS232 out (request buffer) ** offset 0xe00 : for RS232 in (scratch buffer) -** offset 0x800 : for inbound message code message_wbuffer (driver send to IOP331) -** offset 0xa00 : for outbound message code message_rbuffer (IOP331 send to driver) +** offset 0xa00 : for inbound message code message_rwbuffer (driver send to IOP331) +** offset 0xa00 : for outbound message code message_rwbuffer (IOP331 send to driver) ** 4. RS-232 emulation ** Currently 128 byte buffer is used ** 1st uint32_t : Data length (1--124) @@ -253,7 +247,7 @@ typedef struct _FIRMWARE_INFO { ** 8. Message1 Out - Diag Status Code (????) ** 9. Message0 message code : ** 0x00 : NOP -** 0x01 : Get Config ->offset 0xa00 :for outbound message code message_rbuffer (IOP331 send to driver) +** 0x01 : Get Config ->offset 0xa00 :for outbound message code message_rwbuffer (IOP331 send to driver) ** Signature 0x87974060(4) ** Request len 0x00000200(4) ** numbers of queue 0x00000100(4) @@ -265,7 +259,7 @@ typedef struct _FIRMWARE_INFO { ** Device Map 16 bytes char ** ** FirmwareVersion DWORD <== Added for checking of new firmware capability -** 0x02 : Set Config ->offset 0x800 : for inbound message code message_wbuffer (driver send to IOP331) +** 0x02 : Set Config ->offset 0xa00 :for inbound message code message_rwbuffer (driver send to IOP331) ** Signature 0x87974063(4) ** UPPER32 of Request Frame (4)-->Driver Only ** 0x03 : Reset (Abort all queued Command) @@ -273,7 +267,7 @@ typedef struct _FIRMWARE_INFO { ** 0x05 : Flush Cache ** 0x06 : Start Background Activity (re-start if background is halted) ** 0x07 : Check If Host Command Pending (Novell May Need This Function) -** 0x08 : Set controller time ->offset 0xa00 : for inbound message code message_wbuffer (driver to IOP331) +** 0x08 : Set controller time ->offset 0xa00 : for inbound message code message_rwbuffer (driver to IOP331) ** byte 0 : 0xaa <-- signature ** byte 1 : 0x55 <-- signature ** byte 2 : year (04) @@ -284,6 +278,9 @@ typedef struct _FIRMWARE_INFO { ** byte 7 : second (0..59) ************************************************************************************************ */ +/* signature of set and get firmware config */ +#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 +#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063 /* message code of inbound message register */ #define ARCMSR_INBOUND_MESG0_NOP 0x00000000 #define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001 @@ -332,13 +329,8 @@ typedef struct _ARCMSR_CDB { uint32_t DataLength; /* 0ch not used now */ uint8_t Cdb[16]; /* 10h SCSI CDB */ - /* - ******************************************************** - **Device Status : the same from SCSI bus if error occur - ** SCSI bus status codes. - ******************************************************** - */ - uint8_t DeviceStatus; /* 20h if error */ + + uint8_t DeviceStatus; /* 20h SCSI bus status */ #define SCSISTAT_GOOD 0x00 #define SCSISTAT_CHECK_CONDITION 0x02 #define SCSISTAT_CONDITION_MET 0x04 @@ -351,7 +343,6 @@ typedef struct _ARCMSR_CDB { #define ARCMSR_DEV_SELECT_TIMEOUT 0xF0 #define ARCMSR_DEV_ABORTED 0xF1 #define ARCMSR_DEV_INIT_FAIL 0xF2 - uint8_t SenseData[15]; /* 21h output */ union { @@ -438,17 +429,16 @@ typedef struct _MU { uint32_t outbound_queueport; /*0044 0047 */ uint32_t reserved2[2]; /*0048 004F */ uint32_t reserved3[492]; /*0050 07FF ......local_buffer 492 */ - uint32_t message_wbuffer[128]; /*0800 09FF 128 */ - uint32_t message_rbuffer[256]; /*0a00 0DFF 256 */ + uint32_t reserved4[128]; /*0800 09FF 128 */ + uint32_t message_rwbuffer[256]; /*0a00 0DFF 256 */ uint32_t ioctl_wbuffer[32]; /*0E00 0E7F 32 */ - uint32_t reserved4[32]; /*0E80 0EFF 32 */ + uint32_t reserved5[32]; /*0E80 0EFF 32 */ uint32_t ioctl_rbuffer[32]; /*0F00 0F7F 32 */ - uint32_t reserved5[32]; /*0F80 0FFF 32 */ + uint32_t reserved6[32]; /*0F80 0FFF 32 */ } MU, *PMU; /* ********************************************************************* ** Adapter Control Block -** ********************************************************************* */ typedef struct _ACB { @@ -468,19 +458,19 @@ typedef struct _ACB { #define ACB_F_IOPDATA_OVERFLOW 0x0008 /* iop ioctl data rqbuffer overflow */ #define ACB_F_IOCTL_WQBUFFER_CLEARED 0x0010 /* ioctl clear wqbuffer */ #define ACB_F_IOCTL_RQBUFFER_CLEARED 0x0020 /* ioctl clear rqbuffer */ -#define ACB_F_BUS_RESET 0x0040 -#define ACB_F_IOP_INITED 0x0080 /* iop init */ +#define ACB_F_IOCTL_WQBUFFER_READED 0x0040 +#define ACB_F_BUS_RESET 0x0080 +#define ACB_F_IOP_INITED 0x0100 /* iop init */ +#define ACB_F_HAVE_MSI 0x0200 /* pci message signal interrupt */ - struct _CCB *pccbwait2go[ARCMSR_MAX_OUTSTANDING_CMD]; - atomic_t ccbwait2gocount; + struct _CCB *pccb_pool[ARCMSR_MAX_FREECCB_NUM]; /* used for memory free */ + struct list_head ccb_free_list; /* head of free ccb list */ + struct list_head ccb_pending_list; /* head of pending ccb list */ atomic_t ccboutstandingcount; + atomic_t ccbpendingcount; void *dma_coherent; /* dma_coherent used for memory free */ dma_addr_t dma_coherent_handle; /* dma_coherent_handle used for memory free */ - struct _CCB *pccb_pool[ARCMSR_MAX_FREECCB_NUM]; /* serial ccb pointer array */ - struct _CCB *pccbringQ[ARCMSR_MAX_FREECCB_NUM]; /* working ccb pointer array */ - int32_t ccb_doneindex; /* done ccb array index */ - int32_t ccb_startindex; /* start ccb array index */ uint8_t rqbuffer[ARCMSR_MAX_QBUFFER]; /* data collection buffer for read from 80331 */ int32_t rqbuf_firstindex; /* first of read buffer */ @@ -490,11 +480,11 @@ typedef struct _ACB { int32_t wqbuf_firstindex; /* first of write buffer */ int32_t wqbuf_lastindex; /* last of write buffer */ - spinlock_t isr_lockunlock; - spinlock_t wait2go_lockunlock; - spinlock_t qbuffer_lockunlock; - spinlock_t ccb_doneindex_lockunlock; - spinlock_t ccb_startindex_lockunlock; + spinlock_t qbuffer_lock; + spinlock_t pending_list_lock; + spinlock_t working_list_lock; + spinlock_t done_list_lock; + uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN]; /* id0 ..... id15,lun0...lun7 */ #define ARECA_RAID_GONE 0x55 #define ARECA_RAID_GOOD 0xaa @@ -509,9 +499,7 @@ typedef struct _ACB { } ACB, *PACB; /* HW_DEVICE_EXTENSION */ /* ********************************************************************* -** Command Control Block (SrbExtension) -** CCB must be not cross page boundary,and the order from offset 0 -** structure describing an ATA disk request +** Command Control Block ** this CCB length must be 32 bytes boundary ********************************************************************* */ @@ -519,45 +507,47 @@ typedef struct _CCB { struct _ARCMSR_CDB arcmsr_cdb; /* 0-503 (size of CDB=504): arcmsr messenger scsi command descriptor size 504 bytes */ uint32_t cdb_shifted_phyaddr; /* 504-507 */ uint32_t reserved1; /* 508-511 */ - /* ======================512+32 bytes======================== */ #if BITS_PER_LONG == 64 - struct scsi_cmnd *pcmd; /* 512-515 516-519 pointer of linux scsi command */ - struct _ACB *pACB; /* 520-523 524-527 */ + /* ======================512+64 bytes======================== */ + struct list_head list; /* 512-527 16 bytes next/prev ptrs for ccb lists */ + struct scsi_cmnd *pcmd; /* 528-535 8 bytes pointer of linux scsi command */ + struct _ACB *pACB; /* 536-543 8 bytes pointer of acb */ - uint16_t ccb_flags; /* 528-529 */ + uint16_t ccb_flags; /* 544-545 */ #define CCB_FLAG_READ 0x0000 #define CCB_FLAG_WRITE 0x0001 #define CCB_FLAG_ERROR 0x0002 #define CCB_FLAG_FLUSHCACHE 0x0004 #define CCB_FLAG_MASTER_ABORTED 0x0008 - uint16_t startdone; /* 530-531 */ + uint16_t startdone; /* 546-547 */ #define ARCMSR_CCB_DONE 0x0000 #define ARCMSR_CCB_START 0x55AA #define ARCMSR_CCB_ABORTED 0xAA55 #define ARCMSR_CCB_ILLEGAL 0xFFFF - uint32_t reserved2[3]; /* 532-535 536-539 540-543 */ + uint32_t reserved2[7]; /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */ #else - struct scsi_cmnd *pcmd; /* 512-515 pointer of linux scsi command */ - struct _ACB *pACB; /* 516-519 */ + /* ======================512+32 bytes======================== */ + struct list_head list; /* 512-519 8 bytes next/prev ptrs for ccb lists */ + struct scsi_cmnd *pcmd; /* 520-523 4 bytes pointer of linux scsi command */ + struct _ACB *pACB; /* 524-527 4 bytes pointer of acb */ - uint16_t ccb_flags; /* 520-521 */ + uint16_t ccb_flags; /* 528-529 */ #define CCB_FLAG_READ 0x0000 #define CCB_FLAG_WRITE 0x0001 #define CCB_FLAG_ERROR 0x0002 #define CCB_FLAG_FLUSHCACHE 0x0004 #define CCB_FLAG_MASTER_ABORTED 0x0008 - uint16_t startdone; /* 522-523 */ + uint16_t startdone; /* 530-531 */ #define ARCMSR_CCB_DONE 0x0000 #define ARCMSR_CCB_START 0x55AA #define ARCMSR_CCB_ABORTED 0xAA55 #define ARCMSR_CCB_ILLEGAL 0xFFFF - uint32_t reserved2[5]; /* 524-527 528-531 532-535 536-539 540-543 */ + uint32_t reserved2[3]; /* 532-535 536-539 540-543 */ #endif /* ========================================================== */ } CCB, *PCCB; /* ********************************************************************* -** ********************************************************************* */ typedef struct _HCBARC { @@ -1674,7 +1664,6 @@ typedef struct _SENSE_DATA { *********************************************************************************** */ #define ARCMSR_ATU_BIST_REG 0x0F /*byte */ - /* *************************************************************************************** ** ATU Base Registers and Associated Limit Registers @@ -3072,7 +3061,6 @@ typedef struct _SENSE_DATA { ************************************************************************** */ #define ARCMSR_PCIX_STATUS_REG 0xE4 /*dword 0xE7,0xE6,0xE5,0xE4 */ - /* ************************************************************************** ** Inbound Read Transaction diff -puN drivers/scsi/arcmsr/arcmsr.txt~areca-raid-linux-scsi-driver-updates drivers/scsi/arcmsr/arcmsr.txt --- devel/drivers/scsi/arcmsr/arcmsr.txt~areca-raid-linux-scsi-driver-updates 2006-01-03 23:21:16.000000000 -0800 +++ devel-akpm/drivers/scsi/arcmsr/arcmsr.txt 2006-01-03 23:21:16.000000000 -0800 @@ -1,50 +1,55 @@ README file for the arcmsr RAID controller SCSI driver ====================================================== -History - - REV# DATE NAME DESCRIPTION - 1.00.00.00 3/31/2004 Erich Chen First release - 1.10.00.04 7/28/2004 Erich Chen modify for ioctl - 1.10.00.06 8/28/2004 Erich Chen modify for 2.6.x - 1.10.00.08 9/28/2004 Erich Chen modify for x86_64 - 1.10.00.10 10/10/2004 Erich Chen bug fix for SMP & ioctl - 1.20.00.00 11/29/2004 Erich Chen bug fix with arcmsr_bus_reset when PHY error - 1.20.00.02 12/09/2004 Erich Chen bug fix with over 2T bytes RAID Volume - 1.20.00.04 1/09/2005 Erich Chen fits for Debian linux kernel version 2.2.xx - 1.20.00.05 2/20/2005 Erich Chen cleanly as look like a Linux driver at 2.6.x - thanks for peoples kindness comment - Kornel Wieliczek - Christoph Hellwig - Adrian Bunk - Andrew Morton - Christoph Hellwig - James Bottomley - Arjan van de Ven - 1.20.00.06 3/12/2005 Erich Chen fix with arcmsr_pci_unmap_dma "unsigned long" cast, - modify PCCB POOL allocated by "dma_alloc_coherent" - (Kornel Wieliczek's comment) - - 1.20.00.07 3/23/2005 Erich Chen bug fix with arcmsr_scsi_host_template_init ocur segmentation fault, - if RAID adapter does not on PCI slot and modprobe/rmmod this driver twice. - bug fix enormous stack usage (Adrian Bunk's comment) - 1.20.00.08 6/23/2005 Erich Chen bug fix with abort command,in case of heavy loading when sata cable - working on low quality connection - 1.20.00.09 9/12/2005 Erich Chen bug fix with abort command handling,firmware version check - and firmware update notify for hardware bug fix - 1.20.00.10 9/23/2005 Erich Chen enhance sysfs function for change driver's max tag Q number. - add DMA_64BIT_MASK for backward compatible with all 2.6.x - add some useful message for abort command - add ioctl code 'ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE' - customer can send this command for sync raid volume data - 1.20.00.11 9/29/2005 Erich Chen by comment of Arjan van de Ven fix incorrect msleep redefine - cast off sizeof(dma_addr_t) condition for 64bit pci_set_dma_mask - 1.20.00.12 9/30/2005 Erich Chen bug fix with 64bit platform's ccbs using if over 4G system memory - change 64bit pci_set_consistent_dma_mask into 32bit - increcct adapter count if adapter initialize fail. - miss edit at arcmsr_build_ccb.... - psge += sizeof(struct _SG64ENTRY *) => psge += sizeof(struct _SG64ENTRY) - 64 bits sg entry would be incorrectly calculated - thanks Kornel Wieliczek give me kindly notify and detail description +************************************************************************** +** History +** +** REV# DATE NAME DESCRIPTION +** 1.00.00.00 3/31/2004 Erich Chen First release +** 1.10.00.04 7/28/2004 Erich Chen modify for ioctl +** 1.10.00.06 8/28/2004 Erich Chen modify for 2.6.x +** 1.10.00.08 9/28/2004 Erich Chen modify for x86_64 +** 1.10.00.10 10/10/2004 Erich Chen bug fix for SMP & ioctl +** 1.20.00.00 11/29/2004 Erich Chen bug fix with arcmsr_bus_reset when PHY error +** 1.20.00.02 12/09/2004 Erich Chen bug fix with over 2T bytes RAID Volume +** 1.20.00.04 1/09/2005 Erich Chen fits for Debian linux kernel version 2.2.xx +** 1.20.00.05 2/20/2005 Erich Chen cleanly as look like a Linux driver at 2.6.x +** thanks for peoples kindness comment +** Kornel Wieliczek +** Christoph Hellwig +** Adrian Bunk +** Andrew Morton +** Christoph Hellwig +** James Bottomley +** Arjan van de Ven +** 1.20.00.06 3/12/2005 Erich Chen fix with arcmsr_pci_unmap_dma "unsigned long" cast, +** modify PCCB POOL allocated by "dma_alloc_coherent" +** (Kornel Wieliczek's comment) +** 1.20.00.07 3/23/2005 Erich Chen bug fix with arcmsr_scsi_host_template_init occur segmentation fault, +** if RAID adapter does not on PCI slot and modprobe/rmmod this driver twice. +** bug fix enormous stack usage (Adrian Bunk's comment) +** 1.20.00.08 6/23/2005 Erich Chen bug fix with abort command,in case of heavy loading when sata cable +** working on low quality connection +** 1.20.00.09 9/12/2005 Erich Chen bug fix with abort command handling,firmware version check +** and firmware update notify for hardware bug fix +** 1.20.00.10 9/23/2005 Erich Chen enhance sysfs function for change driver's max tag Q number. +** add DMA_64BIT_MASK for backward compatible with all 2.6.x +** add some useful message for abort command +** add ioctl code 'ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE' +** customer can send this command for sync raid volume data +** 1.20.00.11 9/29/2005 Erich Chen by comment of Arjan van de Ven fix incorrect msleep redefine +** cast off sizeof(dma_addr_t) condition for 64bit pci_set_dma_mask +** 1.20.00.12 9/30/2005 Erich Chen bug fix with 64bit platform's ccbs using if over 4G system memory +** change 64bit pci_set_consistent_dma_mask into 32bit +** increcct adapter count if adapter initialize fail. +** miss edit at arcmsr_build_ccb.... +** psge += sizeof(struct _SG64ENTRY *) => psge += sizeof(struct _SG64ENTRY) +** 64 bits sg entry would be incorrectly calculated +** thanks Kornel Wieliczek give me kindly notify and detail description +** 1.20.00.13 11/15/2005 Erich Chen scheduling pending ccb with FIFO +** change the architecture of arcmsr command queue list +** for linux standard list +** enable usage of pci message signal interrupt +************************************************************************** ===================================================================================================== Support: diff -puN drivers/scsi/Kconfig~areca-raid-linux-scsi-driver-updates drivers/scsi/Kconfig --- devel/drivers/scsi/Kconfig~areca-raid-linux-scsi-driver-updates 2006-01-03 23:21:16.000000000 -0800 +++ devel-akpm/drivers/scsi/Kconfig 2006-01-03 23:21:16.000000000 -0800 @@ -289,20 +289,6 @@ config SCSI_DECSII tristate "DEC SII Scsi Driver" depends on MACH_DECSTATION && SCSI && 32BIT -config SCSI_ARCMSR - tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support" - depends on PCI && SCSI - help - This driver supports all of ARECA's SATA RAID controllers cards. - This is an ARECA maintained driver by Erich Chen. - If you have any problems, please mail to: < erich@areca.com.tw > - Areca have suport Linux RAID config tools - - < http://www.areca.com.tw > - - To compile this driver as a module, choose M here: the - module will be called arcmsr (modprobe arcmsr) . - config BLK_DEV_3W_XXXX_RAID tristate "3ware 5/6/7/8xxx ATA-RAID support" depends on PCI && SCSI @@ -438,6 +424,20 @@ config SCSI_AIC7XXX_OLD source "drivers/scsi/aic7xxx/Kconfig.aic79xx" +config SCSI_ARCMSR + tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support" + depends on PCI && SCSI + help + This driver supports all of ARECA's SATA RAID controllers cards. + This is an ARECA maintained driver by Erich Chen. + If you have any problems, please mail to: < erich@areca.com.tw > + Areca have suport Linux RAID config tools + + < http://www.areca.com.tw > + + To compile this driver as a module, choose M here: the + module will be called arcmsr (modprobe arcmsr) . + # All the I2O code and drivers do not seem to be 64bit safe. config SCSI_DPT_I2O tristate "Adaptec I2O RAID support " _