* need help to merge (small) virtual scsi driver upstream.
@ 2009-01-19 19:04 Henrik Stokseth
2009-01-19 19:29 ` Bart Van Assche
2009-01-21 6:12 ` FUJITA Tomonori
0 siblings, 2 replies; 6+ messages in thread
From: Henrik Stokseth @ 2009-01-19 19:04 UTC (permalink / raw)
To: Linux SCSI ML
[-- Attachment #1: Type: text/plain, Size: 821 bytes --]
Hi! I'm one of the developers on the CDEmu project.
We want to get a driver merged into vanilla linux kernel. CDEmu is a
software suite that allows people to take a CD/DVD-image and mount it on
the system in the form of a virtual disc. Major parts of this software
is based on user-space components, but we have a kernel module that's
responsible for acting like a SCSI HBA. Mainly all
this HBA does is to send requests to a userspace daemon for processing
and then fetch the result and send it back to the SCSI subsystem.
The project's homepage is here: http://cdemu.sourceforge.net
I went over the code to make sure it follows the coding style that's
used. Is there anything else I need to do? I'm a programmer but
kernel code is something that I seldom touch.
Any help is appreciated.
Sincerely,
Henrik Stokseth
[-- Attachment #2: v-hba.c --]
[-- Type: text/x-csrc, Size: 25431 bytes --]
/*
* vhba.c
*
* Copyright (C) 2007 Chia-I Wu <b90201047 AT ntu DOT edu DOT tw>
*
* This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/highmem.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <kernel.api.h>
MODULE_AUTHOR("Chia-I Wu");
MODULE_VERSION(VHBA_VERSION);
MODULE_DESCRIPTION("Virtual SCSI HBA");
MODULE_LICENSE("GPL");
#ifdef DEBUG
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
#else
#define DPRINTK(fmt, args...)
#endif
#define scmd_dbg(scmd, fmt, a...) \
dev_dbg(&(scmd)->device->sdev_gendev, fmt, ##a)
#define scmd_warn(scmd, fmt, a...) \
dev_warn(&(scmd)->device->sdev_gendev, fmt, ##a)
#define VHBA_MAX_SECTORS_PER_IO 128
#define VHBA_MAX_ID 32
#define VHBA_CAN_QUEUE 32
#define VHBA_INVALID_ID VHBA_MAX_ID
#define DATA_TO_DEVICE(dir) ((dir) == DMA_TO_DEVICE || (dir) == DMA_BIDIRECTIONAL)
#define DATA_FROM_DEVICE(dir) ((dir) == DMA_FROM_DEVICE || (dir) == DMA_BIDIRECTIONAL)
enum vhba_req_state {
VHBA_REQ_FREE,
VHBA_REQ_PENDING,
VHBA_REQ_READING,
VHBA_REQ_SENT,
VHBA_REQ_WRITING,
};
struct vhba_command {
struct scsi_cmnd *cmd;
int status;
struct list_head entry;
};
struct vhba_device {
uint id;
spinlock_t cmd_lock;
struct list_head cmd_list;
wait_queue_head_t cmd_wq;
atomic_t refcnt;
};
struct vhba_host {
struct Scsi_Host *shost;
spinlock_t cmd_lock;
int cmd_next;
struct vhba_command commands[VHBA_CAN_QUEUE];
spinlock_t dev_lock;
struct vhba_device *devices[VHBA_MAX_ID];
int num_devices;
DECLARE_BITMAP(chgmap, VHBA_MAX_ID);
struct work_struct scan_devices;
};
#define MAX_COMMAND_SIZE 16
struct vhba_request {
__u32 tag;
__u32 lun;
__u8 cdb[MAX_COMMAND_SIZE];
__u8 cdb_len;
__u32 data_len;
};
struct vhba_response {
__u32 tag;
__u32 status;
__u32 data_len;
};
static struct vhba_command *vhba_alloc_command(void);
static void vhba_free_command(struct vhba_command *vcmd);
static struct platform_device vhba_platform_device;
static struct vhba_device *vhba_device_alloc(void)
{
struct vhba_device *vdev;
vdev = kzalloc(sizeof(struct vhba_device), GFP_KERNEL);
if (!vdev)
return NULL;
vdev->id = VHBA_INVALID_ID;
spin_lock_init(&vdev->cmd_lock);
INIT_LIST_HEAD(&vdev->cmd_list);
init_waitqueue_head(&vdev->cmd_wq);
atomic_set(&vdev->refcnt, 1);
return vdev;
}
static void vhba_device_put(struct vhba_device *vdev)
{
if (atomic_dec_and_test(&vdev->refcnt))
kfree(vdev);
}
static struct vhba_device *vhba_device_get(struct vhba_device *vdev)
{
atomic_inc(&vdev->refcnt);
return vdev;
}
static int vhba_device_queue(struct vhba_device *vdev, struct scsi_cmnd *cmd)
{
struct vhba_command *vcmd;
unsigned long flags;
vcmd = vhba_alloc_command();
if (!vcmd)
return SCSI_MLQUEUE_HOST_BUSY;
vcmd->cmd = cmd;
spin_lock_irqsave(&vdev->cmd_lock, flags);
list_add_tail(&vcmd->entry, &vdev->cmd_list);
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
wake_up_interruptible(&vdev->cmd_wq);
return 0;
}
static int vhba_device_dequeue(struct vhba_device *vdev, struct scsi_cmnd *cmd)
{
struct vhba_command *vcmd;
int retval;
unsigned long flags;
spin_lock_irqsave(&vdev->cmd_lock, flags);
list_for_each_entry(vcmd, &vdev->cmd_list, entry) {
if (vcmd->cmd == cmd) {
list_del_init(&vcmd->entry);
break;
}
}
/* command not found */
if (&vcmd->entry == &vdev->cmd_list) {
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
return SUCCESS;
}
while (vcmd->status == VHBA_REQ_READING || vcmd->status == VHBA_REQ_WRITING) {
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
scmd_dbg(cmd, "wait for I/O before aborting\n");
schedule_timeout(1);
spin_lock_irqsave(&vdev->cmd_lock, flags);
}
retval = (vcmd->status == VHBA_REQ_SENT) ? FAILED : SUCCESS;
vhba_free_command(vcmd);
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
return retval;
}
static void vhba_scan_devices(struct work_struct *work)
{
struct vhba_host *vhost = container_of(work, struct vhba_host, scan_devices);
int id;
unsigned long flags;
/* no need to lock here; it'll be scheduled and run again if some device missed */
while ((id = find_first_bit(vhost->chgmap, vhost->shost->max_id)) < vhost->shost->max_id) {
int remove;
spin_lock_irqsave(&vhost->dev_lock, flags);
clear_bit(id, vhost->chgmap);
remove = !(vhost->devices[id]);
spin_unlock_irqrestore(&vhost->dev_lock, flags);
dev_dbg(&vhost->shost->shost_gendev, "try to %s target 0:%d:0\n", (remove) ? "remove" : "add", id);
if (remove) {
struct scsi_device *sdev;
sdev = scsi_device_lookup(vhost->shost, 0, id, 0);
if (sdev) {
scsi_remove_device(sdev);
scsi_device_put(sdev);
}
} else {
scsi_add_device(vhost->shost, 0, id, 0);
}
}
}
static int vhba_add_device(struct vhba_device *vdev)
{
struct vhba_host *vhost;
int i;
unsigned long flags;
vhost = platform_get_drvdata(&vhba_platform_device);
vhba_device_get(vdev);
spin_lock_irqsave(&vhost->dev_lock, flags);
if (vhost->num_devices >= vhost->shost->max_id) {
spin_unlock_irqrestore(&vhost->dev_lock, flags);
vhba_device_put(vdev);
return -EBUSY;
}
for (i = 0; i < vhost->shost->max_id; i++) {
if (vhost->devices[i] == NULL) {
vdev->id = i;
vhost->devices[i] = vdev;
vhost->num_devices++;
set_bit(vdev->id, vhost->chgmap);
break;
}
}
spin_unlock_irqrestore(&vhost->dev_lock, flags);
schedule_work(&vhost->scan_devices);
return 0;
}
static int vhba_remove_device(struct vhba_device *vdev)
{
struct vhba_host *vhost;
unsigned long flags;
vhost = platform_get_drvdata(&vhba_platform_device);
spin_lock_irqsave(&vhost->dev_lock, flags);
set_bit(vdev->id, vhost->chgmap);
vhost->devices[vdev->id] = NULL;
vhost->num_devices--;
vdev->id = VHBA_INVALID_ID;
spin_unlock_irqrestore(&vhost->dev_lock, flags);
vhba_device_put(vdev);
schedule_work(&vhost->scan_devices);
return 0;
}
static struct vhba_device *vhba_lookup_device(int id)
{
struct vhba_host *vhost;
struct vhba_device *vdev = NULL;
unsigned long flags;
vhost = platform_get_drvdata(&vhba_platform_device);
if (likely(id < vhost->shost->max_id)) {
spin_lock_irqsave(&vhost->dev_lock, flags);
vdev = vhost->devices[id];
if (vdev)
vdev = vhba_device_get(vdev);
spin_unlock_irqrestore(&vhost->dev_lock, flags);
}
return vdev;
}
static struct vhba_command *vhba_alloc_command(void)
{
struct vhba_host *vhost;
struct vhba_command *vcmd;
unsigned long flags;
int i;
vhost = platform_get_drvdata(&vhba_platform_device);
spin_lock_irqsave(&vhost->cmd_lock, flags);
vcmd = vhost->commands + vhost->cmd_next++;
if (vcmd->status != VHBA_REQ_FREE) {
for (i = 0; i < vhost->shost->can_queue; i++) {
vcmd = vhost->commands + i;
if (vcmd->status == VHBA_REQ_FREE) {
vhost->cmd_next = i + 1;
break;
}
}
if (i == vhost->shost->can_queue)
vcmd = NULL;
}
if (vcmd)
vcmd->status = VHBA_REQ_PENDING;
vhost->cmd_next %= vhost->shost->can_queue;
spin_unlock_irqrestore(&vhost->cmd_lock, flags);
return vcmd;
}
static void vhba_free_command(struct vhba_command *vcmd)
{
struct vhba_host *vhost;
unsigned long flags;
vhost = platform_get_drvdata(&vhba_platform_device);
spin_lock_irqsave(&vhost->cmd_lock, flags);
vcmd->status = VHBA_REQ_FREE;
spin_unlock_irqrestore(&vhost->cmd_lock, flags);
}
static int vhba_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct vhba_device *vdev;
int retval;
scmd_dbg(cmd, "queue %lu\n", cmd->serial_number);
vdev = vhba_lookup_device(cmd->device->id);
if (!vdev) {
scmd_dbg(cmd, "no such device\n");
cmd->result = DID_NO_CONNECT << 16;
done(cmd);
return 0;
}
cmd->scsi_done = done;
retval = vhba_device_queue(vdev, cmd);
vhba_device_put(vdev);
return retval;
}
static int vhba_abort(struct scsi_cmnd *cmd)
{
struct vhba_device *vdev;
int retval = SUCCESS;
scmd_warn(cmd, "abort %lu\n", cmd->serial_number);
vdev = vhba_lookup_device(cmd->device->id);
if (vdev) {
retval = vhba_device_dequeue(vdev, cmd);
vhba_device_put(vdev);
} else {
cmd->result = DID_NO_CONNECT << 16;
}
return retval;
}
static struct scsi_host_template vhba_template = {
.module = THIS_MODULE,
.name = "vhba",
.proc_name = "vhba",
.queuecommand = vhba_queuecommand,
.eh_abort_handler = vhba_abort,
.can_queue = VHBA_CAN_QUEUE,
.this_id = -1,
.cmd_per_lun = 1,
.max_sectors = VHBA_MAX_SECTORS_PER_IO,
.sg_tablesize = 256,
};
static ssize_t do_request(struct scsi_cmnd *cmd, char __user *buf, size_t buf_len)
{
struct vhba_request vreq;
ssize_t ret;
scmd_dbg(cmd, "request %lu, cdb 0x%x, bufflen %d, use_sg %d\n",
cmd->serial_number, cmd->cmnd[0], scsi_bufflen(cmd), scsi_sg_count(cmd));
ret = sizeof(vreq);
if (DATA_TO_DEVICE(cmd->sc_data_direction))
ret += scsi_bufflen(cmd);
if (ret > buf_len) {
scmd_warn(cmd, "buffer too small (%zd < %zd) for a request\n", buf_len, ret);
return -EIO;
}
vreq.tag = cmd->serial_number;
vreq.lun = cmd->device->lun;
memcpy(vreq.cdb, cmd->cmnd, MAX_COMMAND_SIZE);
vreq.cdb_len = cmd->cmd_len;
vreq.data_len = scsi_bufflen(cmd);
if (copy_to_user(buf, &vreq, sizeof(vreq)))
return -EFAULT;
if (DATA_TO_DEVICE(cmd->sc_data_direction) && vreq.data_len) {
buf += sizeof(vreq);
/* XXX use_sg? */
if (copy_to_user(buf, scsi_sglist(cmd), vreq.data_len))
return -EFAULT;
}
return ret;
}
static ssize_t do_response(struct scsi_cmnd *cmd, const char __user *buf, size_t buf_len, struct vhba_response *res)
{
ssize_t ret = 0;
scmd_dbg(cmd, "response %lu, status %x, data len %d, use_sg %d\n",
cmd->serial_number, res->status, res->data_len, scsi_sg_count(cmd));
if (res->status) {
if (res->data_len > SCSI_SENSE_BUFFERSIZE) {
scmd_warn(cmd, "truncate sense (%d < %d)", SCSI_SENSE_BUFFERSIZE, res->data_len);
res->data_len = SCSI_SENSE_BUFFERSIZE;
}
if (copy_from_user(cmd->sense_buffer, buf, res->data_len))
return -EFAULT;
cmd->result = res->status;
ret += res->data_len;
} else if (DATA_FROM_DEVICE(cmd->sc_data_direction) && scsi_bufflen(cmd)) {
size_t to_read;
if (res->data_len > scsi_bufflen(cmd)) {
scmd_warn(cmd, "truncate data (%d < %d)\n", scsi_bufflen(cmd), res->data_len);
res->data_len = scsi_bufflen(cmd);
}
to_read = res->data_len;
if (scsi_sg_count(cmd)) {
unsigned char buf_stack[64];
unsigned char *kaddr, *uaddr, *kbuf;
struct scatterlist *sg = scsi_sglist(cmd);
int i;
uaddr = (unsigned char *) buf;
if (res->data_len > 64) {
kbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
} else {
kbuf = buf_stack;
}
for (i = 0; i < scsi_sg_count(cmd); i++) {
size_t len = (sg[i].length < to_read) ? sg[i].length : to_read;
if (copy_from_user(kbuf, uaddr, len)) {
if (kbuf != buf_stack)
kfree(kbuf);
return -EFAULT;
}
uaddr += len;
kaddr = kmap_atomic(sg_page(&sg[i]), KM_USER0);
memcpy(kaddr + sg[i].offset, kbuf, len);
kunmap_atomic(kaddr, KM_USER0);
to_read -= len;
if (to_read == 0)
break;
}
if (kbuf != buf_stack)
kfree(kbuf);
} else {
if (copy_from_user(scsi_sglist(cmd), buf, res->data_len))
return -EFAULT;
to_read -= res->data_len;
}
scsi_set_resid(cmd, to_read);
ret += res->data_len - to_read;
}
return ret;
}
static inline struct vhba_command *next_command(struct vhba_device *vdev)
{
struct vhba_command *vcmd;
list_for_each_entry(vcmd, &vdev->cmd_list, entry) {
if (vcmd->status == VHBA_REQ_PENDING)
break;
}
if (&vcmd->entry == &vdev->cmd_list)
vcmd = NULL;
return vcmd;
}
static inline struct vhba_command *match_command(struct vhba_device *vdev, u32 tag)
{
struct vhba_command *vcmd;
list_for_each_entry(vcmd, &vdev->cmd_list, entry) {
if (vcmd->cmd->serial_number == tag)
break;
}
if (&vcmd->entry == &vdev->cmd_list)
vcmd = NULL;
return vcmd;
}
static struct vhba_command *wait_command(struct vhba_device *vdev, unsigned long flags)
{
struct vhba_command *vcmd;
DEFINE_WAIT(wait);
while (!(vcmd = next_command(vdev))) {
if (signal_pending(current))
break;
prepare_to_wait(&vdev->cmd_wq, &wait, TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
schedule();
spin_lock_irqsave(&vdev->cmd_lock, flags);
}
finish_wait(&vdev->cmd_wq, &wait);
if (vcmd)
vcmd->status = VHBA_REQ_READING;
return vcmd;
}
static ssize_t vhba_ctl_read(struct file *file, char __user *buf, size_t buf_len, loff_t *offset)
{
struct vhba_device *vdev;
struct vhba_command *vcmd;
ssize_t ret;
unsigned long flags;
vdev = file->private_data;
spin_lock_irqsave(&vdev->cmd_lock, flags);
vcmd = wait_command(vdev, flags);
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
if (!vcmd)
return -ERESTARTSYS;
ret = do_request(vcmd->cmd, buf, buf_len);
spin_lock_irqsave(&vdev->cmd_lock, flags);
if (ret >= 0) {
vcmd->status = VHBA_REQ_SENT;
*offset += ret;
} else {
vcmd->status = VHBA_REQ_PENDING;
}
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
return ret;
}
static ssize_t vhba_ctl_write(struct file *file, const char __user *buf, size_t buf_len, loff_t *offset)
{
struct vhba_device *vdev;
struct vhba_command *vcmd;
struct vhba_response res;
ssize_t ret;
unsigned long flags;
if (buf_len < sizeof(res))
return -EIO;
if (copy_from_user(&res, buf, sizeof(res)))
return -EFAULT;
vdev = file->private_data;
spin_lock_irqsave(&vdev->cmd_lock, flags);
vcmd = match_command(vdev, res.tag);
if (!vcmd || vcmd->status != VHBA_REQ_SENT) {
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
DPRINTK("not expecting response\n");
return -EIO;
}
vcmd->status = VHBA_REQ_WRITING;
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
ret = do_response(vcmd->cmd, buf + sizeof(res), buf_len - sizeof(res), &res);
spin_lock_irqsave(&vdev->cmd_lock, flags);
if (ret >= 0) {
vcmd->cmd->scsi_done(vcmd->cmd);
ret += sizeof(res);
/* don't compete with vhba_device_dequeue */
if (!list_empty(&vcmd->entry)) {
list_del_init(&vcmd->entry);
vhba_free_command(vcmd);
}
} else {
vcmd->status = VHBA_REQ_SENT;
}
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
return ret;
}
static int vhba_ctl_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct vhba_device *vdev = file->private_data;
struct vhba_host *vhost;
struct scsi_device *sdev;
switch (cmd) {
case 0xBEEF001:
vhost = platform_get_drvdata(&vhba_platform_device);
sdev = scsi_device_lookup(vhost->shost, 0, vdev->id, 0);
if (sdev) {
int id[4] = {
sdev->host->host_no,
sdev->channel,
sdev->id,
sdev->lun
};
scsi_device_put(sdev);
if (copy_to_user((void *)arg, id, sizeof(id)))
return -EFAULT;
return 0;
} else {
return -ENODEV;
}
}
return -ENOTTY;
}
static unsigned int vhba_ctl_poll(struct file *file, poll_table *wait)
{
struct vhba_device *vdev = file->private_data;
unsigned int mask = 0;
unsigned long flags;
poll_wait(file, &vdev->cmd_wq, wait);
spin_lock_irqsave(&vdev->cmd_lock, flags);
if (next_command(vdev))
mask |= POLLIN | POLLRDNORM;
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
return mask;
}
static int vhba_ctl_open(struct inode *inode, struct file *file)
{
struct vhba_device *vdev;
int retval;
DPRINTK("open\n");
/* check if vhba is probed */
if (!platform_get_drvdata(&vhba_platform_device))
return -ENODEV;
vdev = vhba_device_alloc();
if (!vdev)
return -ENOMEM;
if (!(retval = vhba_add_device(vdev)))
file->private_data = vdev;
vhba_device_put(vdev);
return retval;
}
static int vhba_ctl_release(struct inode *inode, struct file *file)
{
struct vhba_device *vdev;
struct vhba_command *vcmd;
unsigned long flags;
DPRINTK("release\n");
vdev = file->private_data;
vhba_device_get(vdev);
vhba_remove_device(vdev);
spin_lock_irqsave(&vdev->cmd_lock, flags);
list_for_each_entry(vcmd, &vdev->cmd_list, entry) {
WARN_ON(vcmd->status == VHBA_REQ_READING || vcmd->status == VHBA_REQ_WRITING);
scmd_warn(vcmd->cmd, "device released with command %lu\n", vcmd->cmd->serial_number);
vcmd->cmd->result = DID_NO_CONNECT << 16;
vcmd->cmd->scsi_done(vcmd->cmd);
vhba_free_command(vcmd);
}
INIT_LIST_HEAD(&vdev->cmd_list);
spin_unlock_irqrestore(&vdev->cmd_lock, flags);
vhba_device_put(vdev);
return 0;
}
static struct file_operations vhba_ctl_fops = {
.owner = THIS_MODULE,
.open = vhba_ctl_open,
.release = vhba_ctl_release,
.read = vhba_ctl_read,
.write = vhba_ctl_write,
.poll = vhba_ctl_poll,
.ioctl = vhba_ctl_ioctl,
};
static struct miscdevice vhba_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "vhba_ctl",
.fops = &vhba_ctl_fops,
};
static int vhba_probe(struct platform_device *pdev)
{
struct Scsi_Host *shost;
struct vhba_host *vhost;
int i;
shost = scsi_host_alloc(&vhba_template, sizeof(struct vhba_host));
if (!shost)
return -ENOMEM;
shost->max_id = VHBA_MAX_ID;
/* we don't support lun > 0 */
shost->max_lun = 1;
vhost = (struct vhba_host *) shost->hostdata;
memset(vhost, 0, sizeof(*vhost));
vhost->shost = shost;
vhost->num_devices = 0;
spin_lock_init(&vhost->dev_lock);
spin_lock_init(&vhost->cmd_lock);
INIT_WORK(&vhost->scan_devices, vhba_scan_devices);
vhost->cmd_next = 0;
for (i = 0; i < vhost->shost->can_queue; i++)
vhost->commands[i].status = VHBA_REQ_FREE;
platform_set_drvdata(pdev, vhost);
if (scsi_add_host(shost, &pdev->dev)) {
scsi_host_put(shost);
return -ENOMEM;
}
return 0;
}
static int vhba_remove(struct platform_device *pdev)
{
struct vhba_host *vhost;
struct Scsi_Host *shost;
vhost = platform_get_drvdata(pdev);
shost = vhost->shost;
scsi_remove_host(shost);
scsi_host_put(shost);
return 0;
}
static void vhba_release(struct device * dev)
{
return;
}
static struct platform_device vhba_platform_device = {
.name = "vhba",
.id = -1,
.dev = {
.release = vhba_release,
},
};
static struct platform_driver vhba_platform_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "vhba",
},
.probe = vhba_probe,
.remove = vhba_remove,
};
static int __init vhba_init(void)
{
int ret;
ret = platform_device_register(&vhba_platform_device);
if (ret < 0)
return ret;
ret = platform_driver_register(&vhba_platform_driver);
if (ret < 0) {
platform_device_unregister(&vhba_platform_device);
return ret;
}
ret = misc_register(&vhba_miscdev);
if (ret < 0) {
platform_driver_unregister(&vhba_platform_driver);
platform_device_unregister(&vhba_platform_device);
return ret;
}
return 0;
}
static void __exit vhba_exit(void)
{
misc_deregister(&vhba_miscdev);
platform_driver_unregister(&vhba_platform_driver);
platform_device_unregister(&vhba_platform_device);
}
module_init(vhba_init);
module_exit(vhba_exit);
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: need help to merge (small) virtual scsi driver upstream.
2009-01-19 19:04 need help to merge (small) virtual scsi driver upstream Henrik Stokseth
@ 2009-01-19 19:29 ` Bart Van Assche
2009-01-21 6:12 ` FUJITA Tomonori
1 sibling, 0 replies; 6+ messages in thread
From: Bart Van Assche @ 2009-01-19 19:29 UTC (permalink / raw)
To: Henrik Stokseth; +Cc: Linux SCSI ML
On Mon, Jan 19, 2009 at 8:04 PM, Henrik Stokseth <henrik@hw0.org> wrote:
> Hi! I'm one of the developers on the CDEmu project.
>
> We want to get a driver merged into vanilla linux kernel. CDEmu is a
> software suite that allows people to take a CD/DVD-image and mount it on
> the system in the form of a virtual disc. Major parts of this software
> is based on user-space components, but we have a kernel module that's
> responsible for acting like a SCSI HBA. Mainly all
> this HBA does is to send requests to a userspace daemon for processing
> and then fetch the result and send it back to the SCSI subsystem.
>
> The project's homepage is here: http://cdemu.sourceforge.net
>
> I went over the code to make sure it follows the coding style that's
> used. Is there anything else I need to do? I'm a programmer but
> kernel code is something that I seldom touch.
Does your software emulate a SCSI CD drive ? If so, are you familiar
with the support for userspace SCSI targets in STGT and/or SCST ?
Bart.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: need help to merge (small) virtual scsi driver upstream.
2009-01-19 19:04 need help to merge (small) virtual scsi driver upstream Henrik Stokseth
2009-01-19 19:29 ` Bart Van Assche
@ 2009-01-21 6:12 ` FUJITA Tomonori
2009-01-21 7:45 ` Henrik Stokseth
1 sibling, 1 reply; 6+ messages in thread
From: FUJITA Tomonori @ 2009-01-21 6:12 UTC (permalink / raw)
To: henrik; +Cc: linux-scsi
On Mon, 19 Jan 2009 20:04:50 +0100
Henrik Stokseth <henrik@hw0.org> wrote:
> Hi! I'm one of the developers on the CDEmu project.
>
> We want to get a driver merged into vanilla linux kernel. CDEmu is a
> software suite that allows people to take a CD/DVD-image and mount it on
> the system in the form of a virtual disc. Major parts of this software
> is based on user-space components, but we have a kernel module that's
> responsible for acting like a SCSI HBA. Mainly all
> this HBA does is to send requests to a userspace daemon for processing
> and then fetch the result and send it back to the SCSI subsystem.
>
> The project's homepage is here: http://cdemu.sourceforge.net
>
> I went over the code to make sure it follows the coding style that's
> used. Is there anything else I need to do? I'm a programmer but
> kernel code is something that I seldom touch.
>From a quick look at the patch, your driver links requests to a list
and then the user-space daemon reads the requests via the special
character device file and sends the response back to kernel space.
If I correctly understand what you want, there are some possible
alternatives, I guess.
Note that I'm not sure 2) and 3) is acceptable to the SCSI maintainer.
1) use iSCSI initiator and target on the same machine
First, set up iSCSI target software supporting CD/DVD. For example,
you can use tgt (http://stgt.berlios.de), user-space program.
Then you set up the iSCSI initiator to connect the target. Basically,
the iSCSI initiator works like a virtual hba as you like. The iSCSI
initiator and target communicate via tcp while your software
communicates via the special character device.
If you go with this setup, all you need are already in mainline.
2) extend SCSI_TGT
CONFIG_SCSI_TGT and CONFIG_SCSI_IBMVSCSIS do the similar thing as you
do, creating a virtual hba, sending requests to userspace, and getting
the responses. CONFIG_SCSI_IBMVSCSIS is designed for IBM POWER
architectures. But you can implement a new driver working with
CONFIG_SCSI_TGT. CONFIG_SCSI_TGT also uses tgt so CD/DVD support is
ready.
3) extend scsi_debug.c
drivers/scsi/scsi_debug.c provides a virtual hba and virtual disk. You
could extend it to support CD/DVD.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: need help to merge (small) virtual scsi driver upstream.
2009-01-21 6:12 ` FUJITA Tomonori
@ 2009-01-21 7:45 ` Henrik Stokseth
2009-01-21 23:09 ` FUJITA Tomonori
2009-01-23 20:23 ` Vladislav Bolkhovitin
0 siblings, 2 replies; 6+ messages in thread
From: Henrik Stokseth @ 2009-01-21 7:45 UTC (permalink / raw)
To: FUJITA Tomonori, Linux SCSI ML
FUJITA Tomonori wrote:
>
>
> From a quick look at the patch, your driver links requests to a list
> and then the user-space daemon reads the requests via the special
> character device file and sends the response back to kernel space.
>
> If I correctly understand what you want, there are some possible
> alternatives, I guess.
>
> Note that I'm not sure 2) and 3) is acceptable to the SCSI maintainer.
>
>
> 1) use iSCSI initiator and target on the same machine
>
> First, set up iSCSI target software supporting CD/DVD. For example,
> you can use tgt (http://stgt.berlios.de), user-space program.
>
> Then you set up the iSCSI initiator to connect the target. Basically,
> the iSCSI initiator works like a virtual hba as you like. The iSCSI
> initiator and target communicate via tcp while your software
> communicates via the special character device.
>
> If you go with this setup, all you need are already in mainline.
>
It would be desirable for us to rely upon an interface already present
in the mainstream kernel for practical reasons.
Pardon the dumb question but is it possible to talk to the TGT framework
without using iSCSI?
SCST has a nice user-space interface but I couldn't tell whether STGT
had something similar (as documentation is pretty much non-existent).
ありがとう。
Sincerely,
Henrik Stokseth.
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: need help to merge (small) virtual scsi driver upstream.
2009-01-21 7:45 ` Henrik Stokseth
@ 2009-01-21 23:09 ` FUJITA Tomonori
2009-01-23 20:23 ` Vladislav Bolkhovitin
1 sibling, 0 replies; 6+ messages in thread
From: FUJITA Tomonori @ 2009-01-21 23:09 UTC (permalink / raw)
To: henrik; +Cc: fujita.tomonori, linux-scsi
On Wed, 21 Jan 2009 08:45:04 +0100
Henrik Stokseth <henrik@hw0.org> wrote:
> FUJITA Tomonori wrote:
> >
> >
> > From a quick look at the patch, your driver links requests to a list
> > and then the user-space daemon reads the requests via the special
> > character device file and sends the response back to kernel space.
> >
> > If I correctly understand what you want, there are some possible
> > alternatives, I guess.
> >
> > Note that I'm not sure 2) and 3) is acceptable to the SCSI maintainer.
> >
> >
> > 1) use iSCSI initiator and target on the same machine
> >
> > First, set up iSCSI target software supporting CD/DVD. For example,
> > you can use tgt (http://stgt.berlios.de), user-space program.
> >
> > Then you set up the iSCSI initiator to connect the target. Basically,
> > the iSCSI initiator works like a virtual hba as you like. The iSCSI
> > initiator and target communicate via tcp while your software
> > communicates via the special character device.
> >
> > If you go with this setup, all you need are already in mainline.
> >
>
> It would be desirable for us to rely upon an interface already present
> in the mainstream kernel for practical reasons.
>
> Pardon the dumb question but is it possible to talk to the TGT framework
> without using iSCSI?
>
> SCST has a nice user-space interface but I couldn't tell whether STGT
> had something similar (as documentation is pretty much non-existent).
tgt has such but I don't think that anyone needs to use tgt's
interface between user and kernel space so there is no documentation
(it's better to have such though). tgt user-space daemon supports sbc,
ssc, smc, mmc, and osd emulation. Why do you need to invent your own
user-space tgt daemon?
Why you can't simply use iSCSI? It should work for you.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: need help to merge (small) virtual scsi driver upstream.
2009-01-21 7:45 ` Henrik Stokseth
2009-01-21 23:09 ` FUJITA Tomonori
@ 2009-01-23 20:23 ` Vladislav Bolkhovitin
1 sibling, 0 replies; 6+ messages in thread
From: Vladislav Bolkhovitin @ 2009-01-23 20:23 UTC (permalink / raw)
To: Henrik Stokseth; +Cc: FUJITA Tomonori, Linux SCSI ML, scst-devel
Henrik Stokseth, on 01/21/2009 10:45 AM wrote:
> FUJITA Tomonori wrote:
>>
>> From a quick look at the patch, your driver links requests to a list
>> and then the user-space daemon reads the requests via the special
>> character device file and sends the response back to kernel space.
>>
>> If I correctly understand what you want, there are some possible
>> alternatives, I guess.
>>
>> Note that I'm not sure 2) and 3) is acceptable to the SCSI maintainer.
>>
>>
>> 1) use iSCSI initiator and target on the same machine
>>
>> First, set up iSCSI target software supporting CD/DVD. For example,
>> you can use tgt (http://stgt.berlios.de), user-space program.
>>
>> Then you set up the iSCSI initiator to connect the target. Basically,
>> the iSCSI initiator works like a virtual hba as you like. The iSCSI
>> initiator and target communicate via tcp while your software
>> communicates via the special character device.
>>
>> If you go with this setup, all you need are already in mainline.
I'm not sure CDEmu's users would be happy to additionally learn how to
setup and use both iSCSI target and initiator..
> It would be desirable for us to rely upon an interface already present
> in the mainstream kernel for practical reasons.
>
> Pardon the dumb question but is it possible to talk to the TGT framework
> without using iSCSI?
> SCST has a nice user-space interface but I couldn't tell whether STGT
> had something similar (as documentation is pretty much non-existent).
If SCST was in the mainline kernel, the only thing you would need is to
write a small glue layer between CDEmu and the user space interface,
provided by scst_user module. There would be no need for any your
additional kernel module. Then using scst_local module you would be able
to use CDEmu facilities. Also you would be automatically able to use
them on any remote initiator with any supported by SCST SCSI transport
(iSCSI, Fibre Channel, etc..). STGT doesn't provide such possibility.
You can vote for SCST inclusion in the mainline kernel when in the next
couple of months I will send its patches for the next iteration of the
review and inclusion.
Vlad
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-01-23 20:23 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-19 19:04 need help to merge (small) virtual scsi driver upstream Henrik Stokseth
2009-01-19 19:29 ` Bart Van Assche
2009-01-21 6:12 ` FUJITA Tomonori
2009-01-21 7:45 ` Henrik Stokseth
2009-01-21 23:09 ` FUJITA Tomonori
2009-01-23 20:23 ` Vladislav Bolkhovitin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox