Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 28 Feb 2009 11:25:05 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r189166 - head/sys/dev/ata
Message-ID:  <200902281125.n1SBP5WZ007813@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Feb 28 11:25:05 2009
New Revision: 189166
URL: http://svn.freebsd.org/changeset/base/189166

Log:
  Rework device probing by moving ata_getparam() call from ata_identify() to
  drivers' probe routines. It allows not to sleep and so not drop Giant inside
  ata_identify() critical section and so avoid crash if it reentered on
  request timeout. Reentering of probe call checked inside of it.
  
  Give device own knowledge about it's type (ata/atapi/atapicam). It is not
  a good idea to ask channel status for device type inside ata_getparam().
  
  Add softc memory deallocation on device destruction.

Modified:
  head/sys/dev/ata/ata-all.c
  head/sys/dev/ata/ata-all.h
  head/sys/dev/ata/ata-disk.c
  head/sys/dev/ata/atapi-cam.c
  head/sys/dev/ata/atapi-cd.c
  head/sys/dev/ata/atapi-fd.c
  head/sys/dev/ata/atapi-tape.c

Modified: head/sys/dev/ata/ata-all.c
==============================================================================
--- head/sys/dev/ata/ata-all.c	Sat Feb 28 11:22:09 2009	(r189165)
+++ head/sys/dev/ata/ata-all.c	Sat Feb 28 11:25:05 2009	(r189166)
@@ -61,7 +61,6 @@ static struct cdevsw ata_cdevsw = {
 
 /* prototypes */
 static void ata_boot_attach(void);
-static device_t ata_add_child(device_t, struct ata_device *, int);
 static void ata_conn_event(void *, int);
 static void bswap(int8_t *, int);
 static void btrim(int8_t *, int);
@@ -180,7 +179,7 @@ ata_detach(device_t dev)
     if (!device_get_children(dev, &children, &nchildren)) {
 	for (i = 0; i < nchildren; i++)
 	    if (children[i])
-		device_delete_child(dev, children[i]);
+		ata_delete_child(dev, children[i]);
 	free(children, M_TEMP);
     } 
     taskqueue_drain(taskqueue_thread, &ch->conntask);
@@ -265,7 +264,7 @@ ata_reinit(device_t dev)
 			    ata_finish(request);
 		    request = NULL;
 		}
-		device_delete_child(dev, children[i]);
+		ata_delete_child(dev, children[i]);
 	    }
 	}
 	free(children, M_TEMP);
@@ -590,19 +589,44 @@ ata_boot_attach(void)
 /*
  * misc support functions
  */
-static device_t
-ata_add_child(device_t parent, struct ata_device *atadev, int unit)
+device_t
+ata_add_child(device_t parent, int unit, int atapi)
 {
+    struct ata_device *atadev;
     device_t child;
+    int dev_unit = -1;
 
-    if ((child = device_add_child(parent, NULL, unit))) {
+#ifdef ATA_STATIC_ID
+    if (!atapi)
+	dev_unit = (device_get_unit(parent) << 1) + unit;
+#endif
+    if ((child = device_add_child(parent, NULL, dev_unit))) {
+	if (!(atadev = malloc(sizeof(struct ata_device),
+			  M_ATA, M_NOWAIT | M_ZERO))) {
+	    device_printf(parent, "out of memory\n");
+	    device_delete_child(parent, child);
+	    return (NULL);
+	}
 	device_set_softc(child, atadev);
 	device_quiet(child);
 	atadev->dev = child;
+	atadev->unit = unit;
+	atadev->type = atapi ? ATA_T_ATAPI : ATA_T_ATA;
 	atadev->max_iosize = DEV_BSIZE;
 	atadev->mode = ATA_PIO_MAX;
     }
-    return child;
+    return (child);
+}
+
+int
+ata_delete_child(device_t parent, device_t child)
+{
+    struct ata_device *atadev = device_get_softc(child);
+    int res;
+
+    res = device_delete_child(parent, child);
+    free(atadev, M_ATA);
+    return (res);
 }
 
 int
@@ -613,11 +637,11 @@ ata_getparam(struct ata_device *atadev, 
     u_int8_t command = 0;
     int error = ENOMEM, retries = 2;
 
-    if (ch->devices & (ATA_ATA_MASTER << atadev->unit))
+    if (atadev->type == ATA_T_ATA)
 	command = ATA_ATA_IDENTIFY;
-    if (ch->devices & (ATA_ATAPI_MASTER << atadev->unit))
+    else if (atadev->type == ATA_T_ATAPI)
 	command = ATA_ATAPI_IDENTIFY;
-    if (!command)
+    else
 	return ENXIO;
 
     while (retries-- > 0 && error) {
@@ -663,17 +687,18 @@ ata_getparam(struct ata_device *atadev, 
 	btrim(atacap->serial, sizeof(atacap->serial));
 	bpack(atacap->serial, atacap->serial, sizeof(atacap->serial));
 
-	if (bootverbose)
-	    printf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n",
+	if (init) {
+	    char buffer[64];
+
+	    if (bootverbose) {
+		printf("ata%d-%s: pio=%s wdma=%s udma=%s cable=%s wire\n",
 		   device_get_unit(ch->dev),
 		   ata_unit2str(atadev),
 		   ata_mode2str(ata_pmode(atacap)),
 		   ata_mode2str(ata_wmode(atacap)),
 		   ata_mode2str(ata_umode(atacap)),
 		   (atacap->hwres & ATA_CABLE_ID) ? "80":"40");
-
-	if (init) {
-	    char buffer[64];
+	    }
 
 	    sprintf(buffer, "%.40s/%.8s", atacap->model, atacap->revision);
 	    device_set_desc_copy(atadev->dev, buffer);
@@ -706,7 +731,6 @@ ata_identify(device_t dev)
     struct ata_channel *ch = device_get_softc(dev);
     struct ata_device *atadev;
     device_t *children;
-    device_t child;
     int nchildren, i, n = ch->devices;
 
     if (bootverbose)
@@ -721,37 +745,18 @@ ata_identify(device_t dev)
 	}
 	free(children, M_TEMP);
     }
-    /* Create new devices. */
     if (bootverbose)
 	device_printf(dev, "New devices: %08x\n", n);
     if (n == 0) {
 	mtx_unlock(&Giant);
 	return (0);
     }
+    /* Create new devices. */
     for (i = 0; i < ATA_PM; ++i) {
-	if (n & (((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << i))) {
-	    int unit = -1;
-
-	    if (!(atadev = malloc(sizeof(struct ata_device),
-				  M_ATA, M_NOWAIT | M_ZERO))) {
-		device_printf(dev, "out of memory\n");
-		return ENOMEM;
-	    }
-	    atadev->unit = i;
-#ifdef ATA_STATIC_ID
-	    if (n & (ATA_ATA_MASTER << i))
-		unit = (device_get_unit(dev) << 1) + i;
-#endif
-	    if ((child = ata_add_child(dev, atadev, unit))) {
-		if (ata_getparam(atadev, 1)) {
-		    device_delete_child(dev, child);
-		    free(atadev, M_ATA);
-		}
-	    }
-	    else
-		free(atadev, M_ATA);
-	}
+	if (n & (((ATA_ATA_MASTER | ATA_ATAPI_MASTER) << i)))
+	    ata_add_child(dev, i, n & (ATA_ATAPI_MASTER << i));
     }
+
     bus_generic_probe(dev);
     bus_generic_attach(dev);
     mtx_unlock(&Giant);

Modified: head/sys/dev/ata/ata-all.h
==============================================================================
--- head/sys/dev/ata/ata-all.h	Sat Feb 28 11:22:09 2009	(r189165)
+++ head/sys/dev/ata/ata-all.h	Sat Feb 28 11:25:05 2009	(r189166)
@@ -410,6 +410,10 @@ struct ata_device {
 #define         ATA_MASTER              0x00
 #define         ATA_SLAVE               0x01
 #define         ATA_PM                  0x0f
+    int                         type;           /* device type */
+#define         ATA_T_ATA               0x00
+#define         ATA_T_ATAPI             0x01
+#define         ATA_T_ATAPI_CAM         0x02
 
     struct ata_params           param;          /* ata param structure */
     int                         mode;           /* current transfermode */
@@ -422,6 +426,8 @@ struct ata_device {
 #define         ATA_D_MEDIA_CHANGED     0x0002
 #define         ATA_D_ENC_PRESENT       0x0004
 #define         ATA_D_48BIT_ACTIVE      0x0008
+#define         ATA_D_PROBED            0x0010
+#define         ATA_D_VALID             0x0020
 };
 
 /* structure for holding DMA Physical Region Descriptors (PRD) entries */
@@ -559,6 +565,8 @@ void ata_interrupt(void *data);
 int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data);
 int ata_getparam(struct ata_device *atadev, int init);
 int ata_identify(device_t dev);
+device_t ata_add_child(device_t, int, int);
+int ata_delete_child(device_t , device_t);
 void ata_default_registers(device_t dev);
 void ata_modify_if_48bit(struct ata_request *request);
 void ata_udelay(int interval);

Modified: head/sys/dev/ata/ata-disk.c
==============================================================================
--- head/sys/dev/ata/ata-disk.c	Sat Feb 28 11:22:09 2009	(r189165)
+++ head/sys/dev/ata/ata-disk.c	Sat Feb 28 11:25:05 2009	(r189166)
@@ -79,6 +79,18 @@ ad_probe(device_t dev)
 {
     struct ata_device *atadev = device_get_softc(dev);
 
+    if (atadev->type != ATA_T_ATA)
+	return (ENXIO);
+
+    if (!(atadev->flags & ATA_D_PROBED)) {
+	atadev->flags |= ATA_D_PROBED;
+	if (ata_getparam(atadev, 1) == 0)
+	    atadev->flags |= ATA_D_VALID;
+    }
+
+    if (!(atadev->flags & ATA_D_VALID))
+	return (ENXIO);
+
     if (!(atadev->param.config & ATA_PROTO_ATAPI) ||
 	(atadev->param.config == ATA_CFA_MAGIC1) ||
 	(atadev->param.config == ATA_CFA_MAGIC2) ||

Modified: head/sys/dev/ata/atapi-cam.c
==============================================================================
--- head/sys/dev/ata/atapi-cam.c	Sat Feb 28 11:22:09 2009	(r189165)
+++ head/sys/dev/ata/atapi-cam.c	Sat Feb 28 11:25:05 2009	(r189166)
@@ -147,7 +147,7 @@ static void
 atapi_cam_identify(driver_t *driver, device_t parent)
 {
 	struct atapi_xpt_softc *scp =
-	    malloc (sizeof (struct atapi_xpt_softc), M_ATACAM, M_NOWAIT|M_ZERO);
+	    malloc (sizeof (struct atapi_xpt_softc), M_ATA, M_NOWAIT|M_ZERO);
 	device_t child;
 
 	if (scp == NULL) {
@@ -159,10 +159,11 @@ atapi_cam_identify(driver_t *driver, dev
 	child = device_add_child(parent, "atapicam", -1);
 	if (child == NULL) {
 		printf ("atapi_cam_identify: out of memory, can't add child");
-		free (scp, M_ATACAM);
+		free (scp, M_ATA);
 		return;
 	}
 	scp->atapi_cam_dev.unit = -1;
+	scp->atapi_cam_dev.type = ATA_T_ATAPI_CAM;
 	scp->atapi_cam_dev.dev  = child;
 	device_quiet(child);
 	device_set_softc(child, scp);
@@ -174,12 +175,10 @@ atapi_cam_probe(device_t dev)
 	struct ata_device *atadev = device_get_softc (dev);
 
 	KASSERT(atadev != NULL, ("expect valid struct ata_device"));
-	if (atadev->unit < 0) {
-		device_set_desc(dev, "ATAPI CAM Attachment");
-		return (0);
-	} else {
-		return ENXIO;
-	}
+	if (atadev->type != ATA_T_ATAPI_CAM)
+		return (ENXIO);
+	device_set_desc(dev, "ATAPI CAM Attachment");
+	return (0);
 }
 
 static int
@@ -925,11 +924,8 @@ atapi_cam_event_handler(module_t mod, in
 	    if (devlist != NULL) {
 		while (devlist != NULL && devcount > 0) {
 		    device_t child = devlist[--devcount];
-		    struct atapi_xpt_softc *scp = device_get_softc(child);
 
-		    device_delete_child(device_get_parent(child),child);
-		    if (scp != NULL)
-			free(scp, M_ATACAM);
+		    ata_delete_child(device_get_parent(child),child);
 		}
 		free(devlist, M_TEMP);
 	    }

Modified: head/sys/dev/ata/atapi-cd.c
==============================================================================
--- head/sys/dev/ata/atapi-cd.c	Sat Feb 28 11:22:09 2009	(r189165)
+++ head/sys/dev/ata/atapi-cd.c	Sat Feb 28 11:25:05 2009	(r189166)
@@ -108,6 +108,18 @@ acd_probe(device_t dev)
 {
     struct ata_device *atadev = device_get_softc(dev);
 
+    if (atadev->type != ATA_T_ATAPI)
+	return (ENXIO);
+
+    if (!(atadev->flags & ATA_D_PROBED)) {
+	atadev->flags |= ATA_D_PROBED;
+	if (ata_getparam(atadev, 1) == 0)
+	    atadev->flags |= ATA_D_VALID;
+    }
+
+    if (!(atadev->flags & ATA_D_VALID))
+	return (ENXIO);
+
     if ((atadev->param.config & ATA_PROTO_ATAPI) &&
 	(atadev->param.config & ATA_ATAPI_TYPE_MASK) == ATA_ATAPI_TYPE_CDROM)
 	return 0;

Modified: head/sys/dev/ata/atapi-fd.c
==============================================================================
--- head/sys/dev/ata/atapi-fd.c	Sat Feb 28 11:22:09 2009	(r189165)
+++ head/sys/dev/ata/atapi-fd.c	Sat Feb 28 11:25:05 2009	(r189166)
@@ -66,6 +66,19 @@ static int 
 afd_probe(device_t dev)
 {
     struct ata_device *atadev = device_get_softc(dev);
+
+    if (atadev->type != ATA_T_ATAPI)
+	return (ENXIO);
+
+    if (!(atadev->flags & ATA_D_PROBED)) {
+	atadev->flags |= ATA_D_PROBED;
+	if (ata_getparam(atadev, 1) == 0)
+	    atadev->flags |= ATA_D_VALID;
+    }
+
+    if (!(atadev->flags & ATA_D_VALID))
+	return (ENXIO);
+
     if ((atadev->param.config & ATA_PROTO_ATAPI) &&
 	(atadev->param.config & ATA_ATAPI_TYPE_MASK) == ATA_ATAPI_TYPE_DIRECT)
 	return 0;  

Modified: head/sys/dev/ata/atapi-tape.c
==============================================================================
--- head/sys/dev/ata/atapi-tape.c	Sat Feb 28 11:22:09 2009	(r189165)
+++ head/sys/dev/ata/atapi-tape.c	Sat Feb 28 11:25:05 2009	(r189166)
@@ -90,6 +90,18 @@ ast_probe(device_t dev)
 {
     struct ata_device *atadev = device_get_softc(dev);
 
+    if (atadev->type != ATA_T_ATAPI)
+	return (ENXIO);
+
+    if (!(atadev->flags & ATA_D_PROBED)) {
+	atadev->flags |= ATA_D_PROBED;
+	if (ata_getparam(atadev, 1) == 0)
+	    atadev->flags |= ATA_D_VALID;
+    }
+
+    if (!(atadev->flags & ATA_D_VALID))
+	return (ENXIO);
+
     if ((atadev->param.config & ATA_PROTO_ATAPI) &&
 	(atadev->param.config & ATA_ATAPI_TYPE_MASK) == ATA_ATAPI_TYPE_TAPE)
 	return 0;



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