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