linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andre Hedrick <andre@linux-ide.org>
To: linux-kernel@vger.kernel.org
Cc: Martin Dalecki <dalecki@evision-ventures.com>
Subject: [PATCH] linux-2.5.7.fix2.patch
Date: Sat, 23 Mar 2002 14:53:58 -0800 (PST)	[thread overview]
Message-ID: <Pine.LNX.4.10.10203231441530.1053-200000@master.linux-ide.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 1137 bytes --]


Martin et al.

This is the next step in stablizing the transport layer.
I have not booted but it will compile, and it is nearly identical to what
I generated for 2.4 to be released soon.

The comments are harsh on the interface but it functionally correct.
If you get an device error in PIO, bad things can happen to the data.
This is no different in the stock 2.4.0->2.4.18->19x.

Of of all the transport data handlers.

CLEAN and SAFE:
	DMA read/write is safe and has always been.
	Single sector PIO WRITING is clean and safe.

DIRTY but operational (error events in the hardware will cause data problems) 
	Single sector PIO READING can corrupt a single sector if there
		is a device error.
	Multi-Read/Write will corrupt and misreport data only on an error.

What is still lacking in block is the much needed in proccess bio walker.
Once I can finish coding this fix into BLOCK, then I can complete the
transport layer and slap it on a bus analyzer and force articial errors on
the buss to see if the driver behaves correctly.  If this passes, we are
good to run like the wind.

Regards,

Andre Hedrick
LAD Storage Consulting Group

[-- Attachment #2: Type: text/plain, Size: 33460 bytes --]

diff -urN linux-2.5.7/drivers/ide/hpt34x.c linux-2.5.7.fix/drivers/ide/hpt34x.c
--- linux-2.5.7/drivers/ide/hpt34x.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/hpt34x.c	Fri Mar 22 21:47:09 2002
@@ -334,6 +334,8 @@
 			drive->waiting_for_dma = 1;
 			if (drive->type != ATA_DISK)
 				return 0;
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
 			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			return 0;
diff -urN linux-2.5.7/drivers/ide/icside.c linux-2.5.7.fix/drivers/ide/icside.c
--- linux-2.5.7/drivers/ide/icside.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/icside.c	Fri Mar 22 21:47:41 2002
@@ -444,6 +444,9 @@
 		if (drive->media != ide_disk)
 			return 0;
 
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
+
 		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
 		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
 			 IDE_COMMAND_REG);
diff -urN linux-2.5.7/drivers/ide/ide-cd.c linux-2.5.7.fix/drivers/ide/ide-cd.c
--- linux-2.5.7/drivers/ide/ide-cd.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/ide-cd.c	Fri Mar 22 21:50:58 2002
@@ -745,6 +745,9 @@
 		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
 		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
 		return ide_started;
@@ -786,6 +789,9 @@
 			return startstop;
 	}
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
 	/* Arm the interrupt handler. */
 	ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
 
@@ -1005,6 +1011,9 @@
 
 	/* Done moving data!
 	   Wait for another interrupt. */
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
@@ -1335,6 +1344,9 @@
 	}
 
 	/* Now we wait for another interrupt. */
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 	return ide_started;
 }
@@ -1559,6 +1571,9 @@
 	}
 
 	/* re-arm handler */
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
 	return ide_started;
 }
diff -urN linux-2.5.7/drivers/ide/ide-dma.c linux-2.5.7.fix/drivers/ide/ide-dma.c
--- linux-2.5.7/drivers/ide/ide-dma.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/ide-dma.c	Fri Mar 22 21:51:28 2002
@@ -588,6 +588,9 @@
 			drive->waiting_for_dma = 1;
 			if (drive->type != ATA_DISK)
 				return 0;
+
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
 			if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
 			    (drive->addressing == 1)) {
diff -urN linux-2.5.7/drivers/ide/ide-floppy.c linux-2.5.7.fix/drivers/ide/ide-floppy.c
--- linux-2.5.7/drivers/ide/ide-floppy.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/ide-floppy.c	Fri Mar 22 21:54:53 2002
@@ -968,6 +968,9 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
 				idefloppy_discard_data (drive,bcount.all);
+
+				if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+					BUG();
 				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
 				return ide_started;
 			}
@@ -990,6 +993,8 @@
 	pc->actually_transferred+=bcount.all;				/* Update the current position */
 	pc->current_position+=bcount.all;
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
 	return ide_started;
 }
@@ -1014,6 +1019,8 @@
 		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
 		return ide_stopped;
 	}
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
 	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
 	return ide_started;
@@ -1062,9 +1069,13 @@
 	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
 	 * not be actually used until after the packet is moved in about 50 msec.
 	 */
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
 	ide_set_handler (drive, 
 	  &idefloppy_pc_intr, 		/* service routine for packet command */
-	  floppy->ticks,			/* wait this long before "failing" */
+	  floppy->ticks,		/* wait this long before "failing" */
 	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
 	return ide_started;
 }
@@ -1145,6 +1156,9 @@
 	}
 	
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
 		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 		return ide_started;
diff -urN linux-2.5.7/drivers/ide/ide-pmac.c linux-2.5.7.fix/drivers/ide/ide-pmac.c
--- linux-2.5.7/drivers/ide/ide-pmac.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/ide-pmac.c	Fri Mar 22 21:55:20 2002
@@ -993,6 +993,8 @@
 		drive->waiting_for_dma = 1;
 		if (drive->media != ide_disk)
 			return 0;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
 		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
 		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
 			 IDE_COMMAND_REG);
diff -urN linux-2.5.7/drivers/ide/ide-tape.c linux-2.5.7.fix/drivers/ide/ide-tape.c
--- linux-2.5.7/drivers/ide/ide-tape.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/ide-tape.c	Fri Mar 22 21:57:56 2002
@@ -2155,6 +2155,9 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
 				idetape_discard_data (drive, bcount.all);
+				if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+					BUG();
+
 				ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 				return ide_started;
 			}
@@ -2181,6 +2184,9 @@
 	if (tape->debug_level >= 2)
 		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
 #endif
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
 	return ide_started;
 }
@@ -2255,6 +2261,8 @@
 		return ide_stopped;
 	}
 	tape->cmd_start_time = jiffies;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
 	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
 	return ide_started;
@@ -2328,6 +2336,9 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
 		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
diff -urN linux-2.5.7/drivers/ide/ide-taskfile.c linux-2.5.7.fix/drivers/ide/ide-taskfile.c
--- linux-2.5.7/drivers/ide/ide-taskfile.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/ide-taskfile.c	Sat Mar 23 02:48:14 2002
@@ -1,8 +1,27 @@
 /*
- *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ * linux/drivers/ide/ide-taskfile.c     Version 0.30    Mar 23, 2002
  *
- *  May be copied or modified under the terms of the GNU General Public License
+ *  Copyright (C) 2000-2002	Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *
+ *  The big the bad and the ugly.
+ *
+ *  Problems to be fixed because of BIO interface or the lack therefore.
+ *
+ *  Fill me in stupid !!!
+ *
+ *  HOST:
+ *	General refers to the Controller and Driver "pair".
+ *  DATA HANDLER:
+ *	Under the context of Linux it generally refers to an interrupt handler.
+ *	However, it correctly describes the 'HOST'
+ *  DATA BLOCK:
+ *	The amount of data needed to be transfered as predefined in the
+ *	setup of the device.
+ *  STORAGE ATOMIC:
+ *	The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
+ *	small as a single sector or as large as the entire command block
+ *	request.
  */
 
 #include <linux/config.h>
@@ -33,7 +52,7 @@
 #define DEBUG_TASKFILE	0	/* unset when fixed */
 
 #if DEBUG_TASKFILE
-#define DTF(x...) printk(##x)
+#define DTF(x...) printk(x)
 #else
 #define DTF(x...)
 #endif
@@ -55,7 +74,7 @@
 				unsigned long *flags)
 {
 	if (rq->bio)
-	    bio_kunmap_irq(to, flags);
+		bio_kunmap_irq(to, flags);
 }
 
 static void bswap_data (void *buffer, int wcount)
