changeset 276:7c784ab26b5a

6239895 scsa1394: panic seen when doing a cp -r to a mounted hard drive 6260568 scsa1394 panics kernel when attempting to access firewire disk 6262353 scsa1394: assertion failed: num_cmds != 0, file: ../../common/io/1394/t1394.c 6271950 scsa1394 support for vold hotplug 6272461 Null pointer panic in sbp2_ses_remove_task_locked() 6273456 panic seen when restarting vold on an SB2500 with a firewire disk
author artem
date Tue, 02 Aug 2005 16:40:23 -0700
parents b765b3d4d672
children 1e4ddc05e491
files usr/src/uts/common/io/1394/targets/scsa1394/hba.c usr/src/uts/common/io/1394/targets/scsa1394/sbp2_driver.c usr/src/uts/common/io/sbp2/sbp2.c usr/src/uts/common/sys/1394/targets/scsa1394/impl.h
diffstat 4 files changed, 86 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/1394/targets/scsa1394/hba.c	Tue Aug 02 14:37:02 2005 -0700
+++ b/usr/src/uts/common/io/1394/targets/scsa1394/hba.c	Tue Aug 02 16:40:23 2005 -0700
@@ -873,12 +873,15 @@
 			return (DDI_FAILURE);
 		}
 
-		ret = scsa1394_sbp2_login(sp, lun);
-
-		return (ret);
+		if (scsa1394_dev_is_online(sp)) {
+			return (scsa1394_sbp2_login(sp, lun));
+		} else {
+			return (DDI_FAILURE);
+		}
 	}
 
-	if ((lun >= sp->s_nluns) || (sp->s_lun[lun].l_cdip != NULL)) {
+	if ((lun >= sp->s_nluns) || (sp->s_lun[lun].l_cdip != NULL) ||
+	    !scsa1394_dev_is_online(sp)) {
 		return (DDI_FAILURE);
 	}
 
@@ -1447,6 +1450,7 @@
 			ddi_dma_free_handle(&cmd->sc_buf_dma_hdl);
 			return (DDI_FAILURE);
 		}
+		lp->l_stat.stat_cmd_buf_dma_partial++;
 		break;
 
 	case DDI_DMA_NORESOURCES:
@@ -1546,8 +1550,12 @@
 		nsegs = max(ccount, cmd->sc_win_len / SBP2_PT_SEGSIZE_MAX) * 2;
 		segsize_max = SBP2_PT_SEGSIZE_MAX;
 	} else {
-		/* For Symbios workaround we know exactly the number of pages */
-		nsegs = howmany(cmd->sc_win_len, scsa1394_symbios_page_size);
+		/*
+		 * For Symbios workaround we know exactly the number of segments
+		 * Additional segment may be needed if buffer is not aligned.
+		 */
+		nsegs =
+		    howmany(cmd->sc_win_len, scsa1394_symbios_page_size) + 1;
 		segsize_max = scsa1394_symbios_page_size;
 	}
 
@@ -1777,7 +1785,9 @@
 	/*
 	 * setup page table if needed
 	 */
