PERFORCE change 173612 for review

Alexander Motin mav at FreeBSD.org
Sun Jan 24 10:49:43 UTC 2010


http://p4web.freebsd.org/chv.cgi?CH=173612

Change 173612 by mav at mav_mavtest on 2010/01/24 10:49:20

	Implement two-level SCSI error recovery: send request sense request
	(if needed) for recovery requests errors. For example, it makes cd
	driver to poll ATAPI CD device while it loading the media, instead of
	just returning error.

Affected files ...

.. //depot/projects/scottl-camlock/src/sys/cam/cam_periph.c#51 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_periph.h#26 edit

Differences ...

==== //depot/projects/scottl-camlock/src/sys/cam/cam_periph.c#51 (text+ko) ====

@@ -71,7 +71,6 @@
 static int		camperiphscsistatuserror(union ccb *ccb,
 						 cam_flags camflags,
 						 u_int32_t sense_flags,
-						 union ccb *save_ccb,
 						 int *openings,
 						 u_int32_t *relsim_flags,
 						 u_int32_t *timeout,
@@ -79,7 +78,6 @@
 static	int		camperiphscsisenseerror(union ccb *ccb,
 					        cam_flags camflags,
 					        u_int32_t sense_flags,
-					        union ccb *save_ccb,
 					        int *openings,
 					        u_int32_t *relsim_flags,
 					        u_int32_t *timeout,
@@ -1008,16 +1006,86 @@
 }
 
 #define saved_ccb_ptr ppriv_ptr0
+#define recovery_depth ppriv_field1
+static void
+camperiphsensedone(struct cam_periph *periph, union ccb *done_ccb)
+{
+	union ccb      *saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
+	cam_status	status;
+	int		frozen = 0;
+	u_int		sense_key;
+	int		depth = done_ccb->ccb_h.recovery_depth;
+
+	status = done_ccb->ccb_h.status;
+	if (status & CAM_DEV_QFRZN) {
+		frozen = 1;
+		/*
+		 * Clear freeze flag now for case of retry,
+		 * freeze will be dropped later.
+		 */
+		done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
+	}
+	status &= CAM_STATUS_MASK;
+	switch (status) {
+	case CAM_REQ_CMP:
+	{
+		/*
+		 * If we manually retrieved sense into a CCB and got
+		 * something other than "NO SENSE" send the updated CCB
+		 * back to the client via xpt_done() to be processed via
+		 * the error recovery code again.
+		 */
+		sense_key = saved_ccb->csio.sense_data.flags;
+		sense_key &= SSD_KEY;
+		if (sense_key != SSD_KEY_NO_SENSE) {
+			saved_ccb->ccb_h.status |=
+			    CAM_AUTOSNS_VALID;
+		} else {
+			saved_ccb->ccb_h.status &=
+			    ~CAM_STATUS_MASK;
+			saved_ccb->ccb_h.status |=
+			    CAM_AUTOSENSE_FAIL;
+		}
+		bcopy(saved_ccb, done_ccb, sizeof(union ccb));
+		xpt_free_ccb(saved_ccb);
+		break;
+	}
+	default:
+		bcopy(saved_ccb, done_ccb, sizeof(union ccb));
+		xpt_free_ccb(saved_ccb);
+		done_ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+		done_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
+		break;
+	}
+	periph->flags &= ~CAM_PERIPH_SENSE_INPROG;
+	/*
+	 * If it is the end of recovery, drop freeze, taken due to
+	 * CAM_DEV_QFREEZE flag, set on recovery request.
+	 */
+	if (depth == 0) {
+		cam_release_devq(done_ccb->ccb_h.path,
+			 /*relsim_flags*/0,
+			 /*openings*/0,
+			 /*timeout*/0,
+			 /*getcount_only*/0);
+	}
+	/*
+	 * Copy frozen flag from recovery request if it is set there
+	 * for some reason.
+	 */
+	if (frozen != 0)
+		done_ccb->ccb_h.status |= CAM_DEV_QFRZN;
+	(*done_ccb->ccb_h.cbfcnp)(periph, done_ccb);
+}
+
 static void
 camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
 {
-	union ccb      *saved_ccb;
+	union ccb      *saved_ccb, *save_ccb;
 	cam_status	status;
 	int		frozen = 0;
-	int		sense;
 	struct scsi_start_stop_unit *scsi_cmd;
 	u_int32_t	relsim_flags, timeout;
-	int		xpt_done_ccb = FALSE;
 
 	status = done_ccb->ccb_h.status;
 	if (status & CAM_DEV_QFRZN) {
@@ -1028,14 +1096,12 @@
 		 */
 		done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
 	}
-	sense  = (status & CAM_AUTOSNS_VALID) != 0;
-	status &= CAM_STATUS_MASK;
 
 	timeout = 0;
 	relsim_flags = 0;
 	saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
 
-	switch (status) {
+	switch (status & CAM_STATUS_MASK) {
 	case CAM_REQ_CMP:
 	{
 		/*
@@ -1044,56 +1110,19 @@
 		 * the inquiry information.  Many devices (mostly disks)
 		 * don't properly report their inquiry information unless
 		 * they are spun up.
-		 *
-		 * If we manually retrieved sense into a CCB and got
-		 * something other than "NO SENSE" send the updated CCB
-		 * back to the client via xpt_done() to be processed via
-		 * the error recovery code again.
 		 */
-		if (done_ccb->ccb_h.func_code == XPT_SCSI_IO) {
-			scsi_cmd = (struct scsi_start_stop_unit *)
-					&done_ccb->csio.cdb_io.cdb_bytes;
+		scsi_cmd = (struct scsi_start_stop_unit *)
+				&done_ccb->csio.cdb_io.cdb_bytes;
 
-		 	if (scsi_cmd->opcode == START_STOP_UNIT)
-				xpt_async(AC_INQ_CHANGED,
-					  done_ccb->ccb_h.path, NULL);
-			if (scsi_cmd->opcode == REQUEST_SENSE) {
-				u_int sense_key;
-
-				sense_key = saved_ccb->csio.sense_data.flags;
-				sense_key &= SSD_KEY;
-				if (sense_key != SSD_KEY_NO_SENSE) {
-					saved_ccb->ccb_h.status |=
-					    CAM_AUTOSNS_VALID;
-#if 0
-					xpt_print(saved_ccb->ccb_h.path,
-					    "Recovered Sense\n");
-					cam_error_print(saved_ccb, CAM_ESF_ALL,
-							CAM_EPF_ALL);
-#endif
-				} else {
-					saved_ccb->ccb_h.status &=
-					    ~CAM_STATUS_MASK;
-					saved_ccb->ccb_h.status |=
-					    CAM_AUTOSENSE_FAIL;
-				}
-				xpt_done_ccb = TRUE;
-			}
-		}
-		bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb,
-		      sizeof(union ccb));
-
-		periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-
-		if (xpt_done_ccb == FALSE)
-			xpt_action(done_ccb);
-
-		break;
+	 	if (scsi_cmd->opcode == START_STOP_UNIT)
+			xpt_async(AC_INQ_CHANGED,
+				  done_ccb->ccb_h.path, NULL);
+		goto final;
 	}
 	case CAM_SCSI_STATUS_ERROR:
 		scsi_cmd = (struct scsi_start_stop_unit *)
 				&done_ccb->csio.cdb_io.cdb_bytes;
-		if (sense != 0) {
+		if (status & CAM_AUTOSNS_VALID) {
 			struct ccb_getdev cgd;
 			struct scsi_sense_data *sense;
 			int    error_code, sense_key, asc, ascq;	
@@ -1102,7 +1131,6 @@
 			sense = &done_ccb->csio.sense_data;
 			scsi_extract_sense(sense, &error_code, 
 					   &sense_key, &asc, &ascq);
-
 			/*
 			 * Grab the inquiry data for this device.
 			 */
@@ -1112,7 +1140,6 @@
 			xpt_action((union ccb *)&cgd);
 			err_action = scsi_error_action(&done_ccb->csio,
 						       &cgd.inq_data, 0);
-
 			/*
 	 		 * If the error is "invalid field in CDB", 
 			 * and the load/eject flag is set, turn the 
@@ -1122,7 +1149,6 @@
 			 * the load/eject flag by default for 
 			 * removable media.
 			 */
-
 			/* XXX KDM 
 			 * Should we check to see what the specific
 			 * scsi status is??  Or does it not matter
@@ -1137,9 +1163,7 @@
 			     (done_ccb->ccb_h.retry_count > 0)) {
 
 				scsi_cmd->how &= ~SSS_LOEJ;
-
 				xpt_action(done_ccb);
-
 			} else if ((done_ccb->ccb_h.retry_count > 1)
 				&& ((err_action & SS_MASK) != SS_FAIL)) {
 
@@ -1150,53 +1174,51 @@
 				 * it another try unless this is an
 				 * unretryable error.
 				 */
-
 				/* set the timeout to .5 sec */
 				relsim_flags =
 					RELSIM_RELEASE_AFTER_TIMEOUT;
 				timeout = 500;
-
 				xpt_action(done_ccb);
-
 				break;
-
 			} else {
 				/* 
 				 * Perform the final retry with the original
 				 * CCB so that final error processing is
 				 * performed by the owner of the CCB.
 				 */
-				bcopy(done_ccb->ccb_h.saved_ccb_ptr,		
-				      done_ccb, sizeof(union ccb));
-
-				periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-
-				xpt_action(done_ccb);
+				goto final;
 			}
 		} else {
+			save_ccb = xpt_alloc_ccb_nowait();
+			if (save_ccb == NULL)
+				goto final;
+			bcopy(done_ccb, save_ccb, sizeof(*save_ccb));
+			periph->flags |= CAM_PERIPH_SENSE_INPROG;
 			/*
-			 * Eh??  The command failed, but we don't
-			 * have any sense.  What's up with that?
-			 * Fire the CCB again to return it to the
-			 * caller.
+			 * Send a Request Sense to the device.  We
+			 * assume that we are in a contingent allegiance
+			 * condition so we do not tag this request.
 			 */
-			bcopy(done_ccb->ccb_h.saved_ccb_ptr,
-			      done_ccb, sizeof(union ccb));
-
-			periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-
+			scsi_request_sense(&done_ccb->csio, /*retries*/1,
+					   camperiphsensedone,
+					   &save_ccb->csio.sense_data,
+					   sizeof(save_ccb->csio.sense_data),
+					   CAM_TAG_ACTION_NONE,
+					   /*sense_len*/SSD_FULL_SIZE,
+					   /*timeout*/5000);
+			done_ccb->ccb_h.pinfo.priority--;
+			done_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
+			done_ccb->ccb_h.saved_ccb_ptr = save_ccb;
+			done_ccb->ccb_h.recovery_depth++;
 			xpt_action(done_ccb);
-
 		}
 		break;
 	default:
-		bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb,
-		      sizeof(union ccb));
-
+final:
+		bcopy(saved_ccb, done_ccb, sizeof(*done_ccb));
+		xpt_free_ccb(saved_ccb);
 		periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
-
 		xpt_action(done_ccb);
-
 		break;
 	}
 
@@ -1219,23 +1241,13 @@
 			 /*openings*/0,
 			 /*timeout*/timeout,
 			 /*getcount_only*/0);
-	if (xpt_done_ccb == TRUE) {
-		/*
-		 * Copy frozen flag from recovery request if it is set there
-		 * for some reason.
-		 */
-		if (frozen != 0)
-			done_ccb->ccb_h.status |= CAM_DEV_QFRZN;
-		(*done_ccb->ccb_h.cbfcnp)(periph, done_ccb);
-	} else {
-		/* Drop freeze taken, if this recovery request got error. */
-		if (frozen != 0) {
-			cam_release_devq(done_ccb->ccb_h.path,
-				 /*relsim_flags*/0,
-				 /*openings*/0,
-				 /*timeout*/0,
-				 /*getcount_only*/0);
-		}
+	/* Drop freeze taken, if this recovery request got error. */
+	if (frozen != 0) {
+		cam_release_devq(done_ccb->ccb_h.path,
+			 /*relsim_flags*/0,
+			 /*openings*/0,
+			 /*timeout*/0,
+			 /*getcount_only*/0);
 	}
 }
 
@@ -1296,7 +1308,7 @@
 
 static int
 camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
-			 u_int32_t sense_flags, union ccb *save_ccb,
+			 u_int32_t sense_flags,
 			 int *openings, u_int32_t *relsim_flags,
 			 u_int32_t *timeout, const char **action_string)
 {
@@ -1316,7 +1328,6 @@
 		error = camperiphscsisenseerror(ccb,
 					        camflags,
 					        sense_flags,
-					        save_ccb,
 					        openings,
 					        relsim_flags,
 					        timeout,
@@ -1414,16 +1425,17 @@
 
 static int
 camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
-			u_int32_t sense_flags, union ccb *save_ccb,
+			u_int32_t sense_flags,
 		       int *openings, u_int32_t *relsim_flags,
 		       u_int32_t *timeout, const char **action_string)
 {
 	struct cam_periph *periph;
+	union ccb *orig_ccb = ccb;
 	int error;
 
 	periph = xpt_path_periph(ccb->ccb_h.path);
-	if (periph->flags & CAM_PERIPH_RECOVERY_INPROG) {
-
+	if (periph->flags &
+	    (CAM_PERIPH_RECOVERY_INPROG | CAM_PERIPH_SENSE_INPROG)) {
 		/*
 		 * If error recovery is already in progress, don't attempt
 		 * to process this error, but requeue it unconditionally
@@ -1441,13 +1453,6 @@
 	} else {
 		scsi_sense_action err_action;
 		struct ccb_getdev cgd;
-		union ccb* print_ccb;
-
-		/*
-		 * The location of the orignal ccb
-		 * for sense printing purposes.
-		 */
-		print_ccb = ccb;
 
 		/*
 		 * Grab the inquiry data for this device.
@@ -1485,8 +1490,9 @@
 			 * Do common portions of commands that
 			 * use recovery CCBs.
 			 */
-			if (save_ccb == NULL) {
-				*action_string = "No recovery CCB supplied";
+			orig_ccb = xpt_alloc_ccb_nowait();
+			if (orig_ccb == NULL) {
+				*action_string = "Can't allocate recovery CCB";
 				goto sense_error_done;
 			}
 			/*
@@ -1494,9 +1500,7 @@
 			 * this freeze will be dropped as part of ERESTART.
 			 */
 			ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
-			bcopy(ccb, save_ccb, sizeof(*save_ccb));
-			print_ccb = save_ccb;
-			periph->flags |= CAM_PERIPH_RECOVERY_INPROG;
+			bcopy(ccb, orig_ccb, sizeof(*orig_ccb));
 		}
 
 		switch (err_action & SS_MASK) {
@@ -1520,6 +1524,7 @@
 			 * then retry the command.
 			 */
 			*action_string = "Attempting to start unit";
+			periph->flags |= CAM_PERIPH_RECOVERY_INPROG;
 
 			/*
 			 * Check for removable media and set
@@ -1560,6 +1565,7 @@
 				*action_string = "Testing device for readiness";
 				retries = 1;
 			}
+			periph->flags |= CAM_PERIPH_RECOVERY_INPROG;
 			scsi_test_unit_ready(&ccb->csio,
 					     retries,
 					     camperiphdone,
@@ -1578,15 +1584,16 @@
 		case SS_REQSENSE:
 		{
 			*action_string = "Requesting SCSI sense data";
+			periph->flags |= CAM_PERIPH_SENSE_INPROG;
 			/*
 			 * Send a Request Sense to the device.  We
 			 * assume that we are in a contingent allegiance
 			 * condition so we do not tag this request.
 			 */
 			scsi_request_sense(&ccb->csio, /*retries*/1,
-					   camperiphdone,
-					   &save_ccb->csio.sense_data,
-					   sizeof(save_ccb->csio.sense_data),
+					   camperiphsensedone,
+					   &orig_ccb->csio.sense_data,
+					   sizeof(orig_ccb->csio.sense_data),
 					   CAM_TAG_ACTION_NONE,
 					   /*sense_len*/SSD_FULL_SIZE,
 					   /*timeout*/5000);
@@ -1607,14 +1614,15 @@
 			 */
 			ccb->ccb_h.pinfo.priority--;
 			ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
-			ccb->ccb_h.saved_ccb_ptr = save_ccb;
+			ccb->ccb_h.saved_ccb_ptr = orig_ccb;
+			ccb->ccb_h.recovery_depth = 0;
 			error = ERESTART;
 		}
 
 sense_error_done:
 		if ((err_action & SSQ_PRINT_SENSE) != 0
 		 && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)
-			cam_error_print(print_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
+			cam_error_print(orig_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
 	}
 	return (error);
 }
@@ -1650,7 +1658,6 @@
 		error = camperiphscsistatuserror(ccb,
 						 camflags,
 						 sense_flags,
-						 save_ccb,
 						 &openings,
 						 &relsim_flags,
 						 &timeout,

==== //depot/projects/scottl-camlock/src/sys/cam/cam_periph.h#26 (text+ko) ====

@@ -118,6 +118,7 @@
 #define CAM_PERIPH_INVALID		0x08
 #define CAM_PERIPH_NEW_DEV_FOUND	0x10
 #define CAM_PERIPH_RECOVERY_INPROG	0x20
+#define CAM_PERIPH_SENSE_INPROG		0x40
 	u_int32_t		 immediate_priority;
 	u_int32_t		 refcount;
 	SLIST_HEAD(, ccb_hdr)	 ccb_list;	/* For "immediate" requests */


More information about the p4-projects mailing list