Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 Apr 2012 12:58:14 +0000 (UTC)
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r234177 - head/sys/cam/scsi
Message-ID:  <201204121258.q3CCwEVe029227@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trasz
Date: Thu Apr 12 12:58:14 2012
New Revision: 234177
URL: http://svn.freebsd.org/changeset/base/234177

Log:
  Refactor da(4) to remove one of two code paths used to query capacity
  data.
  
  Reviewed by:	ken, mav (earlier version)
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/sys/cam/scsi/scsi_da.c

Modified: head/sys/cam/scsi/scsi_da.c
==============================================================================
--- head/sys/cam/scsi/scsi_da.c	Thu Apr 12 12:37:53 2012	(r234176)
+++ head/sys/cam/scsi/scsi_da.c	Thu Apr 12 12:58:14 2012	(r234177)
@@ -83,7 +83,8 @@ typedef enum {
 	DA_FLAG_RETRY_UA	= 0x080,
 	DA_FLAG_OPEN		= 0x100,
 	DA_FLAG_SCTX_INIT	= 0x200,
-	DA_FLAG_CAN_RC16	= 0x400
+	DA_FLAG_CAN_RC16	= 0x400,
+	DA_FLAG_PROBED		= 0x800		
 } da_flags;
 
 typedef enum {
@@ -829,7 +830,7 @@ static	void		dadone(struct cam_periph *p
 static  int		daerror(union ccb *ccb, u_int32_t cam_flags,
 				u_int32_t sense_flags);
 static void		daprevent(struct cam_periph *periph, int action);
-static int		dagetcapacity(struct cam_periph *periph);
+static void		dareprobe(struct cam_periph *periph);
 static void		dasetgeom(struct cam_periph *periph, uint32_t block_len,
 				  uint64_t maxsector,
 				  struct scsi_read_capacity_data_long *rcaplong,
@@ -929,36 +930,29 @@ daopen(struct disk *dp)
 		softc->flags &= ~DA_FLAG_PACK_INVALID;
 	}
 
-	error = dagetcapacity(periph);
+	dareprobe(periph);
 
-	if (error == 0) {
-
-		softc->disk->d_sectorsize = softc->params.secsize;
-		softc->disk->d_mediasize = softc->params.secsize * (off_t)softc->params.sectors;
-		softc->disk->d_stripesize = softc->params.stripesize;
-		softc->disk->d_stripeoffset = softc->params.stripeoffset;
-		/* XXX: these are not actually "firmware" values, so they may be wrong */
-		softc->disk->d_fwsectors = softc->params.secs_per_track;
-		softc->disk->d_fwheads = softc->params.heads;
-		softc->disk->d_devstat->block_size = softc->params.secsize;
-		softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE;
-		if (softc->delete_method > DA_DELETE_DISABLE)
-			softc->disk->d_flags |= DISKFLAG_CANDELETE;
-		else
-			softc->disk->d_flags &= ~DISKFLAG_CANDELETE;
-
-		if ((softc->flags & DA_FLAG_PACK_REMOVABLE) != 0 &&
-		    (softc->quirks & DA_Q_NO_PREVENT) == 0)
-			daprevent(periph, PR_PREVENT);
-	} else
-		softc->flags &= ~DA_FLAG_OPEN;
+	/* Wait for the disk size update.  */
+	error = msleep(&softc->disk->d_mediasize, periph->sim->mtx, PRIBIO,
+	    "dareprobe", 0);
+	if (error != 0)
+		xpt_print(periph->path, "unable to retrieve capacity data");
+
+	if (periph->flags & CAM_PERIPH_INVALID)
+		error = ENXIO;
+
+	if (error == 0 && (softc->flags & DA_FLAG_PACK_REMOVABLE) != 0 &&
+	    (softc->quirks & DA_Q_NO_PREVENT) == 0)
+		daprevent(periph, PR_PREVENT);
 
 	cam_periph_unhold(periph);
 	cam_periph_unlock(periph);
 
 	if (error != 0) {
+		softc->flags &= ~DA_FLAG_OPEN;
 		cam_periph_release(periph);
 	}
+
 	return (error);
 }
 
@@ -2364,7 +2358,7 @@ dadone(struct cam_periph *periph, union 
 			}
 		}
 		free(csio->data_ptr, M_SCSIDA);
-		if (announce_buf[0] != '\0') {
+		if (announce_buf[0] != '\0' && ((softc->flags & DA_FLAG_PROBED) == 0)) {
 			/*
 			 * Create our sysctl variables, now that we know
 			 * we have successfully attached.
@@ -2378,9 +2372,7 @@ dadone(struct cam_periph *periph, union 
 				xpt_print(periph->path, "fatal error, "
 				    "could not acquire reference count\n");
 			}
-				
 		}
-		softc->state = DA_STATE_NORMAL;	
 		/*
 		 * Since our peripheral may be invalidated by an error
 		 * above or an external event, we must release our CCB
@@ -2390,7 +2382,13 @@ dadone(struct cam_periph *periph, union 
 		 * operation.
 		 */
 		xpt_release_ccb(done_ccb);
-		cam_periph_unhold(periph);
+		softc->state = DA_STATE_NORMAL;	
+		wakeup(&softc->disk->d_mediasize);
+		if ((softc->flags & DA_FLAG_PROBED) == 0) {
+			softc->flags |= DA_FLAG_PROBED;
+			cam_periph_unhold(periph);
+		} else
+			cam_periph_release_locked(periph);
 		return;
 	}
 	case DA_CCB_WAITING:
@@ -2408,6 +2406,30 @@ dadone(struct cam_periph *periph, union 
 	xpt_release_ccb(done_ccb);
 }
 
+static void
+dareprobe(struct cam_periph *periph)
+{
+	struct da_softc	  *softc;
+	cam_status status;
+
+	softc = (struct da_softc *)periph->softc;
+
+	/* Probe in progress; don't interfere. */
+	if ((softc->flags & DA_FLAG_PROBED) == 0)
+		return;
+
+	status = cam_periph_acquire(periph);
+	KASSERT(status == CAM_REQ_CMP,
+	    ("dareprobe: cam_periph_acquire failed"));
+
+	if (softc->flags & DA_FLAG_CAN_RC16)
+		softc->state = DA_STATE_PROBE2;
+	else
+		softc->state = DA_STATE_PROBE;
+
+	xpt_schedule(periph, CAM_PRIORITY_DEV);
+}
+
 static int
 daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
 {
@@ -2437,6 +2459,16 @@ daerror(union ccb *ccb, u_int32_t cam_fl
 				   &error_code, &sense_key, &asc, &ascq);
 		if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
  			error = cmd6workaround(ccb);
+		/*
+		 * If the target replied with CAPACITY DATA HAS CHANGED UA,
+		 * query the capacity and notify upper layers.
+		 */
+		else if (sense_key == SSD_KEY_UNIT_ATTENTION &&
+		    asc == 0x2A && ascq == 0x09) {
+			xpt_print(periph->path, "capacity data has changed\n");
+			dareprobe(periph);
+			sense_flags |= SF_NO_PRINT;
+		}
 	}
 	if (error == ERESTART)
 		return (ERESTART);
@@ -2490,164 +2522,6 @@ daprevent(struct cam_periph *periph, int
 	xpt_release_ccb(ccb);
 }
 
-static int
-dagetcapacity(struct cam_periph *periph)
-{
-	struct da_softc *softc;
-	union ccb *ccb;
-	struct scsi_read_capacity_data *rcap;
-	struct scsi_read_capacity_data_long *rcaplong;
-	uint32_t block_len;
-	uint64_t maxsector;
-	int error, rc16failed;
-	u_int32_t sense_flags;
-	u_int lbppbe;	/* Logical blocks per physical block exponent. */
-	u_int lalba;	/* Lowest aligned LBA. */
-
-	softc = (struct da_softc *)periph->softc;
-	block_len = 0;
-	maxsector = 0;
-	lbppbe = 0;
-	lalba = 0;
-	error = 0;
-	rc16failed = 0;
-	rcaplong = NULL;
-	sense_flags = SF_RETRY_UA;
-	if (softc->flags & DA_FLAG_PACK_REMOVABLE)
-		sense_flags |= SF_NO_PRINT;
-
-	/* Do a read capacity */
-	rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcaplong),
-							M_SCSIDA,
-							M_NOWAIT | M_ZERO);
-	if (rcap == NULL)
-		return (ENOMEM);
-	rcaplong = (struct scsi_read_capacity_data_long *)rcap;
-
-	ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
-
-	/* Try READ CAPACITY(16) first if we think it should work. */
-	if (softc->flags & DA_FLAG_CAN_RC16) {
-		scsi_read_capacity_16(&ccb->csio,
-				      /*retries*/ 4,
-				      /*cbfcnp*/ dadone,
-				      /*tag_action*/ MSG_SIMPLE_Q_TAG,
-				      /*lba*/ 0,
-				      /*reladr*/ 0,
-				      /*pmi*/ 0,
-				      /*rcap_buf*/ (uint8_t *)rcaplong,
-				      /*rcap_buf_len*/ sizeof(*rcaplong),
-				      /*sense_len*/ SSD_FULL_SIZE,
-				      /*timeout*/ 60000);
-		ccb->ccb_h.ccb_bp = NULL;
-
-		error = cam_periph_runccb(ccb, daerror,
-					  /*cam_flags*/CAM_RETRY_SELTO,
-					  sense_flags, softc->disk->d_devstat);
-		if (error == 0)
-			goto rc16ok;
-
-		/* If we got ILLEGAL REQUEST, do not prefer RC16 any more. */
-		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
-			softc->flags &= ~DA_FLAG_CAN_RC16;
-		} else if (((ccb->ccb_h.status & CAM_STATUS_MASK) ==
-			     CAM_SCSI_STATUS_ERROR)
-			&& (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
-			&& (ccb->ccb_h.status & CAM_AUTOSNS_VALID)
-			&& ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0)
-			&& ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
-			int sense_key, error_code, asc, ascq;
-
-			scsi_extract_sense_len(&ccb->csio.sense_data,
-					       ccb->csio.sense_len -
-					       ccb->csio.sense_resid,
-					       &error_code, &sense_key,
-					       &asc, &ascq, /*show_errors*/1);
-			/*
-			 * If we don't have enough sense to get the sense
-			 * key, or if it's illegal request, turn off
-			 * READ CAPACITY (16).
-			 */
-			if ((sense_key == -1)
-			 || (sense_key == SSD_KEY_ILLEGAL_REQUEST))
-				softc->flags &= ~DA_FLAG_CAN_RC16;
-		}
-		rc16failed = 1;
-	}
-
-	/* Do READ CAPACITY(10). */
-	scsi_read_capacity(&ccb->csio,
-			   /*retries*/4,
-			   /*cbfncp*/dadone,
-			   MSG_SIMPLE_Q_TAG,
-			   rcap,
-			   SSD_FULL_SIZE,
-			   /*timeout*/60000);
-	ccb->ccb_h.ccb_bp = NULL;
-
-	error = cam_periph_runccb(ccb, daerror,
-				  /*cam_flags*/CAM_RETRY_SELTO,
-				  sense_flags,
-				  softc->disk->d_devstat);
-	if (error == 0) {
-		block_len = scsi_4btoul(rcap->length);
-		maxsector = scsi_4btoul(rcap->addr);
-
-		if (maxsector != 0xffffffff || rc16failed)
-			goto done;
-	} else
-		goto done;
-
-	/* If READ CAPACITY(10) returned overflow, use READ CAPACITY(16) */
-	scsi_read_capacity_16(&ccb->csio,
-			      /*retries*/ 4,
-			      /*cbfcnp*/ dadone,
-			      /*tag_action*/ MSG_SIMPLE_Q_TAG,
-			      /*lba*/ 0,
-			      /*reladr*/ 0,
-			      /*pmi*/ 0,
-			      /*rcap_buf*/ (uint8_t *)rcaplong,
-			      /*rcap_buf_len*/ sizeof(*rcaplong),
-			      /*sense_len*/ SSD_FULL_SIZE,
-			      /*timeout*/ 60000);
-	ccb->ccb_h.ccb_bp = NULL;
-
-	error = cam_periph_runccb(ccb, daerror,
-				  /*cam_flags*/CAM_RETRY_SELTO,
-				  sense_flags,
-				  softc->disk->d_devstat);
-	if (error == 0) {
-rc16ok:
-		block_len = scsi_4btoul(rcaplong->length);
-		maxsector = scsi_8btou64(rcaplong->addr);
-		lbppbe = rcaplong->prot_lbppbe & SRC16_LBPPBE;
-		lalba = scsi_2btoul(rcaplong->lalba_lbp);
-	}
-
-done:
-
-	if (error == 0) {
-		if (block_len >= MAXPHYS || block_len == 0) {
-			xpt_print(periph->path,
-			    "unsupportable block size %ju\n",
-			    (uintmax_t) block_len);
-			error = EINVAL;
-		} else {
-			dasetgeom(periph, block_len, maxsector,
-				  rcaplong, sizeof(*rcaplong));
-			if ((lalba & SRC16_LBPME)
-			 && softc->delete_method == DA_DELETE_NONE)
-				softc->delete_method = DA_DELETE_UNMAP;
-		}
-	}
-
-	xpt_release_ccb(ccb);
-
-	free(rcap, M_SCSIDA);
-
-	return (error);
-}
-
 static void
 dasetgeom(struct cam_periph *periph, uint32_t block_len, uint64_t maxsector,
 	  struct scsi_read_capacity_data_long *rcaplong, size_t rcap_len)
@@ -2747,6 +2621,20 @@ dasetgeom(struct cam_periph *periph, uin
 			      min(sizeof(softc->rcaplong), rcap_len));
 		}
 	}
+
+	softc->disk->d_sectorsize = softc->params.secsize;
+	softc->disk->d_mediasize = softc->params.secsize * (off_t)softc->params.sectors;
+	softc->disk->d_stripesize = softc->params.stripesize;
+	softc->disk->d_stripeoffset = softc->params.stripeoffset;
+	/* XXX: these are not actually "firmware" values, so they may be wrong */
+	softc->disk->d_fwsectors = softc->params.secs_per_track;
+	softc->disk->d_fwheads = softc->params.heads;
+	softc->disk->d_devstat->block_size = softc->params.secsize;
+	softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE;
+	if (softc->delete_method > DA_DELETE_DISABLE)
+		softc->disk->d_flags |= DISKFLAG_CANDELETE;
+	else
+		softc->disk->d_flags &= ~DISKFLAG_CANDELETE;
 }
 
 static void



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