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 #include <sys/types.h>
47 #include <sys/cmn_err.h>
48 #include <sys/conf.h>
49 #include <sys/ddi.h>
50 #include <sys/ddi_impldefs.h>
51 #include <sys/devops.h>
52 #include <sys/instance.h>
53 #include <sys/modctl.h>
54 #include <sys/open.h>
55 #include <sys/stat.h>
56 #include <sys/sunddi.h>
57 #include <sys/sunndi.h>
58 #include <sys/systm.h>
59 #include <sys/mkdev.h>
60 #include <sys/list.h>
61 #include <sys/note.h>
62 #include "heci_data_structures.h"
63
64 #include "heci.h"
65 #include "heci_interface.h"
66
67 /*
68 * interrupt function prototypes
69 */
70 static void heci_bh_handler(void *data);
71 static int heci_bh_read_handler(struct io_heci_list *complete_list,
72 struct iamt_heci_device *dev,
73 int32_t *slots);
74 static int heci_bh_write_handler(struct io_heci_list *complete_list,
75 struct iamt_heci_device *dev,
76 int32_t *slots);
77 static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
78 struct heci_msg_hdr *heci_hdr);
79 static int heci_bh_read_pthi_message(struct io_heci_list *complete_list,
80 struct iamt_heci_device *dev,
81 struct heci_msg_hdr *heci_hdr);
82 static int heci_bh_read_client_message(struct io_heci_list *complete_list,
83 struct iamt_heci_device *dev,
84 struct heci_msg_hdr *heci_hdr);
85 static void heci_client_connect_response(struct iamt_heci_device *dev,
86 struct hbm_client_connect_response *connect_res);
87 static void heci_client_disconnect_response(struct iamt_heci_device *dev,
88 struct hbm_client_connect_response *disconnect_res);
89 static void heci_client_flow_control_response(struct iamt_heci_device *dev,
90 struct hbm_flow_control *flow_control);
91 static void heci_client_disconnect_request(struct iamt_heci_device *dev,
92 struct hbm_client_disconnect_request *disconnect_req);
93
94 static int heci_bh_process_device(struct iamt_heci_device *dev);
95
96 /*
97 * heci_isr_interrupt - The ISR of the HECI device
98 *
99 * @irq: The irq number
100 * @dev_id: pointer to the device structure
101 *
102 * @return irqreturn_t
103 */
104 uint_t
heci_isr_interrupt(caddr_t arg1)105 heci_isr_interrupt(caddr_t arg1)
106 {
107 struct iamt_heci_device *device =
108 (struct iamt_heci_device *)(void *)arg1;
109
110 mutex_enter(&device->device_lock);
111
112 if (device->heci_state == HECI_POWER_DOWN) {
113 mutex_exit(&device->device_lock);
114 return (DDI_INTR_UNCLAIMED);
115 }
116 device->host_hw_state = read_heci_register(device, H_CSR);
117
118 if ((device->host_hw_state & H_IS) != H_IS) {
119 mutex_exit(&device->device_lock);
120 return (DDI_INTR_UNCLAIMED);
121 }
122
123 /* disable interrupts */
124 heci_csr_disable_interrupts(device);
125
126 mutex_exit(&device->device_lock);
127
128 /*
129 * Our device interrupted, schedule work the heci_bh_handler
130 * to handle the interrupt processing. This needs to be a
131 * taskq
132 */
133 DBG("schedule work the heci_bh_handler.\n");
134 if (ddi_taskq_dispatch(device->work, heci_bh_handler,
135 (void*)arg1, DDI_NOSLEEP) == DDI_FAILURE)
136 cmn_err(CE_WARN, "taskq_dispatch failed for heci_bh_handler");
137
138 return (DDI_INTR_CLAIMED);
139 }
140
141 /*
142 * _heci_cmpl: process completed operation.
143 *
144 * @file_ext: private data of the file object.
145 * @priv_cb_pos: callback block.
146 */
_heci_cmpl(struct heci_file_private * file_ext,struct heci_cb_private * priv_cb_pos)147 static void _heci_cmpl(struct heci_file_private *file_ext,
148 struct heci_cb_private *priv_cb_pos)
149 {
150 if (priv_cb_pos->major_file_operations == HECI_WRITE) {
151 heci_free_cb_private(priv_cb_pos);
152 DBG("completing write call back.\n");
153 file_ext->writing_state = HECI_WRITE_COMPLETE;
154 pollwakeup(&file_ext->tx_pollwait, POLL_IN|POLLRDNORM);
155
156 } else if (priv_cb_pos->major_file_operations == HECI_READ &&
157 HECI_READING == file_ext->reading_state) {
158 DBG("completing read call back information= %lu\n",
159 priv_cb_pos->information);
160 file_ext->reading_state = HECI_READ_COMPLETE;
161 cv_broadcast(&file_ext->rx_wait);
162
163 }
164 }
165
166 /*
167 * _heci_cmpl_iamthif: process completed iamthif operation.
168 *
169 * @dev: Device object for our driver.
170 * @priv_cb_pos: callback block.
171 */
_heci_cmpl_iamthif(struct iamt_heci_device * dev,struct heci_cb_private * priv_cb_pos)172 static void _heci_cmpl_iamthif(struct iamt_heci_device *dev,
173 struct heci_cb_private *priv_cb_pos)
174 {
175 if (dev->iamthif_canceled != 1) {
176 dev->iamthif_state = HECI_IAMTHIF_READ_COMPLETE;
177 dev->iamthif_stall_timer = 0;
178 (void) memcpy(priv_cb_pos->response_buffer.data,
179 dev->iamthif_msg_buf,
180 dev->iamthif_msg_buf_index);
181 list_add_tail(&priv_cb_pos->cb_list,
182 &dev->pthi_read_complete_list.heci_cb.cb_list);
183 DBG("pthi read completed.\n");
184 } else {
185 run_next_iamthif_cmd(dev);
186 }
187 if (&dev->iamthif_file_ext.pollwait) {
188 DBG("completing pthi call back.\n");
189 pollwakeup(&dev->iamthif_file_ext.pollwait, POLL_IN|POLLRDNORM);
190 }
191 }
192 /*
193 * heci_bh_handler - function called after ISR to handle the interrupt
194 * processing.
195 *
196 * @work: pointer to the work structure
197 *
198 * NOTE: This function is called by schedule work
199 */
200 static void
heci_bh_handler(void * data)201 heci_bh_handler(void *data)
202 {
203 struct iamt_heci_device *dev = (struct iamt_heci_device *)data;
204
205 #ifdef SUNOS
206 while (heci_bh_process_device(dev))
207 ;
208 #elif defined(LINUX)
209 if (heci_bh_process_device(dev)) {
210 PEPARE_WORK(&dev->work, heci_bh_handler);
211 DBG("schedule work the heci_bh_handler.\n");
212 rets = schedule_work(&dev->work);
213 if (!rets) {
214 printk(KERN_ERR "heci: schedule the heci_bh_handler"
215 " failed error=%x\n", rets);
216 }
217 }
218 #else
219
220 #error "Unknown platform!"
221
222 #endif
223 }
224
225 static int
heci_bh_process_device(struct iamt_heci_device * dev)226 heci_bh_process_device(struct iamt_heci_device *dev)
227 {
228 struct io_heci_list complete_list;
229 int32_t slots;
230 int rets, isr_pending = 0;
231 struct heci_cb_private *cb_pos = NULL, *cb_next = NULL;
232 struct heci_file_private *file_ext;
233 int bus_message_received = 0;
234
235 DBG("function called after ISR to handle the interrupt processing.\n");
236 /* initialize our complete list */
237 mutex_enter(&dev->device_lock);
238 heci_initialize_list(&complete_list, dev);
239 dev->host_hw_state = read_heci_register(dev, H_CSR);
240 dev->me_hw_state = read_heci_register(dev, ME_CSR_HA);
241
242 /* check if ME wants a reset */
243 if (((dev->me_hw_state & ME_RDY_HRA) == 0) &&
244 (dev->heci_state != HECI_RESETING) &&
245 (dev->heci_state != HECI_INITIALIZING)) {
246 DBG("FW not ready.\n");
247 heci_reset(dev, 1);
248 mutex_exit(&dev->device_lock);
249 return (0);
250 }
251
252 /* check if we need to start the dev */
253 if ((dev->host_hw_state & H_RDY) == 0) {
254 if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
255 DBG("we need to start the dev.\n");
256 dev->host_hw_state |= (H_IE | H_IG | H_RDY);
257 heci_set_csr_register(dev);
258 if (dev->heci_state == HECI_INITIALIZING) {
259 dev->recvd_msg = 1;
260 cv_broadcast(&dev->wait_recvd_msg);
261 mutex_exit(&dev->device_lock);
262
263 return (0);
264
265 } else {
266 mutex_exit(&dev->device_lock);
267 if (dev->reinit_tsk &&
268 ddi_taskq_dispatch(dev->reinit_tsk,
269 heci_task_initialize_clients,
270 dev, DDI_SLEEP) == DDI_FAILURE) {
271
272 cmn_err(CE_WARN, "taskq_dispatch "
273 "failed for reinit_tsk");
274 }
275 return (0);
276 }
277 } else {
278 DBG("enable interrupt FW not ready.\n");
279 heci_csr_enable_interrupts(dev);
280 mutex_exit(&dev->device_lock);
281 return (0);
282 }
283 }
284 /* check slots avalable for reading */
285 slots = count_full_read_slots(dev);
286 DBG("slots =%08x extra_write_index =%08x.\n",
287 slots, dev->extra_write_index);
288 while ((slots > 0) && (!dev->extra_write_index)) {
289 DBG("slots =%08x extra_write_index =%08x.\n", slots,
290 dev->extra_write_index);
291 DBG("call heci_bh_read_handler.\n");
292 rets = heci_bh_read_handler(&complete_list, dev, &slots);
293 if (rets != 0)
294 goto end;
295 }
296 rets = heci_bh_write_handler(&complete_list, dev, &slots);
297 end:
298 DBG("end of bottom half function.\n");
299 dev->host_hw_state = read_heci_register(dev, H_CSR);
300 dev->host_buffer_is_empty = host_buffer_is_empty(dev);
301
302 if ((dev->host_hw_state & H_IS) == H_IS) {
303 /* acknowledge interrupt and disable interrupts */
304 heci_csr_disable_interrupts(dev);
305
306 DBG("schedule work the heci_bh_handler.\n");
307 isr_pending = 1;
308
309
310 } else {
311 heci_csr_enable_interrupts(dev);
312 }
313
314 if (dev->recvd_msg) {
315 DBG("received waiting bus message\n");
316 bus_message_received = 1;
317 }
318
319 if (bus_message_received) {
320 DBG("wake up dev->wait_recvd_msg\n");
321 cv_broadcast(&dev->wait_recvd_msg);
322 bus_message_received = 0;
323 }
324 if ((complete_list.status != 0) ||
325 list_empty(&complete_list.heci_cb.cb_list)) {
326 mutex_exit(&dev->device_lock);
327 return (isr_pending);
328 }
329
330 mutex_exit(&dev->device_lock);
331
332 list_for_each_entry_safe(cb_pos, cb_next,
333 &complete_list.heci_cb.cb_list, cb_list, struct heci_cb_private) {
334 file_ext = (struct heci_file_private *)cb_pos->file_private;
335 list_del(&cb_pos->cb_list);
336 if (file_ext != NULL) {
337 if (file_ext != &dev->iamthif_file_ext) {
338 DBG("completing call back.\n");
339 _heci_cmpl(file_ext, cb_pos);
340 cb_pos = NULL;
341 } else if (file_ext == &dev->iamthif_file_ext) {
342 _heci_cmpl_iamthif(dev, cb_pos);
343 }
344 }
345 }
346 return (isr_pending);
347 }
348
349
350 /*
351 * heci_bh_read_handler - bottom half read routine after ISR to
352 * handle the read processing.
353 *
354 * @cmpl_list: An instance of our list structure
355 * @dev: Device object for our driver
356 * @slots: slots to read.
357 *
358 * @return 0 on success, <0 on failure.
359 */
360 static int
heci_bh_read_handler(struct io_heci_list * cmpl_list,struct iamt_heci_device * dev,int32_t * slots)361 heci_bh_read_handler(struct io_heci_list *cmpl_list,
362 struct iamt_heci_device *dev,
363 int32_t *slots)
364 {
365 struct heci_msg_hdr *heci_hdr;
366 int ret = 0;
367 struct heci_file_private *file_pos = NULL;
368 struct heci_file_private *file_next = NULL;
369
370 if (!dev->rd_msg_hdr) {
371 dev->rd_msg_hdr = read_heci_register(dev, ME_CB_RW);
372 DBG("slots=%08x.\n", *slots);
373 (*slots)--;
374 DBG("slots=%08x.\n", *slots);
375 }
376 heci_hdr = (struct heci_msg_hdr *)&dev->rd_msg_hdr;
377 DBG("heci_hdr->length =%d\n", heci_hdr->length);
378
379 if ((heci_hdr->reserved) || !(dev->rd_msg_hdr)) {
380 DBG("corrupted message header.\n");
381 ret = -ECORRUPTED_MESSAGE_HEADER;
382 goto end;
383 }
384
385 if ((heci_hdr->host_addr) || (heci_hdr->me_addr)) {
386 list_for_each_entry_safe(file_pos, file_next,
387 &dev->file_list, link, struct heci_file_private) {
388 DBG("list_for_each_entry_safe read host"
389 " client = %d, ME client = %d\n",
390 file_pos->host_client_id,
391 file_pos->me_client_id);
392 if ((file_pos->host_client_id == heci_hdr->host_addr) &&
393 (file_pos->me_client_id == heci_hdr->me_addr))
394 break;
395 }
396
397 if (&file_pos->link == &dev->file_list) {
398 DBG("corrupted message header\n");
399 ret = -ECORRUPTED_MESSAGE_HEADER;
400 goto end;
401 }
402 }
403 if (((*slots) * sizeof (uint32_t)) < heci_hdr->length) {
404 DBG("we can't read the message slots=%08x.\n", *slots);
405 /* we can't read the message */
406 ret = -ERANGE;
407 goto end;
408 }
409
410 /* decide where to read the message too */
411 if (!heci_hdr->host_addr) {
412 DBG("call heci_bh_read_bus_message.\n");
413 heci_bh_read_bus_message(dev, heci_hdr);
414 DBG("end heci_bh_read_bus_message.\n");
415 } else if ((heci_hdr->host_addr ==
416 dev->iamthif_file_ext.host_client_id) &&
417 (HECI_FILE_CONNECTED == dev->iamthif_file_ext.state) &&
418 (dev->iamthif_state == HECI_IAMTHIF_READING)) {
419
420 DBG("call heci_bh_read_iamthif_message.\n");
421 DBG("heci_hdr->length =%d\n", heci_hdr->length);
422 ret = heci_bh_read_pthi_message(cmpl_list, dev, heci_hdr);
423 if (ret != 0)
424 goto end;
425
426 } else {
427 DBG("call heci_bh_read_client_message.\n");
428 ret = heci_bh_read_client_message(cmpl_list, dev, heci_hdr);
429 if (ret != 0)
430 goto end;
431
432 }
433
434 /* reset the number of slots and header */
435 *slots = count_full_read_slots(dev);
436 dev->rd_msg_hdr = 0;
437
438 if (*slots == -ESLOTS_OVERFLOW) {
439 /* overflow - reset */
440 DBG("reseting due to slots overflow.\n");
441 /* set the event since message has been read */
442 ret = -ERANGE;
443 goto end;
444 }
445 end:
446 return (ret);
447 }
448
449
450 /*
451 * heci_bh_read_bus_message - bottom half read routine after ISR to
452 * handle the read bus message cmd processing.
453 *
454 * @dev: Device object for our driver
455 * @heci_hdr: header of bus message
456 */
heci_bh_read_bus_message(struct iamt_heci_device * dev,struct heci_msg_hdr * heci_hdr)457 static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
458 struct heci_msg_hdr *heci_hdr)
459 {
460 struct heci_bus_message *heci_msg;
461 struct hbm_host_version_response *version_res;
462 struct hbm_client_connect_response *connect_res;
463 struct hbm_client_connect_response *disconnect_res;
464 struct hbm_flow_control *flow_control;
465 struct hbm_props_response *props_res;
466 struct hbm_host_enum_response *enum_res;
467 struct hbm_client_disconnect_request *disconnect_req;
468 struct hbm_host_stop_request *h_stop_req;
469 int i;
470 unsigned char *buffer;
471
472 /* read the message to our buffer */
473 buffer = (unsigned char *)dev->rd_msg_buf;
474 ASSERT(heci_hdr->length < sizeof (dev->rd_msg_buf));
475 heci_read_slots(dev, buffer, heci_hdr->length);
476 heci_msg = (struct heci_bus_message *)buffer;
477
478 switch (*(uint8_t *)heci_msg) {
479 case HOST_START_RES_CMD:
480 version_res = (struct hbm_host_version_response *)heci_msg;
481 if (version_res->host_version_supported) {
482 dev->version.major_version = HBM_MAJOR_VERSION;
483 dev->version.minor_version = HBM_MINOR_VERSION;
484 } else {
485 dev->version = version_res->me_max_version;
486 }
487 dev->recvd_msg = 1;
488 DBG("host start response message received.\n");
489 break;
490
491 case CLIENT_CONNECT_RES_CMD:
492 connect_res =
493 (struct hbm_client_connect_response *)heci_msg;
494 heci_client_connect_response(dev, connect_res);
495 DBG("client connect response message received.\n");
496 cv_broadcast(&dev->wait_recvd_msg);
497 break;
498
499 case CLIENT_DISCONNECT_RES_CMD:
500 disconnect_res =
501 (struct hbm_client_connect_response *)heci_msg;
502 heci_client_disconnect_response(dev, disconnect_res);
503 DBG("client disconnect response message received.\n");
504 cv_broadcast(&dev->wait_recvd_msg);
505 break;
506
507 case HECI_FLOW_CONTROL_CMD:
508 flow_control = (struct hbm_flow_control *)heci_msg;
509 heci_client_flow_control_response(dev, flow_control);
510 DBG("client flow control response message received.\n");
511 break;
512
513 case HOST_CLIENT_PROPERTEIS_RES_CMD:
514 props_res = (struct hbm_props_response *)heci_msg;
515 if (props_res->status != 0) {
516 ASSERT(0);
517 break;
518 }
519 for (i = 0; i < dev->num_heci_me_clients; i++) {
520 if (dev->me_clients[i].client_id ==
521 props_res->address) {
522 dev->me_clients[i].props =
523 props_res->client_properties;
524 break;
525 }
526
527 }
528 dev->recvd_msg = 1;
529 break;
530
531 case HOST_ENUM_RES_CMD:
532 enum_res = (struct hbm_host_enum_response *)heci_msg;
533 (void) memcpy(dev->heci_me_clients,
534 enum_res->valid_addresses, 32);
535 dev->recvd_msg = 1;
536 break;
537
538 case HOST_STOP_RES_CMD:
539 dev->heci_state = HECI_DISABLED;
540 DBG("reseting because of FW stop response.\n");
541 heci_reset(dev, 1);
542 break;
543
544 case CLIENT_DISCONNECT_REQ_CMD:
545 /* search for client */
546 disconnect_req =
547 (struct hbm_client_disconnect_request *)heci_msg;
548 heci_client_disconnect_request(dev, disconnect_req);
549 break;
550
551 case ME_STOP_REQ_CMD:
552 /* prepare stop request */
553 heci_hdr = (struct heci_msg_hdr *)&dev->ext_msg_buf[0];
554 heci_hdr->host_addr = 0;
555 heci_hdr->me_addr = 0;
556 heci_hdr->length = sizeof (struct hbm_host_stop_request);
557 heci_hdr->msg_complete = 1;
558 heci_hdr->reserved = 0;
559 h_stop_req =
560 (struct hbm_host_stop_request *)&dev->ext_msg_buf[1];
561 (void) memset(h_stop_req, 0,
562 sizeof (struct hbm_host_stop_request));
563 h_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
564 h_stop_req->reason = DRIVER_STOP_REQUEST;
565 h_stop_req->reserved[0] = 0;
566 h_stop_req->reserved[1] = 0;
567 dev->extra_write_index = 2;
568 break;
569
570 default:
571 ASSERT(0);
572 break;
573
574 }
575 }
576
577 /*
578 * heci_bh_read_pthi_message - bottom half read routine after ISR to
579 * handle the read pthi message data processing.
580 *
581 * @complete_list: An instance of our list structure
582 * @dev: Device object for our driver
583 * @heci_hdr: header of pthi message
584 *
585 * @return 0 on success, <0 on failure.
586 */
587 static int
heci_bh_read_pthi_message(struct io_heci_list * complete_list,struct iamt_heci_device * dev,struct heci_msg_hdr * heci_hdr)588 heci_bh_read_pthi_message(struct io_heci_list *complete_list,
589 struct iamt_heci_device *dev,
590 struct heci_msg_hdr *heci_hdr)
591 {
592 struct heci_file_private *file_ext;
593 struct heci_cb_private *priv_cb;
594 unsigned char *buffer;
595
596 ASSERT(heci_hdr->me_addr == dev->iamthif_file_ext.me_client_id);
597 ASSERT(dev->iamthif_state == HECI_IAMTHIF_READING);
598
599 buffer = (unsigned char *)(dev->iamthif_msg_buf +
600 dev->iamthif_msg_buf_index);
601 ASSERT(sizeof (dev->iamthif_msg_buf) >=
602 (dev->iamthif_msg_buf_index + heci_hdr->length));
603
604 heci_read_slots(dev, buffer, heci_hdr->length);
605
606 dev->iamthif_msg_buf_index += heci_hdr->length;
607
608 if (!(heci_hdr->msg_complete))
609 return (0);
610
611 DBG("pthi_message_buffer_index=%d\n", heci_hdr->length);
612 DBG("completed pthi read.\n ");
613 if (!dev->iamthif_current_cb)
614 return (-ENODEV);
615
616 priv_cb = dev->iamthif_current_cb;
617 dev->iamthif_current_cb = NULL;
618
619 file_ext = (struct heci_file_private *)priv_cb->file_private;
620 if (!file_ext)
621 return (-ENODEV);
622
623 dev->iamthif_stall_timer = 0;
624 priv_cb->information = dev->iamthif_msg_buf_index;
625 priv_cb->read_time = ddi_get_time();
626 if ((dev->iamthif_ioctl) && (file_ext == &dev->iamthif_file_ext)) {
627 /* found the iamthif cb */
628 DBG("complete the pthi read cb.\n ");
629 if (&dev->iamthif_file_ext) {
630 DBG("add the pthi read cb to complete.\n ");
631 list_add_tail(&priv_cb->cb_list,
632 &complete_list->heci_cb.cb_list);
633 }
634 }
635 return (0);
636 }
637
638 /*
639 * _heci_bh_state_ok - check if heci header matches file private data
640 *
641 * @file_ext: private data of the file object
642 * @heci_hdr: header of heci client message
643 *
644 * @return !=0 if matches, 0 if no match.
645 */
646 static int
_heci_bh_state_ok(struct heci_file_private * file_ext,struct heci_msg_hdr * heci_hdr)647 _heci_bh_state_ok(struct heci_file_private *file_ext,
648 struct heci_msg_hdr *heci_hdr)
649 {
650 return ((file_ext->host_client_id == heci_hdr->host_addr) &&
651 (file_ext->me_client_id == heci_hdr->me_addr) &&
652 (file_ext->state == HECI_FILE_CONNECTED) &&
653 (HECI_READ_COMPLETE != file_ext->reading_state));
654 }
655
656 /*
657 * heci_bh_read_client_message - bottom half read routine after ISR to
658 * handle the read heci client message data processing.
659 *
660 * @complete_list: An instance of our list structure
661 * @dev: Device object for our driver
662 * @heci_hdr: header of heci client message
663 *
664 * @return 0 on success, <0 on failure.
665 */
666 static int
heci_bh_read_client_message(struct io_heci_list * complete_list,struct iamt_heci_device * dev,struct heci_msg_hdr * heci_hdr)667 heci_bh_read_client_message(struct io_heci_list *complete_list,
668 struct iamt_heci_device *dev,
669 struct heci_msg_hdr *heci_hdr)
670 {
671 struct heci_file_private *file_ext;
672 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
673 unsigned char *buffer = NULL;
674
675 DBG("start client msg\n");
676 if (!((dev->read_list.status == 0) &&
677 !list_empty(&dev->read_list.heci_cb.cb_list)))
678 goto quit;
679
680 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
681 &dev->read_list.heci_cb.cb_list, cb_list, struct heci_cb_private) {
682 file_ext = (struct heci_file_private *)
683 priv_cb_pos->file_private;
684 if ((file_ext != NULL) &&
685 (_heci_bh_state_ok(file_ext, heci_hdr))) {
686 mutex_enter(&file_ext->read_io_lock);
687 file_ext->reading_state = HECI_READING;
688 buffer = (unsigned char *)
689 (priv_cb_pos->response_buffer.data +
690 priv_cb_pos->information);
691 ASSERT(priv_cb_pos->response_buffer.size >=
692 heci_hdr->length +
693 priv_cb_pos->information);
694
695 if (priv_cb_pos->response_buffer.size <
696 heci_hdr->length +
697 priv_cb_pos->information) {
698 DBG("message overflow.\n");
699 list_del(&priv_cb_pos->cb_list);
700 mutex_exit(&file_ext->read_io_lock);
701 return (-ENOMEM);
702 }
703 if (buffer) {
704 heci_read_slots(dev, buffer,
705 heci_hdr->length);
706 }
707 priv_cb_pos->information += heci_hdr->length;
708 if (heci_hdr->msg_complete) {
709 file_ext->status = 0;
710 list_del(&priv_cb_pos->cb_list);
711 mutex_exit(&file_ext->read_io_lock);
712 DBG("completed read host client = %d,"
713 "ME client = %d, "
714 "data length = %lu\n",
715 file_ext->host_client_id,
716 file_ext->me_client_id,
717 priv_cb_pos->information);
718
719 DBG("priv_cb_pos->res_buffer - %s\n",
720 priv_cb_pos->response_buffer.data);
721 list_add_tail(&priv_cb_pos->cb_list,
722 &complete_list->heci_cb.cb_list);
723 } else {
724 mutex_exit(&file_ext->read_io_lock);
725 }
726
727 break;
728 }
729
730 }
731
732 quit:
733 DBG("message read\n");
734 if (!buffer) {
735 heci_read_slots(dev, (unsigned char *)dev->rd_msg_buf,
736 heci_hdr->length);
737 DBG("discarding message, header=%08x.\n",
738 *(uint32_t *)dev->rd_msg_buf);
739 }
740
741 return (0);
742 }
743
744 /*
745 * _heci_bh_iamthif_read: prepare to read iamthif data.
746 *
747 * @dev: Device object for our driver.
748 * @slots: free slots.
749 *
750 * @return 0, OK; otherwise, error.
751 */
752 static int
_heci_bh_iamthif_read(struct iamt_heci_device * dev,int32_t * slots)753 _heci_bh_iamthif_read(struct iamt_heci_device *dev, int32_t *slots)
754 {
755
756 if (((*slots) * sizeof (uint32_t)) >= (sizeof (struct heci_msg_hdr)
757 + sizeof (struct hbm_flow_control))) {
758 *slots -= (sizeof (struct heci_msg_hdr) +
759 sizeof (struct hbm_flow_control) + 3) / 4;
760 if (!heci_send_flow_control(dev, &dev->iamthif_file_ext)) {
761 DBG("iamthif flow control failed\n");
762 } else {
763 DBG("iamthif flow control success\n");
764 dev->iamthif_state = HECI_IAMTHIF_READING;
765 dev->iamthif_flow_control_pending = 0;
766 dev->iamthif_msg_buf_index = 0;
767 dev->iamthif_msg_buf_size = 0;
768 dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
769 dev->host_buffer_is_empty = host_buffer_is_empty(dev);
770 }
771 return (0);
772 } else {
773 return (-ECOMPLETE_MESSAGE);
774 }
775 }
776
777 /*
778 * _heci_bh_close: process close related operation.
779 *
780 * @dev: Device object for our driver.
781 * @slots: free slots.
782 * @priv_cb_pos: callback block.
783 * @file_ext: private data of the file object.
784 * @cmpl_list: complete list.
785 *
786 * @return 0, OK; otherwise, error.
787 */
788 static int
_heci_bh_close(struct iamt_heci_device * dev,int32_t * slots,struct heci_cb_private * priv_cb_pos,struct heci_file_private * file_ext,struct io_heci_list * cmpl_list)789 _heci_bh_close(struct iamt_heci_device *dev, int32_t *slots,
790 struct heci_cb_private *priv_cb_pos,
791 struct heci_file_private *file_ext,
792 struct io_heci_list *cmpl_list)
793 {
794 if ((*slots * sizeof (uint32_t)) >= (sizeof (struct heci_msg_hdr) +
795 sizeof (struct hbm_client_disconnect_request))) {
796 *slots -= (sizeof (struct heci_msg_hdr) +
797 sizeof (struct hbm_client_disconnect_request) + 3) / 4;
798
799 if (!heci_disconnect(dev, file_ext)) {
800 file_ext->status = 0;
801 priv_cb_pos->information = 0;
802 list_relink_node(&priv_cb_pos->cb_list,
803 &cmpl_list->heci_cb.cb_list);
804 return (-ECOMPLETE_MESSAGE);
805 } else {
806 file_ext->state = HECI_FILE_DISCONNECTING;
807 file_ext->status = 0;
808 priv_cb_pos->information = 0;
809 list_relink_node(&priv_cb_pos->cb_list,
810 &dev->ctrl_rd_list.heci_cb.cb_list);
811 file_ext->timer_count = HECI_CONNECT_TIMEOUT;
812 }
813 } else {
814 /* return the cancel routine */
815 return (-ECORRUPTED_MESSAGE_HEADER);
816 }
817
818 return (0);
819 }
820
821 /*
822 * _heci_hb_close: process read related operation.
823 *
824 * @dev: Device object for our driver.
825 * @slots: free slots.
826 * @priv_cb_pos: callback block.
827 * @file_ext: private data of the file object.
828 * @cmpl_list: complete list.
829 *
830 * @return 0, OK; otherwise, error.
831 */
832 static int
_heci_bh_read(struct iamt_heci_device * dev,int32_t * slots,struct heci_cb_private * priv_cb_pos,struct heci_file_private * file_ext,struct io_heci_list * cmpl_list)833 _heci_bh_read(struct iamt_heci_device *dev, int32_t *slots,
834 struct heci_cb_private *priv_cb_pos,
835 struct heci_file_private *file_ext,
836 struct io_heci_list *cmpl_list)
837 {
838 if ((*slots * sizeof (uint32_t)) >= (sizeof (struct heci_msg_hdr) +
839 sizeof (struct hbm_flow_control))) {
840 *slots -= (sizeof (struct heci_msg_hdr) +
841 sizeof (struct hbm_flow_control) + 3) / 4;
842 if (!heci_send_flow_control(dev, file_ext)) {
843 file_ext->status = -ENODEV;
844 priv_cb_pos->information = 0;
845 list_relink_node(&priv_cb_pos->cb_list,
846 &cmpl_list->heci_cb.cb_list);
847 return (-ENODEV);
848 } else {
849 list_relink_node(&priv_cb_pos->cb_list,
850 &dev->read_list.heci_cb.cb_list);
851 }
852 } else {
853 /* return the cancel routine */
854 list_del(&priv_cb_pos->cb_list);
855 return (-ECORRUPTED_MESSAGE_HEADER);
856 }
857
858 return (0);
859 }
860
861
862 /*
863 * _heci_bh_ioctl: process ioctl related operation.
864 *
865 * @dev: Device object for our driver.
866 * @slots: free slots.
867 * @priv_cb_pos: callback block.
868 * @file_ext: private data of the file object.
869 * @cmpl_list: complete list.
870 *
871 * @return 0, OK; otherwise, error.
872 */
873 static int
_heci_bh_ioctl(struct iamt_heci_device * dev,int32_t * slots,struct heci_cb_private * priv_cb_pos,struct heci_file_private * file_ext,struct io_heci_list * cmpl_list)874 _heci_bh_ioctl(struct iamt_heci_device *dev, int32_t *slots,
875 struct heci_cb_private *priv_cb_pos,
876 struct heci_file_private *file_ext,
877 struct io_heci_list *cmpl_list)
878 {
879 _NOTE(ARGUNUSED(cmpl_list));
880
881 if ((*slots * sizeof (uint32_t)) >= (sizeof (struct heci_msg_hdr) +
882 sizeof (struct hbm_client_connect_request))) {
883 file_ext->state = HECI_FILE_CONNECTING;
884 *slots -= (sizeof (struct heci_msg_hdr) +
885 sizeof (struct hbm_client_connect_request) + 3) / 4;
886 if (!heci_connect(dev, file_ext)) {
887 file_ext->status = -ENODEV;
888 priv_cb_pos->information = 0;
889 list_del(&priv_cb_pos->cb_list);
890 return (-ENODEV);
891 } else {
892 list_relink_node(&priv_cb_pos->cb_list,
893 &dev->ctrl_rd_list.heci_cb.cb_list);
894 file_ext->timer_count = HECI_CONNECT_TIMEOUT;
895 }
896 } else {
897 /* return the cancel routine */
898 list_del(&priv_cb_pos->cb_list);
899 return (-ECORRUPTED_MESSAGE_HEADER);
900 }
901
902 return (0);
903 }
904
905 /*
906 * _heci_bh_cmpl: process completed and no-iamthif operation.
907 *
908 * @dev: Device object for our driver.
909 * @slots: free slots.
910 * @priv_cb_pos: callback block.
911 * @file_ext: private data of the file object.
912 * @cmpl_list: complete list.
913 *
914 * @return 0, OK; otherwise, error.
915 */
916 static int
_heci_bh_cmpl(struct iamt_heci_device * dev,int32_t * slots,struct heci_cb_private * priv_cb_pos,struct heci_file_private * file_ext,struct io_heci_list * cmpl_list)917 _heci_bh_cmpl(struct iamt_heci_device *dev, int32_t *slots,
918 struct heci_cb_private *priv_cb_pos,
919 struct heci_file_private *file_ext,
920 struct io_heci_list *cmpl_list)
921 {
922 struct heci_msg_hdr *heci_hdr;
923
924 if ((*slots * sizeof (uint32_t)) >= (sizeof (struct heci_msg_hdr) +
925 (priv_cb_pos->request_buffer.size -
926 priv_cb_pos->information))) {
927 heci_hdr = (struct heci_msg_hdr *)&dev->wr_msg_buf[0];
928 heci_hdr->host_addr = file_ext->host_client_id;
929 heci_hdr->me_addr = file_ext->me_client_id;
930 heci_hdr->length = ((priv_cb_pos->request_buffer.size) -
931 (priv_cb_pos->information));
932 heci_hdr->msg_complete = 1;
933 heci_hdr->reserved = 0;
934 DBG("priv_cb_pos->request_buffer.size =%d"
935 "heci_hdr->msg_complete= %d\n",
936 priv_cb_pos->request_buffer.size,
937 heci_hdr->msg_complete);
938 DBG("priv_cb_pos->information =%lu\n",
939 priv_cb_pos->information);
940 DBG("heci_hdr->length =%d\n",
941 heci_hdr->length);
942 *slots -= (sizeof (struct heci_msg_hdr) +
943 heci_hdr->length + 3) / 4;
944 if (!heci_write_message(dev, heci_hdr,
945 (unsigned char *)(priv_cb_pos->request_buffer.data +
946 priv_cb_pos->information),
947 heci_hdr->length)) {
948 file_ext->status = -ENODEV;
949 list_relink_node(&priv_cb_pos->cb_list,
950 &cmpl_list->heci_cb.cb_list);
951 return (-ENODEV);
952 } else {
953 flow_ctrl_reduce(dev, file_ext);
954 file_ext->status = 0;
955 priv_cb_pos->information += heci_hdr->length;
956 list_relink_node(&priv_cb_pos->cb_list,
957 &dev->write_waiting_list.heci_cb.cb_list);
958 }
959 } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
960 /* buffer is still empty */
961 heci_hdr = (struct heci_msg_hdr *)&dev->wr_msg_buf[0];
962 heci_hdr->host_addr = file_ext->host_client_id;
963 heci_hdr->me_addr = file_ext->me_client_id;
964 heci_hdr->length =
965 (*slots * sizeof (uint32_t)) - sizeof (struct heci_msg_hdr);
966 heci_hdr->msg_complete = 0;
967 heci_hdr->reserved = 0;
968
969 (*slots) -= (sizeof (struct heci_msg_hdr) +
970 heci_hdr->length + 3) / 4;
971 if (!heci_write_message(dev, heci_hdr,
972 (unsigned char *)
973 (priv_cb_pos->request_buffer.data +
974 priv_cb_pos->information),
975 heci_hdr->length)) {
976 file_ext->status = -ENODEV;
977 list_relink_node(&priv_cb_pos->cb_list,
978 &cmpl_list->heci_cb.cb_list);
979 return (-ENODEV);
980 } else {
981 priv_cb_pos->information += heci_hdr->length;
982 DBG("priv_cb_pos->request_buffer.size =%d"
983 " heci_hdr->msg_complete= %d\n",
984 priv_cb_pos->request_buffer.size,
985 heci_hdr->msg_complete);
986 DBG("priv_cb_pos->information =%lu\n",
987 priv_cb_pos->information);
988 DBG("heci_hdr->length =%d\n", heci_hdr->length);
989 }
990 return (-ECOMPLETE_MESSAGE);
991 } else {
992 return (-ECORRUPTED_MESSAGE_HEADER);
993 }
994
995 return (0);
996 }
997
998 /*
999 * _heci_bh_cmpl_iamthif: process completed iamthif operation.
1000 *
1001 * @dev: Device object for our driver.
1002 * @slots: free slots.
1003 * @priv_cb_pos: callback block.
1004 * @file_ext: private data of the file object.
1005 * @cmpl_list: complete list.
1006 *
1007 * @return 0, OK; otherwise, error.
1008 */
1009 static int
_heci_bh_cmpl_iamthif(struct iamt_heci_device * dev,int32_t * slots,struct heci_cb_private * priv_cb_pos,struct heci_file_private * file_ext,struct io_heci_list * cmpl_list)1010 _heci_bh_cmpl_iamthif(struct iamt_heci_device *dev, int32_t *slots,
1011 struct heci_cb_private *priv_cb_pos,
1012 struct heci_file_private *file_ext,
1013 struct io_heci_list *cmpl_list)
1014 {
1015 struct heci_msg_hdr *heci_hdr;
1016
1017 _NOTE(ARGUNUSED(cmpl_list));
1018
1019 if ((*slots * sizeof (uint32_t)) >= (sizeof (struct heci_msg_hdr) +
1020 dev->iamthif_msg_buf_size -
1021 dev->iamthif_msg_buf_index)) {
1022 heci_hdr = (struct heci_msg_hdr *)&dev->wr_msg_buf[0];
1023 heci_hdr->host_addr = file_ext->host_client_id;
1024 heci_hdr->me_addr = file_ext->me_client_id;
1025 heci_hdr->length = dev->iamthif_msg_buf_size -
1026 dev->iamthif_msg_buf_index;
1027 heci_hdr->msg_complete = 1;
1028 heci_hdr->reserved = 0;
1029
1030 *slots -= (sizeof (struct heci_msg_hdr) +
1031 heci_hdr->length + 3) / 4;
1032
1033 if (!heci_write_message(dev, heci_hdr,
1034 (dev->iamthif_msg_buf +
1035 dev->iamthif_msg_buf_index),
1036 heci_hdr->length)) {
1037 dev->iamthif_state = HECI_IAMTHIF_IDLE;
1038 file_ext->status = -ENODEV;
1039 list_del(&priv_cb_pos->cb_list);
1040 return (-ENODEV);
1041 } else {
1042 flow_ctrl_reduce(dev, file_ext);
1043 dev->iamthif_msg_buf_index += heci_hdr->length;
1044 priv_cb_pos->information = dev->iamthif_msg_buf_index;
1045 file_ext->status = 0;
1046 dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL;
1047 dev->iamthif_flow_control_pending = 1;
1048 /* save iamthif cb sent to pthi client */
1049 dev->iamthif_current_cb = priv_cb_pos;
1050 list_relink_node(&priv_cb_pos->cb_list,
1051 &dev->write_waiting_list.heci_cb.cb_list);
1052
1053 }
1054 } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
1055 /* buffer is still empty */
1056 heci_hdr = (struct heci_msg_hdr *)&dev->wr_msg_buf[0];
1057 heci_hdr->host_addr = file_ext->host_client_id;
1058 heci_hdr->me_addr = file_ext->me_client_id;
1059 heci_hdr->length =
1060 (*slots * sizeof (uint32_t)) - sizeof (struct heci_msg_hdr);
1061 heci_hdr->msg_complete = 0;
1062 heci_hdr->reserved = 0;
1063
1064 *slots -= (sizeof (struct heci_msg_hdr) +
1065 heci_hdr->length + 3) / 4;
1066
1067 if (!heci_write_message(dev, heci_hdr,
1068 (dev->iamthif_msg_buf +
1069 dev->iamthif_msg_buf_index),
1070 heci_hdr->length)) {
1071 file_ext->status = -ENODEV;
1072 list_del(&priv_cb_pos->cb_list);
1073 } else {
1074 dev->iamthif_msg_buf_index += heci_hdr->length;
1075 }
1076 return (-ECOMPLETE_MESSAGE);
1077 } else {
1078 return (-ECORRUPTED_MESSAGE_HEADER);
1079 }
1080
1081 return (0);
1082 }
1083
1084 /*
1085 * heci_bh_write_handler - bottom half write routine after
1086 * ISR to handle the write processing.
1087 *
1088 * @cmpl_list: An instance of our list structure
1089 * @dev: Device object for our driver
1090 * @slots: slots to write.
1091 *
1092 * @return 0 on success, <0 on failure.
1093 */
1094 static int
heci_bh_write_handler(struct io_heci_list * cmpl_list,struct iamt_heci_device * dev,int32_t * slots)1095 heci_bh_write_handler(struct io_heci_list *cmpl_list,
1096 struct iamt_heci_device *dev,
1097 int32_t *slots)
1098 {
1099
1100 struct heci_file_private *file_ext;
1101 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1102 struct io_heci_list *list;
1103 int ret;
1104
1105 if (!host_buffer_is_empty(dev)) {
1106 DBG("host buffer is not empty.\n");
1107 return (0);
1108 }
1109 dev->write_hang = (uint8_t)-1;
1110 *slots = count_empty_write_slots(dev);
1111 /* complete all waiting for write CB */
1112 DBG("complete all waiting for write cb.\n");
1113
1114 list = &dev->write_waiting_list;
1115 if ((list->status == 0) &&
1116 !list_empty(&list->heci_cb.cb_list)) {
1117 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1118 &list->heci_cb.cb_list, cb_list, struct heci_cb_private) {
1119 file_ext = (struct heci_file_private *)
1120 priv_cb_pos->file_private;
1121 if (file_ext != NULL) {
1122 file_ext->status = 0;
1123 list_del(&priv_cb_pos->cb_list);
1124 if ((HECI_WRITING == file_ext->writing_state) &&
1125 (priv_cb_pos->major_file_operations ==
1126 HECI_WRITE) &&
1127 (file_ext != &dev->iamthif_file_ext)) {
1128 DBG("HECI WRITE COMPLETE\n");
1129 file_ext->writing_state =
1130 HECI_WRITE_COMPLETE;
1131 list_add_tail(&priv_cb_pos->cb_list,
1132 &cmpl_list->heci_cb.cb_list);
1133 }
1134 if (file_ext == &dev->iamthif_file_ext) {
1135 DBG("check iamthif flow control.\n");
1136 if (dev->iamthif_flow_control_pending) {
1137 ret = _heci_bh_iamthif_read(dev,
1138 slots);
1139 if (ret != 0)
1140 return (ret);
1141 }
1142 }
1143 }
1144
1145 }
1146 }
1147
1148 if ((dev->stop) && (!dev->wd_pending)) {
1149 dev->wd_stoped = 1;
1150 cv_broadcast(&dev->wait_stop_wd);
1151 return (0);
1152 }
1153
1154 if (dev->extra_write_index != 0) {
1155 DBG("extra_write_index =%d.\n", dev->extra_write_index);
1156 if (!heci_write_message(dev,
1157 (struct heci_msg_hdr *)&dev->ext_msg_buf[0],
1158 (unsigned char *)&dev->ext_msg_buf[1],
1159 (dev->extra_write_index - 1) * sizeof (uint32_t))) {
1160 DBG("heci_bh_handler: writing msg failed\n");
1161 }
1162 *slots -= dev->extra_write_index;
1163 dev->extra_write_index = 0;
1164 }
1165 if (dev->heci_state == HECI_ENABLED) {
1166 if (dev->wd_pending &&
1167 flow_ctrl_creds(dev, &dev->wd_file_ext)) {
1168 if (!heci_send_wd(dev)) {
1169 DBG("wd send failed.\n");
1170 } else
1171 flow_ctrl_reduce(dev, &dev->wd_file_ext);
1172
1173 dev->wd_pending = 0;
1174
1175 if (dev->wd_timeout != 0) {
1176 *slots -= (sizeof (struct heci_msg_hdr) +
1177 HECI_START_WD_DATA_SIZE + 3) / 4;
1178 dev->wd_due_counter = 2;
1179 } else {
1180 *slots -= (sizeof (struct heci_msg_hdr) +
1181 HECI_WD_PARAMS_SIZE + 3) / 4;
1182 dev->wd_due_counter = 0;
1183 }
1184
1185 }
1186 }
1187 if (dev->stop)
1188 return (~ENODEV);
1189
1190 /* complete control write list CB */
1191 if (dev->ctrl_wr_list.status == 0) {
1192 /* complete control write list CB */
1193 DBG("complete control write list cb.\n");
1194 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1195 &dev->ctrl_wr_list.heci_cb.cb_list,
1196 cb_list, struct heci_cb_private) {
1197 file_ext = (struct heci_file_private *)
1198 priv_cb_pos->file_private;
1199 if (file_ext == NULL) {
1200 list_del(&priv_cb_pos->cb_list);
1201 return (-ENODEV);
1202 }
1203 switch (priv_cb_pos->major_file_operations) {
1204 case HECI_CLOSE:
1205 /* send disconnect message */
1206 ret = _heci_bh_close(dev, slots,
1207 priv_cb_pos,
1208 file_ext, cmpl_list);
1209 if (ret != 0)
1210 return (ret);
1211
1212 break;
1213 case HECI_READ:
1214 /* send flow control message */
1215 ret = _heci_bh_read(dev, slots,
1216 priv_cb_pos,
1217 file_ext, cmpl_list);
1218 if (ret != 0)
1219 return (ret);
1220
1221 break;
1222 case HECI_IOCTL:
1223 /* connect message */
1224 if (!other_client_is_connecting(dev, file_ext))
1225 continue;
1226 ret = _heci_bh_ioctl(dev, slots,
1227 priv_cb_pos,
1228 file_ext, cmpl_list);
1229 if (ret != 0)
1230 return (ret);
1231
1232 break;
1233
1234 default:
1235 ASSERT(0);
1236 }
1237
1238 }
1239 }
1240 /* complete write list CB */
1241 if ((dev->write_list.status == 0) &&
1242 !list_empty(&dev->write_list.heci_cb.cb_list)) {
1243
1244 DBG("complete write list cb.\n");
1245 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1246 &dev->write_list.heci_cb.cb_list,
1247 cb_list, struct heci_cb_private) {
1248
1249 file_ext = (struct heci_file_private *)
1250 priv_cb_pos->file_private;
1251 if (file_ext != NULL) {
1252 if (file_ext != &dev->iamthif_file_ext) {
1253 if (!flow_ctrl_creds(dev, file_ext)) {
1254 DBG("No flow control"
1255 " credentials for client"
1256 " %d, not sending.\n",
1257 file_ext->host_client_id);
1258 continue;
1259 }
1260 ret = _heci_bh_cmpl(dev, slots,
1261 priv_cb_pos, file_ext, cmpl_list);
1262 if (ret != 0)
1263 return (ret);
1264
1265 } else if (file_ext == &dev->iamthif_file_ext) {
1266 /* IAMTHIF IOCTL */
1267 DBG("complete pthi write cb.\n");
1268 if (!flow_ctrl_creds(dev, file_ext)) {
1269 DBG("No flow control"
1270 " credentials for pthi"
1271 " client %d.\n",
1272 file_ext->host_client_id);
1273 continue;
1274 }
1275 ret = _heci_bh_cmpl_iamthif(dev, slots,
1276 priv_cb_pos, file_ext, cmpl_list);
1277 if (ret != 0)
1278 return (ret);
1279
1280 }
1281 }
1282
1283 }
1284 }
1285 return (0);
1286 }
1287
1288
1289 /*
1290 * is_treat_specially_client - check if the message belong
1291 * to the file private data.
1292 *
1293 * @file_ext: private data of the file object
1294 * @rs: connect response bus message
1295 * @dev: Device object for our driver
1296 *
1297 * @return 0 on success, <0 on failure.
1298 */
1299 static int
is_treat_specially_client(struct heci_file_private * file_ext,struct hbm_client_connect_response * rs)1300 is_treat_specially_client(struct heci_file_private *file_ext,
1301 struct hbm_client_connect_response *rs)
1302 {
1303 int ret = 0;
1304
1305 if ((file_ext->host_client_id == rs->host_addr) &&
1306 (file_ext->me_client_id == rs->me_addr)) {
1307 if (rs->status == 0) {
1308 DBG("client connect status = 0x%08x.\n", rs->status);
1309 file_ext->state = HECI_FILE_CONNECTED;
1310 file_ext->status = 0;
1311 } else {
1312 DBG("client connect status = 0x%08x.\n", rs->status);
1313 file_ext->state = HECI_FILE_DISCONNECTED;
1314 file_ext->status = -ENODEV;
1315 }
1316 ret = 1;
1317 }
1318 DBG("client state = %d.\n", file_ext->state);
1319 return (ret);
1320 }
1321
1322 /*
1323 * heci_client_connect_response - connect response bh routine
1324 *
1325 * @dev: Device object for our driver
1326 * @rs: connect response bus message
1327 */
1328 static void
heci_client_connect_response(struct iamt_heci_device * dev,struct hbm_client_connect_response * rs)1329 heci_client_connect_response(struct iamt_heci_device *dev,
1330 struct hbm_client_connect_response *rs)
1331 {
1332
1333 struct heci_file_private *file_ext;
1334 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1335
1336 /* if WD or iamthif client treat specially */
1337
1338 if ((is_treat_specially_client(&(dev->wd_file_ext), rs)) ||
1339 (is_treat_specially_client(&(dev->iamthif_file_ext), rs)))
1340 return;
1341
1342 if (dev->ctrl_rd_list.status == 0 &&
1343 !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) {
1344
1345 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1346 &dev->ctrl_rd_list.heci_cb.cb_list,
1347 cb_list, struct heci_cb_private) {
1348
1349 file_ext = (struct heci_file_private *)
1350 priv_cb_pos->file_private;
1351 if (file_ext == NULL) {
1352 list_del(&priv_cb_pos->cb_list);
1353 return;
1354 }
1355 if (HECI_IOCTL == priv_cb_pos->major_file_operations) {
1356 if (is_treat_specially_client(file_ext, rs)) {
1357 list_del(&priv_cb_pos->cb_list);
1358 file_ext->status = 0;
1359 file_ext->timer_count = 0;
1360 break;
1361 }
1362 }
1363 }
1364 }
1365 }
1366
1367 /*
1368 * heci_client_disconnect_response - disconnect response bh routine
1369 *
1370 * @dev: Device object for our driver
1371 * @rs: disconnect response bus message
1372 */
heci_client_disconnect_response(struct iamt_heci_device * dev,struct hbm_client_connect_response * rs)1373 static void heci_client_disconnect_response(struct iamt_heci_device *dev,
1374 struct hbm_client_connect_response *rs)
1375 {
1376 struct heci_file_private *file_ext;
1377 struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL;
1378
1379 if (dev->ctrl_rd_list.status == 0 &&
1380 !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) {
1381
1382 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
1383 &dev->ctrl_rd_list.heci_cb.cb_list,
1384 cb_list, struct heci_cb_private) {
1385
1386 file_ext = (struct heci_file_private *)
1387 priv_cb_pos->file_private;
1388
1389 if (file_ext == NULL) {
1390 list_del(&priv_cb_pos->cb_list);
1391 return;
1392 }
1393
1394 DBG("list_for_each_entry_safe in ctrl_rd_list.\n");
1395 if ((file_ext->host_client_id == rs->host_addr) &&
1396 (file_ext->me_client_id == rs->me_addr)) {
1397
1398 list_del(&priv_cb_pos->cb_list);
1399 if (rs->status == 0) {
1400 file_ext->state =
1401 HECI_FILE_DISCONNECTED;
1402 }
1403
1404 file_ext->status = 0;
1405 file_ext->timer_count = 0;
1406 break;
1407 }
1408 }
1409 }
1410 }
1411
1412 /*
1413 * same_flow_addr - tell they have same address.
1414 *
1415 * @file: private data of the file object.
1416 * @flow: flow control.
1417 *
1418 * @return !=0, same; 0,not.
1419 */
1420 static int
same_flow_addr(struct heci_file_private * file,struct hbm_flow_control * flow)1421 same_flow_addr(struct heci_file_private *file,
1422 struct hbm_flow_control *flow)
1423 {
1424 return ((file->host_client_id == flow->host_addr) &&
1425 (file->me_client_id == flow->me_addr));
1426 }
1427
1428 /*
1429 * add_single_flow_creds - add single buffer credentials.
1430 *
1431 * @file: private data ot the file object.
1432 * @flow: flow control.
1433 */
1434 static void
add_single_flow_creds(struct iamt_heci_device * dev,struct hbm_flow_control * flow)1435 add_single_flow_creds(struct iamt_heci_device *dev,
1436 struct hbm_flow_control *flow)
1437 {
1438 struct heci_me_client *client;
1439 int i;
1440
1441 for (i = 0; i < dev->num_heci_me_clients; i++) {
1442 client = &dev->me_clients[i];
1443 if ((client != NULL) &&
1444 (flow->me_addr == client->client_id)) {
1445 if (client->props.single_recv_buf != 0) {
1446 client->flow_ctrl_creds++;
1447 DBG("recv flow ctrl msg ME %d (single).\n",
1448 flow->me_addr);
1449 DBG("flow control credentials=%d.\n",
1450 client->flow_ctrl_creds);
1451 } else {
1452 ASSERT(0); /* error in flow control */
1453 }
1454 }
1455 }
1456 }
1457 /*
1458 * heci_client_flow_control_response - flow control response bh routine
1459 *
1460 * @dev: Device object for our driver
1461 * @flow_control: flow control response bus message
1462 */
1463 static void
heci_client_flow_control_response(struct iamt_heci_device * dev,struct hbm_flow_control * flow_control)1464 heci_client_flow_control_response(struct iamt_heci_device *dev,
1465 struct hbm_flow_control *flow_control)
1466 {
1467 struct heci_file_private *file_pos = NULL;
1468 struct heci_file_private *file_next = NULL;
1469
1470 if (flow_control->host_addr == 0) {
1471 /* single receive buffer */
1472 add_single_flow_creds(dev, flow_control);
1473 } else {
1474 /* normal connection */
1475 list_for_each_entry_safe(file_pos, file_next,
1476 &dev->file_list, link, struct heci_file_private) {
1477 DBG("list_for_each_entry_safe in file_list\n");
1478
1479 DBG("file_ext of host client %d ME client %d.\n",
1480 file_pos->host_client_id,
1481 file_pos->me_client_id);
1482 DBG("flow ctrl msg for host %d ME %d.\n",
1483 flow_control->host_addr,
1484 flow_control->me_addr);
1485 if (same_flow_addr(file_pos, flow_control)) {
1486 DBG("recv ctrl msg for host %d ME %d.\n",
1487 flow_control->host_addr,
1488 flow_control->me_addr);
1489 file_pos->flow_ctrl_creds++;
1490 DBG("flow control credentials=%d.\n",
1491 file_pos->flow_ctrl_creds);
1492 break;
1493 }
1494 }
1495 }
1496 }
1497
1498 /*
1499 * same_disconn_addr - tell they have same address
1500 *
1501 * @file: private data of the file object.
1502 * @disconn: disconnection request.
1503 *
1504 * @return !=0, same; 0,not.
1505 */
1506 static int
same_disconn_addr(struct heci_file_private * file,struct hbm_client_disconnect_request * disconn)1507 same_disconn_addr(struct heci_file_private *file,
1508 struct hbm_client_disconnect_request *disconn)
1509 {
1510 return ((file->host_client_id == disconn->host_addr) &&
1511 (file->me_client_id == disconn->me_addr));
1512 }
1513
1514 /*
1515 * heci_client_disconnect_request - disconnect request bh routine
1516 *
1517 * @dev: Device object for our driver.
1518 * @disconnect_req: disconnect request bus message.
1519 */
1520 static void
heci_client_disconnect_request(struct iamt_heci_device * dev,struct hbm_client_disconnect_request * disconnect_req)1521 heci_client_disconnect_request(struct iamt_heci_device *dev,
1522 struct hbm_client_disconnect_request *disconnect_req)
1523 {
1524 struct heci_msg_hdr *heci_hdr;
1525 struct hbm_client_connect_response *disconnect_res;
1526 struct heci_file_private *file_pos = NULL;
1527 struct heci_file_private *file_next = NULL;
1528
1529 list_for_each_entry_safe(file_pos, file_next, &dev->file_list,
1530 link, struct heci_file_private) {
1531
1532 if (same_disconn_addr(file_pos, disconnect_req)) {
1533 DBG("disconnect request host client %d ME client %d.\n",
1534 disconnect_req->host_addr,
1535 disconnect_req->me_addr);
1536 file_pos->state = HECI_FILE_DISCONNECTED;
1537 file_pos->timer_count = 0;
1538 if (file_pos == &dev->wd_file_ext) {
1539 dev->wd_due_counter = 0;
1540 dev->wd_pending = 0;
1541 } else if (file_pos == &dev->iamthif_file_ext)
1542 dev->iamthif_timer = 0;
1543
1544 /* prepare disconnect response */
1545 heci_hdr =
1546 (struct heci_msg_hdr *)&dev->ext_msg_buf[0];
1547 heci_hdr->host_addr = 0;
1548 heci_hdr->me_addr = 0;
1549 heci_hdr->length =
1550 sizeof (struct hbm_client_connect_response);
1551 heci_hdr->msg_complete = 1;
1552 heci_hdr->reserved = 0;
1553
1554 disconnect_res =
1555 (struct hbm_client_connect_response *)
1556 &dev->ext_msg_buf[1];
1557 disconnect_res->host_addr = file_pos->host_client_id;
1558 disconnect_res->me_addr = file_pos->me_client_id;
1559 *(uint8_t *)(&disconnect_res->cmd) =
1560 CLIENT_DISCONNECT_RES_CMD;
1561 disconnect_res->status = 0;
1562 dev->extra_write_index = 2;
1563 break;
1564 }
1565 }
1566 }
1567
1568 /*
1569 * heci_timer - timer function.
1570 *
1571 * @data: pointer to the device structure
1572 *
1573 * NOTE: This function is called by timer interrupt work
1574 */
1575 void
heci_wd_timer(void * data)1576 heci_wd_timer(void *data)
1577 {
1578 struct iamt_heci_device *dev = (struct iamt_heci_device *)data;
1579
1580 DBG("send watchdog.\n");
1581 mutex_enter(&dev->device_lock);
1582 if (dev->heci_state != HECI_ENABLED) {
1583 dev->wd_timer = timeout(heci_wd_timer, data, 2 * HZ);
1584 mutex_exit(&dev->device_lock);
1585 return;
1586 }
1587 if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) {
1588 dev->wd_timer = timeout(heci_wd_timer, data, 2 * HZ);
1589 mutex_exit(&dev->device_lock);
1590 return;
1591 }
1592 /* Watchdog */
1593 if ((dev->wd_due_counter != 0) && (dev->wd_bypass == 0)) {
1594 if (--dev->wd_due_counter == 0) {
1595 if (dev->host_buffer_is_empty &&
1596 flow_ctrl_creds(dev, &dev->wd_file_ext)) {
1597 dev->host_buffer_is_empty = 0;
1598 if (!heci_send_wd(dev)) {
1599 DBG("wd send failed.\n");
1600 } else {
1601 flow_ctrl_reduce(dev,
1602 &dev->wd_file_ext);
1603 }
1604
1605 if (dev->wd_timeout != 0)
1606 dev->wd_due_counter = 2;
1607 else
1608 dev->wd_due_counter = 0;
1609
1610 } else
1611 dev->wd_pending = 1;
1612
1613 }
1614 }
1615 if (dev->iamthif_stall_timer != 0) {
1616 if (--dev->iamthif_stall_timer == 0) {
1617 DBG("reseting because of hang to PTHI.\n");
1618 heci_reset(dev, 1);
1619 dev->iamthif_msg_buf_size = 0;
1620 dev->iamthif_msg_buf_index = 0;
1621 dev->iamthif_canceled = 0;
1622 dev->iamthif_ioctl = 1;
1623 dev->iamthif_state = HECI_IAMTHIF_IDLE;
1624 dev->iamthif_timer = 0;
1625 mutex_exit(&dev->device_lock);
1626
1627 if (dev->iamthif_current_cb)
1628 heci_free_cb_private(dev->iamthif_current_cb);
1629
1630 mutex_enter(&dev->device_lock);
1631 dev->iamthif_file_object = NULL;
1632 dev->iamthif_current_cb = NULL;
1633 run_next_iamthif_cmd(dev);
1634 }
1635 }
1636 dev->wd_timer = timeout(heci_wd_timer, data, 2 * HZ);
1637 mutex_exit(&dev->device_lock);
1638 }
1639