diff options
Diffstat (limited to 'drivers/scsi/aacraid/commsup.c')
| -rw-r--r-- | drivers/scsi/aacraid/commsup.c | 105 |
1 files changed, 82 insertions, 23 deletions
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index afc9aeba5ed..cab190af634 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,9 +64,11 @@ static int fib_map_alloc(struct aac_dev *dev) "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n", dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue, AAC_NUM_MGT_FIB, &dev->hw_fib_pa)); - if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, dev->max_fib_size - * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), - &dev->hw_fib_pa))==NULL) + dev->hw_fib_va = pci_alloc_consistent(dev->pdev, + (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) + * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1), + &dev->hw_fib_pa); + if (dev->hw_fib_va == NULL) return -ENOMEM; return 0; } @@ -91,7 +94,7 @@ void aac_fib_map_free(struct aac_dev *dev) * aac_fib_setup - setup the fibs * @dev: Adapter to set up * - * Allocate the PCI space for the fibs, map it and then intialise the + * Allocate the PCI space for the fibs, map it and then initialise the * fib area, the unmapped fib data and also the free list */ @@ -110,9 +113,22 @@ int aac_fib_setup(struct aac_dev * dev) if (i<0) return -ENOMEM; + /* 32 byte alignment for PMC */ + hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1); + dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + + (hw_fib_pa - dev->hw_fib_pa)); + dev->hw_fib_pa = hw_fib_pa; + memset(dev->hw_fib_va, 0, + (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) * + (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); + + /* add Xport header */ + dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + + sizeof(struct aac_fib_xporthdr)); + dev->hw_fib_pa += sizeof(struct aac_fib_xporthdr); + hw_fib = dev->hw_fib_va; hw_fib_pa = dev->hw_fib_pa; - memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); /* * Initialise the fibs */ @@ -120,6 +136,7 @@ int aac_fib_setup(struct aac_dev * dev) i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) { + fibptr->flags = 0; fibptr->dev = dev; fibptr->hw_fib_va = hw_fib; fibptr->data = (void *) fibptr->hw_fib_va->data; @@ -129,8 +146,10 @@ int aac_fib_setup(struct aac_dev * dev) hw_fib->header.XferState = cpu_to_le32(0xffffffff); hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size); fibptr->hw_fib_pa = hw_fib_pa; - hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size); - hw_fib_pa = hw_fib_pa + dev->max_fib_size; + hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + + dev->max_fib_size + sizeof(struct aac_fib_xporthdr)); + hw_fib_pa = hw_fib_pa + + dev->max_fib_size + sizeof(struct aac_fib_xporthdr); } /* * Add the fib chain to the free list @@ -222,11 +241,11 @@ void aac_fib_init(struct fib *fibptr) { struct hw_fib *hw_fib = fibptr->hw_fib_va; + memset(&hw_fib->header, 0, sizeof(struct aac_fibhdr)); hw_fib->header.StructType = FIB_MAGIC; hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size); hw_fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable); - hw_fib->header.SenderFibAddress = 0; /* Filled in later if needed */ - hw_fib->header.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa); + hw_fib->header.u.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa); hw_fib->header.SenderSize = cpu_to_le16(fibptr->dev->max_fib_size); } @@ -241,7 +260,6 @@ void aac_fib_init(struct fib *fibptr) static void fib_dealloc(struct fib * fibptr) { struct hw_fib *hw_fib = fibptr->hw_fib_va; - BUG_ON(hw_fib->header.StructType != FIB_MAGIC); hw_fib->header.XferState = 0; } @@ -352,7 +370,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); entry->addr = hw_fib->header.SenderFibAddress; /* Restore adapters pointer to the FIB */ - hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress; /* Let the adapter now where to find its data */ + hw_fib->header.u.ReceiverFibAddress = hw_fib->header.SenderFibAddress; /* Let the adapter now where to find its data */ map = 0; } /* @@ -398,12 +416,13 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, unsigned long flags = 0; unsigned long qflags; unsigned long mflags = 0; + unsigned long sflags = 0; if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned))) return -EBUSY; /* - * There are 5 cases with the wait and reponse requested flags. + * There are 5 cases with the wait and response requested flags. * The only invalid cases are if the caller requests to wait and * does not request a response and if the caller does not want a * response and the Fib is not allocated from pool. If a response @@ -431,7 +450,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, */ hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2); - hw_fib->header.SenderData = (u32)(fibptr - dev->fibs); + hw_fib->header.Handle = (u32)(fibptr - dev->fibs) + 1; /* * Set FIB state to indicate where it came from and if we want a * response from the adapter. Also load the command from the @@ -441,7 +460,6 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, */ hw_fib->header.Command = cpu_to_le16(command); hw_fib->header.XferState |= cpu_to_le32(SentFromHost); - fibptr->hw_fib_va->header.Flags = 0; /* 0 the flags field - internal only*/ /* * Set the size of the Fib we want to send to the adapter */ @@ -494,6 +512,31 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, spin_lock_irqsave(&fibptr->event_lock, flags); } + if (dev->sync_mode) { + if (wait) + spin_unlock_irqrestore(&fibptr->event_lock, flags); + spin_lock_irqsave(&dev->sync_lock, sflags); + if (dev->sync_fib) { + list_add_tail(&fibptr->fiblink, &dev->sync_fib_list); + spin_unlock_irqrestore(&dev->sync_lock, sflags); + } else { + dev->sync_fib = fibptr; + spin_unlock_irqrestore(&dev->sync_lock, sflags); + aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, + (u32)fibptr->hw_fib_pa, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL); + } + if (wait) { + fibptr->flags |= FIB_CONTEXT_FLAG_WAIT; + if (down_interruptible(&fibptr->event_wait)) { + fibptr->flags &= ~FIB_CONTEXT_FLAG_WAIT; + return -EFAULT; + } + return 0; + } + return -EINPROGRESS; + } + if (aac_adapter_deliver(fibptr) != 0) { printk(KERN_ERR "aac_fib_send: returned -EBUSY\n"); if (wait) { @@ -520,10 +563,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, * functioning because an interrupt routing or other * hardware failure has occurred. */ - unsigned long count = 36000000L; /* 3 minutes */ + unsigned long timeout = jiffies + (180 * HZ); /* 3 minutes */ while (down_trylock(&fibptr->event_wait)) { int blink; - if (--count == 0) { + if (time_is_before_eq_jiffies(timeout)) { struct aac_queue * q = &dev->queues->queue[AdapNormCmdQueue]; spin_lock_irqsave(q->lock, qflags); q->numpending--; @@ -544,7 +587,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, } return -EFAULT; } - udelay(5); + /* We used to udelay() here but that absorbed + * a CPU when a timeout occured. Not very + * useful. */ + cpu_relax(); } } else if (down_interruptible(&fibptr->event_wait)) { /* Do nothing ... satisfy @@ -664,17 +710,25 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) unsigned long nointr = 0; unsigned long qflags; + if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1 || + dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) { + kfree(hw_fib); + return 0; + } + if (hw_fib->header.XferState == 0) { if (dev->comm_interface == AAC_COMM_MESSAGE) - kfree (hw_fib); + kfree(hw_fib); return 0; } /* * If we plan to do anything check the structure type first. */ - if (hw_fib->header.StructType != FIB_MAGIC) { + if (hw_fib->header.StructType != FIB_MAGIC && + hw_fib->header.StructType != FIB_MAGIC2 && + hw_fib->header.StructType != FIB_MAGIC2_64) { if (dev->comm_interface == AAC_COMM_MESSAGE) - kfree (hw_fib); + kfree(hw_fib); return -EINVAL; } /* @@ -734,7 +788,9 @@ int aac_fib_complete(struct fib *fibptr) * If we plan to do anything check the structure type first. */ - if (hw_fib->header.StructType != FIB_MAGIC) + if (hw_fib->header.StructType != FIB_MAGIC && + hw_fib->header.StructType != FIB_MAGIC2 && + hw_fib->header.StructType != FIB_MAGIC2_64) return -EINVAL; /* * This block completes a cdb which orginated on the host and we @@ -1260,6 +1316,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) kfree(aac->queues); aac->queues = NULL; free_irq(aac->pdev->irq, aac); + if (aac->msi) + pci_disable_msi(aac->pdev); kfree(aac->fsa_dev); aac->fsa_dev = NULL; quirks = aac_get_driver_ident(index)->quirks; @@ -1278,7 +1336,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) if ((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(32)))) goto out; if (jafo) { - aac->thread = kthread_run(aac_command_thread, aac, aac->name); + aac->thread = kthread_run(aac_command_thread, aac, "%s", + aac->name); if (IS_ERR(aac->thread)) { retval = PTR_ERR(aac->thread); goto out; |
