summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/skd/skd.h
blob: c7d968977ea7105a9c1e74c240614b65acb260cc (plain)
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
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2013 STEC, Inc.  All rights reserved.
 * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
 */

#ifndef _SKD_H
#define	_SKD_H

#include	<sys/types.h>
#include	<sys/stropts.h>
#include	<sys/stream.h>
#include	<sys/cmn_err.h>
#include	<sys/kmem.h>
#include	<sys/modctl.h>
#include	<sys/ddi.h>
#include	<sys/sunddi.h>
#include	<sys/strsun.h>
#include	<sys/kstat.h>
#include 	<sys/conf.h>
#include 	<sys/debug.h>
#include 	<sys/modctl.h>
#include 	<sys/errno.h>
#include 	<sys/pci.h>
#include 	<sys/memlist.h>
#include 	<sys/param.h>
#include	<sys/queue.h>

#define	DRV_NAME 	"skd"
#define	DRV_VERSION 	"2.2.1"
#define	DRV_BUILD_ID 	"0264"
#define	PFX DRV_NAME    ": "
#define	DRV_BIN_VERSION 0x100
#define	DRV_VER_COMPL   DRV_VERSION "." DRV_BUILD_ID
#define	VERSIONSTR 	DRV_VERSION


#define	SG_BOUNDARY		0x20000


#ifdef _BIG_ENDIAN
#define	be64_to_cpu(x) (x)
#define	be32_to_cpu(x) (x)
#define	cpu_to_be64(x) (x)
#define	cpu_to_be32(x) (x)
#else
#define	be64_to_cpu(x) BSWAP_64(x)
#define	be32_to_cpu(x) BSWAP_32(x)
#define	cpu_to_be64(x) BSWAP_64(x)
#define	cpu_to_be32(x) BSWAP_32(x)
#endif

#define	ATYPE_64BIT		0
#define	ATYPE_32BIT		1

#define	BIT_0			0x00001
#define	BIT_1			0x00002
#define	BIT_2			0x00004
#define	BIT_3			0x00008
#define	BIT_4			0x00010
#define	BIT_5			0x00020
#define	BIT_6			0x00040
#define	BIT_7			0x00080
#define	BIT_8			0x00100
#define	BIT_9			0x00200
#define	BIT_10			0x00400
#define	BIT_11			0x00800
#define	BIT_12			0x01000
#define	BIT_13			0x02000
#define	BIT_14			0x04000
#define	BIT_15			0x08000
#define	BIT_16			0x10000
#define	BIT_17			0x20000
#define	BIT_18			0x40000
#define	BIT_19			0x80000

/* Attach progress flags */
#define	SKD_ATTACHED			BIT_0
#define	SKD_SOFT_STATE_ALLOCED		BIT_1
#define	SKD_CONFIG_SPACE_SETUP		BIT_3
#define	SKD_IOBASE_MAPPED		BIT_4
#define	SKD_IOMAP_IOBASE_MAPPED		BIT_5
#define	SKD_REGS_MAPPED			BIT_6
#define	SKD_DEV_IOBASE_MAPPED		BIT_7
#define	SKD_CONSTRUCTED			BIT_8
#define	SKD_PROBED			BIT_9
#define	SKD_INTR_ADDED			BIT_10
#define	SKD_PATHNAME_ALLOCED		BIT_11
#define	SKD_SUSPENDED			BIT_12
#define	SKD_CMD_ABORT_TMO		BIT_13
#define	SKD_MUTEX_INITED		BIT_14
#define	SKD_MUTEX_DESTROYED		BIT_15

#define	SKD_IODONE_WIOC			1	/* I/O done */
#define	SKD_IODONE_WNIOC		2	/* I/O NOT done */
#define	SKD_IODONE_WDEBUG		3	/* I/O - debug stuff */

#ifdef SKD_PM
#define	MAX_POWER_LEVEL			0
#define	LOW_POWER_LEVEL			(BIT_1 | BIT_0)
#endif

#define	SKD_MSIX_AIF		0x0
#define	SKD_MSIX_RSPQ		0x1
#define	SKD_MSIX_MAXAIF		SKD_MSIX_RSPQ + 1

/*
 * Stuff from Linux
 */
#define	SAM_STAT_GOOD			0x00
#define	SAM_STAT_CHECK_CONDITION	0x02

#define	TEST_UNIT_READY		0x00
#define	INQUIRY			0x12
#define	INQUIRY2		(0x12 + 0xe0)
#define	READ_CAPACITY		0x25
#define	READ_CAPACITY_EXT	0x9e
#define	SYNCHRONIZE_CACHE	0x35

/*
 *  SENSE KEYS
 */
#define	NO_SENSE	    0x00
#define	RECOVERED_ERROR	    0x01
#define	UNIT_ATTENTION	    0x06
#define	ABORTED_COMMAND	    0x0b

