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