]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/mpt/mpt_user.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / 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
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/conf.h>
38 #include <sys/errno.h>
39 #include <sys/ioccom.h>
40 #include <sys/mpt_ioctl.h>
41
42 #include <dev/mpt/mpt.h>
43
44 struct mpt_user_raid_action_result {
45         uint32_t        volume_status;
46         uint32_t        action_data[4];
47         uint16_t        action_status;
48 };
49
50 struct mpt_page_memory {
51         bus_dma_tag_t   tag;
52         bus_dmamap_t    map;
53         bus_addr_t      paddr;
54         void            *vaddr;
55 };
56
57 static mpt_probe_handler_t      mpt_user_probe;
58 static mpt_attach_handler_t     mpt_user_attach;
59 static mpt_enable_handler_t     mpt_user_enable;
60 static mpt_ready_handler_t      mpt_user_ready;
61 static mpt_event_handler_t      mpt_user_event;
62 static mpt_reset_handler_t      mpt_user_reset;
63 static mpt_detach_handler_t     mpt_user_detach;
64
65 static struct mpt_personality mpt_user_personality = {
66         .name           = "mpt_user",
67         .probe          = mpt_user_probe,
68         .attach         = mpt_user_attach,
69         .enable         = mpt_user_enable,
70         .ready          = mpt_user_ready,
71         .event          = mpt_user_event,
72         .reset          = mpt_user_reset,
73         .detach         = mpt_user_detach,
74 };
75
76 DECLARE_MPT_PERSONALITY(mpt_user, SI_ORDER_SECOND);
77
78 static mpt_reply_handler_t      mpt_user_reply_handler;
79
80 static d_open_t         mpt_open;
81 static d_close_t        mpt_close;
82 static d_ioctl_t        mpt_ioctl;
83
84 static struct cdevsw mpt_cdevsw = {
85         .d_version =    D_VERSION,
86         .d_flags =      0,
87         .d_open =       mpt_open,
88         .d_close =      mpt_close,
89         .d_ioctl =      mpt_ioctl,
90         .d_name =       "mpt",
91 };
92
93 static MALLOC_DEFINE(M_MPTUSER, "mpt_user", "Buffers for mpt(4) ioctls");
94
95 static uint32_t user_handler_id = MPT_HANDLER_ID_NONE;
96
97 static int
98 mpt_user_probe(struct mpt_softc *mpt)
99 {
100
101         /* Attach to every controller. */
102         return (0);
103 }
104
105 static int
106 mpt_user_attach(struct mpt_softc *mpt)
107 {
108         mpt_handler_t handler;
109         int error, unit;
110
111         MPT_LOCK(mpt);
112         handler.reply_handler = mpt_user_reply_handler;
113         error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler,
114                                      &user_handler_id);
115         MPT_UNLOCK(mpt);
116         if (error != 0) {
117                 mpt_prt(mpt, "Unable to register user handler!\n");
118                 return (error);
119         }
120         unit = device_get_unit(mpt->dev);
121         mpt->cdev = make_dev(&mpt_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
122             "mpt%d", unit);
123         if (mpt->cdev == NULL) {
124                 MPT_LOCK(mpt);
125                 mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
126                     user_handler_id);
127                 MPT_UNLOCK(mpt);
128                 return (ENOMEM);
129         }
130         mpt->cdev->si_drv1 = mpt;
131         return (0);
132 }
133
134 static int
135 mpt_user_enable(struct mpt_softc *mpt)
136 {
137
138         return (0);
139 }
140
141 static void
142 mpt_user_ready(struct mpt_softc *mpt)
143 {
144
145 }
146
147 static int
148 mpt_user_event(struct mpt_softc *mpt, request_t *req,
149     MSG_EVENT_NOTIFY_REPLY *msg)
150 {
151
152         /* Someday we may want to let a user daemon listen for events? */
153         return (0);
154 }
155
156 static void
157 mpt_user_reset(struct mpt_softc *mpt, int type)
158 {
159
160 }
161
162 static void
163 mpt_user_detach(struct mpt_softc *mpt)
164 {
165         mpt_handler_t handler;
166
167         /* XXX: do a purge of pending requests? */
168         destroy_dev(mpt->cdev);
169
170         MPT_LOCK(mpt);
171         handler.reply_handler = mpt_user_reply_handler;
172         mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler,
173             user_handler_id);
174         MPT_UNLOCK(mpt);
175 }
176
177 static int
178 mpt_open(struct cdev *dev, int flags, int fmt, struct thread *td)
179 {
180
181         return (0);
182 }
183
184 static int
185 mpt_close(struct cdev *dev, int flags, int fmt, struct thread *td)
186 {
187
188         return (0);
189 }
190
191 static int
192 mpt_alloc_buffer(struct mpt_softc *mpt, struct mpt_page_memory *page_mem,
193     size_t len)
194 {
195         struct mpt_map_info mi;
196         int error;
197
198         page_mem->vaddr = NULL;
199
200         /* Limit requests to 16M. */
201         if (len > 16 * 1024 * 1024)
202                 return (ENOSPC);
203         error = mpt_dma_tag_create(mpt, mpt->parent_dmat, 1, 0,
204             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
205             len, 1, len, 0, &page_mem->tag);
206         if (error)
207                 return (error);
208         error = bus_dmamem_alloc(page_mem->tag, &page_mem->vaddr,
209             BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &page_mem->map);
210         if (error) {
211                 bus_dma_tag_destroy(page_mem->tag);
212                 return (error);
213         }
214         mi.mpt = mpt;
215         error = bus_dmamap_load(page_mem->tag, page_mem->map, page_mem->vaddr,
216             len, mpt_map_rquest, &mi, BUS_DMA_NOWAIT);
217         if (error == 0)
218                 error = mi.error;
219         if (error) {
220                 bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
221                 bus_dma_tag_destroy(page_mem->tag);
222                 page_mem->vaddr = NULL;
223                 return (error);
224         }
225         page_mem->paddr = mi.phys;
226         return (0);
227 }
228
229 static void
230 mpt_free_buffer(struct mpt_page_memory *page_mem)
231 {
232
233         if (page_mem->vaddr == NULL)
234                 return;
235         bus_dmamap_unload(page_mem->tag, page_mem->map);
236         bus_dmamem_free(page_mem->tag, page_mem->vaddr, page_mem->map);
237         bus_dma_tag_destroy(page_mem->tag);
238         page_mem->vaddr = NULL;
239 }
240
241 static int
242 mpt_user_read_cfg_header(struct mpt_softc *mpt,
243     struct mpt_cfg_page_req *page_req)
244 {
245         request_t  *req;
246         cfgparms_t params;
247         MSG_CONFIG *cfgp;
248         int         error;
249
250         req = mpt_get_request(mpt, TRUE);
251         if (req == NULL) {
252                 mpt_prt(mpt, "mpt_user_read_cfg_header: Get request failed!\n");
253                 return (ENOMEM);
254         }
255
256         params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
257         params.PageVersion = 0;
258         params.PageLength = 0;
259         params.PageNumber = page_req->header.PageNumber;
260         params.PageType = page_req->header.PageType;
261         params.PageAddress = le32toh(page_req->page_address);
262         error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
263                                   TRUE, 5000);
264         if (error != 0) {
265                 /*
266                  * Leave the request. Without resetting the chip, it's
267                  * still owned by it and we'll just get into trouble
268                  * freeing it now. Mark it as abandoned so that if it
269                  * shows up later it can be freed.
270                  */
271                 mpt_prt(mpt, "read_cfg_header timed out\n");
272                 return (ETIMEDOUT);
273         }
274
275         page_req->ioc_status = htole16(req->IOCStatus);
276         if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
277                 cfgp = req->req_vbuf;
278                 bcopy(&cfgp->Header, &page_req->header,
279                     sizeof(page_req->header));
280         }
281         mpt_free_request(mpt, req);
282         return (0);
283 }
284
285 static int
286 mpt_user_read_cfg_page(struct mpt_softc *mpt, struct mpt_cfg_page_req *page_req,
287     struct mpt_page_memory *mpt_page)
288 {
289         CONFIG_PAGE_HEADER *hdr;
290         request_t    *req;
291         cfgparms_t    params;
292         int           error;
293
294         req = mpt_get_request(mpt, TRUE);
295         if (req == NULL) {
296                 mpt_prt(mpt, "mpt_user_read_cfg_page: Get request failed!\n");
297                 return (ENOMEM);
298         }
299
300         hdr = mpt_page->vaddr;
301         params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
302         params.PageVersion = hdr->PageVersion;
303         params.PageLength = hdr->PageLength;
304         params.PageNumber = hdr->PageNumber;
305         params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
306         params.PageAddress = le32toh(page_req->page_address);
307         bus_dmamap_sync(mpt_page->tag, mpt_page->map,
308             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
309         error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
310             le32toh(page_req->len), TRUE, 5000);
311         if (error != 0) {
312                 mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n");
313                 return (ETIMEDOUT);
314         }
315
316         page_req->ioc_status = htole16(req->IOCStatus);
317         if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
318                 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
319                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
320         mpt_free_request(mpt, req);
321         return (0);
322 }
323
324 static int
325 mpt_user_read_extcfg_header(struct mpt_softc *mpt,
326     struct mpt_ext_cfg_page_req *ext_page_req)
327 {
328         request_t  *req;
329         cfgparms_t params;
330         MSG_CONFIG_REPLY *cfgp;
331         int         error;
332
333         req = mpt_get_request(mpt, TRUE);
334         if (req == NULL) {
335                 mpt_prt(mpt, "mpt_user_read_extcfg_header: Get request failed!\n");
336                 return (ENOMEM);
337         }
338
339         params.Action = MPI_CONFIG_ACTION_PAGE_HEADER;
340         params.PageVersion = ext_page_req->header.PageVersion;
341         params.PageLength = 0;
342         params.PageNumber = ext_page_req->header.PageNumber;
343         params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
344         params.PageAddress = le32toh(ext_page_req->page_address);
345         params.ExtPageType = ext_page_req->header.ExtPageType;
346         params.ExtPageLength = 0;
347         error = mpt_issue_cfg_req(mpt, req, &params, /*addr*/0, /*len*/0,
348                                   TRUE, 5000);
349         if (error != 0) {
350                 /*
351                  * Leave the request. Without resetting the chip, it's
352                  * still owned by it and we'll just get into trouble
353                  * freeing it now. Mark it as abandoned so that if it
354                  * shows up later it can be freed.
355                  */
356                 mpt_prt(mpt, "mpt_user_read_extcfg_header timed out\n");
357                 return (ETIMEDOUT);
358         }
359
360         ext_page_req->ioc_status = htole16(req->IOCStatus);
361         if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) {
362                 cfgp = req->req_vbuf;
363                 ext_page_req->header.PageVersion = cfgp->Header.PageVersion;
364                 ext_page_req->header.PageNumber = cfgp->Header.PageNumber;
365                 ext_page_req->header.PageType = cfgp->Header.PageType;
366                 ext_page_req->header.ExtPageLength = cfgp->ExtPageLength;
367                 ext_page_req->header.ExtPageType = cfgp->ExtPageType;
368         }
369         mpt_free_request(mpt, req);
370         return (0);
371 }
372
373 static int
374 mpt_user_read_extcfg_page(struct mpt_softc *mpt,
375     struct mpt_ext_cfg_page_req *ext_page_req, struct mpt_page_memory *mpt_page)
376 {
377         CONFIG_EXTENDED_PAGE_HEADER *hdr;
378         request_t    *req;
379         cfgparms_t    params;
380         int           error;
381
382         req = mpt_get_request(mpt, TRUE);
383         if (req == NULL) {
384                 mpt_prt(mpt, "mpt_user_read_extcfg_page: Get request failed!\n");
385                 return (ENOMEM);
386         }
387
388         hdr = mpt_page->vaddr;
389         params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
390         params.PageVersion = hdr->PageVersion;
391         params.PageLength = 0;
392         params.PageNumber = hdr->PageNumber;
393         params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
394         params.PageAddress = le32toh(ext_page_req->page_address);
395         params.ExtPageType = hdr->ExtPageType;
396         params.ExtPageLength = hdr->ExtPageLength;
397         bus_dmamap_sync(mpt_page->tag, mpt_page->map,
398             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
399         error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
400             le32toh(ext_page_req->len), TRUE, 5000);
401         if (error != 0) {
402                 mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n");
403                 return (ETIMEDOUT);
404         }
405
406         ext_page_req->ioc_status = htole16(req->IOCStatus);
407         if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS)
408                 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
409                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
410         mpt_free_request(mpt, req);
411         return (0);
412 }
413
414 static int
415 mpt_user_write_cfg_page(struct mpt_softc *mpt,
416     struct mpt_cfg_page_req *page_req, struct mpt_page_memory *mpt_page)
417 {
418         CONFIG_PAGE_HEADER *hdr;
419         request_t    *req;
420         cfgparms_t    params;
421         u_int         hdr_attr;
422         int           error;
423
424         hdr = mpt_page->vaddr;
425         hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK;
426         if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE &&
427             hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) {
428                 mpt_prt(mpt, "page type 0x%x not changeable\n",
429                         hdr->PageType & MPI_CONFIG_PAGETYPE_MASK);
430                 return (EINVAL);
431         }
432
433 #if     0
434         /*
435          * We shouldn't mask off other bits here.
436          */
437         hdr->PageType &= ~MPI_CONFIG_PAGETYPE_MASK;
438 #endif
439
440         req = mpt_get_request(mpt, TRUE);
441         if (req == NULL)
442                 return (ENOMEM);
443
444         bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_PREREAD |
445             BUS_DMASYNC_PREWRITE);
446
447         /*
448          * There isn't any point in restoring stripped out attributes
449          * if you then mask them going down to issue the request.
450          */
451
452         params.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
453         params.PageVersion = hdr->PageVersion;
454         params.PageLength = hdr->PageLength;
455         params.PageNumber = hdr->PageNumber;
456         params.PageAddress = le32toh(page_req->page_address);
457 #if     0
458         /* Restore stripped out attributes */
459         hdr->PageType |= hdr_attr;
460         params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK;
461 #else
462         params.PageType = hdr->PageType;
463 #endif
464         error = mpt_issue_cfg_req(mpt, req, &params, mpt_page->paddr,
465             le32toh(page_req->len), TRUE, 5000);
466         if (error != 0) {
467                 mpt_prt(mpt, "mpt_write_cfg_page timed out\n");
468                 return (ETIMEDOUT);
469         }
470
471         page_req->ioc_status = htole16(req->IOCStatus);
472         bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_POSTREAD |
473             BUS_DMASYNC_POSTWRITE);
474         mpt_free_request(mpt, req);
475         return (0);
476 }
477
478 static int
479 mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req,
480     uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame)
481 {
482         MSG_RAID_ACTION_REPLY *reply;
483         struct mpt_user_raid_action_result *res;
484
485         if (req == NULL)
486                 return (TRUE);
487
488         if (reply_frame != NULL) {
489                 reply = (MSG_RAID_ACTION_REPLY *)reply_frame;
490                 req->IOCStatus = le16toh(reply->IOCStatus);
491                 res = (struct mpt_user_raid_action_result *)
492                     (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
493                 res->action_status = reply->ActionStatus;
494                 res->volume_status = reply->VolumeStatus;
495                 bcopy(&reply->ActionData, res->action_data,
496                     sizeof(res->action_data));
497         }
498
499         req->state &= ~REQ_STATE_QUEUED;
500         req->state |= REQ_STATE_DONE;
501         TAILQ_REMOVE(&mpt->request_pending_list, req, links);
502
503         if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) {
504                 wakeup(req);
505         } else if ((req->state & REQ_STATE_TIMEDOUT) != 0) {
506                 /*
507                  * Whew- we can free this request (late completion)
508                  */
509                 mpt_free_request(mpt, req);
510         }
511
512         return (TRUE);
513 }
514
515 /*
516  * We use the first part of the request buffer after the request frame
517  * to hold the action data and action status from the RAID reply.  The
518  * rest of the request buffer is used to hold the buffer for the
519  * action SGE.
520  */
521 static int
522 mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act,
523         struct mpt_page_memory *mpt_page)
524 {
525         request_t *req;
526         struct mpt_user_raid_action_result *res;
527         MSG_RAID_ACTION_REQUEST *rap;
528         SGE_SIMPLE32 *se;
529         int error;
530
531         req = mpt_get_request(mpt, TRUE);
532         if (req == NULL)
533                 return (ENOMEM);
534         rap = req->req_vbuf;
535         memset(rap, 0, sizeof *rap);
536         rap->Action = raid_act->action;
537         rap->ActionDataWord = raid_act->action_data_word;
538         rap->Function = MPI_FUNCTION_RAID_ACTION;
539         rap->VolumeID = raid_act->volume_id;
540         rap->VolumeBus = raid_act->volume_bus;
541         rap->PhysDiskNum = raid_act->phys_disk_num;
542         se = (SGE_SIMPLE32 *)&rap->ActionDataSGE;
543         if (mpt_page->vaddr != NULL && raid_act->len != 0) {
544                 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
545                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
546                 se->Address = htole32(mpt_page->paddr);
547                 MPI_pSGE_SET_LENGTH(se, le32toh(raid_act->len));
548                 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
549                     MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
550                     MPI_SGE_FLAGS_END_OF_LIST |
551                     (raid_act->write ? MPI_SGE_FLAGS_HOST_TO_IOC :
552                     MPI_SGE_FLAGS_IOC_TO_HOST)));
553         }
554         se->FlagsLength = htole32(se->FlagsLength);
555         rap->MsgContext = htole32(req->index | user_handler_id);
556
557         mpt_check_doorbell(mpt);
558         mpt_send_cmd(mpt, req);
559
560         error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, TRUE,
561             2000);
562         if (error != 0) {
563                 /*
564                  * Leave request so it can be cleaned up later.
565                  */
566                 mpt_prt(mpt, "mpt_user_raid_action timed out\n");
567                 return (error);
568         }
569
570         raid_act->ioc_status = htole16(req->IOCStatus);
571         if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) {
572                 mpt_free_request(mpt, req);
573                 return (0);
574         }
575         
576         res = (struct mpt_user_raid_action_result *)
577             (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt));
578         raid_act->volume_status = res->volume_status;
579         raid_act->action_status = res->action_status;
580         bcopy(res->action_data, raid_act->action_data,
581             sizeof(res->action_data));
582         if (mpt_page->vaddr != NULL)
583                 bus_dmamap_sync(mpt_page->tag, mpt_page->map,
584                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
585         mpt_free_request(mpt, req);
586         return (0);
587 }
588
589 #ifdef __amd64__
590 #define PTRIN(p)                ((void *)(uintptr_t)(p))
591 #define PTROUT(v)               ((u_int32_t)(uintptr_t)(v))
592 #endif
593
594 static int
595 mpt_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
596 {
597         struct mpt_softc *mpt;
598         struct mpt_cfg_page_req *page_req;
599         struct mpt_ext_cfg_page_req *ext_page_req;
600         struct mpt_raid_action *raid_act;
601         struct mpt_page_memory mpt_page;
602 #ifdef __amd64__
603         struct mpt_cfg_page_req32 *page_req32;
604         struct mpt_cfg_page_req page_req_swab;
605         struct mpt_ext_cfg_page_req32 *ext_page_req32;
606         struct mpt_ext_cfg_page_req ext_page_req_swab;
607         struct mpt_raid_action32 *raid_act32;
608         struct mpt_raid_action raid_act_swab;
609 #endif
610         int error;
611
612         mpt = dev->si_drv1;
613         page_req = (void *)arg;
614         ext_page_req = (void *)arg;
615         raid_act = (void *)arg;
616         mpt_page.vaddr = NULL;
617
618 #ifdef __amd64__
619         /* Convert 32-bit structs to native ones. */
620         page_req32 = (void *)arg;
621         ext_page_req32 = (void *)arg;
622         raid_act32 = (void *)arg;
623         switch (cmd) {
624         case MPTIO_READ_CFG_HEADER32:
625         case MPTIO_READ_CFG_PAGE32:
626         case MPTIO_WRITE_CFG_PAGE32:
627                 page_req = &page_req_swab;
628                 page_req->header = page_req32->header;
629                 page_req->page_address = page_req32->page_address;
630                 page_req->buf = PTRIN(page_req32->buf);
631                 page_req->len = page_req32->len;
632                 page_req->ioc_status = page_req32->ioc_status;
633                 break;
634         case MPTIO_READ_EXT_CFG_HEADER32:
635         case MPTIO_READ_EXT_CFG_PAGE32:
636                 ext_page_req = &ext_page_req_swab;
637                 ext_page_req->header = ext_page_req32->header;
638                 ext_page_req->page_address = ext_page_req32->page_address;
639                 ext_page_req->buf = PTRIN(ext_page_req32->buf);
640                 ext_page_req->len = ext_page_req32->len;
641                 ext_page_req->ioc_status = ext_page_req32->ioc_status;
642                 break;
643         case MPTIO_RAID_ACTION32:
644                 raid_act = &raid_act_swab;
645                 raid_act->action = raid_act32->action;
646                 raid_act->volume_bus = raid_act32->volume_bus;
647                 raid_act->volume_id = raid_act32->volume_id;
648                 raid_act->phys_disk_num = raid_act32->phys_disk_num;
649                 raid_act->action_data_word = raid_act32->action_data_word;
650                 raid_act->buf = PTRIN(raid_act32->buf);
651                 raid_act->len = raid_act32->len;
652                 raid_act->volume_status = raid_act32->volume_status;
653                 bcopy(raid_act32->action_data, raid_act->action_data,
654                     sizeof(raid_act->action_data));
655                 raid_act->action_status = raid_act32->action_status;
656                 raid_act->ioc_status = raid_act32->ioc_status;
657                 raid_act->write = raid_act32->write;
658                 break;
659         }
660 #endif
661
662         switch (cmd) {
663 #ifdef __amd64__
664         case MPTIO_READ_CFG_HEADER32:
665 #endif
666         case MPTIO_READ_CFG_HEADER:
667                 MPT_LOCK(mpt);
668                 error = mpt_user_read_cfg_header(mpt, page_req);
669                 MPT_UNLOCK(mpt);
670                 break;
671 #ifdef __amd64__
672         case MPTIO_READ_CFG_PAGE32:
673 #endif
674         case MPTIO_READ_CFG_PAGE:
675                 error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
676                 if (error)
677                         break;
678                 error = copyin(page_req->buf, mpt_page.vaddr,
679                     sizeof(CONFIG_PAGE_HEADER));
680                 if (error)
681                         break;
682                 MPT_LOCK(mpt);
683                 error = mpt_user_read_cfg_page(mpt, page_req, &mpt_page);
684                 MPT_UNLOCK(mpt);
685                 if (error)
686                         break;
687                 error = copyout(mpt_page.vaddr, page_req->buf, page_req->len);
688                 break;
689 #ifdef __amd64__
690         case MPTIO_READ_EXT_CFG_HEADER32:
691 #endif
692         case MPTIO_READ_EXT_CFG_HEADER:
693                 MPT_LOCK(mpt);
694                 error = mpt_user_read_extcfg_header(mpt, ext_page_req);
695                 MPT_UNLOCK(mpt);
696                 break;
697 #ifdef __amd64__
698         case MPTIO_READ_EXT_CFG_PAGE32:
699 #endif
700         case MPTIO_READ_EXT_CFG_PAGE:
701                 error = mpt_alloc_buffer(mpt, &mpt_page, ext_page_req->len);
702                 if (error)
703                         break;
704                 error = copyin(ext_page_req->buf, mpt_page.vaddr,
705                     sizeof(CONFIG_EXTENDED_PAGE_HEADER));
706                 if (error)
707                         break;
708                 MPT_LOCK(mpt);
709                 error = mpt_user_read_extcfg_page(mpt, ext_page_req, &mpt_page);
710                 MPT_UNLOCK(mpt);
711                 if (error)
712                         break;
713                 error = copyout(mpt_page.vaddr, ext_page_req->buf,
714                     ext_page_req->len);
715                 break;
716 #ifdef __amd64__
717         case MPTIO_WRITE_CFG_PAGE32:
718 #endif
719         case MPTIO_WRITE_CFG_PAGE:
720                 error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len);
721                 if (error)
722                         break;
723                 error = copyin(page_req->buf, mpt_page.vaddr, page_req->len);
724                 if (error)
725                         break;
726                 MPT_LOCK(mpt);
727                 error = mpt_user_write_cfg_page(mpt, page_req, &mpt_page);
728                 MPT_UNLOCK(mpt);
729                 break;
730 #ifdef __amd64__
731         case MPTIO_RAID_ACTION32:
732 #endif
733         case MPTIO_RAID_ACTION:
734                 if (raid_act->buf != NULL) {
735                         error = mpt_alloc_buffer(mpt, &mpt_page, raid_act->len);
736                         if (error)
737                                 break;
738                         error = copyin(raid_act->buf, mpt_page.vaddr,
739                             raid_act->len);
740                         if (error)
741                                 break;
742                 }
743                 MPT_LOCK(mpt);
744                 error = mpt_user_raid_action(mpt, raid_act, &mpt_page);
745                 MPT_UNLOCK(mpt);
746                 if (error)
747                         break;
748                 if (raid_act->buf != NULL)
749                         error = copyout(mpt_page.vaddr, raid_act->buf,
750                             raid_act->len);
751                 break;
752         default:
753                 error = ENOIOCTL;
754                 break;
755         }
756
757         mpt_free_buffer(&mpt_page);
758
759         if (error)
760                 return (error);
761
762 #ifdef __amd64__
763         /* Convert native structs to 32-bit ones. */
764         switch (cmd) {
765         case MPTIO_READ_CFG_HEADER32:
766         case MPTIO_READ_CFG_PAGE32:
767         case MPTIO_WRITE_CFG_PAGE32:
768                 page_req32->header = page_req->header;
769                 page_req32->page_address = page_req->page_address;
770                 page_req32->buf = PTROUT(page_req->buf);
771                 page_req32->len = page_req->len;
772                 page_req32->ioc_status = page_req->ioc_status;
773                 break;
774         case MPTIO_READ_EXT_CFG_HEADER32:
775         case MPTIO_READ_EXT_CFG_PAGE32:         
776                 ext_page_req32->header = ext_page_req->header;
777                 ext_page_req32->page_address = ext_page_req->page_address;
778                 ext_page_req32->buf = PTROUT(ext_page_req->buf);
779                 ext_page_req32->len = ext_page_req->len;
780                 ext_page_req32->ioc_status = ext_page_req->ioc_status;
781                 break;
782         case MPTIO_RAID_ACTION32:
783                 raid_act32->action = raid_act->action;
784                 raid_act32->volume_bus = raid_act->volume_bus;
785                 raid_act32->volume_id = raid_act->volume_id;
786                 raid_act32->phys_disk_num = raid_act->phys_disk_num;
787                 raid_act32->action_data_word = raid_act->action_data_word;
788                 raid_act32->buf = PTROUT(raid_act->buf);
789                 raid_act32->len = raid_act->len;
790                 raid_act32->volume_status = raid_act->volume_status;
791                 bcopy(raid_act->action_data, raid_act32->action_data,
792                     sizeof(raid_act->action_data));
793                 raid_act32->action_status = raid_act->action_status;
794                 raid_act32->ioc_status = raid_act->ioc_status;
795                 raid_act32->write = raid_act->write;
796                 break;
797         }
798 #endif
799
800         return (0);
801 }