Mercurial > illumos > illumos-gate
changeset 11081:5c9c847827a4
6766563 iscsit should support phase collapse
author | Priya Krishnan <Priya.Krishnan@Sun.COM> |
---|---|
date | Tue, 17 Nov 2009 15:48:05 -0500 |
parents | 368ac1f03f55 |
children | 2209146bde7a |
files | usr/src/uts/common/io/comstar/port/iscsit/iscsit.c usr/src/uts/common/io/comstar/port/iscsit/iscsit.h usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c usr/src/uts/common/io/ib/clients/iser/iser_xfer.c usr/src/uts/common/io/idm/idm.c usr/src/uts/common/io/idm/idm_impl.c usr/src/uts/common/io/idm/idm_so.c usr/src/uts/common/sys/idm/idm.h usr/src/uts/common/sys/idm/idm_impl.h |
diffstat | 11 files changed, 199 insertions(+), 86 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c Tue Nov 17 15:48:05 2009 -0500 @@ -141,9 +141,6 @@ iscsit_set_cmdsn(iscsit_conn_t *ict, idm_pdu_t *rx_pdu); static void -iscsit_calc_rspsn(iscsit_conn_t *ict, idm_pdu_t *resp); - -static void iscsit_deferred_dispatch(idm_pdu_t *rx_pdu); static void @@ -949,6 +946,48 @@ return (rc); } +/* + * iscsit_update_statsn is invoked for all the PDUs which have the StatSN + * field in the header. The StatSN is incremented if the IDM_PDU_ADVANCE_STATSN + * flag is set in the pdu flags field. The StatSN is connection-wide and is + * protected by the mutex ict_statsn_mutex. For Data-In PDUs, if the flag + * IDM_TASK_PHASECOLLAPSE_REQ is set, the status (phase-collapse) is also filled + */ +void +iscsit_update_statsn(idm_task_t *idm_task, idm_pdu_t *pdu) +{ + iscsi_scsi_rsp_hdr_t *rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr; + iscsit_conn_t *ict = (iscsit_conn_t *)pdu->isp_ic->ic_handle; + iscsit_task_t *itask = NULL; + scsi_task_t *task = NULL; + + mutex_enter(&ict->ict_statsn_mutex); + rsp->statsn = htonl(ict->ict_statsn); + if (pdu->isp_flags & IDM_PDU_ADVANCE_STATSN) + ict->ict_statsn++; + mutex_exit(&ict->ict_statsn_mutex); + + /* + * The last SCSI Data PDU passed for a command may also contain the + * status if the status indicates termination with no expections, i.e. + * no sense data or response involved. If the command completes with + * an error, then the response and sense data will be sent in a + * separate iSCSI Response PDU. + */ + if ((idm_task) && (idm_task->idt_flags & IDM_TASK_PHASECOLLAPSE_REQ)) { + itask = idm_task->idt_private; + task = itask->it_stmf_task; + + rsp->cmd_status = task->task_scsi_status; + rsp->flags |= ISCSI_FLAG_DATA_STATUS; + if (task->task_status_ctrl & TASK_SCTRL_OVER) { + rsp->flags |= ISCSI_FLAG_CMD_OVERFLOW; + } else if (task->task_status_ctrl & TASK_SCTRL_UNDER) { + rsp->flags |= ISCSI_FLAG_CMD_UNDERFLOW; + } + rsp->residual_count = htonl(task->task_resid); + } +} void iscsit_build_hdr(idm_task_t *idm_task, idm_pdu_t *pdu, uint8_t opcode) @@ -971,6 +1010,7 @@ /* Maintain current statsn for RTT responses */ dh->statsn = (opcode == ISCSI_OP_RTT_RSP) ? htonl(itask->it_ict->ict_statsn) : 0; + dh->expcmdsn = htonl(itask->it_ict->ict_sess->ist_expcmdsn); dh->maxcmdsn = htonl(itask->it_ict->ict_sess->ist_maxcmdsn); @@ -981,7 +1021,7 @@ * data.dlength * data.datasn * data.offset - * residual_count and cmd_status (if we ever implement phase collapse) + * statsn, residual_count and cmd_status (for phase collapse) * rtt.rttsn * rtt.data_offset * rtt.data_length @@ -1006,13 +1046,20 @@ */ nop_in_pdu = idm_pdu_alloc(sizeof (*nop_in), 0); idm_pdu_init(nop_in_pdu, ic, NULL, NULL); - nop_in = (iscsi_nop_in_hdr_t *)nop_in_pdu->isp_hdr; bzero(nop_in, sizeof (*nop_in)); nop_in->opcode = ISCSI_OP_NOOP_IN; nop_in->flags = ISCSI_FLAG_FINAL; nop_in->itt = ISCSI_RSVD_TASK_TAG; /* + * When the target sends a NOP-In as a Ping, the target transfer tag + * is set to a valid (not reserved) value and the initiator task tag + * is set to ISCSI_RSVD_TASK_TAG (0xffffffff). In this case the StatSN + * will always contain the next sequence number but the StatSN for the + * connection is not advanced after this PDU is sent. + */ + nop_in_pdu->isp_flags |= IDM_PDU_SET_STATSN; + /* * This works because we don't currently allocate ttt's anywhere else * in iscsit so as long as we stay out of IDM's range we are safe. * If we need to allocate ttt's for other PDU's in the future this will @@ -1058,6 +1105,7 @@ ict->ict_keepalive_ttt = IDM_TASKIDS_MAX; /* Avoid IDM TT range */ ic->ic_handle = ict; mutex_init(&ict->ict_mutex, NULL, MUTEX_DRIVER, NULL); + mutex_init(&ict->ict_statsn_mutex, NULL, MUTEX_DRIVER, NULL); idm_refcnt_init(&ict->ict_refcnt, ict); /* @@ -1317,6 +1365,7 @@ uint32_t ioflags) { iscsit_task_t *iscsit_task = task->task_port_private; + iscsit_sess_t *ict_sess = iscsit_task->it_ict->ict_sess; iscsit_buf_t *ibuf = dbuf->db_port_private; int idm_rc; @@ -1333,26 +1382,34 @@ ASSERT(ibuf->ibuf_is_immed == B_FALSE); if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) { /* + * The DB_SEND_STATUS_GOOD flag in the STMF data buffer allows + * the port provider to phase-collapse, i.e. send the status + * along with the final data PDU for the command. The port + * provider passes this request to the transport layer by + * setting a flag IDM_TASK_PHASECOLLAPSE_REQ in the task. + */ + if (dbuf->db_flags & DB_SEND_STATUS_GOOD) + iscsit_task->it_idm_task->idt_flags |= + IDM_TASK_PHASECOLLAPSE_REQ; + /* * IDM will call iscsit_build_hdr so lock now to serialize * access to the SN values. We need to lock here to enforce * lock ordering */ - rw_enter(&iscsit_task->it_ict->ict_sess->ist_sn_rwlock, - RW_READER); + rw_enter(&ict_sess->ist_sn_rwlock, RW_READER); idm_rc = idm_buf_tx_to_ini(iscsit_task->it_idm_task, ibuf->ibuf_idm_buf, dbuf->db_relative_offset, dbuf->db_data_size, &iscsit_buf_xfer_cb, dbuf); - rw_exit(&iscsit_task->it_ict->ict_sess->ist_sn_rwlock); + rw_exit(&ict_sess->ist_sn_rwlock); return (iscsit_idm_to_stmf(idm_rc)); } else if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) { /* Grab the SN lock (see comment above) */ - rw_enter(&iscsit_task->it_ict->ict_sess->ist_sn_rwlock, - RW_READER); + rw_enter(&ict_sess->ist_sn_rwlock, RW_READER); idm_rc = idm_buf_rx_from_ini(iscsit_task->it_idm_task, ibuf->ibuf_idm_buf, dbuf->db_relative_offset, dbuf->db_data_size, &iscsit_buf_xfer_cb, dbuf); - rw_exit(&iscsit_task->it_ict->ict_sess->ist_sn_rwlock); + rw_exit(&ict_sess->ist_sn_rwlock); return (iscsit_idm_to_stmf(idm_rc)); } @@ -1377,13 +1434,24 @@ } /* - * COMSTAR currently requires port providers to support - * the DB_SEND_STATUS_GOOD flag even if phase collapse is - * not supported. So we will roll our own... pretend we are - * COMSTAR and ask for a status PDU. + * For ISCSI over TCP (not iSER), the last SCSI Data PDU passed + * for a successful command contains the status as requested by + * by COMSTAR (via the DB_SEND_STATUS_GOOD flag). But the iSER + * transport does not support phase-collapse. So pretend we are + * COMSTAR and send the status in a separate PDU now. */ - if ((dbuf->db_flags & DB_SEND_STATUS_GOOD) && + if (idb->idb_task_binding->idt_flags & IDM_TASK_PHASECOLLAPSE_SUCCESS) { + /* + * Mark task complete, remove task from the session task + * list and notify COMSTAR that the status has been sent. + */ + iscsit_task_done(itask); + itask->it_idm_task->idt_state = TASK_COMPLETE; + stmf_send_status_done(itask->it_stmf_task, + iscsit_idm_to_stmf(status), STMF_IOF_LPORT_DONE); + } else if ((dbuf->db_flags & DB_SEND_STATUS_GOOD) && status == IDM_STATUS_SUCCESS) { + /* * If iscsit_send_scsi_status succeeds then the TX PDU * callback will call stmf_send_status_done and set @@ -1465,11 +1533,14 @@ /* * Fast path. Cached status PDU's are already * initialized. We just need to fill in - * connection and task information. + * connection and task information. StatSN is + * incremented by 1 for every status sent a + * connection. */ pdu = kmem_cache_alloc(iscsit_status_pdu_cache, KM_SLEEP); pdu->isp_ic = itask->it_ict->ict_ic; pdu->isp_private = itask; + pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr; rsp->itt = itask->it_itt; @@ -1492,6 +1563,7 @@ pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), resp_datalen); idm_pdu_init(pdu, itask->it_ict->ict_ic, itask, iscsit_send_status_done); + pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr; bzero(rsp, sizeof (*rsp)); @@ -2009,6 +2081,13 @@ rsp_pdu = idm_pdu_alloc(sizeof (iscsi_scsi_rsp_hdr_t), 0); idm_pdu_init(rsp_pdu, ic, NULL, NULL); + /* + * StatSN is incremented by 1 for every response sent on + * a connection except for responses sent as a result of + * a retry or SNACK + */ + rsp_pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; + resp = (iscsi_scsi_rsp_hdr_t *)rsp_pdu->isp_hdr; resp->opcode = ISCSI_OP_SCSI_RSP; @@ -2038,6 +2117,13 @@ { iscsi_scsi_task_mgt_rsp_hdr_t *tm_resp; + /* + * The target must take note of the last-sent StatSN. + * The StatSN is to be incremented after sending a + * task management response. Digest recovery can only + * work if StatSN is incremented. + */ + tm_resp_pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; tm_resp = (iscsi_scsi_task_mgt_rsp_hdr_t *)tm_resp_pdu->isp_hdr; tm_resp->response = tm_status; @@ -2261,6 +2347,14 @@ bcopy(rx_pdu->isp_data, resp->isp_data, resp_datalen); } + /* + * When sending a NOP-In as a response to a NOP-Out from the initiator, + * the target must respond with the same initiator task tag that was + * provided in the NOP-Out request, the target transfer tag must be + * ISCSI_RSVD_TASK_TAG (0xffffffff) and StatSN will contain the next + * status sequence number. The StatSN for the connection is advanced + * after this PDU is sent. + */ in = (iscsi_nop_in_hdr_t *)resp->isp_hdr; bzero(in, sizeof (*in)); in->opcode = ISCSI_OP_NOOP_IN; @@ -2269,7 +2363,7 @@ in->itt = out->itt; in->ttt = ISCSI_RSVD_TASK_TAG; hton24(in->dlength, resp_datalen); - + resp->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; /* Any other field in resp to be set? */ iscsit_pdu_tx(resp); idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS); @@ -2297,7 +2391,12 @@ /* Allocate a PDU to respond */ resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0); idm_pdu_init(resp, ict->ict_ic, NULL, NULL); - + /* + * The StatSN is to be sent to the initiator, + * it is not required to increment the number + * as the connection is terminating. + */ + resp->isp_flags |= IDM_PDU_SET_STATSN; /* * Logout results in the immediate termination of all tasks except * if the logout reason is ISCSI_LOGOUT_REASON_RECOVERY. The @@ -2350,64 +2449,26 @@ } /* - * Update local StatSN and set SNs in response - */ -static void -iscsit_calc_rspsn(iscsit_conn_t *ict, idm_pdu_t *resp) -{ - iscsit_sess_t *ist; - iscsi_scsi_rsp_hdr_t *rsp; - - /* Get iSCSI session handle */ - ist = ict->ict_sess; - - rsp = (iscsi_scsi_rsp_hdr_t *)resp->isp_hdr; - - /* Update StatSN */ - rsp->statsn = htonl(ict->ict_statsn); - switch (IDM_PDU_OPCODE(resp)) { - case ISCSI_OP_RTT_RSP: - /* Do nothing */ - break; - case ISCSI_OP_NOOP_IN: - /* - * Refer to section 10.19.1, RFC3720. - * Advance only if target is responding initiator - */ - if (((iscsi_nop_in_hdr_t *)rsp)->ttt == ISCSI_RSVD_TASK_TAG) - ict->ict_statsn++; - break; - case ISCSI_OP_SCSI_DATA_RSP: - if (rsp->flags & ISCSI_FLAG_DATA_STATUS) - ict->ict_statsn++; - else - rsp->statsn = 0; - break; - default: - ict->ict_statsn++; - break; - } - - /* Set ExpCmdSN and MaxCmdSN */ - rsp->maxcmdsn = htonl(ist->ist_maxcmdsn); - rsp->expcmdsn = htonl(ist->ist_expcmdsn); -} - -/* * Wrapper funtion, calls iscsi_calc_rspsn and idm_pdu_tx */ void iscsit_pdu_tx(idm_pdu_t *pdu) { iscsit_conn_t *ict = pdu->isp_ic->ic_handle; + iscsi_scsi_rsp_hdr_t *rsp = (iscsi_scsi_rsp_hdr_t *)pdu->isp_hdr; + iscsit_sess_t *ist = ict->ict_sess; /* - * Protect ict->ict_statsn, ist->ist_maxcmdsn, and ist->ist_expcmdsn - * (which are used by iscsit_calc_rspsn) with the session mutex - * (ist->ist_sn_mutex). + * The command sequence numbers are session-wide and must stay + * consistent across the transfer, so protect the cmdsn with a + * reader lock on the session. The status sequence number will + * be updated just before the transport layer transmits the PDU. */ - rw_enter(&ict->ict_sess->ist_sn_rwlock, RW_WRITER); - iscsit_calc_rspsn(ict, pdu); + + rw_enter(&ict->ict_sess->ist_sn_rwlock, RW_READER); + /* Set ExpCmdSN and MaxCmdSN */ + rsp->maxcmdsn = htonl(ist->ist_maxcmdsn); + rsp->expcmdsn = htonl(ist->ist_expcmdsn); idm_pdu_tx(pdu); rw_exit(&ict->ict_sess->ist_sn_rwlock); } @@ -2431,8 +2492,14 @@ return; } + /* + * A asynchronous message is sent by the target to request a logout. + * The StatSN for the connection is advanced after the PDU is sent + * to allow for initiator and target state synchronization. + */ idm_pdu_init(abt, ict->ict_ic, NULL, NULL); abt->isp_datalen = 0; + abt->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; async_abt = (iscsi_async_evt_hdr_t *)abt->isp_hdr; bzero(async_abt, sizeof (*async_abt)); @@ -2475,7 +2542,8 @@ return; } idm_pdu_init(reject_pdu, ict->ict_ic, NULL, NULL); - + /* StatSN is advanced after a Reject PDU */ + reject_pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; reject_pdu->isp_datalen = rejected_pdu->isp_hdrlen; bcopy(rejected_pdu->isp_hdr, reject_pdu->isp_data, rejected_pdu->isp_hdrlen);
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h Tue Nov 17 15:48:05 2009 -0500 @@ -491,6 +491,7 @@ iscsit_op_params_t ict_op; uint16_t ict_cid; uint32_t ict_statsn; + kmutex_t ict_statsn_mutex; uint32_t ict_keepalive_ttt; struct iscsit_conn_s *ict_reinstate_conn; uint32_t ict_reinstating:1, @@ -622,6 +623,7 @@ idm_task_cb_t iscsit_task_aborted; idm_client_notify_cb_t iscsit_client_notify; idm_build_hdr_cb_t iscsit_build_hdr; +idm_update_statsn_cb_t iscsit_update_statsn; idm_keepalive_cb_t iscsit_keepalive; /*
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c Tue Nov 17 15:48:05 2009 -0500 @@ -890,8 +890,8 @@ hton24(lh_resp->dlength, pdu->isp_datalen); /* - * If this is going to be the last PDU of a login response - * that moves us to FFP then generate the ILE_LOGIN_FFP event. + * If the login is successful, this login response will contain + * the next StatSN and advance the StatSN for the connection. */ if (lh_resp->status_class == ISCSI_STATUS_CLASS_SUCCESS) { ASSERT(ict->ict_sess != NULL); @@ -911,6 +911,7 @@ } iscsit_conn_hold(ict); + pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; iscsit_pdu_tx(pdu); } else { /*
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c Tue Nov 17 15:48:05 2009 -0500 @@ -397,6 +397,8 @@ */ resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), len); idm_pdu_init(resp, ict->ict_ic, ict, iscsit_text_resp_complete_cb); + /* Advance the StatSN for each Text Response sent */ + resp->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; base = ict->ict_text_rsp_buf + ict->ict_text_rsp_off; bcopy(base, resp->isp_data, len); /*
--- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c Tue Nov 17 15:48:05 2009 -0500 @@ -1948,6 +1948,8 @@ sr.sr_conn_ops.icb_client_notify = &iscsit_client_notify; sr.sr_conn_ops.icb_build_hdr = &iscsit_build_hdr; + sr.sr_conn_ops.icb_update_statsn = + &iscsit_update_statsn; sr.sr_conn_ops.icb_keepalive = &iscsit_keepalive; if (idm_tgt_svc_create(&sr, &svc) !=
--- a/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c Tue Nov 17 15:48:05 2009 -0500 @@ -246,10 +246,22 @@ return (ISER_STATUS_FAIL); } + ic = chan->ic_conn->ic_idmc; + + /* Pull the BHS out of the PDU handle */ + bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; + /* * All SCSI command PDU (except SCSI Read and SCSI Write) and the SCSI * Response PDU are sent to the remote end using the SendSE Message. * + * The StatSN may need to be sent (and possibly advanced) at this time + * for some PDUs, identified by the IDM_PDU_SET_STATSN flag. + */ + if (pdu->isp_flags & IDM_PDU_SET_STATSN) { + (ic->ic_conn_ops.icb_update_statsn)(NULL, pdu); + } + /* * Setup a Send Message for carrying the iSCSI control-type PDU * preceeded by an iSER header. */ @@ -268,11 +280,6 @@ return (ISER_STATUS_FAIL); } - /* Pull the BHS out of the PDU handle */ - bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; - - ic = chan->ic_conn->ic_idmc; - hdr = (iser_ctrl_hdr_t *)(uintptr_t)msg->msg_ds.ds_va; /*
--- a/usr/src/uts/common/io/idm/idm.c Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/idm/idm.c Tue Nov 17 15:48:05 2009 -0500 @@ -1285,7 +1285,7 @@ idt->idt_private = NULL; idt->idt_exp_datasn = 0; idt->idt_exp_rttsn = 0; - + idt->idt_flags = 0; return (idt); }
--- a/usr/src/uts/common/io/idm/idm_impl.c Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/idm/idm_impl.c Tue Nov 17 15:48:05 2009 -0500 @@ -1026,7 +1026,7 @@ * transport that requires a different size, we'll revisit this. */ idt->idt_transport_hdr = (void *)(idt + 1); /* pointer arithmetic */ - + idt->idt_flags = 0; return (0); }
--- a/usr/src/uts/common/io/idm/idm_so.c Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/io/idm/idm_so.c Tue Nov 17 15:48:05 2009 -0500 @@ -2298,8 +2298,10 @@ * DataSN starts with 0 for the first data PDU of an input command and advances * by 1 for each subsequent data PDU. Each sequence will have its own F bit, * which is set to 1 for the last data PDU of a sequence. + * If the initiator supports phase collapse, the status bit must be set along + * with the F bit to indicate that the status is shipped together with the last + * Data-In PDU. * - * Scope for Prototype build: * The data PDUs within a sequence will be sent in order with the buffer offset * in increasing order. i.e. initiator and target must have negotiated the * "DataPDUInOrder" to "Yes". The order between sequences is not enforced. @@ -2391,6 +2393,7 @@ pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP); pdu->isp_ic = idt->idt_ic; + pdu->isp_flags = 0; /* initialize isp_flags */ bzero(pdu->isp_hdr, sizeof (iscsi_rtt_hdr_t)); /* iSCSI layer fills the TTT, ITT, StatSN, ExpCmdSN, MaxCmdSN */ @@ -2588,6 +2591,7 @@ /* Data PDU headers will always be sizeof (iscsi_hdr_t) */ pdu = kmem_cache_alloc(idm.idm_sotx_pdu_cache, KM_SLEEP); pdu->isp_ic = ic; + pdu->isp_flags = 0; /* initialize isp_flags */ /* * We've already built a build a header template @@ -2609,10 +2613,27 @@ hton24(bhs->dlength, chunk); bhs->offset = htonl(idb->idb_bufoffset + data_offset); + /* setup data */ + pdu->isp_data = (uint8_t *)idb->idb_buf + data_offset; + pdu->isp_datalen = (uint_t)chunk; + if (chunk == remainder) { bhs->flags = ISCSI_FLAG_FINAL; /* F bit set to 1 */ + /* Piggyback the status with the last data PDU */ + if (idt->idt_flags & IDM_TASK_PHASECOLLAPSE_REQ) { + pdu->isp_flags |= IDM_PDU_SET_STATSN | + IDM_PDU_ADVANCE_STATSN; + (*idt->idt_ic->ic_conn_ops.icb_update_statsn) + (idt, pdu); + idt->idt_flags |= + IDM_TASK_PHASECOLLAPSE_SUCCESS; + + } } + remainder -= chunk; + data_offset += chunk; + /* Instrument the data-send DTrace probe. */ if (IDM_PDU_OPCODE(pdu) == ISCSI_OP_SCSI_DATA_RSP) { DTRACE_ISCSI_2(data__send, @@ -2620,11 +2641,6 @@ iscsi_data_rsp_hdr_t *, (iscsi_data_rsp_hdr_t *)pdu->isp_hdr); } - /* setup data */ - pdu->isp_data = (uint8_t *)idb->idb_buf + data_offset; - pdu->isp_datalen = (uint_t)chunk; - remainder -= chunk; - data_offset += chunk; /* * Now that we're done working with idt_exp_datasn, @@ -2767,13 +2783,18 @@ mutex_exit(&so_conn->ic_tx_mutex); switch (object->idm_tx_obj_magic) { - case IDM_PDU_MAGIC: + case IDM_PDU_MAGIC: { + idm_pdu_t *pdu = (idm_pdu_t *)object; DTRACE_PROBE2(soconn__tx__pdu, idm_conn_t *, ic, idm_pdu_t *, (idm_pdu_t *)object); + if (pdu->isp_flags & IDM_PDU_SET_STATSN) { + /* No IDM task */ + (ic->ic_conn_ops.icb_update_statsn)(NULL, pdu); + } status = idm_i_so_tx((idm_pdu_t *)object); break; - + } case IDM_BUF_MAGIC: { idm_buf_t *idb = (idm_buf_t *)object; idm_task_t *idt = idb->idb_task_binding;
--- a/usr/src/uts/common/sys/idm/idm.h Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/sys/idm/idm.h Tue Nov 17 15:48:05 2009 -0500 @@ -149,6 +149,9 @@ typedef void (idm_build_hdr_cb_t)( struct idm_task_s *task, struct idm_pdu_s *pdu, uint8_t opcode); +typedef void (idm_update_statsn_cb_t)( + struct idm_task_s *task, struct idm_pdu_s *pdu); + typedef void (idm_keepalive_cb_t)(struct idm_conn_s *ic); typedef union idm_sockaddr { @@ -169,6 +172,7 @@ idm_task_cb_t *icb_task_aborted; idm_client_notify_cb_t *icb_client_notify; idm_build_hdr_cb_t *icb_build_hdr; + idm_update_statsn_cb_t *icb_update_statsn; /* advance statsn */ idm_keepalive_cb_t *icb_keepalive; } idm_conn_ops_t;
--- a/usr/src/uts/common/sys/idm/idm_impl.h Tue Nov 17 11:03:15 2009 -0800 +++ b/usr/src/uts/common/sys/idm/idm_impl.h Tue Nov 17 15:48:05 2009 -0500 @@ -260,6 +260,7 @@ */ int idt_transport_hdrlen; void *idt_transport_hdr; + uint32_t idt_flags; /* phase collapse */ } idm_task_t; int idm_task_constructor(void *task_void, void *arg, int flags); @@ -268,6 +269,9 @@ #define IDM_TASKIDS_MAX 16384 #define IDM_BUF_MAGIC 0x49425546 /* "IBUF" */ +#define IDM_TASK_PHASECOLLAPSE_REQ 0x00000001 /* request phase collapse */ +#define IDM_TASK_PHASECOLLAPSE_SUCCESS 0x00000002 /* phase collapse success */ + /* Protect with task mutex */ typedef struct idm_buf_s { uint32_t idb_magic; /* "IBUF" */ @@ -392,6 +396,8 @@ #define IDM_PDU_ADDL_HDR 0x00000002 #define IDM_PDU_ADDL_DATA 0x00000004 #define IDM_PDU_LOGIN_TX 0x00000008 +#define IDM_PDU_SET_STATSN 0x00000010 +#define IDM_PDU_ADVANCE_STATSN 0x00000020 #define OSD_EXT_CDB_AHSLEN (200 - 15) #define BIDI_AHS_LENGTH 5