typedef struct dma_mem_t {
	void			*bp;
	ddi_acc_handle_t	acc_handle;
	ddi_dma_handle_t	dma_handle;
	ddi_dma_cookie_t	cookie;
	ddi_dma_cookie_t	*cookies;
	uint32_t		size;
} dma_mem_t;

#define	SKD_WRITEL(DEV, VAL, OFF)	skd_reg_write32(DEV, VAL, OFF)
#define	SKD_READL(DEV, OFF)		skd_reg_read32(DEV, OFF)
#define	SKD_WRITEQ(DEV, VAL, OFF)	skd_reg_write64(DEV, VAL, OFF)

/* Capability lists */
#define	PCI_CAP_ID_EXP		0x10	/* PCI Express */

/*
 * End Stuff from Linux
 */

#define	SKD_DMA_MAXXFER			(2048 * DEV_BSIZE)

#define	SKD_DMA_LOW_ADDRESS		(uint64_t)0
#define	SKD_DMA_HIGH_64BIT_ADDRESS	(uint64_t)0xffffffffffffffff
#define	SKD_DMA_HIGH_32BIT_ADDRESS	(uint64_t)0xffffffff
#define	SKD_DMA_XFER_COUNTER		(uint64_t)0xffffffff
#define	SKD_DMA_ADDRESS_ALIGNMENT	(uint64_t)SG_BOUNDARY
#define	SKD_DMA_BURSTSIZES		0xff
#define	SKD_DMA_MIN_XFER_SIZE		1
#define	SKD_DMA_MAX_XFER_SIZE		(uint64_t)0xfffffe00
#define	SKD_DMA_SEGMENT_BOUNDARY	(uint64_t)0xffffffff
#define	SKD_DMA_SG_LIST_LENGTH		256
#define	SKD_DMA_XFER_FLAGS		0
#define	SKD_DMA_GRANULARITY		512 /* 1 */

#define	PCI_VENDOR_ID_STEC  0x1B39
#define	PCI_DEVICE_ID_SUMO  0x0001

#define	SKD_N_FITMSG_BYTES	(512u)

#define	SKD_N_SPECIAL_CONTEXT	64u
#define	SKD_N_SPECIAL_FITMSG_BYTES (128u)
#define	SKD_N_SPECIAL_DATA_BYTES  (8u*1024u)


/*
 * SG elements are 32 bytes, so we can make this 4096 and still be under the
 * 128KB limit.	 That allows 4096*4K = 16M xfer size
 */
#define	SKD_N_SG_PER_REQ_DEFAULT 256u
#define	SKD_N_SG_PER_SPECIAL	256u

#define	SKD_N_COMPLETION_ENTRY		256u
#define	SKD_N_READ_CAP_BYTES		(8u)
#define	SKD_N_READ_CAP_EXT_BYTES	(16)

#define	SKD_N_INTERNAL_BYTES   (512u)

/* 5 bits of uniqifier, 0xF800 */
#define	SKD_ID_INCR		(0x400)
#define	SKD_ID_TABLE_MASK	(3u << 8u)
#define	SKD_ID_RW_REQUEST	(0u << 8u)
#define	SKD_ID_INTERNAL		(1u << 8u)
#define	SKD_ID_FIT_MSG		(3u << 8u)
#define	SKD_ID_SLOT_MASK	0x00FFu
#define	SKD_ID_SLOT_AND_TABLE_MASK 0x03FFu

#define	SKD_N_TIMEOUT_SLOT	8u
#define	SKD_TIMEOUT_SLOT_MASK	7u

#define	SKD_TIMER_SECONDS(seconds) (seconds)
#define	SKD_TIMER_MINUTES(minutes) ((minutes)*(60))

/*
 * NOTE:  INTR_LOCK() should be held prior to grabbing WAITQ_LOCK() if both
 * are needed.
 */
#define	INTR_LOCK(skdev)		mutex_enter(&skdev->skd_intr_mutex)
#define	INTR_UNLOCK(skdev)		mutex_exit(&skdev->skd_intr_mutex)
#define	INTR_LOCK_HELD(skdev)		MUTEX_HELD(&skdev->skd_intr_mutex)

#define	WAITQ_LOCK(skdev) \
	mutex_enter(&skdev->waitqueue_mutex)
#define	WAITQ_UNLOCK(skdev) \
	mutex_exit(&skdev->waitqueue_mutex)
#define	WAITQ_LOCK_HELD(skdev) \
	MUTEX_HELD(&skdev->waitqueue_mutex)

#define	ADAPTER_STATE_LOCK(skdev)	mutex_enter(&skdev->skd_lock_mutex)
#define	ADAPTER_STATE_UNLOCK(skdev)	mutex_exit(&skdev->skd_lock_mutex)

enum skd_drvr_state {
	SKD_DRVR_STATE_LOAD,			/* 0 when driver first loaded */
	SKD_DRVR_STATE_IDLE,			/* 1 when device goes offline */
	SKD_DRVR_STATE_BUSY,			/* 2 */
	SKD_DRVR_STATE_STARTING,		/* 3 */
	SKD_DRVR_STATE_ONLINE,			/* 4 */
	SKD_DRVR_STATE_PAUSING,			/* 5 */
	SKD_DRVR_STATE_PAUSED,			/* 6 */
	SKD_DRVR_STATE_DRAINING_TIMEOUT,	/* 7 */
	SKD_DRVR_STATE_RESTARTING,		/* 8 */
	SKD_DRVR_STATE_RESUMING,		/* 9 */
	SKD_DRVR_STATE_STOPPING,	/* 10 when driver is unloading */
	SKD_DRVR_STATE_FAULT,			/* 11 */
	SKD_DRVR_STATE_DISAPPEARED,		/* 12 */
	SKD_DRVR_STATE_PROTOCOL_MISMATCH,	/* 13 */
	SKD_DRVR_STATE_BUSY_ERASE,		/* 14 */
	SKD_DRVR_STATE_BUSY_SANITIZE,		/* 15 */
	SKD_DRVR_STATE_BUSY_IMMINENT,		/* 16 */
	SKD_DRVR_STATE_WAIT_BOOT,		/* 17 */
	SKD_DRVR_STATE_SYNCING			/* 18 */
};

#define	SKD_WAIT_BOOT_TO 90u
#define	SKD_STARTING_TO	 248u

enum skd_req_state {
	SKD_REQ_STATE_IDLE,
	SKD_REQ_STATE_SETUP,
	SKD_REQ_STATE_BUSY,
	SKD_REQ_STATE_COMPLETED,
	SKD_REQ_STATE_TIMEOUT,
	SKD_REQ_STATE_ABORTED,
};

enum skd_fit_msg_state {
	SKD_MSG_STATE_IDLE,
	SKD_MSG_STATE_BUSY,
};

enum skd_check_status_action {
	SKD_CHECK_STATUS_REPORT_GOOD,
	SKD_CHECK_STATUS_REPORT_SMART_ALERT,
	SKD_CHECK_STATUS_REQUEUE_REQUEST,
	SKD_CHECK_STATUS_REPORT_ERROR,
	SKD_CHECK_STATUS_BUSY_IMMINENT,
};

/* NOTE:  mbu_t users should name this field "mbu". */
typedef union {
	uint8_t *mb8;
	uint64_t *mb64;
} mbu_t;
#define	msg_buf mbu.mb8
#define	msg_buf64 mbu.mb64

struct skd_fitmsg_context {
	enum skd_fit_msg_state state;
	struct skd_fitmsg_context *next;
	uint32_t	id;
	uint16_t	outstanding;
	uint32_t	length;
	uint32_t	offset;
	mbu_t		mbu;	/* msg_buf & msg_buf64 */
	dma_mem_t	mb_dma_address;
};

struct skd_request_context {
	enum skd_req_state		state;
	struct skd_request_context	*next;
	uint16_t			did_complete;
	uint16_t			id;
	uint32_t			fitmsg_id;
	struct skd_buf_private		*pbuf;
	uint32_t			timeout_stamp;
	uint8_t				sg_data_dir;
	uint32_t			n_sg;
	ddi_dma_handle_t		io_dma_handle;
	struct fit_sg_descriptor	*sksg_list;
	dma_mem_t			sksg_dma_address;
	struct fit_completion_entry_v1	completion;
	struct fit_comp_error_info	err_info;
	int				total_sg_bcount;
};

#define	SKD_DATA_DIR_HOST_TO_CARD	1
#define	SKD_DATA_DIR_CARD_TO_HOST	2

struct skd_special_context {
	struct skd_request_context req;
	uint8_t			   orphaned;
	uint32_t		   sg_byte_count;
	void			   *data_buf;
	dma_mem_t		   db_dma_address;
	mbu_t			   mbu;	/* msg_buf & msg_buf64 */
	dma_mem_t		   mb_dma_address;
	int			   io_pending;
};

typedef struct skd_buf_private {
	SIMPLEQ_ENTRY(skd_buf_private) sq;
	struct skd_request_context *skreq;
	bd_xfer_t *x_xfer;
	int dir;
} skd_buf_private_t;

SIMPLEQ_HEAD(waitqueue, skd_buf_private);

typedef struct skd_device skd_device_t;

struct skd_device {
	int		irq_type;
	int		gendisk_on;
	int		sync_done;

	char		name[32];

	enum		skd_drvr_state state;
	uint32_t		drive_state;

	uint32_t	queue_depth_busy;
	uint32_t	queue_depth_limit;
	uint32_t	queue_depth_lowat;
	uint32_t	soft_queue_depth_limit;
	uint32_t	hard_queue_depth_limit;

	uint32_t	num_fitmsg_context;
	uint32_t	num_req_context;

	uint32_t	timeout_slot[SKD_N_TIMEOUT_SLOT];
	uint32_t	timeout_stamp;

	struct skd_fitmsg_context *skmsg_free_list;
	struct skd_fitmsg_context *skmsg_table;

	struct skd_request_context *skreq_free_list;
	struct skd_request_context *skreq_table;
	struct skd_special_context internal_skspcl;

	uint64_t	read_cap_last_lba;
	uint32_t	read_cap_blocksize;
	int		read_cap_is_valid;
	int		inquiry_is_valid;
	char		inq_serial_num[13]; /* 12 chars plus null term */
	char		inq_vendor_id[9];
	char		inq_product_id[17];
	char		inq_product_rev[5];
	char		id_str[128]; /* holds a composite name (pci + sernum) */

	uint8_t		skcomp_cycle;
	uint32_t	skcomp_ix;
	struct fit_completion_entry_v1 *skcomp_table;
	struct fit_comp_error_info *skerr_table;
	dma_mem_t	cq_dma_address;

	uint32_t	timer_active;
	uint32_t	timer_countdown;
	uint32_t	timer_substate;

	int		sgs_per_request;
	uint32_t	last_mtd;

	uint32_t	proto_ver;

	int		dbg_level;

	uint32_t	timo_slot;

	ddi_acc_handle_t	pci_handle;
	ddi_acc_handle_t	iobase_handle;
	ddi_acc_handle_t	iomap_handle;
	caddr_t			iobase;
	caddr_t			iomap_iobase;

	ddi_acc_handle_t	dev_handle;
	caddr_t			dev_iobase;
	int			dev_memsize;

	char			*pathname;

	dev_info_t		*dip;

	int			instance;
	uint16_t		vendor_id;
	uint16_t		device_id;

	kmutex_t		skd_lock_mutex;
	kmutex_t		skd_intr_mutex;
	kmutex_t		skd_fit_mutex;

	uint32_t		flags;

#ifdef SKD_PM
	uint8_t			power_level;
#endif

	/* AIF (Advanced Interrupt Framework) support */
	ddi_intr_handle_t	*htable;
	uint32_t		hsize;
	int32_t			intr_cnt;
	uint32_t		intr_pri;
	int32_t			intr_cap;

	uint64_t		Nblocks;

	ddi_iblock_cookie_t	iblock_cookie;

	int		n_req;
	uint32_t	progress;
	uint64_t	intr_cntr;
	uint64_t	fitmsg_sent1;
	uint64_t	fitmsg_sent2;
	uint64_t	active_cmds;

	kmutex_t	skd_internalio_mutex;
	kcondvar_t	cv_waitq;

	kmutex_t	waitqueue_mutex;
	struct waitqueue waitqueue;
	int		disks_initialized;

	ddi_devid_t	s1120_devid;
	char		devid_str[80];

	uint32_t	d_blkshift;

	int		attached;

	int		ios_queued;
	int		ios_started;
	int		ios_completed;
	int		ios_errors;
	int		iodone_wioc;
	int		iodone_wnioc;
	int		iodone_wdebug;
	int		iodone_unknown;

	bd_handle_t	s_bdh;
	int		bd_attached;

#ifdef USE_SKE_EMULATOR
	ske_device_t *ske_handle;
#endif

	timeout_id_t	skd_timer_timeout_id;
};

static void skd_disable_interrupts(struct skd_device *skdev);
static void skd_isr_completion_posted(struct skd_device *skdev);
static void skd_recover_requests(struct skd_device *skdev);
static void skd_log_skdev(struct skd_device *skdev, const char *event);
static void skd_restart_device(struct skd_device *skdev);
static void skd_destruct(struct skd_device *skdev);
static int skd_unquiesce_dev(struct skd_device *skdev);
static void skd_send_special_fitmsg(struct skd_device *skdev,
    struct skd_special_context *skspcl);
static void skd_end_request(struct skd_device *skdev,
    struct skd_request_context *skreq, int error);
static void skd_log_skmsg(struct skd_device *skdev,
    struct skd_fitmsg_context *skmsg, const char *event);
static void skd_log_skreq(struct skd_device *skdev,
    struct skd_request_context *skreq, const char *event);
static void skd_send_fitmsg(struct skd_device *skdev,
    struct skd_fitmsg_context *skmsg);

static const char *skd_drive_state_to_str(int state);
static const char *skd_skdev_state_to_str(enum skd_drvr_state state);

#endif /* _SKD_H */