1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #ifndef	_FCT_IMPL_H
26 #define	_FCT_IMPL_H
27 
28 #ifdef	__cplusplus
29 extern "C" {
30 #endif
31 
32 #define	RSCN_OPTION_VERIFY	0x0001
33 
34 typedef enum fct_li_state {
35 	LI_STATE_DO_FLOGI = 0,	/* FLOGI handled by FCA */
36 	LI_STATE_FINI_TOPOLOGY,	/* Finalize topology */
37 	LI_STATE_N2N_PLOGI,	/* In case of a N2N connection */
38 
39 	LI_STATE_DO_FCLOGIN,	/* Login into 0xFFFFFD */
40 	LI_STATE_DO_SCR,	/* State change registration */
41 
42 	LI_STATE_DO_NSLOGIN,	/* Login into 0xFFFFFC */
43 	LI_STATE_DO_RNN,	/* Register node name */
44 	LI_STATE_DO_RCS,	/* Register classes of service */
45 	LI_STATE_DO_RFT,	/* Register FC-4 types */
46 	LI_STATE_DO_RSPN,	/* Register symbolic port name */
47 	LI_STATE_DO_RSNN,	/* Register symbolic node name */
48 
49 	LI_STATE_MAX		/* Not a real state */
50 } fct_li_state_t;
51 
52 #define	LI_STATE_START			0
53 #define	LI_STATE_MASK			0x3F
54 /* Next state depends on the return value */
55 #define	LI_STATE_FLAG_CMD_RETCHECK	0x40
56 /* Link init cmd is still outstanding */
57 #define	LI_STATE_FLAG_CMD_WAITING	0x80
58 /* Flag to indicate that link info is not available yet */
59 #define	LI_STATE_FLAG_NO_LI_YET		0x100
60 
61 #define	FCT_MAX_CACHED_CMDS	256
62 #define	USEC_ELS_TIMEOUT	(10 * 1000 * 1000)
63 #define	USEC_SOL_TIMEOUT	(10 * 1000 * 1000)
64 #define	USEC_DEREG_RP_TIMEOUT	(25 * 1000 * 1000)
65 #define	USEC_DEREG_RP_INTERVAL	(2 * 1000 * 1000)
66 
67 struct fct_i_cmd;
68 typedef void (* fct_icmd_cb_t)(struct fct_i_cmd *icmd);
69 typedef struct fct_i_cmd {
70 	fct_cmd_t		*icmd_cmd;
71 	uint32_t		 icmd_alloc_size;
72 	fct_struct_id_t		 icmd_struct_id;
73 	uint32_t		 icmd_flags;
74 	clock_t			 icmd_start_time;
75 	struct fct_i_cmd	*icmd_next;	/* iport_abort_queue and irp */
76 	struct fct_i_cmd	*icmd_solcmd_next;	/* iport_solcmd_queue */
77 	fct_icmd_cb_t		 icmd_cb;
78 	void			*icmd_cb_private;
79 } fct_i_cmd_t;
80 
81 /*
82  * icmd_flags
83  */
84 #define	ICMD_SESSION_AFFECTING		0x0002
85 #define	ICMD_IN_IRP_QUEUE		0x0004
86 #define	ICMD_BEING_ABORTED		0x0008
87 #define	ICMD_KNOWN_TO_FCA		0x0020
88 #define	ICMD_FCA_ABORT_CALLED		0x0040
89 #define	ICMD_CMD_COMPLETE		0x0080
90 #define	ICMD_IN_TRANSITION		0x0100
91 #define	ICMD_ABTS_RECEIVED		0x0200
92 #define	ICMD_IMPLICIT			0x0400
93 #define	ICMD_IMPLICIT_CMD_HAS_RESOURCE	0x0800
94 /* High order are debug flags */
95 #define	ICMD_ELS_PROCESSING_STARTED	0x80000000
96 
97 /*
98  * For solicited commands, there's only 3 states:
99  * 1) it's new. We need send it to FCA. ICMD_SOLCMD_NEW is set
100  * 2) it's running. We are waiting for completion.
101  * 3) it's completed. We need free it. ICMD_CMD_COMPLETE is set
102  * ICMD_SOLCMD_NEW and ICMD_CMD_COMPLETE should not be set in the same time
103  */
104 #define	ICMD_IN_SOLCMD_QUEUE		0x010000
105 #define	ICMD_SOLCMD_NEW			0x020000
106 
107 typedef struct fct_i_remote_port {
108 	fct_remote_port_t		*irp_rp;
109 	uint32_t			irp_alloc_size;
110 	fct_struct_id_t			irp_struct_id;
111 	krwlock_t			irp_lock;
112 
113 	/* For queueing to local port */
114 	struct fct_i_remote_port	*irp_next;
115 
116 	/* For queueing to handle elses */
117 	struct fct_i_remote_port	*irp_discovery_next;
118 
119 	fct_i_cmd_t			*irp_els_list;
120 
121 	/*
122 	 * sa stands for session affecting, nsa is non session affecting.
123 	 * The els counts only represent elses under progress not the ones
124 	 * that are terminated. active_xchg_count covers everything including
125 	 * the ones waiting to be terminated.
126 	 */
127 	uint16_t			irp_sa_elses_count;
128 	uint16_t			irp_nsa_elses_count;
129 	uint16_t			irp_fcp_xchg_count;
130 	uint16_t			irp_nonfcp_xchg_count;
131 
132 	uint32_t			irp_flags;
133 	clock_t				irp_deregister_timer;
134 	uint32_t			irp_dereg_count;
135 
136 	uint32_t			irp_portid;
137 	uint8_t				irp_id[24];
138 	uint32_t			irp_rcvd_prli_params;
139 	uint32_t			irp_sent_prli_params;
140 
141 	/*
142 	 * Most HBAs will only register symbolic node name instead of port name,
143 	 * so we use SNN as session alias.
144 	 */
145 	stmf_scsi_session_t		*irp_session;
146 	char				*irp_snn;
147 
148 	/* items will be filled in ns cmd */
149 	uint8_t				irp_fc4types[32]; /* FC-4 types */
150 	char				*irp_spn;	/* port symbolic name */
151 	uint32_t			irp_cos;	/* class of service */
152 
153 	uint32_t			irp_rscn_counter;
154 } fct_i_remote_port_t;
155 
156 /*
157  * irp flags
158  */
159 #define	IRP_PLOGI_DONE			0x0001
160 #define	IRP_PRLI_DONE			0x0002
161 #define	IRP_IN_DISCOVERY_QUEUE		0x0004
162 #define	IRP_FCP_CLEANUP			0x0008
163 #define	IRP_SESSION_CLEANUP		(IRP_FCP_CLEANUP | 0x0010)
164 #define	IRP_HANDLE_OPENED		0x0020
165 #define	IRP_SCSI_SESSION_STARTED	0x0040
166 #define	IRP_RSCN_QUEUED			0x0080
167 #define	IRP_SOL_PLOGI_IN_PROGRESS	0x0100
168 
169 typedef struct fct_cmd_slot {
170 	fct_i_cmd_t		*slot_cmd;
171 	uint16_t		slot_no;
172 	uint16_t		slot_next;
173 	uint8_t			slot_uniq_cntr;
174 } fct_cmd_slot_t;
175 #define	FCT_SLOT_EOL		0xffff
176 
177 #define	FCT_HASH_TABLE_SIZE		256
178 #define	FCT_LOOP_HASH(portid)		(portid & 0xff)
179 #define	FCT_FABRIC_HASH(portid)		(((portid & 0x1f00) | \
180 	((portid & 0x70000)>>3)) >> 8)
181 #define	FCT_PORTID_HASH_FUNC(portid) \
182 	((portid & 0xFFFF00)?FCT_FABRIC_HASH(portid):FCT_LOOP_HASH(portid))
183 
184 typedef struct fct_i_local_port {
185 	fct_local_port_t	*iport_port;
186 	uint32_t		iport_alloc_size;
187 	fct_struct_id_t		iport_struct_id;
188 
189 	struct fct_i_local_port	*iport_next;
190 	struct fct_i_local_port	*iport_prev;
191 
192 	char			*iport_alias;
193 	char			iport_alias_mem[16];
194 	uint8_t			iport_id[24];	/* scsi_devid_desc_t */
195 	krwlock_t		iport_lock;
196 	uint32_t		iport_flags;
197 	uint16_t		iport_link_state;
198 	uint8_t			iport_state:7,
199 	    iport_state_not_acked:1;
200 	uint8_t			iport_offline_prstate;
201 	struct fct_link_info	iport_link_info;
202 
203 	fct_i_remote_port_t	**iport_rp_slots;
204 	fct_i_remote_port_t	**iport_rp_tb;
205 	uint32_t		iport_nrps_login; /* currently logged in */
206 	uint32_t		iport_nrps;	/* items in hash table */
207 	uint64_t		iport_last_change;
208 
209 	/*
210 	 * These variables are used to manage fct_cmd_t cache for SCSI traffic
211 	 */
212 	/*
213 	 * Total # of cmds allocated by the driver. Some of which are free
214 	 * and sitting on iport_cached_cmdlist. And some are executing.
215 	 */
216 	uint32_t		iport_total_alloced_ncmds;
217 
218 	/*
219 	 * Max active cmds in last interval (10 or 30 seconds)
220 	 */
221 	uint32_t		iport_max_active_ncmds;
222 
223 	/*
224 	 * # of free cmds sitting on the iport_cached_cmdlist
225 	 */
226 	uint32_t		iport_cached_ncmds;
227 	struct fct_i_cmd	*iport_cached_cmdlist;
228 	kmutex_t		iport_cached_cmd_lock;
229 
230 	/*
231 	 * To release free cmds periodically
232 	 */
233 	clock_t			iport_cmdcheck_clock;
234 
235 	uint16_t		iport_task_green_limit;
236 	uint16_t		iport_task_yellow_limit;
237 	uint16_t		iport_task_red_limit;
238 	/* cmd slots */
239 	uint16_t		iport_nslots_free;
240 
241 	/* upper 16 bits is just a counter to avoid ABA issues */
242 	uint32_t		iport_next_free_slot;
243 
244 	uint8_t			iport_login_retry; /* for flogi and N2N plogi */
245 	uint8_t			iport_link_old_topology;
246 	uint8_t			iport_link_cleanup_retry;
247 	clock_t			iport_li_cmd_timeout; /* for li state m/c */
248 	fct_cmd_slot_t		*iport_cmd_slots;
249 
250 	/* worker thread data */
251 	ddi_taskq_t		*iport_worker_taskq;
252 	kmutex_t		iport_worker_lock;
253 	kcondvar_t		iport_worker_cv;
254 	struct fct_i_event	*iport_event_head;
255 	struct fct_i_event	*iport_event_tail;
256 	struct fct_i_cmd	*iport_abort_queue;
257 	struct fct_i_cmd	**iport_ppicmd_term;
258 
259 	/* link initialization */
260 	fct_status_t		iport_li_comp_status;
261 	enum fct_li_state	iport_li_state;
262 
263 	/* solicited cmd link */
264 	struct fct_i_cmd	*iport_solcmd_queue;
265 
266 	/* rpwe = remote port with pending els(es) */
267 	fct_i_remote_port_t	*iport_rpwe_head;
268 	fct_i_remote_port_t	*iport_rpwe_tail;
269 
270 } fct_i_local_port_t;
271 
272 #define	IPORT_FLOGI_DONE(iport)	PORT_FLOGI_DONE(&(iport)->iport_link_info)
273 
274 /*
275  * iport flags
276  */
277 #define	IPORT_WORKER_RUNNING		0x0001
278 #define	IPORT_TERMINATE_WORKER		0x0002
279 #define	IPORT_WORKER_DOING_TIMEDWAIT	0x0004
280 #define	IPORT_WORKER_DOING_WAIT		0x0008
281 #define	IPORT_FLAG_PORT_OFFLINED	0x0010
282 #define	IPORT_ALLOW_UNSOL_FLOGI		0x0020
283 
284 #define	IS_WORKER_SLEEPING(iport)	((iport)->iport_flags & \
285 	(IPORT_WORKER_DOING_TIMEDWAIT | IPORT_WORKER_DOING_WAIT))
286 
287 /* Limits for scsi task load of local port */
288 #define	FCT_TASK_GREEN_LIMIT		80
289 #define	FCT_TASK_YELLOW_LIMIT		90
290 #define	FCT_TASK_RED_LIMIT		95
291 
292 typedef struct fct_i_event {
293 	struct fct_i_event	*event_next;
294 	int			event_type;
295 } fct_i_event_t;
296 
297 typedef enum { /* Seggested action values for discovery thread */
298     DISC_ACTION_NO_WORK = 0,
299     DISC_ACTION_RESCAN = 1,
300     DISC_ACTION_DELAY_RESCAN = 2,
301     DISC_ACTION_USE_SHORT_DELAY = 4
302 } disc_action_t;
303 
304 /*
305  * Local port state definitions
306  * NOTE that every time there is a state change, the newly set bit suggests
307  * the action. So far there are 3 actions S_PORT_CLEANUP, S_ADAPTER_FATAL
308  * and S_INIT_LINK.
309  */
310 #define	S_RCVD_LINK_DOWN	0x01
311 #define	S_RCVD_LINK_UP		0x02
312 #define	S_LINK_ONLINE		0x04
313 #define	S_INIT_LINK		0x08
314 #define	S_PORT_CLEANUP		0x10
315 
316 #define	PORT_STATE_LINK_DOWN		0x00
317 #define	PORT_STATE_LINK_INIT_START	(S_RCVD_LINK_UP | S_LINK_ONLINE |\
318     S_INIT_LINK)
319 #define	PORT_STATE_LINK_INIT_DONE	(S_LINK_ONLINE)
320 #define	PORT_STATE_LINK_UP_CLEANING	(S_RCVD_LINK_UP | S_PORT_CLEANUP)
321 #define	PORT_STATE_LINK_DOWN_CLEANING	(S_RCVD_LINK_DOWN | S_PORT_CLEANUP)
322 
323 /*
324  * Internal events
325  */
326 #define	FCT_I_EVENT_LINK_INIT_DONE	0x80
327 #define	FCT_I_EVENT_CLEANUP_POLL	0x81
328 
329 /*
330  * Offline processing states, used by worker thread.
331  */
332 #define	FCT_OPR_DONE			0
333 #define	FCT_OPR_START			1
334 #define	FCT_OPR_CMD_CLEANUP_WAIT	2
335 #define	FCT_OPR_INT_CLEANUP_WAIT	3
336 
337 /*
338  * Check time
339  */
340 #define	FCT_CMDLIST_CHECK_SECONDS	10
341 
342 /*
343  * Define frequently used macros
344  */
345 #define	ICMD_TO_CT(x_icmd)	\
346 	((fct_sol_ct_t *)(x_icmd)->icmd_cmd->cmd_specific)
347 
348 #define	ICMD_TO_ELS(x_icmd)	\
349 	((fct_els_t *)(x_icmd)->icmd_cmd->cmd_specific)
350 
351 #define	ICMD_TO_IPORT(x_icmd)	\
352 	((fct_i_local_port_t *)(x_icmd)->icmd_cmd->cmd_port->port_fct_private)
353 
354 #define	ICMD_TO_PORT(x_icmd)	\
355 	((x_icmd)->icmd_cmd->cmd_port)
356 
357 #define	ICMD_TO_IRP(x_icmd)	\
358 	((fct_i_remote_port_t *)(x_icmd)->icmd_cmd->cmd_rp->rp_fct_private)
359 
360 #define	CMD_TO_ICMD(x_cmd)	((fct_i_cmd_t *)(x_cmd)->cmd_fct_private)
361 
362 #define	RP_TO_IRP(x_rp)		((fct_i_remote_port_t *)(x_rp)->rp_fct_private)
363 
364 #define	PORT_TO_IPORT(x_port)	\
365 	((fct_i_local_port_t *)(x_port)->port_fct_private)
366 
367 #define	FCT_IS_ELS_ACC(x_icmd)	\
368 	(((x_icmd)->icmd_cmd->cmd_comp_status == FCT_SUCCESS) &&	\
369 	(ICMD_TO_ELS(x_icmd)->els_resp_payload[0] == ELS_OP_ACC))
370 
371 #define	FCT_IS_CT_ACC(x_icmd)	\
372 	(((x_icmd)->icmd_cmd->cmd_comp_status == FCT_SUCCESS) &&	\
373 	(ICMD_TO_CT(x_icmd)->ct_resp_payload[8] == 0x80) &&\
374 	(ICMD_TO_CT(x_icmd)->ct_resp_payload[9] == 0x02))
375 
376 #define	IPORT_IN_NS_TOPO(x_iport)	\
377 	((x_iport)->iport_link_info.port_topology & PORT_TOPOLOGY_FABRIC_BIT)
378 
379 #define	IS_LOGO_ELS(icmd)	\
380 	(ICMD_TO_ELS(icmd)->els_req_payload[0] == ELS_OP_LOGO)
381 
382 stmf_status_t fct_xfer_scsi_data(scsi_task_t *task,
383     stmf_data_buf_t *dbuf, uint32_t ioflags);
384 stmf_status_t fct_send_scsi_status(scsi_task_t *task, uint32_t ioflags);
385 fct_i_remote_port_t *fct_portid_to_portptr(fct_i_local_port_t *iport,
386     uint32_t portid);
387 fct_i_remote_port_t *fct_lookup_irp_by_nodewwn(fct_i_local_port_t *iport,
388     uint8_t *nodewwn);
389 fct_i_remote_port_t *fct_lookup_irp_by_portwwn(fct_i_local_port_t *iport,
390     uint8_t *portwwn);
391 void fct_queue_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp);
392 void fct_deque_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp);
393 int fct_implicitly_logo_all(fct_i_local_port_t *iport, int force_implicit);
394 void fct_post_implicit_logo(fct_cmd_t *cmd);
395 void fct_rehash(fct_i_local_port_t *iport);
396 uint8_t fct_local_port_cleanup_done(fct_i_local_port_t *iport);
397 void fct_handle_rcvd_abts(fct_cmd_t *cmd);
398 void fct_fill_abts_acc(fct_cmd_t *cmd);
399 void fct_q_for_termination_lock_held(fct_i_local_port_t *iport,
400     fct_i_cmd_t *icmd, fct_status_t s);
401 disc_action_t fct_handle_port_offline(fct_i_local_port_t *iport);
402 disc_action_t fct_cmd_terminator(fct_i_local_port_t *iport);
403 void fct_cmd_free(fct_cmd_t *cmd);
404 void fct_scsi_task_free(scsi_task_t *task);
405 stmf_status_t fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd,
406     void *arg, uint32_t flags);
407 stmf_status_t fct_info(uint32_t cmd, stmf_local_port_t *lport,
408     void *arg, uint8_t *buf, uint32_t *bufsizep);
409 void fct_event_handler(stmf_local_port_t *lport, int eventid,
410     void *arg, uint32_t flags);
411 uint16_t fct_alloc_cmd_slot(fct_i_local_port_t *iport, fct_cmd_t *cmd);
412 void fct_post_to_discovery_queue(fct_i_local_port_t *iport,
413     fct_i_remote_port_t *irp, fct_i_cmd_t *icmd);
414 fct_cmd_t *fct_create_solct(fct_local_port_t *port, fct_remote_port_t *rp,
415     uint16_t ctop, fct_icmd_cb_t icmdcb);
416 fct_cmd_t *fct_create_solels(fct_local_port_t *port, fct_remote_port_t *rp,
417     int implicit, uchar_t elsop, uint32_t wkdid, fct_icmd_cb_t icmdcb);
418 void fct_handle_solct(fct_cmd_t *cmd);
419 void fct_post_to_solcmd_queue(fct_local_port_t *port, fct_cmd_t *cmd);
420 void fct_logo_cb(fct_i_cmd_t *icmd);
421 void fct_link_init_cb(fct_i_cmd_t *icmd);
422 void fct_gsnn_cb(fct_i_cmd_t *icmd);
423 void fct_gcs_cb(fct_i_cmd_t *icmd);
424 void fct_gft_cb(fct_i_cmd_t *icmd);
425 void fct_gspn_cb(fct_i_cmd_t *icmd);
426 disc_action_t fct_process_link_init(fct_i_local_port_t *iport);
427 
428 #ifdef	__cplusplus
429 }
430 #endif
431 
432 #endif /* _FCT_IMPL_H */
433