diff options
| author | Priya Krishnan <Priya.Krishnan@Sun.COM> | 2009-11-17 15:48:05 -0500 |
|---|---|---|
| committer | Priya Krishnan <Priya.Krishnan@Sun.COM> | 2009-11-17 15:48:05 -0500 |
| commit | 60220f10412f6a7c5b45f950f6f6aa364658a179 (patch) | |
| tree | 9b7570206c0f49cfe38f79f2911483b961627344 /usr/src/uts/common | |
| parent | 31f572c226019e62b274ff14c94d5a53f5d79ee8 (diff) | |
| download | illumos-gate-60220f10412f6a7c5b45f950f6f6aa364658a179.tar.gz | |
6766563 iscsit should support phase collapse
Diffstat (limited to 'usr/src/uts/common')
| -rw-r--r-- | usr/src/uts/common/io/comstar/port/iscsit/iscsit.c | 206 | ||||
| -rw-r--r-- | usr/src/uts/common/io/comstar/port/iscsit/iscsit.h | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c | 5 | ||||
| -rw-r--r-- | usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/io/ib/clients/iser/iser_xfer.c | 17 | ||||
| -rw-r--r-- | usr/src/uts/common/io/idm/idm.c | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/io/idm/idm_impl.c | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/io/idm/idm_so.c | 37 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/idm/idm.h | 4 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/idm/idm_impl.h | 6 |
11 files changed, 199 insertions, 86 deletions
diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c index 896a1f2d07..801bf2904e 100644 --- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c @@ -141,9 +141,6 @@ void 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 @@ iscsit_client_notify(idm_conn_t *ic, idm_client_notify_t icn, 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 @@ iscsit_build_hdr(idm_task_t *idm_task, idm_pdu_t *pdu, uint8_t opcode) /* 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 @@ iscsit_build_hdr(idm_task_t *idm_task, idm_pdu_t *pdu, uint8_t opcode) * 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 @@ iscsit_keepalive(idm_conn_t *ic) */ 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 @@ iscsit_conn_accept(idm_conn_t *ic) 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 @@ iscsit_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf, 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 @@ iscsit_xfer_scsi_data(scsi_task_t *task, stmf_data_buf_t *dbuf, 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 @@ iscsit_buf_xfer_cb(idm_buf_t *idb, idm_status_t status) } /* - * 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 @@ iscsit_send_scsi_status(scsi_task_t *task, uint32_t ioflags) /* * 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 @@ iscsit_send_scsi_status(scsi_task_t *task, uint32_t ioflags) 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 @@ iscsit_send_direct_scsi_resp(iscsit_conn_t *ict, idm_pdu_t *rx_pdu, 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 @@ iscsit_send_task_mgmt_resp(idm_pdu_t *tm_resp_pdu, uint8_t tm_status) { 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 @@ iscsit_pdu_op_noop(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) 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 @@ iscsit_pdu_op_noop(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) 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 @@ iscsit_pdu_op_logout_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) /* 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 @@ iscsit_set_cmdsn(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) } /* - * 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 @@ iscsit_send_async_event(iscsit_conn_t *ict, uint8_t event) 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 @@ iscsit_send_reject(iscsit_conn_t *ict, idm_pdu_t *rejected_pdu, uint8_t reason) 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); diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h index ac1be1683a..eea078a31d 100644 --- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.h @@ -491,6 +491,7 @@ typedef struct iscsit_conn_s { 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_rx_pdu_error_cb_t iscsit_rx_pdu_error; 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; /* diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c index bd726eb9e5..dba720a3f6 100644 --- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_login.c @@ -890,8 +890,8 @@ login_sm_send_next_response(iscsit_conn_t *ict, idm_pdu_t *pdu) 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 @@ login_sm_send_next_response(iscsit_conn_t *ict, idm_pdu_t *pdu) } iscsit_conn_hold(ict); + pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; iscsit_pdu_tx(pdu); } else { /* diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c index 05f78f3f3e..c9111f42d4 100644 --- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_text.c @@ -397,6 +397,8 @@ iscsit_send_next_text_response(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) */ 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); /* diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c index eeadd82943..8700ec544c 100644 --- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit_tgt.c @@ -1948,6 +1948,8 @@ iscsit_portal_online(iscsit_portal_t *portal) 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) != diff --git a/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c b/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c index 9b4c09bc47..02661b55fa 100644 --- a/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c +++ b/usr/src/uts/common/io/ib/clients/iser/iser_xfer.c @@ -246,10 +246,22 @@ iser_xfer_ctrlpdu(iser_chan_t *chan, idm_pdu_t *pdu) 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 @@ iser_xfer_ctrlpdu(iser_chan_t *chan, idm_pdu_t *pdu) 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; /* diff --git a/usr/src/uts/common/io/idm/idm.c b/usr/src/uts/common/io/idm/idm.c index 6538950282..6660910ba8 100644 --- a/usr/src/uts/common/io/idm/idm.c +++ b/usr/src/uts/common/io/idm/idm.c @@ -1285,7 +1285,7 @@ idm_task_alloc(idm_conn_t *ic) idt->idt_private = NULL; idt->idt_exp_datasn = 0; idt->idt_exp_rttsn = 0; - + idt->idt_flags = 0; return (idt); } diff --git a/usr/src/uts/common/io/idm/idm_impl.c b/usr/src/uts/common/io/idm/idm_impl.c index 1b3fa2e369..02ca53c2c6 100644 --- a/usr/src/uts/common/io/idm/idm_impl.c +++ b/usr/src/uts/common/io/idm/idm_impl.c @@ -1026,7 +1026,7 @@ idm_task_constructor(void *hdl, void *arg, int flags) * 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); } diff --git a/usr/src/uts/common/io/idm/idm_so.c b/usr/src/uts/common/io/idm/idm_so.c index 6506591b77..12c04cf788 100644 --- a/usr/src/uts/common/io/idm/idm_so.c +++ b/usr/src/uts/common/io/idm/idm_so.c @@ -2298,8 +2298,10 @@ idm_i_so_tx(idm_pdu_t *pdu) * 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 @@ idm_so_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb) 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 @@ idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb, /* 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 @@ idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb, 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 @@ idm_so_send_buf_region(idm_task_t *idt, idm_buf_t *idb, 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 @@ idm_sotx_thread(void *arg) 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; diff --git a/usr/src/uts/common/sys/idm/idm.h b/usr/src/uts/common/sys/idm/idm.h index ada422a1b0..0be365e42e 100644 --- a/usr/src/uts/common/sys/idm/idm.h +++ b/usr/src/uts/common/sys/idm/idm.h @@ -149,6 +149,9 @@ typedef void (idm_task_cb_t)(struct idm_task_s *task, idm_status_t status); 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 @@ typedef struct { 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; diff --git a/usr/src/uts/common/sys/idm/idm_impl.h b/usr/src/uts/common/sys/idm/idm_impl.h index ef507ed3be..c015216018 100644 --- a/usr/src/uts/common/sys/idm/idm_impl.h +++ b/usr/src/uts/common/sys/idm/idm_impl.h @@ -260,6 +260,7 @@ typedef struct idm_task_s { */ 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 @@ void idm_task_destructor(void *task_void, void *arg); #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 @@ typedef struct { #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 |
