| /* |
| * |
| * Linux MegaRAID device driver |
| * |
| * Copyright (c) 2003-2004 LSI Logic Corporation. |
| * |
| * 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 of the License, or (at your option) any later version. |
| * |
| * FILE : mega_common.h |
| * |
| * Libaray of common routine used by all low-level megaraid drivers |
| */ |
| |
| #ifndef _MEGA_COMMON_H_ |
| #define _MEGA_COMMON_H_ |
| |
| #include <linux/kernel.h> |
| #include <linux/types.h> |
| #include <linux/pci.h> |
| #include <linux/spinlock.h> |
| #include <linux/interrupt.h> |
| #include <linux/delay.h> |
| #include <linux/blkdev.h> |
| #include <linux/list.h> |
| #include <linux/version.h> |
| #include <linux/moduleparam.h> |
| #include <linux/dma-mapping.h> |
| #include <asm/semaphore.h> |
| #include <scsi/scsi.h> |
| #include <scsi/scsi_cmnd.h> |
| #include <scsi/scsi_device.h> |
| #include <scsi/scsi_host.h> |
| |
| |
| #define LSI_MAX_CHANNELS 16 |
| #define LSI_MAX_LOGICAL_DRIVES_64LD (64+1) |
| |
| |
| /** |
| * scb_t - scsi command control block |
| * @param ccb : command control block for individual driver |
| * @param list : list of control blocks |
| * @param gp : general purpose field for LLDs |
| * @param sno : all SCBs have a serial number |
| * @param scp : associated scsi command |
| * @param state : current state of scb |
| * @param dma_dir : direction of data transfer |
| * @param dma_type : transfer with sg list, buffer, or no data transfer |
| * @param dev_channel : actual channel on the device |
| * @param dev_target : actual target on the device |
| * @param status : completion status |
| * |
| * This is our central data structure to issue commands the each driver. |
| * Driver specific data structures are maintained in the ccb field. |
| * scb provides a field 'gp', which can be used by LLD for its own purposes |
| * |
| * dev_channel and dev_target must be initialized with the actual channel and |
| * target on the controller. |
| */ |
| typedef struct { |
| caddr_t ccb; |
| struct list_head list; |
| unsigned long gp; |
| unsigned int sno; |
| struct scsi_cmnd *scp; |
| uint32_t state; |
| uint32_t dma_direction; |
| uint32_t dma_type; |
| uint16_t dev_channel; |
| uint16_t dev_target; |
| uint32_t status; |
| } scb_t; |
| |
| /* |
| * SCB states as it transitions from one state to another |
| */ |
| #define SCB_FREE 0x0000 /* on the free list */ |
| #define SCB_ACTIVE 0x0001 /* off the free list */ |
| #define SCB_PENDQ 0x0002 /* on the pending queue */ |
| #define SCB_ISSUED 0x0004 /* issued - owner f/w */ |
| #define SCB_ABORT 0x0008 /* Got an abort for this one */ |
| #define SCB_RESET 0x0010 /* Got a reset for this one */ |
| |
| /* |
| * DMA types for scb |
| */ |
| #define MRAID_DMA_NONE 0x0000 /* no data transfer for this command */ |
| #define MRAID_DMA_WSG 0x0001 /* data transfer using a sg list */ |
| #define MRAID_DMA_WBUF 0x0002 /* data transfer using a contiguous buffer */ |
| |
| |
| /** |
| * struct adapter_t - driver's initialization structure |
| * @param dpc_h : tasklet handle |
| * @param pdev : pci configuration pointer for kernel |
| * @param host : pointer to host structure of mid-layer |
| * @param host_lock : pointer to appropriate lock |
| * @param lock : synchronization lock for mid-layer and driver |
| * @param quiescent : driver is quiescent for now. |
| * @param outstanding_cmds : number of commands pending in the driver |
| * @param kscb_list : pointer to the bulk of SCBs pointers for IO |
| * @param kscb_pool : pool of free scbs for IO |
| * @param kscb_pool_lock : lock for pool of free scbs |
| * @param pend_list : pending commands list |
| * @param pend_list_lock : exlusion lock for pending commands list |
| * @param completed_list : list of completed commands |
| * @param completed_list_lock : exclusion lock for list of completed commands |
| * @param sglen : max sg elements supported |
| * @param device_ids : to convert kernel device addr to our devices. |
| * @param raid_device : raid adapter specific pointer |
| * @param max_channel : maximum channel number supported - inclusive |
| * @param max_target : max target supported - inclusive |
| * @param max_lun : max lun supported - inclusive |
| * @param unique_id : unique identifier for each adapter |
| * @param irq : IRQ for this adapter |
| * @param ito : internal timeout value, (-1) means no timeout |
| * @param ibuf : buffer to issue internal commands |
| * @param ibuf_dma_h : dma handle for the above buffer |
| * @param uscb_list : SCB pointers for user cmds, common mgmt module |
| * @param uscb_pool : pool of SCBs for user commands |
| * @param uscb_pool_lock : exclusion lock for these SCBs |
| * @param max_cmds : max outstanding commands |
| * @param fw_version : firmware version |
| * @param bios_version : bios version |
| * @param max_cdb_sz : biggest CDB size supported. |
| * @param ha : is high availability present - clustering |
| * @param init_id : initiator ID, the default value should be 7 |
| * @param max_sectors : max sectors per request |
| * @param cmd_per_lun : max outstanding commands per LUN |
| * @param being_detached : set when unloading, no more mgmt calls |
| * |
| * |
| * mraid_setup_device_map() can be called anytime after the device map is |
| * available and MRAID_GET_DEVICE_MAP() can be called whenever the mapping is |
| * required, usually from LLD's queue entry point. The formar API sets up the |
| * MRAID_IS_LOGICAL(adapter_t *, struct scsi_cmnd *) to find out if the |
| * device in question is a logical drive. |
| * |
| * quiescent flag should be set by the driver if it is not accepting more |
| * commands |
| * |
| * NOTE: The fields of this structures are placed to minimize cache misses |
| */ |
| |
| // amount of space required to store the bios and firmware version strings |
| #define VERSION_SIZE 16 |
| |
| typedef struct { |
| struct tasklet_struct dpc_h; |
| struct pci_dev *pdev; |
| struct Scsi_Host *host; |
| spinlock_t *host_lock; |
| spinlock_t lock; |
| uint8_t quiescent; |
| int outstanding_cmds; |
| scb_t *kscb_list; |
| struct list_head kscb_pool; |
| spinlock_t kscb_pool_lock; |
| struct list_head pend_list; |
| spinlock_t pend_list_lock; |
| struct list_head completed_list; |
| spinlock_t completed_list_lock; |
| uint16_t sglen; |
| int device_ids[LSI_MAX_CHANNELS] |
| [LSI_MAX_LOGICAL_DRIVES_64LD]; |
| caddr_t raid_device; |
| uint8_t max_channel; |
| uint16_t max_target; |
| uint8_t max_lun; |
| |
| uint32_t unique_id; |
| uint8_t irq; |
| uint8_t ito; |
| caddr_t ibuf; |
| dma_addr_t ibuf_dma_h; |
| scb_t *uscb_list; |
| struct list_head uscb_pool; |
| spinlock_t uscb_pool_lock; |
| int max_cmds; |
| uint8_t fw_version[VERSION_SIZE]; |
| uint8_t bios_version[VERSION_SIZE]; |
| uint8_t max_cdb_sz; |
| uint8_t ha; |
| uint16_t init_id; |
| uint16_t max_sectors; |
| uint16_t cmd_per_lun; |
| atomic_t being_detached; |
| } adapter_t; |
| |
| #define SCSI_FREE_LIST_LOCK(adapter) (&adapter->kscb_pool_lock) |
| #define USER_FREE_LIST_LOCK(adapter) (&adapter->uscb_pool_lock) |
| #define PENDING_LIST_LOCK(adapter) (&adapter->pend_list_lock) |
| #define COMPLETED_LIST_LOCK(adapter) (&adapter->completed_list_lock) |
| |
| |
| // conversion from scsi command |
| #define SCP2HOST(scp) (scp)->device->host // to host |
| #define SCP2HOSTDATA(scp) SCP2HOST(scp)->hostdata // to soft state |
| #define SCP2CHANNEL(scp) (scp)->device->channel // to channel |
| #define SCP2TARGET(scp) (scp)->device->id // to target |
| #define SCP2LUN(scp) (scp)->device->lun // to LUN |
| |
| // generic macro to convert scsi command and host to controller's soft state |
| #define SCSIHOST2ADAP(host) (((caddr_t *)(host->hostdata))[0]) |
| #define SCP2ADAPTER(scp) (adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp)) |
| |
| |
| /** |
| * MRAID_GET_DEVICE_MAP - device ids |
| * @param adp - Adapter's soft state |
| * @param scp - mid-layer scsi command pointer |
| * @param p_chan - physical channel on the controller |
| * @param target - target id of the device or logical drive number |
| * @param islogical - set if the command is for the logical drive |
| * |
| * Macro to retrieve information about device class, logical or physical and |
| * the corresponding physical channel and target or logical drive number |
| **/ |
| #define MRAID_IS_LOGICAL(adp, scp) \ |
| (SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0 |
| |
| #define MRAID_IS_LOGICAL_SDEV(adp, sdev) \ |
| (sdev->channel == (adp)->max_channel) ? 1 : 0 |
| |
| #define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical) \ |
| /* \ |
| * Is the request coming for the virtual channel \ |
| */ \ |
| islogical = MRAID_IS_LOGICAL(adp, scp); \ |
| \ |
| /* \ |
| * Get an index into our table of drive ids mapping \ |
| */ \ |
| if (islogical) { \ |
| p_chan = 0xFF; \ |
| target = \ |
| (adp)->device_ids[(adp)->max_channel][SCP2TARGET(scp)]; \ |
| } \ |
| else { \ |
| p_chan = ((adp)->device_ids[SCP2CHANNEL(scp)] \ |
| [SCP2TARGET(scp)] >> 8) & 0xFF; \ |
| target = ((adp)->device_ids[SCP2CHANNEL(scp)] \ |
| [SCP2TARGET(scp)] & 0xFF); \ |
| } |
| |
| /* |
| * ### Helper routines ### |
| */ |
| #define LSI_DBGLVL mraid_debug_level // each LLD must define a global |
| // mraid_debug_level |
| |
| #ifdef DEBUG |
| #if defined (_ASSERT_PANIC) |
| #define ASSERT_ACTION panic |
| #else |
| #define ASSERT_ACTION printk |
| #endif |
| |
| #define ASSERT(expression) \ |
| if (!(expression)) { \ |
| ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \ |
| #expression, __FILE__, __LINE__, __FUNCTION__); \ |
| } |
| #else |
| #define ASSERT(expression) |
| #endif |
| |
| /* |
| * struct mraid_pci_blk - structure holds DMA memory block info |
| * @param vaddr : virtual address to a memory block |
| * @param dma_addr : DMA handle to a memory block |
| * |
| * This structure is filled up for the caller. It is the responsibilty of the |
| * caller to allocate this array big enough to store addresses for all |
| * requested elements |
| */ |
| struct mraid_pci_blk { |
| caddr_t vaddr; |
| dma_addr_t dma_addr; |
| }; |
| |
| #endif // _MEGA_COMMON_H_ |
| |
| // vim: set ts=8 sw=8 tw=78: |