1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
#ifndef _STMF_IMPL_H
#define _STMF_IMPL_H
#include <sys/stmf_defines.h>
#include <sys/stmf_ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint32_t stmf_event_handle_t;
#define STMF_MAX_NUM_EVENTS (sizeof (stmf_event_handle_t) * 8)
#define STMF_EVENT_ADD(h, e) (atomic_or_32(&(h), \
((uint32_t)1) << (e)))
#define STMF_EVENT_REMOVE(h, e) (atomic_and_32(&(h), \
~(((uint32_t)1) << (e))))
#define STMF_EVENT_ENABLED(h, e) (((h) & ((uint32_t)1) << (e)) != 0)
#define STMF_EVENT_CLEAR_ALL(h) ((h) = 0)
#define STMF_EVENT_ALLOC_HANDLE(h) ((h) = 0)
#define STMF_EVENT_FREE_HANDLE(h) ((h) = 0)
#define STMF_TGT_NAME_LEN 256
#define STMF_GUID_INPUT 32
#define STMF_UPDATE_KSTAT_IO(kip, dbuf) \
if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) { \
kip->reads++; \
kip->nread += dbuf->db_data_size; \
} else { \
kip->writes++; \
kip->nwritten += dbuf->db_data_size; \
}
struct stmf_i_scsi_task;
struct stmf_itl_data;
typedef struct stmf_i_lu_provider {
stmf_lu_provider_t *ilp_lp;
uint32_t ilp_alloc_size;
uint32_t ilp_nlus; /* # LUNs being exported */
uint32_t ilp_cb_in_progress:1,
ilp_rsvd:31;
struct stmf_i_lu_provider *ilp_next;
struct stmf_pp_data *ilp_ppd;
} stmf_i_lu_provider_t;
typedef struct stmf_i_lu {
stmf_lu_t *ilu_lu;
uint32_t ilu_alloc_size;
uint32_t ilu_flags;
uint32_t ilu_ref_cnt;
uint8_t ilu_state;
uint8_t ilu_prev_state;
uint8_t ilu_access;
uint8_t ilu_alua;
stmf_event_handle_t ilu_event_hdl;
struct stmf_i_lu *ilu_next;
struct stmf_i_lu *ilu_prev;
char *ilu_alias;
char ilu_ascii_hex_guid[STMF_GUID_INPUT + 1];
kmutex_t ilu_task_lock;
uint32_t ilu_task_cntr1;
uint32_t ilu_task_cntr2;
uint32_t *ilu_cur_task_cntr;
uint32_t ilu_ntasks; /* # of tasks in the ilu_task list */
uint32_t ilu_ntasks_free; /* # of tasks that are free */
uint32_t ilu_ntasks_min_free; /* # minimal free tasks */
uint32_t ilu_additional_ref;
uint32_t ilu_proxy_registered;
uint64_t ilu_reg_msgid;
struct stmf_i_scsi_task *ilu_tasks;
struct stmf_i_scsi_task *ilu_free_tasks;
struct stmf_itl_data *ilu_itl_list;
kstat_t *ilu_kstat_info;
kstat_t *ilu_kstat_io;
kmutex_t ilu_kstat_lock;
kcondvar_t ilu_offline_pending_cv;
/* point to the luid entry in stmf_state.stmf_luid_list */
void *ilu_luid;
} stmf_i_lu_t;
/*
* ilu_flags
*/
#define ILU_STALL_DEREGISTER 0x0001
#define ILU_RESET_ACTIVE 0x0002
typedef struct stmf_i_port_provider {
stmf_port_provider_t *ipp_pp;
uint32_t ipp_alloc_size;
uint32_t ipp_npps;
uint32_t ipp_cb_in_progress:1,
ipp_rsvd:31;
struct stmf_i_port_provider *ipp_next;
struct stmf_pp_data *ipp_ppd;
} stmf_i_port_provider_t;
#define MAX_ILPORT 0x10000
typedef struct stmf_i_local_port {
stmf_local_port_t *ilport_lport;
uint32_t ilport_alloc_size;
uint32_t ilport_nsessions;
struct stmf_i_scsi_session *ilport_ss_list;
krwlock_t ilport_lock;
struct stmf_i_local_port *ilport_next;
struct stmf_i_local_port *ilport_prev;
uint8_t ilport_state;
uint8_t ilport_prev_state;
uint8_t ilport_standby;
uint8_t ilport_alua;
uint16_t ilport_rtpid; /* relative tpid */
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;
uint32_t ilport_online_times;
uint32_t ilport_flags;
kstat_t *ilport_kstat_info;
kstat_t *ilport_kstat_io;
kmutex_t ilport_kstat_lock;
char ilport_kstat_tgt_name[STMF_TGT_NAME_LEN];
/* which target group this port belongs to in stmf_state.stmf_tg_list */
void *ilport_tg;
id_t ilport_instance;
/* XXX Need something to track all the remote ports also */
} stmf_i_local_port_t;
#define STMF_AVG_ONLINE_INTERVAL (30 * drv_usectohz(1000000))
#define MAX_IRPORT 0x10000
typedef struct stmf_i_remote_port {
struct scsi_devid_desc *irport_id;
kmutex_t irport_mutex;
int irport_refcnt;
id_t irport_instance;
avl_node_t irport_ln;
/* number of active read tasks */
uint32_t irport_nread_tasks;
/* number of active write tasks */
uint32_t irport_nwrite_tasks;
hrtime_t irport_rdstart_timestamp;
hrtime_t irport_rddone_timestamp;
hrtime_t irport_wrstart_timestamp;
hrtime_t irport_wrdone_timestamp;
kstat_t *irport_kstat_info;
kstat_t *irport_kstat_io;
kstat_t *irport_kstat_estat; /* extended stats */
boolean_t irport_info_dirty;
} stmf_i_remote_port_t;
/*
* ilport flags
*/
#define ILPORT_FORCED_OFFLINE 0x01
#define ILPORT_SS_GOT_INITIAL_LUNS 0x02
typedef struct stmf_i_scsi_session {
stmf_scsi_session_t *iss_ss;
uint32_t iss_alloc_size;
uint32_t iss_flags;
stmf_i_remote_port_t *iss_irport;
struct stmf_i_scsi_session *iss_next;
/*
* Ideally we should maintain 2 maps. One would indicate a new map
* which will become available only upon receipt of a REPORT LUN
* cmd.
*/
struct stmf_lun_map *iss_sm;
/*
* which host group the host of this session belongs to in
* stmf_state.stmf_hg_list
*/
void *iss_hg;
krwlock_t *iss_lockp;
time_t iss_creation_time;
} stmf_i_scsi_session_t;
/*
* iss flags
*/
#define ISS_LUN_INVENTORY_CHANGED 0x0001
#define ISS_RESET_ACTIVE 0x0002
#define ISS_BEING_CREATED 0x0004
#define ISS_GOT_INITIAL_LUNS 0x0008
#define ISS_EVENT_ACTIVE 0x0010
#define ISS_NULL_TPTID 0x0020
#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;
uint32_t itask_alloc_size;
uint32_t itask_flags;
kmutex_t itask_mutex; /* protects flags and lists */
uint64_t itask_proxy_msg_id;
stmf_data_buf_t *itask_proxy_dbuf;
struct stmf_worker *itask_worker;
uint32_t *itask_ilu_task_cntr;
struct stmf_i_scsi_task *itask_worker_next;
struct stmf_i_scsi_task *itask_lu_next;
struct stmf_i_scsi_task *itask_lu_prev;
struct stmf_i_scsi_task *itask_lu_free_next;
struct stmf_itl_data *itask_itl_datap;
clock_t itask_start_time; /* abort and normal */
/* For now we only support 4 parallel buffers. Should be enough. */
stmf_data_buf_t *itask_dbufs[4];
clock_t itask_poll_timeout;
uint8_t itask_cmd_stack[ITASK_MAX_NCMDS];
uint8_t itask_ncmds;
uint8_t itask_allocated_buf_map;
uint16_t itask_cdb_buf_size;
/* Task profile data */
hrtime_t itask_start_timestamp;
hrtime_t itask_done_timestamp;
hrtime_t itask_xfer_done_timestamp;
hrtime_t itask_waitq_enter_timestamp;
hrtime_t itask_waitq_time;
hrtime_t itask_lu_read_time;
hrtime_t itask_lu_write_time;
hrtime_t itask_lport_read_time;
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
/*
* Common code to encode an itask onto the worker_task queue is placed
* in this macro to simplify future maintenace activity.
*/
#define STMF_ENQUEUE_ITASK(w, i) \
ASSERT((itask->itask_flags & ITASK_IN_FREE_LIST) == 0); \
ASSERT(mutex_owned(&itask->itask_mutex)); \
ASSERT(mutex_owned(&w->worker_lock)); \
i->itask_worker_next = NULL; \
if (w->worker_task_tail) { \
w->worker_task_tail->itask_worker_next = i; \
} else { \
w->worker_task_head = i; \
} \
w->worker_task_tail = i; \
if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { \
w->worker_max_qdepth_pu = w->worker_queue_depth; \
} \
atomic_inc_32(&w->worker_ref_count); \
atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); \
i->itask_waitq_enter_timestamp = gethrtime(); \
if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) \
cv_signal(&w->worker_cv);
#define STMF_DEQUEUE_ITASK(w, itask) \
ASSERT(mutex_owned(&w->worker_lock)); \
if ((itask = w->worker_task_head) != NULL) { \
w->worker_task_head = itask->itask_worker_next; \
if (w->worker_task_head == NULL) { \
w->worker_task_tail = NULL; \
} \
} else { \
w->worker_task_tail = NULL; \
}
/*
* itask_flags
*/
#define ITASK_IN_FREE_LIST 0x0001
#define ITASK_IN_TRANSITION 0x0002
#define ITASK_IN_WORKER_QUEUE 0x0004
#define ITASK_BEING_ABORTED 0x0008
#define ITASK_BEING_COMPLETED 0x0010
#define ITASK_KNOWN_TO_TGT_PORT 0x0020
#define ITASK_KNOWN_TO_LU 0x0040
#define ITASK_LU_ABORT_CALLED 0x0080
#define ITASK_TGT_PORT_ABORT_CALLED 0x0100
#define ITASK_DEFAULT_HANDLING 0x0200
#define ITASK_CAUSING_LU_RESET 0x0400
#define ITASK_CAUSING_TARGET_RESET 0x0800
#define ITASK_KSTAT_IN_RUNQ 0x1000
#define ITASK_PROXY_TASK 0x2000
/*
* itask cmds.
*/
#define ITASK_CMD_MASK 0x1F
#define ITASK_CMD_BUF_NDX(cmd) (((uint8_t)(cmd)) >> 5)
#define ITASK_CMD_NEW_TASK 0x1
#define ITASK_CMD_DATA_XFER_DONE 0x2
#define ITASK_CMD_STATUS_DONE 0x3
#define ITASK_CMD_ABORT 0x4
#define ITASK_CMD_SEND_STATUS 0x5
#define ITASK_CMD_POLL 0x10
#define ITASK_CMD_POLL_LU (ITASK_CMD_POLL | 1)
#define ITASK_CMD_POLL_LPORT (ITASK_CMD_POLL | 2)
/*
* struct maintained on a per itl basis when the lu registers ITL handle.
*/
typedef struct stmf_itl_data {
uint32_t itl_counter;
uint8_t itl_flags;
uint8_t itl_hdlrm_reason;
uint16_t itl_lun;
void *itl_handle;
struct stmf_i_lu *itl_ilu;
struct stmf_i_scsi_session *itl_session;
struct stmf_itl_data *itl_next;
} stmf_itl_data_t;
/*
* itl flags
*/
#define STMF_ITL_BEING_TERMINATED 0x01
/*
* data structures to maintain provider private data.
*/
typedef struct stmf_pp_data {
struct stmf_pp_data *ppd_next;
void *ppd_provider;
nvlist_t *ppd_nv;
uint32_t ppd_lu_provider:1,
ppd_port_provider:1,
ppd_rsvd:30;
uint32_t ppd_alloc_size;
uint64_t ppd_token;
char ppd_name[8];
} stmf_pp_data_t;
typedef struct stmf_worker {
kthread_t *worker_tid;
stmf_i_scsi_task_t *worker_task_head;
stmf_i_scsi_task_t *worker_task_tail;
stmf_i_scsi_task_t *worker_wait_head;
stmf_i_scsi_task_t *worker_wait_tail;
kmutex_t worker_lock;
kcondvar_t worker_cv;
uint32_t worker_flags;
uint32_t worker_queue_depth; /* ntasks cur queued */
uint32_t worker_max_qdepth_pu; /* maxqd / unit time */
uint32_t worker_max_sys_qdepth_pu; /* for all workers */
uint32_t worker_ref_count; /* # IOs referencing */
hrtime_t worker_signal_timestamp;
} stmf_worker_t;
/*
* worker flags
*/
#define STMF_WORKER_STARTED 1
#define STMF_WORKER_ACTIVE 2
#define STMF_WORKER_TERMINATE 4
/*
* data struct for managing transfers.
*/
typedef struct stmf_xfer_data {
uint32_t alloc_size; /* Including this struct */
uint32_t size_done;
uint32_t size_left;
uint8_t buf[4];
} stmf_xfer_data_t;
/*
* Define frequently used macros
*/
#define TASK_TO_ITASK(x_task) \
((stmf_i_scsi_task_t *)(x_task)->task_stmf_private)
void stmf_dlun_init();
stmf_status_t stmf_dlun_fini();
void stmf_worker_init();
stmf_status_t stmf_worker_fini();
void stmf_task_free(scsi_task_t *task);
void stmf_do_task_abort(scsi_task_t *task);
void stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl,
uint8_t hdlrm_reason);
void stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid,
void *arg, uint32_t flags);
void stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid,
void *arg, uint32_t flags);
#ifdef __cplusplus
}
#endif
#endif /* _STMF_IMPL_H */
|