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);