/*
 *      sd.c Copyright (C) 1992 Drew Eckhardt
 *           Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
 *
 *      Linux scsi disk driver
 *              Initial versions: Drew Eckhardt
 *              Subsequent revisions: Eric Youngdale
 *
 *      <drew@colorado.edu>
 *
 *       Modified by Eric Youngdale ericy@andante.org to
 *       add scatter-gather, multiple outstanding request, and other
 *       enhancements.
 *
 *       Modified by Eric Youngdale eric@andante.org to support loadable
 *       low-level scsi drivers.
 *
 *       Modified by Jirka Hanika geo@ff.cuni.cz to support more
 *       scsi disks using eight major numbers.
 *
 *       Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs.
 *	
 *	 Modified by Torben Mathiasen tmm@image.dk
 *       Resource allocation fixes in sd_init and cleanups.
 *	
 *	 Modified by Alex Davis <letmein@erols.com>
 *       Fix problem where partition info not being read in sd_open.
 *	
 *	 Modified by Alex Davis <letmein@erols.com>
 *       Fix problem where removable media could be ejected after sd_open.
 *
 *	 Modified by Kurt Garloff <garloff@suse.de>
 *	 Dynamically allocate majors and support > 128 disks.
 */

#include <linux/config.h>
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/hdreg.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/init.h>

#include <linux/smp.h>

#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>

#include <linux/blk.h>
#include <linux/blkpg.h>
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
#include "sd_dynalloc.h"
#include <scsi/scsi_ioctl.h>
#include "constants.h"
#include <scsi/scsicam.h>	/* must follow "hosts.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 (60 * HZ)
#define SD_MOD_TIMEOUT (75 * HZ)

static int check_scsidisk_media_change(kdev_t);
static int fop_revalidate_scsidisk(kdev_t);

static int sd_init_onedisk(int, int);

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 int sd_init_command(Scsi_Cmnd *);
static int sd_find_kdev(Scsi_Device*, char*, kdev_t*);
static int sd_drives_dev(kdev_t);

static struct Scsi_Device_Template sd_template = {
	name:"disk",
	tag:"sd",
	scsi_type:TYPE_DISK,
	major:SCSI_DISK0_MAJOR,
	blk:1,
	detect:sd_detect,
	init:sd_init,
	finish:sd_finish,
	attach:sd_attach,
	detach:sd_detach,
	init_command:sd_init_command,
	find_kdev:sd_find_kdev,
	drives_dev:sd_drives_dev,
};


static void rw_intr(Scsi_Cmnd * SCpnt);

#if defined(CONFIG_PPC)
/*
 * Moved from arch/ppc/pmac_setup.c.  This is where it really belongs.
 */
kdev_t __init
sd_find_target(void *host, int tgt)
{
    	SD_Major  *sd_major;
	Scsi_Device *SDev;
	int midx, didx;
	for (midx = 0; midx < sd_majors; ++midx) {
		sd_major = SD_MAJOR_PTR(midx);
		for (didx = 0; didx < SCSI_DISKS_PER_MAJOR; ++didx) {
			SDev = SD_DISK_PTR(sd_major, didx)->device;
			if (SDev && SDev->host == host
			    && SDev->id == tgt)
				return MDIDX_TO_KDEV(midx,didx);
		}
	}
	return 0;
}
#endif

static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
	kdev_t dev = inode->i_rdev;
	struct Scsi_Host * host;
	Scsi_Device * SDev;
	int diskinfo[4];
	int midx, didx;
	SD_Major  *sd_major;
	Scsi_Disk *scsi_disk;
    
	midx = MAJOR_TO_MIDX(MAJOR(dev));
	didx = MINOR_TO_DIDX(MINOR(dev));
	
	if (midx == SD_NO_MIDX)
		return -ENODEV;
	sd_major  = SD_MAJOR_PTR(midx);
	scsi_disk = SD_DISK_PTR(sd_major,didx);
	SDev = scsi_disk->device;
	if (!SDev)
		return -ENODEV;

	/*
	 * If we are in the middle of error recovery, don't let anyone
	 * else try and use this device.  Also, if error recovery fails, it
	 * may try and take the device offline, in which case all further
	 * access to the device is prohibited.
	 */

	if( !scsi_block_when_processing_errors(SDev) )
		return -ENODEV;

	switch (cmd) 
	{
		case HDIO_GETGEO:   /* Return BIOS disk parameters */
		{
			struct hd_geometry *loc = (struct hd_geometry *) arg;
			if(!loc)
				return -EINVAL;

			host = SDev->host;
	
			/* default to most commonly used values */
	
		        diskinfo[0] = 0x40;
	        	diskinfo[1] = 0x20;
	        	diskinfo[2] = scsi_disk->capacity >> 11;
	
			/* override with calculated, extended default, or driver values */
	
			if(host->hostt->bios_param != NULL)
				host->hostt->bios_param(scsi_disk,
							dev, &diskinfo[0]);
			else scsicam_bios_param(scsi_disk,
						dev, &diskinfo[0]);

			if (put_user(diskinfo[0], &loc->heads) ||
			    put_user(diskinfo[1], &loc->sectors) ||
			    put_user(diskinfo[2], &loc->cylinders) ||
			    put_user(sd_major->sd_gendisk.part[MINOR(dev)].start_sect,
				     &loc->start))
				return -EFAULT;
			return 0;
		}
		case HDIO_GETGEO_BIG:
		{
			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;

			if(!loc)
				return -EINVAL;

			host = SDev->host;

			/* default to most commonly used values */

			diskinfo[0] = 0x40;
			diskinfo[1] = 0x20;
			diskinfo[2] = scsi_disk->capacity >> 11;

			/* override with calculated, extended default, or driver values */

			if(host->hostt->bios_param != NULL)
				host->hostt->bios_param(scsi_disk,
							dev, &diskinfo[0]);
			else scsicam_bios_param(scsi_disk,
						dev, &diskinfo[0]);

			if (put_user(diskinfo[0], &loc->heads) ||
			    put_user(diskinfo[1], &loc->sectors) ||
			    put_user(diskinfo[2], (unsigned int *) &loc->cylinders) ||
			    put_user(sd_major->sd_gendisk.part[MINOR(dev)].start_sect, 
				     &loc->start))
				return -EFAULT;
			return 0;
		}
		case BLKGETSIZE:
		case BLKGETSIZE64:
		case BLKROSET:
		case BLKROGET:
		case BLKRASET:
		case BLKRAGET:
		case BLKFLSBUF:
		case BLKSSZGET:
		case BLKPG:
		case BLKELVGET:
		case BLKELVSET:
		case BLKBSZGET:
		case BLKBSZSET:
			return blk_ioctl(inode->i_rdev, cmd, arg);

		case BLKRRPART: /* Re-read partition tables */
		        if (!capable(CAP_SYS_ADMIN))
		                return -EACCES;
			return revalidate_scsidisk(dev, 1);

		default:
			return scsi_ioctl(SDev, cmd, (void *) arg);
	}
}

int sd_devname(kdev_t dev, char *buffer)
{
	const unsigned int disknum = KDEV_TO_DISKNO(dev);
	const unsigned int part = MINOR(dev) & (SCSI_DISK_MAX_PART-1);
	if (disknum >= SD_NO_MIDX << SCSI_DISK_DISK_SHIFT)
		return -1;
	if (disknum < 26)
		sprintf(buffer, "sd%c", 'a' + disknum);
	else if (disknum < (26*27)) {
		const unsigned int min1 = disknum / 26 - 1;
		const unsigned int min2 = disknum % 26;
		sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2);
	} else {
		const unsigned int min1 = (disknum / 26 - 1) / 26 - 1;
		const unsigned int min2 = (disknum / 26 - 1) % 26;
		const unsigned int min3 = disknum % 26;
		sprintf(buffer, "sd%c%c%c", 'a' + min1, 'a' + min2, 'a' + min3);
	}
	/* Used by fs/partition/check.c */
	if (part) {
		const int pos = strlen(buffer);
		sprintf (buffer+pos, "%d", part);
	}
	return 0;
}

static int sd_find_kdev(Scsi_Device *sdp, char* nm, kdev_t *dev)
{
	SD_Major  *sd_major;
	int midx, didx;
	
	if (sdp && (sdp->type == TYPE_DISK || sdp->type == TYPE_MOD)) {
		for (midx = 0; midx < sd_majors; ++midx) {
			sd_major = SD_MAJOR_PTR(midx);
			for (didx = 0; didx < SCSI_DISKS_PER_MAJOR; ++didx) {
				if (SD_DISK_PTR(sd_major, didx)->device == sdp) {
					*dev = MDIDX_TO_KDEV(midx, didx);
					sd_devname(*dev, nm);
					return 0;
				}
			}
		}
	}
	return 1;
}

request_queue_t *sd_find_queue(kdev_t dev)
{
	Scsi_Disk *dpnt;
	int midx, didx;
	
	midx = MAJOR_TO_MIDX (MAJOR(dev));
	didx = MINOR_TO_DIDX (MINOR(dev));
	if (midx == SD_NO_MIDX) {
		printk (KERN_ERR "sd_find_queue %02x:%02x not found!\n",
			MAJOR(dev), MINOR(dev));
		return NULL;
	}
	dpnt = SD_DISK_PTR(SD_MAJOR_PTR(midx), didx);
	if (!dpnt->device)
		return NULL;	/* No such device */
	return &dpnt->device->request_queue;
}

static int sd_drives_dev(kdev_t dev)
{
	int midx = MAJOR_TO_MIDX(MAJOR(dev));
	if (midx == SD_NO_MIDX)
		return 0;
	else
		return 1;
}

static int sd_init_command(Scsi_Cmnd * SCpnt)
{
	int block, this_count, hw_ssize;
	struct hd_struct *ppnt;
	Scsi_Disk *dpnt;
#if CONFIG_SCSI_LOGGING
	char nbuff[10];
#endif
	int midx, didx;
	SD_Major  *sd_major;

	midx = MAJOR_TO_MIDX(MAJOR(SCpnt->request.rq_dev));
	didx = MINOR_TO_DIDX(MINOR(SCpnt->request.rq_dev));
	if (midx == SD_NO_MIDX) {
		printk ("Can not sd_init_command for dev %02x:%02x!\n",
			MAJOR(SCpnt->request.rq_dev), 
			MINOR(SCpnt->request.rq_dev));
		return 0;
	}
	
	sd_major = SD_MAJOR_PTR(midx);
	dpnt = SD_DISK_PTR(sd_major, didx);
	ppnt = sd_major->sd_gendisk.part+MINOR(SCpnt->request.rq_dev);

	block = SCpnt->request.sector;
	this_count = SCpnt->request_bufflen >> 9;

	hw_ssize = (SCpnt->device->sector_size >> 9) - 1;
	if (SCpnt->request.sector & hw_ssize
	    || SCpnt->request.nr_sectors & hw_ssize)
		return 0;

	SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = 0x%x, block = %d\n",
				   SCpnt->request.rq_dev, block));

	if (!dpnt->device ||
	    !dpnt->device->online ||
	    block + SCpnt->request.nr_sectors > ppnt->nr_sects) {
		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
		return 0;
	}
	block += ppnt->start_sect;
	if (dpnt->device->changed) {
		/*
		 * quietly refuse to do anything to a changed disc until the changed
		 * bit has been reset
		 */
		/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
		return 0;
	}
	SCSI_LOG_HLQUEUE(2, sd_devname(SCpnt->request.rq_dev, nbuff));
	SCSI_LOG_HLQUEUE(2, printk("%s : %02x:%02x, block = %d\n",
				   nbuff, MAJOR(SCpnt->request.rq_dev),
				   MINOR(SCpnt->request.rq_dev), block));

	/*
	 * If we have a 1K hardware sectorsize, prevent access to single
	 * 512 byte sectors.  In theory we could handle this - in fact
	 * the scsi cdrom driver must be able to handle this because
	 * we typically use 1K blocksizes, and cdroms typically have
	 * 2K hardware sectorsizes.  Of course, things are simpler
	 * with the cdrom, since it is read-only.  For performance
	 * reasons, the filesystems should be able to handle this
	 * and not force the scsi disk driver to use bounce buffers
	 * for this.
	 */
	if (dpnt->device->sector_size == 1024) {
		if ((block & 1) || (SCpnt->request.nr_sectors & 1)) {
			printk("sd.c:Bad block number requested");
			return 0;
		} else {
			block = block >> 1;
			this_count = this_count >> 1;
		}
	}
	if (dpnt->device->sector_size == 2048) {
		if ((block & 3) || (SCpnt->request.nr_sectors & 3)) {
			printk("sd.c:Bad block number requested");
			return 0;
		} else {
			block = block >> 2;
			this_count = this_count >> 2;
		}
	}
	if (dpnt->device->sector_size == 4096) {
		if ((block & 7) || (SCpnt->request.nr_sectors & 7)) {
			printk("sd.c:Bad block number requested");
			return 0;
		} else {
			block = block >> 3;
			this_count = this_count >> 3;
		}
	}
	switch (SCpnt->request.cmd) {
	case WRITE:
		if (!dpnt->device->writeable) {
			return 0;
		}
		SCpnt->cmnd[0] = WRITE_6;
		SCpnt->sc_data_direction = SCSI_DATA_WRITE;
		break;
	case READ:
		SCpnt->cmnd[0] = READ_6;
		SCpnt->sc_data_direction = SCSI_DATA_READ;
		break;
	default:
		panic("Unknown sd command %d\n", SCpnt->request.cmd);
	}

	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
				   nbuff,
		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
				 this_count, SCpnt->request.nr_sectors));

	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
			 ((SCpnt->lun << 5) & 0xe0) : 0;

	if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) {
		if (this_count > 0xffff)
			this_count = 0xffff;

		SCpnt->cmnd[0] += READ_10 - READ_6;
		SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
		SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
		SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
		SCpnt->cmnd[5] = (unsigned char) block & 0xff;
		SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0;
		SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
		SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
	} else {
		if (this_count > 0xff)
			this_count = 0xff;

		SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
		SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff);
		SCpnt->cmnd[3] = (unsigned char) block & 0xff;
		SCpnt->cmnd[4] = (unsigned char) this_count;
		SCpnt->cmnd[5] = 0;
	}

	/*
	 * We shouldn't disconnect in the middle of a sector, so with a dumb
	 * host adapter, it's safe to assume that we can at least transfer
	 * this many bytes between each connect / disconnect.
	 */
	SCpnt->transfersize = dpnt->device->sector_size;
	SCpnt->underflow = this_count << 9;

	SCpnt->allowed = MAX_RETRIES;
	SCpnt->timeout_per_command = (SCpnt->device->type == TYPE_DISK ?
				      SD_TIMEOUT : SD_MOD_TIMEOUT);

	/*
	 * This is the completion routine we use.  This is matched in terms
	 * of capability to this function.
	 */
	SCpnt->done = rw_intr;

	/*
	 * This indicates that the command is ready from our end to be
	 * queued.
	 */
	return 1;
}

static int sd_open(struct inode *inode, struct file *filp)
{
	int retval = -ENXIO;
	Scsi_Device * SDev;
	int midx, didx;
	SD_Major  *sd_major;
	Scsi_Disk *scsi_disk;
	
	midx = MAJOR_TO_MIDX(MAJOR(inode->i_rdev));
	didx = MINOR_TO_DIDX(MINOR(inode->i_rdev));

	SCSI_LOG_HLQUEUE(1, printk("target=%d\n", MDIDX_TO_DISKNO(midx, didx)));

	if (midx == SD_NO_MIDX)
		return -ENXIO;
	sd_major  = SD_MAJOR_PTR(midx);
	scsi_disk = SD_DISK_PTR(sd_major, didx);
	SDev = scsi_disk->device;
	
	if (!SDev)
		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(SDev)) {
		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 (SDev->busy) {
		barrier();
		cpu_relax();
		set_current_state(TASK_INTERRUPTIBLE);
		schedule_timeout(HZ / 10);
	}

	/*
	 * The following code can sleep.
	 * Module unloading must be prevented
	 */
	if (SDev->host->hostt->module)
		__MOD_INC_USE_COUNT(SDev->host->hostt->module);
	if (sd_template.module)
		__MOD_INC_USE_COUNT(sd_template.module);
	SDev->access_count++;

 	if (SDev->removable) {
		SDev->allow_revalidate = 1;
		check_disk_change(inode->i_rdev);
		SDev->allow_revalidate = 0;

		/*
		 * If the drive is empty, just let the open fail.
		 */
		if ((!scsi_disk->ready) && !(filp->f_flags & O_NDELAY)) {
			retval = -ENOMEDIUM;
			goto error_out;
		}

		/*
		 * 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 ((scsi_disk->write_prot) && (filp->f_mode & 2)) {
			retval = -EROFS;
			goto error_out;
		}
	}
	/*
	 * 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 (!SDev->online) {
		goto error_out;
	}
	/*
	 * See if we are requesting a non-existent partition.  Do this
	 * after checking for disk change.
	 */
	if (sd_major->sd_sizes[MINOR(inode->i_rdev)] == 0) {
		goto error_out;
	}

	if (SDev->removable)
		if (SDev->access_count==1)
			if (scsi_block_when_processing_errors(SDev))
				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);

	
	return 0;

error_out:
	SDev->access_count--;
	if (SDev->host->hostt->module)
		__MOD_DEC_USE_COUNT(SDev->host->hostt->module);
	if (sd_template.module)
		__MOD_DEC_USE_COUNT(sd_template.module);
	return retval;	
}

