📄 sg.c
字号:
/* This function is a "bottom half" handler that is called by the * mid level when a command is completed (or has failed). */static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt){ Scsi_Request * SRpnt = SCpnt->sc_request; int dev = MINOR(SRpnt->sr_request.rq_dev); Sg_device * sdp = NULL; Sg_fd * sfp; Sg_request * srp = NULL; read_lock(&sg_dev_arr_lock); if (sg_dev_arr && (dev >= 0)) { if (dev < sg_template.dev_max) sdp = sg_dev_arr[dev]; } if ((NULL == sdp) || sdp->detached) { read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(1, printk("sg...bh: dev=%d gone\n", dev)); scsi_release_request(SRpnt); SRpnt = NULL; return; } sfp = sdp->headfp; while (sfp) { read_lock(&sfp->rq_list_lock); for (srp = sfp->headrp; srp; srp = srp->nextrp) { if (SRpnt == srp->my_cmdp) break; } read_unlock(&sfp->rq_list_lock); if (srp) break; sfp = sfp->nextfp; } if (! srp) { read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev)); scsi_release_request(SRpnt); SRpnt = NULL; return; } /* First transfer ownership of data buffers to sg_device object. */ srp->data.k_use_sg = SRpnt->sr_use_sg; srp->data.sglist_len = SRpnt->sr_sglist_len; srp->data.bufflen = SRpnt->sr_bufflen; srp->data.buffer = SRpnt->sr_buffer; /* now clear out request structure */ SRpnt->sr_use_sg = 0; SRpnt->sr_sglist_len = 0; SRpnt->sr_bufflen = 0; SRpnt->sr_buffer = NULL; SRpnt->sr_underflow = 0; SRpnt->sr_request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ request blk */ srp->my_cmdp = NULL; srp->done = 1; read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n", dev, srp->header.pack_id, (int)SRpnt->sr_result)); srp->header.resid = SCpnt->resid; /* sg_unmap_and(&srp->data, 0); */ /* unmap locked pages a.s.a.p. */ /* N.B. unit of duration changes here from jiffies to millisecs */ srp->header.duration = sg_jif_to_ms(jiffies - (int)srp->header.duration); if (0 != SRpnt->sr_result) { memcpy(srp->sense_b, SRpnt->sr_sense_buffer, sizeof(srp->sense_b)); srp->header.status = 0xff & SRpnt->sr_result; srp->header.masked_status = status_byte(SRpnt->sr_result); srp->header.msg_status = msg_byte(SRpnt->sr_result); srp->header.host_status = host_byte(SRpnt->sr_result); srp->header.driver_status = driver_byte(SRpnt->sr_result); if ((sdp->sgdebug > 0) && ((CHECK_CONDITION == srp->header.masked_status) || (COMMAND_TERMINATED == srp->header.masked_status))) print_req_sense("sg_cmd_done_bh", SRpnt); /* Following if statement is a patch supplied by Eric Youngdale */ if (driver_byte(SRpnt->sr_result) != 0 && (SRpnt->sr_sense_buffer[0] & 0x7f) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION && sdp->device->removable) { /* Detected disc change. Set the bit - this may be used if */ /* there are filesystems using this device. */ sdp->device->changed = 1; } } /* Rely on write phase to clean out srp status values, so no "else" */ scsi_release_request(SRpnt); SRpnt = NULL; if (sfp->closed) { /* whoops this fd already released, cleanup */ SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, freeing ...\n")); sg_finish_rem_req(srp); srp = NULL; if (NULL == sfp->headrp) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n")); if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */ sdp->device->access_count--; if (sdp->device->host->hostt->module) __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); } if (sg_template.module) __MOD_DEC_USE_COUNT(sg_template.module); sfp = NULL; } } else if (srp && srp->orphan) { if (sfp->keep_orphan) srp->sg_io_owned = 0; else { sg_finish_rem_req(srp); srp = NULL; } } if (sfp && srp) { /* Now wake up any sg_read() that is waiting for this packet. */ wake_up_interruptible(&sfp->read_wait); kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); }}static struct file_operations sg_fops = { owner: THIS_MODULE, read: sg_read, write: sg_write, poll: sg_poll, ioctl: sg_ioctl, open: sg_open, mmap: sg_mmap, release: sg_release, fasync: sg_fasync,};static int sg_detect(Scsi_Device * scsidp){ sg_template.dev_noticed++; return 1;}/* Driver initialization */static int sg_init(){ static int sg_registered = 0; unsigned long iflags; if ((sg_template.dev_noticed == 0) || sg_dev_arr) return 0; write_lock_irqsave(&sg_dev_arr_lock, iflags); if(!sg_registered) { if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) { printk(KERN_ERR "Unable to get major %d for generic SCSI device\n", SCSI_GENERIC_MAJOR); write_unlock_irqrestore(&sg_dev_arr_lock, iflags); sg_template.dev_noticed = 0; return 1; } sg_registered++; } SCSI_LOG_TIMEOUT(3, printk("sg_init\n")); sg_template.dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP; sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * sizeof(Sg_device *), GFP_ATOMIC); if (NULL == sg_dev_arr) { printk(KERN_ERR "sg_init: no space for sg_dev_arr\n"); write_unlock_irqrestore(&sg_dev_arr_lock, iflags); sg_template.dev_noticed = 0; return 1; } memset(sg_dev_arr, 0, sg_template.dev_max * sizeof(Sg_device *)); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);#ifdef CONFIG_PROC_FS sg_proc_init();#endif /* CONFIG_PROC_FS */ return 0;}#ifndef MODULEstatic int __init sg_def_reserved_size_setup(char *str){ int tmp; if (get_option(&str, &tmp) == 1) { def_reserved_size = tmp; if (tmp >= 0) sg_big_buff = tmp; return 1; } else { printk(KERN_WARNING "sg_def_reserved_size : usage " "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n"); return 0; }}__setup("sg_def_reserved_size=", sg_def_reserved_size_setup);#endifstatic int sg_attach(Scsi_Device * scsidp){ Sg_device * sdp; unsigned long iflags; int k; write_lock_irqsave(&sg_dev_arr_lock, iflags); if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */ Sg_device ** tmp_da; int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP; tmp_da = (Sg_device **)kmalloc(tmp_dev_max * sizeof(Sg_device *), GFP_ATOMIC); if (NULL == tmp_da) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); printk(KERN_ERR "sg_attach: device array cannot be resized\n"); return 1; } memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *)); memcpy(tmp_da, sg_dev_arr, sg_template.dev_max * sizeof(Sg_device *)); kfree((char *)sg_dev_arr); sg_dev_arr = tmp_da; sg_template.dev_max = tmp_dev_max; } for(k = 0; k < sg_template.dev_max; k++) if(! sg_dev_arr[k]) break; if (k > MINORMASK) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>" " type=%d, minor number exceed %d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->type, MINORMASK); return 1; } if(k < sg_template.dev_max) sdp = (Sg_device *)kmalloc(sizeof(Sg_device), GFP_ATOMIC); else sdp = NULL; if (NULL == sdp) { scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n"); return 1; } SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); sdp->device = scsidp; init_waitqueue_head(&sdp->o_excl_wait); sdp->headfp= NULL; sdp->exclude = 0; sdp->sgdebug = 0; sdp->detached = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k); sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT, SCSI_GENERIC_MAJOR, k, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &sg_fops, sdp); sg_template.nr_dev++; sg_dev_arr[k] = sdp; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); switch (scsidp->type) { case TYPE_DISK: case TYPE_MOD: case TYPE_ROM: case TYPE_WORM: case TYPE_TAPE: break; default: printk(KERN_NOTICE "Attached scsi generic sg%d at scsi%d, channel" " %d, id %d, lun %d, type %d\n", k, scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->type); } return 0;}/* Called at 'finish' of init process, after all attaches */static void sg_finish(void){ }static void sg_detach(Scsi_Device * scsidp){ Sg_device * sdp; unsigned long iflags; Sg_fd * sfp; Sg_fd * tsfp; Sg_request * srp; Sg_request * tsrp; int k, delay; if (NULL == sg_dev_arr) return; delay = 0; write_lock_irqsave(&sg_dev_arr_lock, iflags); for (k = 0; k < sg_template.dev_max; k++) { sdp = sg_dev_arr[k]; if ((NULL == sdp) || (sdp->device != scsidp)) continue; /* dirty but lowers nesting */ if (sdp->headfp) { sdp->detached = 1; for (sfp = sdp->headfp; sfp; sfp = tsfp) { tsfp = sfp->nextfp; for (srp = sfp->headrp; srp; srp = tsrp) { tsrp = srp->nextrp; if (sfp->closed || (0 == srp->done)) sg_finish_rem_req(srp); } if (sfp->closed) { sdp->device->access_count--; if (sg_template.module) __MOD_DEC_USE_COUNT(sg_template.module); if (sdp->device->host->hostt->module) __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); __sg_remove_sfp(sdp, sfp); } else { delay = 1; wake_up_interruptible(&sfp->read_wait); kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); } } SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k)); devfs_unregister (sdp->de); sdp->de = NULL; if (NULL == sdp->headfp) { kfree((char *)sdp); sg_dev_arr[k] = NULL; } } else { /* nothing active, simple case */ SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); devfs_unregister (sdp->de); kfree((char *)sdp); sg_dev_arr[k] = NULL; } scsidp->attached--; sg_template.nr_dev--; sg_template.dev_noticed--; /* from <dan@lectra.fr> */ break; } write_unlock_irqrestore(&sg_dev_arr_lock, iflags); if (delay) scsi_sleep(2); /* dirty detach so delay device destruction */}MODULE_AUTHOR("Douglas Gilbert");MODULE_DESCRIPTION("SCSI generic (sg) driver");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifMODULE_PARM(def_reserved_size, "i");MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");static int __init init_sg(void) { if (def_reserved_size >= 0) sg_big_buff = def_reserved_size; sg_template.module = THIS_MODULE; return scsi_register_module(MODULE_SCSI_DEV, &sg_template);}static void __exit exit_sg( void){#ifdef CONFIG_PROC_FS sg_proc_cleanup();#endif /* CONFIG_PROC_FS */ scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); if(sg_dev_arr != NULL) { kfree((char *)sg_dev_arr); sg_dev_arr = NULL; } sg_template.dev_max = 0;}static int sg_start_req(Sg_request * srp){ int res; Sg_fd * sfp = srp->parentfp; sg_io_hdr_t * hp = &srp->header; int dxfer_len = (int)hp->dxfer_len; int dxfer_dir = hp->dxfer_direction; Sg_scatter_hold * req_schp = &srp->data; Sg_scatter_hold * rsv_schp = &sfp->reserve; SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len)); if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE)) return 0; if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -