Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 25 Jan 2012 23:33:50 +0000 (UTC)
From:      Sean Bruno <sbruno@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r230558 - head/sys/dev/firewire
Message-ID:  <201201252333.q0PNXoWK050308@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sbruno
Date: Wed Jan 25 23:33:50 2012
New Revision: 230558
URL: http://svn.freebsd.org/changeset/base/230558

Log:
  Update sbp_targ such that it can actually handle multiple CTIO's during operation
  
  PR:	kern/119575

Modified:
  head/sys/dev/firewire/sbp_targ.c

Modified: head/sys/dev/firewire/sbp_targ.c
==============================================================================
--- head/sys/dev/firewire/sbp_targ.c	Wed Jan 25 22:39:22 2012	(r230557)
+++ head/sys/dev/firewire/sbp_targ.c	Wed Jan 25 23:33:50 2012	(r230558)
@@ -62,6 +62,7 @@
 #include <cam/cam_debug.h>
 #include <cam/cam_periph.h>
 #include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_message.h>
 
 #define SBP_TARG_RECV_LEN	8
 #define MAX_INITIATORS		8
@@ -186,6 +187,21 @@ struct morb4 {
 #endif
 };
 
+ 
+/*
+ * Urestricted page table format 
+ * states that the segment length
+ * and high base addr are in the first
+ * 32 bits and the base low is in 
+ * the second
+ */
+struct unrestricted_page_table_fmt {
+	uint16_t segment_len;
+	uint16_t segment_base_high;
+	uint32_t segment_base_low;
+};
+
+
 struct orb_info {
 	struct sbp_targ_softc *sc;
 	struct fw_device *fwdev;
@@ -208,7 +224,10 @@ struct orb_info {
 	struct corb4 orb4;
 	STAILQ_ENTRY(orb_info) link;
 	uint32_t orb[8];
-	uint32_t *page_table;
+	struct unrestricted_page_table_fmt *page_table;
+	struct unrestricted_page_table_fmt *cur_pte;
+	struct unrestricted_page_table_fmt *last_pte;
+	uint32_t  last_block_read;
 	struct sbp_status status;
 };
 
@@ -219,6 +238,7 @@ static char *orb_fun_name[] = {
 static void sbp_targ_recv(struct fw_xfer *);
 static void sbp_targ_fetch_orb(struct sbp_targ_softc *, struct fw_device *,
     uint16_t, uint32_t, struct sbp_targ_login *, int);
+static void sbp_targ_xfer_pt(struct orb_info *);
 static void sbp_targ_abort(struct sbp_targ_softc *, struct orb_info *);
 
 static void
@@ -252,13 +272,19 @@ sbp_targ_dealloc_login(struct sbp_targ_l
 	}
 	for (orbi = STAILQ_FIRST(&login->orbs); orbi != NULL; orbi = next) {
 		next = STAILQ_NEXT(orbi, link);
+		if (debug)
+			printf("%s: free orbi %p\n", __func__, orbi);
 		free(orbi, M_SBP_TARG);
+		orbi = NULL;
 	}
 	callout_stop(&login->hold_callout);
 
 	STAILQ_REMOVE(&login->lstate->logins, login, sbp_targ_login, link);
 	login->lstate->sc->logins[login->id] = NULL;
+	if (debug)
+		printf("%s: free login %p\n", __func__, login);
 	free((void *)login, M_SBP_TARG);
+	login = NULL;
 }
 
 static void
@@ -361,20 +387,26 @@ sbp_targ_find_devs(struct sbp_targ_softc
 	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD &&
 	    ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
 		*lstate = sc->black_hole;
+		if (debug)
+			printf("setting black hole for this target id(%d)\n", ccb->ccb_h.target_id);
 		return (CAM_REQ_CMP);
 	}
 
-	if (ccb->ccb_h.target_id != 0)
-		return (CAM_TID_INVALID);
-
 	lun = ccb->ccb_h.target_lun;
 	if (lun >= MAX_LUN)
 		return (CAM_LUN_INVALID);
 	
 	*lstate = sc->lstate[lun];
 
-	if (notfound_failure != 0 && *lstate == NULL)
+	if (notfound_failure != 0 && *lstate == NULL) {
+		if (debug)
+			printf("%s: lstate for lun is invalid, target(%d), lun(%d)\n",
+				__func__, ccb->ccb_h.target_id, lun);
 		return (CAM_PATH_INVALID);
+	} else
+		if (debug)
+			printf("%s: setting lstate for tgt(%d) lun(%d)\n",
+				__func__,ccb->ccb_h.target_id, lun);
 
 	return (CAM_REQ_CMP);
 }
