File:  [Early Linux] / linux / kernel / blk_drv / scsi / sd.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:15:31 2018 UTC (8 years, 2 months ago) by root
Branches: linus, MAIN
CVS tags: linux098, HEAD
linux 0.98

/*
 *	sd.c Copyright (C) 1992 Drew Eckhardt 
 *	Linux scsi disk driver by
 *		Drew Eckhardt 
 *
 *	<[email protected]>
 */

#include <linux/config.h>

#ifdef CONFIG_BLK_DEV_SD
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>

#include "scsi.h"
#include "sd.h"

#define MAJOR_NR 8

#include "../blk.h"
#include <linux/genhd.h>

/*
static const char RCSid[] = "$Header:";
*/

#define MAX_RETRIES 5

/*
 *	Time out in seconds
 */

#define SD_TIMEOUT 200

struct hd_struct sd[MAX_SD << 4];
				
int NR_SD=0;
Scsi_Disk rscsi_disks[MAX_SD];
static int sd_sizes[MAX_SD << 4] = {0, };
static int this_count, total_count = 0;
static int the_result;

static char sense_buffer[255];

extern int sd_ioctl(struct inode *, struct file *, unsigned long, unsigned long);

static void sd_release(struct inode * inode, struct file * file)
{
	sync_dev(inode->i_rdev);
}

static struct gendisk sd_gendisk;

static void sd_geninit (void) {
	int i;
	for (i = 0; i < NR_SD; ++i)
	  sd[i << 4].nr_sects = rscsi_disks[i].capacity;
	sd_gendisk.nr_real = NR_SD;
}

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,			/* no special open code */
	sd_release		/* release */
};

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 */
	MAX_SD,		/* maximum number of real */
	sd_geninit,	/* init function */
	sd,		/* hd struct */
	sd_sizes,	/* block sizes */
	0,		/* number */
	(void *) rscsi_disks,	/* internal */
	NULL		/* next */
};

/*
	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 on of several actions based on success or failure.
*/

static void rw_intr (int host, int result)
{
	if (HOST != host)
		panic ("sd.o : rw_intr() recieving interrupt for different host.");

#ifdef DEBUG
	printk("sd%d : rw_intr(%d, %x)\n", MINOR(CURRENT->dev), host, result);
#endif

/*
	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 (!result) {
		CURRENT->nr_sectors -= this_count;
		total_count -= this_count;
		if(total_count){
		  CURRENT->sector += this_count;
		  CURRENT->buffer += (this_count << 9);
		  do_sd_request();
		  return;
		};

#ifdef DEBUG
		printk("sd%d : %d sectors remain.\n", MINOR(CURRENT->dev), CURRENT->nr_sectors);
#endif

/*
 * 	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 (CURRENT->nr_sectors)
			{
			CURRENT->sector += this_count;
			CURRENT->errors = 0;

			if (!CURRENT->bh)
				{
#ifdef DEBUG
				printk("sd%d : handling page request, no buffer\n", 
					MINOR(CURRENT->dev));
#endif

/*
	The CURRENT->nr_sectors field is always done in 512 byte sectors,
	even if this really isn't the case.
*/
				(char *) CURRENT->buffer += this_count << 9;
				}
			else
				{
#ifdef DEBUG
				printk("sd%d :  handling linked buffer request\n", MINOR(CURRENT->dev));
#endif
				end_request(1);
				}
			}
		else
			end_request(1);
		do_sd_request();			 
		}

/*
 *	Of course, the error handling code is a little Fubar down in scsi.c.  
 *	Version 2 of the drivers will fix that, and we will *really* recover 
 *	from errors.
 */

/*
	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.
*/

	else if (driver_byte(result) & DRIVER_SENSE) {
		if (sugestion(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(CURRENT->dev)].remap
				{
				result = 0;
				}
			else
			
#endif
		}
/*
	If we had an ILLEGAL REQUEST returned, then we may have performed
	an unsupported command.  The only thing this should be would be a  ten
	byte read where only a six byte read was supportted.  Also, on a 
	system where READ CAPACITY failed, we mave have read past the end of the
	disk.
*/
	
		else if (sense_buffer[7] == ILLEGAL_REQUEST) {
			if (rscsi_disks[DEVICE_NR(CURRENT->dev)].ten) {
				rscsi_disks[DEVICE_NR(CURRENT->dev)].ten = 0;
				do_sd_request();
				result = 0;
			} else {
			}
		}
	}
	if (result) {
		printk("SCSI disk error : host %d id %d lun %d return code = %03x\n", 
		       rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no, 
		       rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id,
		       rscsi_disks[DEVICE_NR(CURRENT->dev)].device->lun);

		if (driver_byte(result) & DRIVER_SENSE) 
			printk("\tSense class %x, sense error %x, extended sense %x\n",
				sense_class(sense_buffer[0]), 
				sense_error(sense_buffer[0]),
				sense_buffer[2] & 0xf);

		end_request(0);
	}
}

/*
	do_sd_request() is the request handler function for the sd driver.  
	Its function in life is to take block device requests, and translate 
	them to SCSI commands.
*/
	
static void do_sd_request (void)
{
	int dev, block;
	unsigned char cmd[10];

repeat:
	INIT_REQUEST;
	dev =  MINOR(CURRENT->dev);
	block = CURRENT->sector;

#ifdef DEBUG
	printk("Doing sd request, dev = %d, block = %d\n", dev, block);
#endif

	if (dev >= (NR_SD << 4) || block + CURRENT->nr_sectors > sd[dev].nr_sects) 
		{
		end_request(0);	
		goto repeat;
		}
	
	block += sd[dev].start_sect;
	dev = DEVICE_NR(dev);

#ifdef DEBUG
	printk("sd%d : real dev = /dev/sd%d, block = %d\n", MINOR(CURRENT->dev), dev, block);
#endif


	if (!CURRENT->bh)  	
		this_count = CURRENT->nr_sectors;
	else
		this_count = (BLOCK_SIZE / 512);
/* This is a temporary hack for the AHA1742. */
	if(total_count == 0)
	  total_count = this_count;
	this_count = 1;  /* Take only 512 bytes at a time */

#ifdef DEBUG
	printk("sd%d : %s %d/%d 512 byte blocks.\n", MINOR(CURRENT->dev), 
		(CURRENT->cmd == WRITE) ? "writing" : "reading",
		this_count, CURRENT->nr_sectors);
#endif
	
	switch (CURRENT->cmd)
		{
		case WRITE : 
			if (!rscsi_disks[dev].device->writeable)
				{
				end_request(0);
				goto repeat;
				} 
			cmd[0] = WRITE_6;
			break;
		case READ : 
			cmd[0] = READ_6;
			break;
		default : 
			printk ("Unknown sd command %d\r\n", CURRENT->cmd);
			panic("");
		}

	cmd[1] = (LUN << 5) & 0xe0;

	if (((this_count > 0xff) ||  (block > 0x1fffff)) && rscsi_disks[dev].ten) 
		{
		if (this_count > 0xffff)
			this_count = 0xffff;

		cmd[0] += READ_10 - READ_6 ;
		cmd[2] = (unsigned char) (block >> 24) & 0xff;
		cmd[3] = (unsigned char) (block >> 16) & 0xff;
		cmd[4] = (unsigned char) (block >> 8) & 0xff;
		cmd[5] = (unsigned char) block & 0xff;
		cmd[6] = cmd[9] = 0;
		cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
		cmd[8] = (unsigned char) this_count & 0xff;
		}
	else
		{
		if (this_count > 0xff)
			this_count = 0xff;
	
		cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
		cmd[2] = (unsigned char) ((block >> 8) & 0xff);
		cmd[3] = (unsigned char) block & 0xff;
		cmd[4] = (unsigned char) this_count;
		cmd[5] = 0;
		}
			
	scsi_do_cmd (HOST, ID, (void *) cmd, CURRENT->buffer, this_count << 9, 
		     rw_intr, SD_TIMEOUT, sense_buffer, MAX_RETRIES);
}

static void sd_init_done (int host, int result)
{
	the_result = result;
}

/*
	The sd_init() function looks at all SCSI drives present, determines 
	their size, and reads partition	table entries for them.
*/

void sd_init(void)
{
	int i,j;
	unsigned char cmd[10];
	unsigned char buffer[513];
	int try_again;

	
	for (i = 0; i < NR_SD; ++i)
		{
		try_again=2;
		cmd[0] = READ_CAPACITY;
		cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
		memset ((void *) &cmd[2], 0, 8);	

/*
 *	Super Kludge - since the midlevel error handling code doesn't work
 *	Version 2 will - it's under development 8^) 
 * 
 *	We manually retry
 */
	

		do {
	 	the_result = -1;
#ifdef DEBUG
	printk("sd%d : READ CAPACITY\n ", i); 
#endif
		scsi_do_cmd (rscsi_disks[i].device->host_no , 
				rscsi_disks[i].device->id, 
				(void *) cmd, (void *) buffer,
				 512, sd_init_done,  SD_TIMEOUT, sense_buffer,
				 MAX_RETRIES);

		while(the_result < 0);
		} while (try_again  && the_result);
/*
 *	The SCSI standard says "READ CAPACITY is necessary for self confuring software"
 *	While not mandatory, support of READ CAPACITY is strongly encouraged.
 *	We used to die if we couldn't successfully do a READ CAPACITY.  
 *	But, now we go on about our way.  The side effects of this are
 *
 *	1.  We can't know block size with certainty.  I have said "512 bytes is it"
 *	   	as this is most common.
 *
 *	2.  Recovery from when some one attempts to read past the end of the raw device will
 *	    be slower.  
 */
	
		if (the_result)
			{
			printk ("sd%d : READ CAPACITY failed.\n" 
				"sd%d : status = %x, message = %02x, host = %02x, driver = %02x \n",
				i,i,
				rscsi_disks[i].device->host_no, rscsi_disks[i].device->id,
				rscsi_disks[i].device->lun,
			        status_byte(the_result),
			        msg_byte(the_result),
			        host_byte(the_result),
			        driver_byte(the_result)
			        );
			if (driver_byte(the_result)  & DRIVER_SENSE)  
				printk("sd%d : extended sense code = %1x \n", i, sense_buffer[2] & 0xf);
			else
				printk("sd%d : sense not available. \n", i);

			printk("sd%d : block size assumed to be 512 bytes, disk size 1GB.  \n", i);
			rscsi_disks[i].capacity = 0x1fffff;
			rscsi_disks[i].sector_size = 512;
			}
		else
			{
			rscsi_disks[i].capacity = (buffer[0] << 24) |	
						  (buffer[1] << 16) |
						  (buffer[2] << 8) |
						  buffer[3];

			if ((rscsi_disks[i].sector_size = (buffer[4] << 24) |
						     (buffer[5] << 16) |  
						     (buffer[6] << 8) | 
						     buffer[7]) != 512)
				{
				printk ("sd%d : unsupported sector size %d.\n", 
					i, rscsi_disks[i].sector_size);
				printk ("scsi : deleting disk entry.\n");
				for  (j=i;  j < NR_SD;)
					rscsi_disks[j] = rscsi_disks[++j];
				--i;
				continue;
				}
			}

		rscsi_disks[i].ten = 1;
		rscsi_disks[i].remap = 1;
		}

	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
	blkdev_fops[MAJOR_NR] = &sd_fops;
	sd_gendisk.next = gendisk_head;
	gendisk_head = &sd_gendisk;
}
#endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.