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

📄 sd.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *      sd.c Copyright (C) 1992 Drew Eckhardt  *           Copyright (C) 1993, 1994, 1995 Eric Youngdale * *      Linux scsi disk driver *              Initial versions: Drew Eckhardt  *              Subsequent revisions: Eric Youngdale * *      <drew@colorado.edu> * *       Modified by Eric Youngdale ericy@cais.com to *       add scatter-gather, multiple outstanding request, and other *       enhancements. * *       Modified by Eric Youngdale eric@aib.com to support loadable *       low-level scsi drivers. */#include <linux/module.h>#ifdef MODULE/* * This is a variable in scsi.c that is set when we are processing something * after boot time.  By definition, this is true when we are a loadable module * ourselves. */#define MODULE_FLAG 1#else#define MODULE_FLAG scsi_loadable_module_flag#endif /* MODULE */#include <linux/fs.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <asm/system.h>#define MAJOR_NR SCSI_DISK_MAJOR#include <linux/blk.h>#include "scsi.h"#include "hosts.h"#include "sd.h"#include <scsi/scsi_ioctl.h>#include "constants.h"#include <linux/genhd.h>/* *  static const char RCSid[] = "$Header:"; */#define MAX_RETRIES 5/* *  Time out in seconds for disks and Magneto-opticals (which are slower). */#define SD_TIMEOUT (20 * HZ)#define SD_MOD_TIMEOUT (25 * HZ)#define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \				SC->device->type != TYPE_MOD)struct hd_struct * sd;Scsi_Disk * rscsi_disks = NULL;static int * sd_sizes;static int * sd_blocksizes;static int * sd_hardsizes;              /* Hardware sector size */extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);static int check_scsidisk_media_change(kdev_t);static int fop_revalidate_scsidisk(kdev_t);static int sd_init_onedisk(int);static void requeue_sd_request (Scsi_Cmnd * SCpnt);static int sd_init(void);static void sd_finish(void);static int sd_attach(Scsi_Device *);static int sd_detect(Scsi_Device *);static void sd_detach(Scsi_Device *);struct Scsi_Device_Template sd_template = { NULL, "disk", "sd", NULL, TYPE_DISK,       SCSI_DISK_MAJOR, 0, 0, 0, 1,      sd_detect, sd_init,      sd_finish, sd_attach, sd_detach};static int sd_open(struct inode * inode, struct file * filp){    int target;    target =  DEVICE_NR(inode->i_rdev);        if(target >= sd_template.dev_max || !rscsi_disks[target].device)	return -ENXIO;   /* No such device */        /*      * Make sure that only one process can do a check_change_disk at one time.     * This is also used to lock out further access when the partition table      * is being re-read.      */        while (rscsi_disks[target].device->busy)        barrier();       if(rscsi_disks[target].device->removable) {	check_disk_change(inode->i_rdev);		/*	 * If the drive is empty, just let the open fail.	 */	if ( !rscsi_disks[target].ready )	    return -ENXIO;	/*	 * Similarly, if the device has the write protect tab set,	 * have the open fail if the user expects to be able to write	 * to the thing.	 */	if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) )	    return -EROFS;    }    /*     * See if we are requesting a non-existent partition.  Do this     * after checking for disk change.     */    if(sd_sizes[MINOR(inode->i_rdev)] == 0)	return -ENXIO;        if(rscsi_disks[target].device->removable)	if(!rscsi_disks[target].device->access_count)	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);    rscsi_disks[target].device->access_count++;    if (rscsi_disks[target].device->host->hostt->usage_count)	(*rscsi_disks[target].device->host->hostt->usage_count)++;    if(sd_template.usage_count) (*sd_template.usage_count)++;    return 0;}static void sd_release(struct inode * inode, struct file * file){    int target;    fsync_dev(inode->i_rdev);        target =  DEVICE_NR(inode->i_rdev);        rscsi_disks[target].device->access_count--;    if (rscsi_disks[target].device->host->hostt->usage_count)	(*rscsi_disks[target].device->host->hostt->usage_count)--;    if(sd_template.usage_count) (*sd_template.usage_count)--;        if(rscsi_disks[target].device->removable) {	if(!rscsi_disks[target].device->access_count)	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);    }}static void sd_geninit(struct gendisk *);static struct file_operations sd_fops = {    NULL,                        /* lseek - default */    block_read,                  /* read - general block-dev read */    block_write,                 /* write - general block-dev write */    NULL,                        /* readdir - bad */    NULL,                        /* select */    sd_ioctl,                    /* ioctl */    NULL,                        /* mmap */    sd_open,                     /* open code */    sd_release,                  /* release */    block_fsync,                 /* fsync */    NULL,                        /* fasync */    check_scsidisk_media_change, /* Disk change */    fop_revalidate_scsidisk      /* revalidate */};static struct gendisk sd_gendisk = {    MAJOR_NR,                    /* Major number */    "sd",                        /* Major name */    4,                           /* Bits to shift to get real from partition */    1 << 4,                      /* Number of partitions per real */    0,                           /* maximum number of real */    sd_geninit,                  /* init function */    NULL,                        /* hd struct */    NULL,                        /* block sizes */    0,                           /* number */    NULL,                        /* internal */    NULL                         /* next */};static void sd_geninit (struct gendisk *ignored){    int i;        for (i = 0; i < sd_template.dev_max; ++i)	if(rscsi_disks[i].device) 	    sd[i << 4].nr_sects = rscsi_disks[i].capacity;#if 0    /* No longer needed - we keep track of this as we attach/detach */    sd_gendisk.nr_real = sd_template.dev_max;#endif}/* * rw_intr is the interrupt routine for the device driver. * It will be notified on the end of a SCSI read / write, and * will take one of several actions based on success or failure. */static void rw_intr (Scsi_Cmnd *SCpnt){    int result = SCpnt->result;    int this_count = SCpnt->bufflen >> 9;    int good_sectors = (result == 0 ? this_count : 0);    int block_sectors = 1;    #ifdef DEBUG    printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev), 	   SCpnt->host->host_no, result);#endif    /*      Handle MEDIUM ERRORs that indicate partial success.  Since this is a      relatively rare error condition, no care is taken to avoid unnecessary      additional work such as memcpy's that could be avoided.    */    if (driver_byte(result) != 0 &&		    /* An error occurred */	SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */	SCpnt->sense_buffer[2] == MEDIUM_ERROR)      {	long error_sector = (SCpnt->sense_buffer[3] << 24) |			    (SCpnt->sense_buffer[4] << 16) |			    (SCpnt->sense_buffer[5] << 8) |			    SCpnt->sense_buffer[6];	int sector_size =	  rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].sector_size;	if (SCpnt->request.bh != NULL)	  block_sectors = SCpnt->request.bh->b_size >> 9;	if (sector_size == 1024)	  {	    error_sector <<= 1;	    if (block_sectors < 2) block_sectors = 2;	  }	else if (sector_size == 256)	  error_sector >>= 1;	error_sector -= sd[MINOR(SCpnt->request.rq_dev)].start_sect;	error_sector &= ~ (block_sectors - 1);	good_sectors = error_sector - SCpnt->request.sector;	if (good_sectors < 0 || good_sectors >= this_count)	  good_sectors = 0;      }        /*     * Handle RECOVERED ERRORs that indicate success after recovery action     * by the target device.     */    if (SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */	SCpnt->sense_buffer[2] == RECOVERED_ERROR)      {	printk("scsidisk recovered I/O error: dev %s, sector %lu, absolute sector %lu\n",	       kdevname(SCpnt->request.rq_dev), SCpnt->request.sector, 	       SCpnt->request.sector + sd[MINOR(SCpnt->request.rq_dev)].start_sect);	good_sectors = this_count;	result = 0;      }    /*     * First case : we assume that the command succeeded.  One of two things      * will happen here.  Either we will be finished, or there will be more     * sectors that we were unable to read last time.     */    if (good_sectors > 0) {	#ifdef DEBUG	printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.rq_dev),	       SCpnt->request.nr_sectors);	printk("use_sg is %d\n ",SCpnt->use_sg);#endif	if (SCpnt->use_sg) {	    struct scatterlist * sgpnt;	    int i;	    sgpnt = (struct scatterlist *) SCpnt->buffer;	    for(i=0; i<SCpnt->use_sg; i++) {#ifdef DEBUG		printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, 		       sgpnt[i].length);#endif		if (sgpnt[i].alt_address) {		    if (SCpnt->request.cmd == READ)			memcpy(sgpnt[i].alt_address, sgpnt[i].address, 			       sgpnt[i].length);		    scsi_free(sgpnt[i].address, sgpnt[i].length);		}	    }	    /* Free list of scatter-gather pointers */	    scsi_free(SCpnt->buffer, SCpnt->sglist_len);  	} else {	    if (SCpnt->buffer != SCpnt->request.buffer) {#ifdef DEBUG		printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,		       SCpnt->bufflen);#endif  		if (SCpnt->request.cmd == READ)		    memcpy(SCpnt->request.buffer, SCpnt->buffer,			   SCpnt->bufflen);		scsi_free(SCpnt->buffer, SCpnt->bufflen);	    }	}	/*	 * If multiple sectors are requested in one buffer, then	 * they will have been finished off by the first command.	 * If not, then we have a multi-buffer command.	 */	if (SCpnt->request.nr_sectors > this_count)	{	    SCpnt->request.errors = 0;	    	    if (!SCpnt->request.bh)	    {#ifdef DEBUG		printk("sd%c : handling page request, no buffer\n",		       'a' + MINOR(SCpnt->request.rq_dev));#endif		/*		 * The SCpnt->request.nr_sectors field is always done in 		 * 512 byte sectors, even if this really isn't the case.		 */		panic("sd.c: linked page request (%lx %x)",		      SCpnt->request.sector, this_count);	    }	}	SCpnt = end_scsi_request(SCpnt, 1, good_sectors);	if (result == 0)	  {	    requeue_sd_request(SCpnt);	    return;	  }    }        if (good_sectors == 0) {    /* Free up any indirection buffers we allocated for DMA purposes. */    if (SCpnt->use_sg) {	struct scatterlist * sgpnt;	int i;	sgpnt = (struct scatterlist *) SCpnt->buffer;	for(i=0; i<SCpnt->use_sg; i++) {#ifdef DEBUG	    printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,		   SCpnt->bufflen);#endif	    if (sgpnt[i].alt_address) {		scsi_free(sgpnt[i].address, sgpnt[i].length);	    }	}	scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */    } else {#ifdef DEBUG	printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,	       SCpnt->bufflen);#endif	if (SCpnt->buffer != SCpnt->request.buffer)	    scsi_free(SCpnt->buffer, SCpnt->bufflen);    }    }    /*     * Now, if we were good little boys and girls, Santa left us a request     * sense buffer.  We can extract information from this, so we     * can choose a block to remap, etc.     */    if (driver_byte(result) != 0) {	if (suggestion(result) == SUGGEST_REMAP) {#ifdef REMAP	    /*	     * Not yet implemented.  A read will fail after being remapped,	     * a write will call the strategy routine again.	     */	    if rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].remap	    {		result = 0;	    }	    else#endif	}		if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {	    if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {		if(rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->removable) {		    /* detected disc change.  set a bit and quietly refuse		     * further access.		     */  		    rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1;		    SCpnt = end_scsi_request(SCpnt, 0, this_count);		    requeue_sd_request(SCpnt);		    return;		}                else                {                    /*                     * Must have been a power glitch, or a bus reset.                     * Could not have been a media change, so we just retry                     * the request and see what happens.                     */                    requeue_sd_request(SCpnt);                    return;                }	    }	}		

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -