Redo a lot of the target mode infrastructure to be cognizant of Dual Bus

cards like the 1280 && the 12160. Cleanup isp_target_putback_atio.
Make sure bus and correct tag ids and firmware handles get propagated
as needed.
This commit is contained in:
mjacob 2001-04-04 21:58:29 +00:00
parent 7892febf24
commit 44f132def7

View File

@ -28,6 +28,7 @@
#include <dev/isp/isp_freebsd.h> #include <dev/isp/isp_freebsd.h>
#include <machine/stdarg.h> /* for use by isp_prt below */ #include <machine/stdarg.h> /* for use by isp_prt below */
static void isp_intr_enable(void *); static void isp_intr_enable(void *);
static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *); static void isp_cam_async(void *, u_int32_t, struct cam_path *, void *);
static void isp_poll(struct cam_sim *); static void isp_poll(struct cam_sim *);
@ -172,39 +173,39 @@ isp_intr_enable(void *arg)
#ifdef ISP_TARGET_MODE #ifdef ISP_TARGET_MODE
static __inline int is_lun_enabled(struct ispsoftc *, lun_id_t); static __inline int is_lun_enabled(struct ispsoftc *, int, lun_id_t);
static __inline int are_any_luns_enabled(struct ispsoftc *); static __inline int are_any_luns_enabled(struct ispsoftc *, int);
static __inline tstate_t *get_lun_statep(struct ispsoftc *, lun_id_t); static __inline tstate_t *get_lun_statep(struct ispsoftc *, int, lun_id_t);
static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *); static __inline void rls_lun_statep(struct ispsoftc *, tstate_t *);
static __inline int isp_psema_sig_rqe(struct ispsoftc *); static __inline int isp_psema_sig_rqe(struct ispsoftc *);
static __inline int isp_cv_wait_timed_rqe(struct ispsoftc *, int); static __inline int isp_cv_wait_timed_rqe(struct ispsoftc *, int);
static __inline void isp_cv_signal_rqe(struct ispsoftc *, int); static __inline void isp_cv_signal_rqe(struct ispsoftc *, int);
static __inline void isp_vsema_rqe(struct ispsoftc *); static __inline void isp_vsema_rqe(struct ispsoftc *);
static cam_status static cam_status
create_lun_state(struct ispsoftc *, struct cam_path *, tstate_t **); create_lun_state(struct ispsoftc *, int, struct cam_path *, tstate_t **);
static void destroy_lun_state(struct ispsoftc *, tstate_t *); static void destroy_lun_state(struct ispsoftc *, tstate_t *);
static void isp_en_lun(struct ispsoftc *, union ccb *); static void isp_en_lun(struct ispsoftc *, union ccb *);
static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *); static cam_status isp_abort_tgt_ccb(struct ispsoftc *, union ccb *);
static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *);
static cam_status isp_target_putback_atio(struct ispsoftc *, union ccb *);
static timeout_t isp_refire_putback_atio; static timeout_t isp_refire_putback_atio;
static void isp_complete_ctio(union ccb *);
static void isp_target_putback_atio(union ccb *);
static cam_status isp_target_start_ctio(struct ispsoftc *, union ccb *);
static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *); static int isp_handle_platform_atio(struct ispsoftc *, at_entry_t *);
static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *); static int isp_handle_platform_atio2(struct ispsoftc *, at2_entry_t *);
static int isp_handle_platform_ctio(struct ispsoftc *, void *); static int isp_handle_platform_ctio(struct ispsoftc *, void *);
static void isp_handle_platform_ctio_part2(struct ispsoftc *, union ccb *);
static __inline int static __inline int
is_lun_enabled(struct ispsoftc *isp, lun_id_t lun) is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun)
{ {
tstate_t *tptr; tstate_t *tptr;
ISP_LOCK(isp); ISP_LOCK(isp);
if ((tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]) == NULL) { tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
if (tptr == NULL) {
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
return (0); return (0);
} }
do { do {
if (tptr->lun == (lun_id_t) lun) { if (tptr->lun == (lun_id_t) lun && tptr->bus == bus) {
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
return (1); return (1);
} }
@ -214,11 +215,18 @@ is_lun_enabled(struct ispsoftc *isp, lun_id_t lun)
} }
static __inline int static __inline int
are_any_luns_enabled(struct ispsoftc *isp) are_any_luns_enabled(struct ispsoftc *isp, int port)
{ {
int i; int lo, hi;
for (i = 0; i < LUN_HASH_SIZE; i++) { if (IS_DUALBUS(isp)) {
if (isp->isp_osinfo.lun_hash[i]) { lo = (port * (LUN_HASH_SIZE >> 1));
hi = lo + (LUN_HASH_SIZE >> 1);
} else {
lo = 0;
hi = LUN_HASH_SIZE;
}
for (lo = 0; lo < hi; lo++) {
if (isp->isp_osinfo.lun_hash[lo]) {
return (1); return (1);
} }
} }
@ -226,18 +234,18 @@ are_any_luns_enabled(struct ispsoftc *isp)
} }
static __inline tstate_t * static __inline tstate_t *
get_lun_statep(struct ispsoftc *isp, lun_id_t lun) get_lun_statep(struct ispsoftc *isp, int bus, lun_id_t lun)
{ {
tstate_t *tptr; tstate_t *tptr;
ISP_LOCK(isp); ISP_LOCK(isp);
if (lun == CAM_LUN_WILDCARD) { if (lun == CAM_LUN_WILDCARD) {
tptr = &isp->isp_osinfo.tsdflt; tptr = &isp->isp_osinfo.tsdflt[bus];
tptr->hold++; tptr->hold++;
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
return (tptr); return (tptr);
} else { } else {
tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]; tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(isp, bus, lun)];
} }
if (tptr == NULL) { if (tptr == NULL) {
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
@ -245,7 +253,7 @@ get_lun_statep(struct ispsoftc *isp, lun_id_t lun)
} }
do { do {
if (tptr->lun == lun) { if (tptr->lun == lun && tptr->bus == bus) {
tptr->hold++; tptr->hold++;
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
return (tptr); return (tptr);
@ -310,17 +318,19 @@ isp_vsema_rqe(struct ispsoftc *isp)
} }
static cam_status static cam_status
create_lun_state(struct ispsoftc *isp, struct cam_path *path, tstate_t **rslt) create_lun_state(struct ispsoftc *isp, int bus,
struct cam_path *path, tstate_t **rslt)
{ {
cam_status status; cam_status status;
lun_id_t lun; lun_id_t lun;
int hfx;
tstate_t *tptr, *new; tstate_t *tptr, *new;
lun = xpt_path_lun_id(path); lun = xpt_path_lun_id(path);
if (lun < 0) { if (lun < 0) {
return (CAM_LUN_INVALID); return (CAM_LUN_INVALID);
} }
if (is_lun_enabled(isp, lun)) { if (is_lun_enabled(isp, bus, lun)) {
return (CAM_LUN_ALRDY_ENA); return (CAM_LUN_ALRDY_ENA);
} }
new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO); new = (tstate_t *) malloc(sizeof (tstate_t), M_DEVBUF, M_NOWAIT|M_ZERO);
@ -334,14 +344,17 @@ create_lun_state(struct ispsoftc *isp, struct cam_path *path, tstate_t **rslt)
free(new, M_DEVBUF); free(new, M_DEVBUF);
return (status); return (status);
} }
new->bus = bus;
new->lun = lun; new->lun = lun;
SLIST_INIT(&new->atios); SLIST_INIT(&new->atios);
SLIST_INIT(&new->inots); SLIST_INIT(&new->inots);
new->hold = 1; new->hold = 1;
hfx = LUN_HASH_FUNC(isp, new->bus, new->lun);
ISP_LOCK(isp); ISP_LOCK(isp);
if ((tptr = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)]) == NULL) { tptr = isp->isp_osinfo.lun_hash[hfx];
isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(lun)] = new; if (tptr == NULL) {
isp->isp_osinfo.lun_hash[hfx] = new;
} else { } else {
while (tptr->next) while (tptr->next)
tptr = tptr->next; tptr = tptr->next;
@ -355,24 +368,26 @@ create_lun_state(struct ispsoftc *isp, struct cam_path *path, tstate_t **rslt)
static __inline void static __inline void
destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr) destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr)
{ {
int hfx;
tstate_t *lw, *pw; tstate_t *lw, *pw;
hfx = LUN_HASH_FUNC(isp, tptr->bus, tptr->lun);
ISP_LOCK(isp); ISP_LOCK(isp);
if (tptr->hold) { if (tptr->hold) {
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
return; return;
} }
pw = isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(tptr->lun)]; pw = isp->isp_osinfo.lun_hash[hfx];
if (pw == NULL) { if (pw == NULL) {
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
return; return;
} else if (pw->lun == tptr->lun) { } else if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
isp->isp_osinfo.lun_hash[LUN_HASH_FUNC(tptr->lun)] = pw->next; isp->isp_osinfo.lun_hash[hfx] = pw->next;
} else { } else {
lw = pw; lw = pw;
pw = lw->next; pw = lw->next;
while (pw) { while (pw) {
if (pw->lun == tptr->lun) { if (pw->lun == tptr->lun && pw->bus == tptr->bus) {
lw->next = pw->next; lw->next = pw->next;
break; break;
} }
@ -391,7 +406,7 @@ destroy_lun_state(struct ispsoftc *isp, tstate_t *tptr)
static void static void
isp_en_lun(struct ispsoftc *isp, union ccb *ccb) isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
{ {
const char lfmt[] = "Lun now %sabled for target mode"; const char lfmt[] = "Lun now %sabled for target mode on channel %d";
struct ccb_en_lun *cel = &ccb->cel; struct ccb_en_lun *cel = &ccb->cel;
tstate_t *tptr; tstate_t *tptr;
u_int16_t rstat; u_int16_t rstat;
@ -400,13 +415,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
target_id_t tgt; target_id_t tgt;
bus = XS_CHANNEL(ccb); bus = XS_CHANNEL(ccb) & 0x1;
if (bus != 0) {
isp_prt(isp, ISP_LOGERR,
"second channel target mode not supported");
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
return;
}
tgt = ccb->ccb_h.target_id; tgt = ccb->ccb_h.target_id;
lun = ccb->ccb_h.target_lun; lun = ccb->ccb_h.target_lun;
@ -420,8 +429,10 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
return; return;
} }
if (IS_SCSI(isp)) { if (IS_SCSI(isp)) {
sdparam *sdp = isp->isp_param;
sdp += bus;
if (tgt != CAM_TARGET_WILDCARD && if (tgt != CAM_TARGET_WILDCARD &&
tgt != SDPARAM(isp)->isp_initiator_id) { tgt != sdp->isp_initiator_id) {
ccb->ccb_h.status = CAM_TID_INVALID; ccb->ccb_h.status = CAM_TID_INVALID;
return; return;
} }
@ -490,10 +501,10 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
* If so, we enable/disable target mode but don't do any lun enabling. * If so, we enable/disable target mode but don't do any lun enabling.
*/ */
if (lun == CAM_LUN_WILDCARD && tgt == CAM_TARGET_WILDCARD) { if (lun == CAM_LUN_WILDCARD && tgt == CAM_TARGET_WILDCARD) {
int av; int av = bus << 31;
tptr = &isp->isp_osinfo.tsdflt; tptr = &isp->isp_osinfo.tsdflt[bus];
if (cel->enable) { if (cel->enable) {
if (isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) { if (isp->isp_osinfo.tmflags & (1 << bus)) {
ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
if (frozen) if (frozen)
xpt_release_simq(isp->isp_sim, 1); xpt_release_simq(isp->isp_sim, 1);
@ -511,7 +522,7 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
} }
SLIST_INIT(&tptr->atios); SLIST_INIT(&tptr->atios);
SLIST_INIT(&tptr->inots); SLIST_INIT(&tptr->inots);
av = 1; av |= ENABLE_TARGET_FLAG;
ISP_LOCK(isp); ISP_LOCK(isp);
av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
if (av) { if (av) {
@ -522,22 +533,21 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
xpt_release_simq(isp->isp_sim, 1); xpt_release_simq(isp->isp_sim, 1);
return; return;
} }
isp->isp_osinfo.tmflags |= TM_TMODE_ENABLED; isp->isp_osinfo.tmflags |= (1 << bus);
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
} else { } else {
if ((isp->isp_osinfo.tmflags & TM_TMODE_ENABLED) == 0) { if ((isp->isp_osinfo.tmflags & (1 << bus)) == 0) {
ccb->ccb_h.status = CAM_LUN_INVALID; ccb->ccb_h.status = CAM_LUN_INVALID;
if (frozen) if (frozen)
xpt_release_simq(isp->isp_sim, 1); xpt_release_simq(isp->isp_sim, 1);
return; return;
} }
if (are_any_luns_enabled(isp)) { if (are_any_luns_enabled(isp, bus)) {
ccb->ccb_h.status = CAM_SCSI_BUSY; ccb->ccb_h.status = CAM_SCSI_BUSY;
if (frozen) if (frozen)
xpt_release_simq(isp->isp_sim, 1); xpt_release_simq(isp->isp_sim, 1);
return; return;
} }
av = 0;
ISP_LOCK(isp); ISP_LOCK(isp);
av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av); av = isp_control(isp, ISPCTL_TOGGLE_TMODE, &av);
if (av) { if (av) {
@ -547,12 +557,13 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
xpt_release_simq(isp->isp_sim, 1); xpt_release_simq(isp->isp_sim, 1);
return; return;
} }
isp->isp_osinfo.tmflags &= ~TM_TMODE_ENABLED; isp->isp_osinfo.tmflags &= ~(1 << bus);
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
ccb->ccb_h.status = CAM_REQ_CMP; ccb->ccb_h.status = CAM_REQ_CMP;
} }
xpt_print_path(ccb->ccb_h.path); xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGINFO, lfmt, (cel->enable) ? "en" : "dis"); isp_prt(isp, ISP_LOGINFO, "Target Mode %sabled on channel %d",
(cel->enable) ? "en" : "dis", bus);
if (frozen) if (frozen)
xpt_release_simq(isp->isp_sim, 1); xpt_release_simq(isp->isp_sim, 1);
return; return;
@ -568,12 +579,12 @@ isp_en_lun(struct ispsoftc *isp, union ccb *ccb)
if (cel->enable) { if (cel->enable) {
ccb->ccb_h.status = ccb->ccb_h.status =
create_lun_state(isp, ccb->ccb_h.path, &tptr); create_lun_state(isp, bus, ccb->ccb_h.path, &tptr);
if (ccb->ccb_h.status != CAM_REQ_CMP) { if (ccb->ccb_h.status != CAM_REQ_CMP) {
return; return;
} }
} else { } else {
tptr = get_lun_statep(isp, lun); tptr = get_lun_statep(isp, bus, lun);
if (tptr == NULL) { if (tptr == NULL) {
ccb->ccb_h.status = CAM_LUN_INVALID; ccb->ccb_h.status = CAM_LUN_INVALID;
return; return;
@ -670,7 +681,8 @@ out:
destroy_lun_state(isp, tptr); destroy_lun_state(isp, tptr);
} else { } else {
xpt_print_path(ccb->ccb_h.path); xpt_print_path(ccb->ccb_h.path);
isp_prt(isp, ISP_LOGINFO, lfmt, (cel->enable) ? "en" : "dis"); isp_prt(isp, ISP_LOGINFO, lfmt,
(cel->enable) ? "en" : "dis", bus);
rls_lun_statep(isp, tptr); rls_lun_statep(isp, tptr);
if (cel->enable == 0) { if (cel->enable == 0) {
destroy_lun_state(isp, tptr); destroy_lun_state(isp, tptr);
@ -697,7 +709,7 @@ isp_abort_tgt_ccb(struct ispsoftc *isp, union ccb *ccb)
return (CAM_PATH_INVALID); return (CAM_PATH_INVALID);
} }
} }
tptr = get_lun_statep(isp, accb->ccb_h.target_lun); tptr = get_lun_statep(isp, XS_CHANNEL(ccb), accb->ccb_h.target_lun);
if (tptr == NULL) { if (tptr == NULL) {
return (CAM_PATH_INVALID); return (CAM_PATH_INVALID);
} }
@ -778,10 +790,6 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
cto->ct_resid = atiop->ccb_h.spriv_field0; cto->ct_resid = atiop->ccb_h.spriv_field0;
} }
/*
* We always have to use the tag_id- it has the responder
* exchange id in it.
*/
cto->ct_rxid = cso->tag_id; cto->ct_rxid = cso->tag_id;
if (cso->dxfer_len == 0) { if (cso->dxfer_len == 0) {
cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA; cto->ct_flags |= CT2_FLAG_MODE1 | CT2_NO_DATA;
@ -813,31 +821,26 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
ccb->ccb_h.flags &= ~CAM_SEND_SENSE; ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
} }
if (cto->ct_flags & CT2_SENDSTATUS) { if (cto->ct_flags & CT2_SENDSTATUS) {
isp_prt(isp, ISP_LOGTDEBUG2, isp_prt(isp, ISP_LOGTDEBUG1,
"CTIO2[%x] SCSI STATUS 0x%x datalength %u", "CTIO2[%x] SCSI STATUS 0x%x datalength %u",
cto->ct_rxid, cso->scsi_status, cto->ct_resid); cto->ct_rxid, cso->scsi_status, cto->ct_resid);
} }
cto->ct_timeout = 2; if (cto->ct_flags & CT2_SENDSTATUS)
cto->ct_flags |= CT2_CCINCR;
cto->ct_timeout = 10;
hp = &cto->ct_syshandle; hp = &cto->ct_syshandle;
} else { } else {
ct_entry_t *cto = qe; ct_entry_t *cto = qe;
/*
* We always have to use the tag_id- it has the handle
* for this command.
*/
cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
cto->ct_header.rqs_entry_count = 1; cto->ct_header.rqs_entry_count = 1;
cto->ct_iid = cso->init_id; cto->ct_iid = cso->init_id;
cto->ct_iid |= XS_CHANNEL(ccb) << 7;
cto->ct_tgt = ccb->ccb_h.target_id; cto->ct_tgt = ccb->ccb_h.target_id;
cto->ct_lun = ccb->ccb_h.target_lun; cto->ct_lun = ccb->ccb_h.target_lun;
cto->ct_fwhandle = cso->tag_id >> 8; cto->ct_fwhandle = AT_GET_HANDLE(cso->tag_id);
cto->ct_tag_val = cso->tag_id & 0xff; if (AT_HAS_TAG(cso->tag_id)) {
if (cto->ct_tag_val && cso->tag_action) { cto->ct_tag_val = (u_int8_t) AT_GET_TAG(cso->tag_id);
/*
* We don't specify a tag type for regular SCSI,
* just the tag value and set a flag.
*/
cto->ct_flags |= CT_TQAE; cto->ct_flags |= CT_TQAE;
} }
if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) { if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
@ -856,13 +859,16 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
cto->ct_resid = cso->resid; cto->ct_resid = cso->resid;
} }
if (cto->ct_flags & CT_SENDSTATUS) { if (cto->ct_flags & CT_SENDSTATUS) {
isp_prt(isp, ISP_LOGTDEBUG2, isp_prt(isp, ISP_LOGTDEBUG1,
"CTIO SCSI STATUS 0x%x resid %d", "CTIO[%x] SCSI STATUS 0x%x resid %d tag_id %x",
cso->scsi_status, cso->resid); cto->ct_fwhandle, cso->scsi_status, cso->resid,
cso->tag_id);
} }
cto->ct_timeout = 2; cto->ct_timeout = 10;
hp = &cto->ct_syshandle; hp = &cto->ct_syshandle;
ccb->ccb_h.flags &= ~CAM_SEND_SENSE; ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
if (cto->ct_flags & CT_SENDSTATUS)
cto->ct_flags |= CT_CCINCR;
} }
if (isp_save_xs(isp, (XS_T *)ccb, hp)) { if (isp_save_xs(isp, (XS_T *)ccb, hp)) {
@ -882,6 +888,7 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
*/ */
save_handle = *hp; save_handle = *hp;
switch (ISP_DMASETUP(isp, cso, qe, &iptr, optr)) { switch (ISP_DMASETUP(isp, cso, qe, &iptr, optr)) {
case CMD_QUEUED: case CMD_QUEUED:
ISP_ADD_REQUEST(isp, iptr); ISP_ADD_REQUEST(isp, iptr);
@ -898,63 +905,85 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
} }
} }
static cam_status static void
isp_target_putback_atio(struct ispsoftc *isp, union ccb *ccb) isp_refire_putback_atio(void *arg)
{ {
void *qe; int s = splcam();
struct ccb_accept_tio *atiop; isp_target_putback_atio(arg);
splx(s);
}
static void
isp_target_putback_atio(union ccb *ccb)
{
struct ispsoftc *isp;
struct ccb_scsiio *cso;
u_int16_t iptr, optr; u_int16_t iptr, optr;
void *qe;
isp = XS_ISP(ccb);
if (isp_getrqentry(isp, &iptr, &optr, &qe)) { if (isp_getrqentry(isp, &iptr, &optr, &qe)) {
xpt_print_path(ccb->ccb_h.path); (void) timeout(isp_refire_putback_atio, ccb, 10);
printf("Request Queue Overflow in isp_target_putback_atio\n"); isp_prt(isp, ISP_LOGWARN,
return (CAM_RESRC_UNAVAIL); "isp_target_putback_atio: Request Queue Overflow");
return;
} }
bzero(qe, QENTRY_LEN); bzero(qe, QENTRY_LEN);
atiop = (struct ccb_accept_tio *) ccb; cso = &ccb->csio;
if (IS_FC(isp)) { if (IS_FC(isp)) {
at2_entry_t *at = qe; at2_entry_t *at = qe;
at->at_header.rqs_entry_type = RQSTYPE_ATIO2; at->at_header.rqs_entry_type = RQSTYPE_ATIO2;
at->at_header.rqs_entry_count = 1; at->at_header.rqs_entry_count = 1;
if (isp->isp_maxluns > 16) { if (isp->isp_maxluns > 16) {
at->at_scclun = (uint16_t) atiop->ccb_h.target_lun; at->at_scclun = (uint16_t) ccb->ccb_h.target_lun;
} else { } else {
at->at_lun = (uint8_t) atiop->ccb_h.target_lun; at->at_lun = (uint8_t) ccb->ccb_h.target_lun;
} }
at->at_status = CT_OK; at->at_status = CT_OK;
at->at_rxid = atiop->tag_id; at->at_rxid = cso->tag_id;
ISP_SWIZ_ATIO2(isp, qe, qe); ISP_SWIZ_ATIO2(isp, qe, qe);
} else { } else {
at_entry_t *at = qe; at_entry_t *at = qe;
at->at_header.rqs_entry_type = RQSTYPE_ATIO; at->at_header.rqs_entry_type = RQSTYPE_ATIO;
at->at_header.rqs_entry_count = 1; at->at_header.rqs_entry_count = 1;
at->at_iid = atiop->init_id; at->at_iid = cso->init_id;
at->at_tgt = atiop->ccb_h.target_id; at->at_iid |= XS_CHANNEL(ccb) << 7;
at->at_lun = atiop->ccb_h.target_lun; at->at_tgt = cso->ccb_h.target_id;
at->at_lun = cso->ccb_h.target_lun;
at->at_status = CT_OK; at->at_status = CT_OK;
if (atiop->ccb_h.status & CAM_TAG_ACTION_VALID) { at->at_tag_val = AT_GET_TAG(cso->tag_id);
at->at_tag_type = atiop->tag_action; at->at_handle = AT_GET_HANDLE(cso->tag_id);
}
at->at_tag_val = atiop->tag_id & 0xff;
at->at_handle = atiop->tag_id >> 8;
ISP_SWIZ_ATIO(isp, qe, qe); ISP_SWIZ_ATIO(isp, qe, qe);
} }
ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe); ISP_TDQE(isp, "isp_target_putback_atio", (int) optr, qe);
ISP_ADD_REQUEST(isp, iptr); ISP_ADD_REQUEST(isp, iptr);
return (CAM_REQ_CMP); isp_complete_ctio(ccb);
} }
static void static void
isp_refire_putback_atio(void *arg) isp_complete_ctio(union ccb *ccb)
{ {
union ccb *ccb = arg; struct ispsoftc *isp = XS_ISP(ccb);
int s = splcam(); if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
if (isp_target_putback_atio(XS_ISP(ccb), ccb) != CAM_REQ_CMP) { ccb->ccb_h.status |= CAM_REQ_CMP;
(void) timeout(isp_refire_putback_atio, ccb, 10);
} else {
isp_handle_platform_ctio_part2(XS_ISP(ccb), ccb);
} }
splx(s); ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
if (isp->isp_osinfo.simqfrozen == 0) {
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
isp_prt(isp, ISP_LOGDEBUG2, "ctio->relsimq");
ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
} else {
isp_prt(isp, ISP_LOGWARN, "ctio->devqfrozen");
}
} else {
isp_prt(isp, ISP_LOGWARN,
"ctio->simqfrozen(%x)", isp->isp_osinfo.simqfrozen);
}
}
xpt_done(ccb);
} }
/* /*
@ -966,7 +995,7 @@ static int
isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep) isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
{ {
tstate_t *tptr; tstate_t *tptr;
int status; int status, bus;
struct ccb_accept_tio *atiop; struct ccb_accept_tio *atiop;
/* /*
@ -999,9 +1028,11 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
return (0); return (0);
} }
tptr = get_lun_statep(isp, aep->at_lun); bus = aep->at_iid >> 7;
aep->at_iid &= 0x7f;
tptr = get_lun_statep(isp, bus, aep->at_lun);
if (tptr == NULL) { if (tptr == NULL) {
tptr = get_lun_statep(isp, CAM_LUN_WILDCARD); tptr = get_lun_statep(isp, bus, CAM_LUN_WILDCARD);
} }
if (tptr == NULL) { if (tptr == NULL) {
@ -1030,8 +1061,8 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
*/ */
xpt_print_path(tptr->owner); xpt_print_path(tptr->owner);
isp_prt(isp, ISP_LOGWARN, isp_prt(isp, ISP_LOGWARN,
"no ATIOS for lun %d from initiator %d", "no ATIOS for lun %d from initiator %d on channel %d",
aep->at_lun, aep->at_iid); aep->at_lun, aep->at_iid, bus);
rls_lun_statep(isp, tptr); rls_lun_statep(isp, tptr);
if (aep->at_flags & AT_TQAE) if (aep->at_flags & AT_TQAE)
isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0); isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
@ -1040,7 +1071,7 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
return (0); return (0);
} }
SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
if (tptr == &isp->isp_osinfo.tsdflt) { if (tptr == &isp->isp_osinfo.tsdflt[bus]) {
atiop->ccb_h.target_id = aep->at_tgt; atiop->ccb_h.target_id = aep->at_tgt;
atiop->ccb_h.target_lun = aep->at_lun; atiop->ccb_h.target_lun = aep->at_lun;
} }
@ -1058,16 +1089,21 @@ isp_handle_platform_atio(struct ispsoftc *isp, at_entry_t *aep)
atiop->sense_len = 0; atiop->sense_len = 0;
} }
atiop->init_id = aep->at_iid; atiop->init_id = aep->at_iid & 0x7f;
atiop->cdb_len = aep->at_cdblen; atiop->cdb_len = aep->at_cdblen;
MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen); MEMCPY(atiop->cdb_io.cdb_bytes, aep->at_cdb, aep->at_cdblen);
atiop->ccb_h.status = CAM_CDB_RECVD; atiop->ccb_h.status = CAM_CDB_RECVD;
atiop->tag_id = aep->at_tag_val | (aep->at_handle << 8); /*
if ((atiop->tag_action = aep->at_tag_type) != 0) { * Construct a tag 'id' based upon tag value (which may be 0..255)
* and the handle (which we have to preserve).
*/
AT_MAKE_TAGID(atiop->tag_id, aep);
if (aep->at_flags & AT_TQAE) {
atiop->tag_action = aep->at_tag_type;
atiop->ccb_h.status |= CAM_TAG_ACTION_VALID; atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
} }
xpt_done((union ccb*)atiop); xpt_done((union ccb*)atiop);
isp_prt(isp, ISP_LOGTDEBUG2, isp_prt(isp, ISP_LOGTDEBUG1,
"ATIO[%x] CDB=0x%x iid%d->lun%d tag 0x%x ttype 0x%x %s", "ATIO[%x] CDB=0x%x iid%d->lun%d tag 0x%x ttype 0x%x %s",
aep->at_handle, aep->at_cdb[0] & 0xff, aep->at_iid, aep->at_lun, aep->at_handle, aep->at_cdb[0] & 0xff, aep->at_iid, aep->at_lun,
aep->at_tag_val & 0xff, aep->at_tag_type, aep->at_tag_val & 0xff, aep->at_tag_type,
@ -1101,9 +1137,9 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
} else { } else {
lun = aep->at_lun; lun = aep->at_lun;
} }
tptr = get_lun_statep(isp, lun); tptr = get_lun_statep(isp, 0, lun);
if (tptr == NULL) { if (tptr == NULL) {
tptr = get_lun_statep(isp, CAM_LUN_WILDCARD); tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
} }
if (tptr == NULL) { if (tptr == NULL) {
@ -1168,7 +1204,7 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
} }
SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle); SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
if (tptr == &isp->isp_osinfo.tsdflt) { if (tptr == &isp->isp_osinfo.tsdflt[0]) {
atiop->ccb_h.target_id = atiop->ccb_h.target_id =
((fcparam *)isp->isp_param)->isp_loopid; ((fcparam *)isp->isp_param)->isp_loopid;
atiop->ccb_h.target_lun = lun; atiop->ccb_h.target_lun = lun;
@ -1209,7 +1245,7 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
atiop->ccb_h.spriv_field0 = aep->at_datalen; atiop->ccb_h.spriv_field0 = aep->at_datalen;
xpt_done((union ccb*)atiop); xpt_done((union ccb*)atiop);
isp_prt(isp, ISP_LOGTDEBUG2, isp_prt(isp, ISP_LOGTDEBUG1,
"ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u", "ATIO2[%x] CDB=0x%x iid%d->lun%d tattr 0x%x datalen %u",
aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid, aep->at_rxid, aep->at_cdb[0] & 0xff, aep->at_iid,
lun, aep->at_taskflags, aep->at_datalen); lun, aep->at_taskflags, aep->at_datalen);
@ -1221,7 +1257,7 @@ static int
isp_handle_platform_ctio(struct ispsoftc *isp, void *arg) isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
{ {
union ccb *ccb; union ccb *ccb;
int sentstatus, ok, notify_cam; int sentstatus, ok, notify_cam, resid = 0;
/* /*
* CTIO and CTIO2 are close enough.... * CTIO and CTIO2 are close enough....
@ -1235,83 +1271,76 @@ isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
ct2_entry_t *ct = arg; ct2_entry_t *ct = arg;
sentstatus = ct->ct_flags & CT2_SENDSTATUS; sentstatus = ct->ct_flags & CT2_SENDSTATUS;
ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
if (ok && (ccb->ccb_h.flags & CAM_SEND_SENSE)) { if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
ccb->ccb_h.status |= CAM_SENT_SENSE; ccb->ccb_h.status |= CAM_SENT_SENSE;
} }
isp_prt(isp, ISP_LOGTDEBUG2, isp_prt(isp, ISP_LOGTDEBUG1,
"CTIO2[%x] sts 0x%x flg 0x%x sns %d FIN", "CTIO2[%x] sts 0x%x flg 0x%x sns %d %s",
ct->ct_rxid, ct->ct_status, ct->ct_flags, ct->ct_rxid, ct->ct_status, ct->ct_flags,
(ccb->ccb_h.status & CAM_SENT_SENSE) != 0); (ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
notify_cam = ct->ct_header.rqs_seqno; sentstatus? "FIN" : "MID");
notify_cam = ct->ct_header.rqs_seqno & 0x1;
if (ct->ct_flags & CT2_DATAMASK)
resid = ct->ct_resid;
} else { } else {
ct_entry_t *ct = arg; ct_entry_t *ct = arg;
sentstatus = ct->ct_flags & CT_SENDSTATUS; sentstatus = ct->ct_flags & CT_SENDSTATUS;
ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK; ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
isp_prt(isp, ISP_LOGTDEBUG2, isp_prt(isp, ISP_LOGTDEBUG1,
"CTIO tag 0x%x sts 0x%x flg 0x%x FIN", "CTIO[%x] tag %x iid %x tgt %d lun %d sts 0x%x flg %x %s",
ct->ct_tag_val, ct->ct_status, ct->ct_flags); ct->ct_fwhandle, ct->ct_tag_val, ct->ct_iid, ct->ct_tgt,
notify_cam = ct->ct_header.rqs_seqno; ct->ct_lun, ct->ct_status, ct->ct_flags,
sentstatus? "FIN" : "MID");
/*
* We *ought* to be able to get back to the original ATIO
* here, but for some reason this gets lost. It's just as
* well because it's squirrelled away as part of periph
* private data.
*
* We can live without it as long as we continue to use
* the auto-replenish feature for CTIOs.
*/
notify_cam = ct->ct_header.rqs_seqno & 0x1;
if (ct->ct_status & QLTM_SVALID) {
char *sp = (char *)ct;
sp += CTIO_SENSE_OFFSET;
ccb->csio.sense_len =
min(sizeof (ccb->csio.sense_data), QLTM_SENSELEN);
MEMCPY(&ccb->csio.sense_data, sp, ccb->csio.sense_len);
ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
}
if (ct->ct_flags & CT_DATAMASK)
resid = ct->ct_resid;
} }
ccb->csio.resid += resid;
/* /*
* We're here either because data transfers are done (and * We're here either because intermediate data transfers are done
* it's time to send a final status CTIO) or because the final * and/or the final status CTIO (which may have joined with a
* status CTIO is done. We don't get called for all intermediate * Data Transfer) is done.
* CTIOs that happen for a large data transfer.
* *
* In any case, for this platform, the upper layers figure out * In any case, for this platform, the upper layers figure out
* what to do next, so all we do here is collect status and * what to do next, so all we do here is collect status and
* pass information along. The exception is that we clear * pass information along. Any DMA handles have already been
* the notion of handling a non-disconnecting command here. * freed.
*/ */
if (sentstatus) {
/*
* Data transfer done. See if all went okay.
*/
if (ok) {
ccb->csio.resid = 0;
} else {
ccb->csio.resid = ccb->csio.dxfer_len;
}
}
if (notify_cam == 0) { if (notify_cam == 0) {
isp_prt(isp, ISP_LOGTDEBUG1, "Intermediate CTIO done"); isp_prt(isp, ISP_LOGTDEBUG0, " INTER CTIO done");
return (0); return (0);
} }
isp_prt(isp, ISP_LOGTDEBUG1, "Final CTIO done");
if (isp_target_putback_atio(isp, ccb) != CAM_REQ_CMP) { isp_prt(isp, ISP_LOGTDEBUG0, "%s CTIO done (resid %d)",
(void) timeout(isp_refire_putback_atio, ccb, 10); (sentstatus)? " FINAL " : "MIDTERM ", ccb->csio.resid);
if (!ok) {
isp_target_putback_atio(ccb);
} else { } else {
isp_handle_platform_ctio_part2(isp, ccb); isp_complete_ctio(ccb);
} }
return (0); return (0);
} }
static void
isp_handle_platform_ctio_part2(struct ispsoftc *isp, union ccb *ccb)
{
if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) {
ccb->ccb_h.status |= CAM_REQ_CMP;
}
ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
if (isp->isp_osinfo.simqfrozen == 0) {
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
isp_prt(isp, ISP_LOGDEBUG2, "ctio->relsimq");
ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
} else {
isp_prt(isp, ISP_LOGDEBUG2, "ctio->devqfrozen");
}
} else {
isp_prt(isp, ISP_LOGDEBUG2,
"ctio->simqfrozen(%x)", isp->isp_osinfo.simqfrozen);
}
}
xpt_done(ccb);
}
#endif #endif
static void static void
@ -1327,22 +1356,27 @@ isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg)
if (IS_SCSI(isp)) { if (IS_SCSI(isp)) {
u_int16_t oflags, nflags; u_int16_t oflags, nflags;
sdparam *sdp = isp->isp_param; sdparam *sdp = isp->isp_param;
int rvf, tgt; int tgt;
tgt = xpt_path_target_id(path); tgt = xpt_path_target_id(path);
rvf = ISP_FW_REVX(isp->isp_fwrev);
ISP_LOCK(isp); ISP_LOCK(isp);
sdp += cam_sim_bus(sim); sdp += cam_sim_bus(sim);
isp->isp_update |= (1 << cam_sim_bus(sim)); #ifndef ISP_TARGET_MODE
nflags = DPARM_SAFE_DFLT; if (tgt == sdp->isp_initiator_id) {
if (rvf >= ISP_FW_REV(7, 55, 0) || nflags = DPARM_DEFAULT;
(ISP_FW_REV(4, 55, 0) <= rvf && } else {
(rvf < ISP_FW_REV(5, 0, 0)))) { nflags = DPARM_SAFE_DFLT;
nflags |= DPARM_NARROW | DPARM_ASYNC; if (isp->isp_loaded_fw) {
nflags |= DPARM_NARROW | DPARM_ASYNC;
}
} }
#else
nflags = DPARM_DEFAULT;
#endif
oflags = sdp->isp_devparam[tgt].dev_flags; oflags = sdp->isp_devparam[tgt].dev_flags;
sdp->isp_devparam[tgt].dev_flags = nflags; sdp->isp_devparam[tgt].dev_flags = nflags;
sdp->isp_devparam[tgt].dev_update = 1; sdp->isp_devparam[tgt].dev_update = 1;
isp->isp_update |= (1 << cam_sim_bus(sim));
(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);
sdp->isp_devparam[tgt].dev_flags = oflags; sdp->isp_devparam[tgt].dev_flags = oflags;
ISP_UNLOCK(isp); ISP_UNLOCK(isp);
@ -1590,7 +1624,8 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */ case XPT_IMMED_NOTIFY: /* Add Immediate Notify Resource */
case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */ case XPT_ACCEPT_TARGET_IO: /* Add Accept Target IO Resource */
{ {
tstate_t *tptr = get_lun_statep(isp, ccb->ccb_h.target_lun); tstate_t *tptr =
get_lun_statep(isp, XS_CHANNEL(ccb), ccb->ccb_h.target_lun);
if (tptr == NULL) { if (tptr == NULL) {
ccb->ccb_h.status = CAM_LUN_INVALID; ccb->ccb_h.status = CAM_LUN_INVALID;
xpt_done(ccb); xpt_done(ccb);
@ -1600,9 +1635,6 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
ccb->ccb_h.sim_priv.entries[1].ptr = isp; ccb->ccb_h.sim_priv.entries[1].ptr = isp;
ISP_LOCK(isp); ISP_LOCK(isp);
if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) { if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
#if 0
(void) isp_target_putback_atio(isp, ccb);
#endif
SLIST_INSERT_HEAD(&tptr->atios, SLIST_INSERT_HEAD(&tptr->atios,
&ccb->ccb_h, sim_links.sle); &ccb->ccb_h, sim_links.sle);
} else { } else {
@ -1899,12 +1931,7 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
cpi->version_num = 1; cpi->version_num = 1;
#ifdef ISP_TARGET_MODE #ifdef ISP_TARGET_MODE
/* XXX: we don't support 2nd bus target mode yet */ cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
if (cam_sim_bus(sim) == 0)
cpi->target_sprt =
PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO;
else
cpi->target_sprt = 0;
#else #else
cpi->target_sprt = 0; cpi->target_sprt = 0;
#endif #endif