mpsvar.h revision 213839
1/*-
2 * Copyright (c) 2009 Yahoo! Inc.
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 * $FreeBSD: head/sys/dev/mps/mpsvar.h 213839 2010-10-14 16:44:05Z mdf $
27 */
28
29#ifndef _MPSVAR_H
30#define _MPSVAR_H
31
32#define MPS_DB_MAX_WAIT		2500
33
34#define MPS_REQ_FRAMES		1024
35#define MPS_EVT_REPLY_FRAMES	32
36#define MPS_REPLY_FRAMES	MPS_REQ_FRAMES
37#define MPS_CHAIN_FRAMES	1024
38#define MPS_SENSE_LEN		SSD_FULL_SIZE
39#define MPS_MSI_COUNT		1
40#define MPS_SGE64_SIZE		12
41#define MPS_SGE32_SIZE		8
42#define MPS_SGC_SIZE		8
43
44#define MPS_PERIODIC_DELAY	1	/* 1 second heartbeat/watchdog check */
45
46struct mps_softc;
47struct mps_command;
48struct mpssas_softc;
49struct mpssas_target;
50
51MALLOC_DECLARE(M_MPT2);
52
53typedef void mps_evt_callback_t(struct mps_softc *, uintptr_t,
54    MPI2_EVENT_NOTIFICATION_REPLY *reply);
55typedef void mps_command_callback_t(struct mps_softc *, struct mps_command *cm);
56
57struct mps_chain {
58	TAILQ_ENTRY(mps_chain)		chain_link;
59	MPI2_SGE_IO_UNION		*chain;
60	uint32_t			chain_busaddr;
61};
62
63struct mps_command {
64	TAILQ_ENTRY(mps_command)	cm_link;
65	struct mps_softc		*cm_sc;
66	void				*cm_data;
67	u_int				cm_length;
68	u_int				cm_sglsize;
69	MPI2_SGE_IO_UNION		*cm_sge;
70	uint8_t				*cm_req;
71	uint8_t				*cm_reply;
72	uint32_t			cm_reply_data;
73	mps_command_callback_t		*cm_complete;
74	void				*cm_complete_data;
75	struct mpssas_target		*cm_targ;
76	MPI2_REQUEST_DESCRIPTOR_UNION	cm_desc;
77	u_int				cm_flags;
78#define MPS_CM_FLAGS_POLLED		(1 << 0)
79#define MPS_CM_FLAGS_COMPLETE		(1 << 1)
80#define MPS_CM_FLAGS_SGE_SIMPLE		(1 << 2)
81#define MPS_CM_FLAGS_DATAOUT		(1 << 3)
82#define MPS_CM_FLAGS_DATAIN		(1 << 4)
83#define MPS_CM_FLAGS_WAKEUP		(1 << 5)
84#define MPS_CM_FLAGS_ACTIVE		(1 << 6)
85	u_int				cm_state;
86#define MPS_CM_STATE_FREE		0
87#define MPS_CM_STATE_BUSY		1
88#define MPS_CM_STATE_TIMEDOUT		2
89	bus_dmamap_t			cm_dmamap;
90	struct scsi_sense_data		*cm_sense;
91	TAILQ_HEAD(, mps_chain)		cm_chain_list;
92	uint32_t			cm_req_busaddr;
93	uint32_t			cm_sense_busaddr;
94	struct callout			cm_callout;
95};
96
97struct mps_event_handle {
98	TAILQ_ENTRY(mps_event_handle)	eh_list;
99	mps_evt_callback_t		*callback;
100	void				*data;
101	uint8_t				mask[16];
102};
103
104struct mps_softc {
105	device_t			mps_dev;
106	struct cdev			*mps_cdev;
107	u_int				mps_flags;
108#define MPS_FLAGS_INTX		(1 << 0)
109#define MPS_FLAGS_MSI		(1 << 1)
110#define MPS_FLAGS_BUSY		(1 << 2)
111#define MPS_FLAGS_SHUTDOWN	(1 << 3)
112	u_int				mps_debug;
113	u_int				allow_multiple_tm_cmds;
114	int				tm_cmds_active;
115	struct sysctl_ctx_list		sysctl_ctx;
116	struct sysctl_oid		*sysctl_tree;
117	struct mps_command		*commands;
118	struct mps_chain		*chains;
119	struct callout			periodic;
120
121	struct mpssas_softc		*sassc;
122
123	TAILQ_HEAD(, mps_command)	req_list;
124	TAILQ_HEAD(, mps_chain)		chain_list;
125	TAILQ_HEAD(, mps_command)	tm_list;
126	int				replypostindex;
127	int				replyfreeindex;
128	int				replycurindex;
129
130	struct resource			*mps_regs_resource;
131	bus_space_handle_t		mps_bhandle;
132	bus_space_tag_t			mps_btag;
133	int				mps_regs_rid;
134
135	bus_dma_tag_t			mps_parent_dmat;
136	bus_dma_tag_t			buffer_dmat;
137
138	MPI2_IOC_FACTS_REPLY		*facts;
139	MPI2_PORT_FACTS_REPLY		*pfacts;
140	int				num_reqs;
141	int				num_replies;
142	int				fqdepth;	/* Free queue */
143	int				pqdepth;	/* Post queue */
144
145	uint8_t				event_mask[16];
146	TAILQ_HEAD(, mps_event_handle)	event_list;
147	struct mps_event_handle		*mps_log_eh;
148
149	struct mtx			mps_mtx;
150	struct intr_config_hook		mps_ich;
151	struct resource			*mps_irq[MPS_MSI_COUNT];
152	void				*mps_intrhand[MPS_MSI_COUNT];
153	int				mps_irq_rid[MPS_MSI_COUNT];
154
155	uint8_t				*req_frames;
156	bus_addr_t			req_busaddr;
157	bus_dma_tag_t			req_dmat;
158	bus_dmamap_t			req_map;
159
160	uint8_t				*reply_frames;
161	bus_addr_t			reply_busaddr;
162	bus_dma_tag_t			reply_dmat;
163	bus_dmamap_t			reply_map;
164
165	struct scsi_sense_data		*sense_frames;
166	bus_addr_t			sense_busaddr;
167	bus_dma_tag_t			sense_dmat;
168	bus_dmamap_t			sense_map;
169
170	uint8_t				*chain_frames;
171	bus_addr_t			chain_busaddr;
172	bus_dma_tag_t			chain_dmat;
173	bus_dmamap_t			chain_map;
174
175	MPI2_REPLY_DESCRIPTORS_UNION	*post_queue;
176	bus_addr_t			post_busaddr;
177	uint32_t			*free_queue;
178	bus_addr_t			free_busaddr;
179	bus_dma_tag_t			queues_dmat;
180	bus_dmamap_t			queues_map;
181};
182
183struct mps_config_params {
184	MPI2_CONFIG_EXT_PAGE_HEADER_UNION	hdr;
185	u_int		action;
186	u_int		page_address;	/* Attributes, not a phys address */
187	u_int		status;
188	void		*buffer;
189	u_int		length;
190	int		timeout;
191	void		(*callback)(struct mps_softc *, struct mps_config_params *);
192	void		*cbdata;
193};
194
195static __inline uint32_t
196mps_regread(struct mps_softc *sc, uint32_t offset)
197{
198	return (bus_space_read_4(sc->mps_btag, sc->mps_bhandle, offset));
199}
200
201static __inline void
202mps_regwrite(struct mps_softc *sc, uint32_t offset, uint32_t val)
203{
204	bus_space_write_4(sc->mps_btag, sc->mps_bhandle, offset, val);
205}
206
207static __inline void
208mps_free_reply(struct mps_softc *sc, uint32_t busaddr)
209{
210
211	if (++sc->replyfreeindex >= sc->fqdepth)
212		sc->replyfreeindex = 0;
213	sc->free_queue[sc->replyfreeindex] = busaddr;
214	mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
215}
216
217static __inline struct mps_chain *
218mps_alloc_chain(struct mps_softc *sc)
219{
220	struct mps_chain *chain;
221
222	if ((chain = TAILQ_FIRST(&sc->chain_list)) != NULL)
223		TAILQ_REMOVE(&sc->chain_list, chain, chain_link);
224	return (chain);
225}
226
227static __inline void
228mps_free_chain(struct mps_softc *sc, struct mps_chain *chain)
229{
230#if 0
231	bzero(chain->chain, 128);
232#endif
233	TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link);
234}
235
236static __inline void
237mps_free_command(struct mps_softc *sc, struct mps_command *cm)
238{
239	struct mps_chain *chain, *chain_temp;
240
241	if (cm->cm_reply != NULL)
242		mps_free_reply(sc, cm->cm_reply_data);
243	cm->cm_flags = 0;
244	cm->cm_complete = NULL;
245	cm->cm_complete_data = NULL;
246	cm->cm_targ = 0;
247	cm->cm_state = MPS_CM_STATE_FREE;
248	TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) {
249		TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link);
250		mps_free_chain(sc, chain);
251	}
252	TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link);
253}
254
255static __inline struct mps_command *
256mps_alloc_command(struct mps_softc *sc)
257{
258	struct mps_command *cm;
259
260	cm = TAILQ_FIRST(&sc->req_list);
261	if (cm == NULL)
262		return (NULL);
263
264	TAILQ_REMOVE(&sc->req_list, cm, cm_link);
265	KASSERT(cm->cm_state == MPS_CM_STATE_FREE, ("mps: Allocating busy command\n"));
266	cm->cm_state = MPS_CM_STATE_BUSY;
267	return (cm);
268}
269
270static __inline void
271mps_lock(struct mps_softc *sc)
272{
273	mtx_lock(&sc->mps_mtx);
274}
275
276static __inline void
277mps_unlock(struct mps_softc *sc)
278{
279	mtx_unlock(&sc->mps_mtx);
280}
281
282#define MPS_INFO	(1 << 0)
283#define MPS_TRACE	(1 << 1)
284#define MPS_FAULT	(1 << 2)
285#define MPS_EVENT	(1 << 3)
286#define MPS_LOG		(1 << 4)
287
288#define mps_printf(sc, args...)				\
289	device_printf((sc)->mps_dev, ##args)
290
291#define mps_dprint(sc, level, msg, args...)		\
292do {							\
293	if (sc->mps_debug & level)			\
294		device_printf(sc->mps_dev, msg, ##args);	\
295} while (0)
296
297#define mps_dprint_field(sc, level, msg, args...)		\
298do {								\
299	if (sc->mps_debug & level)				\
300		printf("\t" msg, ##args);			\
301} while (0)
302
303#define MPS_PRINTFIELD_START(sc, tag...)	\
304	mps_dprint((sc), MPS_INFO, ##tag);	\
305	mps_dprint_field((sc), MPS_INFO, ":\n")
306#define MPS_PRINTFIELD_END(sc, tag)		\
307	mps_dprint((sc), MPS_INFO, tag "\n")
308#define MPS_PRINTFIELD(sc, facts, attr, fmt)	\
309	mps_dprint_field((sc), MPS_INFO, #attr ": " #fmt "\n", (facts)->attr)
310
311#define MPS_EVENTFIELD_START(sc, tag...)	\
312	mps_dprint((sc), MPS_EVENT, ##tag);	\
313	mps_dprint_field((sc), MPS_EVENT, ":\n")
314#define MPS_EVENTFIELD(sc, facts, attr, fmt)	\
315	mps_dprint_field((sc), MPS_EVENT, #attr ": " #fmt "\n", (facts)->attr)
316
317static __inline void
318mps_from_u64(uint64_t data, U64 *mps)
319{
320	(mps)->High = (uint32_t)((data) >> 32);
321	(mps)->Low = (uint32_t)((data) & 0xffffffff);
322}
323
324static __inline uint64_t
325mps_to_u64(U64 *data)
326{
327
328	return (((uint64_t)data->High << 32) | data->Low);
329}
330
331static __inline void
332mps_mask_intr(struct mps_softc *sc)
333{
334	uint32_t mask;
335
336	mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
337	mask |= MPI2_HIM_REPLY_INT_MASK;
338	mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
339}
340
341static __inline void
342mps_unmask_intr(struct mps_softc *sc)
343{
344	uint32_t mask;
345
346	mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
347	mask &= ~MPI2_HIM_REPLY_INT_MASK;
348	mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
349}
350
351int mps_pci_setup_interrupts(struct mps_softc *);
352int mps_attach(struct mps_softc *sc);
353int mps_free(struct mps_softc *sc);
354void mps_intr(void *);
355void mps_intr_msi(void *);
356void mps_intr_locked(void *);
357int mps_register_events(struct mps_softc *, uint8_t *, mps_evt_callback_t *,
358    void *, struct mps_event_handle **);
359int mps_update_events(struct mps_softc *, struct mps_event_handle *, uint8_t *);
360int mps_deregister_events(struct mps_softc *, struct mps_event_handle *);
361int mps_request_polled(struct mps_softc *sc, struct mps_command *cm);
362void mps_enqueue_request(struct mps_softc *, struct mps_command *);
363int mps_push_sge(struct mps_command *, void *, size_t, int);
364int mps_add_dmaseg(struct mps_command *, vm_paddr_t, size_t, u_int, int);
365int mps_attach_sas(struct mps_softc *sc);
366int mps_detach_sas(struct mps_softc *sc);
367int mps_map_command(struct mps_softc *sc, struct mps_command *cm);
368int mps_read_config_page(struct mps_softc *, struct mps_config_params *);
369int mps_write_config_page(struct mps_softc *, struct mps_config_params *);
370void mps_memaddr_cb(void *, bus_dma_segment_t *, int , int );
371int mps_attach_user(struct mps_softc *);
372void mps_detach_user(struct mps_softc *);
373
374SYSCTL_DECL(_hw_mps);
375
376#endif
377
378