xref: /illumos-gate/usr/src/uts/common/sys/emul64var.h (revision 2d6eb4a5)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #ifndef _SYS_SCSI_ADAPTERS_EMUL64VAR_H
28 #define	_SYS_SCSI_ADAPTERS_EMUL64VAR_H
29 
30 #include <sys/avl.h>
31 #include <sys/note.h>
32 #include <sys/emul64.h>
33 
34 #ifdef	__cplusplus
35 extern "C" {
36 #endif
37 
38 /*
39  * Convenient short hand defines
40  */
41 #define	TRUE			 1
42 #define	FALSE			 0
43 #define	UNDEFINED		-1
44 
45 #define	CNUM(emul64)		(ddi_get_instance(emul64->emul64_tran.tran_dev))
46 
47 #define	EMUL64_RETRY_DELAY		5
48 #define	EMUL64_RETRIES		0	/* retry of selections */
49 #define	EMUL64_INITIAL_SOFT_SPACE	5 /* Used for the softstate_init func */
50 
51 #define	MSW(x)			(int16_t)(((int32_t)x >> 16) & 0xFFFF)
52 #define	LSW(x)			(int16_t)((int32_t)x & 0xFFFF)
53 
54 #define	TGT(sp)			(CMD2PKT(sp)->pkt_address.a_target)
55 #define	LUN(sp)			(CMD2PKT(sp)->pkt_address.a_lun)
56 
57 #define	HW_REV(val)		(((val) >>8) & 0xff)
58 #define	FW_REV(val)		((val) & 0xff)
59 
60 /*
61  * max number of LUNs per target
62  */
63 #define	EMUL64_NLUNS_PER_TARGET	32
64 
65 /*
66  * Default emul64 scsi-options
67  */
68 #define	EMUL64_DEFAULT_SCSI_OPTIONS					\
69 					SCSI_OPTIONS_PARITY	|	\
70 					SCSI_OPTIONS_DR		|	\
71 					SCSI_OPTIONS_SYNC	|	\
72 					SCSI_OPTIONS_TAG	|	\
73 					SCSI_OPTIONS_FAST	|	\
74 					SCSI_OPTIONS_WIDE
75 
76 /*
77  *	Tag reject
78  */
79 #define	TAG_REJECT	28
80 /*
81  * Interrupt actions returned by emul64_i_flag_event()
82  */
83 #define	ACTION_CONTINUE		0	/* Continue */
84 #define	ACTION_RETURN		1	/* Exit */
85 #define	ACTION_IGNORE		2	/* Ignore */
86 
87 /*
88  * Reset actions for emul64_i_reset_interface()
89  */
90 #define	EMUL64_RESET_BUS_IF_BUSY	0x01 /* reset scsi bus if it is busy */
91 #define	EMUL64_FORCE_RESET_BUS	0x02	/* reset scsi bus on error reco */
92 
93 
94 /*
95  * extracting period and offset from emul64_synch
96  */
97 #define	PERIOD_MASK(val)	((val) & 0xff)
98 #define	OFFSET_MASK(val)	(((val) >>8) & 0xff)
99 
100 /*
101  * timeout values
102  */
103 #define	EMUL64_GRACE		10	/* Timeout margin (sec.) */
104 #define	EMUL64_TIMEOUT_DELAY(secs, delay)	(secs * (1000000 / delay))
105 
106 /*
107  * delay time for polling loops
108  */
109 #define	EMUL64_NOINTR_POLL_DELAY_TIME		1000	/* usecs */
110 
111 /*
112  * busy wait delay time after chip reset
113  */
114 #define	EMUL64_CHIP_RESET_BUSY_WAIT_TIME		100	/* usecs */
115 
116 /*
117  * timeout for EMUL64 coming out of reset
118  */
119 #define	EMUL64_RESET_WAIT				1000	/* ms */
120 #define	EMUL64_SOFT_RESET_TIME			1	/* second */
121 
122 /*
123  * emul64_softstate flags for introducing hot plug
124  */
125 #define	EMUL64_SS_OPEN		0x01
126 #define	EMUL64_SS_DRAINING		0x02
127 #define	EMUL64_SS_QUIESCED		0x04
128 #define	EMUL64_SS_DRAIN_ERROR	0x08
129 
130 /*
131  * ioctl command definitions
132  */
133 #ifndef	EMUL64_RESET_TARGET
134 #define	EMUL64_RESET_TARGET		(('i' << 8) | 0x03)
135 #endif
136 
137 
138 /*
139  * Debugging macros
140  */
141 #define	EMUL64_DEBUG	if (emul64debug) emul64_i_log
142 #define	EMUL64_DEBUG2	if (emul64debug > 1) emul64_i_log
143 
144 
145 #define	REQ_TGT_LUN(tgt, lun)			(((tgt) << 8) | (lun))
146 
147 
148 #define	RESP_CQ_FLAGS(resp)	((resp->resp_header.cq_flags_seq) & 0xff)
149 
150 
151 #define	EMUL64_NDATASEGS		4
152 
153 
154 /*
155  * translate scsi_pkt flags into EMUL64 request packet flags
156  * It would be illegal if two flags are set; the driver does not
157  * check for this. Setting NODISCON and a tag flag is harmless.
158  */
159 #define	EMUL64_SET_PKT_FLAGS(scsa_flags, emul64_flags) {		\
160 	emul64_flags = (scsa_flags >> 11) & 0xe; /* tags */		\
161 	emul64_flags |= (scsa_flags >> 1) & 0x1; /* no disconnect */	\
162 }
163 
164 /*
165  * throttle values for EMUL64 request queue
166  */
167 #define	SHUTDOWN_THROTTLE	-1	/* do not submit any requests */
168 #define	CLEAR_THROTTLE		(EMUL64_MAX_REQUESTS -1)
169 
170 
171 #define	EMUL64_GET_PKT_STATE(state)	((uint32_t)(state >> 8))
172 #define	EMUL64_GET_PKT_STATS(stats)	((uint32_t)(stats))
173 
174 #define	EMUL64_STAT_NEGOTIATE	0x0080
175 
176 #define	EMUL64_SET_REASON(sp, reason) { \
177 	if ((sp) && CMD2PKT(sp)->pkt_reason == CMD_CMPLT) \
178 		CMD2PKT(sp)->pkt_reason = (reason); \
179 }
180 
181 /*
182  * mutex short hands
183  */
184 #define	EMUL64_REQ_MUTEX(emul64)	(&emul64->emul64_request_mutex)
185 #define	EMUL64_RESP_MUTEX(emul64)	(&emul64->emul64_response_mutex)
186 #define	EMUL64_HOTPLUG_MUTEX(emul64)	(&emul64->emul64_hotplug_mutex)
187 
188 
189 #define	EMUL64_MUTEX_ENTER(emul64) mutex_enter(EMUL64_RESP_MUTEX(emul64)), \
190 				mutex_enter(EMUL64_REQ_MUTEX(emul64))
191 #define	EMUL64_MUTEX_EXIT(emul64)	mutex_exit(EMUL64_RESP_MUTEX(emul64)), \
192 				mutex_exit(EMUL64_REQ_MUTEX(emul64))
193 
194 #define	EMUL64_CV(emul64)			(&(emul64)->emul64_cv)
195 
196 /*
197  * HBA interface macros
198  */
199 #define	SDEV2TRAN(sd)		((sd)->sd_address.a_hba_tran)
200 #define	SDEV2ADDR(sd)		(&((sd)->sd_address))
201 #define	PKT2TRAN(pkt)		((pkt)->pkt_address.a_hba_tran)
202 #define	ADDR2TRAN(ap)		((ap)->a_hba_tran)
203 
204 #define	TRAN2EMUL64(tran)	((struct emul64 *)(tran)->tran_hba_private)
205 #define	SDEV2EMUL64(sd)		(TRAN2EMUL64(SDEV2TRAN(sd)))
206 #define	PKT2EMUL64(pkt)		(TRAN2EMUL64(PKT2TRAN(pkt)))
207 #define	ADDR2EMUL64(ap)		(TRAN2EMUL64(ADDR2TRAN(ap)))
208 
209 #define	CMD2ADDR(cmd)		(&CMD2PKT(cmd)->pkt_address)
210 #define	CMD2TRAN(cmd)		(CMD2PKT(cmd)->pkt_address.a_hba_tran)
211 #define	CMD2EMUL64(cmd)		(TRAN2EMUL64(CMD2TRAN(cmd)))
212 
213 /*
214  * Results of checking for range overlap.
215  */
216 typedef enum emul64_rng_overlap {
217 	O_NONE,			/* No overlap */
218 	O_SAME,			/* Ranges are identical */
219 	O_SUBSET,		/* Blocks are contained in range */
220 	O_OVERLAP		/* Ranges overlap. */
221 } emul64_rng_overlap_t;
222 
223 /*
224  * Rather than keep the entire image of the disk, we only keep
225  * the blocks which have been written with non-zeros.  As the
226  * purpose of this driver is to exercise format and perhaps other
227  * large-disk management tools, only recording the label for
228  * i/o is sufficient
229  */
230 typedef struct blklist {
231 	diskaddr_t	bl_blkno;	/* Disk address of the data */
232 	uchar_t		*bl_data;	/* Pointer to the data */
233 	avl_node_t	bl_node;	/* Our linkage in AVL tree */
234 } blklist_t;
235 
236 /*
237  * Structure to track a range of blocks where writes are to be ignored.
238  */
239 typedef struct emul64_nowrite {
240 	struct emul64_nowrite	*emul64_nwnext;	/* next item in list */
241 	emul64_range_t		emul64_blocked;	/* range to ignore writes */
242 } emul64_nowrite_t;
243 
244 typedef struct emul64_tgt {
245 	struct scsi_address	emul64_tgt_saddr;
246 	struct emul64_tgt	*emul64_tgt_next;	/* Next tgt on ctlr */
247 	emul64_nowrite_t	*emul64_tgt_nowrite;	/* List of regions to */
248 							/* skip writes */
249 	diskaddr_t		emul64_tgt_sectors;	/* # sectors in dev */
250 	char 			emul64_tgt_inq[8+16];
251 	uint_t			emul64_tgt_dtype;
252 	uint_t			emul64_tgt_ncyls;	/* # cylinders in dev */
253 	uint_t			emul64_tgt_nheads;	/* # disk heads */
254 	uint_t			emul64_tgt_nsect;	/* # sectors */
255 	uint64_t		emul64_list_length;	/* # data blks */
256 	avl_tree_t		emul64_tgt_data;	/* Tree of data blks */
257 	kmutex_t		emul64_tgt_blk_lock;	/* Protect data blks */
258 	krwlock_t		emul64_tgt_nw_lock;	/* Guard tgt_nowrite */
259 	/* Fields for error injection */
260 	ushort_t		emul64_einj_state;
261 	ushort_t		emul64_einj_sense_length;
262 	uint_t			emul64_einj_pkt_state;
263 	uint_t			emul64_einj_pkt_reason;
264 	struct scsi_status	emul64_einj_scsi_status;
265 	uint8_t			*emul64_einj_sense_data;
266 } emul64_tgt_t;
267 
268 /*
269  * emul64 softstate structure
270  */
271 
272 /*
273  * deadline slot structure for timeout handling
274  */
275 struct emul64_slot {
276 	struct emul64_cmd	*slot_cmd;
277 	clock_t		slot_deadline;
278 };
279 
280 
281 /*
282  * Record the reset notification requests from target drivers.
283  */
284 struct emul64_reset_notify_entry {
285 	struct scsi_address		*ap;
286 	void				(*callback)(caddr_t);
287 	caddr_t				arg;
288 	struct emul64_reset_notify_entry	*next;
289 };
290 
291 
292 struct emul64 {
293 
294 	/*
295 	 * Transport structure for this instance of the hba
296 	 */
297 	scsi_hba_tran_t		*emul64_tran;
298 
299 	/*
300 	 * dev_info_t reference can be found in the transport structure
301 	 */
302 	dev_info_t		*emul64_dip;
303 
304 	/*
305 	 * Interrupt block cookie
306 	 */
307 	ddi_iblock_cookie_t	emul64_iblock;
308 
309 	/*
310 	 * Firmware revision number
311 	 */
312 	uint16_t		emul64_major_rev;
313 	uint16_t		emul64_minor_rev;
314 
315 	/*
316 	 * timeout id
317 	 */
318 	timeout_id_t		emul64_timeout_id;
319 
320 	/*
321 	 * scsi options, scsi_tag_age_limit  per emul64
322 	 */
323 	int			emul64_scsi_options;
324 	int			emul64_target_scsi_options[NTARGETS_WIDE];
325 	int			emul64_scsi_tag_age_limit;
326 
327 	/*
328 	 * scsi_reset_delay per emul64
329 	 */
330 	clock_t			emul64_scsi_reset_delay;
331 
332 	/*
333 	 * current host ID
334 	 */
335 	uint8_t			emul64_initiator_id;
336 
337 	/*
338 	 * suspended flag for power management
339 	 */
340 	uint8_t			emul64_suspended;
341 
342 	/*
343 	 * Host adapter capabilities and offset/period values per target
344 	 */
345 	uint16_t		emul64_cap[NTARGETS_WIDE];
346 	int16_t			emul64_synch[NTARGETS_WIDE];
347 
348 	/*
349 	 * EMUL64 Hardware register pointer.
350 	 */
351 	struct emul64regs		*emul64_reg;
352 
353 
354 	kmutex_t		emul64_request_mutex;
355 	kmutex_t		emul64_response_mutex;
356 
357 	/*
358 	 * for keeping track of the max LUNs per target on this bus
359 	 */
360 	uchar_t			emul64_max_lun[NTARGETS_WIDE];
361 
362 	/*
363 	 * for keeping track of each target/lun
364 	 */
365 	int	nt_total_sectors[NTARGETS_WIDE][EMUL64_NLUNS_PER_TARGET];
366 
367 	struct emul64_reset_notify_entry	*emul64_reset_notify_listf;
368 
369 	ushort_t		emul64_backoff;
370 	uint_t			emul64_softstate; /* flags for hotplug */
371 	int			emul64_hotplug_waiting;
372 	kcondvar_t		emul64_cv; /* cv for bus quiesce/unquiesce */
373 	kmutex_t		emul64_hotplug_mutex; /* Mutex for hotplug */
374 	taskq_t			*emul64_taskq;
375 	emul64_tgt_t		*emul64_tgt;
376 };
377 
378 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex,
379 				emul64::emul64_queue_space))
380 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex,
381 				emul64::emul64_request_in))
382 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex,
383 				emul64::emul64_request_out))
384 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex,
385 				emul64::emul64_request_ptr))
386 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex,
387 				emul64::emul64_mbox))
388 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_request_mutex,
389 				emul64::emul64_slots))
390 
391 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex,
392 				emul64::emul64_response_in))
393 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex,
394 				emul64::emul64_response_out))
395 _NOTE(MUTEX_PROTECTS_DATA(emul64::emul64_response_mutex,
396 				emul64::emul64_response_ptr))
397 
398 extern void emul64_bsd_init();
399 extern void emul64_bsd_fini();
400 extern void emul64_bsd_get_props(dev_info_t *);
401 
402 extern emul64_rng_overlap_t emul64_overlap(emul64_range_t *,
403 						diskaddr_t, size_t);
404 extern int emul64_bsd_blkcompare(const void *, const void *);
405 extern int emul64debug;
406 extern long emul64_nowrite_count;
407 extern kmutex_t emul64_stats_mutex;
408 extern int emul64_collect_stats;
409 extern uint64_t emul64_taskq_max;
410 extern int emul64_max_task;
411 extern int emul64_task_nthreads;
412 
413 #ifdef	__cplusplus
414 }
415 #endif
416 
417 #endif	/* _SYS_SCSI_ADAPTERS_EMUL64VAR_H */
418