OpenCores
URL https://opencores.org/ocsvn/sata_controller_core/sata_controller_core/trunk

Subversion Repositories sata_controller_core

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 13 to Rev 14
    Reverse comparison

Rev 13 → Rev 14

/sata_controller_core/trunk/sata2_driver_v1_00_a/sata_drv.c
0,0 → 1,458
/*
* sata-drv.c
*
* Linux block device driver for Ashwin Mendon's SATA controller.
*
* Author: Bin Huang <bin.arthur@gmail.com>
*
* 2012 (c) Reconfigurable Computing System Lab at University of North
* Carolina at Charlotte. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied. The code originally comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates.
*/
 
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h> /* invalidate_bdev */
#include <linux/bio.h>
#include <linux/delay.h> /* udelay() */
#include "sata_drv.h"
 
MODULE_LICENSE("Dual BSD/GPL");
 
static int sata_major = 0;
module_param(sata_major, int, 0);
static int hardsect_size = HARDSECT_SIZE;
module_param(hardsect_size, int, 0);
static int nsectors = N_SECTORS; /* How big the drive is */
module_param(nsectors, int, 0);
static int ndevices = 1;
module_param(ndevices, int, 0);
 
/*
* The different "request modes" we can use.
*/
enum {
RM_SIMPLE = 0, /* The extra-simple request function */
RM_FULL = 1, /* The full-blown version */
RM_NOQUEUE = 2, /* Use make_request */
};
static int request_mode = RM_NOQUEUE;
module_param(request_mode, int, 0);
 
static struct sata_dev *Devices = NULL;
 
 
void read_sectors(struct sata_dev *dev, int sector_addr, int sector_count, unsigned int dma_phy_addr);
void write_sectors(struct sata_dev *dev, int sector_addr, int sector_count, unsigned int dma_phy_addr);
 
void read_sectors(struct sata_dev *dev, int sector_addr, int sector_count, unsigned int dma_phy_addr)
{
 
// DDR Read Space Start Address
dev->scp->npi_wr_addr_reg = dma_phy_addr;
// Clear SATA Control Register
dev->scp->ctrl_reg = REG_CLEAR;
 
// Input Sector Address, Count and Command to Sata Core
dev->scp->sector_addr_reg = sector_addr;
dev->scp->sector_count_reg = sector_count;
dev->scp->cmd_reg = (READ_CMD);
// Trigger SATA Core
dev->scp->ctrl_reg = (NEW_CMD);
 
// Wait for Command Completion
while ((dev->scp->status_reg & SATA_CORE_DONE) != SATA_CORE_DONE);
 
//Time to Read Sectors from Disk
#ifdef CONFIG_RCS_SATA_DEBUG
printk("Number of clock cycles to complete this read: %d\n",dev->scp->sector_timer_reg);
#endif
 
while ((dev->scp->status_reg & NPI_DONE) != NPI_DONE);
}
 
 
void write_sectors(struct sata_dev *dev, int sector_addr, int sector_count, unsigned int dma_phy_addr)
{
// DDR Write Space Start Address
dev->scp->npi_rd_addr_reg = dma_phy_addr;
// Clear SATA Control Register
dev->scp->ctrl_reg = REG_CLEAR;
 
// Input Sector Address, Count, DATA and Command to Sata Core
dev->scp->sector_addr_reg = sector_addr;
dev->scp->sector_count_reg = sector_count;
//scp->wr_data_reg = write_data;
dev->scp->cmd_reg = (WRITE_CMD);
// Trigger SATA Core
dev->scp->ctrl_reg = (NEW_CMD);
// Wait for Command Completion
 
while ((dev->scp->status_reg & SATA_CORE_DONE) != SATA_CORE_DONE);
 
//Time to Write Sectors from Disk
#ifdef CONFIG_RCS_SATA_DEBUG
printk("Number of clock cycles to complete this write: %d\n",dev->scp->sector_timer_reg);
#endif
}
 
 
/*
* Handle an I/O request.
*/
static void sata_transfer(struct sata_dev *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
unsigned long offset = sector*KERNEL_SECTOR_SIZE;
unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;
 
if ((offset + nbytes) > dev->size) {
printk (KERN_INFO "Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
if (write){
#ifdef CONFIG_RCS_SATA_DEBUG
printk (KERN_INFO "Write request to: \n");
printk (KERN_INFO "sector = %lu, nsect = %lu, buf_phy_addr = 0x%08lx ... \n ", sector, nsect, virt_to_phys(buffer));
#endif
 
write_sectors(dev, sector, nsect, virt_to_phys(buffer));
 
#ifdef CONFIG_RCS_SATA_DEBUG
printk (KERN_INFO "Write done.\n");
#endif
}
else{
#ifdef CONFIG_RCS_SATA_DEBUG
printk (KERN_INFO "Read request to: \n");
printk (KERN_INFO "sector = %lu, nsect = %lu, buf_phy_addr = 0x%08lx ... \n", sector, nsect, virt_to_phys(buffer));
#endif
 
read_sectors(dev, sector, nsect, virt_to_phys(buffer));
 
#ifdef CONFIG_RCS_SATA_DEBUG
printk (KERN_INFO "Read done\n");
#endif
}
}
 
 
static void sata_request(struct request_queue *q)
{
struct request *req;
req = blk_fetch_request(q);
while (req != NULL) {
struct sata_dev *dev = req->rq_disk->private_data;
if (req == NULL || (req->cmd_type != REQ_TYPE_FS)) {
printk (KERN_NOTICE "Skip non-CMD request\n");
__blk_end_request_all(req, -EIO);
continue;
}
sata_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req),
req->buffer, rq_data_dir(req));
if ( ! __blk_end_request_cur(req, 0) ) {
req = blk_fetch_request(q);
}
}
}
 
 
/*
* Transfer a single BIO.
*/
static int sata_xfer_bio(struct sata_dev *dev, struct bio *bio)
{
int i;
struct bio_vec *bvec;
sector_t sector = bio->bi_sector;
 
void *mem;
 
// Do each segment independently.
bio_for_each_segment(bvec, bio, i) {
char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);
 
mem = kmap(bvec->bv_page);
kunmap(bvec->bv_page);
 
sata_transfer(dev, sector, bio_cur_bytes(bio) >> SECTOR_SHIFT,
buffer, bio_data_dir(bio) == WRITE);
sector += bio_cur_bytes(bio) >> SECTOR_SHIFT;
__bio_kunmap_atomic(bio, KM_USER0);
}
return 0; // Always "succeed"
}
 
 
/*
* The direct make request version.
*/
static int sata_make_request(struct request_queue *q, struct bio *bio)
{
struct sata_dev *dev = q->queuedata;
int status;
 
status = sata_xfer_bio(dev, bio);
bio_endio(bio, status);
return 0;
}
 
 
/*
* Open and close.
*/
 
static int sata_open(struct block_device *bdev, fmode_t mode)
{
struct sata_dev *dev = bdev->bd_disk->private_data;
unsigned long flags;
spin_lock_irqsave(&dev->lock, flags);
dev->users++;
spin_unlock_irqrestore(&dev->lock, flags);
 
check_disk_change(bdev);
return 0;
}
 
 
static int sata_release(struct gendisk *disk, fmode_t mode)
{
struct sata_dev *dev = disk->private_data;
 
spin_lock(&dev->lock);
dev->users--;
 
spin_unlock(&dev->lock);
 
return 0;
}
 
 
/*
* The HDIO_GETGEO ioctl is handled in blkdev_ioctl.
*/
int sata_getgeo (struct block_device *bdev, struct hd_geometry *geo)
{
long size;
struct sata_dev *dev = bdev->bd_disk->private_data;
 
printk(KERN_INFO "SATA block device driver command : HDIO_GETGEO .\n");
size = dev->size*(hardsect_size/KERNEL_SECTOR_SIZE);
geo->cylinders = (size & ~0x3f) >> 6;
geo->heads = 4;
geo->sectors = 16;
geo->start = 0;
return 0;
 
}
 
 
/*
* The device operations structure.
*/
static struct block_device_operations sata_ops =
{
.owner = THIS_MODULE,
.open = sata_open,
.release = sata_release,
.getgeo = sata_getgeo
};
 
 
/*
* Set up our internal device.
*/
static int setup_device(struct sata_dev *dev, int which)
{
int retval = 0;
int try_setup_link = 0;
/*
* Initialize data structure.
*/
memset (dev, 0, sizeof (struct sata_dev));
dev->size = nsectors*hardsect_size;
 
/*
* Remap I/O for SATA controller.
*/
 
if( !request_mem_region(SATA_CFG_BASE, SATA_CFG_REMAP_SIZE, DRIVER_NAME)){
printk(KERN_ERR "Request for SATA configuration memory region failed!\n");
dev->scp = 0;
retval = -1;
goto fail;
}
else {
dev->scp = (SATA_core_t *) ioremap_nocache(SATA_CFG_BASE, SATA_CFG_REMAP_SIZE);
if (dev->scp == 0) {
printk(KERN_ERR
"%s: Couldn't ioremap memory at 0x%08X\n",
DRIVER_NAME, SATA_CFG_BASE);
iounmap(dev->scp);
retval = -EFAULT;
goto fail;
}
else {
#ifdef CONFIG_RCS_SATA_DEBUG
printk(KERN_INFO "Remap Returned Virtual Address: %x\n",(unsigned int)dev->scp);
#endif
}
}
 
dev->scp->ctrl_reg = REG_CLEAR;
dev->scp->cmd_reg = REG_CLEAR;
 
while ((dev->scp->status_reg & SATA_LINK_READY) != SATA_LINK_READY)
{
dev->scp->ctrl_reg = SW_RESET;
dev->scp->ctrl_reg = REG_CLEAR;
 
try_setup_link++;
 
udelay(100000);
 
//It is very disk specific. For the OCZ SSD, it takes a few resets for the link
//to come up but on the Micron SSD or on the Western Digital HD, it comes up
//after the first reset.
if (try_setup_link == 100) {
#ifdef CONFIG_RCS_SATA_DEBUG
printk(KERN_INFO "SATA Link is not ready yet.\n");
#endif
retval = -ENODEV;
goto fail;
}
}
 
spin_lock_init(&dev->lock);
/*
* The I/O queue, depending on whether we are using our own
* make_request function or not.
*/
switch (request_mode) {
case RM_NOQUEUE:
dev->queue = blk_alloc_queue(GFP_KERNEL);
if (dev->queue == NULL)
goto fail;
blk_queue_make_request(dev->queue, sata_make_request);
break;
 
case RM_SIMPLE:
dev->queue = blk_init_queue(sata_request, &dev->lock);
if (dev->queue == NULL)
{
retval = -ENODEV;
goto fail;
}
break;
 
default:
printk(KERN_NOTICE "Bad request mode %d, using simple\n", request_mode);
}
blk_queue_logical_block_size(dev->queue, hardsect_size);
dev->queue->queuedata = dev;
 
/*
* And the gendisk structure.
*/
dev->gd = alloc_disk(SATA_MINORS);
if (! dev->gd) {
printk (KERN_INFO "alloc_disk failure\n");
retval = -ENODEV;
goto fail;
}
printk (KERN_INFO "alloc_disk success\n");
dev->gd->major = sata_major;
dev->gd->first_minor = which*SATA_MINORS;
dev->gd->fops = &sata_ops;
dev->gd->queue = dev->queue;
dev->gd->private_data = dev;
snprintf (dev->gd->disk_name, 32, "sata%c", which + 'a');
set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));
add_disk(dev->gd);
 
return 0; /* success */
 
fail:
printk(KERN_INFO "Fail to setup SATA block device.\n");
printk("SATA controller status: 0x%08x\n", dev->scp->status_reg);
return retval;
}
 
 
static int __init sata_init(void)
{
int i;
int retval = 0;
 
/*
* Get registered.
*/
printk(KERN_INFO "Block device driver for sata controller\n");
sata_major = register_blkdev(sata_major, "sata");
if (sata_major <= 0) {
printk(KERN_WARNING "sata: unable to get major number\n");
return -EBUSY;
}
 
/*
* Allocate the device array, and initialize each one.
*/
Devices = kmalloc(ndevices*sizeof (struct sata_dev), GFP_KERNEL);
if (Devices == NULL)
goto out_unregister;
for (i = 0; i < ndevices; i++){
retval = setup_device(Devices + i, i);
}
return retval;
 
out_unregister:
unregister_blkdev(sata_major, "sata");
return -ENOMEM;
}
 
 
static void sata_exit(void)
{
int i;
 
for (i = 0; i < ndevices; i++) {
struct sata_dev *dev = Devices + i;
 
if (dev->gd) {
del_gendisk(dev->gd);
put_disk(dev->gd);
}
if (dev->queue) {
if (request_mode == RM_NOQUEUE)
blk_put_queue(dev->queue);
else
blk_cleanup_queue(dev->queue);
}
}
unregister_blkdev(sata_major, "sata");
kfree(Devices);
}
module_init(sata_init);
module_exit(sata_exit);
/sata_controller_core/trunk/sata2_driver_v1_00_a/sata_drv.h
0,0 → 1,58
/*
* sata_drv.h
*
* Definitions for the SATA device driver
*
* Author: Bin Huang <bin.arthur@gmail.com>
*
* 2012 (c) Reconfigurable Computing System Lab at University of North
* Carolina at Charlotte. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied. The code originally comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates.
*/
 
#include <linux/ioctl.h>
#include "sata_cfg.h"
 
#define DRIVER_NAME "sata"
 
/*
* Minor number and partition management.
*/
#define SATA_MINORS 2
#define MINOR_SHIFT 4
#define DEVNUM(kdevnum) (MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT
 
/*
* The internal representation of our device.
*/
struct sata_dev {
int size; /* Device size in sectors */
short users; /* How many users */
short media_change; /* Flag a media change? */
spinlock_t lock; /* For mutual exclusion */
struct request_queue *queue; /* The device request queue */
struct gendisk *gd; /* The gendisk structure */
SATA_core_t *scp; /* SATA Core Slave Registers */
};
 
 
#define HARDSECT_SIZE 512
 
/*
* N_SECTORS:
* 409600 -> 200MB
* 819200 -> 400MB
*/
#define N_SECTORS 2097152 //1024MB
 
/*
* We can tweak our hardware sector size, but the kernel talks to us
* in terms of small sectors, always.
*/
#define KERNEL_SECTOR_SIZE 512
 
#define SECTOR_SHIFT 9
/sata_controller_core/trunk/sata2_driver_v1_00_a/Makefile
0,0 → 1,22
LINUX = ../linux-2.6-xlnx
DRIVER_NAME=sata
 
# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := $(DRIVER_NAME).o
$(DRIVER_NAME)-objs := $(DRIVER_NAME)_drv.o
 
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= $(LINUX)
PWD := $(shell pwd)
 
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) ARCH=microblaze CROSS_COMPILE=microblaze-unknown-linux-gnu- modules
endif
 
clean:
rm -rf *.ko *.o *~ modules.order Module.symvers *.mod.c .tmp_versions .$(DRIVER_NAME)*
 
/sata_controller_core/trunk/sata2_driver_v1_00_a/sata_cfg.h
0,0 → 1,52
/*
* sata_cfg.h
*
* Definitions for the SATA core configuration registers
*
* Author: Bin Huang <bin.arthur@gmail.com>
*
* 2012 (c) Reconfigurable Computing System Lab at University of North
* Carolina at Charlotte. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied. The code originally comes from the book "Linux Device
* Drivers" by Alessandro Rubini and Jonathan Corbet, published
* by O'Reilly & Associates.
*/
 
#include "xparameters.h"
 
#define SATA_CFG_BASE XPAR_SATA_CORE_0_BASEADDR
#define SATA_CFG_HIGH XPAR_SATA_CORE_0_HIGHADDR
#define SATA_CFG_REMAP_SIZE (SATA_CFG_HIGH - SATA_CFG_BASE + 1)
 
// Structure maps to SATA Core Slave Registers
typedef struct {
volatile unsigned int ctrl_reg;
volatile unsigned int cmd_reg;
volatile unsigned int status_reg;
volatile unsigned int sector_addr_reg;
volatile unsigned int sector_count_reg;
volatile unsigned int sector_timer_reg;
volatile unsigned int npi_rd_addr_reg;
volatile unsigned int npi_wr_addr_reg;
} SATA_core_t,
*pSATA_core_t;
 
// Special Commands to SATA controller
#define REG_CLEAR 0x00000000
#define SATA_LINK_READY 0x00000002
#define SW_RESET 0x00000001
#define NPI_DONE 0x00000008
#define SATA_CORE_DONE 0x00000004
#define NEW_CMD 0x00000002
#define READ_CMD 0x00000000
#define WRITE_CMD 0x00000001
#define FPDMA_READ_CMD 0x00000002
#define FPDMA_WRITE_CMD 0x00000003
#define IDEN_DEV_CMD 0x00000004
#define SET_FEATURES_CMD 0x00000005
#define QUEUE_DEPTH 0x00000000
#define QUEUE_DEPTH_INT 1
 
#define WORDS_PER_SECTOR 128

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.