Mercurial > illumos > illumos-gate
changeset 12625:918cc39de2dd
6912676 STMF should attempt to catch port provider data transfer double completions
6958379 auditing for SCSI tasks in stmf
author | John Forte <John.Forte@Sun.COM> |
---|---|
date | Tue, 15 Jun 2010 19:09:16 -0700 |
parents | a1fa1ee4d57c |
children | eba16697f6c1 |
files | usr/src/uts/common/io/comstar/stmf/stmf.c usr/src/uts/common/io/comstar/stmf/stmf_impl.h usr/src/uts/common/sys/stmf.h |
diffstat | 3 files changed, 98 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/comstar/stmf/stmf.c Tue Jun 15 13:48:52 2010 -0400 +++ b/usr/src/uts/common/io/comstar/stmf/stmf.c Tue Jun 15 19:09:16 2010 -0700 @@ -74,6 +74,10 @@ char *info); static int stmf_set_alua_state(stmf_alua_state_desc_t *alua_state); static void stmf_get_alua_state(stmf_alua_state_desc_t *alua_state); + +static void stmf_task_audit(stmf_i_scsi_task_t *itask, + task_audit_event_t te, uint32_t cmd_or_iof, stmf_data_buf_t *dbuf); + stmf_xfer_data_t *stmf_prepare_tpgs_data(uint8_t ilu_alua); void stmf_svc_init(); stmf_status_t stmf_svc_fini(); @@ -4246,6 +4250,7 @@ if (dbuf) { task->task_cur_nbufs++; itask->itask_allocated_buf_map |= (1 << ndx); + dbuf->db_flags &= ~DB_LPORT_XFER_ACTIVE; dbuf->db_handle = ndx; return (dbuf); } @@ -4428,6 +4433,7 @@ } itask = (stmf_i_scsi_task_t *)task->task_stmf_private; itask->itask_cdb_buf_size = cdb_length; + mutex_init(&itask->itask_audit_mutex, NULL, MUTEX_DRIVER, NULL); } task->task_session = ss; task->task_lport = lport; @@ -4437,6 +4443,7 @@ itask->itask_lu_read_time = itask->itask_lu_write_time = 0; itask->itask_lport_read_time = itask->itask_lport_write_time = 0; itask->itask_read_xfer = itask->itask_write_xfer = 0; + itask->itask_audit_index = 0; if (new_task) { if (lu->lu_task_alloc(task) != STMF_SUCCESS) { @@ -4707,6 +4714,8 @@ stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) task->task_session->ss_stmf_private; + stmf_task_audit(itask, TE_TASK_FREE, CMD_OR_IOF_NA, NULL); + stmf_free_task_bufs(itask, lport); stmf_itl_task_done(itask); DTRACE_PROBE2(stmf__task__end, scsi_task_t *, task, @@ -4833,6 +4842,7 @@ atomic_add_32(&w->worker_ref_count, 1); itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK; itask->itask_ncmds = 1; + stmf_task_audit(itask, TE_TASK_START, CMD_OR_IOF_NA, dbuf); if (dbuf) { itask->itask_allocated_buf_map = 1; itask->itask_dbufs[0] = dbuf; @@ -4860,6 +4870,24 @@ } } +static void +stmf_task_audit(stmf_i_scsi_task_t *itask, + task_audit_event_t te, uint32_t cmd_or_iof, stmf_data_buf_t *dbuf) +{ + stmf_task_audit_rec_t *ar; + + mutex_enter(&itask->itask_audit_mutex); + ar = &itask->itask_audit_records[itask->itask_audit_index++]; + itask->itask_audit_index &= (ITASK_TASK_AUDIT_DEPTH - 1); + ar->ta_event = te; + ar->ta_cmd_or_iof = cmd_or_iof; + ar->ta_itask_flags = itask->itask_flags; + ar->ta_dbuf = dbuf; + gethrestime(&ar->ta_timestamp); + mutex_exit(&itask->itask_audit_mutex); +} + + /* * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++ * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already @@ -4879,11 +4907,13 @@ stmf_status_t stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags) { - stmf_status_t ret; + stmf_status_t ret = STMF_SUCCESS; stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)task->task_stmf_private; + stmf_task_audit(itask, TE_XFER_START, ioflags, dbuf); + if (ioflags & STMF_IOF_LU_DONE) { uint32_t new, old; do { @@ -4911,14 +4941,17 @@ return (STMF_SUCCESS); } + dbuf->db_flags |= DB_LPORT_XFER_ACTIVE; ret = task->task_lport->lport_xfer_data(task, dbuf, ioflags); /* * Port provider may have already called the buffer callback in * which case dbuf->db_xfer_start_timestamp will be 0. */ - if ((ret != STMF_SUCCESS) && (dbuf->db_xfer_start_timestamp != 0)) { - stmf_lport_xfer_done(itask, dbuf); + if (ret != STMF_SUCCESS) { + dbuf->db_flags &= ~DB_LPORT_XFER_ACTIVE; + if (dbuf->db_xfer_start_timestamp != 0) + stmf_lport_xfer_done(itask, dbuf); } return (ret); @@ -4929,12 +4962,29 @@ { stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)task->task_stmf_private; + stmf_i_local_port_t *ilport; stmf_worker_t *w = itask->itask_worker; uint32_t new, old; uint8_t update_queue_flags, free_it, queue_it; stmf_lport_xfer_done(itask, dbuf); + stmf_task_audit(itask, TE_XFER_DONE, iof, dbuf); + + /* Guard against unexpected completions from the lport */ + if (dbuf->db_flags & DB_LPORT_XFER_ACTIVE) { + dbuf->db_flags &= ~DB_LPORT_XFER_ACTIVE; + } else { + /* + * This should never happen. + */ + ilport = task->task_lport->lport_stmf_private; + ilport->ilport_unexpected_comp++; + cmn_err(CE_PANIC, "Unexpected xfer completion task %p dbuf %p", + (void *)task, (void *)dbuf); + return; + } + mutex_enter(&w->worker_lock); do { new = old = itask->itask_flags; @@ -5012,6 +5062,9 @@ stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *)task->task_stmf_private; + + stmf_task_audit(itask, TE_SEND_STATUS, ioflags, NULL); + if (ioflags & STMF_IOF_LU_DONE) { uint32_t new, old; do { @@ -5058,6 +5111,8 @@ uint32_t new, old; uint8_t free_it, queue_it; + stmf_task_audit(itask, TE_SEND_STATUS_DONE, iof, NULL); + mutex_enter(&w->worker_lock); do { new = old = itask->itask_flags; @@ -5171,6 +5226,8 @@ stmf_worker_t *w; uint32_t old, new; + stmf_task_audit(itask, TE_TASK_ABORT, CMD_OR_IOF_NA, NULL); + do { old = new = itask->itask_flags; if ((old & ITASK_BEING_ABORTED) || @@ -5255,6 +5312,8 @@ stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); unsigned long long st; + stmf_task_audit(itask, TE_TASK_LU_ABORTED, iof, NULL); + st = s; /* gcc fix */ if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { (void) snprintf(info, sizeof (info), @@ -5282,6 +5341,8 @@ unsigned long long st; uint32_t old, new; + stmf_task_audit(itask, TE_TASK_LPORT_ABORTED, iof, NULL); + st = s; if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { (void) snprintf(info, sizeof (info), @@ -6582,6 +6643,7 @@ dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)]; mutex_exit(&w->worker_lock); curcmd &= ITASK_CMD_MASK; + stmf_task_audit(itask, TE_PROCESS_CMD, curcmd, dbuf); switch (curcmd) { case ITASK_CMD_NEW_TASK: iss = (stmf_i_scsi_session_t *)
--- a/usr/src/uts/common/io/comstar/stmf/stmf_impl.h Tue Jun 15 13:48:52 2010 -0400 +++ b/usr/src/uts/common/io/comstar/stmf/stmf_impl.h Tue Jun 15 19:09:16 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _STMF_IMPL_H #define _STMF_IMPL_H @@ -137,6 +136,7 @@ uint16_t ilport_proxy_registered; uint64_t ilport_reg_msgid; uint8_t ilport_no_standby_lu; + uint32_t ilport_unexpected_comp; stmf_event_handle_t ilport_event_hdl; clock_t ilport_last_online_clock; clock_t ilport_avg_interval; @@ -215,6 +215,33 @@ #define ITASK_MAX_NCMDS 14 #define ITASK_DEFAULT_POLL_TIMEOUT 0 + +#define ITASK_TASK_AUDIT_DEPTH 32 /* Must be a power of 2 */ + +typedef enum { + TE_UNDEFINED, + TE_TASK_START, + TE_XFER_START, + TE_XFER_DONE, + TE_SEND_STATUS, + TE_SEND_STATUS_DONE, + TE_TASK_FREE, + TE_TASK_ABORT, + TE_TASK_LPORT_ABORTED, + TE_TASK_LU_ABORTED, + TE_PROCESS_CMD +} task_audit_event_t; + +#define CMD_OR_IOF_NA 0xffffffff + +typedef struct stmf_task_audit_rec { + task_audit_event_t ta_event; + uint32_t ta_cmd_or_iof; + uint32_t ta_itask_flags; + stmf_data_buf_t *ta_dbuf; + timespec_t ta_timestamp; +} stmf_task_audit_rec_t; + struct stmf_worker; typedef struct stmf_i_scsi_task { scsi_task_t *itask_task; @@ -250,6 +277,9 @@ hrtime_t itask_lport_write_time; uint64_t itask_read_xfer; uint64_t itask_write_xfer; + kmutex_t itask_audit_mutex; + uint8_t itask_audit_index; + stmf_task_audit_rec_t itask_audit_records[ITASK_TASK_AUDIT_DEPTH]; } stmf_i_scsi_task_t; #define ITASK_DEFAULT_ABORT_TIMEOUT 5
--- a/usr/src/uts/common/sys/stmf.h Tue Jun 15 13:48:52 2010 -0400 +++ b/usr/src/uts/common/sys/stmf.h Tue Jun 15 19:09:16 2010 -0700 @@ -102,6 +102,7 @@ #define DB_DONT_CACHE 0x0010 #define DB_DONT_REUSE 0x0020 #define DB_LU_DATA_BUF 0x0040 +#define DB_LPORT_XFER_ACTIVE 0x8000 typedef struct scsi_task { void *task_stmf_private;