public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [ANNOUNCE] Adaptec SAS/SATA device driver [17/27]
@ 2005-02-17 17:37 Luben Tuikov
  2005-02-17 21:08 ` Andi Kleen
  0 siblings, 1 reply; 4+ messages in thread
From: Luben Tuikov @ 2005-02-17 17:37 UTC (permalink / raw)
  To: SCSI Mailing List

OSM header file.

diff -Nru a/drivers/scsi/adp94xx/adp94xx_osm.h b/drivers/scsi/adp94xx/adp94xx_osm.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/scsi/adp94xx/adp94xx_osm.h	2005-02-16 16:08:12 -05:00
@@ -0,0 +1,1375 @@
+/*
+ * Adaptec ADP94xx SAS HBA device driver for Linux. 
+ *
+ * Written by : David Chaw <david_chaw@adaptec.com>
+ * 
+ * Copyright (c) 2004 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/razor/linux/src/adp94xx_osm.h#143 $
+ * 
+ */	
+
+#ifndef ADP94XX_OSM_H
+#define ADP94XX_OSM_H
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/nmi.h>
+#include <linux/hdreg.h>
+#include <asm/uaccess.h>
+#include <linux/ioctl.h>
+#include <linux/init.h>
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z)	(((x)<<16) + ((y)<<8) + (z))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <linux/blk.h>
+#include "sd.h"
+#endif
+#include <linux/blkdev.h>
+
+#include "scsi.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include "hosts.h"
+#else
+#include <scsi/scsi_host.h>
+#endif
+
+#define __packed __attribute__ ((packed))
+
+/* Driver name */
+#define ASD_DRIVER_NAME		"adp94xx"
+#define ASD_DRIVER_DESCRIPTION	"Adaptec Linux SAS/SATA Family Driver"
+#define ASD_DRIVER_VERSION	"1.0.5"
+#define ASD_RELEASE_VERSION	12
+
+/* For now, let's limit ourselves on kernel 2.4, 2.6 and greater */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+#error "This driver only support kernel 2.4 or greater"
+#endif
+
+/************************* Forward Declarations *******************************/
+struct asd_softc;
+struct asd_port;
+struct scb;
+struct asd_scb_platform_data; 
+struct asd_domain;
+struct asd_done_list;
+
+/********************* Definitions Required by the Core ***********************/
+/*
+ * Number of SG segments we require.  So long as the S/G segments for
+ * a particular transaction are allocated in a physically contiguous
+ * manner, the number of S/G segments is unrestricted.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/*
+ * We dynamically adjust the number of segments in pre-2.5 kernels to
+ * avoid fragmentation issues in the SCSI mid-layer's private memory
+ * allocator.  See adp94xx_osm.c asd_size_nseg() for details.
+ */
+extern u_int asd_nseg;
+#define	ASD_NSEG 		asd_nseg
+#define	ASD_LINUX_MIN_NSEG 	64
+#else
+#define	ASD_NSEG 		128
+#endif
+
+/* Constants definition */
+#define ASD_MAX_QUEUE		ASD_MAX_ALLOCATED_SCBS
+
+/*
+ * DC: Does MAX_SECTORS 255 works for some SATA drives ?
+ *     Preferable set it to 255 for better performance in 2.6 kernel.
+ *     In 2.4 kernel, it seems that block layer always limited to 64 sectors.
+ */ 
+//#define ASD_MAX_SECTORS	8192
+#define ASD_MAX_SECTORS		128
+#define ASD_MAX_IO_HANDLES	6
+
+/* Device mapping definition */
+/*
+ * XXX This should really be limited by SAS/SAM.  With
+ *     the use of hash tables in the domain and target
+ *     structures as well as DDB site recycling, we
+ *     should have no limit.
+ */
+#define ASD_MAX_LUNS		128
+#define SAS_LUN_LEN		8
+
+/********************************** Misc Macros *******************************/
+#ifndef roundup
+#define	roundup(x, y)   	((((x)+((y)-1))/(y))*(y))
+#endif
+
+static inline uint32_t
+roundup_pow2(uint32_t val)
+{
+	val--;
+	val |= val >> 1;
+	val |= val >> 2;
+	val |= val >> 4;
+	val |= val >> 8;
+	val |= val >> 16;
+	return (val + 1);
+}
+
+#ifndef powerof2
+#define	powerof2(x)	((((x)-1)&(x))==0)
+#endif
+
+#ifndef MAX
+#define MAX(a,b) 	(((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) 	(((a) < (b)) ? (a) : (b))
+#endif
+
+#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array))
+
+/******************************* Byte Order ***********************************/
+#define asd_htobe16(x)		cpu_to_be16(x)
+#define asd_htobe32(x)		cpu_to_be32(x)
+#define asd_htobe64(x)		cpu_to_be64(x)
+#define asd_htole16(x)		cpu_to_le16(x)
+#define asd_htole32(x)		cpu_to_le32(x)
+#define asd_htole64(x)		cpu_to_le64(x)
+
+#define asd_be16toh(x)		be16_to_cpu(x)
+#define asd_be32toh(x)		be32_to_cpu(x)
+#define asd_be64toh(x)		be64_to_cpu(x)
+#define asd_le16toh(x)		le16_to_cpu(x)
+#define asd_le32toh(x)		le32_to_cpu(x)
+#define asd_le64toh(x)		le64_to_cpu(x)
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+#ifndef BYTE_ORDER
+#if defined(__BIG_ENDIAN)
+#define BYTE_ORDER BIG_ENDIAN
+#endif
+#if defined(__LITTLE_ENDIAN)
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#endif /* BYTE_ORDER */
+
+/***************************** Bus Space/DMA **********************************/
+
+struct asd_dma_tag
+{
+	uint32_t	alignment;
+	uint32_t	maxsize;
+};
+typedef struct asd_dma_tag *bus_dma_tag_t;
+
+struct asd_dmamap
+{
+	dma_addr_t	bus_addr;
+};
+typedef struct asd_dmamap * bus_dmamap_t;
+
+/*
+ * Data structure used to track a slab of DMA
+ * safe memory.
+ */
+struct map_node {
+	bus_dmamap_t	 dmamap;
+	dma_addr_t	 busaddr;
+	uint8_t		*vaddr;
+	struct list_head links;
+};
+
+int	asd_dma_tag_create(struct asd_softc *, uint32_t /*alignment*/,
+			   uint32_t /*maxsize*/, int /*flags*/,
+			   bus_dma_tag_t * /*dma_tagp*/);
+void	asd_dma_tag_destroy(struct asd_softc *, bus_dma_tag_t /*tag*/);
+int	asd_dmamem_alloc(struct asd_softc *, bus_dma_tag_t /*dmat*/,
+			 void** /*vaddr*/, int /*flags*/,
+			 bus_dmamap_t * /*mapp*/, dma_addr_t * /*baddr*/);
+void	asd_dmamem_free(struct asd_softc *, bus_dma_tag_t /*dmat*/,
+			void* /*vaddr*/, bus_dmamap_t /*map*/);
+void	asd_dmamap_destroy(struct asd_softc *, bus_dma_tag_t /*tag*/,
+			   bus_dmamap_t /*map*/);
+int	asd_alloc_dma_mem(struct asd_softc *, unsigned, void **,
+			  dma_addr_t *, bus_dma_tag_t *, struct map_node *);
+void	asd_free_dma_mem(struct asd_softc *, bus_dma_tag_t, struct map_node *);
+
+/* IOCTL registration wrappers */
+int 	asd_register_ioctl_dev(void);
+int 	asd_unregister_ioctl_dev(void);
+int 	asd_ctl_init_internal_data(struct asd_softc *asd);
+struct asd_softc * asd_get_softc_by_hba_index(uint32_t hba_index);
+int 	asd_get_number_of_hbas_present(void);
+struct asd_target * 
+	asd_get_os_target_from_port(struct asd_softc *asd,
+				    struct asd_port *port,
+				    struct asd_domain *dm);
+struct asd_device *
+	asd_get_device_from_lun(struct asd_softc *asd, 
+				struct asd_target *targ, uint8_t *saslun);
+int 	asd_get_os_platform_map_from_sasaddr(struct asd_softc *asd, 
+					     struct asd_port *port,
+					     uint8_t *sasaddr, uint8_t *saslun, 
+					     uint8_t *host, uint8_t *bus, 
+					     uint8_t *target, uint8_t *lun);
+struct asd_port *
+	asd_get_sas_addr_from_platform_map(struct asd_softc *asd, 
+					   uint8_t host, uint8_t bus, 
+					   uint8_t target, uint8_t lun, 
+					   uint8_t *sasaddr, uint8_t *saslun);
+struct asd_target * 
+	asd_get_sas_target_from_sasaddr(struct asd_softc *asd, 
+					struct asd_port *port, 
+					uint8_t *sasaddr);
+struct asd_target * 
+	asd_get_os_target_from_sasaddr(struct asd_softc *asd, 
+			 	       struct asd_domain *dm, 
+				       uint8_t *sasddr);
+struct scb *
+	asd_find_pending_scb_by_qtag(struct asd_softc *asd, uint32_t qtag);
+
+int	asd_hwi_check_cmd_pending(struct asd_softc *asd, struct scb *scb, 
+		       		  struct asd_done_list *dl);
+
+/* indicates that the scsi_cmnd is generated by CSMI */
+#define ASD_CSMI_COMMAND 0xfaceface
+
+#if (BITS_PER_LONG > 32) || \
+    (defined CONFIG_HIGHMEM64G && defined CONFIG_HIGHIO)
+	#define ASD_DMA_64BIT_SUPPORT		1
+#else
+	#define	ASD_DMA_64BIT_SUPPORT		0
+#endif 
+
+/*************************** Linux DMA Wrappers *******************************/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#define	asd_alloc_coherent(asd, size, bus_addr_ptr) \
+	dma_alloc_coherent(asd->dev, size, bus_addr_ptr, /*flag*/0)
+
+#define	asd_free_coherent(asd, size, vaddr, bus_addr) \
+	dma_free_coherent(asd->dev, size, vaddr, bus_addr)
+
+#define	asd_map_single(asd, buf, size, direction) \
+	dma_map_single(asd->dev, buf, size, direction)
+
+#define	asd_unmap_single(asd, busaddr, size, direction) \
+	dma_unmap_single(asd->dev, busaddr, size, direction)
+
+#define	asd_map_sg(asd, sg_list, num_sg, direction) \
+	dma_map_sg(asd->dev, sg_list, num_sg, direction)
+
+#define	asd_unmap_sg(asd, sg_list, num_sg, direction) \
+	dma_unmap_sg(asd->dev, sg_list, num_sg, direction)
+
+#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0) */
+
+#define	asd_alloc_coherent(asd, size, bus_addr_ptr) \
+	pci_alloc_consistent(asd->dev, size, bus_addr_ptr)
+
+#define	asd_free_coherent(asd, size, vaddr, bus_addr) \
+	pci_free_consistent(asd->dev, size, vaddr, bus_addr)
+
+#define	asd_map_single(asd, buf, size, direction) \
+	pci_map_single(asd->dev, buf, size, direction)
+
+#define	asd_unmap_single(asd, busaddr, size, direction) \
+	pci_unmap_single(asd->dev, busaddr, size, direction)
+
+#define	asd_map_sg(asd, sg_list, num_sg, direction) \
+	pci_map_sg(asd->dev, sg_list, num_sg, direction)
+
+#define	asd_unmap_sg(asd, sg_list, num_sg, direction) \
+	pci_unmap_sg(asd->dev, sg_list, num_sg, direction)
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+
+#define asd_set_dma_mask(asd, mask) dma_set_mask(asd->dev, mask)
+#define asd_set_consistent_dma_mask(asd, mask) \
+	pci_set_consistent_dma_mask(asd_dev_to_pdev(asd->dev), mask)
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
+
+/*
+ * Device softc is NULL for EISA devices.
+ */
+#define asd_set_dma_mask(asd, mask) 			\
+	((asd)->dev == NULL ? 0 : pci_set_dma_mask(asd->dev, mask))
+
+/* Always successfull in 2.4.X kernels */
+#define asd_set_consistent_dma_mask(asd, mask) (0)
+
+#else
+/*
+ * Device softc is NULL for EISA devices.
+ * Always "return" 0 for success.
+ */
+#define asd_set_dma_mask(asd, mask)			\
+    (((asd)->dev == NULL)				\
+     ? 0						\
+     : (((asd)->dev->dma_mask = mask) && 0))
+
+/* Always successfull in 2.4.X kernels */
+#define asd_set_consistent_dma_mask(asd, mask) (0)
+
+#endif
+
+/* Forward compatibility */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+typedef struct device	*asd_dev_t;
+#else
+typedef struct pci_dev	*asd_dev_t;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#define	asd_dev_to_pdev(dev)		to_pci_dev(dev)
+#define	asd_pdev_to_dev(pdev)		(&pdev->dev)
+#else
+#define	asd_dev_to_pdev(dev)		(dev)
+#define	asd_pdev_to_dev(pdev)		(pdev)
+#endif
+
+#define	asd_pci_dev(asd)		asd_dev_to_pdev((asd)->dev)
+
+#define ASD_GET_PADR(addr)		((uint32_t) (addr))
+#if (BITS_PER_LONG > 32)
+#define ASD_GET_PUADR(addr)		((uint32_t) ((addr) >> 32))
+#else
+#define ASD_GET_PUADR(addr)		((uint32_t) (0))
+#endif
+
+typedef enum {
+	ASD_SCB_UP_EH_SEM	= 0x01,
+	ASD_TIMEOUT_ACTIVE	= 0x02,
+	ASD_RELEASE_SIMQ	= 0x04,
+} asd_scb_flags;
+
+/**************************** Front End Queues ********************************/
+/*
+ * Data structure used to cast the Linux struct scsi_cmnd to something
+ * that allows us to use the queue macros.  The linux structure has
+ * plenty of space to hold the links fields as required by the queue
+ * macros, but the queue macors require them to have the correct type.
+ */
+struct asd_cmd_internal {
+	/* Area owned by the Linux scsi layer. */
+	uint8_t	private[offsetof(struct scsi_cmnd, SCp.Status)];
+	struct list_head		links;
+	uint32_t			end;
+};
+
+union asd_cmd {
+	struct asd_cmd_internal	icmd;
+	struct scsi_cmnd	scsi_cmd;
+};
+
+#define acmd_icmd(cmd)		((cmd)->icmd)
+#define acmd_scsi_cmd(cmd) 	((cmd)->scsi_cmd)
+#define acmd_links 		icmd.links
+
+/************************** Razor Architecture Layers ************************/
+/*
+ * The following typedefs define the protocols for each layer of the Razor
+ * architecture.
+ */
+
+/*
+ * The Command Set layer consists of everything having to do with the type
+ * of command that is sent to the target.
+ */
+typedef enum {
+	ASD_COMMAND_SET_UNKNOWN,
+	ASD_COMMAND_SET_SCSI,
+	ASD_COMMAND_SET_ATA,
+	ASD_COMMAND_SET_ATAPI,
+	ASD_COMMAND_SET_SMP
+} COMMAND_SET_TYPE;
+
+/*
+ * The Device Protocol layer are things that are specific to a device, 
+ * regardless of which command set is used.  For example, a device using
+ * ASD_DEVICE_PROTOCOL_ATA might use the command set ASD_COMMAND_SET_ATA or
+ * ASD_COMMAND_SET_ATAPI.
+ */
+typedef enum {
+	ASD_DEVICE_PROTOCOL_UNKNOWN,
+	ASD_DEVICE_PROTOCOL_SCSI,
+	ASD_DEVICE_PROTOCOL_ATA,
+	ASD_DEVICE_PROTOCOL_SMP
+} DEVICE_PROTOCOL_TYPE;
+
+/*
+ * The transport layer can be thought of as the frame which is used to send
+ * to a device of type DEVICE_PROTOCOL that supports the COMMAND_SET_TYPE
+ * command set.
+ */
+typedef enum {
+	ASD_TRANSPORT_UNKNOWN,
+	ASD_TRANSPORT_SSP,
+	ASD_TRANSPORT_SMP,
+	ASD_TRANSPORT_STP,
+	ASD_TRANSPORT_ATA
+} TRANSPORT_TYPE;
+
+/* 
+ * The management layer deals with issues of routing.
+ */
+typedef enum {
+	ASD_DEVICE_NONE,
+	ASD_DEVICE_FANOUT_EXPANDER,
+	ASD_DEVICE_EDGE_EXPANDER,
+	ASD_DEVICE_END,
+	ASD_DEVICE_UNKNOWN
+} MANAGEMENT_TYPE;
+
+/*
+ * The link layer refers to the link that is connected to the initiator.
+ */
+typedef enum {
+	ASD_LINK_UNKNOWN,
+	ASD_LINK_SAS,
+	ASD_LINK_SATA,
+	ASD_LINK_GPIO,
+	ASD_LINK_I2C
+} LINK_TYPE;
+
+typedef union asd_cmd *asd_io_ctx_t;
+
+/* Discovery include file */
+#include "adp94xx_discover.h"
+
+/* HWI include file */
+#include "adp94xx_hwi.h"
+
+/*************************** Device Data Structures ***************************/
+/*
+ * A per probed device structure used to deal with some error recovery
+ * scenarios that the Linux mid-layer code just doesn't know how to
+ * handle.  The structure allocated for a device only becomes persistent
+ * after a successfully completed inquiry command to the target when
+ * that inquiry data indicates a lun is present.
+ */
+typedef enum {
+	ASD_DEV_UNCONFIGURED	 = 0x0001,
+	ASD_DEV_FREEZE_TIL_EMPTY = 0x0002, /* Freeze until active is empty */
+	ASD_DEV_TIMER_ACTIVE	 = 0x0004, /* Our timer is active */
+	ASD_DEV_ON_RUN_LIST	 = 0x0008, /* Queued to be run later */
+	ASD_DEV_Q_BASIC		 = 0x0010, /* Allow basic device queuing */
+	ASD_DEV_Q_TAGGED	 = 0x0020, /* Allow full SCSI2 cmd queueing */
+	ASD_DEV_SLAVE_CONFIGURED = 0x0040, /* Device has been configured. */
+	ASD_DEV_DESTROY_WAS_ACTIVE = 0x0080, /* Device has active IO(s) when
+						the ITNL timer expired. */
+	ASD_DEV_DPC_ACTIVE	= 0x0100   /* There is an active DPC task,*/
+} asd_dev_flags;
+
+struct asd_target;
+struct asd_device {
+	struct list_head 	 links;
+	struct list_head	 busyq;
+	/*
+	 * The number of transactions currently queued to the device.
+	 */
+	int			 active;
+	/*
+	 * The currently allowed number of transactions that can be queued to
+	 * the device.  Must be signed for conversion from tagged to untagged
+	 * mode where the device may have more than one outstanding active 
+	 * transaction.
+	 */
+	int			 openings;
+	/*
+	 * A positive count indicates that this device's queue is halted.
+	 */
+	u_int			 qfrozen;
+	/*
+	 * Cumulative command counter.
+	 */
+	u_long			 commands_issued;
+	/*
+	 * The number of tagged transactions when running at our current 
+	 * opening level that have been successfully received by this 
+	 * device since the last QUEUE FULL.
+	 */
+	u_int			 tag_success_count;
+#define ASD_TAG_SUCCESS_INTERVAL 50
+
+	asd_dev_flags		 flags;
+	/*
+	 * Per device timer and task.
+	 */
+	struct timer_list	 timer;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)	
+	struct tq_struct	 taskq;
+#else
+	struct work_struct	 workq;
+#endif	
+	/*
+	 * The high limit for the tags variable.
+	 */
+	u_int			 maxtags;
+	/*
+	 * The computed number of tags outstanding
+	 * at the time of the last QUEUE FULL event.
+	 */
+	u_int			 tags_on_last_queuefull;
+	/*
+	 * How many times we have seen a queue full with the same 
+	 * number of tags.  This is used to stop our adaptive queue depth 
+	 * algorithm on devices with a fixed number of tags.
+	 */
+	u_int			 last_queuefull_same_count;
+#define ASD_LOCK_TAGS_COUNT 50
+
+	/* 
+	 * Device mapping path for the OS.
+	 * This is a duplicate of info in scsi_device and
+	 * should be discarded soon.
+	 */
+	u_int			 ch;
+	u_int			 id;
+	u_int			 lun;
+	uint8_t			 saslun[SAS_LUN_LEN];
+	Scsi_Device	       	*scsi_device;
+	struct asd_target	*target;
+#ifdef MULTIPATH_IO
+	struct asd_target	*current_target;
+#endif
+};
+
+typedef enum {
+	ASD_TARG_FLAGS_NONE		= 0x0000,
+	ASD_TARG_IN_RECOVERY		= 0x0001,
+	ASD_TARG_ONLINE			= 0x0002,
+	ASD_TARG_RESEEN			= 0x0004,
+	ASD_TARG_HOT_REMOVED		= 0x0008,
+	ASD_TARG_HOT_ADDED		= 0x0010,
+	ASD_TARG_NEEDS_MAP		= 0x0020,
+	ASD_TARG_MAPPED			= 0x0040,
+	ASD_TARG_MAP_BOOT		= 0x0080
+} asd_targ_flags;
+
+/* 
+ * Contains pertinent fields needed to generete a hardware DDB.
+ */  
+struct asd_ddb_data {
+	uint8_t			sas_addr[SAS_ADDR_LEN];
+	uint8_t			hashed_sas_addr[HASHED_SAS_ADDR_LEN];
+	uint8_t			conn_rate;
+	uint16_t		itnl_const;
+	/* Index to DDB entry. */
+	uint16_t		conn_handle;
+	uint16_t		sister_ddb;
+	/*
+	 * Indicates whether the device port protocol is SSP, STP, SMP, 
+	 * SATA direct attched or SATA Port Multi. This will be used when
+	 * setting value for OPEN field.
+	 */   
+	uint8_t			attr;
+	/*
+	 * OPEN bit will be set if the device port is connected by
+	 * SSP, STP or SMP. In addition for STP, SUPPORT AFFILIATION and 
+	 * STP AFFLIATION policy need to be set. 
+	 * Otherwise, for SATA direct attached or SATA Port Multi, OPEN bit
+ 	 * shall not be set.  
+	 */  
+	uint8_t			open_affl; 	
+	/*
+	 * Initial FIS status.
+	 */
+	uint8_t			sata_status;
+};
+
+#define FIS_LENGTH		20
+
+/*
+ * Defines for the features_state member
+ */
+#define SATA_USES_DMA			0x0001
+#define SATA_USES_48BIT			0x0002
+#define SATA_USES_QUEUEING		0x0004
+#define SATA_USES_WRITE_FUA		0x0008
+#define SATA_USES_REMOVABLE		0x0010
+#define SATA_USES_WRITE_BUFFER		0x0020
+#define SATA_USES_READ_BUFFER		0x0040
+#define SATA_USES_WRITE_CACHE		0x0080
+#define SATA_USES_READ_AHEAD		0x0100
+#define SATA_USES_SMART			0x0200
+#define SATA_USES_UDMA			0x0400
+
+/*
+ * Defines for the features_enabled member
+ */
+#define WRITE_CACHE_FEATURE_ENABLED	0x0001
+#define READ_AHEAD_FEATURE_ENABLED	0x0002
+#define SMART_FEATURE_ENABLED		0x0004
+#define NEEDS_XFER_SETFEATURES		0x0008
+
+int
+asd_sata_identify_build(
+struct asd_softc	*asd,
+struct asd_target	*target,
+struct scb		*scb
+);
+
+// ----------------------------------------------------------------------------
+
+/*
+ * For devices supporting the SCSI command set
+ */
+struct asd_scsi_command_set {
+	unsigned			num_luns;
+	uint32_t			flags;
+	uint64_t			*luns;
+	uint8_t				*ident;
+	unsigned			ident_len;
+	uint8_t				*inquiry;
+};
+
+struct asd_smp_command_set {
+	struct SMPResponseReportManufacturerInfo
+					manufacturer_info;
+};
+
+/*
+ * For devices supporting the ATA command set
+ */
+struct asd_ata_command_set {
+	/*
+	 * There are a few differences in the structures for the data that
+	 * is returned by IDENTIFY and PACKET IDENTIFY.  We are using the
+	 * same structure for both ATA and ATAPI.
+	 */
+	struct hd_driveid		adp_hd_driveid;
+
+	/*
+	 * These members are in the command set structure because they are
+	 * deriviced by, or control features and functions specified in the
+	 * adp_hd_driveid struture.
+	 */
+	unsigned			features_state;
+	unsigned			features_enabled;
+	unsigned			dma_mode_level;
+};
+
+/*
+ * For devices supporting the ATAPI command set
+ */
+struct asd_atapi_command_set {
+	/*
+	 * There are a few differences in the structures for the data that
+	 * is returned by IDENTIFY and PACKET IDENTIFY.  We are using the
+	 * same structure for both ATA and ATAPI.
+	 */
+	struct hd_driveid		adp_hd_driveid;
+
+	/*
+	 * These members are in the command set structure because they are
+	 * deriviced by, or control features and functions specified in the
+	 * adp_hd_driveid struture.
+	 */
+	unsigned			features_state;
+	unsigned			features_enabled;
+	unsigned			dma_mode_level;
+};
+
+/*
+ * These are members that are specific to a specific type of command set.
+ */
+union asd_command_set {
+	struct asd_scsi_command_set	scsi_command_set;
+	struct asd_ata_command_set	ata_command_set;
+	struct asd_atapi_command_set	atapi_command_set;
+	struct asd_smp_command_set	smp_command_set;
+};
+
+#define ata_cmdset	command_set.ata_command_set
+#define scsi_cmdset	command_set.scsi_command_set
+#define atapi_cmdset	command_set.atapi_command_set
+#define smp_cmdset	command_set.smp_command_set
+
+
+// ----------------------------------------------------------------------------
+
+struct asd_ata_device_protocol {
+	uint8_t				initial_fis[FIS_LENGTH];
+};
+
+union asd_device_protocol {
+	struct asd_ata_device_protocol	ata_device_protocol;
+};
+
+/*
+ * Defines for the menagement_flags member
+ */
+#define DEVICE_SET_ROOT		0x0001
+
+struct asd_target {
+	/*
+	 * A positive count indicates that this
+	 * target's queue is halted.
+	 */
+	u_int			  qfrozen;
+
+	/*
+	 * XXX Use hash table for sparse 8byte lun support???
+	 */
+	struct asd_device	 *devices[ASD_MAX_LUNS];
+	u_int			  target;
+	int			  refcount;
+	struct asd_softc	 *softc;
+	asd_targ_flags	  	  flags;
+	struct asd_domain	 *domain;
+
+	/*
+	 * Per target timer.
+	 */
+	struct timer_list	  timer;
+
+	/*
+	 * Command Set Layer (SCSI, ATAPI, ATA, SMP)
+	 * --------------------------------------------------------
+	 */
+	COMMAND_SET_TYPE		command_set_type;
+	union asd_command_set		command_set;
+
+	/*
+	 * Device Protocol Layer (SCSI, ATA, SMP)
+	 * --------------------------------------------------------
+	 */
+	DEVICE_PROTOCOL_TYPE		device_protocol_type;
+	union asd_device_protocol	device_protocol;
+
+	/*
+	 * Transport Layer (SSP, SMP, STP, FIS)
+	 * --------------------------------------------------------
+	 */
+	TRANSPORT_TYPE			transport_type;
+
+	/*
+	 * Management Layer (DIRECT, EXPANDER, FANOUT)
+	 * --------------------------------------------------------
+	 */
+	MANAGEMENT_TYPE			management_type;
+	unsigned			num_phys;
+	unsigned			num_route_indexes;
+	uint16_t			*route_indexes;
+	struct SMPResponseDiscover	*Phy;
+	uint8_t				*RouteTable;
+	uint32_t			management_flags;
+
+	/*
+	 * Our parent SAS device (e.g. expander)
+	 * in this SAS domain.
+	 */
+	struct asd_target	 	*parent;
+	/*
+	 * Our children SAS devices (if not end device)
+	 * in this SAS domain.
+	 */
+	struct list_head	  	children;
+	/*
+	 * List of targets that are connected to a parent 
+	 * expander (children)
+	 */
+	struct list_head	  	siblings;
+	/*
+	 * List links for chaining together all targets
+	 * in this SAS domain on to the port object.
+	 */
+	struct list_head	  	all_domain_targets;
+	/*
+	 * List links of targets that need to be validated
+	 * because they have been hot-added or hot-removed.
+	 */
+	struct list_head	  	validate_links;   
+	/*
+	 * List links of target structures that map to the
+	 * same physical sevice.
+	 */
+	struct list_head	  	multipath;   
+
+	/*
+	 * Link Layer (SAS, SATA, GPIO, I2C)
+	 * --------------------------------------------------------
+	 */
+	LINK_TYPE			link_type;
+	struct asd_ddb_data	  	ddb_profile;
+
+	/*
+	 * Controller port used to route to
+	 * this device.
+	 */
+	struct asd_port		 	*src_port;
+};
+
+struct asd_domain {
+	/*
+	 * XXX Use Hash table to support
+	 * large/sparse target configurations.
+	 */
+	struct asd_target 	*targets[ASD_MAX_TARGETS];
+	u_int			 channel_mapping;
+	u_int			 refcount;
+};
+
+typedef enum {
+	ASD_DISCOVERY_ACTIVE	= 0x01,
+	ASD_DISCOVERY_INIT	= 0x02,
+	ASD_DISCOVERY_SHUTDOWN	= 0x04,
+	ASD_RECOVERY_SHUTDOWN	= 0x08,
+#ifdef ASD_EH_SIMULATION
+	ASD_EH_SIMUL_SHUTDOWN	= 0x10
+#endif		
+} asd_platform_flags;
+
+struct asd_scb_platform_data {
+	struct asd_target 	*targ;
+	struct asd_device	*dev;
+	asd_scb_flags	 	 flags;
+	dma_addr_t		 buf_busaddr;
+	/*
+	 * Timeout timer tick, used to timeout internal cmd that is 
+         * sent to the sequencer or target.
+	 */	 
+	struct timer_list	 timeout;	 
+};
+
+struct asd_platform_data {
+	spinlock_t		  spinlock;
+	struct Scsi_Host	 *scsi_host;
+
+	/*
+	 * Channel to Domain Mapping.
+	 */
+	struct asd_domain	**domains;
+	u_int			  num_domains;
+
+	/*
+	 * Queued device I/O scheduling support.
+	 */
+	struct list_head	  pending_os_scbs;
+	struct list_head 	  device_runq;
+	struct tasklet_struct	  runq_tasklet;
+	struct tasklet_struct	  unblock_tasklet;
+	u_int			  qfrozen;
+
+	/*
+	 * Completion Ordering Queue.
+	 */
+	struct list_head 	  completeq;
+
+	/*
+	 * LRU target DDB ageing queue.  Used to
+	 * select candidates for DDB recycling.
+	 * LFU would be a better scheme and could
+	 * be achieved in O(logN) using a heap
+	 * queue, but keep this simple for now.
+	 */
+	struct list_head 	  lru_ddb_q;
+
+	/*
+	 * Discovery Thread Support.
+	 */
+	pid_t			  discovery_pid;
+	struct semaphore	  discovery_sem;
+	struct semaphore	  discovery_ending_sem;
+
+	/*
+	 * Error Recovery Thread Support.
+	 */
+	pid_t			  ehandler_pid;
+	struct semaphore	  ehandler_sem;
+	struct semaphore	  ehandler_ending_sem;
+
+#ifdef ASD_EH_SIMULATION
+	/*
+	 * EH Recovery Simulation thread.
+         */
+	pid_t			  eh_simul_pid;
+	struct semaphore	  eh_simul_sem;
+#endif
+	
+	/*
+	 * Wait Queue.
+         */	
+	wait_queue_head_t	  waitq;
+
+	/*
+	 * Mid-layer error recovery entry point semaphore.
+	 */
+	struct semaphore	  eh_sem;
+	struct semaphore	  wait_sem;
+
+	asd_platform_flags  	  flags;
+};
+
+/*
+ * Internal data structures.
+ */
+typedef struct asd_init_status {
+	uint8_t		asd_notifier_enabled;
+	uint8_t		asd_pci_registered;
+	uint8_t		asd_irq_registered;
+	uint8_t		asd_ioctl_registered;
+	uint8_t		asd_init_state;
+} asd_init_status_t;
+
+
+/* SMP Locking mechanism routines */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK))
+#define	SCSI_ML_HAS_HOST_LOCK	1
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#define asd_assign_host_lock(asd)				\
+	scsi_assign_lock((asd)->platform_data->scsi_host,	\
+			 &(asd)->platform_data->spinlock)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21)		\
+		&& defined(ASD_RED_HAT_LINUX_KERNEL)
+#define asd_assign_host_lock(asd)				\
+do {								\
+	(asd)->platform_data->scsi_host->host_lock =		\
+	    &(asd)->platform_data->spinlock;			\
+} while (0)
+#else
+#define asd_assign_host_lock(asd)				\
+do {								\
+	(asd)->platform_data->scsi_host->lock =			\
+	    &(asd)->platform_data->spinlock;			\
+} while (0)
+#endif
+#else	/* !SCSI_ML_HAS_HOST_LOCK */
+#define	SCSI_ML_HAS_HOST_LOCK	0
+#define asd_assign_host_lock(asd)
+#endif	/* !SCSI_ML_HAS_HOST_LOCK */
+
+/* OS utility wrappers */
+#define asd_alloc_mem(size, flags)	kmalloc(size, flags)
+#define asd_free_mem(ptr)		kfree(ptr)
+ 
+/* Debug Logging macro */
+
+#define ASD_DBG_INIT		0x01
+#define ASD_DBG_INFO		0x02
+#define ASD_DBG_RUNTIME		0x10
+#define ASD_DBG_ISR		0x20
+#define ASD_DBG_ERROR		0x40
+
+
+/* Debug mask to control the Debug Level printout. */
+extern u_int	debug_mask;
+
+#ifdef ASD_DEBUG
+
+#define asd_log(debug_level, fmt, args...)			\
+do {								\
+	if ((debug_level & debug_mask) != 0) {			\
+		printk("%s(%d) : ", __FUNCTION__, __LINE__);	\
+		printk(fmt, ##args);				\
+	}							\
+} while (0)
+
+/* For initial debugging purpose only. */
+#define IN	0
+#define OUT	1
+#define LINE	2
+
+#define ASD_DBG_FUNC(x)							\
+do {									\
+	if (x == IN) {							\
+		printk("+++ Entering Function: %s:%d.\n", __FUNCTION__, \
+			__LINE__);					\
+	} else if (x == OUT) {						\
+		printk("--- Exiting Function: %s:%d.\n", __FUNCTION__,  \
+			__LINE__);					\
+	} else {							\
+		printk("*** %s (%d).\n", __FUNCTION__, __LINE__);	\
+	}								\
+} while (0)
+
+#if KDB_ENABLE
+#define ASSERT(expression)						\
+	if (!(expression)) {						\
+		printk("assertion failed: %s, file: %s, line: %d\n",	\
+			#expression, __FILE__, __LINE__);		\
+		KDB_ENTER();						\
+	}
+#else
+#define ASSERT(expression)						\
+	if (!(expression)) {						\
+		panic("assertion failed: %s, file: %s, line: %d\n",	\
+			#expression, __FILE__, __LINE__);		\
+	}
+#endif
+
+#else
+
+#define asd_log(debug_level, fmt, args...)	/**/
+#define ASD_DBG_FUNC(x)				/**/
+
+#define ASSERT(expression)
+
+#endif /* ASD_DEBUG */ 
+
+#define asd_print(fmt, args...)		printk(fmt, ##args)
+
+#define ASD_DUMP_REG(reg)		/**/
+
+#ifndef IRQ_RETVAL
+typedef void	irqreturn_t;
+#define IRQ_RETVAL(x)	/**/
+#endif
+
+/*
+ * SCSI Status Byte
+ */
+#define	SCSI_STATUS_OK			0x00
+#define	SCSI_STATUS_CHECK_COND		0x02
+#define	SCSI_STATUS_COND_MET		0x04
+#define	SCSI_STATUS_BUSY		0x08
+#define SCSI_STATUS_INTERMED		0x10
+#define SCSI_STATUS_INTERMED_COND_MET	0x14
+#define SCSI_STATUS_RESERV_CONFLICT	0x18
+#define SCSI_STATUS_CMD_TERMINATED	0x22	/* Obsolete in SAM-2 */
+#define SCSI_STATUS_QUEUE_FULL		0x28
+#define SCSI_STATUS_ACA_ACTIVE		0x30
+#define SCSI_STATUS_TASK_ABORTED	0x40
+
+struct scsi_sense_data
+{
+	uint8_t error_code;
+#define	SSD_ERRCODE			0x7F
+#define		SSD_CURRENT_ERROR	0x70
+#define		SSD_DEFERRED_ERROR	0x71
+#define	SSD_ERRCODE_VALID	0x80	
+	uint8_t segment;
+	uint8_t flags;
+#define	SSD_KEY				0x0F
+#define		SSD_KEY_NO_SENSE	0x00
+#define		SSD_KEY_RECOVERED_ERROR	0x01
+#define		SSD_KEY_NOT_READY	0x02
+#define		SSD_KEY_MEDIUM_ERROR	0x03
+#define		SSD_KEY_HARDWARE_ERROR	0x04
+#define		SSD_KEY_ILLEGAL_REQUEST	0x05
+#define		SSD_KEY_UNIT_ATTENTION	0x06
+#define		SSD_KEY_DATA_PROTECT	0x07
+#define		SSD_KEY_BLANK_CHECK	0x08
+#define		SSD_KEY_Vendor_Specific	0x09
+#define		SSD_KEY_COPY_ABORTED	0x0a
+#define		SSD_KEY_ABORTED_COMMAND	0x0b		
+#define		SSD_KEY_EQUAL		0x0c
+#define		SSD_KEY_VOLUME_OVERFLOW	0x0d
+#define		SSD_KEY_MISCOMPARE	0x0e
+#define		SSD_KEY_RESERVED	0x0f			
+#define	SSD_ILI		0x20
+#define	SSD_EOM		0x40
+#define	SSD_FILEMARK	0x80
+	uint8_t info[4];
+	uint8_t extra_len;
+	uint8_t cmd_spec_info[4];
+	uint8_t add_sense_code;
+	uint8_t add_sense_code_qual;
+	uint8_t fru;
+	uint8_t sense_key_spec[3];
+#define	SSD_SCS_VALID		0x80
+#define SSD_FIELDPTR_CMD	0x40
+#define SSD_BITPTR_VALID	0x08
+#define SSD_BITPTR_VALUE	0x07
+#define SSD_MIN_SIZE 18
+	uint8_t extra_bytes[14];
+#define SSD_FULL_SIZE sizeof(struct scsi_sense_data)
+};
+
+static inline void	scsi_ulto2b(uint32_t val, uint8_t *bytes);
+static inline void	scsi_ulto3b(uint32_t val, uint8_t *bytes);
+static inline void	scsi_ulto4b(uint32_t val, uint8_t *bytes);
+static inline uint32_t	scsi_2btoul(uint8_t *bytes);
+static inline uint32_t	scsi_3btoul(uint8_t *bytes);
+static inline int32_t	scsi_3btol(uint8_t *bytes);
+static inline uint32_t 	scsi_4btoul(uint8_t *bytes);
+
+static inline void
+scsi_ulto2b(uint32_t val, uint8_t *bytes)
+{
+	bytes[0] = (val >> 8) & 0xff;
+	bytes[1] = val & 0xff;
+}
+
+static inline void
+scsi_ulto3b(uint32_t val, uint8_t *bytes)
+{
+	bytes[0] = (val >> 16) & 0xff;
+	bytes[1] = (val >> 8) & 0xff;
+	bytes[2] = val & 0xff;
+}
+
+static inline void
+scsi_ulto4b(uint32_t val, uint8_t *bytes)
+{
+	bytes[0] = (val >> 24) & 0xff;
+	bytes[1] = (val >> 16) & 0xff;
+	bytes[2] = (val >> 8) & 0xff;
+	bytes[3] = val & 0xff;
+}
+
+static inline uint32_t
+scsi_2btoul(uint8_t *bytes)
+{
+	uint32_t rv;
+
+	rv = (bytes[0] << 8) |
+	     bytes[1];
+	return (rv);
+}
+
+static inline uint32_t
+scsi_3btoul(uint8_t *bytes)
+{
+	uint32_t rv;
+
+	rv = (bytes[0] << 16) |
+	     (bytes[1] << 8) |
+	     bytes[2];
+	return (rv);
+}
+
+static inline int32_t 
+scsi_3btol(uint8_t *bytes)
+{
+	uint32_t rc = scsi_3btoul(bytes);
+ 
+	if (rc & 0x00800000)
+		rc |= 0xff000000;
+
+	return (int32_t) rc;
+}
+
+static inline uint32_t
+scsi_4btoul(uint8_t *bytes)
+{
+	uint32_t rv;
+
+	rv = (bytes[0] << 24) |
+	     (bytes[1] << 16) |
+	     (bytes[2] << 8) |
+	     bytes[3];
+	return (rv);
+}
+
+/*********************** Transaction Access Wrappers **************************/
+static inline void	asd_cmd_set_host_status(Scsi_Cmnd *cmd, u_int);
+static inline void 	asd_cmd_set_scsi_status(Scsi_Cmnd *cmd, u_int);
+static inline uint32_t 	asd_cmd_get_host_status(Scsi_Cmnd *cmd);
+static inline uint32_t 	asd_cmd_get_scsi_status(Scsi_Cmnd *cmd);
+static inline void 	asd_freeze_scb(struct scb *scb);
+static inline void 	asd_unfreeze_scb(struct scb *scb);
+
+#define CMD_DRIVER_STATUS_MASK	0xFF000000
+#define CMD_DRIVER_STATUS_SHIFT	24
+#define CMD_HOST_STATUS_MASK	0x00FF0000
+#define CMD_HOST_STATUS_SHIFT	16
+#define CMD_MSG_STATUS_MASK	0x0000FF00
+#define CMD_MSG_STATUS_SHIFT	8
+#define CMD_SCSI_STATUS_MASK	0x000000FF
+#define CMD_SCSI_STATUS_SHIFT	0
+#define CMD_REQ_INPROG		0xFF
+
+static inline
+void asd_cmd_set_driver_status(Scsi_Cmnd *cmd, u_int status)
+{
+	cmd->result &= ~CMD_DRIVER_STATUS_MASK;
+	cmd->result |= status << CMD_DRIVER_STATUS_SHIFT;
+}
+
+static inline
+void asd_cmd_set_host_status(Scsi_Cmnd *cmd, u_int status)
+{
+	cmd->result &= ~CMD_HOST_STATUS_MASK;
+	cmd->result |= status << CMD_HOST_STATUS_SHIFT;
+}
+
+static inline
+void asd_cmd_set_scsi_status(Scsi_Cmnd *cmd, u_int status)
+{
+	cmd->result &= ~CMD_SCSI_STATUS_MASK;
+	cmd->result |= status;
+}
+
+static inline
+uint32_t asd_cmd_get_host_status(Scsi_Cmnd *cmd)
+{
+	return ((cmd->result & CMD_HOST_STATUS_MASK) >> CMD_HOST_STATUS_SHIFT);
+}
+
+static inline
+uint32_t asd_cmd_get_scsi_status(Scsi_Cmnd *cmd)
+{
+	return ((cmd->result & CMD_SCSI_STATUS_MASK) >> CMD_SCSI_STATUS_SHIFT);
+}
+
+static inline void
+asd_freeze_scb(struct scb *scb)
+{
+	if ((scb->flags & SCB_DEV_QFRZN) == 0) {
+		scb->flags |= SCB_DEV_QFRZN;
+		scb->platform_data->dev->qfrozen++;
+        }
+}
+
+static inline void
+asd_unfreeze_scb(struct scb *scb)
+{
+	if ((scb->flags & SCB_DEV_QFRZN) != 0) {
+		scb->flags &= ~SCB_DEV_QFRZN;
+		scb->platform_data->dev->qfrozen--;
+        }
+}
+
+// TODO - where is right spot for these???
+typedef enum {
+	ASD_COMMAND_BUILD_OK,
+	ASD_COMMAND_BUILD_FAILED,
+	ASD_COMMAND_BUILD_FINISHED
+} ASD_COMMAND_BUILD_STATUS;
+
+ASD_COMMAND_BUILD_STATUS 
+	asd_setup_data(struct asd_softc *asd, struct scb *scb, Scsi_Cmnd *cmd);
+
+DISCOVER_RESULTS
+	asd_do_discovery(struct asd_softc *asd, struct asd_port *port);
+
+DISCOVER_RESULTS
+	asd_run_state_machine(struct state_machine_context *sm_contextp);
+
+int	asd_platform_alloc(struct asd_softc *asd);
+void	asd_platform_free(struct asd_softc *asd);
+
+struct asd_scb_platform_data *
+	asd_alloc_scb_platform_data(struct asd_softc *asd);
+void	asd_free_scb_platform_data(struct asd_softc *asd,
+				   struct asd_scb_platform_data *pdata);
+void	asd_unmap_scb(struct asd_softc *asd, struct scb *scb);
+void	asd_recover_cmds(struct asd_softc *asd);
+void	asd_hwi_release_sata_spinup_hold(struct asd_softc *asd,
+					 struct asd_phy	*phy);
+
+struct asd_target *
+	asd_alloc_target(struct asd_softc *asd, struct asd_port *src_port);
+void	asd_free_target(struct asd_softc *asd, struct asd_target *targ);
+int	asd_map_target(struct asd_softc *asd, struct asd_target *targ);
+
+struct asd_device *
+	asd_alloc_device(struct asd_softc *asd, struct asd_target *targ, 
+			 u_int ch, u_int id, u_int lun);
+void	asd_free_device(struct asd_softc *asd, struct asd_device *dev);
+struct asd_device *
+	asd_get_device(struct asd_softc *asd, u_int ch, u_int id,
+		       u_int lun, int alloc);
+void	asd_remap_device(struct asd_softc *asd, struct asd_target *target,
+			 struct asd_target *multipath_target);
+void	asd_timed_run_dev_queue(u_long arg);
+void	asd_destroy_device(void *arg);
+
+#ifndef list_for_each_entry_safe
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against 
+ *                              removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+#endif
+
+#ifndef list_for_each_entry
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head); 					\
+	     pos = list_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next))
+
+#endif
+
+#define list_move_all(to_list, from_list)				\
+	if (!list_empty(from_list)) {					\
+		(to_list)->next = (from_list)->next;			\
+		(to_list)->prev = (from_list)->prev;			\
+		(from_list)->next->prev = to_list;			\
+		(from_list)->prev->next = to_list;			\
+		INIT_LIST_HEAD(from_list);				\
+	} else {							\
+		INIT_LIST_HEAD(to_list);				\
+	}
+
+#define list_copy(to_list, from_list)					\
+do {									\
+	(to_list)->next = (from_list)->next;				\
+	(to_list)->prev = (from_list)->prev;				\
+} while (0)
+
+#endif /* ADP94XX_OSM_H */ 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [ANNOUNCE] Adaptec SAS/SATA device driver [17/27]
  2005-02-17 17:37 [ANNOUNCE] Adaptec SAS/SATA device driver [17/27] Luben Tuikov
@ 2005-02-17 21:08 ` Andi Kleen
  2005-02-17 21:16   ` Luben Tuikov
  0 siblings, 1 reply; 4+ messages in thread
From: Andi Kleen @ 2005-02-17 21:08 UTC (permalink / raw)
  To: Luben Tuikov; +Cc: linux-scsi

Luben Tuikov <luben_tuikov@adaptec.com> writes:


> +/********************************** Misc Macros *******************************/

[... lots of code...]

What are they all good for? As far as I can see every one of them
duplicates or wraps something Linux already has.

How about you just use the native Linux functions directly?

 +
> +#if KDB_ENABLE
> +#define ASSERT(expression)						\
> +	if (!(expression)) {						\
> +		printk("assertion failed: %s, file: %s, line: %d\n",	\
> +			#expression, __FILE__, __LINE__);		\
> +		KDB_ENTER();						\
> +	}
> +#else
> +#define ASSERT(expression)						\
> +	if (!(expression)) {						\
> +		panic("assertion failed: %s, file: %s, line: %d\n",	\
> +			#expression, __FILE__, __LINE__);		\
> +	}
> +#endif

That's called BUG_ON in Linux land.

> +#ifndef list_for_each_entry_safe

[...]

Such compat code does not really belong into a 2.6 driver.

> +
> +#define list_move_all(to_list, from_list)				\

[...]

And this should be put into list.h

-Andi

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [ANNOUNCE] Adaptec SAS/SATA device driver [17/27]
  2005-02-17 21:08 ` Andi Kleen
@ 2005-02-17 21:16   ` Luben Tuikov
  2005-02-17 22:03     ` Jeff Garzik
  0 siblings, 1 reply; 4+ messages in thread
From: Luben Tuikov @ 2005-02-17 21:16 UTC (permalink / raw)
  To: Andi Kleen; +Cc: linux-scsi

On 02/17/05 16:08, Andi Kleen wrote:
> Luben Tuikov <luben_tuikov@adaptec.com> writes:
> 
> 
> 
>>+/********************************** Misc Macros *******************************/
> 
> 
> [... lots of code...]
> 
> What are they all good for? As far as I can see every one of them
> duplicates or wraps something Linux already has.
> 
> How about you just use the native Linux functions directly?
> 
>  +
> 
>>+#if KDB_ENABLE
>>+#define ASSERT(expression)						\
>>+	if (!(expression)) {						\
>>+		printk("assertion failed: %s, file: %s, line: %d\n",	\
>>+			#expression, __FILE__, __LINE__);		\
>>+		KDB_ENTER();						\
>>+	}
>>+#else
>>+#define ASSERT(expression)						\
>>+	if (!(expression)) {						\
>>+		panic("assertion failed: %s, file: %s, line: %d\n",	\
>>+			#expression, __FILE__, __LINE__);		\
>>+	}
>>+#endif
> 
> 
> That's called BUG_ON in Linux land.

Hi Andi,

Yes I agree.  As I didn't write this code I hadn't noticed this.
 
> 
>>+#ifndef list_for_each_entry_safe
> 
> 
> [...]
> 
> Such compat code does not really belong into a 2.6 driver.

Yes, that's true.  The driver was written to compile for 2.4 as well
as for 2.6.
 
> 
>>+
>>+#define list_move_all(to_list, from_list)				\
> 
> 
> [...]
> 
> And this should be put into list.h

Yes, I agree.

	Luben

 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [ANNOUNCE] Adaptec SAS/SATA device driver [17/27]
  2005-02-17 21:16   ` Luben Tuikov
@ 2005-02-17 22:03     ` Jeff Garzik
  0 siblings, 0 replies; 4+ messages in thread
From: Jeff Garzik @ 2005-02-17 22:03 UTC (permalink / raw)
  To: Luben Tuikov; +Cc: Andi Kleen, linux-scsi

Luben Tuikov wrote:
> Yes, that's true.  The driver was written to compile for 2.4 as well
> as for 2.6.


Typically what you want to do is target 2.6, and isolate/emulate missing 
functionality in 2.4.x in a compatibility file.  This compatibility 
file/lib would not exist in 2.6 kernel, but you can give it to vendors 
or distros to ship.  An example of this, called "kcompat", can be found 
at http://sourceforge.net/projects/gkernel/

Another approach, which I took with libata, is to design the code such 
that there are minimal differences between 2.4 and 2.6.  Granted, 
though, with the upcoming NCQ and transport class changes, those 
differences increase.

Either way, cross-OS and cross-kernel-version compatibility stuff needs 
to be carefully examined, and as much excised as possible.  After many 
years, we have found that such portions of code often hide bugs.

We _do_ recognize that it's a bit painful for hardware vendors trying to 
support various Linux versions, but if you plan for it up front, the 
pain can be minimized.  I support libata on both 2.4 and 2.6 
concurrently, for example.

Remember, we have all these "weird" requirements because all source code 
merged into the Linux kernel lives on for many years after the 
hardware's end-of-life.  We need to ensure that source code is 
maintain-able even if the hardware vendor abandons a Linux driver.

	Jeff



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-02-17 22:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-17 17:37 [ANNOUNCE] Adaptec SAS/SATA device driver [17/27] Luben Tuikov
2005-02-17 21:08 ` Andi Kleen
2005-02-17 21:16   ` Luben Tuikov
2005-02-17 22:03     ` Jeff Garzik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox