]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - sys/dev/mps/mps_user.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / sys / dev / mps / mps_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 MPS-Fusion Host Adapter FreeBSD userland interface
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include "opt_compat.h"
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/selinfo.h>
43 #include <sys/module.h>
44 #include <sys/bus.h>
45 #include <sys/conf.h>
46 #include <sys/bio.h>
47 #include <sys/malloc.h>
48 #include <sys/uio.h>
49 #include <sys/sysctl.h>
50 #include <sys/ioccom.h>
51 #include <sys/endian.h>
52 #include <sys/proc.h>
53 #include <sys/sysent.h>
54
55 #include <machine/bus.h>
56 #include <machine/resource.h>
57 #include <sys/rman.h>
58
59 #include <cam/scsi/scsi_all.h>
60
61 #include <dev/mps/mpi/mpi2_type.h>
62 #include <dev/mps/mpi/mpi2.h>
63 #include <dev/mps/mpi/mpi2_ioc.h>
64 #include <dev/mps/mpi/mpi2_cnfg.h>
65 #include <dev/mps/mpsvar.h>
66 #include <dev/mps/mps_table.h>
67 #include <dev/mps/mps_ioctl.h>
68
69 static d_open_t         mps_open;
70 static d_close_t        mps_close;
71 static d_ioctl_t        mps_ioctl_devsw;
72
73 static struct cdevsw mps_cdevsw = {
74         .d_version =    D_VERSION,
75         .d_flags =      0,
76         .d_open =       mps_open,
77         .d_close =      mps_close,
78         .d_ioctl =      mps_ioctl_devsw,
79         .d_name =       "mps",
80 };
81
82 typedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *);
83 static mps_user_f       mpi_pre_ioc_facts;
84 static mps_user_f       mpi_pre_port_facts;
85 static mps_user_f       mpi_pre_fw_download;
86 static mps_user_f       mpi_pre_fw_upload;
87 static mps_user_f       mpi_pre_sata_passthrough;
88 static mps_user_f       mpi_pre_smp_passthrough;
89 static mps_user_f       mpi_pre_config;
90 static mps_user_f       mpi_pre_sas_io_unit_control;
91
92 static int mps_user_read_cfg_header(struct mps_softc *,
93                                     struct mps_cfg_page_req *);
94 static int mps_user_read_cfg_page(struct mps_softc *,
95                                   struct mps_cfg_page_req *, void *);
96 static int mps_user_read_extcfg_header(struct mps_softc *,
97                                      struct mps_ext_cfg_page_req *);
98 static int mps_user_read_extcfg_page(struct mps_softc *,
99                                      struct mps_ext_cfg_page_req *, void *);
100 static int mps_user_write_cfg_page(struct mps_softc *,
101                                    struct mps_cfg_page_req *, void *);
102 static int mps_user_setup_request(struct mps_command *,
103                                   struct mps_usr_command *);
104 static int mps_user_command(struct mps_softc *, struct mps_usr_command *);
105
106 static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls");
107
108 int
109 mps_attach_user(struct mps_softc *sc)
110 {
111         int unit;
112
113         unit = device_get_unit(sc->mps_dev);
114         sc->mps_cdev = make_dev(&mps_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
115             "mps%d", unit);
116         if (sc->mps_cdev == NULL) {
117                 return (ENOMEM);
118         }
119         sc->mps_cdev->si_drv1 = sc;
120         return (0);
121 }
122
123 void
124 mps_detach_user(struct mps_softc *sc)
125 {
126
127         /* XXX: do a purge of pending requests? */
128         destroy_dev(sc->mps_cdev);
129
130 }
131
132 static int
133 mps_open(struct cdev *dev, int flags, int fmt, struct thread *td)
134 {
135
136         return (0);
137 }
138
139 static int
140 mps_close(struct cdev *dev, int flags, int fmt, struct thread *td)
141 {
142
143         return (0);
144 }
145
146 static int
147 mps_user_read_cfg_header(struct mps_softc *sc,
148     struct mps_cfg_page_req *page_req)
149 {
150         MPI2_CONFIG_PAGE_HEADER *hdr;
151         struct mps_config_params params;
152         int         error;
153
154         hdr = &params.hdr.Struct;
155         params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
156         params.page_address = le32toh(page_req->page_address);
157         hdr->PageVersion = 0;
158         hdr->PageLength = 0;
159         hdr->PageNumber = page_req->header.PageNumber;
160         hdr->PageType = page_req->header.PageType;
161         params.buffer = NULL;
162         params.length = 0;
163         params.callback = NULL;
164
165         if ((error = mps_read_config_page(sc, &params)) != 0) {
166                 /*
167                  * Leave the request. Without resetting the chip, it's
168                  * still owned by it and we'll just get into trouble
169                  * freeing it now. Mark it as abandoned so that if it
170                  * shows up later it can be freed.
171                  */
172                 mps_printf(sc, "read_cfg_header timed out\n");
173                 return (ETIMEDOUT);
174         }
175
176         page_req->ioc_status = htole16(params.status);
177         if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
178             MPI2_IOCSTATUS_SUCCESS) {
179                 bcopy(hdr, &page_req->header, sizeof(page_req->header));
180         }
181
182         return (0);
183 }
184
185 static int
186 mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req,
187     void *buf)
188 {
189         MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
190         struct mps_config_params params;
191         int           error;
192
193         reqhdr = buf;
194         hdr = &params.hdr.Struct;
195         hdr->PageVersion = reqhdr->PageVersion;
196         hdr->PageLength = reqhdr->PageLength;
197         hdr->PageNumber = reqhdr->PageNumber;
198         hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK;
199         params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
200         params.page_address = le32toh(page_req->page_address);
201         params.buffer = buf;
202         params.length = le32toh(page_req->len);
203         params.callback = NULL;
204
205         if ((error = mps_read_config_page(sc, &params)) != 0) {
206                 mps_printf(sc, "mps_user_read_cfg_page timed out\n");
207                 return (ETIMEDOUT);
208         }
209
210         page_req->ioc_status = htole16(params.status);
211         return (0);
212 }
213
214 static int
215 mps_user_read_extcfg_header(struct mps_softc *sc,
216     struct mps_ext_cfg_page_req *ext_page_req)
217 {
218         MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
219         struct mps_config_params params;
220         int         error;
221
222         hdr = &params.hdr.Ext;
223         params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
224         hdr->PageVersion = ext_page_req->header.PageVersion;
225         hdr->ExtPageLength = 0;
226         hdr->PageNumber = ext_page_req->header.PageNumber;
227         hdr->ExtPageType = ext_page_req->header.ExtPageType;
228         params.page_address = le32toh(ext_page_req->page_address);
229         if ((error = mps_read_config_page(sc, &params)) != 0) {
230                 /*
231                  * Leave the request. Without resetting the chip, it's
232                  * still owned by it and we'll just get into trouble
233                  * freeing it now. Mark it as abandoned so that if it
234                  * shows up later it can be freed.
235                  */
236                 mps_printf(sc, "mps_user_read_extcfg_header timed out\n");
237                 return (ETIMEDOUT);
238         }
239
240         ext_page_req->ioc_status = htole16(params.status);
241         if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
242             MPI2_IOCSTATUS_SUCCESS) {
243                 ext_page_req->header.PageVersion = hdr->PageVersion;
244                 ext_page_req->header.PageNumber = hdr->PageNumber;
245                 ext_page_req->header.PageType = hdr->PageType;
246                 ext_page_req->header.ExtPageLength = hdr->ExtPageLength;
247                 ext_page_req->header.ExtPageType = hdr->ExtPageType;
248         }
249
250         return (0);
251 }
252
253 static int
254 mps_user_read_extcfg_page(struct mps_softc *sc,
255     struct mps_ext_cfg_page_req *ext_page_req, void *buf)
256 {
257         MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr;
258         struct mps_config_params params;
259         int error;
260
261         reqhdr = buf;
262         hdr = &params.hdr.Ext;
263         params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
264         params.page_address = le32toh(ext_page_req->page_address);
265         hdr->PageVersion = reqhdr->PageVersion;
266         hdr->PageNumber = reqhdr->PageNumber;
267         hdr->ExtPageType = reqhdr->ExtPageType;
268         hdr->ExtPageLength = reqhdr->ExtPageLength;
269         params.buffer = buf;
270         params.length = le32toh(ext_page_req->len);
271         params.callback = NULL;
272
273         if ((error = mps_read_config_page(sc, &params)) != 0) {
274                 mps_printf(sc, "mps_user_read_extcfg_page timed out\n");
275                 return (ETIMEDOUT);
276         }
277
278         ext_page_req->ioc_status = htole16(params.status);
279         return (0);
280 }
281
282 static int
283 mps_user_write_cfg_page(struct mps_softc *sc,
284     struct mps_cfg_page_req *page_req, void *buf)
285 {
286         MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
287         struct mps_config_params params;
288         u_int         hdr_attr;
289         int           error;
290
291         reqhdr = buf;
292         hdr = &params.hdr.Struct;
293         hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK;
294         if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE &&
295             hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) {
296                 mps_printf(sc, "page type 0x%x not changeable\n",
297                         reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK);
298                 return (EINVAL);
299         }
300
301         /*
302          * There isn't any point in restoring stripped out attributes
303          * if you then mask them going down to issue the request.
304          */
305
306         hdr->PageVersion = reqhdr->PageVersion;
307         hdr->PageLength = reqhdr->PageLength;
308         hdr->PageNumber = reqhdr->PageNumber;
309         hdr->PageType = reqhdr->PageType;
310         params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
311         params.page_address = le32toh(page_req->page_address);
312         params.buffer = buf;
313         params.length = le32toh(page_req->len);
314         params.callback = NULL;
315
316         if ((error = mps_write_config_page(sc, &params)) != 0) {
317                 mps_printf(sc, "mps_write_cfg_page timed out\n");
318                 return (ETIMEDOUT);
319         }
320
321         page_req->ioc_status = htole16(params.status);
322         return (0);
323 }
324
325 void
326 mpi_init_sge(struct mps_command *cm, void *req, void *sge)
327 {
328         int off, space;
329
330         space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
331         off = (uintptr_t)sge - (uintptr_t)req;
332
333         KASSERT(off < space, ("bad pointers %p %p, off %d, space %d",
334             req, sge, off, space));
335
336         cm->cm_sge = sge;
337         cm->cm_sglsize = space - off;
338 }
339
340 /*
341  * Prepare the mps_command for an IOC_FACTS request.
342  */
343 static int
344 mpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd)
345 {
346         MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req;
347         MPI2_IOC_FACTS_REPLY *rpl;
348
349         if (cmd->req_len != sizeof *req)
350                 return (EINVAL);
351         if (cmd->rpl_len != sizeof *rpl)
352                 return (EINVAL);
353
354         cm->cm_sge = NULL;
355         cm->cm_sglsize = 0;
356         return (0);
357 }
358
359 /*
360  * Prepare the mps_command for a PORT_FACTS request.
361  */
362 static int
363 mpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd)
364 {
365         MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req;
366         MPI2_PORT_FACTS_REPLY *rpl;
367
368         if (cmd->req_len != sizeof *req)
369                 return (EINVAL);
370         if (cmd->rpl_len != sizeof *rpl)
371                 return (EINVAL);
372
373         cm->cm_sge = NULL;
374         cm->cm_sglsize = 0;
375         return (0);
376 }
377
378 /*
379  * Prepare the mps_command for a FW_DOWNLOAD request.
380  */
381 static int
382 mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd)
383 {
384         MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req;
385         MPI2_FW_DOWNLOAD_REPLY *rpl;
386         MPI2_FW_DOWNLOAD_TCSGE tc;
387         int error;
388
389         /*
390          * This code assumes there is room in the request's SGL for
391          * the TransactionContext plus at least a SGL chain element.
392          */
393         CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
394
395         if (cmd->req_len != sizeof *req)
396                 return (EINVAL);
397         if (cmd->rpl_len != sizeof *rpl)
398                 return (EINVAL);
399
400         if (cmd->len == 0)
401                 return (EINVAL);
402
403         error = copyin(cmd->buf, cm->cm_data, cmd->len);
404         if (error != 0)
405                 return (error);
406
407         mpi_init_sge(cm, req, &req->SGL);
408         bzero(&tc, sizeof tc);
409
410         /*
411          * For now, the F/W image must be provided in a single request.
412          */
413         if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0)
414                 return (EINVAL);
415         if (req->TotalImageSize != cmd->len)
416                 return (EINVAL);
417
418         /*
419          * The value of the first two elements is specified in the
420          * Fusion-MPT Message Passing Interface document.
421          */
422         tc.ContextSize = 0;
423         tc.DetailsLength = 12;
424         tc.ImageOffset = 0;
425         tc.ImageSize = cmd->len;
426
427         cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
428
429         return (mps_push_sge(cm, &tc, sizeof tc, 0));
430 }
431
432 /*
433  * Prepare the mps_command for a FW_UPLOAD request.
434  */
435 static int
436 mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
437 {
438         MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req;
439         MPI2_FW_UPLOAD_REPLY *rpl;
440         MPI2_FW_UPLOAD_TCSGE tc;
441
442         /*
443          * This code assumes there is room in the request's SGL for
444          * the TransactionContext plus at least a SGL chain element.
445          */
446         CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
447
448         if (cmd->req_len != sizeof *req)
449                 return (EINVAL);
450         if (cmd->rpl_len != sizeof *rpl)
451                 return (EINVAL);
452
453         mpi_init_sge(cm, req, &req->SGL);
454         if (cmd->len == 0) {
455                 /* Perhaps just asking what the size of the fw is? */
456                 return (0);
457         }
458
459         bzero(&tc, sizeof tc);
460
461         /*
462          * The value of the first two elements is specified in the
463          * Fusion-MPT Message Passing Interface document.
464          */
465         tc.ContextSize = 0;
466         tc.DetailsLength = 12;
467         /*
468          * XXX Is there any reason to fetch a partial image?  I.e. to
469          * set ImageOffset to something other than 0?
470          */
471         tc.ImageOffset = 0;
472         tc.ImageSize = cmd->len;
473
474         return (mps_push_sge(cm, &tc, sizeof tc, 0));
475 }
476
477 /*
478  * Prepare the mps_command for a SATA_PASSTHROUGH request.
479  */
480 static int
481 mpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
482 {
483         MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
484         MPI2_SATA_PASSTHROUGH_REPLY *rpl;
485
486         if (cmd->req_len != sizeof *req)
487                 return (EINVAL);
488         if (cmd->rpl_len != sizeof *rpl)
489                 return (EINVAL);
490
491         mpi_init_sge(cm, req, &req->SGL);
492         return (0);
493 }
494
495 /*
496  * Prepare the mps_command for a SMP_PASSTHROUGH request.
497  */
498 static int
499 mpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
500 {
501         MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
502         MPI2_SMP_PASSTHROUGH_REPLY *rpl;
503
504         if (cmd->req_len != sizeof *req)
505                 return (EINVAL);
506         if (cmd->rpl_len != sizeof *rpl)
507                 return (EINVAL);
508
509         mpi_init_sge(cm, req, &req->SGL);
510         return (0);
511 }
512
513 /*
514  * Prepare the mps_command for a CONFIG request.
515  */
516 static int
517 mpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd)
518 {
519         MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req;
520         MPI2_CONFIG_REPLY *rpl;
521
522         if (cmd->req_len != sizeof *req)
523                 return (EINVAL);
524         if (cmd->rpl_len != sizeof *rpl)
525                 return (EINVAL);
526
527         mpi_init_sge(cm, req, &req->PageBufferSGE);
528         return (0);
529 }
530
531 /*
532  * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request.
533  */
534 static int
535 mpi_pre_sas_io_unit_control(struct mps_command *cm,
536                              struct mps_usr_command *cmd)
537 {
538
539         cm->cm_sge = NULL;
540         cm->cm_sglsize = 0;
541         return (0);
542 }
543
544 /*
545  * A set of functions to prepare an mps_command for the various
546  * supported requests.
547  */
548 struct mps_user_func {
549         U8              Function;
550         mps_user_f      *f_pre;
551 } mps_user_func_list[] = {
552         { MPI2_FUNCTION_IOC_FACTS,              mpi_pre_ioc_facts },
553         { MPI2_FUNCTION_PORT_FACTS,             mpi_pre_port_facts },
554         { MPI2_FUNCTION_FW_DOWNLOAD,            mpi_pre_fw_download },
555         { MPI2_FUNCTION_FW_UPLOAD,              mpi_pre_fw_upload },
556         { MPI2_FUNCTION_SATA_PASSTHROUGH,       mpi_pre_sata_passthrough },
557         { MPI2_FUNCTION_SMP_PASSTHROUGH,        mpi_pre_smp_passthrough},
558         { MPI2_FUNCTION_CONFIG,                 mpi_pre_config},
559         { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL,    mpi_pre_sas_io_unit_control },
560         { 0xFF,                                 NULL } /* list end */
561 };
562
563 static int
564 mps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd)
565 {
566         MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;   
567         struct mps_user_func *f;
568
569         for (f = mps_user_func_list; f->f_pre != NULL; f++) {
570                 if (hdr->Function == f->Function)
571                         return (f->f_pre(cm, cmd));
572         }
573         return (EINVAL);
574 }       
575
576 static int
577 mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
578 {
579         MPI2_REQUEST_HEADER *hdr;       
580         MPI2_DEFAULT_REPLY *rpl;
581         void *buf = NULL;
582         struct mps_command *cm = NULL;
583         int err = 0;
584         int sz;
585
586         mps_lock(sc);
587         cm = mps_alloc_command(sc);
588
589         if (cm == NULL) {
590                 mps_printf(sc, "mps_user_command: no mps requests\n");
591                 err = ENOMEM;
592                 goto Ret;
593         }
594         mps_unlock(sc);
595
596         hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
597
598         mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d  rpl %p %d\n",
599                     cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len );
600
601         if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) {
602                 err = EINVAL;
603                 goto RetFreeUnlocked;
604         }
605         err = copyin(cmd->req, hdr, cmd->req_len);
606         if (err != 0)
607                 goto RetFreeUnlocked;
608
609         mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X  "
610             "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags );
611
612         err = mps_user_setup_request(cm, cmd);
613         if (err != 0) {
614                 mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
615                     hdr->Function );
616                 goto RetFreeUnlocked;
617         }
618
619         if (cmd->len > 0) {
620                 buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
621                 cm->cm_data = buf;
622                 cm->cm_length = cmd->len;
623         } else {
624                 cm->cm_data = NULL;
625                 cm->cm_length = 0;
626         }
627
628         cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP;
629         cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
630
631         mps_lock(sc);
632         err = mps_map_command(sc, cm);
633
634         if (err != 0 && err != EINPROGRESS) {
635                 mps_printf(sc, "%s: invalid request: error %d\n",
636                     __func__, err);
637                 goto Ret;
638         }
639         msleep(cm, &sc->mps_mtx, 0, "mpsuser", 0);
640
641         rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
642         sz = rpl->MsgLength * 4;
643         
644         if (sz > cmd->rpl_len) {
645                 mps_printf(sc,
646                     "mps_user_command: reply buffer too small %d required %d\n",
647                     cmd->rpl_len, sz );
648                 err = EINVAL;
649                 sz = cmd->rpl_len;
650         }       
651
652         mps_unlock(sc);
653         copyout(rpl, cmd->rpl, sz);
654         if (buf != NULL)
655                 copyout(buf, cmd->buf, cmd->len);
656         mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz );
657
658 RetFreeUnlocked:
659         mps_lock(sc);
660         if (cm != NULL)
661                 mps_free_command(sc, cm);
662 Ret:
663         mps_unlock(sc);
664         if (buf != NULL)
665                 free(buf, M_MPSUSER);
666         return (err);
667 }       
668
669 static int
670 mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag,
671     struct thread *td)
672 {
673         struct mps_softc *sc;
674         struct mps_cfg_page_req *page_req;
675         struct mps_ext_cfg_page_req *ext_page_req;
676         void *mps_page;
677         int error;
678
679         mps_page = NULL;
680         sc = dev->si_drv1;
681         page_req = (void *)arg;
682         ext_page_req = (void *)arg;
683
684         switch (cmd) {
685         case MPSIO_READ_CFG_HEADER:
686                 mps_lock(sc);
687                 error = mps_user_read_cfg_header(sc, page_req);
688                 mps_unlock(sc);
689                 break;
690         case MPSIO_READ_CFG_PAGE:
691                 mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
692                 error = copyin(page_req->buf, mps_page,
693                     sizeof(MPI2_CONFIG_PAGE_HEADER));
694                 if (error)
695                         break;
696                 mps_lock(sc);
697                 error = mps_user_read_cfg_page(sc, page_req, mps_page);
698                 mps_unlock(sc);
699                 if (error)
700                         break;
701                 error = copyout(mps_page, page_req->buf, page_req->len);
702                 break;
703         case MPSIO_READ_EXT_CFG_HEADER:
704                 mps_lock(sc);
705                 error = mps_user_read_extcfg_header(sc, ext_page_req);
706                 mps_unlock(sc);
707                 break;
708         case MPSIO_READ_EXT_CFG_PAGE:
709                 mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
710                 error = copyin(ext_page_req->buf, mps_page,
711                     sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
712                 if (error)
713                         break;
714                 mps_lock(sc);
715                 error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page);
716                 mps_unlock(sc);
717                 if (error)
718                         break;
719                 error = copyout(mps_page, ext_page_req->buf, ext_page_req->len);
720                 break;
721         case MPSIO_WRITE_CFG_PAGE:
722                 mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
723                 error = copyin(page_req->buf, mps_page, page_req->len);
724                 if (error)
725                         break;
726                 mps_lock(sc);
727                 error = mps_user_write_cfg_page(sc, page_req, mps_page);
728                 mps_unlock(sc);
729                 break;
730         case MPSIO_MPS_COMMAND:
731                 error = mps_user_command(sc, (struct mps_usr_command *)arg);
732                 break;
733         default:
734                 error = ENOIOCTL;
735                 break;
736         }
737
738         if (mps_page != NULL)
739                 free(mps_page, M_MPSUSER);
740
741         return (error);
742 }
743
744 #ifdef COMPAT_FREEBSD32
745
746 /* Macros from compat/freebsd32/freebsd32.h */
747 #define PTRIN(v)        (void *)(uintptr_t)(v)
748 #define PTROUT(v)       (uint32_t)(uintptr_t)(v)
749
750 #define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
751 #define PTRIN_CP(src,dst,fld)                           \
752         do { (dst).fld = PTRIN((src).fld); } while (0)
753 #define PTROUT_CP(src,dst,fld) \
754         do { (dst).fld = PTROUT((src).fld); } while (0)
755
756 struct mps_cfg_page_req32 {
757         MPI2_CONFIG_PAGE_HEADER header;
758         uint32_t page_address;
759         uint32_t buf;
760         int     len;    
761         uint16_t ioc_status;
762 };
763
764 struct mps_ext_cfg_page_req32 {
765         MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
766         uint32_t page_address;
767         uint32_t buf;
768         int     len;
769         uint16_t ioc_status;
770 };
771
772 struct mps_raid_action32 {
773         uint8_t action;
774         uint8_t volume_bus;
775         uint8_t volume_id;
776         uint8_t phys_disk_num;
777         uint32_t action_data_word;
778         uint32_t buf;
779         int len;
780         uint32_t volume_status;
781         uint32_t action_data[4];
782         uint16_t action_status;
783         uint16_t ioc_status;
784         uint8_t write;
785 };
786
787 struct mps_usr_command32 {
788         uint32_t req;
789         uint32_t req_len;
790         uint32_t rpl;
791         uint32_t rpl_len;
792         uint32_t buf;
793         int len;
794         uint32_t flags;
795 };
796
797 #define MPSIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mps_cfg_page_req32)
798 #define MPSIO_READ_CFG_PAGE32   _IOWR('M', 201, struct mps_cfg_page_req32)
799 #define MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32)
800 #define MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32)
801 #define MPSIO_WRITE_CFG_PAGE32  _IOWR('M', 204, struct mps_cfg_page_req32)
802 #define MPSIO_RAID_ACTION32     _IOWR('M', 205, struct mps_raid_action32)
803 #define MPSIO_MPS_COMMAND32     _IOWR('M', 210, struct mps_usr_command32)
804
805 static int
806 mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag,
807     struct thread *td)
808 {
809         struct mps_cfg_page_req32 *page32 = _arg;
810         struct mps_ext_cfg_page_req32 *ext32 = _arg;
811         struct mps_raid_action32 *raid32 = _arg;
812         struct mps_usr_command32 *user32 = _arg;
813         union {
814                 struct mps_cfg_page_req page;
815                 struct mps_ext_cfg_page_req ext;
816                 struct mps_raid_action raid;
817                 struct mps_usr_command user;
818         } arg;
819         u_long cmd;
820         int error;
821
822         switch (cmd32) {
823         case MPSIO_READ_CFG_HEADER32:
824         case MPSIO_READ_CFG_PAGE32:
825         case MPSIO_WRITE_CFG_PAGE32:
826                 if (cmd32 == MPSIO_READ_CFG_HEADER32)
827                         cmd = MPSIO_READ_CFG_HEADER;
828                 else if (cmd32 == MPSIO_READ_CFG_PAGE32)
829                         cmd = MPSIO_READ_CFG_PAGE;
830                 else
831                         cmd = MPSIO_WRITE_CFG_PAGE;
832                 CP(*page32, arg.page, header);
833                 CP(*page32, arg.page, page_address);
834                 PTRIN_CP(*page32, arg.page, buf);
835                 CP(*page32, arg.page, len);
836                 CP(*page32, arg.page, ioc_status);
837                 break;
838
839         case MPSIO_READ_EXT_CFG_HEADER32:
840         case MPSIO_READ_EXT_CFG_PAGE32:
841                 if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32)
842                         cmd = MPSIO_READ_EXT_CFG_HEADER;
843                 else
844                         cmd = MPSIO_READ_EXT_CFG_PAGE;
845                 CP(*ext32, arg.ext, header);
846                 CP(*ext32, arg.ext, page_address);
847                 PTRIN_CP(*ext32, arg.ext, buf);
848                 CP(*ext32, arg.ext, len);
849                 CP(*ext32, arg.ext, ioc_status);
850                 break;
851
852         case MPSIO_RAID_ACTION32:
853                 cmd = MPSIO_RAID_ACTION;
854                 CP(*raid32, arg.raid, action);
855                 CP(*raid32, arg.raid, volume_bus);
856                 CP(*raid32, arg.raid, volume_id);
857                 CP(*raid32, arg.raid, phys_disk_num);
858                 CP(*raid32, arg.raid, action_data_word);
859                 PTRIN_CP(*raid32, arg.raid, buf);
860                 CP(*raid32, arg.raid, len);
861                 CP(*raid32, arg.raid, volume_status);
862                 bcopy(raid32->action_data, arg.raid.action_data,
863                     sizeof arg.raid.action_data);
864                 CP(*raid32, arg.raid, ioc_status);
865                 CP(*raid32, arg.raid, write);
866                 break;
867
868         case MPSIO_MPS_COMMAND32:
869                 cmd = MPSIO_MPS_COMMAND;
870                 PTRIN_CP(*user32, arg.user, req);
871                 CP(*user32, arg.user, req_len);
872                 PTRIN_CP(*user32, arg.user, rpl);
873                 CP(*user32, arg.user, rpl_len);
874                 PTRIN_CP(*user32, arg.user, buf);
875                 CP(*user32, arg.user, len);
876                 CP(*user32, arg.user, flags);
877                 break;
878         default:
879                 return (ENOIOCTL);
880         }
881
882         error = mps_ioctl(dev, cmd, &arg, flag, td);
883         if (error == 0 && (cmd32 & IOC_OUT) != 0) {
884                 switch (cmd32) {
885                 case MPSIO_READ_CFG_HEADER32:
886                 case MPSIO_READ_CFG_PAGE32:
887                 case MPSIO_WRITE_CFG_PAGE32:
888                         CP(arg.page, *page32, header);
889                         CP(arg.page, *page32, page_address);
890                         PTROUT_CP(arg.page, *page32, buf);
891                         CP(arg.page, *page32, len);
892                         CP(arg.page, *page32, ioc_status);
893                         break;
894
895                 case MPSIO_READ_EXT_CFG_HEADER32:
896                 case MPSIO_READ_EXT_CFG_PAGE32:
897                         CP(arg.ext, *ext32, header);
898                         CP(arg.ext, *ext32, page_address);
899                         PTROUT_CP(arg.ext, *ext32, buf);
900                         CP(arg.ext, *ext32, len);
901                         CP(arg.ext, *ext32, ioc_status);
902                         break;
903
904                 case MPSIO_RAID_ACTION32:
905                         CP(arg.raid, *raid32, action);
906                         CP(arg.raid, *raid32, volume_bus);
907                         CP(arg.raid, *raid32, volume_id);
908                         CP(arg.raid, *raid32, phys_disk_num);
909                         CP(arg.raid, *raid32, action_data_word);
910                         PTROUT_CP(arg.raid, *raid32, buf);
911                         CP(arg.raid, *raid32, len);
912                         CP(arg.raid, *raid32, volume_status);
913                         bcopy(arg.raid.action_data, raid32->action_data,
914                             sizeof arg.raid.action_data);
915                         CP(arg.raid, *raid32, ioc_status);
916                         CP(arg.raid, *raid32, write);
917                         break;
918
919                 case MPSIO_MPS_COMMAND32:
920                         PTROUT_CP(arg.user, *user32, req);
921                         CP(arg.user, *user32, req_len);
922                         PTROUT_CP(arg.user, *user32, rpl);
923                         CP(arg.user, *user32, rpl_len);
924                         PTROUT_CP(arg.user, *user32, buf);
925                         CP(arg.user, *user32, len);
926                         CP(arg.user, *user32, flags);
927                         break;
928                 }
929         }
930
931         return (error);
932 }
933 #endif /* COMPAT_FREEBSD32 */
934
935 static int
936 mps_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag,
937     struct thread *td)
938 {
939 #ifdef COMPAT_FREEBSD32
940         if (SV_CURPROC_FLAG(SV_ILP32))
941                 return (mps_ioctl32(dev, com, arg, flag, td));
942 #endif
943         return (mps_ioctl(dev, com, arg, flag, td));
944 }