Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/intel/io/heci/heci_main.c
+++ new/usr/src/uts/intel/io/heci/heci_main.c
1 1 /*
2 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 3 * Use is subject to license terms.
4 4 */
5 5
6 6 /*
7 7 * Part of Intel(R) Manageability Engine Interface Linux driver
8 8 *
9 9 * Copyright (c) 2003 - 2008 Intel Corp.
10 10 * All rights reserved.
11 11 *
12 12 * Redistribution and use in source and binary forms, with or without
13 13 * modification, are permitted provided that the following conditions
14 14 * are met:
15 15 * 1. Redistributions of source code must retain the above copyright
16 16 * notice, this list of conditions, and the following disclaimer,
17 17 * without modification.
18 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 19 * substantially similar to the "NO WARRANTY" disclaimer below
20 20 * ("Disclaimer") and any redistribution must be conditioned upon
21 21 * including a substantially similar Disclaimer requirement for further
22 22 * binary redistribution.
23 23 * 3. Neither the names of the above-listed copyright holders nor the names
24 24 * of any contributors may be used to endorse or promote products derived
25 25 * from this software without specific prior written permission.
26 26 *
27 27 * Alternatively, this software may be distributed under the terms of the
28 28 * GNU General Public License ("GPL") version 2 as published by the Free
29 29 * Software Foundation.
30 30 *
31 31 * NO WARRANTY
32 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 42 * POSSIBILITY OF SUCH DAMAGES.
43 43 *
44 44 */
45 45
46 46 #pragma ident "@(#)heci_main.c 1.7 08/03/07 SMI"
47 47
48 48 #include <sys/types.h>
49 49 #include <sys/note.h>
50 50 #include <sys/cmn_err.h>
51 51 #include <sys/conf.h>
52 52 #include <sys/ddi.h>
53 53 #include <sys/ddi_impldefs.h>
54 54 #include <sys/devops.h>
55 55 #include <sys/instance.h>
56 56 #include <sys/modctl.h>
57 57 #include <sys/open.h>
58 58 #include <sys/stat.h>
59 59 #include <sys/sunddi.h>
60 60 #include <sys/file.h>
61 61 #include <sys/priv.h>
62 62 #include <sys/systm.h>
63 63 #include <sys/mkdev.h>
64 64 #include <sys/list.h>
65 65 #include <sys/pci.h>
66 66 #include "heci_data_structures.h"
67 67
68 68 #include "heci.h"
69 69 #include "heci_interface.h"
70 70
71 71 #define MAJOR_VERSION 5
72 72 #define MINOR_VERSION 0
73 73 #define QUICK_FIX_NUMBER 0
74 74 #define VER_BUILD 30
75 75
76 76 #define str(s) name(s)
77 77 #define name(s) #s
78 78 #define HECI_DRIVER_VERSION str(MAJOR_VERSION) "." str(MINOR_VERSION) \
79 79 "." str(QUICK_FIX_NUMBER) "." str(VER_BUILD)
80 80
81 81 #define HECI_READ_TIMEOUT 45
82 82
83 83 #define HECI_DRIVER_NAME "heci"
84 84
85 85 /*
86 86 * heci driver strings
87 87 */
88 88 char heci_driver_name[] = HECI_DRIVER_NAME;
89 89 char heci_driver_string[] = "Intel(R) Management Engine Interface";
90 90 char heci_driver_version[] = HECI_DRIVER_VERSION;
91 91 char heci_copyright[] = "Copyright (c) 2003 - 2008 Intel Corporation.";
92 92
93 93 void * heci_soft_state_p = NULL;
94 94
95 95 #ifdef DEBUG
96 96 int heci_debug = 0;
97 97 #endif
98 98
99 99 /*
100 100 * Local Function Prototypes
101 101 */
102 102 static int heci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
103 103 static int heci_initialize(dev_info_t *dip, struct iamt_heci_device *device);
104 104 static int heci_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
105 105 void *arg, void **result);
106 106 static int heci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
107 107 static int heci_quiesce(dev_info_t *dip);
108 108 static int heci_open(dev_t *devp, int flags, int otyp, cred_t *credp);
109 109 static int heci_close(dev_t dev, int flag, int otyp, struct cred *cred);
110 110 static int heci_read(dev_t dev, struct uio *uio_p, cred_t *cred_p);
111 111 static int heci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
112 112 cred_t *cr, int *rval);
113 113 static int heci_write(dev_t dev, struct uio *uio_p, struct cred *cred);
114 114 static int heci_poll(dev_t dev, short events, int anyyet,
115 115 short *reventsp, struct pollhead **phpp);
116 116 static struct heci_cb_private *find_read_list_entry(
117 117 struct iamt_heci_device *dev,
118 118 struct heci_file_private *file_ext);
119 119 static inline int heci_fe_same_id(struct heci_file_private *fe1,
120 120 struct heci_file_private *fe2);
121 121
122 122 static void heci_resume(dev_info_t *dip);
123 123 static int heci_suspend(dev_info_t *dip);
124 124 static uint16_t g_sus_wd_timeout;
125 125
126 126 static struct cb_ops heci_cb_ops = {
127 127 heci_open, /* open */
128 128 heci_close, /* close */
129 129 nodev, /* strategy */
130 130 nodev, /* print */
131 131 nodev, /* dump */
132 132 heci_read, /* read */
133 133 heci_write, /* write */
134 134 heci_ioctl, /* ioctl */
135 135 nodev, /* devmap */
136 136 nodev, /* mmap */
137 137 nodev, /* segmap */
138 138 heci_poll, /* poll */
139 139 ddi_prop_op, /* cb_prop op */
140 140 NULL, /* stream tab */
141 141 D_MP /* Driver Compatability Flags */
142 142 };
143 143
144 144 static struct dev_ops heci_dev_ops = {
145 145 DEVO_REV, /* devo_rev */
146 146 0, /* refcnt */
147 147 heci_getinfo, /* get_dev_info */
148 148 nulldev, /* identify */
149 149 nulldev, /* probe */
150 150 heci_attach, /* attach */
151 151 heci_detach, /* detach */
152 152 nodev, /* reset */
153 153 &heci_cb_ops, /* Driver Ops */
154 154 (struct bus_ops *)NULL, /* Bus Operations */
155 155 NULL, /* power */
156 156 heci_quiesce /* devo_quiesce */
157 157 };
158 158
159 159 /*
↓ open down ↓ |
159 lines elided |
↑ open up ↑ |
160 160 * Module linkage information for the kernel
161 161 */
162 162
163 163 static struct modldrv modldrv = {
164 164 &mod_driverops, /* Type of Module = Driver */
165 165 heci_driver_string, /* Driver Identifier string. */
166 166 &heci_dev_ops, /* Driver Ops. */
167 167 };
168 168
169 169 static struct modlinkage modlinkage = {
170 - MODREV_1, (void *)&modldrv, NULL
170 + MODREV_1, { (void *)&modldrv, NULL }
171 171 };
172 172
173 173 /*
174 174 * Module Initialization functions.
175 175 */
176 176
177 177 int
178 178 _init(void)
179 179 {
180 180 int stat;
181 181
182 182 /* Allocate soft state */
183 183 if ((stat = ddi_soft_state_init(&heci_soft_state_p,
184 184 sizeof (struct iamt_heci_device), 1)) != DDI_SUCCESS) {
185 185 return (stat);
186 186 }
187 187
188 188 if ((stat = mod_install(&modlinkage)) != 0)
189 189 ddi_soft_state_fini(&heci_soft_state_p);
190 190
191 191 return (stat);
192 192 }
193 193
194 194 int
195 195 _info(struct modinfo *infop)
196 196 {
197 197
198 198 return (mod_info(&modlinkage, infop));
199 199 }
200 200
201 201 int
202 202 _fini(void)
203 203 {
204 204 int stat;
205 205
206 206 if ((stat = mod_remove(&modlinkage)) != 0)
207 207 return (stat);
208 208
209 209 ddi_soft_state_fini(&heci_soft_state_p);
210 210
211 211 return (stat);
212 212 }
213 213
214 214 /*
215 215 * heci_attach - Driver Attach Routine
216 216 */
217 217 static int
218 218 heci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
219 219 {
220 220 int instance, status;
221 221 struct iamt_heci_device *device;
222 222
223 223 switch (cmd) {
224 224 case DDI_ATTACH:
225 225 break;
226 226 case DDI_RESUME:
227 227 heci_resume(dip);
228 228 return (DDI_SUCCESS);
229 229 default:
230 230 return (DDI_FAILURE);
231 231 }
232 232
233 233 DBG("%s - version %s\n", heci_driver_string, heci_driver_version);
234 234 DBG("%s\n", heci_copyright);
235 235
236 236 instance = ddi_get_instance(dip); /* find out which unit */
237 237 status = ddi_soft_state_zalloc(heci_soft_state_p, instance);
238 238 if (status != DDI_SUCCESS)
239 239 return (DDI_FAILURE);
240 240 device = ddi_get_soft_state(heci_soft_state_p, instance);
241 241 ASSERT(device != NULL); /* can't fail - we only just allocated it */
242 242
243 243 device->dip = dip;
244 244
245 245 status = heci_initialize(dip, device);
246 246 if (status != DDI_SUCCESS) {
247 247 ddi_soft_state_free(heci_soft_state_p, instance);
248 248 return (DDI_FAILURE);
249 249 }
250 250
251 251 status = ddi_create_minor_node(dip, "AMT", S_IFCHR,
252 252 MAKE_MINOR_NUM(HECI_MINOR_NUMBER, instance),
253 253 DDI_PSEUDO, 0);
254 254
255 255 if (status != DDI_SUCCESS) {
256 256
257 257 ddi_remove_minor_node(dip, NULL);
258 258 ddi_soft_state_free(heci_soft_state_p, instance);
259 259 return (DDI_FAILURE);
260 260 }
261 261
262 262
263 263 return (status);
264 264 }
265 265
266 266 /*
267 267 * heci_probe - Device Initialization Routine
268 268 */
269 269 static int
270 270 heci_initialize(dev_info_t *dip, struct iamt_heci_device *device)
271 271 {
272 272 int err;
273 273 ddi_device_acc_attr_t attr;
274 274
275 275 err = ddi_get_iblock_cookie(dip, 0, &device->sc_iblk);
276 276 if (err != DDI_SUCCESS) {
277 277 cmn_err(CE_WARN, "heci_probe():"
278 278 " ddi_get_iblock_cookie() failed\n");
279 279 goto end;
280 280 }
281 281 /* initializes the heci device structure */
282 282 init_heci_device(dip, device);
283 283
284 284 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
285 285 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
286 286 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
287 287
288 288 if (ddi_regs_map_setup(dip, 1, (caddr_t *)&device->mem_addr, 0, 0,
289 289 &attr, &device->io_handle) != DDI_SUCCESS) {
290 290 cmn_err(CE_WARN, "heci%d: unable to map PCI regs\n",
291 291 ddi_get_instance(dip));
292 292 goto fini_heci_device;
293 293 }
294 294
295 295 err = ddi_add_intr(dip, 0, &device->sc_iblk, NULL,
296 296 heci_isr_interrupt, (caddr_t)device);
297 297 if (err != DDI_SUCCESS) {
298 298 cmn_err(CE_WARN, "heci_probe(): ddi_add_intr() failed\n");
299 299 goto unmap_memory;
300 300 }
301 301
302 302 if (heci_hw_init(device)) {
303 303 cmn_err(CE_WARN, "init hw failure.\n");
304 304 err = -ENODEV;
305 305 goto release_irq;
306 306 }
307 307 (void) heci_initialize_clients(device);
308 308 if (device->heci_state != HECI_ENABLED) {
309 309 err = -ENODEV;
310 310 goto release_hw;
311 311 }
312 312 if (device->wd_timeout)
313 313 device->wd_timer = timeout(heci_wd_timer, device, 1);
314 314
315 315 DBG("heci driver initialization successful.\n");
316 316 return (0);
317 317
318 318 release_hw:
319 319 /* disable interrupts */
320 320 device->host_hw_state = read_heci_register(device, H_CSR);
321 321 heci_csr_disable_interrupts(device);
322 322
323 323 release_irq:
324 324 ddi_remove_intr(dip, 0, device->sc_iblk);
325 325 unmap_memory:
326 326 if (device->mem_addr)
327 327 ddi_regs_map_free(&device->io_handle);
328 328 fini_heci_device:
329 329 fini_heci_device(device);
330 330 end:
331 331 cmn_err(CE_WARN, "heci driver initialization failed.\n");
332 332 return (err);
333 333 }
334 334
335 335 void
336 336 heci_destroy_locks(struct iamt_heci_device *device_object)
337 337 {
338 338
339 339 mutex_destroy(&device_object->iamthif_file_ext.file_lock);
340 340 mutex_destroy(&device_object->iamthif_file_ext.read_io_lock);
341 341 mutex_destroy(&device_object->iamthif_file_ext.write_io_lock);
342 342
343 343 mutex_destroy(&device_object->wd_file_ext.file_lock);
344 344 mutex_destroy(&device_object->wd_file_ext.read_io_lock);
345 345 mutex_destroy(&device_object->wd_file_ext.write_io_lock);
346 346 mutex_destroy(&device_object->device_lock);
347 347
348 348 cv_destroy(&device_object->iamthif_file_ext.rx_wait);
349 349 cv_destroy(&device_object->wd_file_ext.rx_wait);
350 350 cv_destroy(&device_object->wait_recvd_msg);
351 351 cv_destroy(&device_object->wait_stop_wd);
352 352 }
353 353
354 354 /*
355 355 * heci_remove - Device Removal Routine
356 356 *
357 357 * @pdev: PCI device information struct
358 358 *
359 359 * heci_remove is called by the PCI subsystem to alert the driver
360 360 * that it should release a PCI device.
361 361 */
362 362 static int
363 363 heci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
364 364 {
365 365 struct iamt_heci_device *dev;
366 366 int err;
367 367
368 368 dev = ddi_get_soft_state(heci_soft_state_p, ddi_get_instance(dip));
369 369 ASSERT(dev != NULL);
370 370
371 371 switch (cmd) {
372 372 case DDI_SUSPEND:
373 373 err = heci_suspend(dip);
374 374 if (err)
375 375 return (DDI_FAILURE);
376 376 else
377 377 return (DDI_SUCCESS);
378 378
379 379 case DDI_DETACH:
380 380 break;
381 381
382 382 default:
383 383 return (DDI_FAILURE);
384 384 }
385 385
386 386 if (dev->wd_timer)
387 387 (void) untimeout(dev->wd_timer);
388 388
389 389 mutex_enter(&dev->device_lock);
390 390 if (dev->wd_file_ext.state == HECI_FILE_CONNECTED &&
391 391 dev->wd_timeout) {
392 392 dev->wd_timeout = 0;
393 393 dev->wd_due_counter = 0;
394 394 (void) memcpy(dev->wd_data, stop_wd_params,
395 395 HECI_WD_PARAMS_SIZE);
396 396 dev->stop = 1;
397 397 if (dev->host_buffer_is_empty &&
398 398 flow_ctrl_creds(dev, &dev->wd_file_ext)) {
399 399 dev->host_buffer_is_empty = 0;
400 400
401 401 if (!heci_send_wd(dev)) {
402 402 DBG("send stop WD failed\n");
403 403 } else
404 404 flow_ctrl_reduce(dev, &dev->wd_file_ext);
405 405
406 406 dev->wd_pending = 0;
407 407 } else
408 408 dev->wd_pending = 1;
409 409
410 410 dev->wd_stoped = 0;
411 411
412 412 err = 0;
413 413 while (!dev->wd_stoped && err != -1) {
414 414 err = cv_reltimedwait(&dev->wait_stop_wd,
415 415 &dev->device_lock, 10*HZ, TR_CLOCK_TICK);
416 416 }
417 417
418 418 if (!dev->wd_stoped) {
419 419 DBG("stop wd failed to complete.\n");
420 420 } else {
421 421 DBG("stop wd complete.\n");
422 422 }
423 423
424 424 }
425 425
426 426 mutex_exit(&dev->device_lock);
427 427
428 428 if (dev->iamthif_file_ext.state == HECI_FILE_CONNECTED) {
429 429 dev->iamthif_file_ext.state = HECI_FILE_DISCONNECTING;
430 430 (void) heci_disconnect_host_client(dev,
431 431 &dev->iamthif_file_ext);
432 432 }
433 433 if (dev->wd_file_ext.state == HECI_FILE_CONNECTED) {
434 434 dev->wd_file_ext.state = HECI_FILE_DISCONNECTING;
435 435 (void) heci_disconnect_host_client(dev,
436 436 &dev->wd_file_ext);
437 437 }
438 438
439 439
440 440 /* remove entry if already in list */
441 441 DBG("list del iamthif and wd file list.\n");
442 442 heci_remove_client_from_file_list(dev, dev->wd_file_ext.
443 443 host_client_id);
444 444 heci_remove_client_from_file_list(dev,
445 445 dev->iamthif_file_ext.host_client_id);
446 446
447 447 dev->iamthif_current_cb = NULL;
448 448 dev->iamthif_file_ext.file = NULL;
449 449
450 450 /* disable interrupts */
451 451 heci_csr_disable_interrupts(dev);
452 452
453 453 ddi_remove_intr(dip, 0, dev->sc_iblk);
454 454
455 455 if (dev->work)
456 456 ddi_taskq_destroy(dev->work);
457 457 if (dev->reinit_tsk)
458 458 ddi_taskq_destroy(dev->reinit_tsk);
459 459 if (dev->mem_addr)
460 460 ddi_regs_map_free(&dev->io_handle);
461 461
462 462 if (dev->me_clients && dev->num_heci_me_clients > 0) {
463 463 kmem_free(dev->me_clients, sizeof (struct heci_me_client) *
464 464 dev->num_heci_me_clients);
465 465 }
466 466
467 467 dev->num_heci_me_clients = 0;
468 468
469 469 heci_destroy_locks(dev);
470 470
471 471 ddi_remove_minor_node(dip, NULL);
472 472 ddi_soft_state_free(heci_soft_state_p, ddi_get_instance(dip));
473 473
474 474 return (DDI_SUCCESS);
475 475 }
476 476
477 477
478 478 static int
479 479 heci_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
480 480 {
481 481 int error = DDI_SUCCESS;
482 482 struct iamt_heci_device *device;
483 483 int minor, instance;
484 484
485 485 _NOTE(ARGUNUSED(dip))
486 486
487 487 switch (cmd) {
488 488 case DDI_INFO_DEVT2DEVINFO:
489 489 minor = getminor((dev_t)arg);
490 490 instance = HECI_MINOR_TO_INSTANCE(minor);
491 491 if (!(device = ddi_get_soft_state(heci_soft_state_p, instance)))
492 492 *result = NULL;
493 493 else
494 494 *result = device->dip;
495 495 break;
496 496 case DDI_INFO_DEVT2INSTANCE:
497 497 minor = getminor((dev_t)arg);
498 498 instance = HECI_MINOR_TO_INSTANCE(minor);
499 499 *result = (void *)((long)minor);
500 500 break;
501 501 default:
502 502 error = DDI_FAILURE;
503 503 break;
504 504 }
505 505 return (error);
506 506 }
507 507 /*
508 508 * heci_clear_list - remove all callbacks associated with file
509 509 * from heci_cb_list
510 510 *
511 511 * @file: file information struct
512 512 * @heci_cb_list: callbacks list
513 513 *
514 514 * heci_clear_list is called to clear resources associated with file
515 515 * when application calls close function or Ctrl-C was pressed
516 516 *
517 517 * @return 1 if callback removed from the list, 0 otherwise
518 518 */
519 519 static int
520 520 heci_clear_list(struct iamt_heci_device *dev,
521 521 struct heci_file *file, struct list_node *heci_cb_list)
522 522 {
523 523 struct heci_cb_private *priv_cb_pos = NULL;
524 524 struct heci_cb_private *priv_cb_next = NULL;
525 525 struct heci_file *file_temp;
526 526 int rets = 0;
527 527
528 528 /* list all list member */
529 529 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
530 530 heci_cb_list, cb_list, struct heci_cb_private) {
531 531 file_temp = (struct heci_file *)priv_cb_pos->file_object;
532 532 /* check if list member associated with a file */
533 533 if (file_temp == file) {
534 534 /* remove member from the list */
535 535 list_del(&priv_cb_pos->cb_list);
536 536 /* check if cb equal to current iamthif cb */
537 537 if (dev->iamthif_current_cb == priv_cb_pos) {
538 538 dev->iamthif_current_cb = NULL;
539 539 /* send flow control to iamthif client */
540 540 if (!heci_send_flow_control(dev,
541 541 &dev->iamthif_file_ext)) {
542 542 DBG("sending flow control failed\n");
543 543 }
544 544 }
545 545 /* free all allocated buffers */
546 546 heci_free_cb_private(priv_cb_pos);
547 547 rets = 1;
548 548 }
549 549 }
550 550 return (rets);
551 551 }
552 552
553 553 /*
554 554 * heci_clear_lists - remove all callbacks associated with file
555 555 *
556 556 * @dev: device information struct
557 557 * @file: file information struct
558 558 *
559 559 * heci_clear_lists is called to clear resources associated with file
560 560 * when application calls close function or Ctrl-C was pressed
561 561 *
562 562 * @return 1 if callback removed from the list, 0 otherwise
563 563 */
564 564 static int
565 565 heci_clear_lists(struct iamt_heci_device *dev, struct heci_file *file)
566 566 {
567 567 int rets = 0;
568 568
569 569 /* remove callbacks associated with a file */
570 570 (void) heci_clear_list(dev, file, &dev->pthi_cmd_list.heci_cb.cb_list);
571 571 if (heci_clear_list(dev, file,
572 572 &dev->pthi_read_complete_list.heci_cb.cb_list))
573 573 rets = 1;
574 574
575 575 (void) heci_clear_list(dev, file, &dev->ctrl_rd_list.heci_cb.cb_list);
576 576
577 577 if (heci_clear_list(dev, file, &dev->ctrl_wr_list.heci_cb.cb_list))
578 578 rets = 1;
579 579
580 580 if (heci_clear_list(dev, file,
581 581 &dev->write_waiting_list.heci_cb.cb_list))
582 582 rets = 1;
583 583
584 584 if (heci_clear_list(dev, file, &dev->write_list.heci_cb.cb_list))
585 585 rets = 1;
586 586
587 587 /* check if iamthif_current_cb not NULL */
588 588 if (dev->iamthif_current_cb && (!rets)) {
589 589 /* check file and iamthif current cb association */
590 590 if (dev->iamthif_current_cb->file_object == file) {
591 591 /* remove cb */
592 592 heci_free_cb_private(dev->iamthif_current_cb);
593 593 dev->iamthif_current_cb = NULL;
594 594 rets = 1;
595 595 }
596 596 }
597 597 return (rets);
598 598 }
599 599
600 600 /*
601 601 * heci_open - the open function
602 602 */
603 603 static int
604 604 heci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
605 605 {
606 606 struct iamt_heci_device *dev;
607 607 struct heci_file_private *file_ext = NULL;
608 608 int minor, if_num, instance;
609 609 struct heci_file *file;
610 610
611 611 _NOTE(ARGUNUSED(flags, credp))
612 612
613 613 minor = getminor(*devp);
614 614
615 615 DBG("heci_open: enter...\n");
616 616
617 617 /*
618 618 * Make sure the open is for the right file type.
619 619 */
620 620 if (otyp != OTYP_CHR)
621 621 return (EINVAL);
622 622
623 623 instance = HECI_MINOR_TO_INSTANCE(minor);
624 624 if_num = HECI_MINOR_TO_IFNUM(minor);
625 625
626 626 dev = ddi_get_soft_state(heci_soft_state_p, instance);
627 627
628 628 if ((if_num < HECI_MINOR_NUMBER) || (!dev))
629 629 return (-ENODEV);
630 630
631 631 file_ext = heci_alloc_file_private(NULL);
632 632 if (file_ext == NULL)
633 633 return (-ENOMEM);
634 634
635 635 mutex_enter(&dev->device_lock);
636 636 if (dev->heci_state != HECI_ENABLED) {
637 637 mutex_exit(&dev->device_lock);
638 638 kmem_free(file_ext, sizeof (struct heci_file_private));
639 639 file_ext = NULL;
640 640 return (-ENODEV);
641 641 }
642 642 if (dev->open_handle_count >= HECI_MAX_OPEN_HANDLE_COUNT) {
643 643 mutex_exit(&dev->device_lock);
644 644 kmem_free(file_ext, sizeof (struct heci_file_private));
645 645 file_ext = NULL;
646 646 return (-ENFILE);
647 647 }
648 648 dev->open_handle_count++;
649 649 list_add_tail(&file_ext->link, &dev->file_list);
650 650 while ((dev->heci_host_clients[dev->current_host_client_id / 8]
651 651 & (1 << (dev->current_host_client_id % 8))) != 0) {
652 652
653 653 dev->current_host_client_id++;
654 654 dev->current_host_client_id %= HECI_MAX_OPEN_HANDLE_COUNT;
655 655 DBG("current_host_client_id = %d\n",
656 656 dev->current_host_client_id);
657 657 DBG("dev->open_handle_count = %lu\n",
658 658 dev->open_handle_count);
659 659 }
660 660 DBG("current_host_client_id = %d\n", dev->current_host_client_id);
661 661 file_ext->host_client_id = dev->current_host_client_id;
662 662 *devp = makedevice(getmajor(*devp),
663 663 MAKE_MINOR_NUM(dev->current_host_client_id, instance));
664 664 file = &dev->files[dev->current_host_client_id];
665 665 dev->heci_host_clients[file_ext->host_client_id / 8] |=
666 666 (1 << (file_ext->host_client_id % 8));
667 667 mutex_exit(&dev->device_lock);
668 668 mutex_enter(&file_ext->file_lock);
669 669 file_ext->state = HECI_FILE_INITIALIZING;
670 670 file_ext->sm_state = 0;
671 671
672 672 file->private_data = file_ext;
673 673 mutex_exit(&file_ext->file_lock);
674 674
675 675 return (0);
676 676 }
677 677
678 678 /*
679 679 * heci_close - the close function
680 680 */
681 681 static int
682 682 heci_close(dev_t devt, int flag, int otyp, struct cred *cred)
683 683 {
684 684 int rets = 0;
685 685 int minor, if_num, instance;
686 686 struct heci_file_private *file_ext;
687 687 struct heci_cb_private *priv_cb = NULL;
688 688 struct iamt_heci_device *dev;
689 689 struct heci_file *file;
690 690
691 691 _NOTE(ARGUNUSED(flag, otyp, cred))
692 692
693 693 minor = getminor(devt);
694 694
695 695 instance = HECI_MINOR_TO_INSTANCE(minor);
696 696 if_num = HECI_MINOR_TO_IFNUM(minor);
697 697
698 698 dev = ddi_get_soft_state(heci_soft_state_p, instance);
699 699
700 700 file = &dev->files[if_num];
701 701 file_ext = file->private_data;
702 702
703 703 if ((if_num < HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
704 704 return (-ENODEV);
705 705
706 706 if (file_ext != &dev->iamthif_file_ext) {
707 707 mutex_enter(&file_ext->file_lock);
708 708 if (file_ext->state == HECI_FILE_CONNECTED) {
709 709 file_ext->state = HECI_FILE_DISCONNECTING;
710 710 mutex_exit(&file_ext->file_lock);
711 711 DBG("disconnecting client host client = %d, "
712 712 "ME client = %d\n",
713 713 file_ext->host_client_id,
714 714 file_ext->me_client_id);
715 715 rets = heci_disconnect_host_client(dev, file_ext);
716 716 mutex_enter(&file_ext->file_lock);
717 717 }
718 718 mutex_enter(&dev->device_lock);
719 719 heci_flush_queues(dev, file_ext);
720 720 DBG("remove client host client = %d, ME client = %d\n",
721 721 file_ext->host_client_id,
722 722 file_ext->me_client_id);
723 723
724 724 if (dev->open_handle_count > 0) {
725 725 dev->heci_host_clients[file_ext->host_client_id / 8] &=
726 726 ~(1 << (file_ext->host_client_id % 8));
727 727 dev->open_handle_count--;
728 728 }
729 729 heci_remove_client_from_file_list(dev,
730 730 file_ext->host_client_id);
731 731
732 732 /* free read cb */
733 733 if (file_ext->read_cb != NULL) {
734 734 priv_cb = find_read_list_entry(dev, file_ext);
735 735 /* Remove entry from read list */
736 736 if (priv_cb != NULL)
737 737 list_del(&priv_cb->cb_list);
738 738
739 739 priv_cb = file_ext->read_cb;
740 740 file_ext->read_cb = NULL;
741 741 }
742 742
743 743 mutex_exit(&dev->device_lock);
744 744 file->private_data = NULL;
745 745 mutex_exit(&file_ext->file_lock);
746 746
747 747 if (priv_cb != NULL)
748 748 heci_free_cb_private(priv_cb);
749 749
750 750 heci_free_file_private(file_ext);
751 751 } else {
752 752 mutex_enter(&dev->device_lock);
753 753
754 754 if (dev->open_handle_count > 0)
755 755 dev->open_handle_count--;
756 756
757 757 if (dev->iamthif_file_object == file &&
758 758 dev->iamthif_state != HECI_IAMTHIF_IDLE) {
759 759 DBG("pthi canceled iamthif state %d\n",
760 760 dev->iamthif_state);
761 761 dev->iamthif_canceled = 1;
762 762 if (dev->iamthif_state == HECI_IAMTHIF_READ_COMPLETE) {
763 763 DBG("run next pthi iamthif cb\n");
764 764 run_next_iamthif_cmd(dev);
765 765 }
766 766 }
767 767
768 768 if (heci_clear_lists(dev, file))
769 769 dev->iamthif_state = HECI_IAMTHIF_IDLE;
770 770
771 771 mutex_exit(&dev->device_lock);
772 772 }
773 773 return (rets);
774 774 }
775 775
776 776 static struct heci_cb_private *
777 777 find_read_list_entry(struct iamt_heci_device *dev,
778 778 struct heci_file_private *file_ext)
779 779 {
780 780 struct heci_cb_private *priv_cb_pos = NULL;
781 781 struct heci_cb_private *priv_cb_next = NULL;
782 782 struct heci_file_private *file_ext_list_temp;
783 783
784 784 if (dev->read_list.status == 0 &&
785 785 !list_empty(&dev->read_list.heci_cb.cb_list)) {
786 786
787 787 DBG("remove read_list CB \n");
788 788 list_for_each_entry_safe(priv_cb_pos,
789 789 priv_cb_next,
790 790 &dev->read_list.heci_cb.cb_list, cb_list,
791 791 struct heci_cb_private) {
792 792
793 793 file_ext_list_temp = (struct heci_file_private *)
794 794 priv_cb_pos->file_private;
795 795
796 796 if ((file_ext_list_temp != NULL) &&
797 797 heci_fe_same_id(file_ext, file_ext_list_temp))
798 798 return (priv_cb_pos);
799 799
800 800 }
801 801 }
802 802 return (NULL);
803 803 }
804 804
805 805 /*
806 806 * heci_read - the read client message function.
807 807 */
808 808 static int
809 809 heci_read(dev_t devt, struct uio *uio_p, cred_t *cred_p)
810 810 {
811 811 int i;
812 812 int rets = 0;
813 813 size_t length;
814 814 struct heci_file *file;
815 815 struct heci_file_private *file_ext;
816 816 struct heci_cb_private *priv_cb_pos = NULL;
817 817 int instance, minor, if_num, err;
818 818 struct heci_cb_private *priv_cb = NULL;
819 819 struct iamt_heci_device *dev;
820 820
821 821 _NOTE(ARGUNUSED(cred_p))
822 822
823 823 minor = getminor(devt);
824 824
825 825 instance = HECI_MINOR_TO_INSTANCE(minor);
826 826 if_num = HECI_MINOR_TO_IFNUM(minor);
827 827
828 828 dev = ddi_get_soft_state(heci_soft_state_p, instance);
829 829
830 830 file = &dev->files[if_num];
831 831 file_ext = file->private_data;
832 832
833 833 if ((if_num < HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
834 834 return (-ENODEV);
835 835
836 836 mutex_enter(&dev->device_lock);
837 837 if (dev->heci_state != HECI_ENABLED) {
838 838 mutex_exit(&dev->device_lock);
839 839 return (-ENODEV);
840 840 }
841 841 mutex_exit(&dev->device_lock);
842 842 if (!file_ext)
843 843 return (-ENODEV);
844 844
845 845 mutex_enter(&file_ext->file_lock);
846 846 if ((file_ext->sm_state & HECI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
847 847 mutex_exit(&file_ext->file_lock);
848 848 /* Do not allow to read watchdog client */
849 849 for (i = 0; i < dev->num_heci_me_clients; i++) {
850 850 if (memcmp(&heci_wd_guid,
851 851 &dev->me_clients[i].props.protocol_name,
852 852 sizeof (struct guid)) == 0) {
853 853 if (file_ext->me_client_id ==
854 854 dev->me_clients[i].client_id)
855 855 return (-EBADF);
856 856 }
857 857 }
858 858 } else {
859 859 file_ext->sm_state &= ~HECI_WD_STATE_INDEPENDENCE_MSG_SENT;
860 860 mutex_exit(&file_ext->file_lock);
861 861 }
862 862
863 863 if (file_ext == &dev->iamthif_file_ext) {
864 864 rets = pthi_read(dev, if_num, file, uio_p);
865 865 goto out;
866 866 }
867 867
868 868 if (file_ext->read_cb &&
869 869 file_ext->read_cb->information > UIO_OFFSET(uio_p)) {
870 870 priv_cb = file_ext->read_cb;
871 871 goto copy_buffer;
872 872 } else if (file_ext->read_cb && file_ext->read_cb->information > 0 &&
873 873 file_ext->read_cb->information <= UIO_OFFSET(uio_p)) {
874 874 priv_cb = file_ext->read_cb;
875 875 rets = 0;
876 876 goto free;
877 877 } else if (
878 878 (!file_ext->read_cb || file_ext->read_cb->information == 0) &&
879 879 UIO_OFFSET(uio_p) > 0) {
880 880 /* Offset needs to be cleaned for contingous reads */
881 881 UIO_OFFSET(uio_p) = 0;
882 882 rets = 0;
883 883 goto out;
884 884 }
885 885
886 886 mutex_enter(&file_ext->read_io_lock);
887 887 err = heci_start_read(dev, if_num, file_ext);
888 888 if (err != 0 && err != -EBUSY) {
889 889 DBG("heci start read failure with status = %d\n", err);
890 890 mutex_exit(&file_ext->read_io_lock);
891 891 rets = err;
892 892 goto out;
893 893 }
894 894 while (HECI_READ_COMPLETE != file_ext->reading_state &&
895 895 HECI_FILE_INITIALIZING != file_ext->state &&
896 896 HECI_FILE_DISCONNECTED != file_ext->state &&
897 897 HECI_FILE_DISCONNECTING != file_ext->state) {
898 898 mutex_exit(&file_ext->read_io_lock);
899 899 mutex_enter(&dev->device_lock);
900 900 if (cv_wait_sig(&file_ext->rx_wait, &dev->device_lock) == 0) {
901 901 mutex_exit(&dev->device_lock);
902 902 priv_cb = file_ext->read_cb;
903 903 rets = -EINTR;
904 904 goto free;
905 905 }
906 906 mutex_exit(&dev->device_lock);
907 907
908 908
909 909 if (HECI_FILE_INITIALIZING == file_ext->state ||
910 910 HECI_FILE_DISCONNECTED == file_ext->state ||
911 911 HECI_FILE_DISCONNECTING == file_ext->state) {
912 912 rets = -EBUSY;
913 913 goto out;
914 914 }
915 915 mutex_enter(&file_ext->read_io_lock);
916 916 }
917 917
918 918 priv_cb = file_ext->read_cb;
919 919
920 920 if (!priv_cb) {
921 921 mutex_exit(&file_ext->read_io_lock);
922 922 return (-ENODEV);
923 923 }
924 924 if (file_ext->reading_state != HECI_READ_COMPLETE) {
925 925 mutex_exit(&file_ext->read_io_lock);
926 926 return (0);
927 927 }
928 928 mutex_exit(&file_ext->read_io_lock);
929 929 /* now copy the data to user space */
930 930 copy_buffer:
931 931 DBG("priv_cb->response_buffer size - %d\n",
932 932 priv_cb->response_buffer.size);
933 933 DBG("priv_cb->information - %lu\n", priv_cb->information);
934 934 if (uio_p->uio_resid == 0 || uio_p->uio_resid < priv_cb->information) {
935 935 rets = -EMSGSIZE;
936 936 goto free;
937 937 }
938 938 length = (uio_p->uio_resid <
939 939 (priv_cb->information - uio_p->uio_offset) ?
940 940 uio_p->uio_resid : (priv_cb->information - uio_p->uio_offset));
941 941
942 942 if (uiomove(priv_cb->response_buffer.data,
943 943 length, UIO_READ, uio_p)) {
944 944 rets = -EFAULT;
945 945 goto free;
946 946 }
947 947 else
948 948 rets = 0;
949 949
950 950 free:
951 951 mutex_enter(&dev->device_lock);
952 952 priv_cb_pos = find_read_list_entry(dev, file_ext);
953 953 /* Remove entry from read list */
954 954 if (priv_cb_pos != NULL)
955 955 list_del(&priv_cb_pos->cb_list);
956 956 mutex_exit(&dev->device_lock);
957 957 heci_free_cb_private(priv_cb);
958 958 mutex_enter(&file_ext->read_io_lock);
959 959 file_ext->reading_state = HECI_IDLE;
960 960 file_ext->read_cb = NULL;
961 961 file_ext->read_pending = 0;
962 962 mutex_exit(&file_ext->read_io_lock);
963 963 out: DBG("end heci read rets= %d\n", rets);
964 964 return (rets);
965 965 }
966 966
967 967 /*
968 968 * heci_write - the write function.
969 969 */
970 970 static int
971 971 heci_write(dev_t devt, struct uio *uio_p, struct cred *cred)
972 972 {
973 973 int rets = 0;
974 974 uint8_t i;
975 975 size_t length;
976 976 struct heci_file_private *file_ext;
977 977 struct heci_cb_private *priv_write_cb = NULL;
978 978 struct heci_msg_hdr heci_hdr;
979 979 struct iamt_heci_device *dev;
980 980 unsigned long currtime = ddi_get_time();
981 981 int instance, minor, if_num, err;
982 982 struct heci_file *file;
983 983
984 984 _NOTE(ARGUNUSED(cred))
985 985 DBG("heci_write enter...\n");
986 986
987 987 minor = getminor(devt);
988 988 instance = HECI_MINOR_TO_INSTANCE(minor);
989 989 if_num = HECI_MINOR_TO_IFNUM(minor);
990 990
991 991 dev = ddi_get_soft_state(heci_soft_state_p, instance);
992 992
993 993 file = &dev->files[if_num];
994 994 file_ext = file->private_data;
995 995 if ((if_num < HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
996 996 return (-ENODEV);
997 997
998 998 mutex_enter(&dev->device_lock);
999 999
1000 1000 if (dev->heci_state != HECI_ENABLED) {
1001 1001 mutex_exit(&dev->device_lock);
1002 1002 return (-ENODEV);
1003 1003 }
1004 1004 if (file_ext == &dev->iamthif_file_ext) {
1005 1005 priv_write_cb = find_pthi_read_list_entry(dev, file);
1006 1006 if ((priv_write_cb != NULL) &&
1007 1007 (((currtime - priv_write_cb->read_time) >
1008 1008 IAMTHIF_READ_TIMER) ||
1009 1009 (file_ext->reading_state == HECI_READ_COMPLETE))) {
1010 1010 UIO_OFFSET(uio_p) = 0;
1011 1011 list_del(&priv_write_cb->cb_list);
1012 1012 heci_free_cb_private(priv_write_cb);
1013 1013 priv_write_cb = NULL;
1014 1014 }
1015 1015 }
1016 1016
1017 1017 /* free entry used in read */
1018 1018 if (file_ext->reading_state == HECI_READ_COMPLETE) {
1019 1019 UIO_OFFSET(uio_p) = 0;
1020 1020 priv_write_cb = find_read_list_entry(dev, file_ext);
1021 1021 if (priv_write_cb != NULL) {
1022 1022 list_del(&priv_write_cb->cb_list);
1023 1023 heci_free_cb_private(priv_write_cb);
1024 1024 priv_write_cb = NULL;
1025 1025 mutex_enter(&file_ext->read_io_lock);
1026 1026 file_ext->reading_state = HECI_IDLE;
1027 1027 file_ext->read_cb = NULL;
1028 1028 file_ext->read_pending = 0;
1029 1029 mutex_exit(&file_ext->read_io_lock);
1030 1030 }
1031 1031 } else if (file_ext->reading_state == HECI_IDLE &&
1032 1032 file_ext->read_pending == 0)
1033 1033 UIO_OFFSET(uio_p) = 0;
1034 1034
1035 1035 mutex_exit(&dev->device_lock);
1036 1036
1037 1037 priv_write_cb = kmem_zalloc(sizeof (struct heci_cb_private), KM_SLEEP);
1038 1038 if (!priv_write_cb)
1039 1039 return (-ENOMEM);
1040 1040
1041 1041 priv_write_cb->file_object = file;
1042 1042 priv_write_cb->file_private = file_ext;
1043 1043 priv_write_cb->request_buffer.data =
1044 1044 kmem_zalloc(uio_p->uio_resid, KM_SLEEP);
1045 1045 if (!priv_write_cb->request_buffer.data) {
1046 1046 kmem_free(priv_write_cb, sizeof (struct heci_cb_private));
1047 1047 return (-ENOMEM);
1048 1048 }
1049 1049 length = (int)uio_p->uio_resid;
1050 1050 DBG("length =%d\n", (int)length);
1051 1051
1052 1052 err = uiomove(priv_write_cb->request_buffer.data,
1053 1053 length, UIO_WRITE, uio_p);
1054 1054 if (err) {
1055 1055 rets = err;
1056 1056 goto fail;
1057 1057 }
1058 1058
1059 1059 #define UBUFF UIO_BUFF(uio_p)
1060 1060
1061 1061 mutex_enter(&file_ext->file_lock);
1062 1062 file_ext->sm_state = 0;
1063 1063 if ((length == 4) &&
1064 1064 ((memcmp(heci_wd_state_independence_msg[0], UBUFF, 4) == 0) ||
1065 1065 (memcmp(heci_wd_state_independence_msg[1], UBUFF, 4) == 0) ||
1066 1066 (memcmp(heci_wd_state_independence_msg[2], UBUFF, 4) == 0)))
1067 1067
1068 1068 file_ext->sm_state |= HECI_WD_STATE_INDEPENDENCE_MSG_SENT;
1069 1069
1070 1070 mutex_exit(&file_ext->file_lock);
1071 1071
1072 1072 LIST_INIT_HEAD(&priv_write_cb->cb_list);
1073 1073 if (file_ext == &dev->iamthif_file_ext) {
1074 1074 priv_write_cb->response_buffer.data =
1075 1075 kmem_zalloc(IAMTHIF_MTU, KM_SLEEP);
1076 1076 if (!priv_write_cb->response_buffer.data) {
1077 1077 rets = -ENOMEM;
1078 1078 goto fail;
1079 1079 }
1080 1080 mutex_enter(&dev->device_lock);
1081 1081 if (dev->heci_state != HECI_ENABLED) {
1082 1082 mutex_exit(&dev->device_lock);
1083 1083 rets = -ENODEV;
1084 1084 goto fail;
1085 1085 }
1086 1086 for (i = 0; i < dev->num_heci_me_clients; i++) {
1087 1087 if (dev->me_clients[i].client_id ==
1088 1088 dev->iamthif_file_ext.me_client_id)
1089 1089 break;
1090 1090 }
1091 1091
1092 1092 ASSERT(dev->me_clients[i].client_id == file_ext->me_client_id);
1093 1093 if ((i == dev->num_heci_me_clients) ||
1094 1094 (dev->me_clients[i].client_id !=
1095 1095 dev->iamthif_file_ext.me_client_id)) {
1096 1096
1097 1097 mutex_exit(&dev->device_lock);
1098 1098 rets = -ENODEV;
1099 1099 goto fail;
1100 1100 } else if ((length >
1101 1101 dev->me_clients[i].props.max_msg_length) ||
1102 1102 (length == 0)) {
1103 1103 mutex_exit(&dev->device_lock);
1104 1104 rets = -EMSGSIZE;
1105 1105 goto fail;
1106 1106 }
1107 1107
1108 1108
1109 1109 priv_write_cb->response_buffer.size = IAMTHIF_MTU;
1110 1110 priv_write_cb->major_file_operations = HECI_IOCTL;
1111 1111 priv_write_cb->information = 0;
1112 1112 priv_write_cb->request_buffer.size = (uint32_t)length;
1113 1113 if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) {
1114 1114 mutex_exit(&dev->device_lock);
1115 1115 rets = -ENODEV;
1116 1116 goto fail;
1117 1117 }
1118 1118
1119 1119 if (!list_empty(&dev->pthi_cmd_list.heci_cb.cb_list) ||
1120 1120 dev->iamthif_state != HECI_IAMTHIF_IDLE) {
1121 1121 DBG("pthi_state = %d\n", (int)dev->iamthif_state);
1122 1122 DBG("add PTHI cb to pthi cmd waiting list\n");
1123 1123 list_add_tail(&priv_write_cb->cb_list,
1124 1124 &dev->pthi_cmd_list.heci_cb.cb_list);
1125 1125 rets = 0; /* length; */
1126 1126 } else {
1127 1127 DBG("call pthi write\n");
1128 1128 rets = pthi_write(dev, priv_write_cb);
1129 1129
1130 1130 if (rets != 0) {
1131 1131 DBG("pthi write failed with status = %d\n",
1132 1132 rets);
1133 1133 mutex_exit(&dev->device_lock);
1134 1134 goto fail;
1135 1135 }
1136 1136 rets = 0; /* length; */
1137 1137 }
1138 1138 mutex_exit(&dev->device_lock);
1139 1139 return (rets);
1140 1140 }
1141 1141
1142 1142 priv_write_cb->major_file_operations = HECI_WRITE;
1143 1143 /* make sure information is zero before we start */
1144 1144
1145 1145 priv_write_cb->information = 0;
1146 1146 priv_write_cb->request_buffer.size = (uint32_t)length;
1147 1147
1148 1148 mutex_enter(&dev->device_lock);
1149 1149 mutex_enter(&file_ext->write_io_lock);
1150 1150 DBG("host client = %d, ME client = %d\n",
1151 1151 file_ext->host_client_id, file_ext->me_client_id);
1152 1152 if (file_ext->state != HECI_FILE_CONNECTED) {
1153 1153 rets = -ENODEV;
1154 1154 DBG("host client = %d, is not connected to ME client = %d",
1155 1155 file_ext->host_client_id,
1156 1156 file_ext->me_client_id);
1157 1157
1158 1158 goto unlock;
1159 1159 }
1160 1160 for (i = 0; i < dev->num_heci_me_clients; i++) {
1161 1161 if (dev->me_clients[i].client_id ==
1162 1162 file_ext->me_client_id)
1163 1163 break;
1164 1164 }
1165 1165 ASSERT(dev->me_clients[i].client_id == file_ext->me_client_id);
1166 1166 if (i == dev->num_heci_me_clients) {
1167 1167 rets = -ENODEV;
1168 1168 goto unlock;
1169 1169 }
1170 1170 if (length > dev->me_clients[i].props.max_msg_length || length == 0) {
1171 1171 rets = -EINVAL;
1172 1172 goto unlock;
1173 1173 }
1174 1174 priv_write_cb->file_private = file_ext;
1175 1175
1176 1176 if (flow_ctrl_creds(dev, file_ext) &&
1177 1177 dev->host_buffer_is_empty) {
1178 1178 dev->host_buffer_is_empty = 0;
1179 1179 if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
1180 1180 sizeof (uint32_t)) - sizeof (struct heci_msg_hdr))) {
1181 1181
1182 1182 heci_hdr.length =
1183 1183 (((dev->host_hw_state & H_CBD) >> 24) *
1184 1184 sizeof (uint32_t)) -
1185 1185 sizeof (struct heci_msg_hdr);
1186 1186 heci_hdr.msg_complete = 0;
1187 1187 } else {
1188 1188 heci_hdr.length = (uint32_t)length;
1189 1189 heci_hdr.msg_complete = 1;
1190 1190 }
1191 1191 heci_hdr.host_addr = file_ext->host_client_id;
1192 1192 heci_hdr.me_addr = file_ext->me_client_id;
1193 1193 heci_hdr.reserved = 0;
1194 1194 DBG("call heci_write_message header=%08x.\n",
1195 1195 *((uint32_t *)(void *)&heci_hdr));
1196 1196 /* protect heci low level write */
1197 1197 if (!heci_write_message(dev, &heci_hdr,
1198 1198 (unsigned char *)(priv_write_cb->request_buffer.data),
1199 1199 heci_hdr.length)) {
1200 1200
1201 1201 mutex_exit(&file_ext->write_io_lock);
1202 1202 mutex_exit(&dev->device_lock);
1203 1203 heci_free_cb_private(priv_write_cb);
1204 1204 rets = -ENODEV;
1205 1205 priv_write_cb->information = 0;
1206 1206 return (rets);
1207 1207 }
1208 1208 file_ext->writing_state = HECI_WRITING;
1209 1209 priv_write_cb->information = heci_hdr.length;
1210 1210 if (heci_hdr.msg_complete) {
1211 1211 flow_ctrl_reduce(dev, file_ext);
1212 1212 list_add_tail(&priv_write_cb->cb_list,
1213 1213 &dev->write_waiting_list.heci_cb.cb_list);
1214 1214 } else {
1215 1215 list_add_tail(&priv_write_cb->cb_list,
1216 1216 &dev->write_list.heci_cb.cb_list);
1217 1217 }
1218 1218
1219 1219 } else {
1220 1220
1221 1221 priv_write_cb->information = 0;
1222 1222 file_ext->writing_state = HECI_WRITING;
1223 1223 list_add_tail(&priv_write_cb->cb_list,
1224 1224 &dev->write_list.heci_cb.cb_list);
1225 1225 }
1226 1226 mutex_exit(&file_ext->write_io_lock);
1227 1227 mutex_exit(&dev->device_lock);
1228 1228 return (0);
1229 1229
1230 1230 unlock:
1231 1231 mutex_exit(&file_ext->write_io_lock);
1232 1232 mutex_exit(&dev->device_lock);
1233 1233 fail:
1234 1234 heci_free_cb_private(priv_write_cb);
1235 1235 return (rets);
1236 1236
1237 1237 }
1238 1238
1239 1239 /*
1240 1240 * heci_ioctl - the IOCTL function
1241 1241 */
1242 1242 static int
1243 1243 heci_ioctl(dev_t devt, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval)
1244 1244 {
1245 1245 int rets = 0;
1246 1246 struct heci_file_private *file_ext;
1247 1247 /* in user space */
1248 1248 struct heci_message_data *u_msg = (struct heci_message_data *)arg;
1249 1249 struct heci_message_data k_msg; /* all in kernel on the stack */
1250 1250 struct iamt_heci_device *dev;
1251 1251 int instance, minor, if_num;
1252 1252 struct heci_file *file;
1253 1253
1254 1254 _NOTE(ARGUNUSED(cr, rval))
1255 1255
1256 1256 minor = getminor(devt);
1257 1257
1258 1258 instance = HECI_MINOR_TO_INSTANCE(minor);
1259 1259 if_num = HECI_MINOR_TO_IFNUM(minor);
1260 1260
1261 1261 dev = ddi_get_soft_state(heci_soft_state_p, instance);
1262 1262
1263 1263 file = &dev->files[if_num];
1264 1264 file_ext = file->private_data;
1265 1265
1266 1266 if ((if_num < HECI_MINOR_NUMBER) || (!dev) || (!file_ext))
1267 1267 return (-ENODEV);
1268 1268
1269 1269 mutex_enter(&dev->device_lock);
1270 1270 if (dev->heci_state != HECI_ENABLED) {
1271 1271 mutex_exit(&dev->device_lock);
1272 1272 return (-ENODEV);
1273 1273 }
1274 1274 mutex_exit(&dev->device_lock);
1275 1275
1276 1276 /* first copy from user all data needed */
1277 1277 if (ddi_copyin(u_msg, &k_msg, sizeof (k_msg), mode)) {
1278 1278 DBG("first copy from user all data needed filled\n");
1279 1279 return (-EFAULT);
1280 1280 }
1281 1281 #ifdef _LP64
1282 1282 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1283 1283 uint32_t addr32 = (uint32_t)(uint64_t)k_msg.data;
1284 1284 k_msg.data = (char *)(uint64_t)addr32;
1285 1285 DBG("IPL32: k_msg.data=%p\n", (void *)k_msg.data);
1286 1286 }
1287 1287 #endif
1288 1288 DBG("user message size is %d, cmd = 0x%x\n", k_msg.size, cmd);
1289 1289
1290 1290 switch (cmd) {
1291 1291 case IOCTL_HECI_GET_VERSION:
1292 1292 DBG(": IOCTL_HECI_GET_VERSION\n");
1293 1293 rets = heci_ioctl_get_version(dev, if_num, u_msg, k_msg,
1294 1294 file_ext, mode);
1295 1295 break;
1296 1296
1297 1297 case IOCTL_HECI_CONNECT_CLIENT:
1298 1298 DBG(": IOCTL_HECI_CONNECT_CLIENT.\n");
1299 1299 rets = heci_ioctl_connect_client(dev, if_num, u_msg, k_msg,
1300 1300 file, mode);
1301 1301 break;
1302 1302
1303 1303 case IOCTL_HECI_WD:
1304 1304 DBG(": IOCTL_HECI_WD.\n");
1305 1305 rets = heci_ioctl_wd(dev, if_num, k_msg, file_ext, mode);
1306 1306 break;
1307 1307
1308 1308 case IOCTL_HECI_BYPASS_WD:
1309 1309 DBG(": IOCTL_HECI_BYPASS_WD.\n");
1310 1310 rets = heci_ioctl_bypass_wd(dev, if_num, k_msg, file_ext, mode);
1311 1311 break;
1312 1312
1313 1313 default:
1314 1314 rets = -EINVAL;
1315 1315 break;
1316 1316 }
1317 1317 return (rets);
1318 1318 }
1319 1319
1320 1320 /*
1321 1321 * heci_poll - the poll function
1322 1322 */
1323 1323 static int
1324 1324 heci_poll(dev_t devt, short events, int anyyet,
1325 1325 short *reventsp, struct pollhead **phpp)
1326 1326 {
1327 1327 struct heci_file *file;
1328 1328 struct heci_file_private *file_extension;
1329 1329 struct iamt_heci_device *device = NULL;
1330 1330 int instance, minor, if_num;
1331 1331
1332 1332 _NOTE(ARGUNUSED(events))
1333 1333
1334 1334 minor = getminor(devt);
1335 1335
1336 1336 instance = HECI_MINOR_TO_INSTANCE(minor);
1337 1337 if_num = HECI_MINOR_TO_IFNUM(minor);
1338 1338
1339 1339 device = ddi_get_soft_state(heci_soft_state_p, instance);
1340 1340
1341 1341 file = &device->files[if_num];
1342 1342 file_extension = file->private_data;
1343 1343
1344 1344 if ((if_num < HECI_MINOR_NUMBER) || (!device) || (!file_extension))
1345 1345 return (-ENODEV);
1346 1346
1347 1347 mutex_enter(&device->device_lock);
1348 1348 if (device->heci_state != HECI_ENABLED) {
1349 1349 mutex_exit(&device->device_lock);
1350 1350 return (-ENXIO);
1351 1351
1352 1352 }
1353 1353
1354 1354 mutex_exit(&device->device_lock);
1355 1355
1356 1356 if (file_extension == &device->iamthif_file_ext) {
1357 1357
1358 1358 mutex_enter(&device->iamthif_file_ext.file_lock);
1359 1359
1360 1360 if (device->iamthif_state == HECI_IAMTHIF_READ_COMPLETE &&
1361 1361 device->iamthif_file_object == file) {
1362 1362 *reventsp |= (POLLIN | POLLRDNORM);
1363 1363 mutex_enter(&device->device_lock);
1364 1364 DBG("heci_poll: run next pthi cb\n");
1365 1365 run_next_iamthif_cmd(device);
1366 1366 mutex_exit(&device->device_lock);
1367 1367 } else {
1368 1368 DBG("heci_poll: iamthif no event\n");
1369 1369 *reventsp = 0;
1370 1370 if (!anyyet)
1371 1371 *phpp = &device->iamthif_file_ext.pollwait;
1372 1372 }
1373 1373 mutex_exit(&device->iamthif_file_ext.file_lock);
1374 1374
1375 1375 } else {
1376 1376 mutex_enter(&file_extension->write_io_lock);
1377 1377 if (HECI_WRITE_COMPLETE == file_extension->writing_state) {
1378 1378 *reventsp |= (POLLIN | POLLRDNORM);
1379 1379 DBG("heci_poll: file_extension poll event\n");
1380 1380 } else {
1381 1381 DBG("heci_poll: file_extension no event\n");
1382 1382 *reventsp = 0;
1383 1383 if (!anyyet)
1384 1384 *phpp = &file_extension->tx_pollwait;
1385 1385 }
1386 1386 mutex_exit(&file_extension->write_io_lock);
1387 1387
1388 1388
1389 1389 }
1390 1390
1391 1391 return (0);
1392 1392 }
1393 1393
1394 1394 /*
1395 1395 * heci_fe_same_id - tell if file private data have same id
1396 1396 *
1397 1397 * @fe1: private data of 1. file object
1398 1398 * @fe2: private data of 2. file object
1399 1399 *
1400 1400 * @return !=0 - if ids are the same, 0 - if differ.
1401 1401 */
1402 1402 static inline int heci_fe_same_id(struct heci_file_private *fe1,
1403 1403 struct heci_file_private *fe2)
1404 1404 {
1405 1405 return ((fe1->host_client_id == fe2->host_client_id) &&
1406 1406 (fe1->me_client_id == fe2->me_client_id));
1407 1407 }
1408 1408
1409 1409 /*
1410 1410 * Since the ME firmware won't reset itself during OS reboot, it's not enough
1411 1411 * to only disable interrupts in quiesce(), here we do a full hand-shake
1412 1412 * with the firmware.
1413 1413 */
1414 1414 static int
1415 1415 heci_quiesce(dev_info_t *dip)
1416 1416 {
1417 1417 struct iamt_heci_device *dev;
1418 1418
1419 1419 dev = ddi_get_soft_state(heci_soft_state_p, ddi_get_instance(dip));
1420 1420 ASSERT(dev != NULL);
1421 1421
1422 1422 if (dev->wd_file_ext.state == HECI_FILE_CONNECTED &&
1423 1423 dev->wd_timeout) {
1424 1424 dev->wd_timeout = 0;
1425 1425 dev->wd_due_counter = 0;
1426 1426 (void) memcpy(dev->wd_data, stop_wd_params,
1427 1427 HECI_WD_PARAMS_SIZE);
1428 1428 if (!heci_send_wd(dev)) {
1429 1429 DBG("send stop WD failed\n");
1430 1430 }
1431 1431
1432 1432 }
1433 1433
1434 1434 /* disable interrupts */
1435 1435 heci_csr_disable_interrupts(dev);
1436 1436
1437 1437 return (DDI_SUCCESS);
1438 1438 }
1439 1439
1440 1440 static int
1441 1441 heci_suspend(dev_info_t *dip)
1442 1442 {
1443 1443 struct iamt_heci_device *device;
1444 1444 int err = 0;
1445 1445
1446 1446 device = ddi_get_soft_state(heci_soft_state_p, ddi_get_instance(dip));
1447 1447
1448 1448 if (device->reinit_tsk)
1449 1449 ddi_taskq_wait(device->reinit_tsk);
1450 1450
1451 1451 /* Stop watchdog if exists */
1452 1452 if (device->wd_timer)
1453 1453 (void) untimeout(device->wd_timer);
1454 1454
1455 1455 mutex_enter(&device->device_lock);
1456 1456
1457 1457 if (device->wd_file_ext.state == HECI_FILE_CONNECTED &&
1458 1458 device->wd_timeout) {
1459 1459 g_sus_wd_timeout = device->wd_timeout;
1460 1460 device->wd_timeout = 0;
1461 1461 device->wd_due_counter = 0;
1462 1462 (void) memcpy(device->wd_data, stop_wd_params,
1463 1463 HECI_WD_PARAMS_SIZE);
1464 1464 device->stop = 1;
1465 1465 if (device->host_buffer_is_empty &&
1466 1466 flow_ctrl_creds(device, &device->wd_file_ext)) {
1467 1467 device->host_buffer_is_empty = 0;
1468 1468 if (!heci_send_wd(device)) {
1469 1469 DBG("send stop WD failed\n");
1470 1470 }
1471 1471 else
1472 1472 flow_ctrl_reduce(device, &device->wd_file_ext);
1473 1473
1474 1474 device->wd_pending = 0;
1475 1475 } else {
1476 1476 device->wd_pending = 1;
1477 1477 }
1478 1478 device->wd_stoped = 0;
1479 1479
1480 1480 err = 0;
1481 1481 while (!device->wd_stoped && err != -1) {
1482 1482 err = cv_reltimedwait(&device->wait_stop_wd,
1483 1483 &device->device_lock, 10*HZ, TR_CLOCK_TICK);
1484 1484 }
1485 1485
1486 1486 if (!device->wd_stoped) {
1487 1487 DBG("stop wd failed to complete.\n");
1488 1488 } else {
1489 1489 DBG("stop wd complete %d.\n", err);
1490 1490 err = 0;
1491 1491 }
1492 1492 }
1493 1493 /* Set new heci state */
1494 1494 if (device->heci_state == HECI_ENABLED ||
1495 1495 device->heci_state == HECI_RECOVERING_FROM_RESET) {
1496 1496 device->heci_state = HECI_POWER_DOWN;
1497 1497 heci_reset(device, 0);
1498 1498 }
1499 1499
1500 1500 /* Here interrupts are already disabled by heci_reset() */
1501 1501
1502 1502 mutex_exit(&device->device_lock);
1503 1503
1504 1504
1505 1505 return (err);
1506 1506 }
1507 1507
1508 1508 static void
1509 1509 heci_resume(dev_info_t *dip)
1510 1510 {
1511 1511 struct iamt_heci_device *device;
1512 1512
1513 1513 device = ddi_get_soft_state(heci_soft_state_p, ddi_get_instance(dip));
1514 1514
1515 1515 mutex_enter(&device->device_lock);
1516 1516 device->heci_state = HECI_POWER_UP;
1517 1517 heci_reset(device, 1);
1518 1518 mutex_exit(&device->device_lock);
1519 1519
1520 1520 /* Start watchdog if stopped in suspend */
1521 1521 if (g_sus_wd_timeout != 0) {
1522 1522 device->wd_timeout = g_sus_wd_timeout;
1523 1523
1524 1524 (void) memcpy(device->wd_data, start_wd_params,
1525 1525 HECI_WD_PARAMS_SIZE);
1526 1526 (void) memcpy(device->wd_data + HECI_WD_PARAMS_SIZE,
1527 1527 &device->wd_timeout, sizeof (uint16_t));
1528 1528 device->wd_due_counter = 1;
1529 1529
1530 1530 if (device->wd_timeout)
1531 1531 device->wd_timer = timeout(heci_wd_timer, device, 1);
1532 1532
1533 1533 g_sus_wd_timeout = 0;
1534 1534 }
1535 1535 }
↓ open down ↓ |
1355 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX