mfivar.h revision 163398
1/*-
2 * Copyright (c) 2006 IronPort Systems
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#ifndef _MFIVAR_H
28#define _MFIVAR_H
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/dev/mfi/mfivar.h 163398 2006-10-16 04:18:38Z scottl $");
32
33/*
34 * SCSI structures and definitions are used from here, but no linking
35 * requirements are made to CAM.
36 */
37#include <cam/scsi/scsi_all.h>
38
39struct mfi_hwcomms {
40	uint32_t		hw_pi;
41	uint32_t		hw_ci;
42	uint32_t		hw_reply_q[1];
43};
44
45struct mfi_softc;
46
47struct mfi_command {
48	TAILQ_ENTRY(mfi_command) cm_link;
49	time_t			cm_timestamp;
50	struct mfi_softc	*cm_sc;
51	union mfi_frame		*cm_frame;
52	uint32_t		cm_frame_busaddr;
53	struct mfi_sense	*cm_sense;
54	uint32_t		cm_sense_busaddr;
55	bus_dmamap_t		cm_dmamap;
56	union mfi_sgl		*cm_sg;
57	void			*cm_data;
58	int			cm_len;
59	int			cm_total_frame_size;
60	int			cm_extra_frames;
61	int			cm_flags;
62#define MFI_CMD_MAPPED		(1<<0)
63#define MFI_CMD_DATAIN		(1<<1)
64#define MFI_CMD_DATAOUT		(1<<2)
65#define MFI_CMD_COMPLETED	(1<<3)
66#define MFI_CMD_POLLED		(1<<4)
67#define MFI_ON_MFIQ_FREE	(1<<5)
68#define MFI_ON_MFIQ_READY	(1<<6)
69#define MFI_ON_MFIQ_BUSY	(1<<7)
70#define MFI_ON_MFIQ_MASK	((1<<5)|(1<<6)|(1<<7))
71	int			cm_aen_abort;
72	void			(* cm_complete)(struct mfi_command *cm);
73	void			*cm_private;
74	int			cm_index;
75};
76
77struct mfi_ld {
78	TAILQ_ENTRY(mfi_ld)	ld_link;
79	device_t		ld_disk;
80	struct mfi_ld_info	*ld_info;
81	int			ld_id;
82};
83
84struct mfi_aen {
85	TAILQ_ENTRY(mfi_aen) aen_link;
86	struct proc			*p;
87};
88
89struct mfi_softc {
90	device_t			mfi_dev;
91	int				mfi_flags;
92#define MFI_FLAGS_SG64		(1<<0)
93#define MFI_FLAGS_QFRZN		(1<<1)
94#define MFI_FLAGS_OPEN		(1<<2)
95#define MFI_FLAGS_STOP		(1<<3)
96
97	struct mfi_hwcomms		*mfi_comms;
98	TAILQ_HEAD(,mfi_command)	mfi_free;
99	TAILQ_HEAD(,mfi_command)	mfi_ready;
100	TAILQ_HEAD(,mfi_command)	mfi_busy;
101	struct bio_queue_head		mfi_bioq;
102	struct mfi_qstat		mfi_qstat[MFIQ_COUNT];
103
104	struct resource			*mfi_regs_resource;
105	bus_space_handle_t		mfi_bhandle;
106	bus_space_tag_t			mfi_btag;
107	int				mfi_regs_rid;
108
109	bus_dma_tag_t			mfi_parent_dmat;
110	bus_dma_tag_t			mfi_buffer_dmat;
111
112	bus_dma_tag_t			mfi_comms_dmat;
113	bus_dmamap_t			mfi_comms_dmamap;
114	uint32_t			mfi_comms_busaddr;
115
116	bus_dma_tag_t			mfi_frames_dmat;
117	bus_dmamap_t			mfi_frames_dmamap;
118	uint32_t			mfi_frames_busaddr;
119	union mfi_frame			*mfi_frames;
120
121	TAILQ_HEAD(,mfi_aen)		mfi_aen_pids;
122	struct mfi_command		*mfi_aen_cm;
123	uint32_t			mfi_aen_triggered;
124	uint32_t			mfi_poll_waiting;
125	struct selinfo			mfi_select;
126
127	bus_dma_tag_t			mfi_sense_dmat;
128	bus_dmamap_t			mfi_sense_dmamap;
129	uint32_t			mfi_sense_busaddr;
130	struct mfi_sense		*mfi_sense;
131
132	struct resource			*mfi_irq;
133	void				*mfi_intr;
134	int				mfi_irq_rid;
135
136	struct intr_config_hook		mfi_ich;
137	eventhandler_tag		eh;
138
139	/*
140	 * Allocation for the command array.  Used as an indexable array to
141	 * recover completed commands.
142	 */
143	struct mfi_command		*mfi_commands;
144	/*
145	 * How many commands were actually allocated
146	 */
147	int				mfi_total_cmds;
148	/*
149	 * How many commands the firmware can handle.  Also how big the reply
150	 * queue is, minus 1.
151	 */
152	int				mfi_max_fw_cmds;
153	/*
154	 * How many S/G elements we'll ever actually use
155	 */
156	int				mfi_max_sge;
157	/*
158	 * How many bytes a compound frame is, including all of the extra frames
159	 * that are used for S/G elements.
160	 */
161	int				mfi_cmd_size;
162	/*
163	 * How large an S/G element is.  Used to calculate the number of single
164	 * frames in a command.
165	 */
166	int				mfi_sge_size;
167	/*
168	 * Max number of sectors that the firmware allows
169	 */
170	uint32_t			mfi_max_io;
171
172	TAILQ_HEAD(,mfi_ld)		mfi_ld_tqh;
173	eventhandler_tag		mfi_eh;
174	struct cdev			*mfi_cdev;
175
176	struct callout			mfi_watchdog_callout;
177	struct mtx			mfi_io_lock;
178};
179
180extern int mfi_attach(struct mfi_softc *);
181extern void mfi_free(struct mfi_softc *);
182extern int mfi_shutdown(struct mfi_softc *);
183extern void mfi_startio(struct mfi_softc *);
184extern void mfi_disk_complete(struct bio *);
185extern int mfi_dump_blocks(struct mfi_softc *, int id, uint64_t, void *, int);
186
187#define MFIQ_ADD(sc, qname)					\
188	do {							\
189		struct mfi_qstat *qs;				\
190								\
191		qs = &(sc)->mfi_qstat[qname];			\
192		qs->q_length++;					\
193		if (qs->q_length > qs->q_max)			\
194			qs->q_max = qs->q_length;		\
195	} while (0)
196
197#define MFIQ_REMOVE(sc, qname)	(sc)->mfi_qstat[qname].q_length--
198
199#define MFIQ_INIT(sc, qname)					\
200	do {							\
201		sc->mfi_qstat[qname].q_length = 0;		\
202		sc->mfi_qstat[qname].q_max = 0;			\
203	} while (0)
204
205#define MFIQ_COMMAND_QUEUE(name, index)					\
206	static __inline void						\
207	mfi_initq_ ## name (struct mfi_softc *sc)			\
208	{								\
209		TAILQ_INIT(&sc->mfi_ ## name);				\
210		MFIQ_INIT(sc, index);					\
211	}								\
212	static __inline void						\
213	mfi_enqueue_ ## name (struct mfi_command *cm)			\
214	{								\
215		if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) {		\
216			printf("command %p is on another queue, "	\
217			    "flags = %#x\n", cm, cm->cm_flags);		\
218			panic("command is on another queue");		\
219		}							\
220		TAILQ_INSERT_TAIL(&cm->cm_sc->mfi_ ## name, cm, cm_link); \
221		cm->cm_flags |= MFI_ON_ ## index;			\
222		MFIQ_ADD(cm->cm_sc, index);				\
223	}								\
224	static __inline void						\
225	mfi_requeue_ ## name (struct mfi_command *cm)			\
226	{								\
227		if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) {		\
228			printf("command %p is on another queue, "	\
229			    "flags = %#x\n", cm, cm->cm_flags);		\
230			panic("command is on another queue");		\
231		}							\
232		TAILQ_INSERT_HEAD(&cm->cm_sc->mfi_ ## name, cm, cm_link); \
233		cm->cm_flags |= MFI_ON_ ## index;			\
234		MFIQ_ADD(cm->cm_sc, index);				\
235	}								\
236	static __inline struct mfi_command *				\
237	mfi_dequeue_ ## name (struct mfi_softc *sc)			\
238	{								\
239		struct mfi_command *cm;					\
240									\
241		if ((cm = TAILQ_FIRST(&sc->mfi_ ## name)) != NULL) {	\
242			if ((cm->cm_flags & MFI_ON_ ## index) == 0) {	\
243				printf("command %p not in queue, "	\
244				    "flags = %#x, bit = %#x\n", cm,	\
245				    cm->cm_flags, MFI_ON_ ## index);	\
246				panic("command not in queue");		\
247			}						\
248			TAILQ_REMOVE(&sc->mfi_ ## name, cm, cm_link);	\
249			cm->cm_flags &= ~MFI_ON_ ## index;		\
250			MFIQ_REMOVE(sc, index);				\
251		}							\
252		return (cm);						\
253	}								\
254	static __inline void						\
255	mfi_remove_ ## name (struct mfi_command *cm)			\
256	{								\
257		if ((cm->cm_flags & MFI_ON_ ## index) == 0) {		\
258			printf("command %p not in queue, flags = %#x, " \
259			    "bit = %#x\n", cm, cm->cm_flags,		\
260			    MFI_ON_ ## index);				\
261			panic("command not in queue");			\
262		}							\
263		TAILQ_REMOVE(&cm->cm_sc->mfi_ ## name, cm, cm_link);	\
264		cm->cm_flags &= ~MFI_ON_ ## index;			\
265		MFIQ_REMOVE(cm->cm_sc, index);				\
266	}								\
267struct hack
268
269MFIQ_COMMAND_QUEUE(free, MFIQ_FREE);
270MFIQ_COMMAND_QUEUE(ready, MFIQ_READY);
271MFIQ_COMMAND_QUEUE(busy, MFIQ_BUSY);
272
273static __inline void
274mfi_initq_bio(struct mfi_softc *sc)
275{
276	bioq_init(&sc->mfi_bioq);
277	MFIQ_INIT(sc, MFIQ_BIO);
278}
279
280static __inline void
281mfi_enqueue_bio(struct mfi_softc *sc, struct bio *bp)
282{
283	bioq_insert_tail(&sc->mfi_bioq, bp);
284	MFIQ_ADD(sc, MFIQ_BIO);
285}
286
287static __inline struct bio *
288mfi_dequeue_bio(struct mfi_softc *sc)
289{
290	struct bio *bp;
291
292	if ((bp = bioq_first(&sc->mfi_bioq)) != NULL) {
293		bioq_remove(&sc->mfi_bioq, bp);
294		MFIQ_REMOVE(sc, MFIQ_BIO);
295	}
296	return (bp);
297}
298
299static __inline void
300mfi_print_sense(struct mfi_softc *sc, void *sense)
301{
302	int error, key, asc, ascq;
303
304	scsi_extract_sense((struct scsi_sense_data *)sense,
305	    &error, &key, &asc, &ascq);
306	device_printf(sc->mfi_dev, "sense error %d, sense_key %d, "
307	    "asc %d, ascq %d\n", error, key, asc, ascq);
308}
309
310
311#define MFI_WRITE4(sc, reg, val)	bus_space_write_4((sc)->mfi_btag, \
312	sc->mfi_bhandle, (reg), (val))
313#define MFI_READ4(sc, reg)		bus_space_read_4((sc)->mfi_btag, \
314	(sc)->mfi_bhandle, (reg))
315#define MFI_WRITE2(sc, reg, val)	bus_space_write_2((sc)->mfi_btag, \
316	sc->mfi_bhandle, (reg), (val))
317#define MFI_READ2(sc, reg)		bus_space_read_2((sc)->mfi_btag, \
318	(sc)->mfi_bhandle, (reg))
319#define MFI_WRITE1(sc, reg, val)	bus_space_write_1((sc)->mfi_btag, \
320	sc->mfi_bhandle, (reg), (val))
321#define MFI_READ1(sc, reg)		bus_space_read_1((sc)->mfi_btag, \
322	(sc)->mfi_bhandle, (reg))
323
324MALLOC_DECLARE(M_MFIBUF);
325
326#define MFI_CMD_TIMEOUT 30
327
328#ifdef MFI_DEBUG
329extern void mfi_print_cmd(struct mfi_command *cm);
330extern void mfi_dump_cmds(struct mfi_softc *sc);
331extern void mfi_validate_sg(struct mfi_softc *, struct mfi_command *, const char *, int );
332#define MFI_PRINT_CMD(cm)	mfi_print_cmd(cm)
333#define MFI_DUMP_CMDS(sc)	mfi_dump_cmds(sc)
334#define MFI_VALIDATE_CMD(sc, cm) mfi_validate_sg(sc, cm, __FUNCTION__, __LINE__)
335#else
336#define MFI_PRINT_CMD(cm)
337#define MFI_DUMP_CMDS(sc)
338#define MFI_VALIDATE_CMD(sc, cm)
339#endif
340
341#endif /* _MFIVAR_H */
342