mfivar.h revision 162619
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 162619 2006-09-25 11:35:34Z 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
96	struct mfi_hwcomms		*mfi_comms;
97	TAILQ_HEAD(,mfi_command)	mfi_free;
98	TAILQ_HEAD(,mfi_command)	mfi_ready;
99	TAILQ_HEAD(,mfi_command)	mfi_busy;
100	struct bio_queue_head		mfi_bioq;
101	struct mfi_qstat		mfi_qstat[MFIQ_COUNT];
102
103	struct resource			*mfi_regs_resource;
104	bus_space_handle_t		mfi_bhandle;
105	bus_space_tag_t			mfi_btag;
106	int				mfi_regs_rid;
107
108	bus_dma_tag_t			mfi_parent_dmat;
109	bus_dma_tag_t			mfi_buffer_dmat;
110
111	bus_dma_tag_t			mfi_comms_dmat;
112	bus_dmamap_t			mfi_comms_dmamap;
113	uint32_t			mfi_comms_busaddr;
114
115	bus_dma_tag_t			mfi_frames_dmat;
116	bus_dmamap_t			mfi_frames_dmamap;
117	uint32_t			mfi_frames_busaddr;
118	union mfi_frame			*mfi_frames;
119
120	TAILQ_HEAD(,mfi_aen)		mfi_aen_pids;
121	struct mfi_command		*mfi_aen_cm;
122	uint32_t			mfi_aen_triggered;
123	uint32_t			mfi_poll_waiting;
124	struct selinfo			mfi_select;
125
126	bus_dma_tag_t			mfi_sense_dmat;
127	bus_dmamap_t			mfi_sense_dmamap;
128	uint32_t			mfi_sense_busaddr;
129	struct mfi_sense		*mfi_sense;
130
131	struct resource			*mfi_irq;
132	void				*mfi_intr;
133	int				mfi_irq_rid;
134
135	struct intr_config_hook		mfi_ich;
136	eventhandler_tag		eh;
137
138	/*
139	 * Allocation for the command array.  Used as an indexable array to
140	 * recover completed commands.
141	 */
142	struct mfi_command		*mfi_commands;
143	/*
144	 * How many commands were actually allocated
145	 */
146	int				mfi_total_cmds;
147	/*
148	 * How many commands the firmware can handle.  Also how big the reply
149	 * queue is, minus 1.
150	 */
151	int				mfi_max_fw_cmds;
152	/*
153	 * How many S/G elements we'll ever actually use
154	 */
155	int				mfi_max_sge;
156	/*
157	 * How many bytes a compound frame is, including all of the extra frames
158	 * that are used for S/G elements.
159	 */
160	int				mfi_cmd_size;
161	/*
162	 * How large an S/G element is.  Used to calculate the number of single
163	 * frames in a command.
164	 */
165	int				mfi_sge_size;
166	/*
167	 * Max number of sectors that the firmware allows
168	 */
169	uint32_t			mfi_max_io;
170
171	TAILQ_HEAD(,mfi_ld)		mfi_ld_tqh;
172	eventhandler_tag		mfi_eh;
173	struct cdev			*mfi_cdev;
174
175	struct callout			mfi_watchdog_callout;
176	struct mtx			mfi_io_lock;
177};
178
179extern int mfi_attach(struct mfi_softc *);
180extern void mfi_free(struct mfi_softc *);
181extern int mfi_shutdown(struct mfi_softc *);
182extern void mfi_startio(struct mfi_softc *);
183extern void mfi_disk_complete(struct bio *);
184extern int mfi_dump_blocks(struct mfi_softc *, int id, uint64_t, void *, int);
185
186#define MFIQ_ADD(sc, qname)					\
187	do {							\
188		struct mfi_qstat *qs;				\
189								\
190		qs = &(sc)->mfi_qstat[qname];			\
191		qs->q_length++;					\
192		if (qs->q_length > qs->q_max)			\
193			qs->q_max = qs->q_length;		\
194	} while (0)
195
196#define MFIQ_REMOVE(sc, qname)	(sc)->mfi_qstat[qname].q_length--
197
198#define MFIQ_INIT(sc, qname)					\
199	do {							\
200		sc->mfi_qstat[qname].q_length = 0;		\
201		sc->mfi_qstat[qname].q_max = 0;			\
202	} while (0)
203
204#define MFIQ_COMMAND_QUEUE(name, index)					\
205	static __inline void						\
206	mfi_initq_ ## name (struct mfi_softc *sc)			\
207	{								\
208		TAILQ_INIT(&sc->mfi_ ## name);				\
209		MFIQ_INIT(sc, index);					\
210	}								\
211	static __inline void						\
212	mfi_enqueue_ ## name (struct mfi_command *cm)			\
213	{								\
214		if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) {		\
215			printf("command %p is on another queue, "	\
216			    "flags = %#x\n", cm, cm->cm_flags);		\
217			panic("command is on another queue");		\
218		}							\
219		TAILQ_INSERT_TAIL(&cm->cm_sc->mfi_ ## name, cm, cm_link); \
220		cm->cm_flags |= MFI_ON_ ## index;			\
221		MFIQ_ADD(cm->cm_sc, index);				\
222	}								\
223	static __inline void						\
224	mfi_requeue_ ## name (struct mfi_command *cm)			\
225	{								\
226		if ((cm->cm_flags & MFI_ON_MFIQ_MASK) != 0) {		\
227			printf("command %p is on another queue, "	\
228			    "flags = %#x\n", cm, cm->cm_flags);		\
229			panic("command is on another queue");		\
230		}							\
231		TAILQ_INSERT_HEAD(&cm->cm_sc->mfi_ ## name, cm, cm_link); \
232		cm->cm_flags |= MFI_ON_ ## index;			\
233		MFIQ_ADD(cm->cm_sc, index);				\
234	}								\
235	static __inline struct mfi_command *				\
236	mfi_dequeue_ ## name (struct mfi_softc *sc)			\
237	{								\
238		struct mfi_command *cm;					\
239									\
240		if ((cm = TAILQ_FIRST(&sc->mfi_ ## name)) != NULL) {	\
241			if ((cm->cm_flags & MFI_ON_ ## index) == 0) {	\
242				printf("command %p not in queue, "	\
243				    "flags = %#x, bit = %#x\n", cm,	\
244				    cm->cm_flags, MFI_ON_ ## index);	\
245				panic("command not in queue");		\
246			}						\
247			TAILQ_REMOVE(&sc->mfi_ ## name, cm, cm_link);	\
248			cm->cm_flags &= ~MFI_ON_ ## index;		\
249			MFIQ_REMOVE(sc, index);				\
250		}							\
251		return (cm);						\
252	}								\
253	static __inline void						\
254	mfi_remove_ ## name (struct mfi_command *cm)			\
255	{								\
256		if ((cm->cm_flags & MFI_ON_ ## index) == 0) {		\
257			printf("command %p not in queue, flags = %#x, " \
258			    "bit = %#x\n", cm, cm->cm_flags,		\
259			    MFI_ON_ ## index);				\
260			panic("command not in queue");			\
261		}							\
262		TAILQ_REMOVE(&cm->cm_sc->mfi_ ## name, cm, cm_link);	\
263		cm->cm_flags &= ~MFI_ON_ ## index;			\
264		MFIQ_REMOVE(cm->cm_sc, index);				\
265	}								\
266struct hack
267
268MFIQ_COMMAND_QUEUE(free, MFIQ_FREE);
269MFIQ_COMMAND_QUEUE(ready, MFIQ_READY);
270MFIQ_COMMAND_QUEUE(busy, MFIQ_BUSY);
271
272static __inline void
273mfi_initq_bio(struct mfi_softc *sc)
274{
275	bioq_init(&sc->mfi_bioq);
276	MFIQ_INIT(sc, MFIQ_BIO);
277}
278
279static __inline void
280mfi_enqueue_bio(struct mfi_softc *sc, struct bio *bp)
281{
282	bioq_insert_tail(&sc->mfi_bioq, bp);
283	MFIQ_ADD(sc, MFIQ_BIO);
284}
285
286static __inline struct bio *
287mfi_dequeue_bio(struct mfi_softc *sc)
288{
289	struct bio *bp;
290
291	if ((bp = bioq_first(&sc->mfi_bioq)) != NULL) {
292		bioq_remove(&sc->mfi_bioq, bp);
293		MFIQ_REMOVE(sc, MFIQ_BIO);
294	}
295	return (bp);
296}
297
298static __inline void
299mfi_print_sense(struct mfi_softc *sc, void *sense)
300{
301	int error, key, asc, ascq;
302
303	scsi_extract_sense((struct scsi_sense_data *)sense,
304	    &error, &key, &asc, &ascq);
305	device_printf(sc->mfi_dev, "sense error %d, sense_key %d, "
306	    "asc %d, ascq %d\n", error, key, asc, ascq);
307}
308
309
310#define MFI_WRITE4(sc, reg, val)	bus_space_write_4((sc)->mfi_btag, \
311	sc->mfi_bhandle, (reg), (val))
312#define MFI_READ4(sc, reg)		bus_space_read_4((sc)->mfi_btag, \
313	(sc)->mfi_bhandle, (reg))
314#define MFI_WRITE2(sc, reg, val)	bus_space_write_2((sc)->mfi_btag, \
315	sc->mfi_bhandle, (reg), (val))
316#define MFI_READ2(sc, reg)		bus_space_read_2((sc)->mfi_btag, \
317	(sc)->mfi_bhandle, (reg))
318#define MFI_WRITE1(sc, reg, val)	bus_space_write_1((sc)->mfi_btag, \
319	sc->mfi_bhandle, (reg), (val))
320#define MFI_READ1(sc, reg)		bus_space_read_1((sc)->mfi_btag, \
321	(sc)->mfi_bhandle, (reg))
322
323MALLOC_DECLARE(M_MFIBUF);
324
325#define MFI_CMD_TIMEOUT 30
326
327#ifdef MFI_DEBUG
328extern void mfi_print_cmd(struct mfi_command *cm);
329extern void mfi_dump_cmds(struct mfi_softc *sc);
330#define MFI_PRINT_CMD(cm)	mfi_print_cmd(cm)
331#define MFI_DUMP_CMDS(sc)	mfi_dump_cmds(sc);
332#else
333#define MFI_PRINT_CMD(cm)
334#define MFI_DUMP_CMDS(sc)
335#endif
336
337#endif /* _MFIVAR_H */
338