Commit 815b472b authored by Jeff Garzik's avatar Jeff Garzik

[libata] add ioctl infrastructure

Mainly adding the infrastructure for various ATA ioctls.  Currently
only supports two ATA-specific ioctls:
HDIO_GET_32BIT and HDIO_SET_32BIT (hdparm -c)
parent 7af09f97
......@@ -104,6 +104,7 @@ static struct pci_driver piix_pci_driver = {
static Scsi_Host_Template piix_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -59,7 +59,6 @@ static int ata_choose_xfer_mode(struct ata_port *ap,
u8 *xfer_mode_out,
unsigned int *xfer_shift_out);
static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
static void swap_buf_le16(u16 *buf, unsigned int buf_words);
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
......@@ -2066,7 +2065,7 @@ static void ata_pio_complete (struct ata_port *ap)
ata_qc_complete(qc, drv_stat);
}
static void swap_buf_le16(u16 *buf, unsigned int buf_words)
void swap_buf_le16(u16 *buf, unsigned int buf_words)
{
#ifdef __BIG_ENDIAN
unsigned int i;
......@@ -3561,6 +3560,7 @@ EXPORT_SYMBOL_GPL(ata_bus_reset);
EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_error);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
......
......@@ -29,6 +29,7 @@
#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/uaccess.h>
#include "libata.h"
......@@ -36,6 +37,8 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd);
static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev,
struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *));
static struct ata_device *
ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev);
/**
......@@ -67,6 +70,43 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
return 0;
}
int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
{
struct ata_port *ap;
struct ata_device *dev;
int val = -EINVAL, rc = -EINVAL;
ap = (struct ata_port *) &scsidev->host->hostdata[0];
if (!ap)
goto out;
dev = ata_scsi_find_dev(ap, scsidev);
if (!dev) {
rc = -ENODEV;
goto out;
}
switch (cmd) {
case ATA_IOC_GET_IO32:
val = 0;
if (copy_to_user(arg, &val, 1))
return -EFAULT;
return 0;
case ATA_IOC_SET_IO32:
val = (long) arg;
if (val != 0)
return -EINVAL;
return 0;
default:
rc = -EOPNOTSUPP;
break;
}
out:
return rc;
}
/**
* ata_scsi_qc_new - acquire new ata_queued_cmd reference
......@@ -1172,19 +1212,19 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
* Associated ATA device, or %NULL if not found.
*/
static inline struct ata_device *
ata_scsi_find_dev(struct ata_port *ap, struct scsi_cmnd *cmd)
static struct ata_device *
ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev)
{
struct ata_device *dev;
/* skip commands not addressed to targets we simulate */
if (likely(cmd->device->id < ATA_MAX_DEVICES))
dev = &ap->device[cmd->device->id];
if (likely(scsidev->id < ATA_MAX_DEVICES))
dev = &ap->device[scsidev->id];
else
return NULL;
if (unlikely((cmd->device->channel != 0) ||
(cmd->device->lun != 0)))
if (unlikely((scsidev->channel != 0) ||
(scsidev->lun != 0)))
return NULL;
if (unlikely(!ata_dev_present(dev)))
......@@ -1247,11 +1287,12 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
struct scsi_cmnd *cmd)
{
#ifdef ATA_DEBUG
struct scsi_device *scsidev = cmd->device;
u8 *scsicmd = cmd->cmnd;
DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
ap->id,
cmd->device->channel, cmd->device->id, cmd->device->lun,
scsidev->channel, scsidev->id, scsidev->lun,
scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3],
scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7],
scsicmd[8]);
......@@ -1281,12 +1322,13 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct ata_port *ap;
struct ata_device *dev;
struct scsi_device *scsidev = cmd->device;
ap = (struct ata_port *) &cmd->device->host->hostdata[0];
ap = (struct ata_port *) &scsidev->host->hostdata[0];
ata_scsi_dump_cdb(ap, cmd);
dev = ata_scsi_find_dev(ap, cmd);
dev = ata_scsi_find_dev(ap, scsidev);
if (unlikely(!dev)) {
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
......
......@@ -42,6 +42,7 @@ extern int ata_qc_issue(struct ata_queued_cmd *qc);
extern void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep);
extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf);
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
/* libata-scsi.c */
......
......@@ -178,6 +178,7 @@ static struct pci_driver nv_pci_driver = {
static Scsi_Host_Template nv_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -88,6 +88,7 @@ static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
static Scsi_Host_Template pdc_sata_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -106,6 +106,7 @@ static struct pci_driver sil_pci_driver = {
static Scsi_Host_Template sil_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -76,6 +76,7 @@ static struct pci_driver sis_pci_driver = {
static Scsi_Host_Template sis_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -205,6 +205,7 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
static Scsi_Host_Template k2_sata_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -174,6 +174,7 @@ static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
static Scsi_Host_Template pdc_sata_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -81,6 +81,7 @@ static struct pci_driver svia_pci_driver = {
static Scsi_Host_Template svia_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -190,6 +190,7 @@ irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *reg
static Scsi_Host_Template vsc_sata_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
.eh_strategy_handler = ata_scsi_error,
.can_queue = ATA_DEF_QUEUE,
......
......@@ -182,6 +182,11 @@ enum ata_tf_protocols {
ATA_PROT_ATAPI_DMA, /* packet command with special DMA sauce */
};
enum ata_ioctls {
ATA_IOC_GET_IO32 = 0x309,
ATA_IOC_SET_IO32 = 0x324,
};
/* core structures */
struct ata_prd {
......
......@@ -371,6 +371,7 @@ extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_i
extern void ata_pci_remove_one (struct pci_dev *pdev);
extern int ata_device_add(struct ata_probe_ent *ent);
extern int ata_scsi_detect(Scsi_Host_Template *sht);
extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
extern int ata_scsi_error(struct Scsi_Host *host);
extern int ata_scsi_release(struct Scsi_Host *host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment