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 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 */ 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 */ 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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_WRITING) && 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 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 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 */ 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 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 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 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 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 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 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