Bug 119575 - [firewire] [patch] sbp_targ cannot handle multiple CTIO's for a single ATIO
Summary: [firewire] [patch] sbp_targ cannot handle multiple CTIO's for a single ATIO
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: Sean Bruno
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-01-11 21:30 UTC by Sean Bruno
Modified: 2013-04-04 16:28 UTC (History)
0 users

See Also:


Attachments
file.diff (27.33 KB, patch)
2008-01-11 21:30 UTC, Sean Bruno
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sean Bruno 2008-01-11 21:30:02 UTC
I have been using sbp_targ with our own custom backend target for about
a month now and have generated the following patch that is required to make
the target work and process data correctly.

Issue 1.  Correct CTIO processing when multiple CTIO's are required for a
single ATIO.  This was handled by creating a unrestricted page table
structure and indexing through the page_table with easier to read
variables.  Split out the processing of the page table into a seperate
function(sbp_targ_xfer_pt) for ease of invocation.

Issue 2.  Change the tag_action for every ATIO to be "MSG_SIMPLE_TASK",
this was causing crashes in my backend target when it was set to "1"

Issue 3. Change default handler in sbp_targ_action1() to CAM_PROVIDE_FAIL

Issue 4. Add new transport type of "XPORT_FW" so that my backend target
can detect the differences between firewire and other XPORT types.

Issue 5.  Move atio assignment so that it is not mis-accessed by the error
handlers.

Issue 6.  Implement code for "CAM_NEW_TRAN_CODE" (That's what I use).

Issue 7.  Remove the number "2" in assignment of firewire speed.  Use
define FWSPD_S400 in it's place.  This is a precursor to detecting the
SIM's bus speed capabilities and using that for this value.

Issue 8.  A lot of debugging code added, along with some comments.  They
really helped me out and should be incorporated in some form or fashion
into the code for the "next person".

TODO items

Issue 9. Possible race condition around orbi->refcount
Issue 10. Implement compatibility with sbp so they can coexist
Issue 11. Implement detection of bus speed so firewire 800 cards can be used

Fix: Issues 1-8 are resolved with the patch attached to this PR.

Issues 9-11 are under construction.  :)

Partial credit for these fixes should go to Justin Gibbs.

Patch attached with submission follows:
How-To-Repeat: Try to use sbp_targ with a backend target.
Comment 1 simokawa freebsd_committer freebsd_triage 2008-01-16 22:32:47 UTC
Responsible Changed
From-To: freebsd-bugs->simokawa

I'll take care of this PR.
Comment 2 sean.bruno 2008-01-30 19:03:46 UTC
Looks like I've run into a new item for my TODO list.

Item 12:  firewire_xfer_timeout() finding timed out transactions.
Timeout too small at 200 msec?

Sean
Comment 3 sean.bruno 2008-01-30 22:30:45 UTC
Ah, now windows is exploding all over the place.

Looks like I need to implement all of the task management functions:

ORB_FUN_ATA  <--- Abort task
ORB_FUN_ATS  <--- Abort task set
ORB_FUN_LUR  <--- Logical unit reset
ORB_FUN_RST  <--- Target reset

So add this to the todo list as item 13
Comment 4 Sean Bruno freebsd_committer freebsd_triage 2009-09-29 18:52:59 UTC
Responsible Changed
From-To: simokawa->sbruno

I'm a committer now, I'll take care of this one.
Comment 5 dfilter service freebsd_committer freebsd_triage 2012-01-25 23:34:23 UTC
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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 6 Sean Bruno freebsd_committer freebsd_triage 2012-01-25 23:52:41 UTC
State Changed
From-To: open->patched
Comment 7 Sean Bruno freebsd_committer freebsd_triage 2013-04-04 16:28:01 UTC
State Changed
From-To: patched->closed

Patches applied quite some time ago