📄 sd.c
字号:
/* * 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. * * Modified by Jirka Hanika geo@ff.cuni.cz to support more * scsi disks using eight major numbers. */ #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 <linux/smp.h>#include <asm/system.h>#include <asm/io.h>#define MAJOR_NR SCSI_DISK0_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 SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) #define SCSI_DISKS_PER_MAJOR 16#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8)#define SD_MINOR_NUMBER(i) ((i) & 255)#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), (i) & 255)#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4)#define N_USED_SCSI_DISKS (sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1)#define N_USED_SD_MAJORS (N_USED_SCSI_DISKS / SCSI_DISKS_PER_MAJOR)#define MAX_RETRIES 5/* * Time out in seconds for disks and Magneto-opticals (which are slower). */#define SD_TIMEOUT (30 * HZ)#define SD_MOD_TIMEOUT (75 * 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 *);static void sd_devname(unsigned int disknum, char * buffer){ if( disknum < 26 ) sprintf(buffer, "sd%c", 'a' + disknum); else { unsigned int min1; unsigned int min2; /* * For larger numbers of disks, we need to go to a new * naming scheme. */ min1 = disknum / 26; min2 = disknum % 26; sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); }}struct Scsi_Device_Template sd_template ={ NULL, "disk", "sd", NULL, TYPE_DISK, SCSI_DISK0_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); SCSI_LOG_HLQUEUE(1,printk("target=%d, max=%d\n", target, sd_template.dev_max)); if(target >= sd_template.dev_max || !rscsi_disks[target].device) return -ENXIO; /* No such device */ /* * If the device is in error recovery, wait until it is done. * If the device is offline, then disallow any access to it. */ if( !scsi_block_when_processing_errors(rscsi_disks[target].device) ) { return -ENXIO; } /* * 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; } /* * It is possible that the disk changing stuff resulted in the device being taken * offline. If this is the case, report this to the user, and don't pretend that * the open actually succeeded. */ if( !rscsi_disks[target].device->online ) { return -ENXIO; } /* * See if we are requesting a non-existent partition. Do this * after checking for disk change. */ if(sd_sizes[SD_PARTITION(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->module) __MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); if(sd_template.module) __MOD_INC_USE_COUNT(sd_template.module); return 0;}static int 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->removable) { if(!rscsi_disks[target].device->access_count) sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); } if(rscsi_disks[target].device->host->hostt->module) __MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module); if(sd_template.module) __MOD_DEC_USE_COUNT(sd_template.module); return 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 */ NULL, /* flush */ sd_release, /* release */ block_fsync, /* fsync */ NULL, /* fasync */ check_scsidisk_media_change, /* Disk change */ fop_revalidate_scsidisk /* revalidate */};/* * If we need more than one SCSI disk major (i.e. more than * 16 SCSI disks), we'll have to kmalloc() more gendisks later. */static struct gendisk sd_gendisk = { SCSI_DISK0_MAJOR, /* 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 struct gendisk *sd_gendisks = &sd_gendisk;#define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]#define LAST_SD_GENDISK sd_gendisks[N_USED_SD_MAJORS - 1]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;}/* * 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; char nbuff[6]; int this_count = SCpnt->bufflen >> 9; int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 1; sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff); SCSI_LOG_HLCOMPLETE(1,printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff, SCpnt->host->host_no, result, SCpnt->sense_buffer[0], SCpnt->sense_buffer[2])); /* 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 == 2048) { error_sector <<= 2; if (block_sectors < 4) block_sectors = 4; } else if (sector_size == 256) error_sector >>= 1; error_sector -= sd[SD_PARTITION(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; } /* * 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) { SCSI_LOG_HLCOMPLETE(1,printk("%s : %ld sectors remain.\n", nbuff, SCpnt->request.nr_sectors)); SCSI_LOG_HLCOMPLETE(1,printk("use_sg is %d\n ",SCpnt->use_sg)); if (SCpnt->use_sg) { struct scatterlist * sgpnt; int i; sgpnt = (struct scatterlist *) SCpnt->buffer; for(i=0; i<SCpnt->use_sg; i++) {#if 0 SCSI_LOG_HLCOMPLETE(3,printk(":%p %p %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) { SCSI_LOG_HLCOMPLETE(3,printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, SCpnt->bufflen)); 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) { SCSI_LOG_HLCOMPLETE(2,printk("%s : handling page request, no buffer\n", nbuff)); /* * 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++) { SCSI_LOG_HLCOMPLETE(3,printk("err: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, SCpnt->bufflen)); 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 { SCSI_LOG_HLCOMPLETE(2,printk("nosgerr: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer, SCpnt->bufflen)); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -