diff usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c @ 7201:0259de900d45

6625553 BAD TRAP: type=31 rp=2a100297730 addr=0 mmu_fsr=0 occurred in module "genunix"
author rralphs
date Mon, 28 Jul 2008 10:07:24 -0700
parents 174d749b3f22
children 9d7357dfac4a
line wrap: on
line diff
--- a/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c	Mon Jul 28 09:58:39 2008 -0700
+++ b/usr/src/uts/common/io/scsi/adapters/scsi_vhci/scsi_vhci.c	Mon Jul 28 10:07:24 2008 -0700
@@ -197,7 +197,7 @@
 static void vhci_intr(struct scsi_pkt *);
 static int vhci_do_prout(scsi_vhci_priv_t *);
 static void vhci_run_cmd(void *);
-static int vhci_do_prin(struct vhci_pkt *);
+static int vhci_do_prin(struct vhci_pkt **);
 static struct scsi_pkt *vhci_create_retry_pkt(struct vhci_pkt *);
 static struct vhci_pkt *vhci_sync_retry_pkt(struct vhci_pkt *);
 static struct scsi_vhci_lun *vhci_lun_lookup(dev_info_t *);
@@ -2702,114 +2702,133 @@
  * additional length field equal to the data bytes of the reservation
  * keys to be returned.
  */
+
+#define	VHCI_PRIN_HEADER_SZ (sizeof (prin->length) + sizeof (prin->generation))
+
 static int
