changeset 11853:2adca8ef2c23

6548768 sata framework calls taskq_dispatch with wrong argument - can cause blocking during interrupt 6443107 sata framework: sata commands processing initiated by scsi target driver cannot use KM_SLEEP flag
author Phi Tran <Phi.Tran@Sun.COM>
date Thu, 04 Mar 2010 10:02:10 -0800
parents a53ae86a39c9
children 5351ddd19d45
files usr/src/uts/common/io/sata/impl/sata.c
diffstat 1 files changed, 212 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/impl/sata.c	Thu Mar 04 09:10:33 2010 -0700
+++ b/usr/src/uts/common/io/sata/impl/sata.c	Thu Mar 04 10:02:10 2010 -0800
@@ -2439,11 +2439,19 @@
 		 */
 		if (pkt->pkt_comp != NULL) {
 			/* scsi callback required */
-			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-			    (task_func_t *)pkt->pkt_comp,
-			    (void *)pkt, TQ_NOSLEEP) == NULL)
+			if (servicing_interrupt()) {
+				if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+				    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+				    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) ==
+				    NULL) {
+					return (TRAN_BUSY);
+				}
+			} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 				/* Scheduling the callback failed */
 				return (TRAN_BUSY);
+			}
 			return (TRAN_ACCEPT);
 		}
 		/* No callback available */
@@ -3146,12 +3154,19 @@
 		 */
 		if (spx->txlt_scsi_pkt->pkt_comp != NULL) {
 			/* scsi callback required */
-			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			if (servicing_interrupt()) {
+				if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+				    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+				    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) ==
+				    NULL) {
+					return (TRAN_BUSY);
+				}
+			} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
 			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
-			    (void *)spx->txlt_scsi_pkt,
-			    TQ_SLEEP) == NULL)
+			    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 				/* Scheduling the callback failed */
 				return (TRAN_BUSY);
+			}
 
 			return (TRAN_ACCEPT);
 		}
@@ -3364,14 +3379,21 @@
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
 		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
-		    (void *)spx->txlt_scsi_pkt,
-		    TQ_SLEEP) == NULL)
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 	return (TRAN_ACCEPT);
 }
 
@@ -3405,14 +3427,22 @@
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
-	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsi_hba_pkt_comp,
-		    (void *)spx->txlt_scsi_pkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 	return (TRAN_ACCEPT);
 }
 
@@ -3447,14 +3477,21 @@
 	    spx->txlt_scsi_pkt->pkt_reason);
 
 	if ((spx->txlt_scsi_pkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    spx->txlt_scsi_pkt->pkt_comp != NULL)
+	    spx->txlt_scsi_pkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
 		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
-		    (void *)spx->txlt_scsi_pkt,
-		    TQ_SLEEP) == NULL)
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 	return (TRAN_ACCEPT);
 }
 
@@ -3668,11 +3705,18 @@
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
 	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
 	}
 	return (TRAN_ACCEPT);
 }
@@ -3807,13 +3851,22 @@
 	    "Scsi_pkt completion reason %x\n",
 	    scsipkt->pkt_reason);
 
-	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 	return (TRAN_ACCEPT);
 }
 
@@ -3890,13 +3943,22 @@
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
-	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 
 	return (TRAN_ACCEPT);
 }
@@ -4229,11 +4291,19 @@
 	    "synchronous execution status %x\n",
 	    spx->txlt_sata_pkt->satapkt_reason);
 
-	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0) {
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
+	    scsipkt->pkt_comp != NULL) {
 		sata_set_arq_data(spx->txlt_sata_pkt);
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsi_hba_pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == 0) {
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
+			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
 		}
 	}
@@ -4319,13 +4389,21 @@
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 
 	return (TRAN_ACCEPT);
 }
@@ -4360,7 +4438,14 @@
 	    spx->txlt_scsi_pkt->pkt_cdbp[2] >> 6,
 	    spx->txlt_scsi_pkt->pkt_cdbp[2] & 0x3f);
 
-	buf = kmem_zalloc(1024, KM_SLEEP);
+	if (servicing_interrupt()) {
+		buf = kmem_zalloc(1024, KM_NOSLEEP);
+		if (buf == NULL) {
+			return (TRAN_BUSY);
+		}
+	} else {
+		buf = kmem_zalloc(1024, KM_SLEEP);
+	}
 
 	mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx)));
 
@@ -4590,13 +4675,21 @@
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 
 	return (TRAN_ACCEPT);
 }
@@ -4910,13 +5003,21 @@
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 
 	return (rval);
 }
@@ -5182,7 +5283,14 @@
 	    spx->txlt_scsi_pkt->pkt_cdbp[2] >> 6,
 	    spx->txlt_scsi_pkt->pkt_cdbp[2] & 0x3f);
 
-	buf = kmem_zalloc(MAX_LOG_SENSE_PAGE_SIZE, KM_SLEEP);
+	if (servicing_interrupt()) {
+		buf = kmem_zalloc(MAX_LOG_SENSE_PAGE_SIZE, KM_NOSLEEP);
+		if (buf == NULL) {
+			return (TRAN_BUSY);
+		}
+	} else {
+		buf = kmem_zalloc(MAX_LOG_SENSE_PAGE_SIZE, KM_SLEEP);
+	}
 
 	mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx)));
 
@@ -5395,13 +5503,21 @@
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 
 	return (TRAN_ACCEPT);
 }
@@ -6124,11 +6240,17 @@
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
 	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == 0) {
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
-			rval = TRAN_BUSY;
+			return (TRAN_BUSY);
 		}
 	}
 	return (rval);
@@ -6545,13 +6667,21 @@
 	    "Scsi_pkt completion reason %x\n", scsipkt->pkt_reason);
 
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 	return (TRAN_ACCEPT);
 }
 
@@ -6679,13 +6809,21 @@
 	sense->es_add_code = SD_SCSI_ASC_INVALID_FIELD_IN_CDB;
 
 	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
-	    scsipkt->pkt_comp != NULL)
+	    scsipkt->pkt_comp != NULL) {
 		/* scsi callback required */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp, (void *) scsipkt,
-		    TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
+	}
 
 	return (TRAN_ACCEPT);
 }
@@ -6707,11 +6845,18 @@
 	*scsipkt->pkt_scbp = STATUS_GOOD;
 	if (!(spx->txlt_sata_pkt->satapkt_op_mode & SATA_OPMODE_SYNCH)) {
 		/* scsi callback required - have to schedule it */
-		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
-		    (task_func_t *)scsipkt->pkt_comp,
-		    (void *)scsipkt, TQ_SLEEP) == NULL)
+		if (servicing_interrupt()) {
+			if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+			    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+			    (void *)spx->txlt_scsi_pkt, TQ_NOSLEEP) == NULL) {
+				return (TRAN_BUSY);
+			}
+		} else if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
 			/* Scheduling the callback failed */
 			return (TRAN_BUSY);
+		}
 	}
 	return (TRAN_ACCEPT);
 }