[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Resend: patch for MFM and IDE phantom ST506



Apologies for the line wrapped patch. I will be faithful to emacs
from now on.

-Costa

Index: wdc.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/wdc.c,v
retrieving revision 1.20
diff -u -r1.20 wdc.c
--- wdc.c	2000/07/20 19:15:23	1.20
+++ wdc.c	2000/10/25 08:49:49
@@ -144,6 +144,9 @@
 void wdc_default_write_raw_multi_4 __P((struct channel_softc *, 
     void *, unsigned int));
 
+int wdc_floating_bus __P((struct channel_softc *, int));
+int wdc_preata_drive __P((struct channel_softc *, int));
+
 struct channel_softc_vtbl wdc_default_vtbl = {
 	wdc_default_read_reg,
 	wdc_default_write_reg,
@@ -301,7 +304,7 @@
 {
 	struct ata_atapi_attach *aa_link = aux;
 	if (pnp)
-		printf("atapibus at %s", pnp);
+		printf("atapiscsi at %s", pnp);
 	printf(" channel %d", aa_link->aa_channel);
 	return (UNCONF);
 }
@@ -344,17 +347,99 @@
 	return 0;
 }
 
+int
+wdc_floating_bus(chp, drive)
+	struct channel_softc *chp;
+	int drive;
+	
+{
+	u_int8_t cumulative_status, status;
+	int      iter;
+	
+	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4));
+	delay(10);
+
+	/* Stolen from Phoenix BIOS Drive Autotyping document */
+	cumulative_status = 0;
+	for (iter = 0; iter < 100; iter++) {
+		CHP_WRITE_REG(chp, wdr_seccnt, 0x7f);
+		delay (1);
+
+		status = CHP_READ_REG(chp, wdr_status);
+
+		/* The other bits are meaningless if BSY is set */
+		if (status & WDCS_BSY)
+			continue;
+
+		cumulative_status |= status;
+
+#define BAD_BIT_COMBO  (WDCS_DRDY | WDCS_DSC | WDCS_DRQ | WDCS_ERR)
+		if ((cumulative_status & BAD_BIT_COMBO) == BAD_BIT_COMBO)
+			return 1;
+	}
+
+	/*
+	 * Test register writability
+	 */
+	CHP_WRITE_REG(chp, wdr_cyl_lo, 0xaa);
+	CHP_WRITE_REG(chp, wdr_cyl_hi, 0x55);
+	CHP_WRITE_REG(chp, wdr_seccnt, 0xff);
+
+	if (CHP_READ_REG(chp, wdr_cyl_lo) == 0xaa &&
+	    CHP_READ_REG(chp, wdr_cyl_hi) == 0x55)
+		return 0;
+
+	CHP_WRITE_REG(chp, wdr_seccnt, 0x58);
+
+	return 1;
+}
+
+
+int
+wdc_preata_drive(chp, drive)
+	struct channel_softc *chp;
+	int drive;
+
+{
+	if (wdc_floating_bus(chp, drive)) {
+		WDCDEBUG_PRINT(("%s:%d:%d: floating bus detected\n",
+		    chp->wdc->sc_dev.dv_xname,
+		    chp->channel, drive), DEBUG_PROBE);
+		return 0;
+	}
+
+	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4));
+	delay(100);
+	if (wdcwait(chp, WDCS_DRDY | WDCS_DRQ, WDCS_DRDY, 10000) != 0) {
+		WDCDEBUG_PRINT(("%s:%d:%d: not ready\n",
+		    chp->wdc->sc_dev.dv_xname,
+		    chp->channel, drive), DEBUG_PROBE);
+		return 0;
+	}
+	
+	CHP_WRITE_REG(chp, wdr_command, WDCC_RECAL);
+	if (wdcwait(chp, WDCS_DRDY | WDCS_DRQ, WDCS_DRDY, 10000) != 0) {
+		WDCDEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n",
+		    chp->wdc->sc_dev.dv_xname,
+		    chp->channel, drive), DEBUG_PROBE);
+		return 0;
+	}
+
+	return 1;
+}
+
 
-/* Test to see controller with at last one attached drive is there.
+/* Test to see controller with at least one attached drive is there.
  * Returns a bit for each possible drive found (0x01 for drive 0,
  * 0x02 for drive 1).
  * Logic:
- * - If a status register is at 0xff, assume there is no drive here
- *   (ISA has pull-up resistors). If no drive at all -> return.
+ * - If a status register is at 0x7f, assume there is no drive here
+ *   (ISA has pull-up resistors, but bit 7 sometimes has pull-down resistor?). 
+ *   If no drive at all -> return.
  * - reset the controller, wait for it to complete (may take up to 31s !).
  *   If timeout -> return.
- * - test ATA/ATAPI signatures. If at last one drive found -> return.
- * - try an ATA command on the master.
+ * - test ATA/ATAPI signatures. Wait for ready if drive isn't ATAPI.
+ * - return drive mask.
  */
 
 int
@@ -364,6 +449,7 @@
 	u_int8_t st0, st1, sc, sn, cl, ch;
 	u_int8_t ret_value = 0x03;
 	u_int8_t drive;
+	int	i;
 
 	if (!chp->_vtbl)
 		chp->_vtbl = &wdc_default_vtbl;
@@ -390,24 +476,19 @@
 		    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
 		    chp->channel, st0, st1), DEBUG_PROBE);
 
-		if (st0 == 0xff)
+		if ((st0 & 0x7f) == 0x7f)
 			ret_value &= ~0x01;
-		if (st1 == 0xff)
+		if ((st1 & 0x7f) == 0x7f)
 			ret_value &= ~0x02;
 		if (ret_value == 0) 
 			return 0;
 	}
 
 	/* assert SRST, wait for reset to complete */
-	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM);
+	CHP_WRITE_REG(chp,wdr_ctlr, WDCTL_RST | WDCTL_4BIT); 
 	delay(10);
-	CHP_WRITE_REG(chp,wdr_ctlr, WDCTL_RST | WDCTL_IDS); 
-	DELAY(1000);
-	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS);
-	delay(1000);
-	(void) CHP_READ_REG(chp, wdr_error);
 	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT);
-	delay(10);
+	delay(2000);
 
 	ret_value = __wdcwait_reset(chp, ret_value);
 	WDCDEBUG_PRINT(("%s:%d: after reset, ret_value=0x%d\n",
@@ -420,9 +501,10 @@
 
 	/*
 	 * Test presence of drives. First test register signatures looking for
-	 * ATAPI devices. If it's not an ATAPI and reset said there may be
-	 * something here assume it's ATA or OLD. Ghost will be killed later in
-	 * attach routine.
+	 * ATA/ATAPI devices. If drive isn't ATAPI, wait for it's readiness.
+	 * Timeout -> no drive, if any, drive is ATA or OLD. Distinction
+	 * between ATA and OLD will be done later in attach routine 
+	 * by issuing an IDENTIFY command.
 	 */
 	for (drive = 0; drive < 2; drive++) {
 		if ((ret_value & (0x01 << drive)) == 0)
@@ -436,8 +518,8 @@
 		cl = CHP_READ_REG(chp, wdr_cyl_lo);
 		ch = CHP_READ_REG(chp, wdr_cyl_hi);
 
-		WDCDEBUG_PRINT(("%s:%d:%d: after reset, st=0x%x, sc=0x%x sn=0x%x "
-		    "cl=0x%x ch=0x%x\n",
+		WDCDEBUG_PRINT(("%s:%d:%d: after reset, st=0x%x, sc=0x%x"
+		    " sn=0x%x cl=0x%x ch=0x%x\n",
 		    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
 	    	    chp->channel, drive, st0, sc, sn, cl, ch), DEBUG_PROBE);
 		/*
@@ -448,6 +530,33 @@
 		if (cl == 0x14 && ch == 0xeb) {
 			chp->ch_drive[drive].drive_flags |= DRIVE_ATAPI;
 		} else {
+			/* 
+			   This code should filter out non-existant slaves of 
+			   ATA devices because their status will be 0x00.
+			 */
+
+			for(i = 0; i < 1000; i++) {
+				st0 = CHP_READ_REG(chp, wdr_status);
+				if ((st0 & WDCS_BSY) == 0 && (st0 & WDCS_DRDY) != 0) {
+					WDCDEBUG_PRINT(("%s:%d:%d: waiting for ready %d msec\n",
+					    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
+					    chp->channel, drive, i), DEBUG_PROBE);
+					break;
+				} else {
+					delay(1000);			/* 1 millisecond */
+				}
+			}
+			
+			if((st0 & WDCS_BSY) != 0 || (st0 & WDCS_DRDY) == 0) {
+				ret_value &= ~(0x01 << drive);
+				continue;
+			}
+			
+
+			/* 
+			 * here is ATA or OLD drive, we are 
+			 * distinct it in wdcattach() 
+			 */
 			chp->ch_drive[drive].drive_flags |= DRIVE_ATA;
 			if (chp->wdc == NULL ||
 			    (chp->wdc->cap & WDC_CAPABILITY_PREATA) != 0)
@@ -537,59 +646,29 @@
 		    (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) ==
 		    WDC_CAPABILITY_DATA32)
 			chp->ch_drive[i].drive_flags |= DRIVE_CAP32;
+
 		if ((chp->ch_drive[i].drive_flags & DRIVE) == 0)
 			continue;
 
 		if (i == 1 && ((chp->ch_drive[0].drive_flags & DRIVE) == 0))
 			chp->ch_flags |= WDCF_ONESLAVE;
-
-		/* Issue a IDENTIFY command, to try to detect slave ghost */
+		/*
+		 * Issue an IDENTIFY command in order to distinct ATA from OLD.
+		 * This also kill ATAPI ghost.
+		 */
 		if (ata_get_params(&chp->ch_drive[i], at_poll, &params) ==
 		    CMD_OK) {
 			/* If IDENTIFY succeded, this is not an OLD ctrl */
-			chp->ch_drive[0].drive_flags &= ~DRIVE_OLD;
-			chp->ch_drive[1].drive_flags &= ~DRIVE_OLD;
+			chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;
 		} else {
 			chp->ch_drive[i].drive_flags &=
 			    ~(DRIVE_ATA | DRIVE_ATAPI);
 			WDCDEBUG_PRINT(("%s:%d:%d: IDENTIFY failed\n",
 			    chp->wdc->sc_dev.dv_xname,
 			    chp->channel, i), DEBUG_PROBE);
-			if ((chp->ch_drive[i].drive_flags & DRIVE_OLD) == 0)
-				continue;
-			/*
-			 * Pre-ATA drive ?
-			 * Test registers writability (Error register not
-			 * writable, but cyllo is), then try an ATA command.
-			 */
-			CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (i << 4));
-			delay(10);
-			CHP_WRITE_REG(chp, wdr_features, 0x58);
-			CHP_WRITE_REG(chp, wdr_cyl_lo, 0xa5);
-			if ((CHP_READ_REG(chp, wdr_error) == 0x58) ||
-			    (CHP_READ_REG(chp, wdr_cyl_lo) != 0xa5)) {
-				WDCDEBUG_PRINT(("%s:%d:%d: register "
-				    "writability failed\n",
-				    chp->wdc->sc_dev.dv_xname,
-				    chp->channel, i), DEBUG_PROBE);
-				    chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;
-			}
-			CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (i << 4));
-			delay(100);
-			if (wait_for_ready(chp, 10000) != 0) {
-				WDCDEBUG_PRINT(("%s:%d:%d: not ready\n",
-				    chp->wdc->sc_dev.dv_xname,
-				    chp->channel, i), DEBUG_PROBE);
-				chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;
-				continue;
-			}
-			CHP_WRITE_REG(chp, wdr_command, WDCC_RECAL);
-			if (wait_for_ready(chp, 10000) != 0) {
-				WDCDEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n",
-				    chp->wdc->sc_dev.dv_xname,
-				    chp->channel, i), DEBUG_PROBE);
+
+			if (!wdc_preata_drive(chp, i))
 				chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;
-			}
 		}
 	}
 	ctrl_flags = chp->wdc->sc_dev.dv_cfdata->cf_flags;
@@ -824,13 +903,10 @@
 	if (!chp->_vtbl)
 		chp->_vtbl = &wdc_default_vtbl;
 
-	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); /* master */
-	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_RST | WDCTL_IDS);
-	delay(1000);
-	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS);
-	delay(2000);
-	(void) CHP_READ_REG(chp,wdr_error);
+	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_RST | WDCTL_4BIT);
+	delay(10);
 	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT);
+	delay(2000);
 
 	drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00;
 	drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00;
@@ -856,9 +932,6 @@
 	int timeout;
 	u_int8_t st0, st1;
 
-	/* Wait 50ms for drive firmware to settle */
-	delay(50000);
-
 	/* wait for BSY to deassert */
 	for (timeout = 0; timeout < WDCNDELAY_RST;timeout++) {
 		CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); /* master */
@@ -888,15 +961,16 @@
 		}
 		delay(WDCDELAY);
 	}
-	/* Reset timed out. Maybe it's because drv_mask was not rigth */
+	/* Reset timed out. Maybe it's because drv_mask was not right */
 	if (st0 & WDCS_BSY)
 		drv_mask &= ~0x01;
 	if (st1 & WDCS_BSY)
 		drv_mask &= ~0x02;
 end:
-	WDCDEBUG_PRINT(("%s:%d: wdcwait_reset() end, st0=0x%x, st1=0x%x\n",
+	WDCDEBUG_PRINT(("%s:%d: wdcwait_reset() end, st0=0x%x, st1=0x%x, "
+			"reset time=%d msec\n",
 	    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,
-	    st0, st1), DEBUG_PROBE);
+	    st0, st1, timeout*WDCDELAY/1000), DEBUG_PROBE);
 
 	return drv_mask;
 }