-vhci_do_prin(struct vhci_pkt *vpkt)
+vhci_do_prin(struct vhci_pkt **intr_vpkt)
 {
-	scsi_vhci_priv_t *svp = (scsi_vhci_priv_t *)
-	    mdi_pi_get_vhci_private(vpkt->vpkt_path);
+	scsi_vhci_priv_t *svp;
+	struct vhci_pkt *vpkt = *intr_vpkt;
 	vhci_prin_readkeys_t *prin;
-	scsi_vhci_lun_t *vlun = svp->svp_svl;
-	struct scsi_vhci *vhci =
-	    ADDR2VHCI(&(vpkt->vpkt_tgt_pkt->pkt_address));
+	scsi_vhci_lun_t *vlun;
+	struct scsi_vhci *vhci = ADDR2VHCI(&vpkt->vpkt_tgt_pkt->pkt_address);
 
 	struct buf		*new_bp = NULL;
 	struct scsi_pkt		*new_pkt = NULL;
 	struct vhci_pkt		*new_vpkt = NULL;
-	int			hdr_len = 0;
+	uint32_t		needed_length;
 	int			rval = VHCI_CMD_CMPLT;
 	uint32_t		prin_length = 0;
 	uint32_t		svl_prin_length = 0;
 
-	prin = (vhci_prin_readkeys_t *)
-	    bp_mapin_common(vpkt->vpkt_tgt_init_bp, VM_NOSLEEP);
-
-	if (prin != NULL) {
-		prin_length = BE_32(prin->length);
+	ASSERT(vpkt->vpkt_path);
+	svp = mdi_pi_get_vhci_private(vpkt->vpkt_path);
+	ASSERT(svp);
+	vlun = svp->svp_svl;
+	ASSERT(vlun);
+
+	/*
+	 * If the caller only asked for an amount of data that would not
+	 * be enough to include any key data it is likely that they will
+	 * send the next command with a buffer size based on the information
+	 * from this header. Doing recovery on this would be a duplication
+	 * of efforts.
+	 */
+	if (vpkt->vpkt_tgt_init_bp->b_bcount <= VHCI_PRIN_HEADER_SZ) {
+		rval = VHCI_CMD_CMPLT;
+		goto exit;
+	}
+
+	if (vpkt->vpkt_org_vpkt == NULL) {
+		/*
+		 * Can fail as sleep is not allowed.
+		 */
+		prin = (vhci_prin_readkeys_t *)
+		    bp_mapin_common(vpkt->vpkt_tgt_init_bp, VM_NOSLEEP);
+	} else {
+		/*
+		 * The retry buf doesn't need to be mapped in.
+		 */
+		prin = (vhci_prin_readkeys_t *)
+		    vpkt->vpkt_tgt_init_bp->b_un.b_daddr;
 	}
 
 	if (prin == NULL) {
 		VHCI_DEBUG(5, (CE_WARN, NULL,
 		    "vhci_do_prin: bp_mapin_common failed."));
 		rval = VHCI_CMD_ERROR;
-	} else {
-		/*
-		 * According to SPC-3r22, sec 4.3.4.6: "If the amount of
-		 * information to be transferred exceeds the maximum value
-		 * that the ALLOCATION LENGTH field is capable of specifying,
-		 * the device server shall...terminate the command with CHECK
-		 * CONDITION status".  The ALLOCATION LENGTH field of the
-		 * PERSISTENT RESERVE IN command is 2 bytes. We should never
-		 * get here with an ADDITIONAL LENGTH greater than 0xFFFF
-		 * so if we do, then it is an error!
-		 */
-
-		hdr_len = sizeof (prin->length) + sizeof (prin->generation);
-
-		if ((prin_length + hdr_len) > 0xFFFF) {
-			VHCI_DEBUG(5, (CE_NOTE, NULL,
-			    "vhci_do_prin: Device returned invalid "
-			    "length 0x%x\n", prin_length));
-			rval = VHCI_CMD_ERROR;
-		}
-	}
+		goto fail;
+	}
+
+	prin_length = BE_32(prin->length);
+
+	/*
+	 * According to SPC-3r22, sec 4.3.4.6: "If the amount of
+	 * information to be transferred exceeds the maximum value
+	 * that the ALLOCATION LENGTH field is capable of specifying,
+	 * the device server shall...terminate the command with CHECK
+	 * CONDITION status".  The ALLOCATION LENGTH field of the
+	 * PERSISTENT RESERVE IN command is 2 bytes. We should never
+	 * get here with an ADDITIONAL LENGTH greater than 0xFFFF
+	 * so if we do, then it is an error!
+	 */
+
+
+	if ((prin_length + VHCI_PRIN_HEADER_SZ) > 0xFFFF) {
+		VHCI_DEBUG(5, (CE_NOTE, NULL,
+		    "vhci_do_prin: Device returned invalid "
+		    "length 0x%x\n", prin_length));
+		rval = VHCI_CMD_ERROR;
+		goto fail;
+	}
+	needed_length = prin_length + VHCI_PRIN_HEADER_SZ;
 
 	/*
 	 * If prin->length is greater than the byte count allocated in the
 	 * original buffer, then resend the request with enough buffer
 	 * allocated to get all of the available registered keys.
 	 */
-	if (rval != VHCI_CMD_ERROR) {
-		if ((vpkt->vpkt_tgt_init_bp->b_bcount - hdr_len) <
-		    prin_length) {
-			if (vpkt->vpkt_org_vpkt == NULL) {
-				new_pkt = vhci_create_retry_pkt(vpkt);
-				if (new_pkt != NULL) {
-					new_vpkt = TGTPKT2VHCIPKT(new_pkt);
-
-					/*
-					 * This is the buf with buffer pointer
-					 * where the prin readkeys will be
-					 * returned from the device
-					 */
-					new_bp = scsi_alloc_consistent_buf(
-					    &svp->svp_psd->sd_address,
-					    NULL, (prin_length + hdr_len),
-					    (vpkt->vpkt_tgt_init_bp->
-					    b_flags & (B_READ | B_WRITE)),
-					    NULL_FUNC, NULL);
-					if (new_bp != NULL) {
-						if (new_bp->b_un.b_addr !=
-						    NULL) {
-
-							new_bp->b_bcount =
-							    prin_length +
-							    hdr_len;
-
-							new_pkt->pkt_cdbp[7] =
-							    (uchar_t)(new_bp->
-							    b_bcount >> 8);
-							new_pkt->pkt_cdbp[8] =
-							    (uchar_t)new_bp->
-							    b_bcount;
-
-							rval = VHCI_CMD_RETRY;
-						} else {
-							rval = VHCI_CMD_ERROR;
-						}
-					} else {
-						rval = VHCI_CMD_ERROR;
-					}
-				} else {
-					rval = VHCI_CMD_ERROR;
-				}
-			} else {
-				rval = VHCI_CMD_ERROR;
+	if ((vpkt->vpkt_tgt_init_bp->b_bcount < needed_length) &&
+	    (vpkt->vpkt_org_vpkt == NULL)) {
+
+		new_pkt = vhci_create_retry_pkt(vpkt);
+		if (new_pkt == NULL) {
+			rval = VHCI_CMD_ERROR;
+			goto fail;
+		}
+		new_vpkt = TGTPKT2VHCIPKT(new_pkt);
+
+		/*
+		 * This is the buf with buffer pointer
+		 * where the prin readkeys will be
+		 * returned from the device
+		 */
+		new_bp = scsi_alloc_consistent_buf(&svp->svp_psd->sd_address,
+		    NULL, needed_length, B_READ, NULL_FUNC, NULL);
+		if ((new_bp == NULL) || (new_bp->b_un.b_addr == NULL)) {
+			if (new_bp) {
+				scsi_free_consistent_buf(new_bp);
 			}
-		}
+			vhci_scsi_destroy_pkt(&new_pkt->pkt_address, new_pkt);
+			rval = VHCI_CMD_ERROR;
+			goto fail;
+		}
+		new_bp->b_bcount = needed_length;
+		new_pkt->pkt_cdbp[7] = (uchar_t)(needed_length >> 8);
+		new_pkt->pkt_cdbp[8] = (uchar_t)needed_length;
+
+		rval = VHCI_CMD_RETRY;
+
+		new_vpkt->vpkt_tgt_init_bp = new_bp;
 	}
 
 	if (rval == VHCI_CMD_RETRY) {
-		new_vpkt->vpkt_tgt_init_bp = new_bp;
+
+		/*
+		 * There were more keys then the original request asked for.
+		 */
+		mdi_pathinfo_t *path_holder = vpkt->vpkt_path;
 
 		/*
 		 * Release the old path because it does not matter which path
@@ -2826,35 +2845,48 @@
 		 */
 		if (taskq_dispatch(vhci->vhci_taskq, vhci_dispatch_scsi_start,
 		    (void *) new_vpkt, KM_NOSLEEP) == NULL) {
+			if (path_holder) {
+				vpkt->vpkt_path = path_holder;
+				mdi_hold_path(path_holder);
+			}
+			scsi_free_consistent_buf(new_bp);
+			vhci_scsi_destroy_pkt(&new_pkt->pkt_address, new_pkt);
 			rval = VHCI_CMD_ERROR;
-		} else {
-			/*
-			 * If we return VHCI_CMD_RETRY, that means the caller
-			 * is going to bail and wait for the reissued command
-			 * to complete.  In that case, we need to decrement
-			 * the path command count right now.  In any other
-			 * case, it'll be decremented by the caller.
-			 */
-			VHCI_DECR_PATH_CMDCOUNT(svp);
-		}
-	}
-
-	if ((rval != VHCI_CMD_ERROR) && (rval != VHCI_CMD_RETRY)) {
-		int new, old;
-		int data_len = 0;
-
-		data_len = prin_length / MHIOC_RESV_KEY_SIZE;
+			goto fail;
+		}
+
+		/*
+		 * If we return VHCI_CMD_RETRY, that means the caller
+		 * is going to bail and wait for the reissued command
+		 * to complete.  In that case, we need to decrement
+		 * the path command count right now.  In any other
+		 * case, it'll be decremented by the caller.
+		 */
+		VHCI_DECR_PATH_CMDCOUNT(svp);
+		goto exit;
+
+	}
+
+	if (rval == VHCI_CMD_CMPLT) {
+		/*
+		 * The original request got all of the keys or the recovery
+		 * packet returns.
+		 */
+		int new;
+		int old;
+		int num_keys = prin_length / MHIOC_RESV_KEY_SIZE;
+
 		VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_do_prin: %d keys read\n",
-		    data_len));
+		    num_keys));
 
 #ifdef DEBUG
 		VHCI_DEBUG(5, (CE_NOTE, NULL, "vhci_do_prin: from storage\n"));
 		if (vhci_debug == 5)
-			vhci_print_prin_keys(prin, data_len);
+			vhci_print_prin_keys(prin, num_keys);
 		VHCI_DEBUG(5, (CE_NOTE, NULL,
 		    "vhci_do_prin: MPxIO old keys:\n"));
 		if (vhci_debug == 5)
-			vhci_print_prin_keys(&vlun->svl_prin, data_len);
+			vhci_print_prin_keys(&vlun->svl_prin, num_keys);
 #endif
 
 		/*
@@ -2866,14 +2898,23 @@
 
 		new = 0;
 
-		if (data_len > 0) {
+		/*
+		 * If we got at least 1 key copy it.
+		 */
+		if (num_keys > 0) {
 			vlun->svl_prin.keylist[0] = prin->keylist[0];
 			new++;
 		}
 
-		for (old = 1; old < data_len; old++) {
+		/*
+		 * find next unique key.
+		 */
+		for (old = 1; old < num_keys; old++) {
 			int j;
 			int match = 0;
+
+			if (new >= VHCI_NUM_RESV_KEYS)
+				break;
 			for (j = 0; j < new; j++) {
 				if (bcmp(&prin->keylist[old],
 				    &vlun->svl_prin.keylist[j],
@@ -2889,9 +2930,12 @@
 			}
 		}
 
+		/* Stored Big Endian */
 		vlun->svl_prin.generation = prin->generation;
-		svl_prin_length = new * MHIOC_RESV_KEY_SIZE;
+		svl_prin_length = new * sizeof (mhioc_resv_key_t);
+		/* Stored Big Endian */
 		vlun->svl_prin.length = BE_32(svl_prin_length);
+		svl_prin_length += VHCI_PRIN_HEADER_SZ;
 
 		/*
 		 * If we arrived at this point after issuing a retry, make sure
@@ -2904,6 +2948,7 @@
 			scsi_free_consistent_buf(new_bp);
 
 			vpkt = vhci_sync_retry_pkt(vpkt);
+			*intr_vpkt = vpkt;
 
 			/*
 			 * Make sure the original buffer is mapped into kernel
@@ -2918,13 +2963,12 @@
 		 * Now copy the desired number of prin keys into the original
 		 * target buffer.
 		 */
-		if (svl_prin_length <=
-		    (vpkt->vpkt_tgt_init_bp->b_bcount - hdr_len)) {
+		if (svl_prin_length <= vpkt->vpkt_tgt_init_bp->b_bcount) {
 			/*
 			 * It is safe to return all of the available unique
 			 * keys
 			 */
-			bcopy(&vlun->svl_prin, prin, svl_prin_length + hdr_len);
+			bcopy(&vlun->svl_prin, prin, svl_prin_length);
 		} else {
 			/*
 			 * Not all of the available keys were requested by the
@@ -2944,7 +2988,7 @@
 			vhci_print_prin_keys(&vlun->svl_prin, new);
 #endif
 	}
-
+fail:
 	if (rval == VHCI_CMD_ERROR) {
 		/*
 		 * If we arrived at this point after issuing a
@@ -2976,7 +3020,7 @@
 
 		rval = VHCI_CMD_CMPLT;
 	}
-
+exit:
 	/*
 	 * Make sure that the semaphore is only released once.
 	 */
@@ -3202,7 +3246,7 @@
 		 * Command completed successfully, release the dma binding and
 		 * destroy the transport side of the packet.
 		 */
-		if ((pkt->pkt_cdbp[0] ==  SCMD_PROUT) &&
+		if ((pkt->pkt_cdbp[0] == SCMD_PROUT) &&
 		    (((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_REGISTER) ||
 		    ((pkt->pkt_cdbp[1] & 0x1f) == VHCI_PROUT_R_AND_IGNORE))) {
 			if (SCBP_C(pkt) == STATUS_GOOD) {
@@ -3251,7 +3295,7 @@
 				 * vpkt will contain the address of the
 				 * original vpkt
 				 */
-				if (vhci_do_prin(vpkt) == VHCI_CMD_RETRY) {
+				if (vhci_do_prin(&vpkt) == VHCI_CMD_RETRY) {
 					/*
 					 * The command has been resent to get
 					 * all the keys from the device.  Don't