@@ -288,42 +307,52 @@
 			break;
 	}
 }
-static ide_startstop_t bio_mulout_intr(ide_drive_t *drive);
 
 /*
+ * FIXME before 2.6 ... DATA integrity issue upon error.
+ */
+/*
  * Handler for command write multiple
  * Called directly from execute_drive_cmd for the first bunch of sectors,
  * afterwards only by the ISR
  */
 static ide_startstop_t task_mulout_intr(ide_drive_t *drive)
 {
-	unsigned int		msect, nsect;
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= HWGROUP(drive)->rq;
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	char *pBuf		= NULL;
+	byte stat			= GET_STAT();
+	byte io_32bit			= drive->io_32bit;
+	struct request *rq		= HWGROUP(drive)->rq;
+	ide_hwgroup_t *hwgroup		= HWGROUP(drive);
+	char *pBuf			= NULL;
+	ide_startstop_t startstop	= ide_stopped;
+	unsigned int msect		= drive->mult_count;
+	unsigned int nsect;
 	unsigned long flags;
 
+/*
+ *	held here as a referrence to the past.
+ *	__ide_end_request(drive, 1, rq->hard_nr_sectors);
+ */
 	/*
 	 * (ks/hs): Handle last IRQ on multi-sector transfer,
 	 * occurs after all data was sent in this chunk
 	 */
 	if (rq->current_nr_sectors == 0) {
-		if (stat & (ERR_STAT|DRQ_STAT))
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			printk("%s: MULTI-WRITE assume all data transfered " \
+				"is bad status=0x%02x\n",
+				drive->name, stat);
 			return ide_error(drive, "task_mulout_intr", stat);
-
-		/*
-		 * there may be more, ide_do_request will restart it if
-		 * necessary
-		 */
-		ide_end_request(drive, 1);
-
-		return ide_stopped;
+		}
+		if (!rq->bio)
+			ide_end_request(drive, 1);
+		return startstop;
 	}
 
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
+			printk("%s: MULTI-WRITE assume all data transfered " \
+				"is bad status=0x%02x\n",
+				drive->name, stat);
 			return ide_error(drive, "task_mulout_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
@@ -332,22 +361,41 @@
 		return ide_started;
 	}
 
-	/* (ks/hs): See task_mulin_intr */
-	msect = drive->mult_count;
-	nsect = rq->current_nr_sectors;
-	if (nsect > msect)
-		nsect = msect;
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long lflags;
+		spin_lock_irqsave(&ide_lock, lflags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&ide_lock, lflags);
+	}
 
-	pBuf = ide_map_rq(rq, &flags);
-	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-		pBuf, nsect, rq->current_nr_sectors);
-	drive->io_32bit = 0;
-	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-	ide_unmap_rq(rq, pBuf, &flags);
-	drive->io_32bit = io_32bit;
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = ide_map_rq(rq, &flags);
+		DTF("Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+		drive->io_32bit = 0;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		ide_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		drive->io_32bit = io_32bit;
+		/*
+		 * FIXME :: We really can not legally get a new page/bio
+		 * regardless, if this is the end of our segment.
+		 * BIO walking or segment can only be updated after we
+		 * have a good  GET_STAT(); return.
+		 */
+		if (!rq->current_nr_sectors) {
+			if (!ide_end_request(drive, 1))
+				if (!rq->bio)
+					return ide_stopped;
+		}
+	} while (msect);
 	rq->errors = 0;
-	/* Are we sure that this as all been already transfered? */
-	rq->current_nr_sectors -= nsect;
 	if (hwgroup->handler == NULL)
 		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
 	return ide_started;
@@ -361,11 +409,10 @@
 	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
 
 	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (task->handler != task_mulout_intr && task->handler != bio_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
 
 	if ((id->command_set_2 & 0x0400) &&
 	    (id->cfs_enable_2 & 0x0400) &&
@@ -389,11 +436,6 @@
 	if (task->handler != NULL) {
 		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
 		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-		/*
-		 * Warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
-		 * inside the boundaries of the seek, we should be okay.
-		 */
 		if (task->prehandler != NULL) {
 			return task->prehandler(drive, task->rq);
 		}
@@ -405,7 +447,12 @@
 	return ide_started;
 }
 
-void do_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile,
+/*
+ * FIXME :: Need to merge all taskfile requests regardless of caller
+ *	to the above do_rw_taskfile.
+ */
+void do_taskfile(ide_drive_t *drive,
+		struct hd_drive_task_hdr *taskfile,
 		struct hd_drive_hob_hdr *hobfile,
 		ide_handler_t *handler)
 {
@@ -413,11 +460,10 @@
 	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
 
 	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (*handler != task_mulout_intr && handler != bio_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG)
+		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
+	SELECT_MASK(HWIF(drive), drive, 0);
 
 	if ((id->command_set_2 & 0x0400) &&
 	    (id->cfs_enable_2 & 0x0400) &&
@@ -477,6 +523,8 @@
 	if (stat & (ERR_STAT|DRQ_STAT))
 		return ide_error(drive, "set_geometry_intr", stat);
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
@@ -513,7 +561,10 @@
 }
 
 /*
- * Handler for command with PIO data-in phase
+ * Handler for command with PIO data-in phase, READ
+ */
+/*
+ * FIXME before 2.6 ... DATA integrity issue upon error. <andre@linux-ide.org>
  */
 static ide_startstop_t task_in_intr (ide_drive_t *drive)
 {
@@ -525,65 +576,80 @@
 
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
+#if 0
+			DTF("%s: READ attempting to recover last " \
+				"sector counter status=0x%02x\n",
+				drive->name, stat);
+		/*
+		 * Expect a BUG BOMB if we attempt to rewind the
+		 * offset in the BIO aka PAGE in the current BLOCK
+		 * segment.  This is different than the HOST segment.
+		 */
+
+			rq->current_nr_sectors++;
+#endif
 			return ide_error(drive, "task_in_intr", stat);
 		}
 		if (!(stat & BUSY_STAT)) {
 			DTF("task_in_intr to Soon wait for next interrupt\n");
-			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			if (HWGROUP(drive)->handler == NULL)
+				ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
 			return ide_started;
 		}
 	}
-	DTF("stat: %02x\n", stat);
 	pBuf = ide_map_rq(rq, &flags);
-	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
-
+	DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n",
+		pBuf, (int) rq->current_nr_sectors, stat);
 	drive->io_32bit = 0;
 	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
 	ide_unmap_rq(rq, pBuf, &flags);
 	drive->io_32bit = io_32bit;
-
-	if (--rq->current_nr_sectors <= 0) {
-		/* (hs): swapped next 2 lines */
-		DTF("Request Ended stat: %02x\n", GET_STAT());
-		if (ide_end_request(drive, 1)) {
-			ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
-			return ide_started;
-		}
-	} else {
+	/*
+	 * FIXME :: We really can not legally get a new page/bio
+	 * regardless, if this is the end of our segment.
+	 * BIO walking or segment can only be updated after we have a good
+	 * GET_STAT(); return.
+	 */
+	if (--rq->current_nr_sectors <= 0)
+		if (!ide_end_request(drive, 1))
+			return ide_stopped;
+	if (HWGROUP(drive)->handler == NULL)
 		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
-		return ide_started;
-	}
-	return ide_stopped;
+	return ide_started;
 }
 
+/*
+ * VERIFY ME before 2.6 ... unexpected race is possible based on details
+ * RMK with 74LS245/373/374 TTL buffer logic because of passthrough.
+ */
 static ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 {
-	ide_task_t *args = rq->special;
+	char *pBuf		= NULL;
+	unsigned long flags;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-		printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+			drive->name,
+			drive->addressing ? "WRITE_EXT" : "WRITE");
 		return startstop;
 	}
-
-	/* (ks/hs): Fixed Multi Write */
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
-	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
-		unsigned long flags;
-		char *buf = ide_map_rq(rq, &flags);
-		/* For Write_sectors we need to stuff the first sector */
-		taskfile_output_data(drive, buf, SECTOR_WORDS);
-		rq->current_nr_sectors--;
-		ide_unmap_rq(rq, buf, &flags);
-	} else {
-		ata_poll_drive_ready(drive);
-		return args->handler(drive);
-	}
+	/* For Write_sectors we need to stuff the first sector */
+	pBuf = ide_map_rq(rq, &flags);
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	/*
+	 * WARNING :: Interrupt could happen instantly :-/
+	 */
+	rq->current_nr_sectors--;
+	ide_unmap_rq(rq, pBuf, &flags);
 	return ide_started;
 }
 
 /*
- * Handler for command with PIO data-out phase
+ * Handler for command with PIO data-out phase WRITE
+ *
+ * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org>
  */
 static ide_startstop_t task_out_intr(ide_drive_t *drive)
 {
@@ -593,17 +659,25 @@
 	char *pBuf		= NULL;
 	unsigned long flags;
 
-	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat))
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		DTF("%s: WRITE attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
 		return ide_error(drive, "task_out_intr", stat);
-
+	}
+	/*
+	 * Safe to update request for partial completions.
+	 * We have a good STATUS CHECK!!!
+	 */
 	if (!rq->current_nr_sectors)
 		if (!ide_end_request(drive, 1))
 			return ide_stopped;
-
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
 		rq = HWGROUP(drive)->rq;
 		pBuf = ide_map_rq(rq, &flags);
-		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
+		DTF("write: %p, rq->current_nr_sectors: %d\n",
+			pBuf, (int) rq->current_nr_sectors);
 		drive->io_32bit = 0;
 		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
 		ide_unmap_rq(rq, pBuf, &flags);
@@ -611,145 +685,73 @@
 		rq->errors = 0;
 		rq->current_nr_sectors--;
 	}
-
-	ide_set_handler(drive, task_out_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
 
-static ide_startstop_t pre_bio_out_intr(ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_task_mulout_intr(ide_drive_t *drive, struct request *rq)
 {
 	ide_task_t *args = rq->special;
 	ide_startstop_t startstop;
 
-	/*
-	 * assign private copy for multi-write
-	 */
-	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
-
-	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+			drive->name,
+			drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE");
 		return startstop;
-
+	}
+#if 0
+	if (wait_for_ready(drive, 100))
+		BUG();
+#else
 	ata_poll_drive_ready(drive);
-	return args->handler(drive);
-}
-
-
-static ide_startstop_t bio_mulout_intr (ide_drive_t *drive)
-{
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= &HWGROUP(drive)->wrq;
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	int mcount		= drive->mult_count;
-	ide_startstop_t startstop;
-
+#endif
 	/*
-	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent in this chunk
+	 * WARNING :: if the drive as not acked good status we may not
+	 * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org>
 	 */
-	if (!rq->nr_sectors) {
-		if (stat & (ERR_STAT|DRQ_STAT)) {
-			startstop = ide_error(drive, "bio_mulout_intr", stat);
-			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
-			return startstop;
-		}
-
-		__ide_end_request(drive, 1, rq->hard_nr_sectors);
-		HWGROUP(drive)->wrq.bio = NULL;
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
-		if (stat & (ERR_STAT | DRQ_STAT)) {
-			startstop = ide_error(drive, "bio_mulout_intr", stat);
-			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
-			return startstop;
-		}
-
-		/* no data yet, so wait for another interrupt */
-		if (hwgroup->handler == NULL)
-			ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
-
-		return ide_started;
-	}
-
-	do {
-		char *buffer;
-		int nsect = rq->current_nr_sectors;
-		unsigned long flags;
-
-		if (nsect > mcount)
-			nsect = mcount;
-		mcount -= nsect;
-
-		buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
-		rq->sector += nsect;
-		rq->nr_sectors -= nsect;
-		rq->current_nr_sectors -= nsect;
-
-		/* Do we move to the next bio after this? */
-		if (!rq->current_nr_sectors) {
-			/* remember to fix this up /jens */
-			struct bio *bio = rq->bio->bi_next;
-
-			/* end early early we ran out of requests */
-			if (!bio) {
-				mcount = 0;
-			} else {
-				rq->bio = bio;
-				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
-			}
-		}
-
-		/*
-		 * Ok, we're all setup for the interrupt
-		 * re-entering us on the last transfer.
-		 */
-		taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
-		bio_kunmap_irq(buffer, &flags);
-	} while (mcount);
-
-	drive->io_32bit = io_32bit;
-	rq->errors = 0;
-	if (hwgroup->handler == NULL)
-		ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
-
-	return ide_started;
+	return args->handler(drive);
 }
 
 /*
  * Handler for command with Read Multiple
  */
+/*
+ * FIXME before 2.6 ... DATA integrity issue upon error. <andre@linux-ide.org>
+ */
 static ide_startstop_t task_mulin_intr(ide_drive_t *drive)
 {
-	unsigned int		msect, nsect;
 	byte stat		= GET_STAT();
 	byte io_32bit		= drive->io_32bit;
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned int msect	= drive->mult_count;
+	unsigned int nsect;
 	unsigned long flags;
 
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
+			printk("%s: MULTI-READ assume all data transfered " \
+				"is bad status=0x%02x\n",
+				drive->name, stat);
 			return ide_error(drive, "task_mulin_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
 
-	/* (ks/hs): Fixed Multi-Sector transfer */
-	msect = drive->mult_count;
-
 	do {
 		nsect = rq->current_nr_sectors;
 		if (nsect > msect)
 			nsect = msect;
-
 		pBuf = ide_map_rq(rq, &flags);
-
-		DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-			pBuf, nsect, rq->current_nr_sectors);
+		DTF("Multiread: %p, nsect: %d, msect: %d, " \
+			" rq->current_nr_sectors: %d\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
 		drive->io_32bit = 0;
 		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
 		ide_unmap_rq(rq, pBuf, &flags);
@@ -762,12 +764,8 @@
 				return ide_stopped;
 		}
 	} while (msect);
-
-
-	/*
-	 * more data left
-	 */
-	ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
 
@@ -778,6 +776,9 @@
 
 	args->prehandler = NULL;
 	args->handler = NULL;
+#if 0
+	args->posthandler = NULL; /* put this back in or BUGS will happen */
+#endif
 
 	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
 		case WIN_IDENTIFY:
@@ -814,8 +815,8 @@
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
-			args->prehandler = pre_bio_out_intr;
-			args->handler = bio_mulout_intr;
+			args->prehandler = pre_task_mulout_intr;
+			args->handler = task_mulout_intr;
 			args->command_type = IDE_DRIVE_TASK_RAW_WRITE;
 			return;
 
@@ -1063,6 +1064,9 @@
  *
  * The caller has to make sure buf is never NULL!
  */
+/*
+ * FIXME before 2.6, this needs to map into at taskfile. <andre@linux-ide.org>
+ */
 static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *argbuf)
 {
 	struct request rq;
@@ -1080,6 +1084,9 @@
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
+/*
+ * FIXME before 2.6, this needs to map into at taskfile. <andre@linux-ide.org>
+ */
 int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int err = 0;
@@ -1133,6 +1140,9 @@
 	return err;
 }
 
+/*
+ * FIXME before 2.6, this needs to map into at taskfile. <andre@linux-ide.org>
+ */
 int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int err = 0;
diff -urN linux-2.5.7/drivers/ide/ide.c linux-2.5.7.fix/drivers/ide/ide.c
--- linux-2.5.7/drivers/ide/ide.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/ide.c	Sat Mar 23 01:22:41 2002
@@ -549,6 +549,8 @@
 		printk("%s: ATAPI reset complete\n", drive->name);
 	} else {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
 			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
 			return ide_started;	/* continue polling */
 		}
@@ -574,6 +576,8 @@
 
 	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
 		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
 			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
 			return ide_started;	/* continue polling */
 		}
@@ -645,6 +649,8 @@
 		udelay (20);
 		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
 		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
 		__restore_flags (flags);	/* local CPU only */
 		return ide_started;
@@ -679,6 +685,8 @@
 	}
 	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
 
 	/*
@@ -933,6 +941,9 @@
  */
 void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
 {
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
 	ide_set_handler (drive, handler, WAIT_CMD, NULL);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
diff -urN linux-2.5.7/drivers/ide/pdc4030.c linux-2.5.7.fix/drivers/ide/pdc4030.c
--- linux-2.5.7/drivers/ide/pdc4030.c	Fri Mar 22 02:58:00 2002
+++ linux-2.5.7.fix/drivers/ide/pdc4030.c	Sat Mar 23 01:28:41 2002
@@ -394,6 +394,9 @@
 
 	if (GET_STAT() & BUSY_STAT) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
+
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
 			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 			return ide_started; /* continue polling... */
 		}
@@ -476,6 +479,7 @@
 
 	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */				BUG();
 			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
 			return ide_started; /* continue polling... */
 		}
@@ -489,6 +493,8 @@
 	 */
 	promise_multwrite(drive, 4);
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
 	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
@@ -523,6 +529,8 @@
 		if (promise_multwrite(drive, rq->nr_sectors - 4))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
 		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
 		return ide_started;
 	} else {
@@ -533,6 +541,8 @@
 		if (promise_multwrite(drive, rq->nr_sectors))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+			BUG();
 		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
@@ -554,6 +564,13 @@
 	unsigned long timeout;
 	byte stat;
 
+	/* Check that it's a regular command. If not, bomb out early. */
+	if (!(rq->flags & REQ_CMD)) {
+		blk_dump_rq_flags(rq, "pdc4030 bad flags");
+		ide_end_request(drive, 0);
+		return ide_stopped;
+	}
+
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
 	SELECT_MASK(HWIF(drive), drive, 0);
@@ -568,16 +585,8 @@
 	OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
 	OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
 
-/* Check that it's a regular command. If not, bomb out early. */
-	if (!(rq->flags & REQ_CMD)) {
-		blk_dump_rq_flags(rq, "pdc4030 bad flags");
-		ide_end_request(drive, 0);
-		return ide_stopped;
-	}
-
 	switch (rq_data_dir(rq)) {
 	case READ:
-		OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
 /*
  * The card's behaviour is odd at this point. If the data is
  * available, DRQ will be true, and no interrupt will be
@@ -600,6 +609,8 @@
 				printk(KERN_DEBUG "%s: read: waiting for "
 				                  "interrupt\n", drive->name);
 #endif
+				if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+					BUG();
 				ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
 				return ide_started;
 			}
@@ -612,7 +623,6 @@
 
 	case WRITE: {
 		ide_startstop_t startstop;
-		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
 /*
  * Strategy on write is:
  *	look for the DRQ that should have been immediately asserted
diff -urN linux-2.5.7/drivers/ide/trm290.c linux-2.5.7.fix/drivers/ide/trm290.c
--- linux-2.5.7/drivers/ide/trm290.c	Thu Mar  7 18:18:16 2002
+++ linux-2.5.7.fix/drivers/ide/trm290.c	Sat Mar 23 01:29:29 2002
@@ -194,6 +194,8 @@
 			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
 			if (drive->type != ATA_DISK)
 				return 0;
+			if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+				BUG();
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
 			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			return 0;

             reply	other threads:[~2002-03-23 22:54 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-03-23 22:53 Andre Hedrick [this message]
     [not found] <Pine.LNX.4.10.10203231441530.1053-200000@master.linux-ide. org>
2002-03-27 15:46 ` [PATCH] linux-2.5.7.fix2.patch Anton Altaparmakov
2002-03-27 16:40   ` Martin Dalecki
2002-03-27 20:06   ` Andre Hedrick

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.10.10203231441530.1053-200000@master.linux-ide.org \
    --to=andre@linux-ide.org \
    --cc=dalecki@evision-ventures.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).