Re:Re: problem in sysfs store function count value and buf not appropriate

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

 





Greg KH <greg@xxxxxxxxx> wrote:
On Wed, Mar 22, 2006 at 09:39:51AM -0800, kanishk rastogi wrote:
>
> hi all,
>
> i have created a device file with only write
> permission::
>
> ssize_t add_target_store(struct device *dev, const
> char *buf, size_t count)
> {
> int data;
> struct vt_host_info * vthost;
> vthost=to_vt_host_info(dev);
>
> if(1!=sscanf(buf,"%d",&data))-->it goes inside
> {
> printk(KERN_ERR "Invalid Data Entered count ::%u::
> %s",(unsigned int)count,buf);
> return -EINVAL;
> }
>
> printk("Device target will be added\n");
> return count;
> }
>
> DEVICE_ATTR(add_target, S_IWUSR , NULL,
> add_target_store);
>
> and created the file using ::
> if((i=device_register(dev)))
> return i;
> device_create_file(dev ,&dev_attr_add_target);
> but when i perform
> echo 2 >sysfs file
> it gives garbage

Gives garbage where?
Do you have your whole source code available anywhere?


thanks,

greg k-h

when i dmesg i get garbage value on the console. please note i have used printk in the add_target_store
I have attatched the code
regards


Yahoo! Messenger with Voice. PC-to-Phone calls for ridiculously low rates.


Yahoo! Messenger with Voice. Make PC-to-Phone Calls to the US (and 30+ countries) for 2¢/min or less.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include <scsi/scsicam.h>
#include "scsi_logging.h"
#include <linux/stat.h>

#include "lld.h"

/*Driver Attributes*/

int num_host=NUM_HOST ;
int max_lun=MAX_LUN_PER_TAPE;
int max_target=NUM_TAPE_PER_HOST;
static int add_adapter=0;
static int rm_adapter=0;
/*Driver Attributes ends*/


/*Device Attributes*/

int remove_device;
/*Device Attributes Ends*/
/*Driver Structure Requirements*/

/*Function prototype declarations */

//static int call_inquiry(struct scsi_cmnd *, unsigned int , struct vt_dev_info * );
int fill_from_device_buff(struct scsi_cmnd *,unsigned char *,int );

int vt_remove(struct device *dev)
{
    return 0;
}

static char name[] ="Virtual_Tape_driver";

static struct bus_type vt_bus_type;

static struct device_driver vt_driver = {
    .name   =   name,
    .bus    =   &vt_bus_type,
    .probe  =   vt_probe,
    .remove =   vt_remove,
};


/*attributes discription*/

ssize_t max_target_show(struct device_driver * ddp, char * buf)
{
        return scnprintf(buf, PAGE_SIZE, "%d\n", max_target);
}

ssize_t max_target_store(struct device_driver * ddp,
                  const char * buf, size_t count)
{
        int data;

        if (1 != (count=sscanf(buf, "%d", &data))) {
        return -EINVAL;
        }
		if(data< 1)
		{
			printk("Targets cant be less than 1");
			 return -EINVAL;	
		}
        max_target=data;
        return count ;
}
DRIVER_ATTR(maxi_target, S_IRUGO | S_IWUSR, max_target_show,
        max_target_store);

ssize_t max_lun_show(struct device_driver * ddp, char * buf)
{
        return scnprintf(buf, PAGE_SIZE, "%d\n", max_lun);
}

ssize_t max_lun_store(struct device_driver * ddp,
                  const char * buf, size_t count)
{
        int data;

        if (1 != (count=sscanf(buf, "%d", &data))) {
        return -EINVAL;
		}
		if(data < 1  )
		{
			printk("Invalid Data\n");
			return -EINVAL;
		}
		max_lun=data;
		return count ;
}
DRIVER_ATTR(max_lun, S_IRUGO | S_IWUSR, max_lun_show,
        max_lun_store);

ssize_t add_adapter_show(struct device_driver * ddp, char * buf)
{
        return scnprintf(buf, PAGE_SIZE, "%d\n", add_adapter);
}

ssize_t add_adapter_store(struct device_driver * ddp,
                  const char * buf, size_t count)
{
     	int data;

        if (1 == sscanf(buf, "%d", &data)) {
			if(data	==	add_adapter+1)
			if( FALSE == vt_add_adapter() )
				printk(KERN_ERR "Addition of adapter failed %s\n", __FUNCTION__);
	
        }
    
    return -EINVAL;
}
DRIVER_ATTR(add_adapter, S_IRUGO | S_IWUSR, add_adapter_show,
        add_adapter_store);

ssize_t add_target_store(struct device *dev, const char *buf, size_t count)
{
 	int data;
	 struct vt_host_info * vthost;
	 vthost=to_vt_host_info(dev);

	if(1!=sscanf(buf,"%d",&data))
 	{
	 printk(KERN_ERR "Invalid Data Entered count ::%u:: %s",(unsigned int)count,buf);
	 return -EINVAL;
 }

	return 0;
}


DEVICE_ATTR(add_target, S_IWUSR , NULL,add_target_store);

ssize_t remove_host_store(struct device * dev,const char * buf,size_t count)
{
    int data;
    struct vt_host_info * vthost;
	vthost=to_vt_host_info(dev);
	remove_host(vthost);
    if(1!=sscanf(buf,"%d",&data))
    {
       printk(KERN_ERR "Invalid Data Entered count ::%u::%s",(unsigned int)count,buf);
        return -EINVAL;
    }

    printk(KERN_ERR "Device target will be  removed\n");
    return count;
}

DEVICE_ATTR(remove_host, S_IWUSR , NULL,remove_host_store);

/*attributes discription Ends*/


static void vt_bus_release( struct device *dev)
{
    printk(KERN_DEBUG "vt bus release");

}
/*top level bus device instance*/
static struct device vt_bus = {
    .bus_id = "vtbus0",
    .release = vt_bus_release,
};

static int vt_bus_match(struct device *dev,struct device_driver *drv)
{
    return 1; /*always means new device can be handled by the driver*/
}

static struct bus_type vt_bus_type = {
    .name   =   "vt_bus",
    .match  =   vt_bus_match,
/*where are .subsys, .device, .hotplug etc*/
};


void do_create_driverfs_files()
{
	driver_create_file(&vt_driver,&driver_attr_maxi_target);
	driver_create_file(&vt_driver,&driver_attr_add_adapter);
	driver_create_file(&vt_driver,&driver_attr_max_lun);
}

char tape_info[256];
const char * vir_tape_info(struct Scsi_Host * host)
{

//  sprintf(vtape_info, "virtual tape,dev_size_mb=%d, opts=0x%x",scsi_debug_dev_size_mb,scsi_debug_opts);
    return tape_info;

}

int vir_tape_ioctl(struct scsi_device *sdp, int cmd, void *arg)
{
    return -ENOTTY;
}


static const char * vendor_id = "Linux   ";
static const char * product_id = "virt_tape      ";
static const char * product_rev = "0004";


void timer_intr_handler(unsigned long indx)
{
    struct vt_queued_cmd * sqcp;
    unsigned long iflags;

    if (indx >= VIR_TAPE_CANQUEUE) {
        printk(KERN_ERR "vt:timer_intr_handler: indx too "
               "large\n");
        return;
    }
    spin_lock_irqsave(&queued_arr_lock, iflags);
    sqcp = &queued_arr[(int)indx];
    if (! sqcp->in_use) {
        printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
               "interrupt\n");
        spin_unlock_irqrestore(&queued_arr_lock, iflags);
        return;
    }
    sqcp->in_use = 0;
    if (sqcp->done_funct) {
        sqcp->a_cmnd->result = sqcp->scsi_result;
        sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
    }
    sqcp->done_funct = NULL;
	spin_unlock_irqrestore(&queued_arr_lock, iflags);
}


int fill_from_device_buff(struct scsi_cmnd *scp, unsigned char *arr, int arr_len)
{

    int  req_len, act_len  ;
//    void * kaddr;
//    void * kaddr_off;
//    struct scatterlist * sgpnt;

    if (0 == scp->request_bufflen)
        return 0;
    if (NULL == scp->request_buffer)
        return (DID_ERROR << 16);
    if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
          (scp->sc_data_direction == DMA_FROM_DEVICE)))
        return (DID_ERROR << 16);
    if (0 == scp->use_sg) {
        req_len = scp->request_bufflen;
        act_len = (req_len < arr_len) ? req_len : arr_len;
        memcpy(scp->request_buffer, arr, act_len);
        scp->resid = req_len - act_len;
        return 0;
    }
	return FALSE;
}
	

int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
               const char * dev_id_str, int dev_id_str_len)
{
    int num;

    /* Two identification descriptors: */
    /* T10 vendor identifier field format (faked) */
    arr[0] = 0x2;   /* ASCII */
    arr[1] = 0x1;
    arr[2] = 0x0;
    memcpy(&arr[4], vendor_id, 8);
    memcpy(&arr[12], product_id, 16);
    memcpy(&arr[28], dev_id_str, dev_id_str_len);
    num = 8 + 16 + dev_id_str_len;
    arr[3] = num;
	return num+4;
/*   * NAA IEEE registered identifier (faked) 
    arr[num] = 0x1; 
    arr[num + 1] = 0x3;
    arr[num + 2] = 0x0;
    arr[num + 3] = 0x8;
    arr[num + 4] = 0x51;   
    arr[num + 5] = 0x23;
    arr[num + 6] = 0x45;
    arr[num + 7] = 0x60;
    arr[num + 8] = (dev_id_num >> 24);
    arr[num + 9] = (dev_id_num >> 16) & 0xff;
    arr[num + 10] = (dev_id_num >> 8) & 0xff;
    arr[num + 11] = dev_id_num & 0xff;
    return num + 12;
*/
}

int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
            int bufflen, struct vt_dev_info * devip)
{
    unsigned char arr[VT_MAX_INQ_ARR_SZ];
    int min_len = bufflen > VT_MAX_INQ_ARR_SZ ?
            VT_MAX_INQ_ARR_SZ : bufflen;
	memset(arr, 0, VT_MAX_INQ_ARR_SZ);
	arr[0] = 0x01;  /*TaPe DrIvE EnTrY */
    arr[1] = 0; /* Removable disk */
    arr[2] = vt_scsi_level;//to do
    arr[4] = VT_LONG_INQ_SZ - 5;
    arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
    memcpy(&arr[8], vendor_id, 8);
    memcpy(&arr[16], product_id, 16);
    memcpy(&arr[32], product_rev, 4);
    memcpy(buff, arr, min_len);
    return 0;
}


struct vt_dev_info * devinforeg(struct scsi_device * sdev)
{
    struct vt_host_info * sdbg_host;
    struct vt_dev_info * open_devip = NULL;
    struct vt_dev_info * devip =
            (struct vt_dev_info *)sdev->hostdata;
	if (devip)
        return devip;
    sdbg_host = *(struct vt_host_info **) sdev->host->hostdata;
        if(! sdbg_host) {
                printk(KERN_ERR "Host info NULL\n");
        return NULL;
        }
    list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
        if ((devip->used) && (devip->vt_channel == sdev->channel) &&
                    (devip->vt_target == sdev->id) &&
                    (devip->vt_lun == sdev->lun))
                        return devip;
        else {
            if ((!devip->used) && (!open_devip))
                open_devip = devip;
        }
    }
if (open_devip) {
        open_devip->vt_channel = sdev->channel;
        open_devip->vt_target = sdev->id;
        open_devip->vt_lun = sdev->lun;
        open_devip->vt_host = sdbg_host;
        open_devip->reset = 1;
        open_devip->used = 1;
        memset(open_devip->vt_sense_buff, 0, SENSE_LEN);
        open_devip->vt_sense_buff[0] = 0x70;
        return open_devip;
        }
        return NULL;
}


int schedule_resp(struct scsi_cmnd * cmnd,struct vt_dev_info * devip,void (*done)(struct scsi_cmnd *), int scsi_result, int delta_jiff)
{

/*    if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
        printk(KERN_INFO "scsi_debug: cmd ");
        for (k = 0, num = cmnd->cmd_len; k < num; ++k)
            printk("%02x ", (int)cmnd->cmnd[k]);
        printk("\n");
        if (scsi_result) {
            struct scsi_device * sdp = cmnd->device;

            printk(KERN_INFO "scsi_debug: ... <%u %u %u %u> "
                   "non-zero result=0x%x\n", sdp->host->host_no,
                   sdp->channel, sdp->id, sdp->lun, scsi_result);
        }
    }*/
	if (cmnd && devip) {
        /* simulate autosense by this driver */
        if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
            memcpy(cmnd->sense_buffer, devip->vt_sense_buff,
                   (SCSI_SENSE_BUFFERSIZE > SENSE_LEN) ?
                   SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
    }
	if (delta_jiff <= 0) {
        if (cmnd)
            cmnd->result = scsi_result;
        if (done)
            done(cmnd);
        return 0;
    } else {
        unsigned long iflags;
        unsigned long k;
        struct vt_queued_cmd * sqcp = NULL;
		printk("\nstart of spinlock******\n");

        spin_lock_irqsave(&queued_arr_lock, iflags);
        for (k = 0; k < VIR_TAPE_CANQUEUE; ++k) {
            sqcp = &queued_arr[k];
            if (! sqcp->in_use)
                break;
        }
		if (k >= VIR_TAPE_CANQUEUE) {
            spin_unlock_irqrestore(&queued_arr_lock, iflags);
            printk(KERN_WARNING "vt: can_queue exceeded\n");
            return 1;   /* report busy to mid level */
        }
        sqcp->in_use = 1;
        sqcp->a_cmnd = cmnd;
        sqcp->scsi_result = scsi_result;
        sqcp->done_funct = done;
		sqcp->cmnd_timer.function = timer_intr_handler;
		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
		sqcp->cmnd_timer.data=  k;
        spin_unlock_irqrestore(&queued_arr_lock, iflags);
		printk("\n@#@#@#@end of spinlock******\n");
        if (cmnd)
            cmnd->result = 0;
        return 0;
   } 
}

unsigned char * scatg2virt(const struct scatterlist * sclp)
{
    if (NULL == sclp)
        return NULL;
    else if (sclp->page)
        return (unsigned char *)page_address(sclp->page) +
               sclp->offset;
    else
        return NULL;
}
static struct scsi_host_template vtape_driver_template;

void mk_sense_buffer(struct vt_dev_info * devip,int key,int asc,int asq)
{
	unsigned char * sbuff;
	sbuff=devip->vt_sense_buff;
	memset(sbuff,0,SENSE_LEN);
	sbuff[0] = 0x70;
	sbuff[2] = key;
	sbuff[7] = 0xa;
	sbuff[12] = asc;
	sbuff[13] = asq;
}



int test_unit_ready (struct scsi_cmnd * scp,struct vt_dev_info * devip)
{
	if(devip->reset)
	{
		devip->reset = 0;
		mk_sense_buffer(devip,UNIT_ATTENTION,POWERON_RESET,0);
		return check_condition_result;
	}
	return 0;
	
}	

int resp_report_lun(struct scsi_cmnd * scp,struct vt_dev_info * devip)
{
    unsigned int alloc_len;
    int lun_cnt, i, upper;
    unsigned char *cmd = (unsigned char *)scp->cmnd;
    int select_report = (int)cmd[2];
    struct scsi_lun *one_lun;
    unsigned char arr[VT_RLUN_ARR_SZ];

    alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
    if ((alloc_len < 16) || (select_report > 2)) {
        mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
                    0);
        return check_condition_result;
    }
    /* can produce response with up to 16k luns (lun 0 to lun 16383) */
    memset(arr, 0, VT_RLUN_ARR_SZ);
    lun_cnt = max_lun;
    arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
    arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
    lun_cnt = min((int)((VT_RLUN_ARR_SZ - 8) / sizeof(struct scsi_lun)), lun_cnt);
    one_lun = (struct scsi_lun *) &arr[8];
    for (i = 0; i < lun_cnt; i++) {
        upper = (i >> 8) & 0x3f;
        if (upper)
            one_lun[i].scsi_lun[0] =(upper | (SAM2_LUN_ADDRESS_METHOD << 6));
        one_lun[i].scsi_lun[1] = (i) & 0xff;
    }
    return fill_from_device_buff(scp, arr,min((int)alloc_len, VT_RLUN_ARR_SZ));
}


		
int vir_tape_queuecommand(struct scsi_cmnd * scp,void (*done)(struct scsi_cmnd *))
{
	unsigned char *cmd;
	unsigned char *buff;
    int errsts = 0;
    int target = scp->device->id;
    int bufflen = scp->request_bufflen;
	
	struct vt_dev_info * devip ;
//	scp->use_sg = 0;   //DoNe By Me To MaKe It Not To Perform ScattergatherinG 

	cmd = (unsigned char *) scp->cmnd;
	devip=NULL;
	if (done == NULL)
        return 0;   /* assume mid level reprocessing command */

    if (scp->use_sg) { /* just use first element */
        struct scatterlist *sgpnt = (struct scatterlist *)
                        scp->request_buffer;

        buff = scatg2virt(&sgpnt[0]);//TO DO
        bufflen = sgpnt[0].length;
        /* READ and WRITE process scatterlist themselves */
    }
    else
        buff = (unsigned char *) scp->request_buffer;
    if (NULL == buff) {
        buff = spare_buff;  /* assume cmd moves no data */
        bufflen = SENSE_LEN;
    }
	if(target == vtape_driver_template.this_id) {
        printk(KERN_INFO "scsi_debug: initiator's id used as "
               "target!\n");
        return schedule_resp(scp, NULL, done,
                     DID_NO_CONNECT << 16, 0);
        }
	if (scp->device->lun >= max_lun)
        return schedule_resp(scp, NULL, done,DID_NO_CONNECT << 16, 0);
    devip = devinforeg(scp->device);
    if (NULL == devip)
        return schedule_resp(scp, NULL, done,DID_NO_CONNECT << 16, 0);

/*   if ((scsh_debug_every_nth > 0) &&
            (++scsi_debug_cmnd_count >= scsi_debug_every_nth)) {
                scsi_debug_cmnd_count =0;
        if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
            return 0;  ignore command causing timeout 
        else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
            inj_recovered = 1;  to reads and writes below 
        }
*/
	switch (*cmd) {
    case INQUIRY:     /* mandatory */
        errsts = resp_inquiry(cmd, target, buff, bufflen, devip);
		//errsts = resp_inquiry(cmd,target,devip);
        break;
	case TEST_UNIT_READY:
		errsts = test_unit_ready ( scp, devip );
		break;
	case REPORT_LUNS:
		errsts	=	resp_report_lun( scp, devip);
		break;
	default:
		break;
	}
	return schedule_resp(scp, devip, done, errsts, scsi_debug_delay);
		
}
int vir_tape_release(struct Scsi_Host * shp)
{
    return 0;
}
int vir_tape_slave_alloc(struct scsi_device *sdp)
{
	struct Scsi_Host	*host;
	struct vt_host_info *vthost ;
	struct vt_dev_info *devinfo;
	host =sdp->host;
	vthost =*((struct vt_host_info **)host->hostdata);
	if(NULL==vthost) {
		printk(KERN_ERR "host not found");
		return FALSE;
	}
		
	devinfo = (struct vt_dev_info*)kmalloc(sizeof(struct vt_dev_info), GFP_KERNEL);
	if(!devinfo) {
			printk(KERN_ERR "out of memory %s", __FUNCTION__);
			return FALSE;
	}
	//printk("this_id:%s\n",vthost->dev.bus_id);
	memset(devinfo,0,sizeof(struct vt_dev_info));
	list_add_tail(&(devinfo->dev_list),&(vthost->dev_info_list));	
	devinfo->vt_host = to_vt_host_info(sdp->host);

	devinfo->vt_channel = sdp->channel;
	
	devinfo->vt_host->vt_channel = (devinfo->vt_host->vt_channel < sdp->channel) ? sdp->channel : devinfo->vt_host->vt_channel;
	
			
	devinfo->vt_lun = sdp->lun;
	
	devinfo->vt_host->vt_lun = (devinfo->vt_host->vt_lun < sdp->lun) ? sdp->lun: devinfo->vt_host->vt_lun;
	devinfo->vt_target = sdp->id;
		
	
	devinfo->vt_host->vt_target = (devinfo->vt_host->vt_target < sdp->id) ? sdp->id: devinfo->vt_host->vt_target;

	sdp->hostdata=devinfo;
    
return 0;
}

int vir_tape_slave_configure(struct scsi_device *sdp)
{
	printk("Configure called\n");
    return 0;
}
int vir_tape_slave_destroy(struct scsi_device *sdp)
{
	return 0;
}

int vir_tape_abort(struct scsi_cmnd * scp)
{
    return 0;
}
int vir_tape_bus_reset(struct scsi_cmnd * scp)
{
    return 0;
}
int vir_tape_device_reset(struct scsi_cmnd * scp)
{
    return 0;
}
int vir_tape_host_reset(struct scsi_cmnd * scp)
{
    return 0;
}
static struct scsi_host_template vtape_driver_template = {
    .name   =   "Virtual Tape",
    .info   =   vir_tape_info,
    .ioctl  =   vir_tape_ioctl,
    .queuecommand   =   vir_tape_queuecommand,
    .release    =   vir_tape_release,
    .slave_alloc    =       vir_tape_slave_alloc,
    .slave_configure=       vir_tape_slave_configure,
    .slave_destroy =        vir_tape_slave_destroy,
    .eh_abort_handler = vir_tape_abort,
    .eh_bus_reset_handler = vir_tape_bus_reset,
    .eh_device_reset_handler = vir_tape_device_reset,
    .eh_host_reset_handler = vir_tape_host_reset,
    .can_queue =        VIR_TAPE_CANQUEUE,
    .this_id =      7,
    .sg_tablesize =     64,
    .cmd_per_lun =      3,
    .module =       THIS_MODULE,

};
struct scsi_device *add_target(struct vt_host_info * vthost)
{
	struct scsi_device * sdev=scsi_add_device(vthost->vt_host,vthost->vt_channel,vthost->vt_target+1,vthost->vt_lun);
	if(sdev == ERR_PTR(-ENODEV))
	{
		printk(KERN_ERR "couldn't  add_the device\n");
	}
	return sdev;

}

static void remove_host(struct vt_host_info * vthost)
{
	list_del(&vthost->host_list);
	device_remove_file(&vthost->dev,&dev_attr_add_target);
    device_remove_file(&vthost->dev,&dev_attr_remove_host);
    device_unregister(&vthost->dev);
    --add_adapter;
	rm_adapter++;
	kfree(vthost);
	return;
}

static void vt_release_adapter(struct device *dev)
{
	
	return;
}



static int vt_add_adapter()
{
	int i,dph;
	struct vt_host_info * vthost;
	struct vt_dev_info * vtdev;
	struct list_head * temp1,*temp2;
	vthost=(struct vt_host_info * )kmalloc(sizeof(struct vt_host_info),GFP_KERNEL);
	if(NULL==vthost)
	{
		printk(KERN_ERR "Out of memory at %s",__FUNCTION__);
		return -ENOMEM;
	}
	memset(vthost,0,sizeof(struct vt_host_info));

	INIT_LIST_HEAD(&vthost->dev_info_list);
	dph=max_lun * max_target;
	
	for(i=0;i<dph;i++)
	{
		vtdev=(struct vt_dev_info * )kmalloc(sizeof(struct vt_dev_info),GFP_KERNEL);
	    if(NULL==vtdev)
    	{
        	printk(KERN_ERR "Out of memory at %s",__FUNCTION__);
	        goto clean;
    	}
	    memset(vtdev,0,sizeof(struct vt_dev_info));
		vtdev->vt_host=vthost;
		list_add(&vtdev->dev_list,&vthost->dev_info_list);
	}
	list_add_tail(&vthost->host_list,&vt_host_list);
	
	vthost->dev.bus=&vt_bus_type;
	vthost->dev.parent=&vt_bus;
	vthost->dev.release=vt_release_adapter;
	sprintf(vthost->dev.bus_id,"adapter%d",add_adapter+rm_adapter);
	
	i=device_register(&vthost->dev);
	if(i)
	{
		printk(KERN_ERR "Device Register failed");
		goto clean;
	}
	device_create_file(&vthost->dev,&dev_attr_add_target);
	device_create_file(&vthost->dev,&dev_attr_remove_host);
	vthost->vt_target=0;
	vthost->vt_lun=0;
	vthost->vt_channel=0;
/*TO DO :registe the tapes also.And if u do that what will follow is rapes.*/
	add_adapter++;
	return i;
clean:
	
	list_for_each_safe(temp1,temp2,&vthost->dev_info_list)
	{
		vtdev=list_entry(temp1,struct vt_dev_info,	dev_list);
		list_del(&vtdev->dev_list);
		kfree(vtdev);
	}
	kfree(vthost);
	return i;
}


		