@@ -411,11 +443,18 @@ sbp_targ_en_lun(struct sbp_targ_softc *s
 			printf("Couldn't allocate lstate\n");
 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
 			return;
-		}
-		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD)
+		} else {
+			if (debug)
+				printf("%s: malloc'd lstate %p\n",__func__, lstate);
+		}	
+		if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD) {
 			sc->black_hole = lstate;
-		else
+			if (debug)
+				printf("Blackhole set due to target id == %d\n",
+					ccb->ccb_h.target_id);
+		} else
 			sc->lstate[ccb->ccb_h.target_lun] = lstate;
+
 		memset(lstate, 0, sizeof(*lstate));
 		lstate->sc = sc;
 		status = xpt_create_path(&lstate->path, /*periph*/NULL,
@@ -424,6 +463,7 @@ sbp_targ_en_lun(struct sbp_targ_softc *s
 					 xpt_path_lun_id(ccb->ccb_h.path));
 		if (status != CAM_REQ_CMP) {
 			free(lstate, M_SBP_TARG);
+			lstate = NULL;
 			xpt_print_path(ccb->ccb_h.path);
 			printf("Couldn't allocate path\n");
 			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
@@ -443,6 +483,7 @@ sbp_targ_en_lun(struct sbp_targ_softc *s
 
 		if (lstate == NULL) {
 			ccb->ccb_h.status = CAM_LUN_INVALID;
+			printf("Invalid lstate for this target\n");
 			return;
 		}
 		ccb->ccb_h.status = CAM_REQ_CMP;
@@ -458,6 +499,7 @@ sbp_targ_en_lun(struct sbp_targ_softc *s
 		}
 
 		if (ccb->ccb_h.status != CAM_REQ_CMP) {
+			printf("status != CAM_REQ_CMP\n");
 			return;
 		}
 
@@ -475,7 +517,10 @@ sbp_targ_en_lun(struct sbp_targ_softc *s
 			sc->black_hole = NULL;
 		else
 			sc->lstate[ccb->ccb_h.target_lun] = NULL;
+		if (debug)
+			printf("%s: free lstate %p\n", __func__, lstate);
 		free(lstate, M_SBP_TARG);
+		lstate = NULL;
 
 		/* bus reset */
 		sc->fd.fc->ibr(sc->fd.fc);
@@ -538,7 +583,7 @@ sbp_targ_get_orb_info(struct sbp_targ_ls
 		if (orbi->orb_lo == tag_id)
 			goto found;
 	printf("%s: orb not found tag_id=0x%08x init_id=%d\n",
-				 __func__, tag_id, init_id);
+			 __func__, tag_id, init_id);
 	return (NULL);
 found:
 	return (orbi);
@@ -559,12 +604,13 @@ sbp_targ_abort(struct sbp_targ_softc *sc
 				xpt_done(orbi->ccb);
 				orbi->ccb = NULL;
 			}
-#if 0
 			if (orbi->state <= ORBI_STATUS_ATIO) {
 				sbp_targ_remove_orb_info_locked(orbi->login, orbi);
+				if (debug)
+					printf("%s: free orbi %p\n", __func__, orbi);
 				free(orbi, M_SBP_TARG);
+				orbi = NULL;
 			} else
-#endif
 				orbi->state = ORBI_STATUS_ABORTED;
 		}
 	}
@@ -576,12 +622,21 @@ sbp_targ_free_orbi(struct fw_xfer *xfer)
 {
 	struct orb_info *orbi;
 
-	orbi = (struct orb_info *)xfer->sc;
 	if (xfer->resp != 0) {
 		/* XXX */
 		printf("%s: xfer->resp = %d\n", __func__, xfer->resp);
 	}
+	orbi = (struct orb_info *)xfer->sc;
+	if ( orbi->page_table != NULL ) {
+		if (debug)
+			printf("%s:  free orbi->page_table %p\n", __func__, orbi->page_table);
+		free(orbi->page_table, M_SBP_TARG);
+		orbi->page_table = NULL;
+	}
+	if (debug)
+		printf("%s: free orbi %p\n", __func__, orbi);
 	free(orbi, M_SBP_TARG);
+	orbi = NULL;
 	fw_xfer_free(xfer);
 }
 
@@ -595,7 +650,7 @@ sbp_targ_status_FIFO(struct orb_info *or
 		sbp_targ_remove_orb_info(orbi->login, orbi);
 
 	xfer = fwmem_write_block(orbi->fwdev, (void *)orbi,
-	    /*spd*/2, fifo_hi, fifo_lo,
+	    /*spd*/FWSPD_S400, fifo_hi, fifo_lo,
 	    sizeof(uint32_t) * (orbi->status.len + 1), (char *)&orbi->status,
 	    sbp_targ_free_orbi);
 
@@ -605,6 +660,10 @@ sbp_targ_status_FIFO(struct orb_info *or
 	}
 }
 
+/*
+ * Generate the appropriate CAM status for the
+ * target.
+ */
 static void
 sbp_targ_send_status(struct orb_info *orbi, union ccb *ccb)
 {
@@ -621,6 +680,8 @@ sbp_targ_send_status(struct orb_info *or
 	sbp_status->status = 0; /* XXX */
 	sbp_status->dead = 0; /* XXX */
 
+	ccb->ccb_h.status= CAM_REQ_CMP;
+
 	switch (ccb->csio.scsi_status) {
 	case SCSI_STATUS_OK:
 		if (debug)
@@ -628,8 +689,15 @@ sbp_targ_send_status(struct orb_info *or
 		sbp_status->len = 1;
 		break;
 	case SCSI_STATUS_CHECK_COND:
+		if (debug)
+			printf("%s: STATUS SCSI_STATUS_CHECK_COND\n", __func__);
+		goto process_scsi_status;
 	case SCSI_STATUS_BUSY:
+		if (debug)
+			printf("%s: STATUS SCSI_STATUS_BUSY\n", __func__);
+		goto process_scsi_status;
 	case SCSI_STATUS_CMD_TERMINATED:
+process_scsi_status:
 	{
 		struct sbp_cmd_status *sbp_cmd_status;
 		struct scsi_sense_data *sense;
@@ -640,9 +708,6 @@ sbp_targ_send_status(struct orb_info *or
 		int64_t sinfo;
 		int sense_len;
 
-		if (debug)
-			printf("%s: STATUS %d\n", __func__,
-			    ccb->csio.scsi_status);
 		sbp_cmd_status = (struct sbp_cmd_status *)&sbp_status->data[0];
 		sbp_cmd_status->status = ccb->csio.scsi_status;
 		sense = &ccb->csio.sense_data;
@@ -734,6 +799,7 @@ sbp_targ_send_status(struct orb_info *or
 		if (scsi_get_sks(sense, sense_len, sks) == 0) {
 			bcopy(sks, &sbp_cmd_status->s_keydep[0], sizeof(sks));
 			sbp_status->len = 5;
+			ccb->ccb_h.status |= CAM_SENT_SENSE;
 		}
 
 		break;
@@ -743,13 +809,20 @@ sbp_targ_send_status(struct orb_info *or
 		    sbp_status->status);
 	}
 
-	if (orbi->page_table != NULL)
-		free(orbi->page_table, M_SBP_TARG);
 
 	sbp_targ_status_FIFO(orbi,
 	    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
 }
 
+/*
+ * Invoked as a callback handler from fwmem_read/write_block
+ *
+ * Process read/write of initiator address space
+ * completion and pass status onto the backend target.
+ * If this is a partial read/write for a CCB then
+ * we decrement the orbi's refcount to indicate
+ * the status of the read/write is complete
+ */
 static void
 sbp_targ_cam_done(struct fw_xfer *xfer)
 {
@@ -758,7 +831,7 @@ sbp_targ_cam_done(struct fw_xfer *xfer)
 
 	orbi = (struct orb_info *)xfer->sc;
 
-	if (debug > 1)
+	if (debug)
 		printf("%s: resp=%d refcount=%d\n", __func__,
 			xfer->resp, orbi->refcount);
 
@@ -779,13 +852,26 @@ sbp_targ_cam_done(struct fw_xfer *xfer)
 			if (debug)
 				printf("%s: orbi aborted\n", __func__);
 			sbp_targ_remove_orb_info(orbi->login, orbi);
-			if (orbi->page_table != NULL)
+			if (orbi->page_table != NULL) {
+				if (debug)
+					printf("%s: free orbi->page_table %p\n",
+						__func__, orbi->page_table);
 				free(orbi->page_table, M_SBP_TARG);
+			}
+			if (debug)
+				printf("%s: free orbi %p\n", __func__, orbi);
 			free(orbi, M_SBP_TARG);
-		} else if (orbi->status.resp == 0) {
-			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0)
+			orbi = NULL;
+		} else if (orbi->status.resp == ORBI_STATUS_NONE) {
+			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
+				if (debug) 
+					printf("%s: CAM_SEND_STATUS set %0x\n", __func__, ccb->ccb_h.flags);
 				sbp_targ_send_status(orbi, ccb);
-			ccb->ccb_h.status = CAM_REQ_CMP;
+			} else {
+				if (debug)
+					printf("%s: CAM_SEND_STATUS not set %0x\n", __func__, ccb->ccb_h.flags);
+				ccb->ccb_h.status = CAM_REQ_CMP;
+			}
 			SBP_LOCK(orbi->sc);
 			xpt_done(ccb);
 			SBP_UNLOCK(orbi->sc);
@@ -855,6 +941,13 @@ sbp_targ_abort_ccb(struct sbp_targ_softc
 	return (CAM_PATH_INVALID);
 }
 
+/*
+ * directly execute a read or write to the initiator
+ * address space and set hand(sbp_targ_cam_done) to 
+ * process the completion from the SIM to the target.
+ * set orbi->refcount to inidicate that a read/write
+ * is inflight to/from the initiator.
+ */
 static void
 sbp_targ_xfer_buf(struct orb_info *orbi, u_int offset,
     uint16_t dst_hi, uint32_t dst_lo, u_int size,
@@ -874,16 +967,21 @@ sbp_targ_xfer_buf(struct orb_info *orbi,
 		len = MIN(size, 2048 /* XXX */);
 		size -= len;
 		orbi->refcount ++;
-		if (ccb_dir == CAM_DIR_OUT)
+		if (ccb_dir == CAM_DIR_OUT) {
+			if (debug)
+				printf("%s: CAM_DIR_OUT --> read block in?\n",__func__);
 			xfer = fwmem_read_block(orbi->fwdev,
-			   (void *)orbi, /*spd*/2,
+			   (void *)orbi, /*spd*/FWSPD_S400,
 			    dst_hi, dst_lo + off, len,
 			    ptr + off, hand);
-		else
+		} else {
+			if (debug)
+				printf("%s: CAM_DIR_IN --> write block out?\n",__func__);
 			xfer = fwmem_write_block(orbi->fwdev,
-			   (void *)orbi, /*spd*/2,
+			   (void *)orbi, /*spd*/FWSPD_S400,
 			    dst_hi, dst_lo + off, len,
 			    ptr + off, hand);
+		}
 		if (xfer == NULL) {
 			printf("%s: xfer == NULL", __func__);
 			/* XXX what should we do?? */
@@ -897,18 +995,22 @@ static void
 sbp_targ_pt_done(struct fw_xfer *xfer)
 {
 	struct orb_info *orbi;
-	union ccb *ccb;
-	u_int i, offset, res, len;
-	uint32_t t1, t2, *p;
+	struct unrestricted_page_table_fmt *pt;
+	uint32_t i;
 
 	orbi = (struct orb_info *)xfer->sc;
-	ccb = orbi->ccb;
+
 	if (orbi->state == ORBI_STATUS_ABORTED) {
 		if (debug)
 			printf("%s: orbi aborted\n", __func__);
 		sbp_targ_remove_orb_info(orbi->login, orbi);
+		if (debug) {
+			printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
+			printf("%s: free orbi %p\n", __func__, orbi);
+		}
 		free(orbi->page_table, M_SBP_TARG);
 		free(orbi, M_SBP_TARG);
+		orbi = NULL;
 		fw_xfer_free(xfer);
 		return;
 	}
@@ -920,60 +1022,158 @@ sbp_targ_pt_done(struct fw_xfer *xfer)
 		orbi->status.len = 1;
 		sbp_targ_abort(orbi->sc, STAILQ_NEXT(orbi, link));
 
+		if (debug)
+			printf("%s: free orbi->page_table %p\n", __func__, orbi->page_table);
+
 		sbp_targ_status_FIFO(orbi,
 		    orbi->login->fifo_hi, orbi->login->fifo_lo, /*dequeue*/1);
 		free(orbi->page_table, M_SBP_TARG);
+		orbi->page_table = NULL;
 		fw_xfer_free(xfer);
 		return;
 	}
-	res = ccb->csio.dxfer_len;
-	offset = 0;
-	if (debug)
-		printf("%s: dxfer_len=%d\n", __func__, res);
-	orbi->refcount ++;
-	for (p = orbi->page_table, i = orbi->orb4.data_size; i > 0; i --) {
-		t1 = ntohl(*p++);
-		t2 = ntohl(*p++);
-		if (debug > 1)
-			printf("page_table: %04x:%08x %d\n", 
-			    t1 & 0xffff, t2, t1>>16);
-		len = MIN(t1 >> 16, res);
-		res -= len;
-		sbp_targ_xfer_buf(orbi, offset, t1 & 0xffff, t2, len,
-		    sbp_targ_cam_done);
-		offset += len;
-		if (res == 0)
-			break;
+	orbi->refcount++;
+/*
+ * Set endianess here so we don't have 
+ * to deal with is later
+ */
+	for (i = 0, pt = orbi->page_table; i < orbi->orb4.data_size; i++, pt++) {
+		pt->segment_len = ntohs(pt->segment_len);
+		if (debug)
+			printf("%s:segment_len = %u\n", __func__,pt->segment_len);
+		pt->segment_base_high = ntohs(pt->segment_base_high);
+		pt->segment_base_low = ntohl(pt->segment_base_low);
 	}
-	orbi->refcount --;
+
+	sbp_targ_xfer_pt(orbi);
+
+	orbi->refcount--;
 	if (orbi->refcount == 0)
 		printf("%s: refcount == 0\n", __func__);
-	if (res !=0)
-		/* XXX handle res != 0 case */
-		printf("%s: page table is too small(%d)\n", __func__, res);
 
 	fw_xfer_free(xfer);
 	return;
 }
 
+static void sbp_targ_xfer_pt(struct orb_info *orbi)
+{
+	union ccb *ccb;
+	uint32_t res, offset, len;
+
+	ccb = orbi->ccb;
+	if (debug)
+		printf("%s: dxfer_len=%d\n", __func__, ccb->csio.dxfer_len);
+	res = ccb->csio.dxfer_len;
+	/*
+	 * If the page table required multiple CTIO's to 
+	 * complete, then cur_pte is non NULL 
+	 * and we need to start from the last position
+	 * If this is the first pass over a page table
+	 * then we just start at the beginning of the page
+	 * table.
+	 *
+	 * Parse the unrestricted page table and figure out where we need
+	 * to shove the data from this read request.
+	 */
+	for (offset = 0, len = 0; (res != 0) && (orbi->cur_pte < orbi->last_pte); offset += len) {
+		len = MIN(orbi->cur_pte->segment_len, res);
+		res -= len;
+		if (debug)
+			printf("%s:page_table: %04x:%08x segment_len(%u) res(%u) len(%u)\n", 
+				__func__, orbi->cur_pte->segment_base_high,
+				orbi->cur_pte->segment_base_low,
+				orbi->cur_pte->segment_len,
+				res, len);
+		sbp_targ_xfer_buf(orbi, offset, 
+				orbi->cur_pte->segment_base_high,
+				orbi->cur_pte->segment_base_low,
+				len, sbp_targ_cam_done);
+		/*
+		 * If we have only written partially to
+		 * this page table, then we need to save
+		 * our position for the next CTIO.  If we
+		 * have completed the page table, then we
+		 * are safe to move on to the next entry.
+		 */
+		if (len == orbi->cur_pte->segment_len) {
+			orbi->cur_pte++;
+		} else {
+			uint32_t saved_base_low;
+
+			/* Handle transfers that cross a 4GB boundary. */
+			saved_base_low = orbi->cur_pte->segment_base_low;
+			orbi->cur_pte->segment_base_low += len;
+			if (orbi->cur_pte->segment_base_low < saved_base_low)
+				orbi->cur_pte->segment_base_high++;
+
+			orbi->cur_pte->segment_len -= len;
+		}
+	}
+	if (debug) {
+		printf("%s: base_low(%08x) page_table_off(%p) last_block(%u)\n",
+			__func__, orbi->cur_pte->segment_base_low, 
+			orbi->cur_pte, orbi->last_block_read);  
+	}
+	if (res != 0)
+		printf("Warning - short pt encountered.  "
+			"Could not transfer all data.\n");
+	return;
+}
+
+/*
+ * Create page table in local memory
+ * and transfer it from the initiator
+ * in order to know where we are supposed
+ * to put the data.
+ */
+
 static void
 sbp_targ_fetch_pt(struct orb_info *orbi)
 {
 	struct fw_xfer *xfer;
 
-	if (debug)
-		printf("%s: page_table_size=%d\n",
-		    __func__, orbi->orb4.data_size);
-	orbi->page_table = malloc(orbi->orb4.data_size*8, M_SBP_TARG, M_NOWAIT);
-	if (orbi->page_table == NULL)
-		goto error;
-	xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/2,
-		    orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*8,
-			    (void *)orbi->page_table, sbp_targ_pt_done);
-	if (xfer != NULL)
+	/*
+	 * Pull in page table from initiator
+	 * and setup for data from our
+	 * backend device.
+	 */
+	if (orbi->page_table == NULL) {
+		orbi->page_table = malloc(orbi->orb4.data_size*
+					  sizeof(struct unrestricted_page_table_fmt),
+					  M_SBP_TARG, M_NOWAIT|M_ZERO);
+		if (orbi->page_table == NULL)
+			goto error;
+		orbi->cur_pte = orbi->page_table;
+		orbi->last_pte = orbi->page_table + orbi->orb4.data_size;
+		orbi->last_block_read = orbi->orb4.data_size;
+		if (debug && orbi->page_table != NULL) 
+			printf("%s: malloc'd orbi->page_table(%p), orb4.data_size(%u)\n",
+ 				__func__, orbi->page_table, orbi->orb4.data_size);
+
+		xfer = fwmem_read_block(orbi->fwdev, (void *)orbi, /*spd*/FWSPD_S400,
+					orbi->data_hi, orbi->data_lo, orbi->orb4.data_size*
+					sizeof(struct unrestricted_page_table_fmt),
+					(void *)orbi->page_table, sbp_targ_pt_done);
+
+		if (xfer != NULL)
+			return;
+	} else {
+		/*
+		 * This is a CTIO for a page table we have
+		 * already malloc'd, so just directly invoke
+		 * the xfer function on the orbi.
+		 */
+		sbp_targ_xfer_pt(orbi);
 		return;
+	}
 error:
 	orbi->ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+	if (debug)      
+		printf("%s: free orbi->page_table %p due to xfer == NULL\n", __func__, orbi->page_table);
+	if (orbi->page_table != NULL) {
+		free(orbi->page_table, M_SBP_TARG);
+		orbi->page_table = NULL;
+	}
 	xpt_done(orbi->ccb);
 	return;
 }
@@ -1016,6 +1216,8 @@ sbp_targ_action1(struct cam_sim *sim, un
 			if (debug)
 				printf("%s: ctio aborted\n", __func__);
 			sbp_targ_remove_orb_info_locked(orbi->login, orbi);
+			if (debug)
+				printf("%s: free orbi %p\n", __func__, orbi);
 			free(orbi, M_SBP_TARG);
 			ccb->ccb_h.status = CAM_REQ_ABORTED;
 			xpt_done(ccb);
@@ -1051,17 +1253,16 @@ sbp_targ_action1(struct cam_sim *sim, un
 		}
 
 		/* Sanity check */
-		if (ccb_dir != CAM_DIR_NONE &&
-		    orbi->orb4.data_size != ccb->csio.dxfer_len)
-			printf("%s: data_size(%d) != dxfer_len(%d)\n",
-			    __func__, orbi->orb4.data_size,
-			    ccb->csio.dxfer_len);
-
-		if (ccb_dir != CAM_DIR_NONE)
+		if (ccb_dir != CAM_DIR_NONE) {
 			sbp_targ_xfer_buf(orbi, 0, orbi->data_hi,
 			    orbi->data_lo,
 			    MIN(orbi->orb4.data_size, ccb->csio.dxfer_len),
 			    sbp_targ_cam_done);
+			if ( orbi->orb4.data_size > ccb->csio.dxfer_len ) {
+				orbi->data_lo += ccb->csio.dxfer_len;
+				orbi->orb4.data_size -= ccb->csio.dxfer_len;
+			}
+		}
 
 		if (ccb_dir == CAM_DIR_NONE) {
 			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
@@ -1125,7 +1326,8 @@ sbp_targ_action1(struct cam_sim *sim, un
 		cpi->target_sprt = PIT_PROCESSOR
 				 | PIT_DISCONNECT
 				 | PIT_TERM_IO;
-		cpi->hba_misc = PIM_NOBUSRESET | PIM_NO_6_BYTE;
+		cpi->transport = XPORT_SPI; /* FIXME add XPORT_FW type to cam */
+		cpi->hba_misc = PIM_NOBUSRESET | PIM_NOBUSRESET;
 		cpi->hba_eng_cnt = 0;
 		cpi->max_target = 7; /* XXX */
 		cpi->max_lun = MAX_LUN - 1;
@@ -1163,10 +1365,42 @@ sbp_targ_action1(struct cam_sim *sim, un
 		xpt_done(ccb);
 		break;
 	}
+#ifdef CAM_NEW_TRAN_CODE
+	case XPT_SET_TRAN_SETTINGS:
+		ccb->ccb_h.status = CAM_REQ_INVALID;
+		xpt_done(ccb);
+		break;
+	case XPT_GET_TRAN_SETTINGS:
+	{
+		struct ccb_trans_settings *cts = &ccb->cts;
+		struct ccb_trans_settings_scsi *scsi =
+			&cts->proto_specific.scsi;
+		struct ccb_trans_settings_spi *spi =
+			&cts->xport_specific.spi;
+
+		cts->protocol = PROTO_SCSI;
+		cts->protocol_version = SCSI_REV_2;
+		cts->transport = XPORT_FW;     /* should have a FireWire */
+		cts->transport_version = 2;
+		spi->valid = CTS_SPI_VALID_DISC;
+		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
+		scsi->valid = CTS_SCSI_VALID_TQ;
+		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
+#if 0
+		printf("%s:%d:%d XPT_GET_TRAN_SETTINGS:\n",
+			device_get_nameunit(sc->fd.dev),
+			ccb->ccb_h.target_id, ccb->ccb_h.target_lun);
+#endif
+		cts->ccb_h.status = CAM_REQ_CMP;
+		xpt_done(ccb);
+		break;
+	}
+#endif
+
 	default:
-		printf("%s: unknown function %d\n",
+		printf("%s: unknown function 0x%x\n",
 		    __func__, ccb->ccb_h.func_code);
-		ccb->ccb_h.status = CAM_REQ_INVALID;
+		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
 		xpt_done(ccb);
 		break;
 	}
@@ -1245,7 +1479,7 @@ sbp_targ_cmd_handler(struct fw_xfer *xfe
 	atio->ccb_h.target_id = 0; /* XXX */
 	atio->ccb_h.target_lun = orbi->login->lstate->lun;
 	atio->sense_len = 0;
-	atio->tag_action = 1; /* XXX */
+	atio->tag_action = MSG_SIMPLE_TASK;
 	atio->tag_id = orbi->orb_lo;
 	atio->init_id = orbi->login->id;
 
@@ -1429,7 +1663,7 @@ sbp_targ_mgm_handler(struct fw_xfer *xfe
 		login->loginres.recon_hold = htons(login->hold_sec);
 
 		STAILQ_INSERT_TAIL(&lstate->logins, login, link);
-		fwmem_write_block(orbi->fwdev, NULL, /*spd*/2, orb[2], orb[3],
+		fwmem_write_block(orbi->fwdev, NULL, /*spd*/FWSPD_S400, orb[2], orb[3],
 		    sizeof(struct sbp_login_res), (void *)&login->loginres,
 		    fw_asy_callback_free);
 		/* XXX return status after loginres is successfully written */
@@ -1515,10 +1749,11 @@ sbp_targ_fetch_orb(struct sbp_targ_softc
 	orbi->orb_lo = orb_lo;
 	orbi->status.orb_hi = htons(orb_hi);
 	orbi->status.orb_lo = htonl(orb_lo);
+	orbi->page_table = NULL;
 
 	switch (mode) {
 	case FETCH_MGM:
-		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
+		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
 		    sizeof(uint32_t) * 8, &orbi->orb[0],
 		    sbp_targ_mgm_handler);
 		break;
@@ -1545,14 +1780,14 @@ sbp_targ_fetch_orb(struct sbp_targ_softc
 		SLIST_REMOVE_HEAD(&login->lstate->accept_tios, sim_links.sle);
 		STAILQ_INSERT_TAIL(&login->orbs, orbi, link);
 		SBP_UNLOCK(sc);
-		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
+		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
 		    sizeof(uint32_t) * 8, &orbi->orb[0],
 		    sbp_targ_cmd_handler);
 		break;
 	case FETCH_POINTER:
 		orbi->state = ORBI_STATUS_POINTER;
 		login->flags |= F_LINK_ACTIVE;
-		fwmem_read_block(fwdev, (void *)orbi, /*spd*/2, orb_hi, orb_lo,
+		fwmem_read_block(fwdev, (void *)orbi, /*spd*/FWSPD_S400, orb_hi, orb_lo,
 		    sizeof(uint32_t) * 2, &orbi->orb[0],
 		    sbp_targ_pointer_handler);
 		break;
@@ -1709,7 +1944,7 @@ done:
 	if (rtcode != 0)
 		printf("%s: rtcode = %d\n", __func__, rtcode);
 	sfp = &xfer->send.hdr;
-	xfer->send.spd = 2; /* XXX */
+	xfer->send.spd = FWSPD_S400;
 	xfer->hand = sbp_targ_resp_callback;
 	sfp->mode.wres.dst = fp->mode.wreqb.src;
 	sfp->mode.wres.tlrt = fp->mode.wreqb.tlrt;



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