[PATCH 3/3] New driver mtipx2xx submission

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Part 3

diff -uNr a/drivers/block/mtipx2xx/block.c
b/drivers/block/mtipx2xx/block.c
--- a/drivers/block/mtipx2xx/block.c	1969-12-31 17:00:00.000000000
-0700
+++ b/drivers/block/mtipx2xx/block.c	2011-05-03 12:57:34.000000000
-0600
@@ -0,0 +1,641 @@
+/**********************************************************************
*******
+ *
+ * block.c - Handles the block layer of the Cyclone SSD Block Driver
+ *   Copyright (C) 2009  Integrated Device Technology, Inc.
+ *
+ *  Changes from IDT 1.0.1 are copyright (C) 2010 Micron Technology,
Inc.
+ *
+ *  This file is part of the Cyclone SSD Block Driver, it 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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program;
+ *  if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street,
+ *  Fifth Floor, Boston,
+ *  MA 02110-1301,
+ *  USA.
+ *
+
************************************************************************
****/
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include "mtipx2xx.h"
+
+/**
+ * This layer will manage the allocation and registration of block
devices,
+ * request queuing, and the inter-face into the kernel block layer.
+ * The block layer will also be required to call into the protocol
layer.
+ * Since multiple protocols are supported, the block layer uses a
structure
+ * called PROTOCOL_FUNCS, which is an array of structures that contain
+ * pointers to functions exported by the protocol layers. An example of
the
+ * PROTOCOL_FUNCS table is shown below.
+ * @verbatim
+static PROTOCOL_FUNCS protocol[] = {
+	{
+		.init = ahci_init,
+		.exit = ahci_exit,
+#ifdef CONFIG_PM
+		.suspend = ahci_suspend,
+		.resume = ahci_resume,
+#endif
+		.shutdown = ahci_shutdown,
+		.read = ahci_read,
+		.write = ahci_write,
+		.hwBlkSize = ahci_hard_blksize,
+		.getCapacity = ahci_get_capacity,
+		.getScatterList = ahci_get_scatterList,
+		.ioctl = ahci_ioctl,
+		.sysfsInit = ahci_sysfs_init,
+		.sysfsExit = ahci_sysfs_exit,
+	},
+	{}
+};
+@endverbatim
+ * In the above example only one protocol is supported, AHCI.
+ * The block layer accesses the appropriate array element in the table
by
+ * using the protocol index value that was defined in the pci_device_id
table
+ * and passed to the block layer in the driver private data structure.
+ * This allows the same Block Layer source code to interface to
multiple
+ * protocol layers based on the PCI vendor/device ID of the device.
+ *
+ * All Cyclone devices will utilize the same major device number,
allocated by
+ * the Module Layer, and will support 16 minor device numbers. This
will allow
+ * each Cyclone device to have an entry under /dev for the "full
device" and 15
+ * partitions.
+ * For example, the first Cyclone device detected will have a major/min
+ * device number of 0,0. The first partition on this drive will have a
+ * major/minor device number of 0,1, and so on. The second Cyclone
device will
+ * have the same major device number but its minor device number will
be 16,
+ * the third Cyclone device will have a minor device number of 32, etc.
Cyclone
+ * devices are registered with the kernel block layer as "cyclone",
+ * consequently they appear under /dev as cyclonex where x is a letter
a-z
+ * which is assigned in the order that the drives are detected.
+ * Partitions are referenced as /dev/cyclonexn, where n is the
+ * partition number 1-15.
+ *
+ * The Kernel block layer requires that the following functions be
implemented
+ * by the block device driver.
+ *
+ * - open() - Called when the block device is opened, i.e. mounted,
etc.
+ * This function will perform minimal initialization since there is
really
+ * nothing to do when the device is opened.
+ *
+ * - release() - Called when the block device is closed.
+ *
+ * - ioctl() - Called by the kernel block layer when it receives an
IOCTL
+ * request that it does not understand. This will be the mechanism by
which
+ * the SMART information will be obtained from the device and how
vendor
+ * specific commands will be issued to the device.
+ *
+ * - make_request() - Called by the kernel to process a BIO structure.
+ * This function is the main guts of the block layer. It receives BIO
requests
+ * from the kernel, processes them, and then issues read or writes to
the
+ * protocol layer. Upon completion of a request by the protocol layer
it will
+ * callback into the block layer to complete the transfer. This is the
only
+ * acceptable manner in which a driver layer may call a function that
belongs
+ * to a higher layer. It is also worth noting that this interface will
bypass
+ * the I/O scheduler. No merging or reordering of the BIO's will be
performed.
+ * See the section titled BIO Processing for detaile information on
exactly
+ * how a BIO is handled.
+ *
+ * Additionally, the PCI layer requires that the following management
functions
+ * be implemented in the drivers block layer.
+ *
+ * - block_initialize() - Called by the PCI layer to initialize the
block device
+ * and layer. This function should first call the Protocol Layer
initialization
+ * function. Once that is done, this function will allocate a block
request
+ * queue, inform the kernel of the hardware block size, allocate a
Linux disk
+ * structure, inform the kernel of the drives capacity, and finally add
the new
+ * disk to the system. The hardware block size and drive capacity are
obtained
+ * by calling the hwBlkSize() and getCapacity() functions in the
Protocol Layer,
+ * respectively.
+ *
+ * - block_remove() - Called by the PCI layer to de-initialize the
block device
+ * and layer. This function must remove the block device from the
system before
+ * calling the Protocol Layer exit() function.
+ *
+ * - block_shutdown() - Called by the PCI layer just before the system
halts
+ * during a shutdown. This function should call the protocol layers
shutdown()
+ * function to sync the device before the system is powered off.
+ *
+ * - block_suspend() - Called by the PCI layer during
hibernation/suspend of the
+ * system. This function should call the protocol layers suspend()
function to
+ * change the power state of the device
+ *
+ * - block_resume() - Called by the PCI layer while resuming from
+ * hiberation/suspend of the system. This function should call the
protocol
+ * layers resume() function to change the power state of the device.
+ */
+
+static int rssd_disk_name_format(char *prefix,
+				int index,
+				char *buf,
+				int buflen);
+
+static DEFINE_IDA(rssd_index_ida);
+
+static struct  PROTOCOL_FUNCS	protocol[] = {
+		{
+				.init = ahci_init,
+				.exit = ahci_exit,
+				.suspend = ahci_suspend,
+				.resume = ahci_resume,
+				.shutdown = ahci_shutdown,
+				.read = ahci_read,
+				.write = ahci_write,
+				.hwBlkSize = ahci_hard_blksize,
+				.getCapacity = ahci_get_capacity,
+				.getScatterList = ahci_get_scatterlist,
+				.ioctl = ahci_ioctl,
+				.sysfsInit = ahci_sysfs_init,
+				.sysfsExit = ahci_sysfs_exit,
+		},
+		{}	/* Terminate the list*/
+};
+
+/**
+ * @brief Block layer IOCTL handler.
+ *
+ * @param dev Pointer to the block_device structure.
+ * @param mode ????
+ * @param cmd IOCTL command passed from the user application.
+ * @param arg Argument passed from the user application.
+ *
+ * @retval 0 IOCTL completed successfully.
+ * @retval -ENOTTY IOCTL not supported or invalid driver data structure
pointer.
+ */
+static int block_ioctl(struct block_device *dev,
+			fmode_t mode,
+			unsigned cmd,
+			unsigned long arg)
+{
+	struct driver_data *dd = dev->bd_disk->private_data;
+	int rv = 0;
+
+	if (!dd)
+		return -ENOTTY;
+
+	switch (cmd) {
+	case BLKFLSBUF: /* Flush the device buffers, if it has any. */
+		printk(KERN_INFO "%s: Received BLKFLSBUF\n", __func__);
+		break;
+	default:
+		rv = protocol[dd->protocol].ioctl(dd, cmd, arg);
+	}
+	return rv;
+}
+
+/**
+ * @brief Obtain the geometry of the device.
+ *
+ * You may think that this function is obsolete, but some applications,
+ * fdisk for example still used CHS values. This function describes the
+ * device as having 224 heads and 56 sectors per cylinder. These values
are
+ * chosen so that each cylinder is aligned on a 4KB boundary. Since a
partition
+ * is described in terms of a start and end cylinder this means that
each
+ * partition is also 4KB aligned. Non-aligned partitions adversely
affects
+ * performance.
+ *
+ * @param dev Pointer to the block_device strucutre.
+ * @param geo Pointer to a hd_geometry structure.
+ *
+ * @retval 0 Operation completed successfully.
+ * @retval -ENOTTY An error occurred while reading the drive capacity.
+ */
+static int block_getgeo(struct block_device *dev, struct hd_geometry
*geo)
+{
+	struct driver_data *dd = dev->bd_disk->private_data;
+	sector_t capacity;
+	capacity = protocol[dd->protocol].getCapacity(dd);
+	if (capacity == (sector_t) -1) {
+		printk(KERN_ERR "%s: Could not get drive capacity.\n",
+					__func__);
+		return -ENOTTY;
+	}
+
+	geo->heads = 224;
+	geo->sectors = 56;
+#if BITS_PER_LONG == 64
+	geo->cylinders = capacity / (geo->heads*geo->sectors);
+#else
+	do_div(capacity, (geo->heads*geo->sectors));
+	geo->cylinders = capacity;
+#endif
+	return 0;
+}
+
+/**
+ * @brief Block device operation function.
+ *
+ * This structure contains pointers to the functions required by the
block
+ * layer.
+ */
+static const struct block_device_operations blockOps = {
+		/**
+		 * Called to process an IOCTL for the block device.
+		 */
+		.ioctl		= block_ioctl,
+		/**
+		 * Called to obtain the drives geometry.
+		 */
+		.getgeo		= block_getgeo,
+		/**
+		 * Owner of this structure.
+		 */
+		.owner		= THIS_MODULE
+};
+
+/**
+ * @brief BIO completion function.
+ *
+ * This function is called by the protocol layer to complete a BIO
transfer.
+ * A Pointer to this function is passed into the protocol layer
read/write
+ * functions as the completion callback.
+ *
+ * @param bio Pointer to the BIO that has completed.
+ * @param status Completion status, 0 = success, non-zero = error.
+ *
+ * @return This function always returns 0.
+ */
+static int complete_bio(struct bio *bio, int status)
+{
+	bio_endio(bio, status);
+	return 0;
+}
+
+
+#define bio_rw_flagged(bio, flag) ((bio)->bi_rw & flag)
+
+/**
+ * @brief Block layer make request function.
+ *
+ * This function is called by the kernel to process a BIO for
+ * the Cyclone device.
+ *
+ * @param queue Pointer to the request queue. Unused other than to
obtain the driver data structure.
+ * @param bio Pointer to the BIO.
+ *
+ * @return This function always returns 0.
+ */
+static int make_request(struct request_queue *queue, struct bio *bio)
+{
+	struct driver_data *dd = queue->queuedata;
+	struct scatterlist *sg;
+	struct bio_vec *bvec;
+	int nents = 0;
+	int tag = 0;
+	if (unlikely(!bio_has_data(bio))) {
+		blk_queue_flush(queue, 0);
+		bio_endio(bio, 0);
+		return 0;
+	}
+
+	sg = protocol[dd->protocol].getScatterList(dd, &tag);
+	if (likely(sg != NULL)) {
+		blk_queue_bounce(queue, &bio);
+
+		if (unlikely((bio)->bi_vcnt > MAX_SG)) {
+			printk(KERN_WARNING "Maximum number of scatter
list entries exceeded\n");
+			bio_io_error(bio);
+			return 0;
+		}
+
+		/*
+		 * Create the scatter list for this bio.
+		 */
+		bio_for_each_segment(bvec, bio, nents)
+		{
+			sg_set_page(&sg[nents],
+					bvec->bv_page,
+					bvec->bv_len,
+					bvec->bv_offset);
+		}
+
+		/*
+		 * Issue the read or write to the protocol layer.
+		 */
+		if (bio_data_dir(bio) == WRITE) {
+			protocol[dd->protocol].write(dd,/* Driver data
*/
+					/* Start sector */
+						bio->bi_sector,
+					/* # sectors to write */
+						bio_sectors(bio),
+					/*entries in the scatterlist*/
+						nents,
+					/*tag obtained with
scatterlist*/
+						tag,
+					/* Blocklayer completion
routineo*/
+						complete_bio,
+					/*Blocklayer completion data*/
+						bio,
+					/*Write must be flushed to
media*/
+						bio_rw_flagged(bio,
REQ_FLUSH));
+		} else {
+			protocol[dd->protocol].read(dd,	/* Driver data
*/
+					/* Start sector */
+						bio->bi_sector,
+					/* # sectors to read */
+						bio_sectors(bio),
+					/* # entries in the scatter list
*/
+						nents,
+					/* tag obtained with scatter
list */
+						tag,
+					/* Block layer completion
routine */
+						complete_bio,
+					/*Block layer completion data*/
+						bio,
+					/*Read must be from
physicalmedia*/
+						bio_rw_flagged(bio,
REQ_FLUSH));
+		}
+	} else {
+			bio_io_error(bio);
+		/*printk(KERN_ERR "%s: Interrupted\n", __func__);*/
+	}
+
+	return 0;
+}
+
+/**
+ * @brief Block layer initialization function.
+ *
+ * This function is called once by the PCI layer for each Cyclone
+ * device that is connected to the system.
+ *
+ * @param dd Pointer to the driver data structure.
+ *
+ * @return 0 on success else an error code.
+ */
+int block_initialize(struct driver_data *dd)
+{
+	int rv = 0;
+	sector_t capacity;
+	unsigned int  index = 0;
+	/*
+	 * Initialize the protocol layer.
+	 */
+	rv = protocol[dd->protocol].init(dd);
+	if (rv  < 0) {
+		printk(KERN_ERR "protocol layer initialization
failed\n");
+		rv = -EINVAL;
+		goto protocol_init_error;
+	}
+
+	/*
+	 * Allocate the request queue.
+	 */
+	dd->queue = blk_alloc_queue(GFP_KERNEL);
+	if (dd->queue == NULL) {
+		printk(KERN_ERR "Unable to allocate request queue\n");
+		rv = -ENOMEM;
+		goto block_queue_alloc_init_error;
+	}
+
+	/*
+	 * Attach our request function to the request queue.
+	 */
+	blk_queue_make_request(dd->queue, make_request);
+
+	/* Set device limits.
+	* Even settings normally directed at the elevator are assigned,
+	* because they are exported to userspace via sysfs and might
+	* be used for tuning.
+	*/
+
+	set_bit(QUEUE_FLAG_NOMERGES, &dd->queue->queue_flags);
+	set_bit(QUEUE_FLAG_NONROT, &dd->queue->queue_flags);
+
+
+	/*set_bit(QUEUE_FLAG_SAME_COMP, &dd->queue->queue_flags);
+	 * fixme: should we use this? */
+	/*set_bit(QUEUE_FLAG_ELVSWITCH, &dd->queue->queue_flags);
+	 * fixme: should we use this? */
+
+	blk_queue_max_segments(dd->queue, MAX_SG);
+
+	/*blk_queue_max_hw_sectors(dd->queue, 1<<20);
+	 * fixme: figure out what the hardware's max sector size is.*/
+
+	blk_queue_physical_block_size(dd->queue, 4096);
+	/*blk_queue_alignment_offset(dd->queue, 0);   // default is 0.*/
+	blk_queue_io_min(dd->queue, 4096);          /*
sysfs/minimum_io_size*/
+	/* not sure yet.  sysfs/optimal_io_size*/
+	/*blk_queue_io_opt(dd->queue, 4096);*/
+
+	/* no discard support yet.*/
+	/*set_bit(QUEUE_FLAG_DISCARD, &dd->queue->queue_flags);
+	*dd->queue->limits.discard_granularity=4096;
+	*not sure yet.  1<<22 is 1<<31 in sectors.
+	*blk_queue_max_discard_sectors(dd->queue, 1<<22);
+	*dd->queue->limits.discard_zeroes_data=0; // ?
+	*/
+	dd->disk = alloc_disk(MAX_MINORS);
+	if (dd->disk  == NULL) {
+		printk(KERN_ERR "Unable to allocate gendisk
structure\n");
+		rv = -EINVAL;
+		goto alloc_disk_error;
+	}
+	/*
+	 * Generate the disk name, implemented same as in sd.c
+	 */
+	do {
+		if (!ida_pre_get(&rssd_index_ida, GFP_KERNEL))
+				goto ida_get_error;
+
+		down_write(&dd->internalSem);
+		rv = ida_get_new(&rssd_index_ida, &index);
+		up_write(&dd->internalSem);
+	} while (rv == -EAGAIN);
+
+	if (rv)
+		goto ida_get_error;
+
+	rv = rssd_disk_name_format("rssd",
+				index,
+				dd->disk->disk_name,
+				DISK_NAME_LEN);
+	if (rv)
+		goto disk_index_error;
+
+	dd->disk->driverfs_dev	= &dd->pdev->dev;
+	dd->disk->major		= dd->major;
+	dd->disk->first_minor	= dd->instance * MAX_MINORS;
+	dd->disk->fops		= &blockOps;
+	dd->disk->queue		= dd->queue;
+	dd->disk->private_data	= dd;
+	dd->queue->queuedata	= dd;
+	dd->index				= index;
+
+	/*
+	 * Set the capacity of the device in 512 byte sectors.
+	 */
+	capacity = protocol[dd->protocol].getCapacity(dd);
+	if (capacity == (sector_t) -1) {
+		printk(KERN_ERR "Could not read drive capacity\n");
+		rv = -EIO;
+		goto read_capacity_error;
+	}
+	set_capacity(dd->disk, capacity);
+
+	/*
+	 * Enable the block device and add it to /dev
+	 */
+	add_disk(dd->disk);
+
+	/*
+	 * Now that the disk is active, initialize any sysfs attributes
+	 * managed by the protocol layer.
+	 */
+	if (protocol[dd->protocol].sysfsInit) {
+		struct kobject *kobj =
+			kobject_get(&disk_to_dev(dd->disk)->kobj);
+		protocol[dd->protocol].sysfsInit(dd, kobj);
+		kobject_put(kobj);
+	}
+
+	return rv;
+
+read_capacity_error:
+	/*
+	 * Delete our gendisk structure. This also removes the device
+	 * from /dev
+	 */
+	del_gendisk(dd->disk);
+
+disk_index_error:
+	down_write(&dd->internalSem);
+	ida_remove(&rssd_index_ida, index);
+	up_write(&dd->internalSem);
+
+ida_get_error:
+	put_disk(dd->disk);
+
+alloc_disk_error:
+
+	blk_cleanup_queue(dd->queue);
+
+block_queue_alloc_init_error:
+	/*
+	 * De-initialize the protocol layer.
+	 */
+	protocol[dd->protocol].exit(dd);
+protocol_init_error:
+	return rv;
+}
+
+/**
+ * @brief Block layer deinitialization function.
+ *
+ * Called by the PCI layer as each Cyclone device is removed.
+ *
+ * @param dd Pointer to the driver data structure.
+ *
+ * @return This function always returns 0.
+ */
+int block_remove(struct driver_data *dd)
+{
+
+	/*
+	 * Clean up the sysfs attributes managed by the protocol layer.
+	 */
+	if (protocol[dd->protocol].sysfsExit) {
+		struct kobject *kobj =
+			kobject_get(&disk_to_dev(dd->disk)->kobj);
+		protocol[dd->protocol].sysfsExit(dd, kobj);
+		kobject_put(kobj);
+	}
+
+	/*
+	 * Delete our gendisk structure. This also removes the device
+	 * from /dev
+	 */
+	del_gendisk(dd->disk);
+	blk_cleanup_queue(dd->queue);
+	dd->disk  = NULL;
+	dd->queue = NULL;
+
+	/*
+	 * De-initialize the protocol layer.
+	 */
+	protocol[dd->protocol].exit(dd);
+
+	return 0;
+}
+
+/**
+ * @brief Function called by the PCI layer when just before the
+ * machine shuts down.
+ *
+ * If a protocol layer shutdown function is present it will be called
+ * by this function.
+ *
+ * @param dd Pointer to the driver data structure.
+ *
+ * @return This function always returns 0.
+ */
+int block_shutdown(struct driver_data *dd)
+{
+	printk(KERN_NOTICE "Shutting down %s\n", dd->disk->disk_name);
+
+	/* Delete our gendisk structure, and cleanup the blk queue. */
+	del_gendisk(dd->disk);
+	blk_cleanup_queue(dd->queue);
+	dd->disk  = NULL;
+	dd->queue = NULL;
+
+	if (protocol[dd->protocol].shutdown)
+		protocol[dd->protocol].shutdown(dd);
+	return 0;
+}
+
+int block_suspend(struct driver_data *dd)
+{
+	printk(KERN_NOTICE "Suspending %s\n", dd->disk->disk_name);
+	if (protocol[dd->protocol].suspend)
+		protocol[dd->protocol].suspend(dd);
+	return 0;
+}
+
+int block_resume(struct driver_data *dd)
+{
+	printk(KERN_NOTICE "Resuming %s\n", dd->disk->disk_name);
+	if (protocol[dd->protocol].resume)
+		protocol[dd->protocol].resume(dd);
+	return 0;
+}
+
+static int rssd_disk_name_format(char *prefix, int index, char *buf,
int buflen)
+{
+	const int base = 'z' - 'a' + 1;
+	char *begin = buf + strlen(prefix);
+	char *end = buf + buflen;
+	char *p;
+	int unit;
+	p = end - 1;
+	*p = '\0';
+	unit = base;
+	do {
+		if (p == begin)
+			return -EINVAL;
+		*--p = 'a' + (index % unit);
+		index = (index / unit) - 1;
+	} while (index >= 0);
+
+	memmove(begin, p, end - p);
+	memcpy(buf, prefix, strlen(prefix));
+
+	return 0;
+}
diff -uNr a/drivers/block/mtipx2xx/module.c
b/drivers/block/mtipx2xx/module.c
--- a/drivers/block/mtipx2xx/module.c	1969-12-31 17:00:00.000000000
-0700
+++ b/drivers/block/mtipx2xx/module.c	2011-05-03 12:57:34.000000000
-0600
@@ -0,0 +1,149 @@
+/**********************************************************************
*******
+ *
+ * module.c - Handles the module layer of the Cyclone SSD Block Driver
+ *   Copyright (C) 2009  Integrated Device Technology, Inc.
+ *
+ *  Changes from IDT 1.0.1 are copyright (C) 2010 Micron Technology,
Inc.
+ *
+ *  This file is part of the Cyclone SSD Block Driver, it 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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program;
+ *  if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street,
+ *  Fifth Floor, Boston,
+ *  MA 02110-1301,
+ *  USA.
+ *
+
************************************************************************
****/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include "mtipx2xx.h"
+
+/**
+ * @file
+ * The module layer manages the loading and unloading of the driver
module.
+ * Primarily this comprises of the module init and exit functions,
prototypes
+ * for which are shown below.
+ *
+ * static int __init cyclone_init(void);@n
+ * static void __exit cyclone_exit(void);
+ *
+ * These functions are declared as the module entry and exit points,
called
+ * when the module is loaded or unloaded by the following Linux macros.
+ *
+ * module_init(cyclone_init);@n
+ * module_exit(cyclone_exit);
+ *
+ * When the module is loaded, cyclone_init() will allocate a new major
device
+ * number for the Cyclone devices, this should be evident by an entry
in
+ * /proc/devices called "cyclone".
+ * This major device number will be used for all Cyclone devices
connected
+ * to the system. Assuming a new major device number was allocated,
+ * cyclone_init() will then register the PCI driver by
+ * calling pci_register_driver() passing the address of the
cyclone_pci_driver
+ * structure which is declared by the PCI layer.
+ *
+ * When the module is unloaded, cyclone_exit() is called to undo the
work
+ * done by cyclone_init(). So, basically freeing the major device
number
+ * and unregistering the PCI driver.
+ */
+
+/** @mainpage Cyclone Linux Block Device Driver
+ *
+ * @section Introduction
+ * The Cyclone SSD Linux Block Device Driver is a high performance low
latency
+ * driver that interfaces directly to the Linux kernel block layer,
bypassing
+ * the I/O scheduler. The driver will be implemented as a loadable
Linux module
+ * that will support multiple Cyclone devices, device versions, and
+ * interface protocols such as AHCI and NVMHCI.
+ * @section Driver Layers
+ * For ease of maintenance the driver will be split into layers as
depicted
+ * in Figure 1.
+ * Each layer will be self contained within a single C module.
+ * Each module exports a number of functions that constitute the layers
API.
+ * A layer may only access the API of the layer that is directly
beneath it.
+ * Calling functions that do not belong to the layer directly below the
+ * calling layer is prohibited, as is calling functions that belong to
the
+ * layer above the calling layer unless done so via a callback.
+ * In effect you can only call down through the stack.
+ *
+ * @image html Layers.jpg Figure 1 - Cyclone Driver Layers
+ */
+
+
+/**
+ * Global variable used to hold the major block device number
+ * allocated in cyclone_init().
+ */
+int cyclone_major;
+
+/**
+ * Module initialization function.
+ *
+ * Called once when the module is loaded. This function allocates a
major
+ * block device number to the Cyclone devices and registers the PCI
layer
+ * of the driver.
+ *
+ * @return 0 on success else error code.
+ */
+static int __init cyclone_init(void)
+{
+	printk(KERN_INFO DRV_NAME " Version " DRV_VERSION "\n");
+
+	/*
+	 * Allocate a major block device number to use with this
+	 * driver.
+	 */
+	cyclone_major = register_blkdev(0, "mtipx2xx");
+	if (cyclone_major < 0) {
+		printk(KERN_ERR "Unable to register block device
(%d)\n",
+						cyclone_major);
+		return -EBUSY;
+	}
+
+	/*
+	 * Register our PCI operations.
+	 */
+	return pci_register_driver(&cyclone_pci_driver);
+}
+
+/**
+ * Module de-initialization function.
+ *
+ * Called once when the module is unloaded. This function deallocates
+ * the major block device number allocated by cyclone_init() and
+ * unregisters the PCI layer of the driver.
+ *
+ * @return N/A
+ */
+static void __exit cyclone_exit(void)
+{
+	/*
+	 * Release the allocated major block device number.
+	 */
+	unregister_blkdev(cyclone_major, "mtipx2xx");
+
+	/*
+	 * Unregister the PCI driver.
+	 */
+	pci_unregister_driver(&cyclone_pci_driver);
+}
+
+MODULE_AUTHOR("Integrated Device Technology, Inc, Micron Technology,
Inc");
+MODULE_DESCRIPTION("Micron RealSSD PCIe Block Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cyclone_init);
+module_exit(cyclone_exit);
diff -uNr a/drivers/block/mtipx2xx/mtipx2xx.h
b/drivers/block/mtipx2xx/mtipx2xx.h
--- a/drivers/block/mtipx2xx/mtipx2xx.h	1969-12-31 17:00:00.000000000
-0700
+++ b/drivers/block/mtipx2xx/mtipx2xx.h	2011-05-03 12:57:34.000000000
-0600
@@ -0,0 +1,806 @@
+/**********************************************************************
*******
+ *
+ * mtipx2xx.h - General header file for the Cyclone SSD Block Driver
+ *   Copyright (C) 2009  Integrated Device Technology, Inc.
+ *
+ *  Changes from IDT 1.0.1 are copyright (C) 2010 Micron Technology,
Inc.
+ *
+ *  This file is part of the Cyclone SSD Block Driver, it 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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program;
+ *  if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street,
+ *  Fifth Floor, Boston,
+ *  MA 02110-1301,
+ *  USA.
+ *
+
************************************************************************
****/
+#ifndef __MTIPX2XX_H__
+#define __MTIPX2XX_H__
+/**
+ * @file
+ */
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+#include <linux/ata.h>
+#include <linux/interrupt.h>
+#include <linux/atomic.h>
+#include <linux/genhd.h>
+#include <linux/version.h>
+
+#ifndef WIN_SMART
+#define WIN_SMART       0xB0
+#endif
+
+/**
+ * Defined for enabling surprise removal handling
+ */
+#define SRSI_IMPLEMENATAION  1
+
+/**
+ * offset of subsystem Device ID in pci confoguration space
+ */
+#define PCI_SUBSYSTEM_DEVICEID 0x2E
+
+/* offset of Device Control register in PCIe extended capabilites space
*/
+#define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET  0x48
+
+#define MAX_RETRIES	5
+/**
+ * Defined if the driver should timeout commands that take
+ * too long to execute.
+ */
+#define COMMAND_TIMEOUT
+/**
+ * If COMMAND_TIMEOUT is defined, this is the timeout value in ms.
+ */
+#define NCQ_COMMAND_TIMEOUT_MS       5000
+#define IOCTL_COMMAND_TIMEOUT_MS     5000
+#define INTERNAL_COMMAND_TIMEOUT_MS  5000
+
+/* check for timeouts every 500ms.*/
+#define TIMEOUT_CHECK_PERIOD 500
+
+/**
+ * How should the driver react when an error occurs?
+ * Set each of these to 1 (enabled) or 0 (disabled)
+ */
+#define ISSUE_COMRESET_ON_TIMEOUT 1
+#define ISSUE_COMRESET_ON_TFE 1
+#define REISSUE_NCQ_COMMANDS_ON_ERR 1
+#define REISSUE_INT_COMMANDS_ON_ERR 0
+#define NULL_BIO_FIX 1
+/**
+ * Use a tasklet for bottom half IRQ processing.
+ *
+ * Set to 1 to use a tasklet for bottom half IRQ processing.
+ */
+#define USE_TASKLET	1
+/**
+ * Macro to extract the tag bit number from a tag value.
+ */
+#define TAG_BIT(tag)	(tag & 0x1f)
+/**
+ * Macro to extract the tag index from a tag value. The index
+ * is used to access the correct SActive/Command Issue register based
+ * on the tag value.
+ */
+#define TAG_INDEX(tag)	(tag >> 5)
+/**
+ * Maximum number of scatter gather entries
+ * a single command may have.
+ */
+#define MAX_SG				128
+/**
+ * Maximum number of slot groups (Command Issue & SActive registers)
+ * NOTE: This is the driver maximum; check dd->slot_groups for actual
value.
+ */
+#define MAX_SLOT_GROUPS			8
+/**
+ * Internal command tag.
+ */
+#define TAG_INTERNAL	0
+/**
+ * Micron Vendor ID
+ */
+#define PCI_VENDOR_ID_MICRON    0x1344
+/**
+ * Micron FPGA SSD device ID
+ */
+#define CYCLONE_FPGA_DEVICE_ID	0x5150
+/**
+ * Driver name string.
+ */
+#define DRV_NAME	"Micron RealSSD PCIe Block Driver"
+/**
+ * Driver version string.
+ */
+#define DRV_VERSION	"1.2.6b"
+/**
+ * Maximum number of minor device numbers per device.
+ */
+#define MAX_MINORS				16
+/**
+ * Maximum number of supported command slots.
+ */
+#define MAX_COMMAND_SLOTS	(MAX_SLOT_GROUPS * 32)
+/**
+ * Per-tag bitfield size in longs.
+ * Linux bit manipulation functions (i.e. test_and_set_bit,
find_next_zero_bit)
+ * manipulate memory in longs, so we try to make the math work.
+ * take the slot groups and find the number of longs, rounding up.
+ * Careful! i386 and x86_64 use different size longs!
+ */
+#define U32_PER_LONG (sizeof(long) / sizeof(u32))
+#define SLOTBITS_IN_LONGS
((MAX_SLOT_GROUPS+(U32_PER_LONG-1))/U32_PER_LONG)
+/**
+ * BAR number used to access the AHCI HBA registers.
+ */
+#define MTIPX2XX_ABAR				5
+/*
+ * Forced Unit Access Bit
+ */
+#define FUA_BIT		0x80
+
+/**
+ * Register Frame Information Structure (FIS), host to device.
+ */
+
+ /**
+ * Macro value specfies the success and failure
+ *
+ */
+#define SUCCESS   0
+#define FAILURE  -1
+
+struct HOST_TO_DEV_FIS {
+	/**
+	 * FIS type.
+	 * - 27h Register FIS, host to device.
+	 * - 34h Register FIS, device to host.
+	 * - 39h DMA Activate FIS, device to host.
+	 * - 41h DMA Setup FIS, bi-directional.
+	 * - 46h Data FIS, bi-directional.
+	 * - 58h BIST Activate FIS, bi-directional.
+	 * - 5Fh PIO Setup FIS, device to host.
+	 * - A1h Set Device Bits FIS, device to host.
+	 */
+	unsigned char type;
+	unsigned char opts;
+	unsigned char command;
+	unsigned char features;
+
+	union {
+		unsigned char LBALow;
+		unsigned char sector;
+	};
+	union {
+		unsigned char LBAMid;
+		unsigned char cylLow;
+	};
+	union {
+		unsigned char LBAHi;
+		unsigned char cylHi;
+	};
+	union {
+		unsigned char device;
+		unsigned char head;
+	};
+
+	union {
+		unsigned char LBALowEx;
+		unsigned char sectorEx;
+	};
+	union {
+		unsigned char LBAMidEx;
+		unsigned char cylLowEx;
+	};
+	union {
+		unsigned char LBAHiEx;
+		unsigned char cylHiEx;
+	};
+	unsigned char featuresEx;
+
+	unsigned char sectCount;
+	unsigned char secCountEx;
+	unsigned char res2;
+	unsigned char control;
+
+	unsigned int res3;
+};
+
+/**
+ * Command header structure.
+ */
+struct COMMAND_HDR {
+	/**
+	 * Command options.
+	 * - Bits 31:16 Number of PRD entries.
+	 * - Bits 15:8 Unused in this implementation.
+	 * - Bit 7 Prefetch bit, informs the drive to prefetch PRD
entries.
+	 * - Bit 6 Write bit, should be set when writing data to the
device.
+	 * - Bit 5 Unused in this implementation.
+	 * - Bits 4:0 Length of the command FIS in DWords (DWord = 4
bytes).
+	 */
+	unsigned int opts;
+	/**
+	 * This field is unsed when using NCQ.
+	 */
+	union {
+		unsigned int byteCount;
+		unsigned int status;
+	};
+	/**
+	 * Lower 32 bits of the command table address associated with
this header.
+	 * The command table addresses must be 128 byte aligned.
+	 */
+	unsigned int ctba;
+	/**
+	 * If 64 bit addressing is used this field is the upper 32 bits
+	 * of the command table address associated with this command.
+	 */
+	unsigned int ctbau;
+	/**
+	 * Reserved and unused.
+	 */
+	unsigned int res[4];
+};
+
+/**
+ * Command scatter gather structure (PRD).
+ */
+struct COMMAND_SG {
+	/**
+	 * Low 32 bits of the data buffer address. For Cyclone this
+	 * address must be 8 byte aligned signified by bits 2:0 being
+	 * set to 0.
+	 */
+	unsigned int dba;
+	/**
+	 * When 64 bit addressing is used this field is the upper
+	 * 32 bits of the data buffer address.
+	 */
+	unsigned int dbaUpper;
+	/**
+	 * Unused.
+	 */
+	unsigned int reserved;
+	/**
+	 * Bit 31: interrupt when this data block has been transferred.
+	 * Bits 30..22: reserved
+	 * Bits 21..0: byte count (minus 1).  For Cyclone the byte count
must be
+	 * 8 byte aligned signified by bits 2:0 being set to 1.
+	 */
+	unsigned int info;
+
+};
+struct port;
+/*struct port;*/
+
+/**
+ * Structure used to describe an AHCI command.
+ */
+struct COMMAND {
+	/**
+	 * Pointer to the command headers in virtual kernel address
space.
+	 */
+	struct COMMAND_HDR *commandHeader;
+	/**
+	 * Pointer to the command headers in physical address space.
+	 */
+	dma_addr_t commandHeaderDMA;
+	/**
+	 * Pointer to the command tables in virtual kernel address
space.
+	 */
+	void *command;
+	/**
+	 * Pointer to the command tables in physical address space.
+	 */
+	dma_addr_t commandDMA;
+	/**
+	 * Completion data passed to completionFunc() upon completion
+	 * of a command.
+	 */
+	void *completionData;
+	/**
+	 * Completion function called by the ISR upon completion of
+	 * a command.
+	 */
+	void (*completionFunc)(struct port *port,
+				int tag,
+				void *data,
+				int status);
+	/**
+	 * Additional callback function that may be called by
+	 * completionFunc().
+	 */
+	void (*asyncCallback)(void *data, int status);
+	/**
+	 * Additional callback data that should be passed to
+	 * asyncCallback().
+	 */
+	void *asyncData;
+	/**
+	 * Number of scatter list entries used by this command.
+	 */
+	int scatterEnts;
+	/**
+	 * Scatter list entries for this command.
+	 */
+	struct scatterlist sg[MAX_SG];
+	/**
+	 * The nuCOMMANDmber of retries left for this command.
+	 */
+	int retries;
+#ifdef COMMAND_TIMEOUT
+	/**
+	 * The time, in jiffies, at which this command should have
completed.
+	 */
+	unsigned long compTime;
+#endif
+	/**
+	 * A bit to declare that this command has been sent to the
drive.
+	 */
+	atomic_t active;
+};
+
+
+/**
+ * Structure usCOMMAND_SGed to describe an AHCI port.
+ */
+struct port {
+	/**
+	 * Pointer back to the driver data for this port.
+	 */
+	struct driver_data *dd;
+	/**
+	 * Used to determine if the data pointed to by the
+	 * identify field is valid.
+	 */
+	int identifyValid;
+	/**
+	 * Base address of the memory mapped IO for the port.
+	 */
+	void __iomem *mmio;
+	/**
+	 * Array of pointers to the memory mapped SActive registers.
+	 */
+	void __iomem *SActive[MAX_SLOT_GROUPS];
+	/**
+	 * Array of pointers to the memory mapped Completed registers.
+	 */
+	void __iomem *Completed[MAX_SLOT_GROUPS];
+	/**
+	 * Array of pointers to the memory mapped Command Issue
registers.
+	 */
+	void __iomem *CommandIssue[MAX_SLOT_GROUPS];
+	/**
+	 * Pointer to the beginning of the command header memory as used
+	 * by the driver.
+	 */
+	void *commandList;
+	/**COMMAND_SG
+	 * Pointer to the beginning of the command header memory as used
+	 * by the DMA.
+	 */
+	dma_addr_t commandListDMA;
+	/**
+	 * Pointer to the beginning of the RX FIS memory as used
+	 * by the driver.
+	 */
+	void *rxFIS;
+	/**
+	 * Pointer to the beginning of the RX FIS memory as used
+	 * by the DMA.
+	 */
+	dma_addr_t rxFISDMA;
+	/**COMMAND_SG
+	 * Pointer to the beginning of the command table memory as used
+	 * by the driver.
+	 */
+	void *commandTbl;
+	/**
+	 * Pointer to the beginning of the command table memory as used
+	 * by the DMA.
+	 */
+	dma_addr_t commandTblDMA;
+	/**
+	 * Pointer to the beginning of the identify data memory as used
+	 * by the driver.
+	 */
+	u16 *identify;
+	/**
+	 * Pointer to the beginning of the identify data memory as used
+	 * by the DMA.
+	 */
+	dma_addr_t identifyDMA;
+	/**
+	 * Pointer to the beginning of a sector buffer that is used
+	 * by the driver when issuing internal commands.
+	 */
+	u16 *sectorBuffer;
+	/**
+	 * Pointer to the beginning of a sector buffer that is used
+	 * by the DMA when the driver issues internal commands.
+	 */
+	dma_addr_t sectorBufferDMA;
+	/**
+	 * Bit significant, used to determine if a command slot has
+	 * been allocated. i.e. the slot is in use.  Bits are cleared
+	 * when the command slot and all associated data structures
+	 * are no longer needed.
+	 */
+	unsigned long allocated[SLOTBITS_IN_LONGS];
+	/**
+	 * Array of command slots. Structure includes pointers to the
+	 * command header and command table, and completion function and
data
+	 * pointers.
+	 */
+	struct COMMAND commands[MAX_COMMAND_SLOTS];
+	/**
+	 * Non-zero if an internal command is in progress.
+	 */
+	int internalCommandInProgress;
+#ifdef COMMAND_TIMEOUT
+	/**
+	 * Timer used to complete commands that have been active for too
long.
+	 */
+	struct timer_list	commandTimer;
+#endif
+	/**
+	 * Semaphore used to block threads if there are no
+	 * command slots available.
+	 */
+	struct semaphore commandSlot;
+	/**
+	 * Spinlock for working around command-issue bug.
+	 */
+	spinlock_t cmdIssueLock;
+};
+
+/**
+ * Structure used to hold information relating to performance
+ * statistics.
+ */
+struct STATS {
+	/**
+	 * Statistics timer.
+	 */
+	struct timer_list	timer;
+	/**
+	 * Statistics, incremented each time the SSD ISR is executed.
+	 * Cleared to zero each second when the value is copied to
currentInts.
+	 */
+	atomic_t interrupts;
+	/**
+	 * Statistics, incremented each time a read is issued to the
device.
+	 * Cleared to zero each second when the value is copied to
+	 * currentReads.
+	 */
+	atomic_t reads;
+	/**
+	 * Statistics, incremented each time a write is issued to the
device.
+	 * Cleared to zero each second when the value is copied to
+	 * currentWrites.
+	 */
+	atomic_t writes;
+	/**
+	 * The current number of interrupts per second.
+	 */
+	atomic_t currentInts;
+	/**
+	 * The current number of reads per second.
+	 */
+	atomic_t currentReads;
+	/**
+	 * The current number of writes per second.
+	 */
+	atomic_t currentWrites;
+	/**
+	 * The current number of IOPS.
+	 */
+	atomic_t currentIOPS;
+	/**
+	 * Minimum response time.
+	 */
+	atomic_t minRespTime;
+	/**
+	 * Maximum response time.
+	 */
+	atomic_t maxRespTime;
+	/**
+	 * Average response time.
+	 */
+	atomic_t avgRespTime;
+	/**
+	 * Average response time.
+	 */
+	atomic_t currentAvgRespTime;
+};
+
+
+/**
+ * Driver private data structure.
+ *
+ * One structure is allocated per probed device.
+ */
+struct  driver_data {
+	/**
+	 * Base address of the HBA registers.
+	 */
+	void __iomem *mmio;
+	/**
+	 * Major device number.
+	 */
+	int	major;
+	/**
+	 * Instance number for this device. First device probed is 0,
second
+	 * is 1, etc.
+	 */
+	int instance;
+	/**
+	 * Protocol ops array index.
+	 */
+	int protocol;
+	/**
+	 * Pointer to our gendisk structure.
+	 */
+	struct gendisk *disk;
+	/**
+	 * Pointer to the PCI device structure.
+	 */
+	struct pci_dev *pdev;
+	/**
+	 * Our request queue.
+	 */
+	struct request_queue	*queue;
+	/**
+	 * Semaphore used to lock out read/write commands during the
+	 * execution of an internal command.
+	 */
+	struct rw_semaphore internalSem;
+	/**
+	 * Pointer to the port data structure.
+	 */
+	struct port  *port;
+#ifdef USE_TASKLET
+	/**
+	 * Tasklet used to process the bottom half of
+	 * the ISR.
+	 */
+	struct tasklet_struct tasklet;
+#endif
+	/**
+	 * Performance statistics.
+	 */
+	struct STATS statistics;
+	/**
+	 * Used to inject random read/write errors.
+	 * - Bit 0 - Insert random read errors.
+	 * - Bit 1 - Insert random write errors.
+	 */
+	int makeItFail;
+	/**
+	 * Tag which caused the simulated failure.
+	 */
+	int makeItFailTag;
+	/**
+	 * Used to store the original start sector value from the FIS
+	 * when an error is injected.
+	 */
+	sector_t makeItFailStart;
+	/**
+	 * Spinlock used to access the make_it_fail counters below.
+	 */
+	spinlock_t	makeItFailLock;
+	/**
+	 * Initialized with a random value when bit 0 is set in
makeItFail.
+	 * The value is decremented each time there is a read, when the
count
+	 * is zero an error is injected into the read command and the
counter
+	 * is written with a new random value.
+	 */
+	unsigned  randomReadCount;
+	/**
+	 * Initialized with a random value when bit 1 is set in
makeItFail.
+	 * The value is decremented each time there is a write, when the
count
+	 * is zero an error is injected into the write command and the
counter
+	 * is written with a new random value.
+	 */
+	unsigned  randomWriteCount;
+	/**
+	 * Store a magic value declaring the product type.
+	 */
+	unsigned product_type;
+	/**
+	 * Store the number of slot groups the product supports.
+	 */
+	unsigned slot_groups;
+	/**
+	 * Atomic varaiable for SRSI
+	 */
+	atomic_t drv_cleanup_done;
+	/*
+	 *Index to determine the disk name
+	 */
+	unsigned long index;
+};
+
+/**
+ * Protocol layer exported functions.
+ *
+ * This structure contains functions that are required by
+ * the block layer.
+ */
+struct PROTOCOL_FUNCS {
+	/**
+	 * Protocol layer initialization function. Called by the
+	 * block layer initialization function (blockInitialize())
+	 * to initialize the protocol layer.
+	 */
+	int (*init)(struct driver_data *dd);
+	/**
+	 * Protocol layer exit function. Called by the block layer
+	 * exit function (blockRemove()) to deinitialize the protocol
+	 * layer.
+	 */
+	int (*exit)(struct driver_data *dd);
+#ifdef CONFIG_PM
+	/**
+	 * Protocol layer suspend function. Called by the block layer
suspend
+	 * routine (blockSuspend()) to suspend the device
+	 */
+	int (*suspend)(struct driver_data *dd);
+	/**
+	 * Protocol layer resume function. Called by the block layer
resume
+	 * routine (blockResume()) to resume the device
+	 */
+	int (*resume)(struct driver_data *dd);
+#endif
+	/**
+	 * Protocol layer shutdown function. Called by the kernel when
+	 * the machine is being shutdown. This function should sync the
+	 * hardware. For Cyclone, this means issuing a Standby Immediate
+	 * command. This function is optional.
+	 */
+	int (*shutdown)(struct driver_data *dd);
+	/**
+	 * Function that returns the actual hardware block size. For the
Cyclone
+	 * SSD this function should return 4096. The information
returned from
+	 * this function is used to be block layer to inform the kernel
of the
+	 * hardware block size. The kernel will then only issue block
read/write
+	 * commands that are a multiples of that size.
+	 */
+	int (*hwBlkSize)(void);
+	/**
+	 * Function to obtain and return the size of the device in 512
+	 * byte sectors.
+	 */
+	sector_t (*getCapacity)(struct driver_data *dd);
+	/**
+	 * Function called by the block later to obtain a free command
+	 * slot and to return a pointer to the scatter list associated
+	 * with it.
+	 */
+	struct scatterlist *(*getScatterList)(struct driver_data *dd,
int *tag);
+	/**
+	 * Called by the Block Layer to issue a read to the hardware.
+	 */
+	int (*read)(struct driver_data *dd,
+			sector_t start,
+			int nsect,
+			int nents,
+			int tag,
+			void *callback,
+			void *data,
+			int barrier);
+	/**
+	 * Called by the Block Layer to issue a write to the hardware.
+	 */
+	int (*write)(struct driver_data *dd,
+			sector_t start,
+			int nsect,
+			int nents,
+			int tag,
+			void *callback,
+			void *data,
+			int barrier);
+	/**
+	 * Called by the Block Layer to handle device specific IOCTL
commands.
+	 */
+	int (*ioctl)(struct driver_data *dd,
+			unsigned int cmd,
+			unsigned long arg);
+	/**
+	 * Function to initialize sysfs attributes for the protocol
layer. This
+	 * function is called by the block layer after the block device
has
+	 * been added to the system by a call to add_disk(). This field
is
+	 * optional.
+	 */
+	int (*sysfsInit)(struct driver_data *dd, struct kobject *kobj);
+	/**
+	 * Function to deinitialize sysfs attributes for the protocol
layer. This
+	 * function is called by the block layer before the block device
is
+	 * removed from the system by a call to del_gendisk(). This
function
+	 * is optional.
+	 */
+	int (*sysfsExit)(struct driver_data *dd, struct kobject *kobj);
+};
+
+extern int cyclone_major;
+extern bool resumeflag;
+extern int block_initialize(struct driver_data *dd);
+extern int block_remove(struct driver_data *dd);
+extern int block_shutdown(struct driver_data *dd);
+extern int block_suspend(struct driver_data *dd);
+extern int block_resume(struct driver_data *dd);
+extern int ahci_init(struct driver_data *dd);
+extern int ahci_exit(struct driver_data *dd);
+extern int ahci_shutdown(struct driver_data *dd);
+extern int ahci_hard_blksize(void);
+extern sector_t ahci_get_capacity(struct driver_data *dd);
+extern struct scatterlist *ahci_get_scatterlist(
+				struct driver_data *dd,
+				int *tag);
+extern int ahci_read(struct driver_data *dd,
+			sector_t start,
+			int nsect,
+			int nents,
+			int tag,
+			void *callback,
+			void *data,
+			int barrier);
+extern int ahci_write(struct driver_data *dd,
+			sector_t start,
+			int nsect,
+			int nents,
+			int tag,
+			void *callback,
+			void *data,
+			int barrier);
+extern int ahci_ioctl(struct driver_data *dd,
+			unsigned int cmd,
+			unsigned long arg);
+extern int ahci_sysfs_init(struct driver_data *dd, struct kobject
*kobj);
+extern int ahci_sysfs_exit(struct driver_data *dd, struct kobject
*kobj);
+extern int ahci_resume(struct driver_data *dd);
+extern int ahci_suspend(struct driver_data *dd);
+
+
+extern struct pci_driver cyclone_pci_driver;
+void command_cleanup(struct driver_data *dd);
+int check_for_surprise_removal(struct pci_dev *pdev);
+
+void restart_port(struct port *);
+/**
+ * Swap halves of 16-bit words in place
+ *
+ * Swap halves of 16-bit words if needed to convert from
+ * little-endian byte order to native cpu byte order, or
+ * vice-versa.
+ *
+ * @param buf Buffer to swap
+ * @param buf_words Number of 16-bit words in buffer.
+ *
+ * @return N/A
+ */
+static inline void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+	unsigned int i;
+
+	for (i = 0; i < buf_words; i++)
+		buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+
+#endif
diff -uNr a/drivers/block/mtipx2xx/pci.c b/drivers/block/mtipx2xx/pci.c
--- a/drivers/block/mtipx2xx/pci.c	1969-12-31 17:00:00.000000000
-0700
+++ b/drivers/block/mtipx2xx/pci.c	2011-05-03 12:57:34.000000000
-0600
@@ -0,0 +1,411 @@
+/**********************************************************************
*******
+ *
+ * pci.c - Handles the PCI layer of the Cyclone SSD Block Driver
+ *   Copyright (C) 2009  Integrated Device Technology, Inc.
+ *
+ *  Changes from IDT 1.0.1 are copyright (C) 2010 Micron Technology,
Inc.
+ *
+ *  This file is part of the Cyclone SSD Block Driver, it 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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program;
+ *  if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street,
+ *  Fifth Floor, Boston,
+ *  MA 02110-1301,
+ *  USA.
+ *
+
************************************************************************
****/
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include "mtipx2xx.h"
+/**
+ * @file
+ * The PCI layer contains the pci_device_id structure which is used to
+ * associate a hardware vendor/device ID with the device driver. An
example of
+ * a pci_device_id structure for Cyclone is shown below.
+ * @verbatim
+static const struct pci_device_id pci_tbl[] = {
+	{ PCI_VDEVICE(MICRON, CYCLONE_FPGA_DEVICE_ID), 0},
+	{}
+};
+@endverbatim
+ * Each entry in the pci_device_id table consists of a vendor/device
ID, the
+ * macro PCI_VDEVICE() is used to correctly populate the vendor/device
entries,
+ * and an integer value that is used by the block layer as an
+ * index into the PROTOCOL_FUNCS table which is described in the Block
Layer
+ * section.
+ * The Linux macro MODULE_DEVICE_TABLE is used to create the relevant
linker
+ * sections so that the depmod command may be used to update the module
+ * dependency files.
+ *
+ * Another structure declared in the PCI layer is the
cyclone_pci_driver
+ * structure. This is the structure that describes the PCI driver entry
points.
+ * A pointer to this structure is passed into the pci_register_driver()
+ * function by the module layer to register the PCI driver.
+ * The following PCI driver methods will be supported by the PCI layer.
+ *
+ * - probe() - When the module is loaded this function is called for
each device
+ * that matches the vendor/device ID's specified in the pci_device_id
table as
+ * they are discovered.
+ * The probe() function performs the following operations.
+ *  - Allocate memory for the drivers private data
+ *  cyclone_major = register_blkdev(0, "mtipx2xx")a structures.
+ *  -	Enables the PCI device.
+ *  -	Iomap the devices BARs.
+ * cyclone_major = register_blkdev(0, "mtipx2xx") -Set the DMA mask for
the
+ * device.
+ *  -	Enable PCI device master operations.
+ *  -	Call the block layer initialization function
(blockInitialize()).
+ * - remove() - When the module is unloaded this function is called for
each
+ * device that matches the vendor/device ID's specified in the
pci_device_id
+ * table.
+ * The remove() function must undo the operations of the probe()
function.
+ *  -	Call the block layer remove function (blockRemove()).
+ *  -	Free the memory allocated for the driver private data
structures.
+ *  -	Unmap the devices BARs.
+ * - shutdown() - This function is called by the kernel PCI
infrastructure
+ * just before the system is halted during a shutdown. This function
should
+ * call into the block layer to sync the device before the power is
switched
+ * off.
+ *
+ * The PCI layer will also handle the suspend and resume operations
which are
+ * issued when the system enters and exits low power states. The
initial
+ * version of the driver will not support these methods.
+ */
+
+/**
+ * Device instance number, incremented each time a device is probed.
+ */
+static int instance;
+
+/**
+ * Called for each supported PCI device detected.
+ *
+ * This function allocates the private data structure, enables the
+ * PCI device and then calls the block layer initialization function.
+ *
+ * @return 0 on success else an error code.
+ */
+static int pci_probe(struct pci_dev *pdev, const struct pci_device_id
*ent)
+{
+	struct driver_data	*dd = NULL;
+	int rv = 0;
+	unsigned short pcie_dev_ctrl, pcie_sub_deviceid;
+	/*
+	 * Allocate memory for this devices private data.
+	 */
+	dd = vmalloc(sizeof(struct driver_data));
+	if (dd == NULL) {
+		printk(KERN_ERR "Unable to allocate memory for driver
data\n");
+		return -ENOMEM;
+	}
+	memset(dd, 0, sizeof(struct driver_data));
+	/**
+	* Set the atomic variable as 1 in case of SRSI
+	*/
+
+	atomic_set(&dd->drv_cleanup_done, true);
+
+	/*
+	 * Attach the private data to this PCI device.
+	 */
+	pci_set_drvdata(pdev, dd);
+
+	/*
+	 * Enable the PCI device.
+	 */
+	rv = pcim_enable_device(pdev);
+	if (rv < 0) {
+		printk(KERN_ERR "Unable to enable device\n");
+		goto iomap_err;
+	}
+
+	/*
+	 * Read the subsystem device id from the pci configuration
+	 * space to identify the 2.5" drive
+	 */
+	 pci_read_config_word(pdev, PCI_SUBSYSTEM_DEVICEID ,
+
&pcie_sub_deviceid);
+	 if (pcie_sub_deviceid & 0x08) {
+		/*
+		 *  workaround for max TLP payload issue
+		 * after surprise insertion
+		 */
+		pci_read_config_word(pdev,
+				PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET,
+				&pcie_dev_ctrl);
+		if (!(pcie_dev_ctrl & 0x20)) {
+			printk(KERN_INFO "mtipx2xx: setting"
+				"max TLP payload size to 256 bytes\n");
+			pcie_dev_ctrl |= 0x20;
+			pci_write_config_word(pdev,
+				PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET,
+				pcie_dev_ctrl);
+		}
+	}
+	/*
+	 * Map BAR5 to memory.
+	 */
+	rv = pcim_iomap_regions(pdev, 1 << MTIPX2XX_ABAR, DRV_NAME);
+	if (rv  < 0) {
+		printk(KERN_ERR "Unable to map regions\n");
+		goto iomap_err;
+	}
+
+	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
+		rv = pci_set_consistent_dma_mask(pdev,
DMA_BIT_MASK(64));
+
+		if (rv) {
+			rv = pci_set_consistent_dma_mask(pdev,
+						DMA_BIT_MASK(32));
+			if (rv) {
+				dev_printk(KERN_ERR, &pdev->dev,
+					"64-bit DMA enable failed\n");
+				return rv;
+			}
+		}
+	}
+
+	/*
+	 * Enable PCI device master operations.
+	 */
+	pci_set_master(pdev);
+
+	/*
+	 * Enable MSI for this device.
+	 */
+	if (pci_enable_msi(pdev))
+		printk(KERN_WARNING "Unable to enable MSI
interrupt.\n");
+
+
+	/*
+	 * Copy the info we may need later into the private data
structure.
+	 */
+	dd->major	= cyclone_major;
+	dd->protocol	= ent->driver_data;
+	dd->instance	= instance;
+	dd->pdev	= pdev;
+
+	/*
+	 * Initialize the block layer.
+	 */
+	rv = block_initialize(dd);
+	if (rv < 0) {
+		printk(KERN_ERR "Unable to initialize block layer\n");
+		goto block_initialize_err;
+	}
+
+	/*
+	 * Increment the instance count so that each device has a unique
+	 * instance number.
+	 */
+	instance++;
+
+	goto done;
+
+block_initialize_err:
+
+	pcim_iounmap_regions(pdev, 1 << MTIPX2XX_ABAR);
+iomap_err:
+	vfree(dd);
+	pci_set_drvdata(pdev, NULL);
+done:
+	/**
+	* Set the atomic variable as 0 in case of SRSI
+	*/
+
+	atomic_set(&dd->drv_cleanup_done, false);
+
+	return rv;
+}
+
+/**
+ * Called for each probed device when the device is removed or the
+ * driver is unloaded.
+ *
+ * @return N/A
+ */
+static void pci_remove(struct pci_dev *pdev)
+{
+	struct driver_data	*dd = pci_get_drvdata(pdev);
+	int Counter = 0;
+
+	/*
+	* Check for the device presence
+	*/
+	if (check_for_surprise_removal(pdev)) {
+		while (atomic_read(&dd->drv_cleanup_done) == false) {
+			Counter++;
+			msleep(20);
+			if (Counter == 10) {
+				/*
+				* Cleanup the outstanding the command
+				*/
+				command_cleanup(dd);
+				break;
+			}
+		}
+	}
+       /*
+	* Set the atomic variable as 1 in case of SRSI
+	*/
+	atomic_set(&dd->drv_cleanup_done, true);
+
+
+	/*
+	 * Clean up the block layer.
+	 */
+	block_remove(dd);
+
+	/*
+	 * Reverse the effects of pci_enable_msi().
+	 */
+	pci_disable_msi(pdev);
+
+	/*
+	 * Free the memory allocated for the private data structure.
+	 */
+	vfree(dd);
+
+	/*
+	 * Unmap the memory regions allocated to the BARs.
+	 */
+	pcim_iounmap_regions(pdev, 1 << MTIPX2XX_ABAR);
+}
+
+
+static int pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+		int rv = 0;
+		struct driver_data	 *dd ;
+
+		resumeflag = 1;
+		dd = pci_get_drvdata(pdev);
+		if (dd == NULL)
+			printk(KERN_ERR "Driver private datastructure is
NULL\n");
+
+
+		/* Disable PORTs and Interrupts.
+		 * It sends standbyImmediate command to controller.*/
+		rv = block_suspend(dd);
+
+		if (rv < 0) {
+			printk(KERN_ERR "Failed to suspend AHCI
controller\n");
+			return rv;
+		}
+
+		/* Save the pci config space to pdev structure &
+		 * disable the device */
+		pci_save_state(pdev);
+		pci_disable_device(pdev);
+
+		/* Move to Low power state*/
+		pci_set_power_state(pdev, PCI_D3hot);
+
+		return rv;
+}
+
+static int pci_resume(struct pci_dev *pdev)
+{
+		int rv = 0;
+		struct driver_data	 *dd;
+
+		dd = pci_get_drvdata(pdev);
+		if (dd == NULL)
+			printk(KERN_ERR "Driver private datastructure is
NULL\n");
+
+
+		/* Move the device to active State*/
+		pci_set_power_state(pdev, PCI_D0);
+
+		/* Restore PCI configuration space*/
+		pci_restore_state(pdev);
+
+		/* Enable the PCI device*/
+		rv = pcim_enable_device(pdev);
+		if (rv < 0) {
+			printk(KERN_ERR "Failed to enable P320 card
during resume\n");
+			goto err;
+		}
+		pci_set_master(pdev);
+
+		/*
+		 * It calls hbaReset , initPort,startPort function
+		 * and enable the interrupt
+		 */
+		rv = block_resume(dd);
+		if (rv < 0) {
+			printk(KERN_ERR "Unable to initialize port\n");
+			goto err;
+		}
+
+err:
+		resumeflag = 0;
+
+		return rv;
+}
+
+static void pci_shutdown(struct pci_dev *pdev)
+{
+	struct driver_data	*dd = pci_get_drvdata(pdev);
+	block_shutdown(dd);
+}
+
+/**
+ * This function check_for_surprise_removal is called
+ * while card is removed from the system and it will
+ * read the vendor id from the configration space
+ *
+ *
+ * @param pdev Pointer to the pci_dev structure.
+ *
+ *
+ * @return 1 if device removed, else 0
+ */
+
+int check_for_surprise_removal(struct pci_dev *pdev)
+{
+	u16 vendor_id = 0;
+
+       /*
+	* Read the vendorID from the configuration space
+	*/
+	pci_read_config_word(pdev, 0x00, &vendor_id);
+	if (vendor_id == 0xFFFF)
+		return 1; /* device removed */
+
+	return 0; /* device present */
+}
+
+/**
+ * Table of devices supported by this driver.
+ */
+static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = {
+	{  PCI_DEVICE(PCI_VENDOR_ID_MICRON, CYCLONE_FPGA_DEVICE_ID) },
+
+	{0}	/* terminate list */
+};
+
+/**
+* Structure that describes the PCI driver functions.
+*/
+struct pci_driver cyclone_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= pci_tbl,
+	.probe			= pci_probe,
+	.remove			= pci_remove,
+	.suspend		= pci_suspend,
+	.resume			= pci_resume,
+	.shutdown		= pci_shutdown,
+};
+
+MODULE_DEVICE_TABLE(pci, pci_tbl);
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux