Merge branch 'vendor/DHCPCD'
[dragonfly.git] / sys / dev / disk / mpt / mpt_user.c
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
43 struct mpt_user_raid_action_result {
44         uint32_t        volume_status;
45         uint32_t        action_data[4];
46         uint16_t        action_status;
47 };
48
49 struct mpt_page_memory {
50         bus_dma_tag_t   tag;
51         bus_dmamap_t    map;
52         bus_addr_t      paddr;
53         void            *vaddr;
54 };
55
56 static mpt_probe_handler_t      mpt_user_probe;
57 static mpt_attach_handler_t     mpt_user_attach;
58 static mpt_enable_handler_t     mpt_user_enable;
59 static mpt_ready_handler_t      mpt_user_ready;
60 static mpt_event_handler_t      mpt_user_event;
61 static mpt_reset_handler_t      mpt_user_reset;
62 static mpt_detach_handler_t     mpt_user_detach;
63
64 static 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
75 DECLARE_MPT_PERSONALITY(mpt_user, SI_ORDER_SECOND);
76
77 static mpt_reply_handler_t      mpt_user_reply_handler;
78
79 static d_open_t         mpt_open;
80 static d_close_t        mpt_close;
81 static d_ioctl_t        mpt_ioctl;
82
83 static 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
90 static uint32_t user_handler_id = MPT_HANDLER_ID_NONE;
91
92 static int
93 mpt_user_probe(struct mpt_softc *mpt)
94 {
95
96         /* Attach to every controller. */
97         return (0);
98 }
99
100 static int
101 mpt_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
129 static int
130 mpt_user_enable(struct mpt_softc *mpt)
131 {
132
133         return (0);
134 }
135
136 static void
137 mpt_user_ready(struct mpt_softc *mpt)
138 {
139
140 }
141
142 static int
143 mpt_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
151 static void
152 mpt_user_reset(struct mpt_softc *mpt, int type)
153 {
154
155 }
156
157 static void
158 mpt_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
172 static int
173 mpt_open(struct dev_open_args *ap)
174 {
175
176         return (0);
177 }
178
179 static int
180 mpt_close(struct dev_close_args *ap)
181 {
182
183         return (0);
184 }
185
186 static int
187 mpt_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
224 static void
225 mpt_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
236 static int
237 mpt_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
280 static int
281 mpt_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
319 static int
320 mpt_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
368 static int
369 mpt_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
409 static int
410 mpt_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
473 static int
474 mpt_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  */
516 static int
517 mpt_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
589 static int
590 mpt_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 }