patch-2.1.15 linux/drivers/block/hd.c
Next file: linux/drivers/block/ide-cd.c
Previous file: linux/drivers/block/Makefile
Back to the patch index
Back to the overall index
- Lines: 566
- Date:
Thu Dec 12 16:51:08 1996
- Orig file:
v2.1.14/linux/drivers/block/hd.c
- Orig date:
Tue Oct 29 19:58:03 1996
diff -u --recursive --new-file v2.1.14/linux/drivers/block/hd.c linux/drivers/block/hd.c
@@ -17,11 +17,15 @@
*
* IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
* and general streamlining by Mark Lord.
+ *
+ * Removed 99% of above. Use Mark's ide driver for those options.
+ * This is now a lightweight ST-506 driver. (Paul Gortmaker)
+ *
*/
-
-#define DEFAULT_MULT_COUNT 0 /* set to 0 to disable multiple mode at boot */
-#define DEFAULT_UNMASK_INTR 0 /* set to 0 to *NOT* unmask irq's more often */
-
+
+/* Uncomment the following if you want verbose error reports. */
+/* #define VERBOSE_ERRORS */
+
#include <asm/irq.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -73,16 +77,13 @@
*/
struct hd_i_struct {
unsigned int head,sect,cyl,wpcom,lzone,ctl;
- };
-static struct hd_driveid *hd_ident_info[MAX_HD] = {0, };
+};
#ifdef HD_TYPE
static struct hd_i_struct hd_info[] = { HD_TYPE };
-struct hd_i_struct bios_info[] = { HD_TYPE };
static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
#else
static struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
-struct hd_i_struct bios_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
static int NR_HD = 0;
#endif
@@ -115,14 +116,14 @@
if (ints[0] != 3)
return;
- if (bios_info[0].head != 0)
+ if (hd_info[0].head != 0)
hdind=1;
- bios_info[hdind].head = hd_info[hdind].head = ints[2];
- bios_info[hdind].sect = hd_info[hdind].sect = ints[3];
- bios_info[hdind].cyl = hd_info[hdind].cyl = ints[1];
- bios_info[hdind].wpcom = hd_info[hdind].wpcom = 0;
- bios_info[hdind].lzone = hd_info[hdind].lzone = ints[1];
- bios_info[hdind].ctl = hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+ hd_info[hdind].head = ints[2];
+ hd_info[hdind].sect = ints[3];
+ hd_info[hdind].cyl = ints[1];
+ hd_info[hdind].wpcom = 0;
+ hd_info[hdind].lzone = ints[1];
+ hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
NR_HD = hdind+1;
}
@@ -134,6 +135,7 @@
devc = CURRENT ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
save_flags (flags);
sti();
+#ifdef VERBOSE_ERRORS
printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
if (stat & BUSY_STAT) printk("Busy ");
if (stat & READY_STAT) printk("DriveReady ");
@@ -164,6 +166,15 @@
}
printk("\n");
}
+#else
+ printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
+ if ((stat & ERR_STAT) == 0) {
+ hd_error = 0;
+ } else {
+ hd_error = inb(HD_ERROR);
+ printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
+ }
+#endif /* verbose errors */
restore_flags (flags);
}
@@ -246,113 +257,6 @@
}
static void hd_request (void);
-static unsigned int identified [MAX_HD] = {0,}; /* 1 = drive ID already displayed */
-static unsigned int unmask_intr [MAX_HD] = {0,}; /* 1 = unmask IRQs during I/O */
-static unsigned int max_mult [MAX_HD] = {0,}; /* max sectors for MultMode */
-static unsigned int mult_req [MAX_HD] = {0,}; /* requested MultMode count */
-static unsigned int mult_count [MAX_HD] = {0,}; /* currently enabled MultMode count */
-static struct request WCURRENT;
-
-static void fixstring (unsigned char *s, int bytecount)
-{
- unsigned char *p, *end = &s[bytecount &= ~1]; /* bytecount must be even */
-
- /* convert from big-endian to little-endian */
- for (p = end ; p != s;) {
- unsigned short *pp = (unsigned short *) (p -= 2);
- *pp = (*pp >> 8) | (*pp << 8);
- }
-
- /* strip leading blanks */
- while (s != end && *s == ' ')
- ++s;
-
- /* compress internal blanks and strip trailing blanks */
- while (s != end && *s) {
- if (*s++ != ' ' || (s != end && *s && *s != ' '))
- *p++ = *(s-1);
- }
-
- /* wipe out trailing garbage */
- while (p != end)
- *p++ = '\0';
-}
-
-static void identify_intr(void)
-{
- unsigned int dev = DEVICE_NR(CURRENT->rq_dev);
- unsigned short stat = inb_p(HD_STATUS);
- struct hd_driveid *id = hd_ident_info[dev];
-
- if (unmask_intr[dev])
- sti();
- if (stat & (BUSY_STAT|ERR_STAT)) {
- printk (" hd%c: non-IDE device, %dMB, CHS=%d/%d/%d\n", dev+'a',
- hd_info[dev].cyl*hd_info[dev].head*hd_info[dev].sect / 2048,
- hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect);
- if (id != NULL) {
- hd_ident_info[dev] = NULL;
- kfree_s (id, 512);
- }
- } else {
- insw(HD_DATA, id, 256); /* get ID info */
- max_mult[dev] = id->max_multsect;
- if ((id->field_valid&1) && id->cur_cyls && id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
- /*
- * Extract the physical drive geometry for our use.
- * Note that we purposely do *not* update the bios_info.
- * This way, programs that use it (like fdisk) will
- * still have the same logical view as the BIOS does,
- * which keeps the partition table from being screwed.
- */
- hd_info[dev].cyl = id->cur_cyls;
- hd_info[dev].head = id->cur_heads;
- hd_info[dev].sect = id->cur_sectors;
- }
- fixstring (id->serial_no, sizeof(id->serial_no));
- fixstring (id->fw_rev, sizeof(id->fw_rev));
- fixstring (id->model, sizeof(id->model));
- printk (" hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
- dev+'a', id->model, id->cyls*id->heads*id->sectors/2048,
- id->buf_size/2, bios_info[dev].cyl, bios_info[dev].head,
- bios_info[dev].sect, id->max_multsect);
- /*
- * Early model Quantum drives go weird at this point,
- * but doing a recalibrate seems to "fix" them.
- * (Doing a full reset confuses some other model Quantums)
- */
- if (!strncmp(id->model, "QUANTUM", 7))
- special_op[dev] = recalibrate[dev] = 1;
- }
-#if (HD_DELAY > 0)
- last_req = read_timer();
-#endif
- hd_request();
- return;
-}
-
-static void set_multmode_intr(void)
-{
- unsigned int dev = DEVICE_NR(CURRENT->rq_dev), stat = inb_p(HD_STATUS);
-
- if (unmask_intr[dev])
- sti();
- if (stat & (BUSY_STAT|ERR_STAT)) {
- mult_req[dev] = mult_count[dev] = 0;
- dump_status("set multmode failed", stat);
- } else {
- if ((mult_count[dev] = mult_req[dev]))
- printk (" hd%c: enabled %d-sector multiple mode\n",
- dev+'a', mult_count[dev]);
- else
- printk (" hd%c: disabled multiple mode\n", dev+'a');
- }
-#if (HD_DELAY > 0)
- last_req = read_timer();
-#endif
- hd_request();
- return;
-}
static int drive_busy(void)
{
@@ -398,17 +302,6 @@
}
if (++i < NR_HD) {
special_op[i] = recalibrate[i] = 1;
- if (unmask_intr[i]) {
- unmask_intr[i] = DEFAULT_UNMASK_INTR;
- printk("hd%c: reset irq-unmasking to %d\n",i+'a',
- DEFAULT_UNMASK_INTR);
- }
- if (mult_req[i] || mult_count[i]) {
- mult_count[i] = 0;
- mult_req[i] = DEFAULT_MULT_COUNT;
- printk("hd%c: reset multiple mode to %d\n",i+'a',
- DEFAULT_MULT_COUNT);
- }
hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
if (reset)
@@ -471,11 +364,8 @@
static void read_intr(void)
{
- unsigned int dev = DEVICE_NR(CURRENT->rq_dev);
- int i, retries = 100000, msect = mult_count[dev], nsect;
+ int i, retries = 100000;
- if (unmask_intr[dev])
- sti(); /* permit other IRQs during xfer */
do {
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
@@ -490,28 +380,20 @@
hd_request();
return;
ok_to_read:
- if (msect) {
- if ((nsect = CURRENT->current_nr_sectors) > msect)
- nsect = msect;
- msect -= nsect;
- } else
- nsect = 1;
- insw(HD_DATA,CURRENT->buffer,nsect<<8);
- CURRENT->sector += nsect;
- CURRENT->buffer += nsect<<9;
+ insw(HD_DATA,CURRENT->buffer,256);
+ CURRENT->sector++;
+ CURRENT->buffer += 512;
CURRENT->errors = 0;
- i = (CURRENT->nr_sectors -= nsect);
-
+ i = --CURRENT->nr_sectors;
+ --CURRENT->current_nr_sectors;
#ifdef DEBUG
- printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=0x%08lx\n",
- dev+'a', CURRENT->sector, CURRENT->sector+nsect,
- CURRENT->nr_sectors, (unsigned long) CURRENT->buffer+(nsect<<9));
+ printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
+ dev+'a', CURRENT->sector, CURRENT->nr_sectors,
+ (unsigned long) CURRENT->buffer+512));
#endif
- if ((CURRENT->current_nr_sectors -= nsect) <= 0)
+ if (CURRENT->current_nr_sectors <= 0)
end_request(1);
if (i > 0) {
- if (msect)
- goto ok_to_read;
SET_INTR(&read_intr);
return;
}
@@ -524,66 +406,11 @@
return;
}
-static inline void multwrite (unsigned int dev)
-{
- unsigned int mcount = mult_count[dev];
-
- while (mcount--) {
- outsw(HD_DATA,WCURRENT.buffer,256);
- if (!--WCURRENT.nr_sectors)
- return;
- WCURRENT.buffer += 512;
- if (!--WCURRENT.current_nr_sectors) {
- WCURRENT.bh = WCURRENT.bh->b_reqnext;
- if (WCURRENT.bh == NULL)
- panic("buffer list corrupted\n");
- WCURRENT.current_nr_sectors = WCURRENT.bh->b_size>>9;
- WCURRENT.buffer = WCURRENT.bh->b_data;
- }
- }
-}
-
-static void multwrite_intr(void)
-{
- int i;
- unsigned int dev = DEVICE_NR(WCURRENT.rq_dev);
-
- if (unmask_intr[dev])
- sti();
- if (OK_STATUS(i=inb_p(HD_STATUS))) {
- if (i & DRQ_STAT) {
- if (WCURRENT.nr_sectors) {
- multwrite(dev);
- SET_INTR(&multwrite_intr);
- return;
- }
- } else {
- if (!WCURRENT.nr_sectors) { /* all done? */
- for (i = CURRENT->nr_sectors; i > 0;){
- i -= CURRENT->current_nr_sectors;
- end_request(1);
- }
-#if (HD_DELAY > 0)
- last_req = read_timer();
-#endif
- if (CURRENT)
- hd_request();
- return;
- }
- }
- }
- dump_status("multwrite_intr", i);
- bad_rw_intr();
- hd_request();
-}
-
static void write_intr(void)
{
int i;
int retries = 100000;
- if (unmask_intr[DEVICE_NR(WCURRENT.rq_dev)])
- sti();
do {
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
@@ -660,17 +487,6 @@
hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
return reset;
}
- if (!identified[dev]) {
- identified[dev] = 1;
- unmask_intr[dev] = DEFAULT_UNMASK_INTR;
- mult_req[dev] = DEFAULT_MULT_COUNT;
- hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
- return reset;
- }
- if (mult_req[dev] != mult_count[dev]) {
- hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
- return reset;
- }
if (hd_info[dev].head > 16) {
printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
end_request(0);
@@ -686,10 +502,8 @@
*
* Interrupts are still masked (by default) whenever we are exchanging
* data/cmds with a drive, because some drives seem to have very poor
- * tolerance for latency during I/O. For devices which don't suffer from
- * that problem (most don't), the unmask_intr[] flag can be set to unmask
- * other interrupts during data/cmd transfers (by defining DEFAULT_UNMASK_INTR
- * to 1, or by using "hdparm -u1 /dev/hd?" from the shell).
+ * tolerance for latency during I/O. The IDE driver has support to unmask
+ * interrupts for non-broken hardware, so use that driver if required.
*/
static void hd_request(void)
{
@@ -738,31 +552,21 @@
dev+'a', (CURRENT->cmd == READ)?"read":"writ",
cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
#endif
- if (!unmask_intr[dev])
- cli();
if (CURRENT->cmd == READ) {
- unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
- hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
+ hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
if (reset)
goto repeat;
return;
}
if (CURRENT->cmd == WRITE) {
- if (mult_count[dev])
- hd_out(dev,nsect,sec,head,cyl,WIN_MULTWRITE,&multwrite_intr);
- else
- hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+ hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
if (reset)
goto repeat;
if (wait_DRQ()) {
bad_rw_intr();
goto repeat;
}
- if (mult_count[dev]) {
- WCURRENT = *CURRENT;
- multwrite(dev);
- } else
- outsw(HD_DATA,CURRENT->buffer,256);
+ outsw(HD_DATA,CURRENT->buffer,256);
return;
}
panic("unknown hd-command");
@@ -780,7 +584,6 @@
{
struct hd_geometry *loc = (struct hd_geometry *) arg;
int dev, err;
- unsigned long flags;
if ((!inode) || !(inode->i_rdev))
return -EINVAL;
@@ -793,11 +596,11 @@
err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
if (err)
return err;
- put_user(bios_info[dev].head,
+ put_user(hd_info[dev].head,
(char *) &loc->heads);
- put_user(bios_info[dev].sect,
+ put_user(hd_info[dev].sect,
(char *) &loc->sectors);
- put_user(bios_info[dev].cyl,
+ put_user(hd_info[dev].cyl,
(short *) &loc->cylinders);
put_user(hd[MINOR(inode->i_rdev)].start_sect,
(long *) &loc->start);
@@ -830,57 +633,6 @@
case BLKRRPART: /* Re-read partition tables */
return revalidate_hddisk(inode->i_rdev, 1);
- case HDIO_SET_UNMASKINTR:
- if (!suser()) return -EACCES;
- if ((arg > 1) || (MINOR(inode->i_rdev) & 0x3F))
- return -EINVAL;
- unmask_intr[dev] = arg;
- return 0;
-
- case HDIO_GET_UNMASKINTR:
- if (!arg) return -EINVAL;
- err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
- if (err)
- return err;
- put_user(unmask_intr[dev], (long *) arg);
- return 0;
-
- case HDIO_GET_MULTCOUNT:
- if (!arg) return -EINVAL;
- err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
- if (err)
- return err;
- put_user(mult_count[dev], (long *) arg);
- return 0;
-
- case HDIO_SET_MULTCOUNT:
- if (!suser()) return -EACCES;
- if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
- save_flags(flags);
- cli(); /* a prior request might still be in progress */
- if (arg > max_mult[dev])
- err = -EINVAL; /* out of range for device */
- else if (mult_req[dev] != mult_count[dev]) {
- special_op[dev] = 1;
- err = -EBUSY; /* busy, try again */
- } else {
- mult_req[dev] = arg;
- special_op[dev] = 1;
- err = 0;
- }
- restore_flags(flags);
- return err;
-
- case HDIO_GET_IDENTITY:
- if (!arg) return -EINVAL;
- if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;
- if (hd_ident_info[dev] == NULL) return -ENOMSG;
- err = verify_area(VERIFY_WRITE, (char *) arg, sizeof(struct hd_driveid));
- if (err)
- return err;
- copy_to_user((char *)arg, (char *) hd_ident_info[dev], sizeof(struct hd_driveid));
- return 0;
-
RO_IOCTLS(inode->i_rdev,arg);
default:
return -EINVAL;
@@ -926,7 +678,7 @@
hd, /* hd struct */
hd_sizes, /* block sizes */
0, /* number */
- (void *) bios_info, /* internal */
+ NULL, /* internal use, not presently used */
NULL /* next */
};
@@ -953,21 +705,21 @@
*/
static void hd_geninit(struct gendisk *ignored)
{
- int i;
+ int drive;
#ifdef __i386__
if (!NR_HD) {
extern struct drive_info drive_info;
unsigned char *BIOS = (unsigned char *) &drive_info;
- int cmos_disks, drive;
+ int cmos_disks;
for (drive=0 ; drive<2 ; drive++) {
- bios_info[drive].cyl = hd_info[drive].cyl = *(unsigned short *) BIOS;
- bios_info[drive].head = hd_info[drive].head = *(2+BIOS);
- bios_info[drive].wpcom = hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
- bios_info[drive].ctl = hd_info[drive].ctl = *(8+BIOS);
- bios_info[drive].lzone = hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
- bios_info[drive].sect = hd_info[drive].sect = *(14+BIOS);
+ hd_info[drive].cyl = *(unsigned short *) BIOS;
+ hd_info[drive].head = *(2+BIOS);
+ hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+ hd_info[drive].ctl = *(8+BIOS);
+ hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+ hd_info[drive].sect = *(14+BIOS);
#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
if (hd_info[drive].cyl && NR_HD == drive)
NR_HD++;
@@ -1004,20 +756,12 @@
NR_HD = 1;
}
#endif /* __i386__ */
- i = NR_HD;
- while (i-- > 0) {
- /*
- * The newer E-IDE BIOSs handle drives larger than 1024
- * cylinders by increasing the number of logical heads
- * to keep the number of logical cylinders below the
- * sacred INT13 limit of 1024 (10 bits). If that is
- * what's happening here, we'll find out and correct
- * it later when "identifying" the drive.
- */
- hd[i<<6].nr_sects = bios_info[i].head *
- bios_info[i].sect * bios_info[i].cyl;
- hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL);
- special_op[i] = 1;
+ for (drive=0 ; drive < NR_HD ; drive++) {
+ hd[drive<<6].nr_sects = hd_info[drive].head *
+ hd_info[drive].sect * hd_info[drive].cyl;
+ printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
+ hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
+ hd_info[drive].head, hd_info[drive].sect);
}
if (NR_HD) {
if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
@@ -1030,7 +774,8 @@
}
hd_gendisk.nr_real = NR_HD;
- for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024;
+ for(drive=0; drive < (MAX_HD << 6); drive++)
+ hd_blocksizes[drive] = 1024;
blksize_size[MAJOR_NR] = hd_blocksizes;
}
@@ -1063,7 +808,7 @@
#define DEVICE_BUSY busy[target]
#define USAGE access_count[target]
-#define CAPACITY (bios_info[target].head*bios_info[target].sect*bios_info[target].cyl)
+#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
/* We assume that the the bios parameters do not change, so the disk capacity
will not change */
#undef MAYBE_REINIT
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov