* [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