summaryrefslogtreecommitdiffstats
path: root/sys/dev/isp
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2002-06-16 05:08:02 +0000
committermjacob <mjacob@FreeBSD.org>2002-06-16 05:08:02 +0000
commit06e71a13c094d792afc07bac76d188c778ee263a (patch)
tree5de6d664f1b030b4c62db49de4efb441fe380d50 /sys/dev/isp
parent60207e6800b5d09d7b681153ab2615fd60c2568b (diff)
downloadFreeBSD-src-06e71a13c094d792afc07bac76d188c778ee263a.zip
FreeBSD-src-06e71a13c094d792afc07bac76d188c778ee263a.tar.gz
Add support for ISP_FC_GETHINFO, which returns current connection
topology, speed, loopid, WWPN/WWNN, etc. Beef up target mode. Add isp_handle_platform_notify_scsi and isp_handle_platform_notify_fc platform handlers to handle immediate notifies (isp_handle_platform_notify_scsi is still stubbed out). In implementation of isp_handle_platform_notify_fc, for IN_ABORT_TASK, peel off a pending XPT_IMMED_NOTIFY and call xpt_done on it and hope that somebody upstream is listening. Make sure on final CTIO2s that we set residual correctly. These are absolutely crucial. Make sure we set relative offset for each CTIO2 based upon bytes we've already xferred. This is what the private adjunct datat to the original ATIO is. Note state of command so we can figure out where to find it if we get an ABORT from the firmware. Make sure we *always* set CAM_TAG_ACTION_VALID for ATIO2s. Make sure we keep track of the original lun. If se sent status (or we're otherwise done with the command), don't forget to free the adjunct structure.
Diffstat (limited to 'sys/dev/isp')
-rw-r--r--sys/dev/isp/isp_freebsd.c196
1 files changed, 158 insertions, 38 deletions
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index dda04a9..9b9a163 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -382,7 +382,21 @@ ispioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
ISP_UNLOCK(isp);
retval = 0;
break;
-
+ case ISP_FC_GETHINFO:
+ {
+ struct isp_hba_device *hba = (struct isp_hba_device *) addr;
+ MEMZERO(hba, sizeof (*hba));
+ ISP_LOCK(isp);
+ hba->fc_speed = FCPARAM(isp)->isp_gbspeed;
+ hba->fc_scsi_supported = 1;
+ hba->fc_topology = FCPARAM(isp)->isp_topo + 1;
+ hba->fc_loopid = FCPARAM(isp)->isp_loopid;
+ hba->active_node_wwn = FCPARAM(isp)->isp_nodewwn;
+ hba->active_port_wwn = FCPARAM(isp)->isp_portwwn;
+ ISP_UNLOCK(isp);
+ retval = 0;
+ break;
+ }
default:
break;
}
@@ -428,6 +442,8 @@ 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_atio2(struct ispsoftc *, at2_entry_t *);
static int isp_handle_platform_ctio(struct ispsoftc *, void *);
+static int isp_handle_platform_notify_scsi(struct ispsoftc *, in_entry_t *);
+static int isp_handle_platform_notify_fc(struct ispsoftc *, in_fcentry_t *);
static __inline int
is_lun_enabled(struct ispsoftc *isp, int bus, lun_id_t lun)
@@ -1032,8 +1048,10 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
atp = isp_get_atpd(isp, cso->tag_id);
if (atp == NULL) {
- panic("cannot find private data adjunct for tag %x",
+ isp_prt(isp, ISP_LOGERR,
+ "cannot find private data adjunct for tag %x",
cso->tag_id);
+ return (-1);
}
cto->ct_rxid = cso->tag_id;
@@ -1044,6 +1062,13 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
cto->rsp.m1.ct_scsi_status = cso->scsi_status;
cto->ct_resid =
atp->orig_datalen - atp->bytes_xfered;
+ if (cto->ct_resid < 0) {
+ cto->rsp.m1.ct_scsi_status |=
+ CT2_DATA_OVER;
+ } else if (cto->ct_resid > 0) {
+ cto->rsp.m1.ct_scsi_status |=
+ CT2_DATA_UNDER;
+ }
}
if ((ccb->ccb_h.flags & CAM_SEND_SENSE) != 0) {
int m = min(cso->sense_len, MAXRESPLEN);
@@ -1058,12 +1083,20 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
} else {
cto->ct_flags |= CT2_DATA_OUT;
}
+ cto->ct_reloff = atp->bytes_xfered;
if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
cto->ct_flags |= CT2_SENDSTATUS;
cto->rsp.m0.ct_scsi_status = cso->scsi_status;
cto->ct_resid =
atp->orig_datalen -
(atp->bytes_xfered + cso->dxfer_len);
+ if (cto->ct_resid < 0) {
+ cto->rsp.m0.ct_scsi_status |=
+ CT2_DATA_OVER;
+ } else if (cto->ct_resid > 0) {
+ cto->rsp.m0.ct_scsi_status |=
+ CT2_DATA_UNDER;
+ }
} else {
atp->last_xframt = cso->dxfer_len;
}
@@ -1080,7 +1113,9 @@ isp_target_start_ctio(struct ispsoftc *isp, union ccb *ccb)
cto->ct_rxid, cso->scsi_status, atp->orig_datalen,
cso->dxfer_len, cto->ct_resid);
cto->ct_flags |= CT2_CCINCR;
- }
+ atp->state = ATPD_STATE_LAST_CTIO;
+ } else
+ atp->state = ATPD_STATE_CTIO;
cto->ct_timeout = 10;
hp = &cto->ct_syshandle;
} else {
@@ -1193,6 +1228,7 @@ isp_target_putback_atio(union ccb *ccb)
}
at->at_status = CT_OK;
at->at_rxid = cso->tag_id;
+ at->at_iid = cso->ccb_h.target_id;
isp_put_atio2(isp, at, qe);
} else {
at_entry_t local, *at = &local;
@@ -1392,6 +1428,7 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
}
tptr = get_lun_statep(isp, 0, lun);
if (tptr == NULL) {
+ isp_prt(isp, ISP_LOGWARN, "no state pointer for lun %d", lun);
tptr = get_lun_statep(isp, 0, CAM_LUN_WILDCARD);
}
@@ -1420,18 +1457,7 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
* at this time.
*
*/
- u_int32_t ccode = SCSI_STATUS_BUSY;
-
- /*
- * Because we can't autofeed sense data back with
- * a command for parallel SCSI, we can't give back
- * a CHECK CONDITION. We'll give back a BUSY status
- * instead. This works out okay because the only
- * time we should, in fact, get this, is in the
- * case that somebody configured us without the
- * blackhole driver, so they get what they deserve.
- */
- isp_endcmd(isp, aep, ccode, 0);
+ isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
return (0);
}
@@ -1448,19 +1474,22 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
*/
xpt_print_path(tptr->owner);
isp_prt(isp, ISP_LOGWARN,
- "no ATIOS for lun %d from initiator %d", lun, aep->at_iid);
+ "no %s for lun %d from initiator %d",
+ (atp == NULL && atiop == NULL)? "ATIO2s *or* ATPS" :
+ ((atp == NULL)? "ATPs" : "ATIO2s"), lun, aep->at_iid);
rls_lun_statep(isp, tptr);
- if (aep->at_flags & AT_TQAE)
- isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
- else
- isp_endcmd(isp, aep, SCSI_STATUS_BUSY, 0);
+ isp_endcmd(isp, aep, SCSI_STATUS_QUEUE_FULL, 0);
return (0);
}
+ atp->state = ATPD_STATE_ATIO;
SLIST_REMOVE_HEAD(&tptr->atios, sim_links.sle);
+ tptr->atio_count--;
+ isp_prt(isp, ISP_LOGTDEBUG0, "Take FREE ATIO2 lun %d, count now %d",
+ lun, tptr->atio_count);
if (tptr == &isp->isp_osinfo.tsdflt[0]) {
atiop->ccb_h.target_id =
- ((fcparam *)isp->isp_param)->isp_loopid;
+ ((fcparam *)isp->isp_param)->isp_loopid;
atiop->ccb_h.target_lun = lun;
}
/*
@@ -1489,16 +1518,16 @@ isp_handle_platform_atio2(struct ispsoftc *isp, at2_entry_t *aep)
atiop->tag_action = 0;
break;
}
- if (atiop->tag_action != 0) {
- atiop->ccb_h.status |= CAM_TAG_ACTION_VALID;
- }
+ atiop->ccb_h.flags = CAM_TAG_ACTION_VALID;
atp->tag = atiop->tag_id;
+ atp->lun = lun;
atp->orig_datalen = aep->at_datalen;
atp->last_xframt = 0;
atp->bytes_xfered = 0;
-
+ atp->state = ATPD_STATE_CAM;
xpt_done((union ccb*)atiop);
+
isp_prt(isp, ISP_LOGTDEBUG0,
"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,
@@ -1524,6 +1553,13 @@ isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
if (IS_FC(isp)) {
ct2_entry_t *ct = arg;
+ atio_private_data_t *atp = isp_get_atpd(isp, ct->ct_rxid);
+ if (atp == NULL) {
+ isp_prt(isp, ISP_LOGERR,
+ "cannot find adjunct for %x after I/O",
+ ct->ct_rxid);
+ return (0);
+ }
sentstatus = ct->ct_flags & CT2_SENDSTATUS;
ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
if (ok && sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
@@ -1531,24 +1567,22 @@ isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
}
notify_cam = ct->ct_header.rqs_seqno & 0x1;
if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
- atio_private_data_t *atp =
- isp_get_atpd(isp, ct->ct_rxid);
- if (atp == NULL) {
- panic("cannot find adjunct after I/O");
- }
resid = ct->ct_resid;
atp->bytes_xfered += (atp->last_xframt - resid);
atp->last_xframt = 0;
- if (sentstatus) {
- atp->tag = 0;
- }
}
- isp_prt(isp, ISP_LOGTDEBUG0,
+ if (sentstatus || !ok) {
+ atp->tag = 0;
+ }
+ isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN,
"CTIO2[%x] sts 0x%x flg 0x%x sns %d resid %d %s",
ct->ct_rxid, ct->ct_status, ct->ct_flags,
(ccb->ccb_h.status & CAM_SENT_SENSE) != 0,
resid, sentstatus? "FIN" : "MID");
tval = ct->ct_rxid;
+
+ /* XXX: should really come after isp_complete_ctio */
+ atp->state = ATPD_STATE_PDON;
} else {
ct_entry_t *ct = arg;
sentstatus = ct->ct_flags & CT_SENDSTATUS;
@@ -1609,6 +1643,68 @@ isp_handle_platform_ctio(struct ispsoftc *isp, void *arg)
}
return (0);
}
+
+static int
+isp_handle_platform_notify_scsi(struct ispsoftc *isp, in_entry_t *inp)
+{
+ return (0); /* XXXX */
+}
+
+static int
+isp_handle_platform_notify_fc(struct ispsoftc *isp, in_fcentry_t *inp)
+{
+
+ switch (inp->in_status) {
+ case IN_PORT_LOGOUT:
+ isp_prt(isp, ISP_LOGWARN, "port logout of iid %d",
+ inp->in_iid);
+ break;
+ case IN_PORT_CHANGED:
+ isp_prt(isp, ISP_LOGWARN, "port changed for iid %d",
+ inp->in_iid);
+ break;
+ case IN_GLOBAL_LOGO:
+ isp_prt(isp, ISP_LOGINFO, "all ports logged out");
+ break;
+ case IN_ABORT_TASK:
+ {
+ atio_private_data_t *atp = isp_get_atpd(isp, inp->in_seqid);
+ struct ccb_immed_notify *inot = NULL;
+
+ if (atp) {
+ tstate_t *tptr = get_lun_statep(isp, 0, atp->lun);
+ if (tptr) {
+ inot = (struct ccb_immed_notify *)
+ SLIST_FIRST(&tptr->inots);
+ if (inot) {
+ SLIST_REMOVE_HEAD(&tptr->inots,
+ sim_links.sle);
+ }
+ }
+ isp_prt(isp, ISP_LOGWARN,
+ "abort task RX_ID %x IID %d state %d",
+ inp->in_seqid, inp->in_iid, atp->state);
+ } else {
+ isp_prt(isp, ISP_LOGWARN,
+ "abort task RX_ID %x from iid %d, state unknown",
+ inp->in_seqid, inp->in_iid);
+ }
+ if (inot) {
+ inot->initiator_id = inp->in_iid;
+ inot->sense_len = 0;
+ inot->message_args[0] = MSG_ABORT_TAG;
+ inot->message_args[1] = inp->in_seqid & 0xff;
+ inot->message_args[2] = (inp->in_seqid >> 8) & 0xff;
+ inot->ccb_h.status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN;
+ xpt_done((union ccb *)inot);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return (0);
+}
#endif
static void
@@ -1966,13 +2062,25 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
}
ccb->ccb_h.sim_priv.entries[0].field = 0;
ccb->ccb_h.sim_priv.entries[1].ptr = isp;
+ ccb->ccb_h.flags = 0;
+
CAMLOCK_2_ISPLOCK(isp);
if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
- SLIST_INSERT_HEAD(&tptr->atios,
- &ccb->ccb_h, sim_links.sle);
- } else {
+ /*
+ * Note that the command itself may not be done-
+ * it may not even have had the first CTIO sent.
+ */
+ tptr->atio_count++;
+ isp_prt(isp, ISP_LOGTDEBUG0,
+ "Put FREE ATIO2, lun %d, count now %d",
+ ccb->ccb_h.target_lun, tptr->atio_count);
+ SLIST_INSERT_HEAD(&tptr->atios, &ccb->ccb_h,
+ sim_links.sle);
+ } else if (ccb->ccb_h.func_code == XPT_IMMED_NOTIFY) {
SLIST_INSERT_HEAD(&tptr->inots, &ccb->ccb_h,
sim_links.sle);
+ } else {
+ ;
}
rls_lun_statep(isp, tptr);
ccb->ccb_h.status = CAM_REQ_INPROG;
@@ -1984,6 +2092,9 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
CAMLOCK_2_ISPLOCK(isp);
ccb->ccb_h.status = isp_target_start_ctio(isp, ccb);
if (ccb->ccb_h.status != CAM_REQ_INPROG) {
+ isp_prt(isp, ISP_LOGWARN,
+ "XPT_CONT_TARGET_IO: status 0x%x",
+ ccb->ccb_h.status);
if (isp->isp_osinfo.simqfrozen == 0) {
xpt_freeze_simq(sim, 1);
xpt_print_path(ccb->ccb_h.path);
@@ -2869,6 +2980,15 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
"event 0x%x for unhandled target action",
((isphdr_t *)arg)->rqs_entry_type);
break;
+ case RQSTYPE_NOTIFY:
+ if (IS_SCSI(isp)) {
+ rv = isp_handle_platform_notify_scsi(isp,
+ (in_entry_t *) arg);
+ } else {
+ rv = isp_handle_platform_notify_fc(isp,
+ (in_fcentry_t *) arg);
+ }
+ break;
case RQSTYPE_ATIO:
rv = isp_handle_platform_atio(isp, (at_entry_t *) arg);
break;
@@ -2903,7 +3023,7 @@ isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg)
mbox6 = 0;
}
isp_prt(isp, ISP_LOGERR,
- "Internal Firmware on bus %d Error @ RISC Address 0x%x",
+ "Internal Firmware Error on bus %d @ RISC Address 0x%x",
mbox6, mbox1);
isp_reinit(isp);
break;
OpenPOWER on IntegriCloud