/drivers/scsi/aacraid/commsup.c
C | 1853 lines | 1158 code | 151 blank | 544 comment | 310 complexity | b9ee617db002054fae241f56d6efce0d MD5 | raw file
Possible License(s): CC-BY-SA-3.0, GPL-2.0, LGPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*
- * Adaptec AAC series RAID controller driver
- * (c) Copyright 2001 Red Hat Inc.
- *
- * based on the old aacraid driver that is..
- * Adaptec aacraid device driver for Linux.
- *
- * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Module Name:
- * commsup.c
- *
- * Abstract: Contain all routines that are required for FSA host/adapter
- * communication.
- *
- */
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/types.h>
- #include <linux/sched.h>
- #include <linux/pci.h>
- #include <linux/spinlock.h>
- #include <linux/slab.h>
- #include <linux/completion.h>
- #include <linux/blkdev.h>
- #include <linux/delay.h>
- #include <linux/kthread.h>
- #include <linux/interrupt.h>
- #include <linux/semaphore.h>
- #include <scsi/scsi.h>
- #include <scsi/scsi_host.h>
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_cmnd.h>
- #include "aacraid.h"
- /**
- * fib_map_alloc - allocate the fib objects
- * @dev: Adapter to allocate for
- *
- * Allocate and map the shared PCI space for the FIB blocks used to
- * talk to the Adaptec firmware.
- */
- static int fib_map_alloc(struct aac_dev *dev)
- {
- dprintk((KERN_INFO
- "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)
- return -ENOMEM;
- return 0;
- }
- /**
- * aac_fib_map_free - free the fib objects
- * @dev: Adapter to free
- *
- * Free the PCI mappings and the memory allocated for FIB blocks
- * on this adapter.
- */
- void aac_fib_map_free(struct aac_dev *dev)
- {
- pci_free_consistent(dev->pdev,
- dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
- dev->hw_fib_va, dev->hw_fib_pa);
- dev->hw_fib_va = NULL;
- dev->hw_fib_pa = 0;
- }
- /**
- * aac_fib_setup - setup the fibs
- * @dev: Adapter to set up
- *
- * Allocate the PCI space for the fibs, map it and then intialise the
- * fib area, the unmapped fib data and also the free list
- */
- int aac_fib_setup(struct aac_dev * dev)
- {
- struct fib *fibptr;
- struct hw_fib *hw_fib;
- dma_addr_t hw_fib_pa;
- int i;
- while (((i = fib_map_alloc(dev)) == -ENOMEM)
- && (dev->scsi_host_ptr->can_queue > (64 - AAC_NUM_MGT_FIB))) {
- dev->init->MaxIoCommands = cpu_to_le32((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) >> 1);
- dev->scsi_host_ptr->can_queue = le32_to_cpu(dev->init->MaxIoCommands) - AAC_NUM_MGT_FIB;
- }
- if (i<0)
- return -ENOMEM;
- 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
- */
- for (i = 0, fibptr = &dev->fibs[i];
- i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
- i++, fibptr++)
- {
- fibptr->dev = dev;
- fibptr->hw_fib_va = hw_fib;
- fibptr->data = (void *) fibptr->hw_fib_va->data;
- fibptr->next = fibptr+1; /* Forward chain the fibs */
- init_MUTEX_LOCKED(&fibptr->event_wait);
- spin_lock_init(&fibptr->event_lock);
- 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;
- }
- /*
- * Add the fib chain to the free list
- */
- dev->fibs[dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1].next = NULL;
- /*
- * Enable this to debug out of queue space
- */
- dev->free_fib = &dev->fibs[0];
- return 0;
- }
- /**
- * aac_fib_alloc - allocate a fib
- * @dev: Adapter to allocate the fib for
- *
- * Allocate a fib from the adapter fib pool. If the pool is empty we
- * return NULL.
- */
- struct fib *aac_fib_alloc(struct aac_dev *dev)
- {
- struct fib * fibptr;
- unsigned long flags;
- spin_lock_irqsave(&dev->fib_lock, flags);
- fibptr = dev->free_fib;
- if(!fibptr){
- spin_unlock_irqrestore(&dev->fib_lock, flags);
- return fibptr;
- }
- dev->free_fib = fibptr->next;
- spin_unlock_irqrestore(&dev->fib_lock, flags);
- /*
- * Set the proper node type code and node byte size
- */
- fibptr->type = FSAFS_NTC_FIB_CONTEXT;
- fibptr->size = sizeof(struct fib);
- /*
- * Null out fields that depend on being zero at the start of
- * each I/O
- */
- fibptr->hw_fib_va->header.XferState = 0;
- fibptr->flags = 0;
- fibptr->callback = NULL;
- fibptr->callback_data = NULL;
- return fibptr;
- }
- /**
- * aac_fib_free - free a fib
- * @fibptr: fib to free up
- *
- * Frees up a fib and places it on the appropriate queue
- */
- void aac_fib_free(struct fib *fibptr)
- {
- unsigned long flags, flagsv;
- spin_lock_irqsave(&fibptr->event_lock, flagsv);
- if (fibptr->done == 2) {
- spin_unlock_irqrestore(&fibptr->event_lock, flagsv);
- return;
- }
- spin_unlock_irqrestore(&fibptr->event_lock, flagsv);
- spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
- if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
- aac_config.fib_timeouts++;
- if (fibptr->hw_fib_va->header.XferState != 0) {
- printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n",
- (void*)fibptr,
- le32_to_cpu(fibptr->hw_fib_va->header.XferState));
- }
- fibptr->next = fibptr->dev->free_fib;
- fibptr->dev->free_fib = fibptr;
- spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags);
- }
- /**
- * aac_fib_init - initialise a fib
- * @fibptr: The fib to initialize
- *
- * Set up the generic fib fields ready for use
- */
- void aac_fib_init(struct fib *fibptr)
- {
- struct hw_fib *hw_fib = fibptr->hw_fib_va;
- 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.SenderSize = cpu_to_le16(fibptr->dev->max_fib_size);
- }
- /**
- * fib_deallocate - deallocate a fib
- * @fibptr: fib to deallocate
- *
- * Will deallocate and return to the free pool the FIB pointed to by the
- * caller.
- */
- 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;
- }