static int sd_release(struct inode *inode, struct file *file)
{
	Scsi_Device *SDev;
	int midx, didx;
	
	midx = MAJOR_TO_MIDX(MAJOR(inode->i_rdev));
	didx = MINOR_TO_DIDX(MINOR(inode->i_rdev));

	if (midx == SD_NO_MIDX) {
		printk (KERN_ERR "sd_release: dev %02x:%02x does not belong to sd!\n", 
			MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
		return -ENODEV;
	}
	
	SDev = SD_DISK_PTR(SD_MAJOR_PTR(midx), didx)->device;
	
	if (!SDev)
		return -ENODEV;

	SDev->access_count--;

	if (SDev->removable) {
		if (!SDev->access_count)
			if (scsi_block_when_processing_errors(SDev))
				scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL);
	}
	if (SDev->host->hostt->module)
		__MOD_DEC_USE_COUNT(SDev->host->hostt->module);
	if (sd_template.module)
		__MOD_DEC_USE_COUNT(sd_template.module);
	return 0;
}

struct block_device_operations sd_fops =
{
	owner:			THIS_MODULE,
	open:			sd_open,
	release:		sd_release,
	ioctl:			sd_ioctl,
	check_media_change:	check_scsidisk_media_change,
	revalidate:		fop_revalidate_scsidisk
};

/*
 * 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;
#if CONFIG_SCSI_LOGGING
	char nbuff[10];
#endif
	int this_count = SCpnt->bufflen >> 9;
	int good_sectors = (result == 0 ? this_count : 0);
	int block_sectors = 1;
	long error_sector;
	int midx, didx;
	
	midx = MAJOR_TO_MIDX(MAJOR(SCpnt->request.rq_dev));
	didx = MINOR_TO_DIDX(MINOR(SCpnt->request.rq_dev));

	SCSI_LOG_HLCOMPLETE(1, sd_devname(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.
	 */

	/* An error occurred */
	if (driver_byte(result) != 0 && 	/* An error occured */
	    (SCpnt->sense_buffer[0] & 0x7f) == 0x70) {	/* Sense data is valid */
		switch (SCpnt->sense_buffer[2]) {
		case MEDIUM_ERROR:
			if (!(SCpnt->sense_buffer[0] & 0x80))
				break;
			error_sector = (SCpnt->sense_buffer[3] << 24) |
			(SCpnt->sense_buffer[4] << 16) |
			(SCpnt->sense_buffer[5] << 8) |
			SCpnt->sense_buffer[6];
			if (SCpnt->request.bh != NULL)
				block_sectors = SCpnt->request.bh->b_size >> 9;
			switch (SCpnt->device->sector_size) {
			case 1024:
				error_sector <<= 1;
				if (block_sectors < 2)
					block_sectors = 2;
				break;
			case 2048:
				error_sector <<= 2;
				if (block_sectors < 4)
					block_sectors = 4;
				break;
			case 4096:
				error_sector <<=3;
				if (block_sectors < 8)
					block_sectors = 8;
				break;
			case 256:
				error_sector >>= 1;
				break;
			default:
				break;
			}
			/* find offset into partition */
			error_sector -= SD_MAJOR_PTR(midx)
				->sd_gendisk.part[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;
			break;

		case RECOVERED_ERROR:
			/*
			 * An error occured, but it recovered.  Inform the
			 * user, but make sure that it's not treated as a
			 * hard error.
			 */
			print_sense("sd", SCpnt);
			SCpnt->result = 0;
			SCpnt->sense_buffer[0] = 0x0;
			good_sectors = this_count;
			break;

		case ILLEGAL_REQUEST:
			if (SCpnt->device->ten == 1) {
				if (SCpnt->cmnd[0] == READ_10 ||
				    SCpnt->cmnd[0] == WRITE_10)
					SCpnt->device->ten = 0;
			}
			break;

		default:
			break;
		}
	}
	/*
	 * This calls the generic completion function, now that we know
	 * how many actual sectors finished, and how many sectors we need
	 * to say have failed.
	 */
	scsi_io_completion(SCpnt, good_sectors, block_sectors);
}
/*
 * requeue_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 int check_scsidisk_media_change(kdev_t full_dev)
{
	int retval = 0;
	int midx, didx;
	SD_Major *sd_major;
	Scsi_Disk *scsi_disk;
	
	midx = MAJOR_TO_MIDX(MAJOR(full_dev));
	didx = MINOR_TO_DIDX(MINOR(full_dev));
	
	if (midx == SD_NO_MIDX) {
		printk("SCSI disk request error: invalid major.\n");
		return 0;
	}
	sd_major  = SD_MAJOR_PTR(midx);
	scsi_disk = SD_DISK_PTR(sd_major, didx);

	if (!scsi_disk->device) {
		printk("SCSI disk request error: invalid device.\n");
		return 0;
	}
	if (!scsi_disk->device->removable)
		return 0;

	/*
	 * If the device is offline, don't send any commands - just pretend as
	 * if the command failed.  If the device ever comes back online, we
	 * can deal with it then.  It is only because of unrecoverable errors
	 * that we would ever take a device offline in the first place.
	 */
	if (scsi_disk->device->online == FALSE) {
		scsi_disk->ready = 0;
		scsi_disk->device->changed = 1;
		return 1;	/* This will force a flush, if called from
				 * check_disk_change */
	}

	/*
	 * Using TEST_UNIT_READY enables differentiation between drive with
	 * no cartridge loaded - NOT READY, drive with changed cartridge -
	 * UNIT ATTENTION, or with same cartridge - GOOD STATUS.
	 *
	 * Drives that auto spin down. eg iomega jaz 1G, will be started
	 * by sd_init_onedisk(), whenever revalidate_scsidisk() is called.
	 */
	retval = -ENODEV;
	if (scsi_block_when_processing_errors(scsi_disk->device))
		retval = scsi_ioctl(scsi_disk->device, SCSI_IOCTL_TEST_UNIT_READY, NULL);

	if (retval) {		/* Unable to test, unit probably not ready.
				 * This usually means there is no disc in the
				 * drive.  Mark as changed, and we will figure
				 * it out later once the drive is available
				 * again.  */

		scsi_disk->ready = 0;
		scsi_disk->device->changed = 1;
		return 1;	/* This will force a flush, if called from
				 * check_disk_change */
	}
	/*
	 * for removable scsi disk ( FLOPTICAL ) we have to recognise the
	 * presence of disk in the drive. This is kept in the Scsi_Disk
	 * struct and tested at open !  Daniel Roche ( dan@lectra.fr )
	 */

	scsi_disk->ready = 1;	/* FLOPTICAL */

	retval = scsi_disk->device->changed;
	/* FIXME: The next statement was behind a if (!flag) conditional
	 * with flag initialized to 0 and never changed ...  KG. */ 
	scsi_disk->device->changed = 0;
	return retval;
}

static int sd_init_onedisk(int midx, int didx)
{
	unsigned char cmd[10];
	char nbuff[8];
	unsigned char *buffer;
	unsigned long spintime_value = 0;
	int the_result, retries, spintime;
	int sector_size; unsigned int sz;
	int part;
	unsigned char cdb1;
	Scsi_Request *SRpnt;
	SD_Major *sd_major = SD_MAJOR_PTR(midx);
	Scsi_Disk *scsi_disk = SD_DISK_PTR(sd_major, didx);

	/*
	 * Get the name of the disk, in case we need to log it somewhere.
	 */
	sd_devname(MDIDX_TO_KDEV(midx,didx), nbuff);

	/*
	 * If the device is offline, don't try and read capacity or any
	 * of the other niceties.
	 */
	if (scsi_disk->device->online == FALSE)
		return -1;

	//printk (KERN_DEBUG "sd_init_onedisk (%i,%i), %s %02x:%02x\n",
	//	midx, didx, nbuff, MIDX_TO_MAJOR(midx), DIDX_TO_MINOR(didx));

	/*
	 * We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
	 * considered a fatal error, and many devices report such an error
	 * just after a scsi bus reset.
	 */

	SRpnt = scsi_allocate_request(scsi_disk->device);
	if (!SRpnt) {
		printk(KERN_WARNING "(sd_init_onedisk:) Request allocation failure.\n");
		return -1;
	}

	buffer = (unsigned char *) scsi_malloc(512);
	if (!buffer) {
		printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation failure.\n");
		scsi_release_request(SRpnt);
		return -1;
	}

	cdb1 = (scsi_disk->device->scsi_level <= SCSI_2) ?
		((scsi_disk->device->lun << 5) & 0xe0) : 0;
	spintime = 0;

	/* Spin up drives, as required.  Only do this at boot time */
	/* Spinup needs to be done for module loads too. */
	do {
		retries = 0;

		while (retries < 3) {
			cmd[0] = TEST_UNIT_READY;
			cmd[1] = cdb1;
			memset((void *) &cmd[2], 0, 8);
			SRpnt->sr_cmd_len = 0;
			SRpnt->sr_sense_buffer[0] = 0;
			SRpnt->sr_sense_buffer[2] = 0;
			SRpnt->sr_data_direction = SCSI_DATA_NONE;

			scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
				       0/*512*/, SD_TIMEOUT, MAX_RETRIES);

			the_result = SRpnt->sr_result;
			retries++;
			if (the_result == 0
			    || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION)
				break;
		}

		/*
		 * If the drive has indicated to us that it doesn't have
		 * any media in it, don't bother with any of the rest of
		 * this crap.
		 */
		if( the_result != 0
		    && ((driver_byte(the_result) & DRIVER_SENSE) != 0)
		    && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION
		    && SRpnt->sr_sense_buffer[12] == 0x3A ) {
			scsi_disk->capacity = 0x1fffff;
			sector_size = 512;
			scsi_disk->device->changed = 1;
			scsi_disk->ready = 0;
			break;
		}

		/* Look for non-removable devices that return NOT_READY.
		 * and don't require manual intervention.
		 * Issue command to spin up drive for these cases. */
		if (the_result && !scsi_disk->device->removable &&
                   SRpnt->sr_sense_buffer[2] == NOT_READY &&
                   ! ( SRpnt->sr_sense_buffer[12] == 0x04 &&   /* ASC */
                       SRpnt->sr_sense_buffer[13] == 0x03 )) { /* ASCQ */
			unsigned long time1;
			if (!spintime) {
				printk("%s: Spinning up disk...", nbuff);
				cmd[0] = START_STOP;
				cmd[1] = cdb1 | 1; /* Return immediately */
				memset((void *) &cmd[2], 0, 8);
				cmd[4] = 1;	/* Start spin cycle */
				SRpnt->sr_cmd_len = 0;
				SRpnt->sr_sense_buffer[0] = 0;
				SRpnt->sr_sense_buffer[2] = 0;

				SRpnt->sr_data_direction = SCSI_DATA_NONE;
				scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
					    0/*512*/, SD_TIMEOUT, MAX_RETRIES);
				spintime_value = jiffies;
			}
			spintime = 1;
			time1 = HZ;
			/* Wait 1 second for next try */
			do {
				current->state = TASK_UNINTERRUPTIBLE;
				time1 = schedule_timeout(time1);
			} while(time1);
			printk(".");
		}
	} while (the_result && spintime &&
		 time_after(spintime_value + 100 * HZ, jiffies));
	if (spintime) {
		if (the_result)
			printk("not responding...\n");
		else
			printk("ready\n");
	}
	retries = 3;
	do {
		cmd[0] = READ_CAPACITY;
		cmd[1] = cdb1;
		memset((void *) &cmd[2], 0, 8);
		memset((void *) buffer, 0, 8);
		SRpnt->sr_cmd_len = 0;
		SRpnt->sr_sense_buffer[0] = 0;
		SRpnt->sr_sense_buffer[2] = 0;

		SRpnt->sr_data_direction = SCSI_DATA_READ;
		scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
			      8, SD_TIMEOUT, MAX_RETRIES);

		the_result = SRpnt->sr_result;
		retries--;

	} while (the_result && retries);

	/*
	 * The SCSI standard says:
	 * "READ CAPACITY is necessary for self configuring 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 someone attempts to read past the
	 *     end of the raw device will be slower.
	 */

	if (the_result) {
		printk("%s : READ CAPACITY failed.\n"
		       "%s : status = %x, message = %02x, host = %d, driver = %02x \n",
		       nbuff, nbuff,
		       status_byte(the_result),
		       msg_byte(the_result),
		       host_byte(the_result),
		       driver_byte(the_result)
		    );
		if (driver_byte(the_result) & DRIVER_SENSE)
			print_req_sense("sd", SRpnt);
		else
			printk("%s : sense not available. \n", nbuff);

		printk("%s : block size assumed to be 512 bytes, disk size 1GB.  \n",
		       nbuff);
		scsi_disk->capacity = 0x1fffff;
		sector_size = 512;

		/* Set dirty bit for removable devices if not ready -
		 * sometimes drives will not report this properly. */
		if (scsi_disk->device->removable &&
		    SRpnt->sr_sense_buffer[2] == NOT_READY)
			scsi_disk->device->changed = 1;

	} else {
		/*
		 * FLOPTICAL, if read_capa is ok, drive is assumed to be ready
		 */
		scsi_disk->ready = 1;

		scsi_disk->capacity = 1 + ((buffer[0] << 24) |
					   (buffer[1] << 16) |
					   (buffer[2] << 8) |
					   buffer[3]);

		sector_size = (buffer[4] << 24) |
			(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];

		if (sector_size == 0) {
			sector_size = 512;
			printk("%s : sector size 0 reported, assuming 512.\n",
			       nbuff);
		}
		if (sector_size != 512 &&
		    sector_size != 1024 &&
		    sector_size != 2048 &&
		    sector_size != 4096 &&
		    sector_size != 256) {
			printk("%s : unsupported sector size %d.\n",
			       nbuff, sector_size);
			/*
			 * The user might want to re-format the drive with
			 * a supported sectorsize.  Once this happens, it
			 * would be relatively trivial to set the thing up.
			 * For this reason, we leave the thing in the table.
			 */
			scsi_disk->capacity = 0;
		}
		if (sector_size > 1024) {
			/*
			 * We must fix the sd_blocksizes and sd_hardsizes
			 * to allow us to read the partition tables.
			 * The disk reading code does not allow for reading
			 * of partial sectors.
			 */
			for (part = 0; part < SCSI_DISK_MAX_PART; ++part)
				sd_major->sd_blocksizes[DIDX_TO_MINOR(didx) + part]
					= sector_size;
		}
		/*
		 * The msdos fs needs to know the hardware sector size
		 * So I have created this table. See ll_rw_blk.c
		 * Jacques Gelinas (Jacques@solucorp.qc.ca)
		 */
		sz = (scsi_disk->capacity/2) * (sector_size/256);
		for (part = 0; part < SCSI_DISK_MAX_PART; ++part)
			sd_major->sd_hardsizes[DIDX_TO_MINOR(didx) + part]
				= sector_size;
		
		printk("SCSI device %s: "
		       "%u %d-byte hdwr sectors (%u MB)\n",
		       nbuff, scsi_disk->capacity,
		       sector_size, (sz - sz/625 + 974)/1950);

		/* Rescale capacity to 512-byte units */
		if (sector_size == 4096)
			scsi_disk->capacity <<= 3;
		if (sector_size == 2048)
			scsi_disk->capacity <<= 2;
		if (sector_size == 1024)
			scsi_disk->capacity <<= 1;
		if (sector_size == 256)
			scsi_disk->capacity >>= 1;
	}


	/*
	 * Unless otherwise specified, this is not write protected.
	 */
	scsi_disk->write_prot = 0;
	if (scsi_disk->device->removable && scsi_disk->ready) {
		/* FLOPTICAL */

		/*
		 * For removable scsi disk ( FLOPTICAL ) we have to recognise
		 * the Write Protect Flag. This flag is kept in the Scsi_Disk
		 * struct and tested at open !
		 * Daniel Roche ( dan@lectra.fr )
		 *
		 * Changed to get all pages (0x3f) rather than page 1 to
		 * get around devices which do not have a page 1.  Since
		 * we're only interested in the header anyway, this should
		 * be fine.
		 *   -- Matthew Dharm (mdharm-scsi@one-eyed-alien.net)
		 */

		memset((void *) &cmd[0], 0, 8);
		cmd[0] = MODE_SENSE;
		cmd[1] = cdb1;
		cmd[2] = 0x3f;	/* Get all pages */
		cmd[4] = 252;   /* Ask for 252 bytes, even tho we want just the first 8 */
		SRpnt->sr_cmd_len = 0;
		SRpnt->sr_sense_buffer[0] = 0;
		SRpnt->sr_sense_buffer[2] = 0;

		/* same code as READCAPA !! */
		SRpnt->sr_data_direction = SCSI_DATA_READ;
		scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
			      252, SD_TIMEOUT, MAX_RETRIES);

		the_result = SRpnt->sr_result;

		if (the_result) {
			printk("%s: test WP failed, assume Write Enabled\n", nbuff);
		} else {
			scsi_disk->write_prot = ((buffer[2] & 0x80) != 0);
			printk("%s: Write Protect is %s\n", nbuff,
			       scsi_disk->write_prot ? "on" : "off");
		}

	}			/* check for write protect */

	SRpnt->sr_device->ten = 1;
	SRpnt->sr_device->remap = 1;
	SRpnt->sr_device->sector_size = sector_size;
	/* Wake up a process waiting for device */
	scsi_release_request(SRpnt);
	SRpnt = NULL;

	scsi_free(buffer, 512);
	return 0;
}

/*
 * We are called on behalf scan_scsis() for every Device.
 * First init(), then attach(Scsi_Device*), finally finish().
 * It's inconvenient: In finish(), we don't know what device
 * has been attached. So we iterate over all disk in
 * sd_finish(). Sigh! KG.
 */

static int sd_registered;

static int sd_init()
{
	int err = 0;
	if (!sd_template.dev_noticed)
		return 0;
	sd_template.dev_max = MAX_SCSI_DYN_MAJORS * SCSI_DISKS_PER_MAJOR;
	SD_LOCK_W;
	//printk(KERN_DEBUG "sd_init()\n");
	if (!sd_majors) {
		/* Register one sd_major at startup */
		err = sd_alloc_major ();
	}
	SD_UNLOCK_W;
	if (err == SD_NO_MAJOR) {
		sd_template.dev_noticed = 0;
		return 1;
	} else {
		sd_registered++;
		return 0;
	}
}


static void sd_finish()
{
	int midx, didx;
	SD_Major  *sd_major;
	Scsi_Disk *scsi_disk;
	/* Everything moved to attach() */
	//printk (KERN_DEBUG "sd_finish()\n");

	for (midx = 0; midx < sd_majors; ++midx) {
		sd_major = SD_MAJOR_PTR(midx);
		for (didx = 0; didx < SCSI_DISKS_PER_MAJOR; ++didx) {
			scsi_disk = SD_DISK_PTR(sd_major, didx);
			if (scsi_disk->device && !scsi_disk->capacity) {
				if (sd_init_onedisk(midx, didx) == -1) {
					scsi_disk->attached = 0;
					sd_major->sd_gendisk.nr_real--;
					sd_template.nr_dev--;
					scsi_disk->device->attached--;
					//sd_next--;
					continue;
				}

				if (!scsi_disk->has_part_table) {
					sd_major->sd_sizes[DIDX_TO_MINOR(didx)] = scsi_disk->capacity;
					register_disk(&sd_major->sd_gendisk, MDIDX_TO_KDEV(midx,didx),
			      			      SCSI_DISK_MAX_PART, &sd_fops,
			      			      scsi_disk->capacity);
					scsi_disk->has_part_table = 1;
				}
		/* If our host adapter is capable of scatter-gather, then we increase
		 * the read-ahead to 128 sectors (64k).  If not, we stay to a 8 sectors 
		 * (4k) default. We can only respect this on a per major basis.
		 */
				if (scsi_disk->device->host->sg_tablesize)
					read_ahead[MIDX_TO_MAJOR(midx)] = 128;
			}
		}
	}
}

static int sd_detect(Scsi_Device * SDp)
{
	if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
		return 0;
	sd_template.dev_noticed++;
	return 1;
}

static int sd_attach(Scsi_Device * SDp)
{
	SD_Major *sd_major;
	Scsi_Disk *scsi_disk;
	struct gendisk *gdp;
	
	int midx, didx;
	char nbuff[8];

	//printk (KERN_DEBUG "sd_attach()\n");
	if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
		return 0;

	if (sd_find_free_slot (SDp, &midx, &didx)) {
		SDp->attached--;
		return 1;
	}

	sd_major  = SD_MAJOR_PTR(midx);
	scsi_disk = SD_DISK_PTR(sd_major, didx);
		
	scsi_disk->device = SDp;
	scsi_disk->has_part_table = 0;
	scsi_disk->attached = 1;
	sd_template.nr_dev++;

	gdp = &sd_major->sd_gendisk;
	gdp->nr_real++;
	gdp->de_arr[didx] = SDp->de;
	
	if (SDp->removable)
		gdp->flags[didx] |= GENHD_FL_REMOVABLE;
	sd_devname(MDIDX_TO_KDEV(midx,didx), nbuff);
	printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
	       SDp->removable ? "removable " : "",
	       nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);

	if (SDp->host->hostt->vary_io)
		memset(sd_major->sd_varyio + DIDX_TO_MINOR(didx), 1, SCSI_DISK_MAX_PART);
	
	blk_dev[MIDX_TO_MAJOR(midx)].queue = sd_find_queue;
	
	return 0;
}

#define DEVICE_BUSY scsi_disk->device->busy
#define ALLOW_REVALIDATE scsi_disk->device->allow_revalidate
#define USAGE scsi_disk->device->access_count
#define CAPACITY scsi_disk->capacity
#define MAYBE_REINIT  sd_init_onedisk(midx,didx)

/* This routine is called to flush all partitions and partition tables
 * for a changed scsi disk, and then re-read the new partition table.
 * If we are revalidating a disk because of a media change, then we
 * enter with usage == 0.  If we are using an ioctl, we automatically have
 * usage == 1 (we need an open channel to use an ioctl :-), so this
 * is our limit.
 */
int revalidate_scsidisk(kdev_t dev, int maxusage)
{
	struct gendisk *sdgd;
	SD_Major *sd_major;
	Scsi_Disk *scsi_disk;
	int midx, didx;
	int max_p, part;
	int major, minor;

	major = MAJOR(dev); minor = MINOR(dev);
	midx = MAJOR_TO_MIDX(major);
	sd_major = SD_MAJOR_PTR(midx);
	didx = MINOR_TO_DIDX(minor);
	scsi_disk = SD_DISK_PTR(sd_major, didx);

	if (DEVICE_BUSY || (ALLOW_REVALIDATE == 0 && USAGE > maxusage)) {
		printk("Device busy for revalidation (usage=%d)\n", USAGE);
		return -EBUSY;
	}
	DEVICE_BUSY = 1;

	sdgd = &sd_major->sd_gendisk;
	max_p = sdgd->max_p;
	minor = DIDX_TO_MINOR(didx); /* equiv to: minor &= ~(SCSI_DISK_MAX_PART-1) */

	for (part = max_p - 1; part >= 0; --part) {
		invalidate_device(MKDEV(major, minor+part), 1);
		sdgd->part[minor+part].start_sect = 0;
		sdgd->part[minor+part].nr_sects = 0;
		/*
		 * Reset the blocksize for everything so that we can read
		 * the partition table.  Technically we will determine the
		 * correct block size when we revalidate, but we do this just
		 * to make sure that everything remains consistent.
		 */
		if (scsi_disk->device->sector_size == 2048)
			sd_major->sd_blocksizes[minor+part] = 2048;
		else
			sd_major->sd_blocksizes[minor+part] = 1024;
	}

#ifdef MAYBE_REINIT
	MAYBE_REINIT;
#endif

	grok_partitions(sdgd, didx, SCSI_DISK_MAX_PART, CAPACITY);

	DEVICE_BUSY = 0;
	return 0;
}

static int fop_revalidate_scsidisk(kdev_t dev)
{
	return revalidate_scsidisk(dev, 0);
}
static void sd_detach(Scsi_Device * SDp)
{
	SD_Major *sd_major;
	Scsi_Disk *scsi_disk;
	int midx, didx;	/* major, disk */
	struct gendisk *sdgd;
	int part;
	int max_p;
	int major, minor; 

	if (sd_majors == 0)
		return;

	for (midx = 0; midx < sd_majors; ++midx) {
		sd_major = SD_MAJOR_PTR(midx);
		for (didx = 0; didx < SCSI_DISKS_PER_MAJOR; ++didx) {
			scsi_disk = SD_DISK_PTR(sd_major, didx);
			if (scsi_disk->device == SDp) {
				/* If we are disconnecting a disk driver, sync and invalidate
				 * everything */
				sdgd  = &sd_major->sd_gendisk;
				major = sdgd->major;
				max_p = sdgd->max_p;
				minor = DIDX_TO_MINOR(didx);
				
				for (part = max_p - 1; part >= 0; --part) {
					invalidate_device(MKDEV(major,minor+part), 1);
					sdgd->part[minor+part].start_sect = 0;
					sdgd->part[minor+part].nr_sects = 0;
					sd_major->sd_sizes[minor+part] = 0;
				}
				devfs_register_partitions (sdgd, minor+part, 1);

				/* unregister_disk() */
				scsi_disk->device = NULL;
				scsi_disk->has_part_table = 0;
				scsi_disk->capacity = 0;
				scsi_disk->attached = 0;
				SDp->attached--;
				sd_template.dev_noticed--;
				sd_template.nr_dev--;
				sd_major->sd_gendisk.nr_real--;
				memset(sd_major->sd_varyio + minor, 0, SCSI_DISK_MAX_PART);
				return;
			}
		}
	}
	return;
}

static int __init init_sd(void)
{
	sd_template.module = THIS_MODULE;
	return scsi_register_module(MODULE_SCSI_DEV, &sd_template);
}

static void __exit exit_sd(void)
{
	scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);

	sd_registered--;
	sd_deallocate_all ();
}

module_init(init_sd);
module_exit(exit_sd);
MODULE_LICENSE("GPL");
