aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/megaraid/mega_common.h
blob: 18969a4946b752a88ba61cd4dc0eb088c41ebac9 (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
/*
 *
 *			Linux MegaRAID device driver
 *
 * Copyright (c) 2003-2004  LSI Logic Corporation.
 *
 *	   This program is free software; you can redistribute it and/or
 *	   modify it under the terms of the GNU General Public License
 *	   as published by the Free Software Foundation; either version
 *	   2 of the License, or (at your option) any later version.
 *
 * FILE		: mega_common.h
 *
 * Libaray of common routine used by all low-level megaraid drivers
 */

#ifndef _MEGA_COMMON_H_
#define _MEGA_COMMON_H_

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/list.h>
#include <linux/version.h>
#include <linux/moduleparam.h>
#include <asm/semaphore.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>


#define LSI_MAX_CHANNELS		16
#define LSI_MAX_LOGICAL_DRIVES_64LD	(64+1)


/**
 * scb_t - scsi command control block
 * @param ccb		: command control block for individual driver
 * @param list		: list of control blocks
 * @param gp		: general purpose field for LLDs
 * @param sno		: all SCBs have a serial number
 * @param scp		: associated scsi command
 * @param state		: current state of scb
 * @param dma_dir	: direction of data transfer
 * @param dma_type	: transfer with sg list, buffer, or no data transfer
 * @param dev_channel	: actual channel on the device
 * @param dev_target	: actual target on the device
 * @param status	: completion status
 *
 * This is our central data structure to issue commands the each driver.
 * Driver specific data structures are maintained in the ccb field.
 * scb provides a field 'gp', which can be used by LLD for its own purposes
 *
 * dev_channel and dev_target must be initialized with the actual channel and
 * target on the controller.
 */
typedef struct {
	caddr_t			ccb;
	struct list_head	list;
	unsigned long		gp;
	unsigned int		sno;
	struct scsi_cmnd	*scp;
	uint32_t		state;
	uint32_t		dma_direction;
	uint32_t		dma_type;
	uint16_t		dev_channel;
	uint16_t		dev_target;
	uint32_t		status;
} scb_t;

/*
 * SCB states as it transitions from one state to another
 */
#define SCB_FREE	0x0000	/* on the free list */
#define SCB_ACTIVE	0x0001	/* off the free list */
#define SCB_PENDQ	0x0002	/* on the pending queue */
#define SCB_ISSUED	0x0004	/* issued - owner f/w */
#define SCB_ABORT	0x0008	/* Got an abort for this one */
#define SCB_RESET	0x0010	/* Got a reset for this one */

/*
 * DMA types for scb
 */
#define MRAID_DMA_NONE	0x0000	/* no data transfer for this command */
#define MRAID_DMA_WSG	0x0001	/* data transfer using a sg list */
#define MRAID_DMA_WBUF	0x0002	/* data transfer using a contiguous buffer */


/**
 * struct adapter_t - driver's initialization structure
 * @param dpc_h			: tasklet handle
 * @param pdev			: pci configuration pointer for kernel
 * @param host			: pointer to host structure of mid-layer
 * @param host_lock		: pointer to appropriate lock
 * @param lock			: synchronization lock for mid-layer and driver
 * @param quiescent		: driver is quiescent for now.
 * @param outstanding_cmds	: number of commands pending in the driver
 * @param kscb_list		: pointer to the bulk of SCBs pointers for IO
 * @param kscb_pool		: pool of free scbs for IO
 * @param kscb_pool_lock	: lock for pool of free scbs
 * @param pend_list		: pending commands list
 * @param pend_list_lock	: exlusion lock for pending commands list
 * @param completed_list	: list of completed commands
 * @param completed_list_lock	: exclusion lock for list of completed commands
 * @param sglen			: max sg elements supported
 * @param device_ids		: to convert kernel device addr to our devices.
 * @param raid_device		: raid adapter specific pointer
 * @param max_channel		: maximum channel number supported - inclusive
 * @param max_target		: max target supported - inclusive
 * @param max_lun		: max lun supported - inclusive
 * @param unique_id		: unique identifier for each adapter
 * @param irq			: IRQ for this adapter
 * @param ito			: internal timeout value, (-1) means no timeout
 * @param ibuf			: buffer to issue internal commands
 * @param ibuf_dma_h		: dma handle for the above buffer
 * @param uscb_list		: SCB pointers for user cmds, common mgmt module
 * @param uscb_pool		: pool of SCBs for user commands
 * @param uscb_pool_lock	: exclusion lock for these SCBs
 * @param max_cmds		: max outstanding commands
 * @param fw_version		: firmware version
 * @param bios_version		: bios version
 * @param max_cdb_sz		: biggest CDB size supported.
 * @param ha			: is high availability present - clustering
 * @param init_id		: initiator ID, the default value should be 7
 * @param max_sectors		: max sectors per request
 * @param cmd_per_lun		: max outstanding commands per LUN
 * @param being_detached	: set when unloading, no more mgmt calls
 *
 *
 * mraid_setup_device_map() can be called anytime after the device map is
 * available and MRAID_GET_DEVICE_MAP() can be called whenever the mapping is
 * required, usually from LLD's queue entry point. The formar API sets up the
 * MRAID_IS_LOGICAL(adapter_t *, struct scsi_cmnd *) to find out if the
 * device in question is a logical drive.
 *
 * quiescent flag should be set by the driver if it is not accepting more
 * commands
 *
 * NOTE: The fields of this structures are placed to minimize cache misses
 */

// amount of space required to store the bios and firmware version strings
#define VERSION_SIZE	16

typedef struct {
	struct tasklet_struct	dpc_h;
	struct pci_dev		*pdev;
	struct Scsi_Host	*host;
	spinlock_t		*host_lock;
	spinlock_t		lock;
	uint8_t			quiescent;
	int			outstanding_cmds;
	scb_t			*kscb_list;
	struct list_head	kscb_pool;
	spinlock_t		kscb_pool_lock;
	struct list_head	pend_list;
	spinlock_t		pend_list_lock;
	struct list_head	completed_list;
	spinlock_t		completed_list_lock;
	uint16_t		sglen;
	int			device_ids[LSI_MAX_CHANNELS]
					[LSI_MAX_LOGICAL_DRIVES_64LD];
	caddr_t			raid_device;
	uint8_t			max_channel;
	uint16_t		max_target;
	uint8_t			max_lun;

	uint32_t		unique_id;
	uint8_t			irq;
	uint8_t			ito;
	caddr_t			ibuf;
	dma_addr_t		ibuf_dma_h;
	scb_t			*uscb_list;
	struct list_head	uscb_pool;
	spinlock_t		uscb_pool_lock;
	int			max_cmds;
	uint8_t			fw_version[VERSION_SIZE];
	uint8_t			bios_version[VERSION_SIZE];
	uint8_t			max_cdb_sz;
	uint8_t			ha;
	uint16_t		init_id;
	uint16_t		max_sectors;
	uint16_t		cmd_per_lun;
	atomic_t		being_detached;
} adapter_t;

#define SCSI_FREE_LIST_LOCK(adapter)	(&adapter->kscb_pool_lock)
#define USER_FREE_LIST_LOCK(adapter)	(&adapter->uscb_pool_lock)
#define PENDING_LIST_LOCK(adapter)	(&adapter->pend_list_lock)
#define COMPLETED_LIST_LOCK(adapter)	(&adapter->completed_list_lock)


// conversion from scsi command
#define SCP2HOST(scp)			(scp)->device->host	// to host
#define SCP2HOSTDATA(scp)		SCP2HOST(scp)->hostdata	// to soft state
#define SCP2CHANNEL(scp)		(scp)->device->channel	// to channel
#define SCP2TARGET(scp)			(scp)->device->id	// to target
#define SCP2LUN(scp)			(scp)->device->lun	// to LUN

// generic macro to convert scsi command and host to controller's soft state
#define SCSIHOST2ADAP(host)	(((caddr_t *)(host->hostdata))[0])
#define SCP2ADAPTER(scp)	(adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp))


/**
 * MRAID_GET_DEVICE_MAP - device ids
 * @param adp		- Adapter's soft state
 * @param scp		- mid-layer scsi command pointer
 * @param p_chan	- physical channel on the controller
 * @param target	- target id of the device or logical drive number
 * @param islogical	- set if the command is for the logical drive
 *
 * Macro to retrieve information about device class, logical or physical and
 * the corresponding physical channel and target or logical drive number
 **/
#define MRAID_IS_LOGICAL(adp, scp)	\
	(SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0

#define MRAID_IS_LOGICAL_SDEV(adp, sdev)	\
	(sdev->channel == (adp)->max_channel) ? 1 : 0

#define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical)	\
	/*								\
	 * Is the request coming for the virtual channel		\
	 */								\
	islogical = MRAID_IS_LOGICAL(adp, scp);				\
									\
	/*								\
	 * Get an index into our table of drive ids mapping		\
	 */								\
	if (islogical) {						\
		p_chan = 0xFF;						\
		target =						\
		(adp)->device_ids[(adp)->max_channel][SCP2TARGET(scp)];	\
	}								\
	else {								\
		p_chan = ((adp)->device_ids[SCP2CHANNEL(scp)]		\
					[SCP2TARGET(scp)] >> 8) & 0xFF;	\
		target = ((adp)->device_ids[SCP2CHANNEL(scp)]		\
					[SCP2TARGET(scp)] & 0xFF);	\
	}

/*
 * ### Helper routines ###
 */
#define LSI_DBGLVL mraid_debug_level	// each LLD must define a global
 					// mraid_debug_level

#ifdef DEBUG
#if defined (_ASSERT_PANIC)
#define ASSERT_ACTION	panic
#else
#define ASSERT_ACTION	printk
#endif

#define ASSERT(expression)						\
	if (!(expression)) {						\
	ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n",	\
			#expression, __FILE__, __LINE__, __FUNCTION__);	\
	}
#else
#define ASSERT(expression)
#endif

/*
 * struct mraid_pci_blk - structure holds DMA memory block info
 * @param vaddr		: virtual address to a memory block
 * @param dma_addr	: DMA handle to a memory block
 *
 * This structure is filled up for the caller. It is the responsibilty of the
 * caller to allocate this array big enough to store addresses for all
 * requested elements
 */
struct mraid_pci_blk {
	caddr_t		vaddr;
	dma_addr_t	dma_addr;
};

#endif // _MEGA_COMMON_H_

// vim: set ts=8 sw=8 tw=78: