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