summaryrefslogtreecommitdiffstats
path: root/sys/dev/isp/isp_library.c
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2012-07-28 20:06:29 +0000
committermjacob <mjacob@FreeBSD.org>2012-07-28 20:06:29 +0000
commita41cb450d69215d0da52701d70146c12971be38d (patch)
treee1ac1dcf97e2541ae902e508daa253c99de306c4 /sys/dev/isp/isp_library.c
parent5792096bc677884a34c715613253e90705f70fe3 (diff)
downloadFreeBSD-src-a41cb450d69215d0da52701d70146c12971be38d.zip
FreeBSD-src-a41cb450d69215d0da52701d70146c12971be38d.tar.gz
-----------
MISC CHANGES Add a new async event- ISP_TARGET_NOTIFY_ACK, that will guarantee eventual delivery of a NOTIFY ACK. This is tons better than just ignoring the return from isp_notify_ack and hoping for the best. Clean up the lower level lun enable code to be a bit more sensible. Fix a botch in isp_endcmd which was messing up the sense data. Fix notify ack for SRR to use a sensible error code in the case of a reject. Clean up and make clear what kind of firmware we've loaded and what capabilities it has. ----------- FULL (252 byte) SENSE DATA In CTIOs for the ISP, there's only a limimted amount of space to load SENSE DATA for associated CHECK CONDITIONS (24 or 26 bytes). This makes it difficult to send full SENSE DATA that can be up to 252 bytes. Implement MODE 2 responses which have us build the FCP Response in system memory which the ISP will put onto the wire directly. On the initiator side, the same problem occurs in that a command status response only has a limited amount of space for SENSE DATA. This data is supplemented by status continuation responses that the ISP pushes onto the response queue after the status response. We now pull them all together so that full sense data can be returned to the periph driver. This is supported on 23XX, 24XX and 25XX cards. This is also preparation for doing >16 byte CDBs. ----------- FC TAPE Implement full FC-TAPE on both initiator and target mode side. This capability is driven by firmware loaded, board type, board NVRAM settings, or hint configuration options to enable or disable. This is supported for 23XX, 24XX and 25XX cards. On the initiator side, we pretty much just have to generate a command reference number for each command we send out. This is FCP-4 compliant in that we do this per ITL nexus to generate the allowed 1 thru 255 CRN. In order to support the target side of FC-TAPE, we now pay attention to more of the PRLI word 3 parameters which will tell us whether an initiator wants confirmed responses. While we're at it, we'll pay attention to the initiator view too and report it. On sending back CTIOs, we will notice whether the initiator wants confirmed responses and we'll set up flags to do so. If a response or data frame is lost the initiator sends us an SRR (Sequence Retransmit Request) ELS which shows up as an SRR notify and all outstanding CTIOs are nuked with SRR Received status. The SRR notify contains the offset that the initiator wants us to restart the data transfer from or to retransmit the response frame. If the ISP driver still has the CCB around for which the data segment or response applies, it will retransmit. However, we typically don't know about a lost data frame until we send the FCP Response and the initiator totes up counters for data moved and notices missing segments. In this case we've already completed the data CCBs already and sent themn back up to the periph driver. Because there's no really clean mechanism yet in CAM to handle this, a hack has been put into place to complete the CTIO CCB with the CAM_MESSAGE_RECV status which will have a MODIFY DATA POINTER extended message in it. The internal ISP target groks this and ctl(8) will be modified to deal with this as well. At any rate, the data is retransmitted and an an FCP response is sent. The whole point here is to successfully complete a command so that you don't have to depend on ULP (SCSI) to have to recover, which in the case of tape is not really possible (hence the name FC-TAPE). Sponsored by: Spectralogic MFC after: 1 month
Diffstat (limited to 'sys/dev/isp/isp_library.c')
-rw-r--r--sys/dev/isp/isp_library.c397
1 files changed, 236 insertions, 161 deletions
diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c
index e8b563f..d5535f2 100644
--- a/sys/dev/isp/isp_library.c
+++ b/sys/dev/isp/isp_library.c
@@ -58,7 +58,7 @@ const char *isp_class3_roles[4] = {
* Called with the first queue entry at least partially filled out.
*/
int
-isp_send_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_t totalcnt, isp_ddir_t ddir)
+isp_send_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_t totalcnt, isp_ddir_t ddir, ispds64_t *ecmd)
{
uint8_t storage[QENTRY_LEN];
uint8_t type, nqe;
@@ -396,11 +396,11 @@ isp_fc_runstate(ispsoftc_t *isp, int chan, int tval)
}
if (fcp->isp_fwstate < FW_READY || fcp->isp_loopstate < LOOP_PDB_RCVD) {
if (isp_control(isp, ISPCTL_FCLINK_TEST, chan, tval) != 0) {
- isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: linktest failed for channel %d", chan);
+ isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: linktest failed for channel %d", chan);
return (-1);
}
if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate < LOOP_PDB_RCVD) {
- isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: f/w not ready for channel %d", chan);
+ isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: f/w not ready for channel %d", chan);
return (-1);
}
}
@@ -410,19 +410,19 @@ isp_fc_runstate(ispsoftc_t *isp, int chan, int tval)
}
if (isp_control(isp, ISPCTL_SCAN_LOOP, chan) != 0) {
- isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: scan loop fails on channel %d", chan);
+ isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: scan loop fails on channel %d", chan);
return (LOOP_PDB_RCVD);
}
if (isp_control(isp, ISPCTL_SCAN_FABRIC, chan) != 0) {
- isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: scan fabric fails on channel %d", chan);
+ isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: scan fabric fails on channel %d", chan);
return (LOOP_LSCAN_DONE);
}
if (isp_control(isp, ISPCTL_PDB_SYNC, chan) != 0) {
- isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: pdb_sync fails on channel %d", chan);
+ isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: pdb_sync fails on channel %d", chan);
return (LOOP_FSCAN_DONE);
}
if (fcp->isp_fwstate != FW_READY || fcp->isp_loopstate != LOOP_READY) {
- isp_prt(isp, ISP_LOGSANCFG, "isp_fc_runstate: f/w not ready again on channel %d", chan);
+ isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: f/w not ready again on channel %d", chan);
return (-1);
}
return (0);
@@ -438,7 +438,7 @@ isp_dump_portdb(ispsoftc_t *isp, int chan)
int i;
for (i = 0; i < MAX_FC_TARG; i++) {
- char mb[4];
+ char mb[4], buf1[64], buf2[64];
const char *dbs[8] = {
"NIL ",
"PROB",
@@ -449,9 +449,6 @@ isp_dump_portdb(ispsoftc_t *isp, int chan)
"ZOMB",
"VLD "
};
- const char *roles[4] = {
- " UNK", " TGT", " INI", "TINI"
- };
fcportdb_t *lp = &fcp->portdb[i];
if (lp->state == FC_PORTDB_STATE_NIL && lp->target_mode == 0) {
@@ -462,12 +459,81 @@ isp_dump_portdb(ispsoftc_t *isp, int chan)
} else {
ISP_SNPRINTF(mb, sizeof (mb), "---");
}
+ isp_gen_role_str(buf1, sizeof (buf1), lp->prli_word3);
+ isp_gen_role_str(buf2, sizeof (buf2), lp->new_prli_word3);
isp_prt(isp, ISP_LOGALL, "Chan %d [%d]: hdl 0x%x %s al%d tgt %s %s 0x%06x =>%s 0x%06x; WWNN 0x%08x%08x WWPN 0x%08x%08x",
- chan, i, lp->handle, dbs[lp->state], lp->autologin, mb, roles[lp->roles], lp->portid, roles[lp->new_roles], lp->new_portid,
+ chan, i, lp->handle, dbs[lp->state], lp->autologin, mb, buf1, lp->portid, buf2, lp->new_portid,
(uint32_t) (lp->node_wwn >> 32), (uint32_t) (lp->node_wwn), (uint32_t) (lp->port_wwn >> 32), (uint32_t) (lp->port_wwn));
}
}
+void
+isp_gen_role_str(char *buf, size_t len, uint16_t p3)
+{
+ int nd = 0;
+ buf[0] = '(';
+ buf[1] = 0;
+ if (p3 & PRLI_WD3_ENHANCED_DISCOVERY) {
+ nd++;
+ strlcat(buf, "EDisc", len);
+ }
+ if (p3 & PRLI_WD3_REC_SUPPORT) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "REC", len);
+ }
+ if (p3 & PRLI_WD3_TASK_RETRY_IDENTIFICATION_REQUESTED) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "RetryID", len);
+ }
+ if (p3 & PRLI_WD3_RETRY) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "Retry", len);
+ }
+ if (p3 & PRLI_WD3_CONFIRMED_COMPLETION_ALLOWED) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "CNFRM", len);
+ }
+ if (p3 & PRLI_WD3_DATA_OVERLAY_ALLOWED) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "DOver", len);
+ }
+ if (p3 & PRLI_WD3_INITIATOR_FUNCTION) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "INI", len);
+ }
+ if (p3 & PRLI_WD3_TARGET_FUNCTION) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "TGT", len);
+ }
+ if (p3 & PRLI_WD3_READ_FCP_XFER_RDY_DISABLED) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "RdXfrDis", len);
+ }
+ if (p3 & PRLI_WD3_WRITE_FCP_XFER_RDY_DISABLED) {
+ if (nd++) {
+ strlcat(buf, ",", len);
+ }
+ strlcat(buf, "XfrDis", len);
+ }
+ strlcat(buf, ")", len);
+}
+
const char *
isp_fc_fw_statename(int state)
{
@@ -535,7 +601,6 @@ isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
isp_del_all_wwn_entries(isp, chan);
#endif
isp_clear_commands(isp);
-
isp_reset(isp, 0);
if (isp->isp_state != ISP_RESETSTATE) {
isp_prt(isp, ISP_LOGERR, "%s: cannot reset card", __func__);
@@ -896,7 +961,8 @@ isp_put_request_t3(ispsoftc_t *isp, ispreqt3_t *src, ispreqt3_t *dst)
ISP_IOXPUT_8(isp, src->req_target, &dst->req_target);
ISP_IOXPUT_16(isp, src->req_scclun, &dst->req_scclun);
ISP_IOXPUT_16(isp, src->req_flags, &dst->req_flags);
- ISP_IOXPUT_16(isp, src->req_reserved, &dst->req_reserved);
+ ISP_IOXPUT_8(isp, src->req_crn, &dst->req_crn);
+ ISP_IOXPUT_8(isp, src->req_reserved, &dst->req_reserved);
ISP_IOXPUT_16(isp, src->req_time, &dst->req_time);
ISP_IOXPUT_16(isp, src->req_seg_count, &dst->req_seg_count);
for (i = 0; i < ASIZE(src->req_cdb); i++) {
@@ -919,7 +985,8 @@ isp_put_request_t3e(ispsoftc_t *isp, ispreqt3e_t *src, ispreqt3e_t *dst)
ISP_IOXPUT_16(isp, src->req_target, &dst->req_target);
ISP_IOXPUT_16(isp, src->req_scclun, &dst->req_scclun);
ISP_IOXPUT_16(isp, src->req_flags, &dst->req_flags);
- ISP_IOXPUT_16(isp, src->req_reserved, &dst->req_reserved);
+ ISP_IOXPUT_8(isp, src->req_crn, &dst->req_crn);
+ ISP_IOXPUT_8(isp, src->req_reserved, &dst->req_reserved);
ISP_IOXPUT_16(isp, src->req_time, &dst->req_time);
ISP_IOXPUT_16(isp, src->req_seg_count, &dst->req_seg_count);
for (i = 0; i < ASIZE(src->req_cdb); i++) {
@@ -1077,15 +1144,34 @@ isp_get_response(ispsoftc_t *isp, ispstatusreq_t *src, ispstatusreq_t *dst)
ISP_IOXGET_16(isp, &src->req_time, dst->req_time);
ISP_IOXGET_16(isp, &src->req_sense_len, dst->req_sense_len);
ISP_IOXGET_32(isp, &src->req_resid, dst->req_resid);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < sizeof (src->req_response); i++) {
ISP_IOXGET_8(isp, &src->req_response[i], dst->req_response[i]);
}
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < sizeof (src->req_sense_data); i++) {
ISP_IOXGET_8(isp, &src->req_sense_data[i], dst->req_sense_data[i]);
}
}
void
+isp_get_cont_response(ispsoftc_t *isp, ispstatus_cont_t *src, ispstatus_cont_t *dst)
+{
+ int i;
+ isp_get_hdr(isp, &src->req_header, &dst->req_header);
+ if (IS_24XX(isp)) {
+ uint32_t *a, *b;
+ a = (uint32_t *) src->req_sense_data;
+ b = (uint32_t *) dst->req_sense_data;
+ for (i = 0; i < (sizeof (src->req_sense_data) / sizeof (uint32_t)); i++) {
+ ISP_IOZGET_32(isp, a++, *b++);
+ }
+ } else {
+ for (i = 0; i < sizeof (src->req_sense_data); i++) {
+ ISP_IOXGET_8(isp, &src->req_sense_data[i], dst->req_sense_data[i]);
+ }
+ }
+}
+
+void
isp_get_24xx_response(ispsoftc_t *isp, isp24xx_statusreq_t *src, isp24xx_statusreq_t *dst)
{
int i;
@@ -1929,6 +2015,29 @@ isp_get_fc_hdr(ispsoftc_t *isp, fc_hdr_t *src, fc_hdr_t *dst)
}
void
+isp_put_fc_hdr(ispsoftc_t *isp, fc_hdr_t *src, fc_hdr_t *dst)
+{
+ ISP_IOZPUT_8(isp, src->r_ctl, &dst->r_ctl);
+ ISP_IOZPUT_8(isp, src->d_id[0], &dst->d_id[0]);
+ ISP_IOZPUT_8(isp, src->d_id[1], &dst->d_id[1]);
+ ISP_IOZPUT_8(isp, src->d_id[2], &dst->d_id[2]);
+ ISP_IOZPUT_8(isp, src->cs_ctl, &dst->cs_ctl);
+ ISP_IOZPUT_8(isp, src->s_id[0], &dst->s_id[0]);
+ ISP_IOZPUT_8(isp, src->s_id[1], &dst->s_id[1]);
+ ISP_IOZPUT_8(isp, src->s_id[2], &dst->s_id[2]);
+ ISP_IOZPUT_8(isp, src->type, &dst->type);
+ ISP_IOZPUT_8(isp, src->f_ctl[0], &dst->f_ctl[0]);
+ ISP_IOZPUT_8(isp, src->f_ctl[1], &dst->f_ctl[1]);
+ ISP_IOZPUT_8(isp, src->f_ctl[2], &dst->f_ctl[2]);
+ ISP_IOZPUT_8(isp, src->seq_id, &dst->seq_id);
+ ISP_IOZPUT_8(isp, src->df_ctl, &dst->df_ctl);
+ ISP_IOZPUT_16(isp, src->seq_cnt, &dst->seq_cnt);
+ ISP_IOZPUT_16(isp, src->ox_id, &dst->ox_id);
+ ISP_IOZPUT_16(isp, src->rx_id, &dst->rx_id);
+ ISP_IOZPUT_32(isp, src->parameter, &dst->parameter);
+}
+
+void
isp_get_fcp_cmnd_iu(ispsoftc_t *isp, fcp_cmnd_iu_t *src, fcp_cmnd_iu_t *dst)
{
int i;
@@ -1998,23 +2107,43 @@ isp_put_ct_hdr(ispsoftc_t *isp, ct_hdr_t *src, ct_hdr_t *dst)
ISP_IOZPUT_8(isp, src->ct_vunique, &dst->ct_vunique);
}
+void
+isp_put_fcp_rsp_iu(ispsoftc_t *isp, fcp_rsp_iu_t *src, fcp_rsp_iu_t *dst)
+{
+ int i;
+ for (i = 0; i < ((sizeof (src->fcp_rsp_reserved))/(sizeof (src->fcp_rsp_reserved[0]))); i++) {
+ ISP_IOZPUT_8(isp, src->fcp_rsp_reserved[i], &dst->fcp_rsp_reserved[i]);
+ }
+ ISP_IOZPUT_16(isp, src->fcp_rsp_status_qualifier, &dst->fcp_rsp_status_qualifier);
+ ISP_IOZPUT_8(isp, src->fcp_rsp_bits, &dst->fcp_rsp_bits);
+ ISP_IOZPUT_8(isp, src->fcp_rsp_scsi_status, &dst->fcp_rsp_scsi_status);
+ ISP_IOZPUT_32(isp, src->fcp_rsp_resid, &dst->fcp_rsp_resid);
+ ISP_IOZPUT_32(isp, src->fcp_rsp_snslen, &dst->fcp_rsp_snslen);
+ ISP_IOZPUT_32(isp, src->fcp_rsp_rsplen, &dst->fcp_rsp_rsplen);
+}
+
#ifdef ISP_TARGET_MODE
/*
* Command shipping- finish off first queue entry and do dma mapping and
* additional segments as needed.
*
- * Called with the first queue entry at least partially filled out.
+ * Called with the first queue entry mostly filled out.
+ * Our job here is to finish that and add additional data
+ * segments if needed.
+ *
+ * We used to do synthetic entries to split data and status
+ * at this level, but that started getting too tricky.
*/
int
isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_t totalcnt, isp_ddir_t ddir, void *snsptr, uint32_t snslen)
{
- uint8_t storage[QENTRY_LEN], storage2[QENTRY_LEN];
+ uint8_t storage[QENTRY_LEN];
uint8_t type, nqe;
uint32_t seg, curseg, seglim, nxt, nxtnxt;
ispds_t *dsp = NULL;
ispds64_t *dsp64 = NULL;
- void *qe0, *qe1, *sqe = NULL;
+ void *qe0, *qe1;
qe0 = isp_getrqentry(isp);
if (qe0 == NULL) {
@@ -2027,7 +2156,7 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_
seglim = 0;
/*
- * If we have no data to transmit, just copy the first IOCB and start it up.
+ * If we have data to transmit, figure out how many segments can fit into the first entry.
*/
if (ddir != ISP_NOXFR) {
/*
@@ -2039,100 +2168,25 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_
seglim = ISP_RQDSEG;
break;
case RQSTYPE_CTIO2:
+ dsp = ((ct2_entry_t *)fqe)->rsp.m0.u.ct_dataseg;
+ seglim = ISP_RQDSEG_T2;
+ break;
case RQSTYPE_CTIO3:
- {
- ct2_entry_t *ct = fqe, *ct2 = (ct2_entry_t *) storage2;
- uint16_t swd = ct->rsp.m0.ct_scsi_status & 0xff;
-
- if ((ct->ct_flags & CT2_SENDSTATUS) && (swd || ct->ct_resid)) {
- memcpy(ct2, ct, QENTRY_LEN);
- /*
- * Clear fields from first CTIO2 that now need to be cleared
- */
- ct->ct_header.rqs_seqno = 0;
- ct->ct_flags &= ~(CT2_SENDSTATUS|CT2_CCINCR|CT2_FASTPOST);
- ct->ct_resid = 0;
- ct->ct_syshandle = 0;
- ct->rsp.m0.ct_scsi_status = 0;
-
- /*
- * Reset fields in the second CTIO2 as appropriate.
- */
- ct2->ct_flags &= ~(CT2_FLAG_MMASK|CT2_DATAMASK|CT2_FASTPOST);
- ct2->ct_flags |= CT2_NO_DATA|CT2_FLAG_MODE1;
- ct2->ct_seg_count = 0;
- ct2->ct_reloff = 0;
- memset(&ct2->rsp, 0, sizeof (ct2->rsp));
- if (swd == SCSI_CHECK && snsptr && snslen) {
- ct2->rsp.m1.ct_senselen = min(snslen, MAXRESPLEN);
- memcpy(ct2->rsp.m1.ct_resp, snsptr, ct2->rsp.m1.ct_senselen);
- swd |= CT2_SNSLEN_VALID;
- }
- if (ct2->ct_resid > 0) {
- swd |= CT2_DATA_UNDER;
- } else if (ct2->ct_resid < 0) {
- swd |= CT2_DATA_OVER;
- }
- ct2->rsp.m1.ct_scsi_status = swd;
- sqe = storage2;
- }
- if (type == RQSTYPE_CTIO2) {
- dsp = ct->rsp.m0.u.ct_dataseg;
- seglim = ISP_RQDSEG_T2;
- } else {
- dsp64 = ct->rsp.m0.u.ct_dataseg64;
- seglim = ISP_RQDSEG_T3;
- }
+ dsp64 = ((ct2_entry_t *)fqe)->rsp.m0.u.ct_dataseg64;
+ seglim = ISP_RQDSEG_T3;
break;
- }
case RQSTYPE_CTIO7:
- {
- ct7_entry_t *ct = fqe, *ct2 = (ct7_entry_t *)storage2;
- uint16_t swd = ct->ct_scsi_status & 0xff;
-
- dsp64 = &ct->rsp.m0.ds;
+ dsp64 = &((ct7_entry_t *)fqe)->rsp.m0.ds;
seglim = 1;
- if ((ct->ct_flags & CT7_SENDSTATUS) && (swd || ct->ct_resid)) {
- memcpy(ct2, ct, sizeof (ct7_entry_t));
-
- /*
- * Clear fields from first CTIO7 that now need to be cleared
- */
- ct->ct_header.rqs_seqno = 0;
- ct->ct_flags &= ~CT7_SENDSTATUS;
- ct->ct_resid = 0;
- ct->ct_syshandle = 0;
- ct->ct_scsi_status = 0;
-
- /*
- * Reset fields in the second CTIO7 as appropriate.
- */
- ct2->ct_flags &= ~(CT7_FLAG_MMASK|CT7_DATAMASK);
- ct2->ct_flags |= CT7_NO_DATA|CT7_NO_DATA|CT7_FLAG_MODE1;
- ct2->ct_seg_count = 0;
- memset(&ct2->rsp, 0, sizeof (ct2->rsp));
- if (swd == SCSI_CHECK && snsptr && snslen) {
- ct2->rsp.m1.ct_resplen = min(snslen, MAXRESPLEN_24XX);
- memcpy(ct2->rsp.m1.ct_resp, snsptr, ct2->rsp.m1.ct_resplen);
- swd |= (FCP_SNSLEN_VALID << 8);
- }
- if (ct2->ct_resid < 0) {
- swd |= (FCP_RESID_OVERFLOW << 8);
- } else if (ct2->ct_resid > 0) {
- swd |= (FCP_RESID_UNDERFLOW << 8);
- }
- ct2->ct_scsi_status = swd;
- sqe = storage2;
- }
break;
- }
default:
return (CMD_COMPLETE);
}
}
/*
- * Fill out the data transfer stuff in the first queue entry
+ * First, fill out any of the data transfer stuff that fits
+ * in the first queue entry.
*/
if (seglim > nsegs) {
seglim = nsegs;
@@ -2147,12 +2201,6 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_
}
/*
- * First, if we are sending status with data and we have a non-zero
- * status or non-zero residual, we have to make a synthetic extra CTIO
- * that contains the status that we'll ship separately (FC cards only).
- */
-
- /*
* Second, start building additional continuation segments as needed.
*/
while (seg < nsegs) {
@@ -2198,25 +2246,10 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_
}
/*
- * If we have a synthetic queue entry to complete things, do it here.
+ * Third, not patch up the first queue entry with the number of segments
+ * we actually are going to be transmitting. At the same time, handle
+ * any mode 2 requests.
*/
- if (sqe) {
- nxtnxt = ISP_NXT_QENTRY(nxt, RQUEST_QUEUE_LEN(isp));
- if (nxtnxt == isp->isp_reqodx) {
- return (CMD_EAGAIN);
- }
- qe1 = ISP_QUEUE_ENTRY(isp->isp_rquest, nxt);
- nxt = nxtnxt;
- if (type == RQSTYPE_CTIO7) {
- isp_put_ctio7(isp, sqe, qe1);
- } else {
- isp_put_ctio2(isp, sqe, qe1);
- }
- if (isp->isp_dblev & ISP_LOGTDEBUG1) {
- isp_print_bytes(isp, "synthetic final queue entry", QENTRY_LEN, storage2);
- }
- }
-
((isphdr_t *)fqe)->rqs_entry_count = nqe;
switch (type) {
case RQSTYPE_CTIO:
@@ -2225,7 +2258,11 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_
break;
case RQSTYPE_CTIO2:
case RQSTYPE_CTIO3:
- ((ct2_entry_t *)fqe)->ct_seg_count = nsegs;
+ if (((ct2_entry_t *)fqe)->ct_flags & CT2_FLAG_MODE2) {
+ ((ct2_entry_t *)fqe)->ct_seg_count = 1;
+ } else {
+ ((ct2_entry_t *)fqe)->ct_seg_count = nsegs;
+ }
if (ISP_CAP_2KLOGIN(isp)) {
isp_put_ctio2e(isp, fqe, qe0);
} else {
@@ -2233,7 +2270,11 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_
}
break;
case RQSTYPE_CTIO7:
- ((ct7_entry_t *)fqe)->ct_seg_count = nsegs;
+ if (((ct7_entry_t *)fqe)->ct_flags & CT7_FLAG_MODE2) {
+ ((ct7_entry_t *)fqe)->ct_seg_count = 1;
+ } else {
+ ((ct7_entry_t *)fqe)->ct_seg_count = nsegs;
+ }
isp_put_ctio7(isp, fqe, qe0);
break;
default:
@@ -2405,8 +2446,9 @@ isp_find_chan_by_did(ispsoftc_t *isp, uint32_t did, uint16_t *cp)
* Add an initiator device to the port database
*/
void
-isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint32_t s_id)
+isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint32_t s_id, uint16_t prli_params)
{
+ char buf[64];
fcparam *fcp;
fcportdb_t *lp;
isp_notify_t nt;
@@ -2415,8 +2457,8 @@ isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
fcp = FCPARAM(isp, chan);
if (nphdl >= MAX_NPORT_HANDLE) {
- isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx bad N-Port handle 0x%04x Port ID 0x%06x",
- __func__, chan, (unsigned long long) ini, nphdl, s_id);
+ isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx bad N-Port handle 0x%04x Port ID 0x%06x",
+ chan, (unsigned long long) ini, nphdl, s_id);
return;
}
@@ -2451,19 +2493,18 @@ isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
if (lp) {
int something = 0;
if (lp->handle != nphdl) {
- isp_prt(isp, ISP_LOGWARN, "%s: Chan %d attempt to re-enter N-port handle 0x%04x IID 0x%016llx Port ID 0x%06x finds IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x",
- __func__, chan, nphdl, (unsigned long long)ini, s_id, (unsigned long long) lp->port_wwn, lp->handle, lp->portid);
+ isp_prt(isp, ISP_LOGWARN, "Chan %d attempt to re-enter N-port handle 0x%04x IID 0x%016llx Port ID 0x%06x finds IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x",
+ chan, nphdl, (unsigned long long)ini, s_id, (unsigned long long) lp->port_wwn, lp->handle, lp->portid);
isp_dump_portdb(isp, chan);
return;
}
if (s_id != PORT_NONE) {
if (lp->portid == PORT_NONE) {
lp->portid = s_id;
- isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d N-port handle 0x%04x gets Port ID 0x%06x", __func__, chan, nphdl, s_id);
+ isp_prt(isp, ISP_LOGTINFO, "Chan %d N-port handle 0x%04x gets Port ID 0x%06x", chan, nphdl, s_id);
something++;
} else if (lp->portid != s_id) {
- isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d N-port handle 0x%04x tries to change Port ID 0x%06x to 0x%06x", __func__, chan, nphdl,
- lp->portid, s_id);
+ isp_prt(isp, ISP_LOGTINFO, "Chan %d N-port handle 0x%04x tries to change Port ID 0x%06x to 0x%06x", chan, nphdl, lp->portid, s_id);
isp_dump_portdb(isp, chan);
return;
}
@@ -2471,18 +2512,24 @@ isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
if (VALID_INI(ini)) {
if (!VALID_INI(lp->port_wwn)) {
lp->port_wwn = ini;
- isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d N-port handle 0x%04x gets WWN 0x%016llxx", __func__, chan, nphdl, (unsigned long long) ini);
+ isp_prt(isp, ISP_LOGTINFO, "Chan %d N-port handle 0x%04x gets WWN 0x%016llxx", chan, nphdl, (unsigned long long) ini);
something++;
} else if (lp->port_wwn != ini) {
- isp_prt(isp, ISP_LOGWARN, "%s: Chan %d N-port handle 0x%04x tries to change WWN 0x%016llx to 0x%016llx", __func__, chan, nphdl,
+ isp_prt(isp, ISP_LOGWARN, "Chan %d N-port handle 0x%04x tries to change WWN 0x%016llx to 0x%016llx", chan, nphdl,
(unsigned long long) lp->port_wwn, (unsigned long long) ini);
isp_dump_portdb(isp, chan);
return;
}
}
-
+ if (prli_params != lp->prli_word3) {
+ lp->prli_word3 = prli_params;
+ isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
+ isp_prt(isp, ISP_LOGTINFO|ISP_LOGCONFIG, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x new PRLI Word 3 params %s", chan,
+ (unsigned long long) lp->port_wwn, lp->handle, lp->portid, buf);
+ something++;
+ }
if (!something) {
- isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x reentered", __func__, chan,
+ isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x reentered", chan,
(unsigned long long) lp->port_wwn, lp->handle, lp->portid);
}
return;
@@ -2500,8 +2547,8 @@ isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
}
}
if (i < 0) {
- isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x- no room in port database",
- __func__, chan, (unsigned long long) ini, nphdl, s_id);
+ isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x- no room in port database",
+ chan, (unsigned long long) ini, nphdl, s_id);
return;
}
@@ -2511,9 +2558,12 @@ isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
lp->handle = nphdl;
lp->portid = s_id;
lp->port_wwn = ini;
+ lp->prli_word3 = prli_params;
+ isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
fcp->isp_tgt_map[nphdl] = i + 1;
- isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d added", __func__, chan, (unsigned long long) ini, nphdl, s_id, fcp->isp_tgt_map[nphdl] - 1);
+ isp_prt(isp, ISP_LOGTINFO, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d %s added", chan,
+ (unsigned long long) ini, nphdl, s_id, fcp->isp_tgt_map[nphdl] - 1, buf);
ISP_MEMZERO(&nt, sizeof (nt));
nt.nt_hba = isp;
@@ -2538,8 +2588,8 @@ isp_del_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
fcportdb_t *lp;
if (nphdl >= MAX_NPORT_HANDLE) {
- isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx bad N-Port handle 0x%04x Port ID 0x%06x",
- __func__, chan, (unsigned long long) ini, nphdl, s_id);
+ isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx bad N-Port handle 0x%04x Port ID 0x%06x",
+ chan, (unsigned long long) ini, nphdl, s_id);
return;
}
@@ -2553,13 +2603,13 @@ isp_del_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3
}
}
if (lp == NULL) {
- isp_prt(isp, ISP_LOGWARN, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x cannot be found to be cleared",
- __func__, chan, (unsigned long long) ini, nphdl, s_id);
+ isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x cannot be found to be cleared",
+ chan, (unsigned long long) ini, nphdl, s_id);
isp_dump_portdb(isp, chan);
return;
}
- isp_prt(isp, ISP_LOGTINFO, "%s: Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d cleared",
- __func__, chan, (unsigned long long) lp->port_wwn, nphdl, lp->portid, fcp->isp_tgt_map[nphdl] - 1);
+ isp_prt(isp, ISP_LOGTINFO, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d cleared",
+ chan, (unsigned long long) lp->port_wwn, nphdl, lp->portid, fcp->isp_tgt_map[nphdl] - 1);
fcp->isp_tgt_map[nphdl] = 0;
ISP_MEMZERO(&nt, sizeof (nt));
@@ -2650,7 +2700,7 @@ isp_del_wwn_entries(ispsoftc_t *isp, isp_notify_t *mp)
return;
}
}
- isp_prt(isp, ISP_LOGWARN, "%s: Chan %d unable to find entry to delete N-port handle 0x%04x initiator WWN 0x%016llx Port ID 0x%06x", __func__,
+ isp_prt(isp, ISP_LOGWARN, "Chan %d unable to find entry to delete N-port handle 0x%04x initiator WWN 0x%016llx Port ID 0x%06x",
mp->nt_channel, mp->nt_nphdl, (unsigned long long) mp->nt_wwn, mp->nt_sid);
}
@@ -2973,8 +3023,14 @@ isp_put_ctio2(ispsoftc_t *isp, ct2_entry_t *src, ct2_entry_t *dst)
ISP_IOXPUT_16(isp, src->rsp.m2._reserved2, &dst->rsp.m2._reserved2);
ISP_IOXPUT_16(isp, src->rsp.m2._reserved3, &dst->rsp.m2._reserved3);
ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, &dst->rsp.m2.ct_datalen);
- ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base);
- ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count);
+ if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO2) {
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base, &dst->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base);
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count, &dst->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count);
+ } else {
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base, &dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base);
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi, &dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi);
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count, &dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count);
+ }
}
}
@@ -3026,8 +3082,14 @@ isp_put_ctio2e(ispsoftc_t *isp, ct2e_entry_t *src, ct2e_entry_t *dst)
ISP_IOXPUT_16(isp, src->rsp.m2._reserved2, &dst->rsp.m2._reserved2);
ISP_IOXPUT_16(isp, src->rsp.m2._reserved3, &dst->rsp.m2._reserved3);
ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, &dst->rsp.m2.ct_datalen);
- ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base);
- ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count);
+ if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO2) {
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base, &dst->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base);
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count, &dst->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count);
+ } else {
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base, &dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base);
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi, &dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi);
+ ISP_IOXPUT_32(isp, src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count, &dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count);
+ }
}
}
@@ -3072,8 +3134,9 @@ isp_put_ctio7(ispsoftc_t *isp, ct7_entry_t *src, ct7_entry_t *dst)
}
} else {
ISP_IOXPUT_32(isp, src->rsp.m2.reserved0, &dst->rsp.m2.reserved0);
- ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, &dst->rsp.m2.ct_datalen);
ISP_IOXPUT_32(isp, src->rsp.m2.reserved1, &dst->rsp.m2.reserved1);
+ ISP_IOXPUT_32(isp, src->rsp.m2.ct_datalen, &dst->rsp.m2.ct_datalen);
+ ISP_IOXPUT_32(isp, src->rsp.m2.reserved2, &dst->rsp.m2.reserved2);
ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_base, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_base);
ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_basehi, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_basehi);
ISP_IOXPUT_32(isp, src->rsp.m2.ct_fcp_rsp_iudata.ds_count, &dst->rsp.m2.ct_fcp_rsp_iudata.ds_count);
@@ -3132,8 +3195,14 @@ isp_get_ctio2(ispsoftc_t *isp, ct2_entry_t *src, ct2_entry_t *dst)
ISP_IOXGET_16(isp, &src->rsp.m2._reserved2, dst->rsp.m2._reserved2);
ISP_IOXGET_16(isp, &src->rsp.m2._reserved3, dst->rsp.m2._reserved3);
ISP_IOXGET_32(isp, &src->rsp.m2.ct_datalen, dst->rsp.m2.ct_datalen);
- ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_base, dst->rsp.m2.ct_fcp_rsp_iudata.ds_base);
- ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_count, dst->rsp.m2.ct_fcp_rsp_iudata.ds_count);
+ if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO2) {
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base, dst->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base);
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count, dst->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count);
+ } else {
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base, dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base);
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi, dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi);
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count, dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count);
+ }
}
}
@@ -3187,8 +3256,14 @@ isp_get_ctio2e(ispsoftc_t *isp, ct2e_entry_t *src, ct2e_entry_t *dst)
ISP_IOXGET_16(isp, &src->rsp.m2._reserved2, dst->rsp.m2._reserved2);
ISP_IOXGET_16(isp, &src->rsp.m2._reserved3, dst->rsp.m2._reserved3);
ISP_IOXGET_32(isp, &src->rsp.m2.ct_datalen, dst->rsp.m2.ct_datalen);
- ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_base, dst->rsp.m2.ct_fcp_rsp_iudata.ds_base);
- ISP_IOXGET_32(isp, &src->rsp.m2.ct_fcp_rsp_iudata.ds_count, dst->rsp.m2.ct_fcp_rsp_iudata.ds_count);
+ if (src->ct_header.rqs_entry_type == RQSTYPE_CTIO2) {
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base, dst->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_base);
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count, dst->rsp.m2.u.ct_fcp_rsp_iudata_32.ds_count);
+ } else {
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base, dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_base);
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi, dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_basehi);
+ ISP_IOXGET_32(isp, &src->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count, dst->rsp.m2.u.ct_fcp_rsp_iudata_64.ds_count);
+ }
}
}
OpenPOWER on IntegriCloud