📄 sg.c
字号:
} else { printk("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("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 < 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("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, NULL); sg_template.nr_dev++; sg_dev_arr[k] = sdp; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 0;}/* Called at 'finish' of init process, after all attaches */static void sg_finish(void){ SCSI_LOG_TIMEOUT(3, printk("sg_finish: dma_free_sectors=%u\n", scsi_dma_free_sectors));}static void sg_detach(Scsi_Device * scsidp){ Sg_device * sdp; unsigned long iflags; Sg_fd * sfp; Sg_request * srp; int k; if (NULL == sg_dev_arr) return; 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) { for (sfp = sdp->headfp; sfp; sfp = sfp->nextfp) { /* no lock on request list here */ for (srp = sfp->headrp; srp; srp = srp->nextrp) { if (! srp->done) { write_unlock_irqrestore(&sg_dev_arr_lock, iflags); sg_shorten_timeout(srp->my_cmdp); write_lock_irqsave(&sg_dev_arr_lock, iflags); } } } write_unlock_irqrestore(&sg_dev_arr_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k)); scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */ devfs_unregister (sdp->de); sdp->de = NULL; sdp->detached = 1; write_lock_irqsave(&sg_dev_arr_lock, iflags); } else { 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--;/* avoid associated device /dev/sg? being incremented * each time module is inserted/removed , <dan@lectra.fr> */ sg_template.dev_noticed--; break; } write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return;}MODULE_AUTHOR("Douglas Gilbert");MODULE_DESCRIPTION("SCSI generic (sg) driver");MODULE_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) {/* Really worrying situation of writes still pending and get here *//* Strategy: shorten timeout on release + wait on detach ... */ kfree((char *)sg_dev_arr); sg_dev_arr = NULL; } sg_template.dev_max = 0;}#if 0extern void scsi_times_out (Scsi_Cmnd * SCpnt);extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);#endif/* Can't see clean way to abort a command so shorten timeout to 1 jiffy */static void sg_shorten_timeout(Scsi_Request * srpnt){#if 0 /* scsi_syms.c is very miserly about exported functions */ scsi_delete_timer(scpnt); if (! scpnt) return; scpnt->timeout_per_command = 1; /* try 1 jiffy (perhaps 0 jiffies) */ if (scpnt->host->hostt->use_new_eh_code) scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_times_out); else scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_old_times_out);#else scsi_sleep(HZ); /* just sleep 1 second and hope ... */#endif}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 ((hp->flags & SG_FLAG_DIRECT_IO) && (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) && (! sfp->parentdp->device->host->unchecked_isa_dma)) { res = sg_build_dir(srp, sfp, dxfer_len); if (res <= 0) /* -ve -> error, 0 -> done, 1 -> try indirect */ return res; } if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) { sg_link_reserve(sfp, srp, dxfer_len); } else { res = sg_build_indi(req_schp, sfp, dxfer_len); if (res) { sg_remove_scat(req_schp); return res; } } return 0;}static void sg_finish_rem_req(Sg_request * srp){ Sg_fd * sfp = srp->parentfp; Sg_scatter_hold * req_schp = &srp->data; SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", (int)srp->res_used)); sg_unmap_and(&srp->data, 1); if (srp->res_used) sg_unlink_reserve(sfp, srp); else sg_remove_scat(req_schp); sg_remove_request(sfp, srp);}static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp){ int mem_src, ret_sz; int sg_bufflen = PAGE_SIZE; int elem_sz = sizeof(struct scatterlist) + sizeof(char); int mx_sc_elems = (sg_bufflen / elem_sz) - 1; mem_src = SG_HEAP_KMAL; schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src); schp->buffer_mem_src = (char)mem_src; if (! schp->buffer) return -ENOMEM; else if (ret_sz != sg_bufflen) { sg_bufflen = ret_sz; mx_sc_elems = (sg_bufflen / elem_sz) - 1; } schp->sglist_len = sg_bufflen; memset(schp->buffer, 0, sg_bufflen); return mx_sc_elems; /* number of scat_gath elements allocated */}static void sg_unmap_and(Sg_scatter_hold * schp, int free_also){#ifdef SG_ALLOW_DIO if (schp && schp->kiobp) { if (schp->mapped) { unmap_kiobuf(schp->kiobp); schp->mapped = 0; } if (free_also) { free_kiovec(1, &schp->kiobp); schp->kiobp = NULL; } }#endif}static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len){#ifdef SG_ALLOW_DIO int res, k, split, offset, num, mx_sc_elems, rem_sz; struct kiobuf * kp; char * mem_src_arr; struct scatterlist * sclp; unsigned long addr, prev_addr; sg_io_hdr_t * hp = &srp->header; Sg_scatter_hold * schp = &srp->data; int sg_tablesize = sfp->parentdp->sg_tablesize; res = alloc_kiovec(1, &schp->kiobp); if (0 != res) { SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res)); return 1; } res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0, schp->kiobp, (unsigned long)hp->dxferp, dxfer_len); if (0 != res) { SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: map_user_kiobuf res=%d\n", res)); sg_unmap_and(schp, 1); return 1; } schp->mapped = 1; kp = schp->kiobp; prev_addr = (unsigned long) page_address(kp->maplist[0]); for (k = 1, split = 0; k < kp->nr_pages; ++k, prev_addr = addr) { addr = (unsigned long) page_address(kp->maplist[k]); if ((prev_addr + PAGE_SIZE) != addr) { split = k; break; } } if (! split) { schp->k_use_sg = 0; schp->buffer = page_address(kp->maplist[0]) + kp->offset; schp->bufflen = dxfer_len; schp->buffer_mem_src = SG_USER_MEM; schp->b_malloc_len = dxfer_len; hp->info |= SG_INFO_DIRECT_IO; return 0; } mx_sc_elems = sg_build_sgat(schp, sfp); if (mx_sc_elems <= 1) { sg_unmap_and(schp, 1); sg_remove_scat(schp); return 1; } mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist)); for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len; (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems); ++k, ++sclp) { offset = (0 == k) ? kp->offset : 0; num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) : rem_sz; sclp->address = page_address(kp->maplist[k]) + offset; sclp->length = num; mem_src_arr[k] = SG_USER_MEM; rem_sz -= num; SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n", k, sclp->address, num, mem_src_arr[k])); } schp->k_use_sg = k; SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: k_use_sg=%d, rem_sz=%d\n", k, rem_sz)); schp->bufflen = dxfer_len; if (rem_sz > 0) { /* must have failed */ sg_unmap_and(schp, 1); sg_remove_scat(schp); return 1; /* out of scatter gather elements, try indirect */ } hp->info |= SG_INFO_DIRECT_IO; return 0;#else return 1;#endif /* SG_ALLOW_DIO */}static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size){ int ret_sz, mem_src; int blk_size = buff_size; char * p = NULL; if ((blk_size < 0) || (! sfp)) return -EFAULT; if (0 == blk_size) ++blk_size; /* don't know why *//* round request up to next highest SG_SECTOR_SZ byte boundary */ blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK); SCSI_LOG_TIMEOUT(4, printk("sg_build_indi: buff_size=%d, blk_size=%d\n", buff_size, blk_size)); if (blk_size <= SG_SCATTER_SZ) { mem_src = SG_HEAP_PAGE; p = sg_malloc(sfp, blk_size, &ret_sz, &mem_src); if (! p) return -ENOMEM; if (blk_size == ret_sz) { /* got it on the first attempt */ schp->k_use_sg = 0; schp->buffer = p; schp->bufflen = blk_size; schp->buffer_mem_src = (char)mem_src; schp->b_malloc_len = blk_size; return 0; } } else { mem_src = SG_HEAP_PAGE; p = sg_malloc(sfp, SG_SCATTER_SZ, &ret_sz, &mem_src); if (! p) return -ENOMEM; }/* Want some local declarations, so start new block ... */ { /* lets try and build a scatter gather list */ struct scatterlist * sclp; int k, rem_sz, num; int mx_sc_elems; int sg_tablesize = sfp->parentdp->sg_tablesize; int first = 1; char * mem_src_arr; /* N.B. ret_sz and mem_src carried into this block ... */ mx_sc_elems = sg_build_sgat(schp, sfp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -