mpt_user.c revision 219335
1198092Srdivacky/*-
2198092Srdivacky * Copyright (c) 2008 Yahoo!, Inc.
3198092Srdivacky * All rights reserved.
4198092Srdivacky * Written by: John Baldwin <jhb@FreeBSD.org>
5198092Srdivacky *
6198092Srdivacky * Redistribution and use in source and binary forms, with or without
7198092Srdivacky * modification, are permitted provided that the following conditions
8198092Srdivacky * are met:
9198092Srdivacky * 1. Redistributions of source code must retain the above copyright
10198092Srdivacky *    notice, this list of conditions and the following disclaimer.
11198092Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
12198092Srdivacky *    notice, this list of conditions and the following disclaimer in the
13198092Srdivacky *    documentation and/or other materials provided with the distribution.
14198092Srdivacky * 3. Neither the name of the author nor the names of any co-contributors
15198092Srdivacky *    may be used to endorse or promote products derived from this software
16198092Srdivacky *    without specific prior written permission.
17198092Srdivacky *
18199990Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19199482Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20198092Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21198092Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22198092Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23198092Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24198092Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25198092Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26198092Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27198092Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28239462Sdim * SUCH DAMAGE.
29239462Sdim *
30239462Sdim * LSI MPT-Fusion Host Adapter FreeBSD userland interface
31198092Srdivacky */
32239462Sdim
33198092Srdivacky#include <sys/cdefs.h>
34239462Sdim__FBSDID("$FreeBSD: head/sys/dev/mpt/mpt_user.c 219335 2011-03-06 12:48:15Z marius $");
35239462Sdim
36239462Sdim#include <sys/param.h>
37239462Sdim#include <sys/conf.h>
38198092Srdivacky#include <sys/errno.h>
39198092Srdivacky#include <sys/ioccom.h>
40239462Sdim#include <sys/mpt_ioctl.h>
41239462Sdim
42239462Sdim#include <dev/mpt/mpt.h>
43198092Srdivacky
44239462Sdimstruct mpt_user_raid_action_result {
45239462Sdim	uint32_t	volume_status;
46239462Sdim	uint32_t	action_data[4];
47198092Srdivacky	uint16_t	action_status;
48198092Srdivacky};
49198092Srdivacky
50198092Srdivackystruct mpt_page_memory {
51198092Srdivacky	bus_dma_tag_t	tag;
52198092Srdivacky	bus_dmamap_t	map;
53198092Srdivacky	bus_addr_t	paddr;
54198092Srdivacky	void		*vaddr;
55198092Srdivacky};
56198092Srdivacky
57198092Srdivackystatic mpt_probe_handler_t	mpt_user_probe;
58198092Srdivackystatic mpt_attach_handler_t	mpt_user_attach;
59198092Srdivackystatic mpt_enable_handler_t	mpt_user_enable;
60198092Srdivackystatic mpt_ready_handler_t	mpt_user_ready;
61198092Srdivackystatic mpt_event_handler_t	mpt_user_event;
62198092Srdivackystatic mpt_reset_handler_t	mpt_user_reset;
63198092Srdivackystatic mpt_detach_handler_t	mpt_user_detach;
64198092Srdivacky
65198092Srdivackystatic struct mpt_personality mpt_user_personality = {
66234353Sdim	.name		= "mpt_user",
67198092Srdivacky	.probe		= mpt_user_probe,
68198092Srdivacky	.attach		= mpt_user_attach,
69198092Srdivacky	.enable		= mpt_user_enable,
70198092Srdivacky	.ready		= mpt_user_ready,
71234353Sdim	.event		= mpt_user_event,
72198092Srdivacky	.reset		= mpt_user_reset,
73234353Sdim	.detach		= mpt_user_detach,
74198092Srdivacky};
75198092Srdivacky
76198092SrdivackyDECLARE_MPT_PERSONALITY(mpt_user, SI_ORDER_SECOND);
77198092Srdivacky
78198092Srdivackystatic mpt_reply_handler_t	mpt_user_reply_handler;
79198092Srdivacky
80234353Sdimstatic d_open_t		mpt_open;
81234353Sdimstatic d_close_t	mpt_close;
82198092Srdivackystatic d_ioctl_t	mpt_ioctl;
83198092Srdivacky
84198092Srdivackystatic struct cdevsw mpt_cdevsw = {
85198092Srdivacky	.d_version =	D_VERSION,
86198092Srdivacky	.d_flags =	0,
87198092Srdivacky	.d_open =	mpt_open,
88198092Srdivacky	.d_close =	mpt_close,
89234353Sdim	.d_ioctl =	mpt_ioctl,
90234353Sdim	.d_name =	"mpt",
91198092Srdivacky};
92198092Srdivacky
93198092Srdivackystatic MALLOC_DEFINE(M_MPTUSER, "mpt_user", "Buffers for mpt(4) ioctls");
94210299Sed
95210299Sedstatic uint32_t user_handler_id = MPT_HANDLER_ID_NONE;
96210299Sed
97210299Sedint
98210299Sedmpt_user_probe(struct mpt_softc *mpt)
99198893Srdivacky{
100234353Sdim
101199990Srdivacky	/* Attach to every controller. */
102199990Srdivacky	return (0);
103199990Srdivacky}
104199990Srdivacky
105234353Sdimint
106198893Srdivackympt_user_attach(struct mpt_softc *mpt)
107198893Srdivacky{
108198893Srdivacky	mpt_handler_t handler;
109198092Srdivacky	int error, unit;
110198092Srdivacky
111218893Sdim	MPT_LOCK(mpt);
112198092Srdivacky	handler.reply_handler = mpt_user_reply_handler;
113198092Srdivacky	error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler,
114198092Srdivacky				     &user_handler_id);
115198092Srdivacky	MPT_UNLOCK(mpt);
116198092Srdivacky	if (error != 0) {
117198092Srdivacky		mpt_prt(mpt, "Unable to register user handler!\n");
118234353Sdim		return (error);
119198092Srdivacky	}
120198092Srdivacky	unit = device_get_unit(mpt->dev);
121198092Srdivacky	mpt->cdev = make_dev(&mpt_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
122198092Srdivacky	    "mpt%d", unit);
123198092Srdivacky	if (mpt->cdev == NULL) {
124198092Srdivacky		MPT_LOCK(mpt);
125198092Srdivacky		mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
126198092Srdivacky		    user_handler_id);
127198092Srdivacky		MPT_UNLOCK(mpt);
128234353Sdim		return (ENOMEM);
129234353Sdim	}
130198092Srdivacky	mpt->cdev->si_drv1 = mpt;
131198092Srdivacky	return (0);
132198092Srdivacky}
133198092Srdivacky
134198092Srdivackyint
135198092Srdivackympt_user_enable(struct mpt_softc *mpt)
136234353Sdim{
137234353Sdim
138234353Sdim	return (0);
139234353Sdim}
140234353Sdim
141234353Sdimvoid
142234353Sdimmpt_user_ready(struct mpt_softc *mpt)
143234353Sdim{
144234353Sdim}
145234353Sdim
146198092Srdivackyint
147198092Srdivackympt_user_event(struct mpt_softc *mpt, request_t *req,
148198092Srdivacky    MSG_EVENT_NOTIFY_REPLY *msg)
149198092Srdivacky{
150198092Srdivacky
151198092Srdivacky	/* Someday we may want to let a user daemon listen for events? */
152198092Srdivacky	return (0);
153198092Srdivacky}
154198092Srdivacky
155198092Srdivackyvoid
156198092Srdivackympt_user_reset(struct mpt_softc *mpt, int type)
157198092Srdivacky{
158198092Srdivacky}
159198092Srdivacky
160198092Srdivackyvoid
161198092Srdivackympt_user_detach(struct mpt_softc *mpt)
162198092Srdivacky{
163198092Srdivacky	mpt_handler_t handler;
164198092Srdivacky
165198092Srdivacky	/* XXX: do a purge of pending requests? */
166198092Srdivacky	destroy_dev(mpt->cdev);
167198092Srdivacky
168198092Srdivacky	MPT_LOCK(mpt);
169198092Srdivacky	handler.reply_handler = mpt_user_reply_handler;
170198092Srdivacky	mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
171198092Srdivacky	    user_handler_id);
172198092Srdivacky	MPT_UNLOCK(mpt);
173212904Sdim}
174212904Sdim
175212904Sdimstatic int
176198092Srdivackympt_open(struct cdev *dev, int flags, int fmt, struct thread *td)
177198092Srdivacky{
178198092Srdivacky
179198092Srdivacky	return (0);
180198092Srdivacky}
181
182static int
183mpt_close(struct cdev *dev, int flags, int fmt, struct thread *td)
184{
185
186	return (0);
187}
188
189static int
190mpt_alloc_buffer(struct mpt_softc *mpt, struct mpt_page_memory *page_mem,
191    size_t len)
192{
193	struct mpt_map_info mi;
194	int error;
195
196	page_mem->vaddr = NULL;
197
198	/* Limit requests to 16M. */
199	if (len > 16 * 1024 * 1024)
200		return (ENOSPC);
201	error = mpt_dma_tag_create(mpt, mpt->parent_dmat, 1, 0,
202	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
203	    len, 1, len, 0, &page_mem->tag);
204	if (error)
205		return (error);
206	error = bus_dmamem_alloc(page_mem->tag, &page_mem->vaddr,
207	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &page_mem->map);
208	if (error) {
209		bus_dma_tag_destroy(page_mem->tag);
210		return (error);
211	}
212	mi.mpt = mpt;
213	error = bus_dmamap_load(page_mem->tag, page_mem->map, page_mem->vaddr,
214	    len, mpt_map_rquest, &mi, BUS_DMA_NOWAIT);
215	if (error == 0)
216		error = mi.error;
217	if (error) {
218		bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
219		bus_dma_tag_destroy(page_mem->tag);
220		page_mem->vaddr = NULL;
221		return (error);
222	}
223	page_mem->paddr = mi.phys;
224	return (0);
225}
226
227static void
228mpt_free_buffer(struct mpt_page_memory *page_mem)
229{
230
231	if (page_mem->vaddr == NULL)
232		return;
233	bus_dmamap_unload(page_mem->tag, page_mem->map);
234	bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
235	bus_dma_tag_destroy(page_mem->tag);
236	page_mem->vaddr = NULL;
237}
238
239static int
240mpt_user_read_cfg_header(struct mpt_softc *mpt,
241    struct mpt_cfg_page_req *page_req)
242{
243	request_t  *req;
244	cfgparms_t params;
245	MSG_CONFIG *cfgp;
246	int	    error;
247
248	req = mpt_get_request(mpt, TRUE);
249	if (req == NULL) {
250		mpt_prt(mpt, "mpt_user_read_cfg_header: Get request failed!\n");
251		return (ENOMEM);
252	}
253
254	params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
255	params.PageVersion = 0;
256	params.PageLength = 0;
257	params.PageNumber = page_req->header.PageNumber;
258	params.PageType = page_req->header.PageType;
259	params.PageAddress = le32toh(page_req->page_address);
260	error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
261				  TRUE, 5000);
262	if (error != 0) {
263		/*
264		 * Leave the request. Without resetting the chip, it's
265		 * still owned by it and we'll just get into trouble
266		 * freeing it now. Mark it as abandoned so that if it
267		 * shows up later it can be freed.
268		 */
269		mpt_prt(mpt, "read_cfg_header timed out\n");
270		return (ETIMEDOUT);
271	}
272
273	page_req->ioc_status = htole16(req->IOCStatus);
274	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
275		cfgp = req->req_vbuf;
276		bcopy(&cfgp->Header, &page_req->header,
277		    sizeof(page_req->header));
278	}
279	mpt_free_request(mpt, req);
280	return (0);
281}
282
283static int
284mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
285    struct mpt_page_memory *mpt_page)
286{
287	CONFIG_PAGE_HEADER *hdr;
288	request_t    *req;
289	cfgparms_t    params;
290	int	      error;
291
292	req = mpt_get_request(mpt, TRUE);
293	if (req == NULL) {
294		mpt_prt(mpt, "mpt_user_read_cfg_page: Get request failed!\n");
295		return (ENOMEM);
296	}
297
298	hdr = mpt_page->vaddr;
299	params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
300	params.PageVersion = hdr->PageVersion;
301	params.PageLength = hdr->PageLength;
302	params.PageNumber = hdr->PageNumber;
303	params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
304	params.PageAddress = le32toh(page_req->page_address);
305	bus_dmamap_sync(mpt_page->tag, mpt_page->map,
306	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
307	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
308	    le32toh(page_req->len), TRUE, 5000);
309	if (error != 0) {
310		mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n");
311		return (ETIMEDOUT);
312	}
313
314	page_req->ioc_status = htole16(req->IOCStatus);
315	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
316		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
317		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
318	mpt_free_request(mpt, req);
319	return (0);
320}
321
322static int
323mpt_user_read_extcfg_header(struct mpt_softc *mpt,
324    struct mpt_ext_cfg_page_req *ext_page_req)
325{
326	request_t  *req;
327	cfgparms_t params;
328	MSG_CONFIG_REPLY *cfgp;
329	int	    error;
330
331	req = mpt_get_request(mpt, TRUE);
332	if (req == NULL) {
333		mpt_prt(mpt, "mpt_user_read_extcfg_header: Get request failed!\n");
334		return (ENOMEM);
335	}
336
337	params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
338	params.PageVersion = ext_page_req->header.PageVersion;
339	params.PageLength = 0;
340	params.PageNumber = ext_page_req->header.PageNumber;
341	params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
342	params.PageAddress = le32toh(ext_page_req->page_address);
343	params.ExtPageType = ext_page_req->header.ExtPageType;
344	params.ExtPageLength = 0;
345	error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
346				  TRUE, 5000);
347	if (error != 0) {
348		/*
349		 * Leave the request. Without resetting the chip, it's
350		 * still owned by it and we'll just get into trouble
351		 * freeing it now. Mark it as abandoned so that if it
352		 * shows up later it can be freed.
353		 */
354		mpt_prt(mpt, "mpt_user_read_extcfg_header timed out\n");
355		return (ETIMEDOUT);
356	}
357
358	ext_page_req->ioc_status = htole16(req->IOCStatus);
359	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
360		cfgp = req->req_vbuf;
361		ext_page_req->header.PageVersion = cfgp->Header.PageVersion;
362		ext_page_req->header.PageNumber = cfgp->Header.PageNumber;
363		ext_page_req->header.PageType = cfgp->Header.PageType;
364		ext_page_req->header.ExtPageLength = cfgp->ExtPageLength;
365		ext_page_req->header.ExtPageType = cfgp->ExtPageType;
366	}
367	mpt_free_request(mpt, req);
368	return (0);
369}
370
371static int
372mpt_user_read_extcfg_page(struct mpt_softc *mpt,
373    struct mpt_ext_cfg_page_req *ext_page_req, struct mpt_page_memory *mpt_page)
374{
375	CONFIG_EXTENDED_PAGE_HEADER *hdr;
376	request_t    *req;
377	cfgparms_t    params;
378	int	      error;
379
380	req = mpt_get_request(mpt, TRUE);
381	if (req == NULL) {
382		mpt_prt(mpt, "mpt_user_read_extcfg_page: Get request failed!\n");
383		return (ENOMEM);
384	}
385
386	hdr = mpt_page->vaddr;
387	params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
388	params.PageVersion = hdr->PageVersion;
389	params.PageLength = 0;
390	params.PageNumber = hdr->PageNumber;
391	params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
392	params.PageAddress = le32toh(ext_page_req->page_address);
393	params.ExtPageType = hdr->ExtPageType;
394	params.ExtPageLength = hdr->ExtPageLength;
395	bus_dmamap_sync(mpt_page->tag, mpt_page->map,
396	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
397	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
398	    le32toh(ext_page_req->len), TRUE, 5000);
399	if (error != 0) {
400		mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n");
401		return (ETIMEDOUT);
402	}
403
404	ext_page_req->ioc_status = htole16(req->IOCStatus);
405	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
406		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
407		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
408	mpt_free_request(mpt, req);
409	return (0);
410}
411
412static int
413mpt_user_write_cfg_page(struct mpt_softc *mpt,
414    struct mpt_cfg_page_req *page_req, struct mpt_page_memory *mpt_page)
415{
416	CONFIG_PAGE_HEADER *hdr;
417	request_t    *req;
418	cfgparms_t    params;
419	u_int	      hdr_attr;
420	int	      error;
421
422	hdr = mpt_page->vaddr;
423	hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
424	if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
425	    hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
426		mpt_prt(mpt, "page type 0x%x not changeable\n",
427			hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
428		return (EINVAL);
429	}
430
431#if	0
432	/*
433	 * We shouldn't mask off other bits here.
434	 */
435	hdr->PageType &= ~MPI_CONFIG_PAGETYPE_MASK;
436#endif
437
438	req = mpt_get_request(mpt, TRUE);
439	if (req == NULL)
440		return (ENOMEM);
441
442	bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_PREREAD |
443	    BUS_DMASYNC_PREWRITE);
444
445	/*
446	 * There isn't any point in restoring stripped out attributes
447	 * if you then mask them going down to issue the request.
448	 */
449
450	params.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
451	params.PageVersion = hdr->PageVersion;
452	params.PageLength = hdr->PageLength;
453	params.PageNumber = hdr->PageNumber;
454	params.PageAddress = le32toh(page_req->page_address);
455#if	0
456	/* Restore stripped out attributes */
457	hdr->PageType |= hdr_attr;
458	params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
459#else
460	params.PageType = hdr->PageType;
461#endif
462	error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
463	    le32toh(page_req->len), TRUE, 5000);
464	if (error != 0) {
465		mpt_prt(mpt, "mpt_write_cfg_page timed out\n");
466		return (ETIMEDOUT);
467	}
468
469	page_req->ioc_status = htole16(req->IOCStatus);
470	bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_POSTREAD |
471	    BUS_DMASYNC_POSTWRITE);
472	mpt_free_request(mpt, req);
473	return (0);
474}
475
476static int
477mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req,
478    uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame)
479{
480	MSG_RAID_ACTION_REPLY *reply;
481	struct mpt_user_raid_action_result *res;
482
483	if (req == NULL)
484		return (TRUE);
485
486	if (reply_frame != NULL) {
487		reply = (MSG_RAID_ACTION_REPLY *)reply_frame;
488		req->IOCStatus = le16toh(reply->IOCStatus);
489		res = (struct mpt_user_raid_action_result *)
490		    (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
491		res->action_status = reply->ActionStatus;
492		res->volume_status = reply->VolumeStatus;
493		bcopy(&reply->ActionData, res->action_data,
494		    sizeof(res->action_data));
495	}
496
497	req->state &= ~REQ_STATE_QUEUED;
498	req->state |= REQ_STATE_DONE;
499	TAILQ_REMOVE(&mpt->request_pending_list, req, links);
500
501	if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) {
502		wakeup(req);
503	} else if ((req->state & REQ_STATE_TIMEDOUT) != 0) {
504		/*
505		 * Whew- we can free this request (late completion)
506		 */
507		mpt_free_request(mpt, req);
508	}
509
510	return (TRUE);
511}
512
513/*
514 * We use the first part of the request buffer after the request frame
515 * to hold the action data and action status from the RAID reply.  The
516 * rest of the request buffer is used to hold the buffer for the
517 * action SGE.
518 */
519static int
520mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
521	struct mpt_page_memory *mpt_page)
522{
523	request_t *req;
524	struct mpt_user_raid_action_result *res;
525	MSG_RAID_ACTION_REQUEST *rap;
526	SGE_SIMPLE32 *se;
527	int error;
528
529	req = mpt_get_request(mpt, TRUE);
530	if (req == NULL)
531		return (ENOMEM);
532	rap = req->req_vbuf;
533	memset(rap, 0, sizeof *rap);
534	rap->Action = raid_act->action;
535	rap->ActionDataWord = raid_act->action_data_word;
536	rap->Function = MPI_FUNCTION_RAID_ACTION;
537	rap->VolumeID = raid_act->volume_id;
538	rap->VolumeBus = raid_act->volume_bus;
539	rap->PhysDiskNum = raid_act->phys_disk_num;
540	se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
541	if (mpt_page->vaddr != NULL && raid_act->len != 0) {
542		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
543		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
544		se->Address = htole32(mpt_page->paddr);
545		MPI_pSGE_SET_LENGTH(se, le32toh(raid_act->len));
546		MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
547		    MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
548		    MPI_SGE_FLAGS_END_OF_LIST |
549		    raid_act->write ? MPI_SGE_FLAGS_HOST_TO_IOC :
550		    MPI_SGE_FLAGS_IOC_TO_HOST));
551	}
552	se->FlagsLength = htole32(se->FlagsLength);
553	rap->MsgContext = htole32(req->index | user_handler_id);
554
555	mpt_check_doorbell(mpt);
556	mpt_send_cmd(mpt, req);
557
558	error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, TRUE,
559	    2000);
560	if (error != 0) {
561		/*
562		 * Leave request so it can be cleaned up later.
563		 */
564		mpt_prt(mpt, "mpt_user_raid_action timed out\n");
565		return (error);
566	}
567
568	raid_act->ioc_status = htole16(req->IOCStatus);
569	if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
570		mpt_free_request(mpt, req);
571		return (0);
572	}
573
574	res = (struct mpt_user_raid_action_result *)
575	    (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
576	raid_act->volume_status = res->volume_status;
577	raid_act->action_status = res->action_status;
578	bcopy(res->action_data, raid_act->action_data,
579	    sizeof(res->action_data));
580	if (mpt_page->vaddr != NULL)
581		bus_dmamap_sync(mpt_page->tag, mpt_page->map,
582		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
583	mpt_free_request(mpt, req);
584	return (0);
585}
586
587#ifdef __amd64__
588#define	PTRIN(p)		((void *)(uintptr_t)(p))
589#define PTROUT(v)		((u_int32_t)(uintptr_t)(v))
590#endif
591
592static int
593mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
594{
595	struct mpt_softc *mpt;
596	struct mpt_cfg_page_req *page_req;
597	struct mpt_ext_cfg_page_req *ext_page_req;
598	struct mpt_raid_action *raid_act;
599	struct mpt_page_memory mpt_page;
600#ifdef __amd64__
601	struct mpt_cfg_page_req32 *page_req32;
602	struct mpt_cfg_page_req page_req_swab;
603	struct mpt_ext_cfg_page_req32 *ext_page_req32;
604	struct mpt_ext_cfg_page_req ext_page_req_swab;
605	struct mpt_raid_action32 *raid_act32;
606	struct mpt_raid_action raid_act_swab;
607#endif
608	int error;
609
610	mpt = dev->si_drv1;
611	page_req = (void *)arg;
612	ext_page_req = (void *)arg;
613	raid_act = (void *)arg;
614	mpt_page.vaddr = NULL;
615
616#ifdef __amd64__
617	/* Convert 32-bit structs to native ones. */
618	page_req32 = (void *)arg;
619	ext_page_req32 = (void *)arg;
620	raid_act32 = (void *)arg;
621	switch (cmd) {
622	case MPTIO_READ_CFG_HEADER32:
623	case MPTIO_READ_CFG_PAGE32:
624	case MPTIO_WRITE_CFG_PAGE32:
625		page_req = &page_req_swab;
626		page_req->header = page_req32->header;
627		page_req->page_address = page_req32->page_address;
628		page_req->buf = PTRIN(page_req32->buf);
629		page_req->len = page_req32->len;
630		page_req->ioc_status = page_req32->ioc_status;
631		break;
632	case MPTIO_READ_EXT_CFG_HEADER32:
633	case MPTIO_READ_EXT_CFG_PAGE32:
634		ext_page_req = &ext_page_req_swab;
635		ext_page_req->header = ext_page_req32->header;
636		ext_page_req->page_address = ext_page_req32->page_address;
637		ext_page_req->buf = PTRIN(ext_page_req32->buf);
638		ext_page_req->len = ext_page_req32->len;
639		ext_page_req->ioc_status = ext_page_req32->ioc_status;
640		break;
641	case MPTIO_RAID_ACTION32:
642		raid_act = &raid_act_swab;
643		raid_act->action = raid_act32->action;
644		raid_act->volume_bus = raid_act32->volume_bus;
645		raid_act->volume_id = raid_act32->volume_id;
646		raid_act->phys_disk_num = raid_act32->phys_disk_num;
647		raid_act->action_data_word = raid_act32->action_data_word;
648		raid_act->buf = PTRIN(raid_act32->buf);
649		raid_act->len = raid_act32->len;
650		raid_act->volume_status = raid_act32->volume_status;
651		bcopy(raid_act32->action_data, raid_act->action_data,
652		    sizeof(raid_act->action_data));
653		raid_act->action_status = raid_act32->action_status;
654		raid_act->ioc_status = raid_act32->ioc_status;
655		raid_act->write = raid_act32->write;
656		break;
657	}
658#endif
659
660	switch (cmd) {
661#ifdef __amd64__
662	case MPTIO_READ_CFG_HEADER32:
663#endif
664	case MPTIO_READ_CFG_HEADER:
665		MPT_LOCK(mpt);
666		error = mpt_user_read_cfg_header(mpt, page_req);
667		MPT_UNLOCK(mpt);
668		break;
669#ifdef __amd64__
670	case MPTIO_READ_CFG_PAGE32:
671#endif
672	case MPTIO_READ_CFG_PAGE:
673		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
674		if (error)
675			break;
676		error = copyin(page_req->buf, mpt_page.vaddr,
677		    sizeof(CONFIG_PAGE_HEADER));
678		if (error)
679			break;
680		MPT_LOCK(mpt);
681		error = mpt_user_read_cfg_page(mpt, page_req, &mpt_page);
682		MPT_UNLOCK(mpt);
683		if (error)
684			break;
685		error = copyout(mpt_page.vaddr, page_req->buf, page_req->len);
686		break;
687#ifdef __amd64__
688	case MPTIO_READ_EXT_CFG_HEADER32:
689#endif
690	case MPTIO_READ_EXT_CFG_HEADER:
691		MPT_LOCK(mpt);
692		error = mpt_user_read_extcfg_header(mpt, ext_page_req);
693		MPT_UNLOCK(mpt);
694		break;
695#ifdef __amd64__
696	case MPTIO_READ_EXT_CFG_PAGE32:
697#endif
698	case MPTIO_READ_EXT_CFG_PAGE:
699		error = mpt_alloc_buffer(mpt, &mpt_page, ext_page_req->len);
700		if (error)
701			break;
702		error = copyin(ext_page_req->buf, mpt_page.vaddr,
703		    sizeof(CONFIG_EXTENDED_PAGE_HEADER));
704		if (error)
705			break;
706		MPT_LOCK(mpt);
707		error = mpt_user_read_extcfg_page(mpt, ext_page_req, &mpt_page);
708		MPT_UNLOCK(mpt);
709		if (error)
710			break;
711		error = copyout(mpt_page.vaddr, ext_page_req->buf,
712		    ext_page_req->len);
713		break;
714#ifdef __amd64__
715	case MPTIO_WRITE_CFG_PAGE32:
716#endif
717	case MPTIO_WRITE_CFG_PAGE:
718		error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
719		if (error)
720			break;
721		error = copyin(page_req->buf, mpt_page.vaddr, page_req->len);
722		if (error)
723			break;
724		MPT_LOCK(mpt);
725		error = mpt_user_write_cfg_page(mpt, page_req, &mpt_page);
726		MPT_UNLOCK(mpt);
727		break;
728#ifdef __amd64__
729	case MPTIO_RAID_ACTION32:
730#endif
731	case MPTIO_RAID_ACTION:
732		if (raid_act->buf != NULL) {
733			error = mpt_alloc_buffer(mpt, &mpt_page, raid_act->len);
734			if (error)
735				break;
736			error = copyin(raid_act->buf, mpt_page.vaddr,
737			    raid_act->len);
738			if (error)
739				break;
740		}
741		MPT_LOCK(mpt);
742		error = mpt_user_raid_action(mpt, raid_act, &mpt_page);
743		MPT_UNLOCK(mpt);
744		if (error)
745			break;
746		if (raid_act->buf != NULL)
747			error = copyout(mpt_page.vaddr, raid_act->buf,
748			    raid_act->len);
749		break;
750	default:
751		error = ENOIOCTL;
752		break;
753	}
754
755	mpt_free_buffer(&mpt_page);
756
757	if (error)
758		return (error);
759
760#ifdef __amd64__
761	/* Convert native structs to 32-bit ones. */
762	switch (cmd) {
763	case MPTIO_READ_CFG_HEADER32:
764	case MPTIO_READ_CFG_PAGE32:
765	case MPTIO_WRITE_CFG_PAGE32:
766		page_req32->header = page_req->header;
767		page_req32->page_address = page_req->page_address;
768		page_req32->buf = PTROUT(page_req->buf);
769		page_req32->len = page_req->len;
770		page_req32->ioc_status = page_req->ioc_status;
771		break;
772	case MPTIO_READ_EXT_CFG_HEADER32:
773	case MPTIO_READ_EXT_CFG_PAGE32:
774		ext_page_req32->header = ext_page_req->header;
775		ext_page_req32->page_address = ext_page_req->page_address;
776		ext_page_req32->buf = PTROUT(ext_page_req->buf);
777		ext_page_req32->len = ext_page_req->len;
778		ext_page_req32->ioc_status = ext_page_req->ioc_status;
779		break;
780	case MPTIO_RAID_ACTION32:
781		raid_act32->action = raid_act->action;
782		raid_act32->volume_bus = raid_act->volume_bus;
783		raid_act32->volume_id = raid_act->volume_id;
784		raid_act32->phys_disk_num = raid_act->phys_disk_num;
785		raid_act32->action_data_word = raid_act->action_data_word;
786		raid_act32->buf = PTROUT(raid_act->buf);
787		raid_act32->len = raid_act->len;
788		raid_act32->volume_status = raid_act->volume_status;
789		bcopy(raid_act->action_data, raid_act32->action_data,
790		    sizeof(raid_act->action_data));
791		raid_act32->action_status = raid_act->action_status;
792		raid_act32->ioc_status = raid_act->ioc_status;
793		raid_act32->write = raid_act->write;
794		break;
795	}
796#endif
797
798	return (0);
799}
800