Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/intel/io/ipmi/ipmi_main.c
+++ new/usr/src/uts/intel/io/ipmi/ipmi_main.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
24 24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 25 */
26 26
27 27 /*
28 28 * The ipmi driver is an openipmi compatible IPMI driver based on the FreeBSD
29 29 * driver.
30 30 *
31 31 * The current implementation has several limitations:
32 32 * 1) It only does discovery through the SMBIOS. The FreeBSD driver has
33 33 * several additional ways to discover the IPMI device (acpi, bus checking,
34 34 * etc.). This support could be ported if necessary.
35 35 * 2) The driver currently only supports the IPMI KCS_MODE mode (reported
36 36 * through the SMBIOS as SMBIOS SMB_IPMI_T_KCS). Support for the other modes
37 37 * (BT_MODE, SMIC_MODE, SSIF_MODE) could be ported if necessary.
38 38 * 3) The driver does not currently set up an IPMI watchdog. This also could
39 39 * be ported if necessary.
40 40 */
41 41
42 42 #include <sys/devops.h>
43 43 #include <sys/conf.h>
44 44 #include <sys/modctl.h>
45 45 #include <sys/types.h>
46 46 #include <sys/file.h>
47 47 #include <sys/errno.h>
48 48 #include <sys/open.h>
49 49 #include <sys/cred.h>
50 50 #include <sys/uio.h>
51 51 #include <sys/stat.h>
52 52 #include <sys/cmn_err.h>
53 53 #include <sys/ddi.h>
54 54 #include <sys/sunddi.h>
55 55 #include <sys/smbios.h>
56 56 #include <sys/smbios_impl.h>
57 57 #include <sys/policy.h>
58 58 #include <sys/ipmi.h>
59 59 #include "ipmivars.h"
60 60
61 61 static dev_info_t *ipmi_dip;
62 62 static boolean_t ipmi_attached = B_FALSE;
63 63 static boolean_t ipmi_found = B_FALSE;
64 64 static struct ipmi_softc softc;
65 65 static struct ipmi_softc *sc = &softc;
66 66 static list_t dev_list;
67 67 static id_space_t *minor_ids;
68 68 static kmutex_t dev_list_lock;
69 69
70 70 #define PTRIN(p) ((void *)(uintptr_t)(p))
71 71 #define PTROUT(p) ((uintptr_t)(p))
72 72
73 73 /*
74 74 * Use the SMBIOS info to determine if the system has an IPMI.
75 75 */
76 76 static int
77 77 get_smbios_ipmi_info(void)
78 78 {
79 79 smbios_ipmi_t ipmi;
80 80
81 81 if (ksmbios == NULL || smbios_info_ipmi(ksmbios, &ipmi) == SMB_ERR)
82 82 return (DDI_FAILURE);
83 83
84 84 cmn_err(CE_CONT, "!SMBIOS type 0x%x, addr 0x%llx", ipmi.smbip_type,
85 85 (long long unsigned int)(ipmi.smbip_addr));
86 86
87 87 /*
88 88 * Some systems have a bios that will report an IPMI device even when
89 89 * it is not installed. In this case we see 0x0 as the base address.
90 90 * If we see this address, assume the device is not really present.
91 91 */
92 92 if (ipmi.smbip_addr == NULL) {
93 93 cmn_err(CE_WARN, "!SMBIOS: Invalid base address");
94 94 return (DDI_FAILURE);
95 95 }
96 96
97 97 sc->ipmi_io_type = ipmi.smbip_type;
98 98 switch (ipmi.smbip_type) {
99 99 case SMB_IPMI_T_KCS:
100 100 case SMB_IPMI_T_SMIC:
101 101 sc->ipmi_io_address = ipmi.smbip_addr;
102 102 sc->ipmi_io_mode = (ipmi.smbip_flags & SMB_IPMI_F_IOADDR) ?
103 103 1 : 0;
104 104 sc->ipmi_io_spacing = ipmi.smbip_regspacing;
105 105 break;
106 106 case SMB_IPMI_T_SSIF:
107 107 if ((ipmi.smbip_addr & 0xffffffffffffff00) != 0) {
108 108 cmn_err(CE_WARN, "!SMBIOS: Invalid SSIF SMBus address, "
109 109 "using BMC I2C slave address instead");
110 110 sc->ipmi_io_address = ipmi.smbip_i2c;
111 111 } else {
112 112 sc->ipmi_io_address = ipmi.smbip_addr;
113 113 }
114 114 break;
115 115 default:
116 116 return (DDI_FAILURE);
117 117 }
118 118
119 119 if (ipmi.smbip_intr > 15) {
120 120 cmn_err(CE_WARN, "!SMBIOS: Non-ISA IRQ %d for IPMI",
121 121 ipmi.smbip_intr);
122 122 return (DDI_FAILURE);
123 123 }
124 124
125 125 sc->ipmi_io_irq = ipmi.smbip_intr;
126 126 return (DDI_SUCCESS);
127 127 }
128 128
129 129 static ipmi_device_t *
130 130 lookup_ipmidev_by_dev(dev_t dev)
131 131 {
132 132 ipmi_device_t *p;
133 133
134 134 mutex_enter(&dev_list_lock);
135 135 for (p = list_head(&dev_list); p; p = list_next(&dev_list, p)) {
136 136 if (dev == p->ipmi_dev) {
137 137 mutex_exit(&dev_list_lock);
138 138 return (p);
139 139 }
140 140 }
141 141 mutex_exit(&dev_list_lock);
142 142 return (NULL);
143 143 }
144 144
145 145 /*
146 146 * Each open returns a new pseudo device.
147 147 */
148 148 /*ARGSUSED*/
149 149 static int
150 150 ipmi_open(dev_t *devp, int flag, int otyp, cred_t *cred)
151 151 {
152 152 minor_t minor;
153 153 ipmi_device_t *dev;
154 154
155 155 if (ipmi_attached == B_FALSE)
156 156 return (ENXIO);
157 157
158 158 if (ipmi_found == B_FALSE)
159 159 return (ENODEV);
160 160
161 161 /* exclusive opens are not supported */
162 162 if (flag & FEXCL)
163 163 return (ENOTSUP);
164 164
165 165 if ((minor = (minor_t)id_alloc_nosleep(minor_ids)) == 0)
166 166 return (ENODEV);
167 167
168 168 /* Initialize the per file descriptor data. */
169 169 dev = kmem_zalloc(sizeof (ipmi_device_t), KM_SLEEP);
170 170
171 171 dev->ipmi_pollhead = kmem_zalloc(sizeof (pollhead_t), KM_SLEEP);
172 172
173 173 TAILQ_INIT(&dev->ipmi_completed_requests);
174 174 dev->ipmi_address = IPMI_BMC_SLAVE_ADDR;
175 175 dev->ipmi_lun = IPMI_BMC_SMS_LUN;
176 176 *devp = makedevice(getmajor(*devp), minor);
177 177 dev->ipmi_dev = *devp;
178 178 cv_init(&dev->ipmi_cv, NULL, CV_DEFAULT, NULL);
179 179
180 180 mutex_enter(&dev_list_lock);
181 181 list_insert_head(&dev_list, dev);
182 182 mutex_exit(&dev_list_lock);
183 183
184 184 return (0);
185 185 }
186 186
187 187 /*ARGSUSED*/
188 188 static int
189 189 ipmi_close(dev_t dev, int flag, int otyp, cred_t *cred)
190 190 {
191 191 ipmi_device_t *dp;
192 192 struct ipmi_request *req, *next;
193 193
194 194 if ((dp = lookup_ipmidev_by_dev(dev)) == NULL)
195 195 return (ENODEV);
196 196
197 197 IPMI_LOCK(sc);
198 198 /* remove any pending requests */
199 199 req = TAILQ_FIRST(&sc->ipmi_pending_requests);
200 200 while (req != NULL) {
201 201 next = TAILQ_NEXT(req, ir_link);
202 202
203 203 if (req->ir_owner == dp) {
204 204 TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link);
205 205 ipmi_free_request(req);
206 206 }
207 207 req = next;
208 208 }
209 209
210 210 dp->ipmi_status |= IPMI_CLOSING;
211 211 while (dp->ipmi_status & IPMI_BUSY)
212 212 cv_wait(&dp->ipmi_cv, &sc->ipmi_lock);
213 213 IPMI_UNLOCK(sc);
214 214
215 215 /* remove any requests in queue of stuff completed */
216 216 while ((req = TAILQ_FIRST(&dp->ipmi_completed_requests)) != NULL) {
217 217 TAILQ_REMOVE(&dp->ipmi_completed_requests, req, ir_link);
218 218 ipmi_free_request(req);
219 219 }
220 220
221 221 mutex_enter(&dev_list_lock);
222 222 list_remove(&dev_list, dp);
223 223 mutex_exit(&dev_list_lock);
224 224 id_free(minor_ids, getminor(dev));
225 225 cv_destroy(&dp->ipmi_cv);
226 226 kmem_free(dp->ipmi_pollhead, sizeof (pollhead_t));
227 227 kmem_free(dp, sizeof (ipmi_device_t));
228 228
229 229 return (0);
230 230 }
231 231
232 232 /*ARGSUSED*/
233 233 static int
234 234 ipmi_ioctl(dev_t dv, int cmd, intptr_t data, int flags, cred_t *cr, int *rvalp)
235 235 {
236 236 struct ipmi_device *dev;
237 237 struct ipmi_request *kreq;
238 238 struct ipmi_req req;
239 239 struct ipmi_recv recv;
240 240 struct ipmi_recv32 recv32;
241 241 struct ipmi_addr addr;
242 242 int error, len;
243 243 model_t model;
244 244 int orig_cmd = 0;
245 245 uchar_t t_lun;
246 246
247 247 if (secpolicy_sys_config(cr, B_FALSE) != 0)
248 248 return (EPERM);
249 249
250 250 if ((dev = lookup_ipmidev_by_dev(dv)) == NULL)
251 251 return (ENODEV);
252 252
253 253 model = get_udatamodel();
254 254 if (model == DATAMODEL_NATIVE) {
255 255 switch (cmd) {
256 256 case IPMICTL_SEND_COMMAND:
257 257 if (copyin((void *)data, &req, sizeof (req)))
258 258 return (EFAULT);
259 259 break;
260 260 case IPMICTL_RECEIVE_MSG_TRUNC:
261 261 case IPMICTL_RECEIVE_MSG:
262 262 if (copyin((void *)data, &recv, sizeof (recv)))
263 263 return (EFAULT);
264 264 break;
265 265 }
266 266 } else {
267 267 /* Convert 32-bit structures to native. */
268 268 struct ipmi_req32 req32;
269 269
270 270 switch (cmd) {
271 271 case IPMICTL_SEND_COMMAND_32:
272 272 if (copyin((void *)data, &req32, sizeof (req32)))
273 273 return (EFAULT);
274 274
275 275 req.addr = PTRIN(req32.addr);
276 276 req.addr_len = req32.addr_len;
277 277 req.msgid = req32.msgid;
278 278 req.msg.netfn = req32.msg.netfn;
279 279 req.msg.cmd = req32.msg.cmd;
280 280 req.msg.data_len = req32.msg.data_len;
281 281 req.msg.data = PTRIN(req32.msg.data);
282 282
283 283 cmd = IPMICTL_SEND_COMMAND;
284 284 break;
285 285
286 286 case IPMICTL_RECEIVE_MSG_TRUNC_32:
287 287 case IPMICTL_RECEIVE_MSG_32:
288 288 if (copyin((void *)data, &recv32, sizeof (recv32)))
289 289 return (EFAULT);
290 290
291 291 recv.addr = PTRIN(recv32.addr);
292 292 recv.addr_len = recv32.addr_len;
293 293 recv.msg.data_len = recv32.msg.data_len;
294 294 recv.msg.data = PTRIN(recv32.msg.data);
295 295
296 296 orig_cmd = cmd;
297 297 cmd = (cmd == IPMICTL_RECEIVE_MSG_TRUNC_32) ?
298 298 IPMICTL_RECEIVE_MSG_TRUNC : IPMICTL_RECEIVE_MSG;
299 299 break;
300 300 }
301 301 }
302 302
303 303 switch (cmd) {
304 304 case IPMICTL_SEND_COMMAND:
305 305 /* Check that we didn't get a ridiculous length */
306 306 if (req.msg.data_len > IPMI_MAX_RX)
307 307 return (EINVAL);
308 308
309 309 kreq = ipmi_alloc_request(dev, req.msgid,
310 310 IPMI_ADDR(req.msg.netfn, 0), req.msg.cmd,
311 311 req.msg.data_len, IPMI_MAX_RX);
312 312 /* This struct is the same for 32/64 */
313 313 if (req.msg.data_len > 0 &&
314 314 copyin(req.msg.data, kreq->ir_request, req.msg.data_len)) {
315 315 ipmi_free_request(kreq);
316 316 return (EFAULT);
317 317 }
318 318 IPMI_LOCK(sc);
319 319 dev->ipmi_requests++;
320 320 error = sc->ipmi_enqueue_request(sc, kreq);
321 321 IPMI_UNLOCK(sc);
322 322 if (error)
323 323 return (error);
324 324 break;
325 325
326 326 case IPMICTL_RECEIVE_MSG_TRUNC:
327 327 case IPMICTL_RECEIVE_MSG:
328 328 /* This struct is the same for 32/64 */
329 329 if (copyin(recv.addr, &addr, sizeof (addr)))
330 330 return (EFAULT);
331 331
332 332 IPMI_LOCK(sc);
333 333 kreq = TAILQ_FIRST(&dev->ipmi_completed_requests);
334 334 if (kreq == NULL) {
335 335 IPMI_UNLOCK(sc);
336 336 return (EAGAIN);
337 337 }
338 338 addr.channel = IPMI_BMC_CHANNEL;
339 339 recv.recv_type = IPMI_RESPONSE_RECV_TYPE;
340 340 recv.msgid = kreq->ir_msgid;
341 341 recv.msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2;
342 342 recv.msg.cmd = kreq->ir_command;
343 343 error = kreq->ir_error;
344 344 if (error) {
345 345 TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
346 346 ir_link);
347 347 dev->ipmi_requests--;
348 348 IPMI_UNLOCK(sc);
349 349 ipmi_free_request(kreq);
350 350 return (error);
351 351 }
352 352 len = kreq->ir_replylen + 1;
353 353 if (recv.msg.data_len < len && cmd == IPMICTL_RECEIVE_MSG) {
354 354 IPMI_UNLOCK(sc);
355 355 return (EMSGSIZE);
356 356 }
357 357 TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link);
358 358 dev->ipmi_requests--;
359 359 IPMI_UNLOCK(sc);
360 360 len = min(recv.msg.data_len, len);
361 361 recv.msg.data_len = (unsigned short)len;
362 362
363 363 if (orig_cmd == IPMICTL_RECEIVE_MSG_TRUNC_32 ||
364 364 orig_cmd == IPMICTL_RECEIVE_MSG_32) {
365 365 /* Update changed fields in 32-bit structure. */
366 366 recv32.recv_type = recv.recv_type;
367 367 recv32.msgid = (int32_t)recv.msgid;
368 368 recv32.msg.netfn = recv.msg.netfn;
369 369 recv32.msg.cmd = recv.msg.cmd;
370 370 recv32.msg.data_len = recv.msg.data_len;
371 371
372 372 error = copyout(&recv32, (void *)data, sizeof (recv32));
373 373 } else {
374 374 error = copyout(&recv, (void *)data, sizeof (recv));
375 375 }
376 376
377 377 /* This struct is the same for 32/64 */
378 378 if (error == 0)
379 379 error = copyout(&addr, recv.addr, sizeof (addr));
380 380 if (error == 0)
381 381 error = copyout(&kreq->ir_compcode, recv.msg.data, 1);
382 382 if (error == 0)
383 383 error = copyout(kreq->ir_reply, recv.msg.data + 1,
384 384 len - 1);
385 385 ipmi_free_request(kreq);
386 386
387 387 if (error)
388 388 return (EFAULT);
389 389
390 390 break;
391 391
392 392 case IPMICTL_SET_MY_ADDRESS_CMD:
393 393 IPMI_LOCK(sc);
394 394 if (copyin((void *)data, &dev->ipmi_address,
395 395 sizeof (dev->ipmi_address))) {
396 396 IPMI_UNLOCK(sc);
397 397 return (EFAULT);
398 398 }
399 399 IPMI_UNLOCK(sc);
400 400 break;
401 401
402 402 case IPMICTL_GET_MY_ADDRESS_CMD:
403 403 IPMI_LOCK(sc);
404 404 if (copyout(&dev->ipmi_address, (void *)data,
405 405 sizeof (dev->ipmi_address))) {
406 406 IPMI_UNLOCK(sc);
407 407 return (EFAULT);
408 408 }
409 409 IPMI_UNLOCK(sc);
410 410 break;
411 411
412 412 case IPMICTL_SET_MY_LUN_CMD:
413 413 IPMI_LOCK(sc);
414 414 if (copyin((void *)data, &t_lun, sizeof (t_lun))) {
415 415 IPMI_UNLOCK(sc);
416 416 return (EFAULT);
417 417 }
418 418 dev->ipmi_lun = t_lun & 0x3;
419 419 IPMI_UNLOCK(sc);
420 420 break;
421 421
422 422 case IPMICTL_GET_MY_LUN_CMD:
423 423 IPMI_LOCK(sc);
424 424 if (copyout(&dev->ipmi_lun, (void *)data,
425 425 sizeof (dev->ipmi_lun))) {
426 426 IPMI_UNLOCK(sc);
427 427 return (EFAULT);
428 428 }
429 429 IPMI_UNLOCK(sc);
430 430 break;
431 431
432 432 case IPMICTL_SET_GETS_EVENTS_CMD:
433 433 break;
434 434
435 435 case IPMICTL_REGISTER_FOR_CMD:
436 436 case IPMICTL_UNREGISTER_FOR_CMD:
437 437 return (EINVAL);
438 438
439 439 default:
440 440 return (EINVAL);
441 441 }
442 442
443 443 return (0);
444 444 }
445 445
446 446 static int
447 447 ipmi_poll(dev_t dv, short events, int anyyet, short *reventsp,
448 448 pollhead_t **phpp)
449 449 {
450 450 struct ipmi_device *dev;
451 451 short revent = 0;
452 452
453 453 if ((dev = lookup_ipmidev_by_dev(dv)) == NULL)
454 454 return (ENODEV);
455 455
456 456 if (events & (POLLIN | POLLRDNORM)) {
457 457 if (!TAILQ_EMPTY(&dev->ipmi_completed_requests))
458 458 revent |= events & (POLLIN | POLLRDNORM);
459 459 if (dev->ipmi_requests == 0)
460 460 revent |= POLLERR;
461 461 }
462 462
463 463 if (revent == 0) {
464 464 /* nothing has occurred */
465 465 if (!anyyet)
466 466 *phpp = dev->ipmi_pollhead;
467 467 }
468 468
469 469 *reventsp = revent;
470 470 return (0);
471 471 }
472 472
473 473 /*ARGSUSED*/
474 474 static int
475 475 ipmi_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
476 476 {
477 477 switch (cmd) {
478 478 case DDI_INFO_DEVT2DEVINFO:
479 479 *resultp = ipmi_dip;
480 480 return (DDI_SUCCESS);
481 481 case DDI_INFO_DEVT2INSTANCE:
482 482 *resultp = NULL;
483 483 return (DDI_SUCCESS);
484 484 }
485 485 return (DDI_FAILURE);
486 486 }
487 487
488 488 static void
489 489 ipmi_cleanup(dev_info_t *dip)
490 490 {
491 491 /* poke the taskq so that it can terminate */
492 492 IPMI_LOCK(sc);
493 493 sc->ipmi_detaching = 1;
494 494 cv_signal(&sc->ipmi_request_added);
495 495 IPMI_UNLOCK(sc);
496 496
497 497 ipmi_shutdown(sc);
498 498 ddi_remove_minor_node(dip, NULL);
499 499 ipmi_dip = NULL;
500 500
501 501 mutex_destroy(&dev_list_lock);
502 502 list_destroy(&dev_list);
503 503 id_space_destroy(minor_ids);
504 504
505 505 sc->ipmi_detaching = 0;
506 506 }
507 507
508 508 static int
509 509 ipmi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
510 510 {
511 511 if (cmd != DDI_ATTACH)
512 512 return (DDI_FAILURE);
513 513
514 514 /* this driver only supports one device instance */
515 515 if (ddi_get_instance(dip) != 0) {
516 516 cmn_err(CE_WARN,
517 517 "!not attaching to non-zero device instance %d",
518 518 ddi_get_instance(dip));
519 519 return (DDI_FAILURE);
520 520 }
521 521
522 522 if (get_smbios_ipmi_info() == DDI_FAILURE)
523 523 return (DDI_FAILURE);
524 524
525 525 /*
526 526 * Support for the other types (SMIC, SSIF) should be added here.
527 527 */
528 528 switch (sc->ipmi_io_type) {
529 529 case SMB_IPMI_T_KCS:
530 530 if (ipmi_kcs_attach(sc) != 0)
531 531 return (DDI_FAILURE);
532 532 break;
533 533 default:
534 534 return (DDI_FAILURE);
535 535 }
536 536 ipmi_found = B_TRUE;
537 537
538 538 if (ddi_create_minor_node(dip, "ipmi", S_IFCHR, 0, DDI_PSEUDO,
539 539 0) == DDI_FAILURE) {
540 540 cmn_err(CE_WARN, "!attach could not create minor node");
541 541 ddi_remove_minor_node(dip, NULL);
542 542 return (DDI_FAILURE);
543 543 }
544 544
545 545 ipmi_dip = dip;
546 546
547 547 list_create(&dev_list, sizeof (ipmi_device_t),
548 548 offsetof(ipmi_device_t, ipmi_node));
549 549 mutex_init(&dev_list_lock, NULL, MUTEX_DRIVER, NULL);
550 550
551 551 /* Create ID space for open devs. ID 0 is reserved. */
552 552 minor_ids = id_space_create("ipmi_id_space", 1, 128);
553 553
554 554 if (ipmi_startup(sc) != B_TRUE) {
555 555 ipmi_cleanup(dip);
556 556 return (DDI_FAILURE);
557 557 }
558 558
559 559 ipmi_attached = B_TRUE;
560 560
561 561 return (DDI_SUCCESS);
562 562 }
563 563
564 564 static int
565 565 ipmi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
566 566 {
567 567 if (cmd != DDI_DETACH)
568 568 return (DDI_FAILURE);
569 569
570 570 if (ipmi_found == B_FALSE)
571 571 return (DDI_SUCCESS);
572 572
573 573 mutex_enter(&dev_list_lock);
574 574 if (!list_is_empty(&dev_list)) {
575 575 mutex_exit(&dev_list_lock);
576 576 return (DDI_FAILURE);
577 577 }
578 578 mutex_exit(&dev_list_lock);
579 579
580 580 ipmi_cleanup(dip);
581 581
582 582 ipmi_attached = B_FALSE;
583 583 return (DDI_SUCCESS);
584 584 }
585 585
586 586 static struct cb_ops ipmi_cb_ops = {
587 587 ipmi_open,
588 588 ipmi_close,
589 589 nodev, /* strategy */
590 590 nodev, /* print */
591 591 nodev, /* dump */
592 592 nodev, /* read */
593 593 nodev, /* write */
594 594 ipmi_ioctl,
595 595 nodev, /* devmap */
596 596 nodev, /* mmap */
597 597 nodev, /* segmap */
598 598 ipmi_poll,
599 599 ddi_prop_op,
600 600 NULL, /* streamtab */
601 601 D_NEW | D_MP, /* flags */
602 602 CB_REV,
603 603 nodev, /* awread */
604 604 nodev /* awrite */
605 605 };
606 606
607 607 static struct dev_ops ipmi_ops = {
608 608 DEVO_REV,
609 609 0, /* reference count */
610 610 ipmi_info,
611 611 nulldev, /* identify */
612 612 nulldev, /* probe */
613 613 ipmi_attach,
614 614 ipmi_detach,
615 615 nodev, /* reset */
616 616 &ipmi_cb_ops,
↓ open down ↓ |
616 lines elided |
↑ open up ↑ |
617 617 NULL, /* bus ops */
618 618 NULL, /* power */
619 619 ddi_quiesce_not_needed,
620 620 };
621 621
622 622 static struct modldrv md = {
623 623 &mod_driverops, "ipmi driver", &ipmi_ops
624 624 };
625 625
626 626 static struct modlinkage ml = {
627 - MODREV_1, &md, NULL
627 + MODREV_1, { &md, NULL }
628 628 };
629 629
630 630 int
631 631 _init(void)
632 632 {
633 633 return (mod_install(&ml));
634 634 }
635 635
636 636 int
637 637 _fini(void)
638 638 {
639 639 return (mod_remove(&ml));
640 640 }
641 641
642 642 int
643 643 _info(struct modinfo *mip)
644 644 {
645 645 return (mod_info(&ml, mip));
646 646 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX