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: src/sys/dev/mpt/mpt_user.c,v 1.4 2009/05/20 17:29:21 imp Exp $ 33 */ 34 35 #include <sys/param.h> 36 #include <sys/conf.h> 37 #include <sys/errno.h> 38 #include <sys/ioccom.h> 39 #include <sys/device.h> 40 #include <sys/mpt_ioctl.h> 41 42 #include <dev/disk/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 int mpt_open(struct dev_open_args *ap); 81 static int mpt_close(struct dev_close_args *ap); 82 static int mpt_ioctl(struct dev_ioctl_args *ap); 83 84 static struct dev_ops mpt_cdevsw = { 85 .d_open = mpt_open, 86 .d_close = mpt_close, 87 .d_ioctl = mpt_ioctl, 88 }; 89 90 static MALLOC_DEFINE(M_MPTUSER, "mpt_user", "Buffers for mpt(4) ioctls"); 91 92 static uint32_t user_handler_id = MPT_HANDLER_ID_NONE; 93 94 int 95 mpt_user_probe(struct mpt_softc *mpt) 96 { 97 98 /* Attach to every controller. */ 99 return (0); 100 } 101 102 int 103 mpt_user_attach(struct mpt_softc *mpt) 104 { 105 mpt_handler_t handler; 106 int error, unit; 107 108 MPT_LOCK(mpt); 109 handler.reply_handler = mpt_user_reply_handler; 110 error = mpt_register_handler(mpt, MPT_HANDLER_REPLY, handler, 111 &user_handler_id); 112 MPT_UNLOCK(mpt); 113 if (error != 0) { 114 mpt_prt(mpt, "Unable to register user handler!\n"); 115 return (error); 116 } 117 unit = device_get_unit(mpt->dev); 118 mpt->cdev = make_dev(&mpt_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640, 119 "mpt%d", unit); 120 if (mpt->cdev == NULL) { 121 MPT_LOCK(mpt); 122 mpt_deregister_handler(mpt, MPT_HANDLER_REPLY, handler, 123 user_handler_id); 124 MPT_UNLOCK(mpt); 125 return (ENOMEM); 126 } 127 mpt->cdev->si_drv1 = mpt; 128 return (0); 129 } 130 131 int 132 mpt_user_enable(struct mpt_softc *mpt) 133 { 134 135 return (0); 136 } 137 138 void 139 mpt_user_ready(struct mpt_softc *mpt) 140 { 141 } 142 143 int 144 mpt_user_event(struct mpt_softc *mpt, request_t *req, 145 MSG_EVENT_NOTIFY_REPLY *msg) 146 { 147 148 /* Someday we may want to let a user daemon listen for events? */ 149 return (0); 150 } 151 152 void 153 mpt_user_reset(struct mpt_softc *mpt, int type) 154 { 155 } 156 157 void 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 173 mpt_open(struct dev_open_args *ap) 174 { 175 176 return (0); 177 } 178 179 static int 180 mpt_close(struct dev_close_args *ap) 181 { 182 183 return (0); 184 } 185 186 static int 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, &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 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 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, ¶ms, /*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 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 error = mpt_issue_cfg_req(mpt, req, ¶ms, mpt_page->paddr, 303 le32toh(page_req->len), TRUE, 5000); 304 if (error != 0) { 305 mpt_prt(mpt, "mpt_user_read_cfg_page timed out\n"); 306 return (ETIMEDOUT); 307 } 308 309 page_req->ioc_status = htole16(req->IOCStatus); 310 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) 311 bus_dmamap_sync(mpt_page->tag, mpt_page->map, 312 BUS_DMASYNC_POSTREAD); 313 mpt_free_request(mpt, req); 314 return (0); 315 } 316 317 static int 318 mpt_user_read_extcfg_header(struct mpt_softc *mpt, 319 struct mpt_ext_cfg_page_req *ext_page_req) 320 { 321 request_t *req; 322 cfgparms_t params; 323 MSG_CONFIG_REPLY *cfgp; 324 int error; 325 326 req = mpt_get_request(mpt, TRUE); 327 if (req == NULL) { 328 mpt_prt(mpt, "mpt_user_read_extcfg_header: Get request failed!\n"); 329 return (ENOMEM); 330 } 331 332 params.Action = MPI_CONFIG_ACTION_PAGE_HEADER; 333 params.PageVersion = ext_page_req->header.PageVersion; 334 params.PageLength = 0; 335 params.PageNumber = ext_page_req->header.PageNumber; 336 params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 337 params.PageAddress = le32toh(ext_page_req->page_address); 338 params.ExtPageType = ext_page_req->header.ExtPageType; 339 params.ExtPageLength = 0; 340 error = mpt_issue_cfg_req(mpt, req, ¶ms, /*addr*/0, /*len*/0, 341 TRUE, 5000); 342 if (error != 0) { 343 /* 344 * Leave the request. Without resetting the chip, it's 345 * still owned by it and we'll just get into trouble 346 * freeing it now. Mark it as abandoned so that if it 347 * shows up later it can be freed. 348 */ 349 mpt_prt(mpt, "mpt_user_read_extcfg_header timed out\n"); 350 return (ETIMEDOUT); 351 } 352 353 ext_page_req->ioc_status = htole16(req->IOCStatus); 354 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) { 355 cfgp = req->req_vbuf; 356 ext_page_req->header.PageVersion = cfgp->Header.PageVersion; 357 ext_page_req->header.PageNumber = cfgp->Header.PageNumber; 358 ext_page_req->header.PageType = cfgp->Header.PageType; 359 ext_page_req->header.ExtPageLength = cfgp->ExtPageLength; 360 ext_page_req->header.ExtPageType = cfgp->ExtPageType; 361 } 362 mpt_free_request(mpt, req); 363 return (0); 364 } 365 366 static int 367 mpt_user_read_extcfg_page(struct mpt_softc *mpt, 368 struct mpt_ext_cfg_page_req *ext_page_req, struct mpt_page_memory *mpt_page) 369 { 370 CONFIG_EXTENDED_PAGE_HEADER *hdr; 371 request_t *req; 372 cfgparms_t params; 373 int error; 374 375 req = mpt_get_request(mpt, TRUE); 376 if (req == NULL) { 377 mpt_prt(mpt, "mpt_user_read_extcfg_page: Get request failed!\n"); 378 return (ENOMEM); 379 } 380 381 hdr = mpt_page->vaddr; 382 params.Action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; 383 params.PageVersion = hdr->PageVersion; 384 params.PageLength = 0; 385 params.PageNumber = hdr->PageNumber; 386 params.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; 387 params.PageAddress = le32toh(ext_page_req->page_address); 388 params.ExtPageType = hdr->ExtPageType; 389 params.ExtPageLength = hdr->ExtPageLength; 390 error = mpt_issue_cfg_req(mpt, req, ¶ms, mpt_page->paddr, 391 le32toh(ext_page_req->len), TRUE, 5000); 392 if (error != 0) { 393 mpt_prt(mpt, "mpt_user_read_extcfg_page timed out\n"); 394 return (ETIMEDOUT); 395 } 396 397 ext_page_req->ioc_status = htole16(req->IOCStatus); 398 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) == MPI_IOCSTATUS_SUCCESS) 399 bus_dmamap_sync(mpt_page->tag, mpt_page->map, 400 BUS_DMASYNC_POSTREAD); 401 mpt_free_request(mpt, req); 402 return (0); 403 } 404 405 static int 406 mpt_user_write_cfg_page(struct mpt_softc *mpt, 407 struct mpt_cfg_page_req *page_req, struct mpt_page_memory *mpt_page) 408 { 409 CONFIG_PAGE_HEADER *hdr; 410 request_t *req; 411 cfgparms_t params; 412 u_int hdr_attr; 413 int error; 414 415 hdr = mpt_page->vaddr; 416 hdr_attr = hdr->PageType & MPI_CONFIG_PAGEATTR_MASK; 417 if (hdr_attr != MPI_CONFIG_PAGEATTR_CHANGEABLE && 418 hdr_attr != MPI_CONFIG_PAGEATTR_PERSISTENT) { 419 mpt_prt(mpt, "page type 0x%x not changeable\n", 420 hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); 421 return (EINVAL); 422 } 423 424 #if 0 425 /* 426 * We shouldn't mask off other bits here. 427 */ 428 hdr->PageType &= ~MPI_CONFIG_PAGETYPE_MASK; 429 #endif 430 431 req = mpt_get_request(mpt, TRUE); 432 if (req == NULL) 433 return (ENOMEM); 434 435 bus_dmamap_sync(mpt_page->tag, mpt_page->map, BUS_DMASYNC_PREWRITE); 436 437 /* 438 * There isn't any point in restoring stripped out attributes 439 * if you then mask them going down to issue the request. 440 */ 441 442 params.Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; 443 params.PageVersion = hdr->PageVersion; 444 params.PageLength = hdr->PageLength; 445 params.PageNumber = hdr->PageNumber; 446 params.PageAddress = le32toh(page_req->page_address); 447 #if 0 448 /* Restore stripped out attributes */ 449 hdr->PageType |= hdr_attr; 450 params.PageType = hdr->PageType & MPI_CONFIG_PAGETYPE_MASK; 451 #else 452 params.PageType = hdr->PageType; 453 #endif 454 error = mpt_issue_cfg_req(mpt, req, ¶ms, mpt_page->paddr, 455 le32toh(page_req->len), TRUE, 5000); 456 if (error != 0) { 457 mpt_prt(mpt, "mpt_write_cfg_page timed out\n"); 458 return (ETIMEDOUT); 459 } 460 461 page_req->ioc_status = htole16(req->IOCStatus); 462 mpt_free_request(mpt, req); 463 return (0); 464 } 465 466 static int 467 mpt_user_reply_handler(struct mpt_softc *mpt, request_t *req, 468 uint32_t reply_desc, MSG_DEFAULT_REPLY *reply_frame) 469 { 470 MSG_RAID_ACTION_REPLY *reply; 471 struct mpt_user_raid_action_result *res; 472 473 if (req == NULL) 474 return (TRUE); 475 476 if (reply_frame != NULL) { 477 bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap, 478 BUS_DMASYNC_POSTREAD); 479 reply = (MSG_RAID_ACTION_REPLY *)reply_frame; 480 req->IOCStatus = le16toh(reply->IOCStatus); 481 res = (struct mpt_user_raid_action_result *) 482 (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt)); 483 res->action_status = reply->ActionStatus; 484 res->volume_status = reply->VolumeStatus; 485 bcopy(&reply->ActionData, res->action_data, 486 sizeof(res->action_data)); 487 } 488 489 req->state &= ~REQ_STATE_QUEUED; 490 req->state |= REQ_STATE_DONE; 491 TAILQ_REMOVE(&mpt->request_pending_list, req, links); 492 493 if ((req->state & REQ_STATE_NEED_WAKEUP) != 0) { 494 wakeup(req); 495 } else if ((req->state & REQ_STATE_TIMEDOUT) != 0) { 496 /* 497 * Whew- we can free this request (late completion) 498 */ 499 mpt_free_request(mpt, req); 500 } 501 502 return (TRUE); 503 } 504 505 /* 506 * We use the first part of the request buffer after the request frame 507 * to hold the action data and action status from the RAID reply. The 508 * rest of the request buffer is used to hold the buffer for the 509 * action SGE. 510 */ 511 static int 512 mpt_user_raid_action(struct mpt_softc *mpt, struct mpt_raid_action *raid_act, 513 struct mpt_page_memory *mpt_page) 514 { 515 request_t *req; 516 struct mpt_user_raid_action_result *res; 517 MSG_RAID_ACTION_REQUEST *rap; 518 SGE_SIMPLE32 *se; 519 int error; 520 521 req = mpt_get_request(mpt, TRUE); 522 if (req == NULL) 523 return (ENOMEM); 524 rap = req->req_vbuf; 525 memset(rap, 0, sizeof *rap); 526 rap->Action = raid_act->action; 527 rap->ActionDataWord = raid_act->action_data_word; 528 rap->Function = MPI_FUNCTION_RAID_ACTION; 529 rap->VolumeID = raid_act->volume_id; 530 rap->VolumeBus = raid_act->volume_bus; 531 rap->PhysDiskNum = raid_act->phys_disk_num; 532 se = (SGE_SIMPLE32 *)&rap->ActionDataSGE; 533 if (mpt_page->vaddr != NULL && raid_act->len != 0) { 534 bus_dmamap_sync(mpt_page->tag, mpt_page->map, 535 BUS_DMASYNC_PREWRITE); 536 se->Address = htole32(mpt_page->paddr); 537 MPI_pSGE_SET_LENGTH(se, le32toh(raid_act->len)); 538 MPI_pSGE_SET_FLAGS(se, (MPI_SGE_FLAGS_SIMPLE_ELEMENT | 539 MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | 540 MPI_SGE_FLAGS_END_OF_LIST | 541 raid_act->write ? MPI_SGE_FLAGS_HOST_TO_IOC : 542 MPI_SGE_FLAGS_IOC_TO_HOST)); 543 } 544 se->FlagsLength = htole32(se->FlagsLength); 545 rap->MsgContext = htole32(req->index | user_handler_id); 546 547 mpt_check_doorbell(mpt); 548 mpt_send_cmd(mpt, req); 549 550 error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE, TRUE, 551 2000); 552 if (error != 0) { 553 /* 554 * Leave request so it can be cleaned up later. 555 */ 556 mpt_prt(mpt, "mpt_user_raid_action timed out\n"); 557 return (error); 558 } 559 560 raid_act->ioc_status = htole16(req->IOCStatus); 561 if ((req->IOCStatus & MPI_IOCSTATUS_MASK) != MPI_IOCSTATUS_SUCCESS) { 562 mpt_free_request(mpt, req); 563 return (0); 564 } 565 566 res = (struct mpt_user_raid_action_result *) 567 (((uint8_t *)req->req_vbuf) + MPT_RQSL(mpt)); 568 raid_act->volume_status = res->volume_status; 569 raid_act->action_status = res->action_status; 570 bcopy(res->action_data, raid_act->action_data, 571 sizeof(res->action_data)); 572 if (mpt_page->vaddr != NULL) 573 bus_dmamap_sync(mpt_page->tag, mpt_page->map, 574 BUS_DMASYNC_POSTREAD); 575 mpt_free_request(mpt, req); 576 return (0); 577 } 578 579 #ifdef __x86_64__ 580 #define PTRIN(p) ((void *)(uintptr_t)(p)) 581 #define PTROUT(v) ((u_int32_t)(uintptr_t)(v)) 582 #endif 583 584 static int 585 mpt_ioctl(struct dev_ioctl_args *ap) 586 { 587 struct mpt_softc *mpt; 588 struct mpt_cfg_page_req *page_req; 589 struct mpt_ext_cfg_page_req *ext_page_req; 590 struct mpt_raid_action *raid_act; 591 struct mpt_page_memory mpt_page; 592 #ifdef __x86_64__ 593 struct mpt_cfg_page_req32 *page_req32; 594 struct mpt_cfg_page_req page_req_swab; 595 struct mpt_ext_cfg_page_req32 *ext_page_req32; 596 struct mpt_ext_cfg_page_req ext_page_req_swab; 597 struct mpt_raid_action32 *raid_act32; 598 struct mpt_raid_action raid_act_swab; 599 #endif 600 u_long cmd = ap->a_cmd; 601 caddr_t arg = ap->a_data; 602 struct cdev *kdev = ap->a_head.a_dev; 603 int error; 604 605 mpt = kdev->si_drv1; 606 page_req = (void *)arg; 607 ext_page_req = (void *)arg; 608 raid_act = (void *)arg; 609 mpt_page.vaddr = NULL; 610 611 #ifdef __x86_64__ 612 /* Convert 32-bit structs to native ones. */ 613 page_req32 = (void *)arg; 614 ext_page_req32 = (void *)arg; 615 raid_act32 = (void *)arg; 616 switch (cmd) { 617 case MPTIO_READ_CFG_HEADER32: 618 case MPTIO_READ_CFG_PAGE32: 619 case MPTIO_WRITE_CFG_PAGE32: 620 page_req = &page_req_swab; 621 page_req->header = page_req32->header; 622 page_req->page_address = page_req32->page_address; 623 page_req->buf = PTRIN(page_req32->buf); 624 page_req->len = page_req32->len; 625 page_req->ioc_status = page_req32->ioc_status; 626 break; 627 case MPTIO_READ_EXT_CFG_HEADER32: 628 case MPTIO_READ_EXT_CFG_PAGE32: 629 ext_page_req = &ext_page_req_swab; 630 ext_page_req->header = ext_page_req32->header; 631 ext_page_req->page_address = ext_page_req32->page_address; 632 ext_page_req->buf = PTRIN(ext_page_req32->buf); 633 ext_page_req->len = ext_page_req32->len; 634 ext_page_req->ioc_status = ext_page_req32->ioc_status; 635 break; 636 case MPTIO_RAID_ACTION32: 637 raid_act = &raid_act_swab; 638 raid_act->action = raid_act32->action; 639 raid_act->volume_bus = raid_act32->volume_bus; 640 raid_act->volume_id = raid_act32->volume_id; 641 raid_act->phys_disk_num = raid_act32->phys_disk_num; 642 raid_act->action_data_word = raid_act32->action_data_word; 643 raid_act->buf = PTRIN(raid_act32->buf); 644 raid_act->len = raid_act32->len; 645 raid_act->volume_status = raid_act32->volume_status; 646 bcopy(raid_act32->action_data, raid_act->action_data, 647 sizeof(raid_act->action_data)); 648 raid_act->action_status = raid_act32->action_status; 649 raid_act->ioc_status = raid_act32->ioc_status; 650 raid_act->write = raid_act32->write; 651 break; 652 } 653 #endif 654 655 switch (cmd) { 656 #ifdef __x86_64__ 657 case MPTIO_READ_CFG_HEADER32: 658 #endif 659 case MPTIO_READ_CFG_HEADER: 660 MPT_LOCK(mpt); 661 error = mpt_user_read_cfg_header(mpt, page_req); 662 MPT_UNLOCK(mpt); 663 break; 664 #ifdef __x86_64__ 665 case MPTIO_READ_CFG_PAGE32: 666 #endif 667 case MPTIO_READ_CFG_PAGE: 668 error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len); 669 if (error) 670 break; 671 error = copyin(page_req->buf, mpt_page.vaddr, 672 sizeof(CONFIG_PAGE_HEADER)); 673 if (error) 674 break; 675 MPT_LOCK(mpt); 676 error = mpt_user_read_cfg_page(mpt, page_req, &mpt_page); 677 MPT_UNLOCK(mpt); 678 if (error) 679 break; 680 error = copyout(mpt_page.vaddr, page_req->buf, page_req->len); 681 break; 682 #ifdef __x86_64__ 683 case MPTIO_READ_EXT_CFG_HEADER32: 684 #endif 685 case MPTIO_READ_EXT_CFG_HEADER: 686 MPT_LOCK(mpt); 687 error = mpt_user_read_extcfg_header(mpt, ext_page_req); 688 MPT_UNLOCK(mpt); 689 break; 690 #ifdef __x86_64__ 691 case MPTIO_READ_EXT_CFG_PAGE32: 692 #endif 693 case MPTIO_READ_EXT_CFG_PAGE: 694 error = mpt_alloc_buffer(mpt, &mpt_page, ext_page_req->len); 695 if (error) 696 break; 697 error = copyin(ext_page_req->buf, mpt_page.vaddr, 698 sizeof(CONFIG_EXTENDED_PAGE_HEADER)); 699 if (error) 700 break; 701 MPT_LOCK(mpt); 702 error = mpt_user_read_extcfg_page(mpt, ext_page_req, &mpt_page); 703 MPT_UNLOCK(mpt); 704 if (error) 705 break; 706 error = copyout(mpt_page.vaddr, ext_page_req->buf, 707 ext_page_req->len); 708 break; 709 #ifdef __x86_64__ 710 case MPTIO_WRITE_CFG_PAGE32: 711 #endif 712 case MPTIO_WRITE_CFG_PAGE: 713 error = mpt_alloc_buffer(mpt, &mpt_page, page_req->len); 714 if (error) 715 break; 716 error = copyin(page_req->buf, mpt_page.vaddr, page_req->len); 717 if (error) 718 break; 719 MPT_LOCK(mpt); 720 error = mpt_user_write_cfg_page(mpt, page_req, &mpt_page); 721 MPT_UNLOCK(mpt); 722 break; 723 #ifdef __x86_64__ 724 case MPTIO_RAID_ACTION32: 725 #endif 726 case MPTIO_RAID_ACTION: 727 if (raid_act->buf != NULL) { 728 error = mpt_alloc_buffer(mpt, &mpt_page, raid_act->len); 729 if (error) 730 break; 731 error = copyin(raid_act->buf, mpt_page.vaddr, 732 raid_act->len); 733 if (error) 734 break; 735 } 736 MPT_LOCK(mpt); 737 error = mpt_user_raid_action(mpt, raid_act, &mpt_page); 738 MPT_UNLOCK(mpt); 739 if (error) 740 break; 741 if (raid_act->buf != NULL) 742 error = copyout(mpt_page.vaddr, raid_act->buf, 743 raid_act->len); 744 break; 745 default: 746 error = ENOIOCTL; 747 break; 748 } 749 750 mpt_free_buffer(&mpt_page); 751 752 if (error) 753 return (error); 754 755 #ifdef __x86_64__ 756 /* Convert native structs to 32-bit ones. */ 757 switch (cmd) { 758 case MPTIO_READ_CFG_HEADER32: 759 case MPTIO_READ_CFG_PAGE32: 760 case MPTIO_WRITE_CFG_PAGE32: 761 page_req32->header = page_req->header; 762 page_req32->page_address = page_req->page_address; 763 page_req32->buf = PTROUT(page_req->buf); 764 page_req32->len = page_req->len; 765 page_req32->ioc_status = page_req->ioc_status; 766 break; 767 case MPTIO_READ_EXT_CFG_HEADER32: 768 case MPTIO_READ_EXT_CFG_PAGE32: 769 ext_page_req32->header = ext_page_req->header; 770 ext_page_req32->page_address = ext_page_req->page_address; 771 ext_page_req32->buf = PTROUT(ext_page_req->buf); 772 ext_page_req32->len = ext_page_req->len; 773 ext_page_req32->ioc_status = ext_page_req->ioc_status; 774 break; 775 case MPTIO_RAID_ACTION32: 776 raid_act32->action = raid_act->action; 777 raid_act32->volume_bus = raid_act->volume_bus; 778 raid_act32->volume_id = raid_act->volume_id; 779 raid_act32->phys_disk_num = raid_act->phys_disk_num; 780 raid_act32->action_data_word = raid_act->action_data_word; 781 raid_act32->buf = PTROUT(raid_act->buf); 782 raid_act32->len = raid_act->len; 783 raid_act32->volume_status = raid_act->volume_status; 784 bcopy(raid_act->action_data, raid_act32->action_data, 785 sizeof(raid_act->action_data)); 786 raid_act32->action_status = raid_act->action_status; 787 raid_act32->ioc_status = raid_act->ioc_status; 788 raid_act32->write = raid_act->write; 789 break; 790 } 791 #endif 792 793 return (0); 794 } 795