-	if ((ccount == 1) && (dmac.dmac_size <= SBP2_PT_SEGSIZE_MAX)) {
+	if ((ccount == 1) && (dmac.dmac_size <= SBP2_PT_SEGSIZE_MAX) &&
+	    (!sp->s_symbios ||
+	    (dmac.dmac_size <= scsa1394_symbios_page_size))) {
 		/* but first, free old resources */
 		if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_PT_VALID) {
 			scsa1394_cmd_pt_dma_free(sp, cmd);
@@ -1823,19 +1833,6 @@
 	scsa1394_lun_t	*lp = cmd->sc_lun;
 	int		ret;
 
-	mutex_enter(&sp->s_mutex);
-	if (sp->s_dev_state != SCSA1394_DEV_ONLINE) {
-		if (sp->s_dev_state == SCSA1394_DEV_BUS_RESET) {
-			/* this should prevent scary console messages */
-			mutex_exit(&sp->s_mutex);
-			return (TRAN_BUSY);
-		} else {
-			mutex_exit(&sp->s_mutex);
-			return (TRAN_FATAL_ERROR);
-		}
-	}
-	mutex_exit(&sp->s_mutex);
-
 	/*
 	 * since we don't support polled I/O, just accept the packet
 	 * so the rest of the file systems get synced properly
@@ -1850,6 +1847,20 @@
 		return (TRAN_BADPKT);
 	}
 
+	mutex_enter(&sp->s_mutex);
+	if (sp->s_dev_state != SCSA1394_DEV_ONLINE) {
+		/*
+		 * If device is temporarily gone due to bus reset,
+		 * return busy to prevent prevent scary console messages.
+		 * If permanently gone, leave it to scsa1394_cmd_fake_comp().
+		 */
+		if (sp->s_dev_state == SCSA1394_DEV_BUS_RESET) {
+			mutex_exit(&sp->s_mutex);
+			return (TRAN_BUSY);
+		}
+	}
+	mutex_exit(&sp->s_mutex);
+
 	if ((ap->a_lun >= sp->s_nluns) ||
 	    (ap->a_lun != pkt->pkt_address.a_lun)) {
 		return (TRAN_BADPKT);
@@ -1967,9 +1978,12 @@
 	case SCMD_WRITE_LONG:
 		lba = SCSA1394_LBA_10BYTE(pkt);
 		len = SCSA1394_LEN_10BYTE(pkt);
-		sz = SCSA1394_CDRW_BLKSZ(bp->b_bcount, len);
-		if (SCSA1394_VALID_CDRW_BLKSZ(sz)) {
-			blk_size = sz;
+		if ((lp->l_dtype_orig == DTYPE_RODIRECT) &&
+		    (bp != NULL) && (len != 0)) {
+			sz = SCSA1394_CDRW_BLKSZ(bp->b_bcount, len);
+			if (SCSA1394_VALID_CDRW_BLKSZ(sz)) {
+				blk_size = sz;
+			}
 		}
 		break;
 	case SCMD_READ_CD:
@@ -1990,12 +2004,12 @@
 		scsa1394_cmd_fill_cdb_other(lp, cmd);
 		return;
 	}
+	cmd->sc_blk_size = blk_size;
 
 	/* limit xfer length for Symbios workaround */
 	if (sp->s_symbios && (len * blk_size > scsa1394_symbios_size_max)) {
 		cmd->sc_flags |= SCSA1394_CMD_SYMBIOS_BREAKUP;
 
-		cmd->sc_blk_size = blk_size;
 		cmd->sc_total_blks = cmd->sc_resid_blks = len;
 
 		len = scsa1394_symbios_size_max / blk_size;
@@ -2026,9 +2040,12 @@
 {
 	struct scsi_pkt	*pkt = CMD2PKT(cmd);
 
-	bcopy(pkt->pkt_cdbp, cmd->sc_cdb, cmd->sc_cdb_len);
+	cmd->sc_xfer_bytes = cmd->sc_win_len;
+	cmd->sc_xfer_blks = cmd->sc_xfer_bytes / lp->l_lba_size;
+	cmd->sc_total_blks = cmd->sc_xfer_blks;
+	cmd->sc_lba = 0;
 
-	cmd->sc_xfer_bytes = cmd->sc_win_len;
+	bcopy(pkt->pkt_cdbp, cmd->sc_cdb, cmd->sc_cdb_len);
 }
 
 /*
@@ -2163,6 +2180,21 @@
 	scsa1394_lun_t	*lp = cmd->sc_lun;
 	int		ret = DDI_SUCCESS;
 
+	/*
+	 * agreement with sd in case of device hot removal
+	 * is to fake completion with CMD_DEV_GONE
+	 */
+	mutex_enter(&sp->s_mutex);
+	if (sp->s_dev_state != SCSA1394_DEV_ONLINE) {
+		mutex_exit(&sp->s_mutex);
+		pkt->pkt_reason = CMD_DEV_GONE;
+		if (pkt->pkt_comp) {
+			(*pkt->pkt_comp)(pkt);
+		}
+		return (DDI_SUCCESS);
+	}
+	mutex_exit(&sp->s_mutex);
+
 	mutex_enter(&lp->l_mutex);
 
 	switch (pkt->pkt_cdbp[0]) {
--- a/usr/src/uts/common/io/1394/targets/scsa1394/sbp2_driver.c	Tue Aug 02 14:37:02 2005 -0700
+++ b/usr/src/uts/common/io/1394/targets/scsa1394/sbp2_driver.c	Tue Aug 02 16:40:23 2005 -0700
@@ -497,36 +497,44 @@
 static void
 scsa1394_sbp2_seg2pt_symbios(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
 {
-	size_t		offset;
-	int		start_page;
 	sbp2_pt_unrestricted_t *pt;
 	scsa1394_cmd_seg_t *seg;
-	size_t		resid;
 	int		nsegs;
+	size_t		resid, skiplen, dataoff, segoff, seglen;
+	uint64_t	baddr;
 
-	/* calculate page table address and size */
+	/* data offset within command */
 	if (cmd->sc_flags & SCSA1394_CMD_SYMBIOS_BREAKUP) {
-		offset = (cmd->sc_total_blks - cmd->sc_resid_blks) *
+		dataoff = (cmd->sc_total_blks - cmd->sc_resid_blks) *
 		    cmd->sc_blk_size;
 	} else {
-		offset = 0;
+		dataoff = 0;
 	}
-	start_page = offset / scsa1394_symbios_page_size;
+
+	/* skip dataoff bytes */
+	seg = &cmd->sc_buf_seg[0];
+	skiplen = 0;
+	while (skiplen + seg->ss_len <= dataoff) {
+		skiplen += seg->ss_len;
+		seg++;
+	}
+	segoff = dataoff - skiplen; /* offset within segment */
 
 	pt = (sbp2_pt_unrestricted_t *)cmd->sc_pt_kaddr;
-	seg = &cmd->sc_buf_seg[start_page];
 	resid = cmd->sc_xfer_bytes;
 	nsegs = 0;
 	while (resid > 0) {
 		ASSERT(seg->ss_len <= scsa1394_symbios_page_size);
 
-		pt->pt_seg_len = min(seg->ss_len, resid);
-		resid -= pt->pt_seg_len;
-		SBP2_SWAP16_1(pt->pt_seg_len);
+		seglen = min(seg->ss_len, resid) - segoff;
+		baddr = seg->ss_baddr + segoff;
 
-		pt->pt_seg_base_hi = SBP2_SWAP16(seg->ss_baddr >> 32);
-		pt->pt_seg_base_lo = SBP2_SWAP32(seg->ss_baddr & 0xFFFFFFFF);
+		pt->pt_seg_len = SBP2_SWAP16(seglen);
+		pt->pt_seg_base_hi = SBP2_SWAP16(baddr >> 32);
+		pt->pt_seg_base_lo = SBP2_SWAP32(baddr & 0xFFFFFFFF);
 
+		segoff = 0;
+		resid -= seglen;
 		nsegs++;
 		pt++;
 		seg++;
--- a/usr/src/uts/common/io/sbp2/sbp2.c	Tue Aug 02 14:37:02 2005 -0700
+++ b/usr/src/uts/common/io/sbp2/sbp2.c	Tue Aug 02 16:40:23 2005 -0700
@@ -389,9 +389,11 @@
 	}
 	if (tp->t_mgt_cmd) {
 		SBP2_FREE_CMD(tp, tp->t_mgt_cmd);
+		tp->t_mgt_cmd = NULL;
 	}
 	if (tp->t_mgt_cmd_data) {
 		freeb(tp->t_mgt_cmd_data);
+		tp->t_mgt_cmd_data = NULL;
 	}
 }
 
@@ -951,7 +953,7 @@
 	 * otherwise use callback.
 	 */
 	callback = (ap->a_active_task != new_task);
-	task = ap->a_active_task;
+	ASSERT(task == ap->a_active_task);
 	ap->a_active_task = NULL;
 	mutex_exit(&ap->a_mutex);
 	sbp2_agent_release(ap);
@@ -961,12 +963,12 @@
 	 * to SBP2_TASK_COMP while it's still on the list, to avoid race with
 	 * upper layer driver (e.g. scsa1394).
 	 */
-	ret = sbp2_ses_remove_task(sp, new_task);
+	ret = sbp2_ses_remove_task(sp, task);
 	ASSERT(ret == SBP2_SUCCESS);
-	new_task->ts_state = SBP2_TASK_COMP;
+	task->ts_state = SBP2_TASK_COMP;
 
 	if (callback) {
-		sp->s_status_cb(sp->s_status_cb_arg, new_task);
+		sp->s_status_cb(sp->s_status_cb_arg, task);
 		return (SBP2_SUCCESS);
 	} else {
 		/* upper layer driver is responsible to call nudge */
--- a/usr/src/uts/common/sys/1394/targets/scsa1394/impl.h	Tue Aug 02 14:37:02 2005 -0700
+++ b/usr/src/uts/common/sys/1394/targets/scsa1394/impl.h	Tue Aug 02 16:40:23 2005 -0700
@@ -95,6 +95,7 @@
 
 	uint_t			stat_cmd_cnt;	/* # of commands submitted */
 	uint_t			stat_cmd_buf_max_nsegs;
+	uint_t			stat_cmd_buf_dma_partial;
 
 	/*
 	 * errors