⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sg.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    } 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 + -