mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-17 05:43:59 +00:00
Update sbp_targ such that it can actually handle multiple CTIO's during operation
PR: kern/119575
This commit is contained in:
parent
23a0e422aa
commit
4636d24459
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=230558
|
@ -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_login *login)
|
|||
}
|
||||
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 *sc, union ccb *ccb,
|
|||
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 *sc, union ccb *ccb)
|
|||
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 *sc, union ccb *ccb)
|
|||
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 *sc, union ccb *ccb)
|
|||
|
||||
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 *sc, union ccb *ccb)
|
|||
}
|
||||
|
||||
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 *sc, union ccb *ccb)
|
|||
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_lstate *lstate,
|
|||
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, struct orb_info *orbi)
|
|||
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 *orbi,
|
|||
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 *orbi,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 *orbi, union ccb *ccb)
|
|||
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 *orbi, union ccb *ccb)
|
|||
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 *orbi, union ccb *ccb)
|
|||
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 *orbi, union ccb *ccb)
|
|||
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 *orbi, union ccb *ccb)
|
|||
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 *sc, union ccb *ccb)
|
|||
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, u_int offset,
|
|||
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, union ccb *ccb)
|
|||
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, union ccb *ccb)
|
|||
}
|
||||
|
||||
/* 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, union ccb *ccb)
|
|||
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,12 +1365,44 @@ sbp_targ_action1(struct cam_sim *sim, union ccb *ccb)
|
|||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("%s: unknown function %d\n",
|
||||
__func__, ccb->ccb_h.func_code);
|
||||
#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 0x%x\n",
|
||||
__func__, ccb->ccb_h.func_code);
|
||||
ccb->ccb_h.status = CAM_PROVIDE_FAIL;
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1245,7 +1479,7 @@ sbp_targ_cmd_handler(struct fw_xfer *xfer)
|
|||
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 *xfer)
|
|||
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 *sc, struct fw_device *fwdev,
|
|||
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 *sc, struct fw_device *fwdev,
|
|||
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 @@ sbp_targ_recv(struct fw_xfer *xfer)
|
|||
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;
|
||||
|
|
Loading…
Reference in a new issue