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