nrelease - fix/improve livecd
[dragonfly.git] / sys / dev / disk / mpt / mpt_user.c
... / ...
CommitLineData
1/*-
2 * Copyright (c) 2008 Yahoo!, Inc.
3 * All rights reserved.
4 * Written by: John Baldwin <jhb@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of any co-contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * LSI MPT-Fusion Host Adapter FreeBSD userland interface
31 *
32 * $FreeBSD: head/sys/dev/mpt/mpt_user.c 251187 2013-05-31 17:27:44Z delphij $
33 */
34
35#include <sys/param.h>
36#include <sys/conf.h>
37#include <sys/device.h>
38#include <sys/errno.h>
39#include <sys/mpt_ioctl.h>
40
41#include <dev/disk/mpt/mpt.h>
42
43struct mpt_user_raid_action_result {
44 uint32_t volume_status;
45 uint32_t action_data[4];
46 uint16_t action_status;
47};
48
49struct mpt_page_memory {
50 bus_dma_tag_t tag;
51 bus_dmamap_t map;
52 bus_addr_t paddr;
53 void *vaddr;
54};
55
56static mpt_probe_handler_t mpt_user_probe;
57static mpt_attach_handler_t mpt_user_attach;
58static mpt_enable_handler_t mpt_user_enable;
59static mpt_ready_handler_t mpt_user_ready;
60static mpt_event_handler_t mpt_user_event;
61static mpt_reset_handler_t mpt_user_reset;
62static mpt_detach_handler_t mpt_user_detach;
63
64static struct mpt_personality mpt_user_personality = {
65 .name = "mpt_user",
66 .probe = mpt_user_probe,
67 .attach = mpt_user_attach,
68 .enable = mpt_user_enable,
69 .ready = mpt_user_ready,
70 .event = mpt_user_event,
71 .reset = mpt_user_reset,
72 .detach = mpt_user_detach,
73};
74
75DECLARE_MPT_PERSONALITY(mpt_user, SI_ORDER_SECOND);
76
77static mpt_reply_handler_t mpt_user_reply_handler;
78
79static d_open_t mpt_open;
80static d_close_t mpt_close;
81static d_ioctl_t mpt_ioctl;
82
83static struct dev_ops mpt_ops = {
84 { "mpt", 0, D_MPSAFE },
85 .d_open = mpt_open,
86 .d_close = mpt_close,
87 .d_ioctl = mpt_ioctl,
88};
89
90static uint32_t user_handler_id = MPT_HANDLER_ID_NONE;
91
92static int
93mpt_user_probe(struct mpt_softc *mpt)
94{
95
96 /* Attach to every controller. */
97 return (0);
98}
99
100static int
101mpt_user_attach(struct mpt_softc *mpt)
102{
103 mpt_handler_t handler;
104 int error, unit;
105
106 MPT_LOCK(mpt);
107 handler.reply_handler = mpt_user_reply_handler;
108 error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler,
109 &user_handler_id);
110 MPT_UNLOCK(mpt);
111 if (error != 0) {
112 mpt_prt(mpt, "Unable to register user handler!\n");
113 return (error);
114 }
115 unit = device_get_unit(mpt->dev);
116 mpt->cdev = make_dev(&mpt_ops, unit, UID_ROOT, GID_OPERATOR, 0640,
117 "mpt%d", unit);
118 if (mpt->cdev == NULL) {
119 MPT_LOCK(mpt);
120 mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
121 user_handler_id);
122 MPT_UNLOCK(mpt);
123 return (ENOMEM);
124 }
125 mpt->cdev->si_drv1 = mpt;
126 return (0);
127}
128
129static int
130mpt_user_enable(struct mpt_softc *mpt)
131{
132
133 return (0);
134}
135
136static void
137mpt_user_ready(struct mpt_softc *mpt)
138{
139
140}
141
142static int
143mpt_user_event(struct mpt_softc *mpt, request_t *req,
144 MSG_EVENT_NOTIFY_REPLY *msg)
145{
146
147 /* Someday we may want to let a user daemon listen for events? */
148 return (0);
149}
150
151static void
152mpt_user_reset(struct mpt_softc *mpt, int type)
153{
154
155}
156
157static void
158mpt_user_detach(struct mpt_softc *mpt)
159{
160 mpt_handler_t handler;
161
162 /* XXX: do a purge of pending requests? */
163 destroy_dev(mpt->cdev);
164
165 MPT_LOCK(mpt);
166 handler.reply_handler = mpt_user_reply_handler;
167 mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
168 user_handler_id);
169 MPT_UNLOCK(mpt);
170}
171
172static int
173mpt_open(struct dev_open_args *ap)
174{
175
176 return (0);
177}
178
179static int
180mpt_close(struct dev_close_args *ap)
181{
182
183 return (0);
184}
185
186static int
187mpt_alloc_buffer(struct mpt_softc *mpt, struct mpt_page_memory *page_mem,
188 size_t len)
189{
190 struct mpt_map_info mi;
191 int error;
192
193 page_mem->vaddr = NULL;
194
195 /* Limit requests to 16M. */
196 if (len > 16 * 1024 * 1024)
197 return (ENOSPC);
198 error = mpt_dma_tag_create(mpt, mpt->parent_dmat, 1, 0,
199 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
200 len, 1, len, 0, &page_mem->tag);
201 if (error)
202 return (error);
203 error = bus_dmamem_alloc(page_mem->tag, &page_mem->vaddr,
204 BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &page_mem->map);
205 if (error) {
206 bus_dma_tag_destroy(page_mem->tag);
207 return (error);
208 }
209 mi.mpt = mpt;
210 error = bus_dmamap_load(page_mem->tag, page_mem->map, page_mem->vaddr,
211 len, mpt_map_rquest, &mi, BUS_DMA_NOWAIT);
212 if (error == 0)
213 error = mi.error;
214 if (error) {
215 bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
216 bus_dma_tag_destroy(page_mem->tag);
217 page_mem->vaddr = NULL;
218 return (error);
219 }
220 page_mem->paddr = mi.phys;
221 return (0);
222}
223
224static void
225mpt_free_buffer(struct mpt_page_memory *page_mem)
226{
227
228 if (page_mem->vaddr == NULL)
229 return;
230 bus_dmamap_unload(page_mem->tag, page_mem->map);
231 bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
232 bus_dma_tag_destroy(page_mem->tag);
233 page_mem->vaddr = NULL;
234}
235
236static int
237mpt_user_read_cfg_header(struct mpt_softc *mpt,
238 struct mpt_cfg_page_req *page_req)
239{
240 request_t *req;
241 cfgparms_t params;
242 MSG_CONFIG *cfgp;
243 int error;
244
245 req = mpt_get_request(mpt, TRUE);
246 if (req == NULL) {
247 mpt_prt(mpt, "mpt_user_read_cfg_header: Get request failed!\n");
248 return (ENOMEM);
249 }
250
251 params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
252 params.PageVersion = 0;
253 params.PageLength = 0;
254 params.PageNumber = page_req->header.PageNumber;
255 params.PageType = page_req->header.PageType;
256 params.PageAddress = le32toh(page_req->page_address);
257 error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
258 TRUE, 5000);
259 if (error != 0) {
260 /*
261 * Leave the request. Without resetting the chip, it's
262 * still owned by it and we'll just get into trouble
263 * freeing it now. Mark it as abandoned so that if it
264 * shows up later it can be freed.
265 */
266 mpt_prt(mpt, "read_cfg_header timed out\n");
267 return (ETIMEDOUT);
268 }
269
270 page_req->ioc_status = htole16(req->IOCStatus);
271 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
272 cfgp = req->req_vbuf;
273 bcopy(&cfgp->Header, &page_req->header,
274 sizeof(page_req->header));
275 }
276 mpt_free_request(mpt, req);
277 return (0);
278}
279
280static int
281mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
282 struct mpt_page_memory *mpt_page)
283{
284 CONFIG_PAGE_HEADER *hdr;
285 request_t *req;
286 cfgparms_t params;
287 int error;
288
289 req = mpt_get_request(mpt, TRUE);
290 if (req == NULL) {
291 mpt_prt(mpt, "mpt_user_read_cfg_page: Get request failed!\n");
292 return (ENOMEM);
293 }
294
295 hdr = mpt_page->vaddr;
296 params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
297 params.PageVersion = hdr->PageVersion;
298 params.PageLength = hdr->PageLength;
299 params.PageNumber = hdr->PageNumber;
300 params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
301 params.PageAddress = le32toh(page_req->page_address);
302 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
303 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
304 error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
305 le32toh(page_req->len), TRUE, 5000);
306 if (error != 0) {
307 mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n");
308 return (ETIMEDOUT);
309 }
310
311 page_req->ioc_status = htole16(req->IOCStatus);
312 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
313 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
314 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
315 mpt_free_request(mpt, req);
316 return (0);
317}
318
319static int
320mpt_user_read_extcfg_header(struct mpt_softc *mpt,
321 struct mpt_ext_cfg_page_req *ext_page_req)
322{
323 request_t *req;
324 cfgparms_t params;
325 MSG_CONFIG_REPLY *cfgp;
326 int error;
327
328 req = mpt_get_request(mpt, TRUE);
329 if (req == NULL) {
330 mpt_prt(mpt, "mpt_user_read_extcfg_header: Get request failed!\n");
331 return (ENOMEM);
332 }
333
334 params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
335 params.PageVersion = ext_page_req->header.PageVersion;
336 params.PageLength = 0;
337 params.PageNumber = ext_page_req->header.PageNumber;
338 params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
339 params.PageAddress = le32toh(ext_page_req->page_address);
340 params.ExtPageType = ext_page_req->header.ExtPageType;
341 params.ExtPageLength = 0;
342 error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
343 TRUE, 5000);
344 if (error != 0) {
345 /*
346 * Leave the request. Without resetting the chip, it's
347 * still owned by it and we'll just get into trouble
348 * freeing it now. Mark it as abandoned so that if it
349 * shows up later it can be freed.
350 */
351 mpt_prt(mpt, "mpt_user_read_extcfg_header timed out\n");
352 return (ETIMEDOUT);
353 }
354
355 ext_page_req->ioc_status = htole16(req->IOCStatus);
356 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
357 cfgp = req->req_vbuf;
358 ext_page_req->header.PageVersion = cfgp->Header.PageVersion;
359 ext_page_req->header.PageNumber = cfgp->Header.PageNumber;
360 ext_page_req->header.PageType = cfgp->Header.PageType;
361 ext_page_req->header.ExtPageLength = cfgp->ExtPageLength;
362 ext_page_req->header.ExtPageType = cfgp->ExtPageType;
363 }
364 mpt_free_request(mpt, req);
365 return (0);
366}
367
368static int
369mpt_user_read_extcfg_page(struct mpt_softc *mpt,
370 struct mpt_ext_cfg_page_req *ext_page_req, struct mpt_page_memory *mpt_page)
371{
372 CONFIG_EXTENDED_PAGE_HEADER *hdr;
373 request_t *req;
374 cfgparms_t params;
375 int error;
376
377 req = mpt_get_request(mpt, TRUE);
378 if (req == NULL) {
379 mpt_prt(mpt, "mpt_user_read_extcfg_page: Get request failed!\n");
380 return (ENOMEM);
381 }
382
383 hdr = mpt_page->vaddr;
384 params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
385 params.PageVersion = hdr->PageVersion;
386 params.PageLength = 0;
387 params.PageNumber = hdr->PageNumber;
388 params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
389 params.PageAddress = le32toh(ext_page_req->page_address);
390 params.ExtPageType = hdr->ExtPageType;
391 params.ExtPageLength = hdr->ExtPageLength;
392 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
393 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
394 error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
395 le32toh(ext_page_req->len), TRUE, 5000);
396 if (error != 0) {
397 mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n");
398 return (ETIMEDOUT);
399 }
400
401 ext_page_req->ioc_status = htole16(req->IOCStatus);
402 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
403 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
404 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
405 mpt_free_request(mpt, req);
406 return (0);
407}
408
409static int
410mpt_user_write_cfg_page(struct mpt_softc *mpt,
411 struct mpt_cfg_page_req *page_req, struct mpt_page_memory *mpt_page)
412{
413 CONFIG_PAGE_HEADER *hdr;
414 request_t *req;
415 cfgparms_t params;
416 u_int hdr_attr;
417 int error;
418
419 hdr = mpt_page->vaddr;
420 hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
421 if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
422 hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
423 mpt_prt(mpt, "page type 0x%x not changeable\n",
424 hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
425 return (EINVAL);
426 }
427
428#if 0
429 /*
430 * We shouldn't mask off other bits here.
431 */
432 hdr->PageType &= ~MPI_CONFIG_PAGETYPE_MASK;
433#endif
434
435 req = mpt_get_request(mpt, TRUE);
436 if (req == NULL)
437 return (ENOMEM);
438
439 bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_PREREAD |
440 BUS_DMASYNC_PREWRITE);
441
442 /*
443 * There isn't any point in restoring stripped out attributes
444 * if you then mask them going down to issue the request.
445 */
446
447 params.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
448 params.PageVersion = hdr->PageVersion;
449 params.PageLength = hdr->PageLength;
450 params.PageNumber = hdr->PageNumber;
451 params.PageAddress = le32toh(page_req->page_address);
452#if 0
453 /* Restore stripped out attributes */
454 hdr->PageType |= hdr_attr;
455 params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
456#else
457 params.PageType = hdr->PageType;
458#endif
459 error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
460 le32toh(page_req->len), TRUE, 5000);
461 if (error != 0) {
462 mpt_prt(mpt, "mpt_write_cfg_page timed out\n");
463 return (ETIMEDOUT);
464 }
465
466 page_req->ioc_status = htole16(req->IOCStatus);
467 bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_POSTREAD |
468 BUS_DMASYNC_POSTWRITE);
469 mpt_free_request(mpt, req);
470 return (0);
471}
472
473static int
474mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req,
475 uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame)
476{
477 MSG_RAID_ACTION_REPLY *reply;
478 struct mpt_user_raid_action_result *res;
479
480 if (req == NULL)
481 return (TRUE);
482
483 if (reply_frame != NULL) {
484 reply = (MSG_RAID_ACTION_REPLY *)reply_frame;
485 req->IOCStatus = le16toh(reply->IOCStatus);
486 res = (struct mpt_user_raid_action_result *)
487 (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
488 res->action_status = reply->ActionStatus;
489 res->volume_status = reply->VolumeStatus;
490 bcopy(&reply->ActionData, res->action_data,
491 sizeof(res->action_data));
492 }
493
494 req->state &= ~REQ_STATE_QUEUED;
495 req->state |= REQ_STATE_DONE;
496 TAILQ_REMOVE(&mpt->request_pending_list, req, links);
497
498 if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) {
499 wakeup(req);
500 } else if ((req->state & REQ_STATE_TIMEDOUT) != 0) {
501 /*
502 * Whew- we can free this request (late completion)
503 */
504 mpt_free_request(mpt, req);
505 }
506
507 return (TRUE);
508}
509
510/*
511 * We use the first part of the request buffer after the request frame
512 * to hold the action data and action status from the RAID reply. The
513 * rest of the request buffer is used to hold the buffer for the
514 * action SGE.
515 */
516static int
517mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
518 struct mpt_page_memory *mpt_page)
519{
520 request_t *req;
521 struct mpt_user_raid_action_result *res;
522 MSG_RAID_ACTION_REQUEST *rap;
523 SGE_SIMPLE32 *se;
524 int error;
525
526 req = mpt_get_request(mpt, TRUE);
527 if (req == NULL)
528 return (ENOMEM);
529 rap = req->req_vbuf;
530 memset(rap, 0, sizeof *rap);
531 rap->Action = raid_act->action;
532 rap->ActionDataWord = raid_act->action_data_word;
533 rap->Function = MPI_FUNCTION_RAID_ACTION;
534 rap->VolumeID = raid_act->volume_id;
535 rap->VolumeBus = raid_act->volume_bus;
536 rap->PhysDiskNum = raid_act->phys_disk_num;
537 se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
538 if (mpt_page->vaddr != NULL && raid_act->len != 0) {
539 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
540 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
541 se->Address = htole32(mpt_page->paddr);
542 MPI_pSGE_SET_LENGTH(se, le32toh(raid_act->len));
543 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
544 MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
545 MPI_SGE_FLAGS_END_OF_LIST |
546 (raid_act->write ? MPI_SGE_FLAGS_HOST_TO_IOC :
547 MPI_SGE_FLAGS_IOC_TO_HOST)));
548 }
549 se->FlagsLength = htole32(se->FlagsLength);
550 rap->MsgContext = htole32(req->index | user_handler_id);
551
552 mpt_check_doorbell(mpt);
553 mpt_send_cmd(mpt, req);
554
555 error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, TRUE,
556 2000);
557 if (error != 0) {
558 /*
559 * Leave request so it can be cleaned up later.
560 */
561 mpt_prt(mpt, "mpt_user_raid_action timed out\n");
562 return (error);
563 }
564
565 raid_act->ioc_status = htole16(req->IOCStatus);
566 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
567 mpt_free_request(mpt, req);
568 return (0);
569 }
570
571 res = (struct mpt_user_raid_action_result *)
572 (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
573 raid_act->volume_status = res->volume_status;
574 raid_act->action_status = res->action_status;
575 bcopy(res->action_data, raid_act->action_data,
576 sizeof(res->action_data));
577 if (mpt_page->vaddr != NULL)
578 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
579 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
580 mpt_free_request(mpt, req);
581 return (0);
582}
583
584#ifdef __x86_64__
585#define PTRIN(p) ((void *)(uintptr_t)(p))
586#define PTROUT(v) ((u_int32_t)(uintptr_t)(v))
587#endif
588
589static int
590mpt_ioctl(struct dev_ioctl_args *ap)
591{
592 cdev_t dev = ap->a_head.a_dev;
593 u_long cmd = ap->a_cmd;
594 caddr_t arg = ap->a_data;
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 __x86_64__
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 __x86_64__
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 __x86_64__
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 __x86_64__
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 __x86_64__
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 __x86_64__
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 __x86_64__
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 __x86_64__
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 __x86_64__
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}