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