Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 8 Aug 2009 13:14:45 GMT
From:      Alexander Motin <mav@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 167102 for review
Message-ID:  <200908081314.n78DEjnt021950@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=167102

Change 167102 by mav@mav_mavbook on 2009/08/08 13:13:58

	Add PIO mode support for DMA incapable devices.

Affected files ...

.. //depot/projects/scottl-camlock/src/sys/cam/ata/ata_da.c#23 edit

Differences ...

==== //depot/projects/scottl-camlock/src/sys/cam/ata/ata_da.c#23 (text+ko) ====

@@ -63,7 +63,8 @@
 #define ATA_MAX_28BIT_LBA               268435455UL
 
 typedef enum {
-	ADA_STATE_NORMAL
+	ADA_STATE_NORMAL,
+	ADA_STATE_SET_MULTI
 } ada_state;
 
 typedef enum {
@@ -71,6 +72,7 @@
 	ADA_FLAG_CAN_48BIT	= 0x002,
 	ADA_FLAG_CAN_FLUSHCACHE	= 0x004,
 	ADA_FLAG_CAN_NCQ	= 0x008,
+	ADA_FLAG_CAN_DMA	= 0x010,
 	ADA_FLAG_NEED_OTAG	= 0x020,
 	ADA_FLAG_WENT_IDLE	= 0x040,
 	ADA_FLAG_RETRY_UA	= 0x080,
@@ -83,8 +85,7 @@
 } ada_quirks;
 
 typedef enum {
-	ADA_CCB_PROBE		= 0x01,
-	ADA_CCB_PROBE2		= 0x02,
+	ADA_CCB_SET_MULTI	= 0x01,
 	ADA_CCB_BUFFER_IO	= 0x03,
 	ADA_CCB_WAITING		= 0x04,
 	ADA_CCB_DUMP		= 0x05,
@@ -113,6 +114,7 @@
 	ada_quirks quirks;
 	int	 ordered_tag_count;
 	int	 outstanding_cmds;
+	int	 secsperint;
 	struct	 disk_params params;
 	struct	 disk *disk;
 	union	 ccb saved_ccb;
@@ -565,6 +567,12 @@
 
 		softc = (struct ada_softc *)periph->softc;
 		/*
+		 * Restore device configuration.
+		 */
+		softc->state = ADA_STATE_SET_MULTI;
+		(void)cam_periph_hold(periph, PRIBIO);
+		xpt_schedule(periph, CAM_PRIORITY_DEV);
+		/*
 		 * Don't fail on the expected unit attention
 		 * that will occur.
 		 */
@@ -640,9 +648,10 @@
 	}
 
 	LIST_INIT(&softc->pending_ccbs);
-	softc->state = ADA_STATE_NORMAL;
 	bioq_init(&softc->bio_queue);
 
+	if (cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA)
+		softc->flags |= ADA_FLAG_CAN_DMA;
 	if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48)
 		softc->flags |= ADA_FLAG_CAN_48BIT;
 	if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE)
@@ -650,6 +659,8 @@
 	if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ &&
 	    cgd->ident_data.queue >= 31)
 		softc->flags |= ADA_FLAG_CAN_NCQ;
+	softc->secsperint = max(1, min(cgd->ident_data.sectors_intr, 16));
+	softc->state = ADA_STATE_SET_MULTI;
 
 	periph->softc = softc;
 
@@ -695,9 +706,9 @@
 	else if (maxio > MAXPHYS)
 		maxio = MAXPHYS;	/* for safety */
 	if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48)
-		maxio = min(maxio, 65535 * 512);
+		maxio = min(maxio, 65536 * 512);
 	else					/* 28bit ATA command limit */
-		maxio = min(maxio, 255 * 512);
+		maxio = min(maxio, 256 * 512);
 	softc->disk->d_maxsize = maxio;
 	softc->disk->d_unit = periph->unit_number;
 	softc->disk->d_flags = 0;
@@ -744,8 +755,8 @@
 	 * to finish the probe.  The reference will be dropped in adadone at
 	 * the end of probe.
 	 */
-//	(void)cam_periph_hold(periph, PRIBIO);
-//	xpt_schedule(periph, CAM_PRIORITY_DEV);
+	(void)cam_periph_hold(periph, PRIBIO);
+	xpt_schedule(periph, CAM_PRIORITY_DEV);
 
 	/*
 	 * Schedule a periodic event to occasionally send an
@@ -762,9 +773,8 @@
 static void
 adastart(struct cam_periph *periph, union ccb *start_ccb)
 {
-	struct ada_softc *softc;
-
-	softc = (struct ada_softc *)periph->softc;
+	struct ada_softc *softc = (struct ada_softc *)periph->softc;
+	struct ccb_ataio *ataio = &start_ccb->ataio;
 
 	switch (softc->state) {
 	case ADA_STATE_NORMAL:
@@ -787,7 +797,6 @@
 		} else if (bp == NULL) {
 			xpt_release_ccb(start_ccb);
 		} else {
-			struct ccb_ataio *ataio = &start_ccb->ataio;
 			u_int8_t tag_code;
 
 			bioq_remove(&softc->bio_queue, bp);
@@ -826,21 +835,43 @@
 					}
 				} else if ((softc->flags & ADA_FLAG_CAN_48BIT) &&
 				    (lba + count >= ATA_MAX_28BIT_LBA ||
-				    count >= 256)) {
-					if (bp->bio_cmd == BIO_READ) {
-						ata_48bit_cmd(ataio, ATA_READ_DMA48,
-						    0, lba, count);
+				    count > 256)) {
+					if (softc->flags & ADA_FLAG_CAN_DMA) {
+						if (bp->bio_cmd == BIO_READ) {
+							ata_48bit_cmd(ataio, ATA_READ_DMA48,
+							    0, lba, count);
+						} else {
+							ata_48bit_cmd(ataio, ATA_WRITE_DMA48,
+							    0, lba, count);
+						}
 					} else {
-						ata_48bit_cmd(ataio, ATA_WRITE_DMA48,
-						    0, lba, count);
+						if (bp->bio_cmd == BIO_READ) {
+							ata_48bit_cmd(ataio, ATA_READ_MUL48,
+							    0, lba, count);
+						} else {
+							ata_48bit_cmd(ataio, ATA_WRITE_MUL48,
+							    0, lba, count);
+						}
 					}
 				} else {
-					if (bp->bio_cmd == BIO_READ) {
-						ata_36bit_cmd(ataio, ATA_READ_DMA,
-						    0, lba, count);
+					if (count == 256)
+						count = 0;
+					if (softc->flags & ADA_FLAG_CAN_DMA) {
+						if (bp->bio_cmd == BIO_READ) {
+							ata_36bit_cmd(ataio, ATA_READ_DMA,
+							    0, lba, count);
+						} else {
+							ata_36bit_cmd(ataio, ATA_WRITE_DMA,
+							    0, lba, count);
+						}
 					} else {
-						ata_36bit_cmd(ataio, ATA_WRITE_DMA,
-						    0, lba, count);
+						if (bp->bio_cmd == BIO_READ) {
+							ata_36bit_cmd(ataio, ATA_READ_MUL,
+							    0, lba, count);
+						} else {
+							ata_36bit_cmd(ataio, ATA_WRITE_MUL,
+							    0, lba, count);
+						}
 					}
 				}
 			}
@@ -858,7 +889,7 @@
 				if (softc->flags & ADA_FLAG_CAN_48BIT)
 					ata_48bit_cmd(ataio, ATA_FLUSHCACHE48, 0, 0, 0);
 				else
-					ata_48bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0);
+					ata_36bit_cmd(ataio, ATA_FLUSHCACHE, 0, 0, 0);
 				break;
 			}
 			start_ccb->ccb_h.ccb_state = ADA_CCB_BUFFER_IO;
@@ -889,6 +920,21 @@
 		}
 		break;
 	}
+	case ADA_STATE_SET_MULTI:
+	{
+		cam_fill_ataio(ataio,
+		    ada_retry_count,
+		    adadone,
+		    CAM_DIR_NONE,
+		    0,
+		    NULL,
+		    0,
+		    ada_default_timeout*1000);
+
+		ata_36bit_cmd(ataio, ATA_SET_MULTI, 0, 0, softc->secsperint);
+		start_ccb->ccb_h.ccb_state = ADA_CCB_SET_MULTI;
+		xpt_action(start_ccb);
+	}
 	}
 }
 
@@ -909,7 +955,7 @@
 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
 			int error;
 			
-			error = adaerror(done_ccb, CAM_RETRY_SELTO, 0);
+			error = adaerror(done_ccb, 0, 0);
 			if (error == ERESTART) {
 				/*
 				 * A retry was scheuled, so
@@ -980,6 +1026,34 @@
 		wakeup(&done_ccb->ccb_h.cbfcnp);
 		return;
 	}
+	case ADA_CCB_SET_MULTI:
+	{
+		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
+		} else {
+			int	error;
+
+			error = adaerror(done_ccb, 0, 0);
+			if (error == ERESTART) {
+				/*
+				 * A retry was scheuled, so
+				 * just return.
+				 */
+				return;
+			}
+		}
+		softc->state = ADA_STATE_NORMAL;
+		/*
+		 * Since our peripheral may be invalidated by an error
+		 * above or an external event, we must release our CCB
+		 * before releasing the probe lock on the peripheral.
+		 * The peripheral will only go away once the last lock
+		 * is removed, and we need it around for the CCB release
+		 * operation.
+		 */
+		xpt_release_ccb(done_ccb);
+		cam_periph_unhold(periph);
+		return;
+	}
 	case ADA_CCB_DUMP:
 		/* No-op.  We're polling */
 		return;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200908081314.n78DEjnt021950>