static int vt_probe(struct device *dev)
{
    int error;
    struct vt_host_info * vthost =to_vt_host_info(dev);
    struct Scsi_Host * shost=NULL;

    shost=scsi_host_alloc(&vtape_driver_template,sizeof(vthost));
    if (NULL == shost) {
                printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
                error = -ENODEV;
        return error;
    }
    vthost->vt_host = shost;
    *((struct vt_host_info **)shost->hostdata) = vthost;
    if ((shost->this_id >= 0) && (max_target > shost->this_id))
        shost->max_id = max_target + 1;
    else
        shost->max_id = max_target;
    shost->max_lun = max_lun;
//    INIT_LIST_HEAD(&vthost->dev_info_list);
	printk("Probe: bus_id:%s\n",vthost->dev.bus_id);
    error = scsi_add_host(shost, &vthost->dev);
    if (error) {
        printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
        error = -ENODEV;
        scsi_host_put(shost);
        } else

 		//printk("\nProbe called\n");
        scsi_scan_host(shost);

    return 0;
}
	
	
static int __init vir_tape(void)
{
	int i;
	if( i = device_register(&vt_bus) ) {
        printk(KERN_DEBUG "vtbus0 registration failed\n");
        return i;
    }

	if(i = bus_register(&vt_bus_type))
	{
		printk(KERN_DEBUG "vt bus type registration failed \n");
        return i; /* if bus registration fails */
    }
	driver_register(&vt_driver);
	do_create_driverfs_files();
	for(i=0;i<num_host;i++)
	{
		if(FALSE==vt_add_adapter())//add_adapter will only add the devices
		{
			printk("Couldnt add adapter\n");
			return FALSE;
		}
	}
	return TRUE;

}
	
static void remove_driverfs_files()
{
	driver_remove_file(&vt_driver,&driver_attr_maxi_target);
	driver_remove_file(&vt_driver,&driver_attr_max_lun);
	driver_remove_file(&vt_driver,&driver_attr_add_adapter);
	return;
}

static void remove_adapter()
{
	struct vt_host_info	* vthost=NULL;
	if(!list_empty(&vt_host_list))
	{
		vthost=list_entry(vt_host_list.prev,struct vt_host_info,host_list);
		list_del(&vthost->host_list);
	}
	if(!vthost)
		return;
	device_remove_file(&vthost->dev,&dev_attr_add_target);
	device_remove_file(&vthost->dev,&dev_attr_remove_host);

	device_unregister(&vthost->dev);
	++rm_adapter;
	--add_adapter;
	kfree(vthost);
}

	
static void __exit vir_exit()
{
//	int i,k=add_adapter;
	for(;add_adapter>0;)
	{
		remove_adapter();
	}
	remove_driverfs_files();
	driver_unregister(&vt_driver);	
	bus_unregister(&vt_bus_type);
	device_unregister(&vt_bus);
	return ;
}

module_init(vir_tape);
module_exit(vir_exit);
MODULE_LICENSE("GPL");

#define SENSE_BUFF 32

#define NUM_HOST 1
#define NUM_TAPE_PER_HOST 1
#define MAX_LUN_PER_TAPE 1
#define SAM2_LUN_ADDRESS_METHOD 0
#define VT_RLUN_ARR_SZ 128
#define VIR_TAPE_CANQUEUE	1

#define TRUE 0
#define FALSE 1

#define NO_ADDED_SENSE 0x0
#define UNRECOVERED_READ_ERR 0x11
#define INVALID_OPCODE 0x20
#define ADDR_OUT_OF_RANGE 0x21
#define INVALID_FIELD_IN_CDB 0x24
#define POWERON_RESET 0x29
#define SAVING_PARAMS_UNSUP 0x39
#define THRESHHOLD_EXCEEDED 0x5d

/*#define DEF_DELAY   1
#define DEF_DEV_SIZE_MB   8
#define DEF_EVERY_NTH   0
#define DEF_NUM_PARTS   0
#define DEF_OPTS   0			//PREVIOUS
#define DEF_SCSI_LEVEL   5     INQUIRY, byte2 [5->SPC-3] 
#define DEF_PTYPE   1
#define DEF_D_SENSE   0
*/
#define DEF_DEV_SIZE_MB   8
#define DEF_EVERY_NTH   0
#define DEF_DELAY   0
#define DEF_SCSI_LEVEL   3
#define DEF_OPTS   0
#define DEF_PTYPE 0

#define SENSE_LEN 32


#define VT_LONG_INQ_SZ 58
#define VT_MAX_INQ_ARR_SZ 128

#define SECTOR_SIZE 512
struct vt_host_info
{
	struct device dev;	
	struct list_head    host_list;
	struct list_head    dev_info_list;
	struct Scsi_Host * vt_host;
	unsigned int no_target;
	unsigned int vt_channel;
    unsigned int vt_lun;
    unsigned int vt_target;

};

#define to_vt_host_info(d)	container_of(d,struct vt_host_info,dev)
#define to_vt_host_from_host(d)  container_of(d,struct vt_host_info,vt_host)

struct vt_dev_info
{
	struct list_head	dev_list;
	unsigned int vt_channel;
	unsigned int vt_lun;
	unsigned int vt_target;
	unsigned char vt_sense_buff[SENSE_BUFF];
	struct vt_host_info * vt_host;
	char reset,used;
};

#define to_vt_dev_info(d)  container_of(d,struct vt_dev_info,dev)

static DEFINE_SPINLOCK(queued_arr_lock);
//static DEFINE_RWLOCK(atomic_rw);

/*struct vtape_queued_cmd {
    int in_use;
    struct timer_list cmnd_timer;
    void (*done_funct)(struct scsi_cmnd *);
    struct scsi_cmnd * a_cmnd;
    int scsi_result;
};
static struct vtape_queued_cmd queued_arr[VIR_TAPE_CANQUEUE];
*/
struct vt_queued_cmd {
    int in_use;
    struct timer_list cmnd_timer;
    void (*done_funct)(struct scsi_cmnd*);
    struct scsi_cmnd * a_cmnd;
    int scsi_result;
};
static struct vt_queued_cmd queued_arr[VIR_TAPE_CANQUEUE];
static unsigned char spare_buff[SENSE_LEN];



LIST_HEAD(vt_host_list);
static const int check_condition_result =
        (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
static int scsi_debug_delay = DEF_DELAY;
//static int virt_tape_dsense = DEF_D_SENSE;
//static int vt_delay = DEF_DELAY;
static int vt_scsi_level = DEF_SCSI_LEVEL;


static void mk_sense_buffer(struct vt_dev_info * ,int ,int ,int );
static int vt_probe(struct device *dev);
static void __exit vir_exit(void);
static int __init vir_tape(void);
static void remove_driverfs_files();
static int vt_add_adapter();
static void remove_adapter();
static int register_the_host(struct device *dev);
ssize_t remove_host_store(struct device * dev,const char * buf, size_t count);
ssize_t add_target_store(struct device * dev, const char * buf, size_t count);
ssize_t add_target_show(struct device * dev, char * buf);
static void vt_release_adapter(struct device *dev);
static void remove_host(struct vt_host_info * vthost);
int vir_tape_device_reset(struct scsi_cmnd * scp);
int vir_tape_host_reset(struct scsi_cmnd * scp);
int vir_tape_bus_reset(struct scsi_cmnd * scp);
int vir_tape_abort(struct scsi_cmnd * scp);
int vir_tape_slave_destroy(struct scsi_device *sdp);
int vir_tape_slave_configure(struct scsi_device *sdp);
int vir_tape_slave_alloc(struct scsi_device *sdp);
int vir_tape_release(struct Scsi_Host * shp);
int vir_tape_queuecommand(struct scsi_cmnd * scp,void (*done)(struct scsi_cmnd *));
int resp_report_lun(struct scsi_cmnd * scp,struct vt_dev_info * devip);
int test_unit_ready (struct scsi_cmnd * scp,struct vt_dev_info * devip);
void mk_sense_buffer(struct vt_dev_info * devip,int key,int asc,int asq);
unsigned char * scatg2virt(const struct scatterlist * sclp);
int schedule_resp(struct scsi_cmnd * cmnd,struct vt_dev_info * devip,void (*done)(struct scsi_cmnd *), int scsi_result, int delta_jiff);
struct vt_dev_info * devinforeg(struct scsi_device * sdev);
 int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
                int bufflen, struct vt_dev_info * devip);
int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
               const char * dev_id_str, int dev_id_str_len);
void timer_intr_handler(unsigned long indx);
int fill_from_device_buff(struct scsi_cmnd *scp, unsigned char *arr, int arr_len);
int vir_tape_ioctl(struct scsi_device *sdp, int cmd, void *arg);
const char * vir_tape_info(struct Scsi_Host * host);
void do_create_driverfs_files();
static void vt_bus_release( struct device *dev);
static int vt_bus_match(struct device *dev,struct device_driver *drv);
struct scsi_device *add_target(struct vt_host_info * vthost);

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux