patch-2.0.34 linux/drivers/block/ide.c

Next file: linux/drivers/block/ide.h
Previous file: linux/drivers/block/ide-cd.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.33/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -272,6 +272,7 @@
  *			acknowledge media change on removable drives
  *			add work-around for BMI drives
  *			remove "LBA" from boot messages
+ * Version 5.53.1	add UDMA "CRC retry" support
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -602,6 +603,11 @@
 	unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
 	unsigned long _10_percent = chs_sects / 10;
 
+	/* very large drives (8GB+) may lie about the number of cylinders */
+	if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) {
+		id->cyls = lba_sects / (16 * 63); /* correct cyls */
+		return 1;	/* lba_capacity is our only option */
+	}
 	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
 	if ((lba_sects - chs_sects) < _10_percent)
 		return 1;	/* lba_capacity is good */
@@ -636,6 +642,7 @@
 	/* Determine capacity, and use LBA if the drive properly supports it */
 	if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
 		if (id->lba_capacity >= capacity) {
+			drive->cyl = id->lba_capacity / (drive->head * drive->sect);
 			capacity = id->lba_capacity;
 			drive->select.b.lba = 1;
 		}
@@ -1043,12 +1050,15 @@
 	} else {
 		if (drive->media == ide_disk && (stat & ERR_STAT)) {
 			/* err has different meaning on cdrom and tape */
-			if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
+					return;	/* some newer drives don't support WIN_SPECIFY */
+			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR))
+				; /* UDMA crc error -- just retry the operation */
+			else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
 				rq->errors = ERROR_MAX;
 			else if (err & TRK0_ERR)	/* help it find track zero */
 				rq->errors |= ERROR_RECAL;
-			else if (err & MC_ERR)
-				drive->special.b.mc = 1;
 		}
 		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
 			try_to_flush_leftover_data(drive);
@@ -2270,7 +2280,7 @@
 		{
 			byte args[4], *argbuf = args;
 			int argsize = 4;
-			if (!suser()) return -EACCES;
+			if (!suser() || securelevel > 0) return -EACCES;
 			if (NULL == (void *) arg) {
 				err = ide_do_drive_cmd(drive, &rq, ide_wait);
 			} else if (!(err = verify_area(VERIFY_READ,(void *)arg, 4))) {
@@ -2561,14 +2571,16 @@
 		drive->head = id->heads;
 		drive->sect = id->sectors;
 	}
+
+	/* calculate drive capacity, and select LBA if possible */
+	(void) current_capacity (drive);
+
 	/* Correct the number of cyls if the bios value is too small */
 	if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) {
 		if (drive->cyl > drive->bios_cyl)
 			drive->bios_cyl = drive->cyl;
 	}
 
-	(void) current_capacity (drive); /* initialize LBA selection */
-
 	if (!strncmp(id->model, "BMI ", 4) &&
 	    strstr(id->model, " ENHANCED IDE ") &&
 	    drive->select.b.lba)
@@ -2587,8 +2599,12 @@
 			drive->special.b.set_multmode = 1;
 	}
 	if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
-		if (!(HWIF(drive)->dmaproc(ide_dma_check, drive)))
-			printk(", DMA");
+		if (!(HWIF(drive)->dmaproc(ide_dma_check, drive))) {
+			if ((id->field_valid & 4) && (id->dma_ultra & (id->dma_ultra >> 8) & 7))
+				printk(", UDMA");
+			else
+				printk(", DMA");
+		}
 	}
 	printk("\n");
 }
@@ -2618,11 +2634,12 @@
 {
 	int hd_status, rc;
 	unsigned long timeout;
-	int irqs = 0;
+	unsigned long irqs_on = 0;
+	int irq_off;
 
 	if (!HWIF(drive)->irq) {		/* already got an IRQ? */
 		probe_irq_off(probe_irq_on());	/* clear dangling irqs */
-		irqs = probe_irq_on();		/* start monitoring irqs */
+		irqs_on = probe_irq_on();	/* start monitoring irqs */
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
 	}
 
@@ -2636,8 +2653,8 @@
 #if CONFIG_BLK_DEV_PROMISE
 	if (IS_PROMISE_DRIVE) {
 		if (promise_cmd(drive,PROMISE_IDENTIFY)) {
-			if (irqs)
-				(void) probe_irq_off(irqs);
+			if (irqs_on)
+				(void) probe_irq_off(irqs_on);
 			return 1;
 		}
 	} else
@@ -2647,8 +2664,8 @@
 	timeout += jiffies;
 	do {
 		if (jiffies > timeout) {
-			if (irqs)
-				(void) probe_irq_off(irqs);
+			if (irqs_on)
+				(void) probe_irq_off(irqs_on);
 			return 1;	/* drive timed-out */
 		}
 		delay_50ms();		/* give drive a breather */
@@ -2666,18 +2683,18 @@
 	} else
 		rc = 2;			/* drive refused ID */
 	if (!HWIF(drive)->irq) {
-		irqs = probe_irq_off(irqs);	/* get our irq number */
-		if (irqs > 0) {
-			HWIF(drive)->irq = irqs; /* save it for later */
-			irqs = probe_irq_on();
+		irq_off = probe_irq_off(irqs_on);	/* get our irq number */
+		if (irq_off > 0) {
+			HWIF(drive)->irq = irq_off; /* save it for later */
+			irqs_on = probe_irq_on();
 			OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
 			udelay(5);
-			(void) probe_irq_off(irqs);
+			(void) probe_irq_off(irqs_on);
 			(void) probe_irq_off(probe_irq_on()); /* clear self-inflicted irq */
 			(void) GET_STAT();	/* clear drive IRQ */
 
 		} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
-			printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
+			printk("%s: IRQ probe failed (%d)\n", drive->name, irq_off);
 #ifdef CONFIG_BLK_DEV_CMD640
 #ifdef CMD640_DUMP_REGS
 			if (HWIF(drive)->chipset == ide_cmd640) {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov