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/note.h> 48 #include <sys/cmn_err.h> 49 #include <sys/conf.h> 50 #include <sys/ddi.h> 51 #include <sys/ddi_impldefs.h> 52 #include <sys/devops.h> 53 #include <sys/instance.h> 54 #include <sys/modctl.h> 55 #include <sys/open.h> 56 #include <sys/stat.h> 57 #include <sys/sunddi.h> 58 #include <sys/sunndi.h> 59 #include <sys/systm.h> 60 #include <sys/mkdev.h> 61 #include <sys/list.h> 62 #include "heci_data_structures.h" 63 #include "heci.h" 64 #include "heci_interface.h" 65 #include "version.h" 66 67 68 static inline int heci_fe_same_id(struct heci_file_private *fe1, 69 struct heci_file_private *fe2); 70 /* 71 * heci_ioctl_get_version - the get driver version IOCTL function 72 * 73 * @dev: Device object for our driver 74 * @if_num: minor number 75 * @*u_msg: pointer to user data struct in user space 76 * @k_msg: data in kernel on the stack 77 * @file_ext: private data of the file object 78 * 79 * @return 0 on success, <0 on failure. 80 */ 81 int 82 heci_ioctl_get_version(struct iamt_heci_device *dev, int if_num, 83 struct heci_message_data *u_msg, 84 struct heci_message_data k_msg, 85 struct heci_file_private *file_ext, int mode) 86 { 87 88 int rets = 0; 89 struct heci_driver_version *version; 90 struct heci_message_data res_msg; 91 92 if ((if_num < HECI_MINOR_NUMBER) || (!dev) || 93 (!file_ext)) 94 return (-ENODEV); 95 96 if (k_msg.size < (sizeof (struct heci_driver_version) - 2)) { 97 DBG("user buffer less than heci_driver_version.\n"); 98 return (-EMSGSIZE); 99 } 100 101 res_msg.data = kmem_zalloc(sizeof (struct heci_driver_version), 102 KM_SLEEP); 103 if (!res_msg.data) { 104 DBG("failed allocation response buffer size = %d.\n", 105 (int)sizeof (struct heci_driver_version)); 106 return (-ENOMEM); 107 } 108 109 version = (struct heci_driver_version *)res_msg.data; 110 version->major = MAJOR_VERSION; 111 version->minor = MINOR_VERSION; 112 version->hotfix = QUICK_FIX_NUMBER; 113 version->build = VER_BUILD; 114 res_msg.size = sizeof (struct heci_driver_version); 115 if (k_msg.size < sizeof (struct heci_driver_version)) 116 res_msg.size -= 2; 117 118 rets = file_ext->status; 119 /* now copy the data to user space */ 120 if (ddi_copyout(res_msg.data, k_msg.data, res_msg.size, mode)) { 121 rets = -EFAULT; 122 goto end; 123 } 124 if (ddi_copyout(&res_msg.size, &u_msg->size, sizeof (uint32_t), mode)) { 125 rets = -EFAULT; 126 goto end; 127 } 128 end: 129 kmem_free(res_msg.data, sizeof (struct heci_driver_version)); 130 return (rets); 131 } 132 133 /* 134 * heci_ioctl_connect_client - the connect to fw client IOCTL function 135 * 136 * @dev: Device object for our driver 137 * @if_num: minor number 138 * @*u_msg: pointer to user data struct in user space 139 * @k_msg: data in kernel on the stack 140 * @file_ext: private data of the file object 141 * 142 * @return 0 on success, <0 on failure. 143 */ 144 int 145 heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, 146 struct heci_message_data *u_msg, 147 struct heci_message_data k_msg, 148 struct heci_file *file, int mode) 149 { 150 151 int rets = 0; 152 struct heci_message_data req_msg, res_msg; 153 struct heci_cb_private *priv_cb = NULL; 154 struct heci_client *client; 155 struct heci_file_private *file_ext; 156 struct heci_file_private *file_pos = NULL; 157 struct heci_file_private *file_next = NULL; 158 long timeout = 15; /* 15 second */ 159 uint8_t i; 160 int err = 0; 161 162 if ((if_num < HECI_MINOR_NUMBER) || (!dev) || (!file)) 163 return (-ENODEV); 164 165 file_ext = file->private_data; 166 if (!file_ext) 167 return (-ENODEV); 168 169 if (k_msg.size != sizeof (struct guid)) { 170 DBG("user buffer size is not equal to size of struct " 171 "guid(16).\n"); 172 return (-EMSGSIZE); 173 } 174 175 if (!k_msg.data) 176 return (-EIO); 177 178 req_msg.data = kmem_zalloc(sizeof (struct guid), KM_SLEEP); 179 res_msg.data = kmem_zalloc(sizeof (struct heci_client), KM_SLEEP); 180 181 if (!res_msg.data) { 182 DBG("failed allocation response buffer size = %d.\n", 183 (int)sizeof (struct heci_client)); 184 kmem_free(req_msg.data, sizeof (struct guid)); 185 return (-ENOMEM); 186 } 187 if (!req_msg.data) { 188 DBG("failed allocation request buffer size = %d.\n", 189 (int)sizeof (struct guid)); 190 if (res_msg.data) { 191 kmem_free(res_msg.data, sizeof (struct heci_client)); 192 res_msg.data = NULL; 193 goto fail; 194 } 195 fail: 196 return (-ENOMEM); 197 } 198 req_msg.size = sizeof (struct guid); 199 res_msg.size = sizeof (struct heci_client); 200 201 /* 202 * copy the message to kernel space - 203 * use a pointer already copied into kernel space 204 */ 205 if (ddi_copyin(k_msg.data, req_msg.data, k_msg.size, mode)) { 206 rets = -EFAULT; 207 goto end; 208 } 209 /* buffered ioctl cb */ 210 priv_cb = kmem_zalloc(sizeof (struct heci_cb_private), KM_SLEEP); 211 if (!priv_cb) { 212 rets = -ENOMEM; 213 goto end; 214 } 215 LIST_INIT_HEAD(&priv_cb->cb_list); 216 priv_cb->response_buffer.data = res_msg.data; 217 priv_cb->response_buffer.size = res_msg.size; 218 priv_cb->request_buffer.data = req_msg.data; 219 priv_cb->request_buffer.size = req_msg.size; 220 priv_cb->major_file_operations = HECI_IOCTL; 221 mutex_enter(&dev->device_lock); 222 if (dev->heci_state != HECI_ENABLED) { 223 rets = -ENODEV; 224 mutex_exit(&dev->device_lock); 225 goto end; 226 } 227 if ((file_ext->state != HECI_FILE_INITIALIZING) && 228 (file_ext->state != HECI_FILE_DISCONNECTED)) { 229 rets = -EBUSY; 230 mutex_exit(&dev->device_lock); 231 goto end; 232 } 233 234 DBG("req_msg.data:%x", *(uint32_t *)(void *)req_msg.data); 235 /* find ME client we're trying to connect to */ 236 for (i = 0; i < dev->num_heci_me_clients; i++) { 237 DBG("guid:%x, me_client_id:%d\n", 238 dev->me_clients[i].props.protocol_name.data1, 239 dev->me_clients[i].client_id); 240 if (memcmp((struct guid *)req_msg.data, 241 &dev->me_clients[i].props.protocol_name, 242 sizeof (struct guid)) == 0) { 243 if (dev->me_clients[i].props.fixed_address == 0) { 244 file_ext->me_client_id = 245 dev->me_clients[i].client_id; 246 file_ext->state = HECI_FILE_CONNECTING; 247 } 248 break; 249 } 250 } 251 /* 252 * if we're connecting to PTHI client so we will use the exist 253 * connection 254 */ 255 if (memcmp((struct guid *)req_msg.data, &heci_pthi_guid, 256 sizeof (struct guid)) == 0) { 257 if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) { 258 rets = -ENODEV; 259 mutex_exit(&dev->device_lock); 260 goto end; 261 } 262 dev->heci_host_clients[file_ext->host_client_id / 8] &= 263 ~(1 << (file_ext->host_client_id % 8)); 264 list_for_each_entry_safe(file_pos, 265 file_next, &dev->file_list, link, 266 struct heci_file_private) { 267 if (heci_fe_same_id(file_ext, file_pos)) { 268 DBG("remove file private data node host" 269 " client = %d, ME client = %d.\n", 270 file_pos->host_client_id, 271 file_pos->me_client_id); 272 list_del(&file_pos->link); 273 } 274 275 } 276 DBG("free file private data memory.\n"); 277 kmem_free(file_ext, sizeof (struct heci_file_private)); 278 file_ext = NULL; 279 file->private_data = &dev->iamthif_file_ext; 280 client = (struct heci_client *)res_msg.data; 281 client->max_message_length = 282 dev->me_clients[i].props.max_msg_length; 283 client->protocol_version = 284 dev->me_clients[i].props.protocol_version; 285 rets = dev->iamthif_file_ext.status; 286 mutex_exit(&dev->device_lock); 287 288 /* now copy the data to user space */ 289 if (ddi_copyout(res_msg.data, k_msg.data, res_msg.size, mode)) { 290 cmn_err(CE_WARN, "ddi_copyout error on res_msg.data"); 291 rets = -EFAULT; 292 goto end; 293 } 294 if (ddi_copyout(&res_msg.size, &u_msg->size, 295 sizeof (uint32_t), mode)) { 296 cmn_err(CE_WARN, "ddi_copyout error on res_msg.size"); 297 rets = -EFAULT; 298 goto end; 299 } 300 goto end; 301 } 302 mutex_enter(&file_ext->file_lock); 303 if (file_ext->state != HECI_FILE_CONNECTING) { 304 rets = -ENODEV; 305 mutex_exit(&file_ext->file_lock); 306 mutex_exit(&dev->device_lock); 307 goto end; 308 } 309 mutex_exit(&file_ext->file_lock); 310 /* prepare the output buffer */ 311 client = (struct heci_client *)res_msg.data; 312 client->max_message_length = dev->me_clients[i].props.max_msg_length; 313 client->protocol_version = dev->me_clients[i].props.protocol_version; 314 if (dev->host_buffer_is_empty && 315 !other_client_is_connecting(dev, file_ext)) { 316 dev->host_buffer_is_empty = 0; 317 if (!heci_connect(dev, file_ext)) { 318 rets = -ENODEV; 319 mutex_exit(&dev->device_lock); 320 goto end; 321 } else { 322 file_ext->timer_count = HECI_CONNECT_TIMEOUT; 323 priv_cb->file_private = file_ext; 324 list_add_tail(&priv_cb->cb_list, 325 &dev->ctrl_rd_list.heci_cb. 326 cb_list); 327 } 328 329 330 } else { 331 priv_cb->file_private = file_ext; 332 DBG("add connect cb to control write list.\n"); 333 list_add_tail(&priv_cb->cb_list, 334 &dev->ctrl_wr_list.heci_cb.cb_list); 335 } 336 err = 0; 337 while (err != -1 && HECI_FILE_CONNECTED != file_ext->state && 338 HECI_FILE_DISCONNECTED != file_ext->state) { 339 err = cv_reltimedwait(&dev->wait_recvd_msg, 340 &dev->device_lock, timeout * HZ, TR_CLOCK_TICK); 341 } 342 mutex_exit(&dev->device_lock); 343 344 if (HECI_FILE_CONNECTED == file_ext->state) { 345 DBG("successfully connected to FW client." 346 " me_client_id:%d, host_client_id:%d\n", 347 file_ext->me_client_id, 348 file_ext->host_client_id); 349 rets = file_ext->status; 350 /* now copy the data to user space */ 351 if (ddi_copyout(res_msg.data, k_msg.data, res_msg.size, mode)) { 352 rets = -EFAULT; 353 goto end; 354 } 355 if (ddi_copyout(&res_msg.size, &u_msg->size, 356 sizeof (uint32_t), mode)) { 357 rets = -EFAULT; 358 goto end; 359 } 360 goto end; 361 } else { 362 DBG("failed to connect to FW client.file_ext->state = %d," 363 " me_client_id:%d, host_client_id:%d\n", 364 file_ext->state, file_ext->me_client_id, 365 file_ext->host_client_id); 366 if (!err) { 367 DBG("wait_event_interruptible_timeout failed on client" 368 " connect message fw response message.\n"); 369 } 370 rets = -EFAULT; 371 goto remove_list; 372 } 373 374 remove_list: 375 if (priv_cb) { 376 mutex_enter(&dev->device_lock); 377 heci_flush_list(&dev->ctrl_rd_list, file_ext); 378 heci_flush_list(&dev->ctrl_wr_list, file_ext); 379 mutex_exit(&dev->device_lock); 380 } 381 end: 382 DBG("free connect cb memory."); 383 kmem_free(req_msg.data, sizeof (struct guid)); 384 req_msg.data = NULL; 385 kmem_free(res_msg.data, sizeof (struct heci_client)); 386 res_msg.data = NULL; 387 if (priv_cb) { 388 kmem_free(priv_cb, sizeof (struct heci_cb_private)); 389 priv_cb = NULL; 390 } 391 return (rets); 392 } 393 394 /* 395 * heci_ioctl_wd - the wd IOCTL function 396 * 397 * @dev: Device object for our driver 398 * @if_num: minor number 399 * @k_msg: data in kernel on the stack 400 * @file_ext: private data of the file object 401 * 402 * @return 0 on success, <0 on failure. 403 */ 404 int 405 heci_ioctl_wd(struct iamt_heci_device *dev, int if_num, 406 struct heci_message_data k_msg, 407 struct heci_file_private *file_ext, int mode) 408 { 409 int rets = 0; 410 struct heci_message_data req_msg; /* in kernel on the stack */ 411 412 if (if_num < HECI_MINOR_NUMBER) 413 return (-ENODEV); 414 415 mutex_enter(&file_ext->file_lock); 416 if (k_msg.size != HECI_WATCHDOG_DATA_SIZE) { 417 DBG("user buffer has invalid size.\n"); 418 mutex_exit(&file_ext->file_lock); 419 return (-EMSGSIZE); 420 } 421 mutex_exit(&file_ext->file_lock); 422 423 req_msg.data = kmem_zalloc(HECI_WATCHDOG_DATA_SIZE, KM_SLEEP); 424 if (!req_msg.data) { 425 DBG("failed allocation request buffer size = %d.\n", 426 HECI_WATCHDOG_DATA_SIZE); 427 return (-ENOMEM); 428 } 429 req_msg.size = HECI_WATCHDOG_DATA_SIZE; 430 431 /* 432 * copy the message to kernel space - use a pointer already 433 * copied into kernel space 434 */ 435 if (ddi_copyin(k_msg.data, req_msg.data, k_msg.size, mode)) { 436 rets = -EFAULT; 437 goto end; 438 } 439 mutex_enter(&dev->device_lock); 440 if (dev->heci_state != HECI_ENABLED) { 441 rets = -ENODEV; 442 mutex_exit(&dev->device_lock); 443 goto end; 444 } 445 446 if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) { 447 rets = -ENODEV; 448 mutex_exit(&dev->device_lock); 449 goto end; 450 } 451 if (!dev->asf_mode) { 452 rets = -EIO; 453 mutex_exit(&dev->device_lock); 454 goto end; 455 } 456 457 (void) memcpy(&dev->wd_data[HECI_WD_PARAMS_SIZE], req_msg.data, 458 HECI_WATCHDOG_DATA_SIZE); 459 460 dev->wd_timeout = (req_msg.data[1] << 8) + req_msg.data[0]; 461 dev->wd_pending = 0; 462 dev->wd_due_counter = 1; /* next timer */ 463 if (dev->wd_timeout == 0) { 464 (void) memcpy(dev->wd_data, &stop_wd_params, 465 HECI_WD_PARAMS_SIZE); 466 } else { 467 (void) memcpy(dev->wd_data, &start_wd_params, 468 HECI_WD_PARAMS_SIZE); 469 dev->wd_timer = timeout(heci_wd_timer, dev, 1); 470 } 471 mutex_exit(&dev->device_lock); 472 end: 473 kmem_free(req_msg.data, HECI_WATCHDOG_DATA_SIZE); 474 return (rets); 475 } 476 477 478 /* 479 * heci_ioctl_bypass_wd - the bypass_wd IOCTL function 480 * 481 * @dev: Device object for our driver 482 * @if_num: minor number 483 * @k_msg: data in kernel on the stack 484 * @file_ext: private data of the file object 485 * 486 * @return 0 on success, <0 on failure. 487 */ 488 int 489 heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num, 490 struct heci_message_data k_msg, 491 struct heci_file_private *file_ext, int mode) 492 { 493 uint8_t flag = 0; 494 int rets = 0; 495 496 if (if_num < HECI_MINOR_NUMBER) 497 return (-ENODEV); 498 499 mutex_enter(&file_ext->file_lock); 500 if (k_msg.size < 1) { 501 DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE.\n"); 502 mutex_exit(&file_ext->file_lock); 503 return (-EMSGSIZE); 504 } 505 mutex_exit(&file_ext->file_lock); 506 if (ddi_copyin(k_msg.data, &flag, 1, mode)) { 507 rets = -EFAULT; 508 goto end; 509 } 510 511 mutex_enter(&dev->device_lock); 512 flag = flag ? (1) : (0); 513 dev->wd_bypass = flag; 514 mutex_exit(&dev->device_lock); 515 end: 516 return (rets); 517 } 518 519 /* 520 * find_pthi_read_list_entry - finds a PTHIlist entry for current file 521 * 522 * @dev: Device object for our driver 523 * @file: pointer to file object 524 * 525 * @return returned a list entry on success, NULL on failure. 526 */ 527 struct heci_cb_private * 528 find_pthi_read_list_entry( 529 struct iamt_heci_device *dev, 530 struct heci_file *file) 531 { 532 struct heci_file_private *file_ext_temp; 533 struct heci_cb_private *priv_cb_pos = NULL; 534 struct heci_cb_private *priv_cb_next = NULL; 535 536 if ((dev->pthi_read_complete_list.status == 0) && 537 !list_empty(&dev->pthi_read_complete_list.heci_cb.cb_list)) { 538 539 list_for_each_entry_safe(priv_cb_pos, priv_cb_next, 540 &dev->pthi_read_complete_list.heci_cb.cb_list, cb_list, 541 struct heci_cb_private) { 542 543 file_ext_temp = (struct heci_file_private *) 544 priv_cb_pos->file_private; 545 if ((file_ext_temp != NULL) && 546 (file_ext_temp == &dev->iamthif_file_ext) && 547 (priv_cb_pos->file_object == file)) 548 return (priv_cb_pos); 549 } 550 } 551 return (NULL); 552 } 553 554 /* 555 * pthi_read - read data from pthi client 556 * 557 * @dev: Device object for our driver 558 * @if_num: minor number 559 * @file: pointer to file object 560 * @*ubuf: pointer to user data in user space 561 * @length: data length to read 562 * @offset: data read offset 563 * 564 * @return 565 * returned data length on success, 566 * zero if no data to read, 567 * negative on failure. 568 */ 569 int 570 pthi_read(struct iamt_heci_device *dev, int if_num, struct heci_file *file, 571 struct uio *uio_p) 572 { 573 574 int rets = 0; 575 struct heci_cb_private *priv_cb = NULL; 576 struct heci_file_private *file_ext = file->private_data; 577 uint8_t i; 578 unsigned long currtime = ddi_get_time(); 579 580 if ((if_num < HECI_MINOR_NUMBER) || (!dev)) 581 return (-ENODEV); 582 583 if ((file_ext == NULL) || (file_ext != &dev->iamthif_file_ext)) 584 return (-ENODEV); 585 586 mutex_enter(&dev->device_lock); 587 for (i = 0; i < dev->num_heci_me_clients; i++) { 588 if (dev->me_clients[i].client_id == 589 dev->iamthif_file_ext.me_client_id) 590 break; 591 } 592 ASSERT(dev->me_clients[i].client_id == file_ext->me_client_id); 593 if ((i == dev->num_heci_me_clients) || 594 (dev->me_clients[i].client_id != 595 dev->iamthif_file_ext.me_client_id)) { 596 DBG("PTHI client not found.\n"); 597 mutex_exit(&dev->device_lock); 598 return (-ENODEV); 599 } 600 priv_cb = find_pthi_read_list_entry(dev, file); 601 if (!priv_cb) { 602 mutex_exit(&dev->device_lock); 603 return (0); /* No more data to read */ 604 } else { 605 if (priv_cb && 606 (currtime - priv_cb->read_time > IAMTHIF_READ_TIMER)) { 607 /* 15 sec for the message has expired */ 608 list_del(&priv_cb->cb_list); 609 mutex_exit(&dev->device_lock); 610 rets = -ETIMEDOUT; 611 goto free; 612 } 613 /* if the whole message will fit remove it from the list */ 614 if ((priv_cb->information >= UIO_OFFSET(uio_p)) && 615 (UIO_LENGTH(uio_p) >= 616 (priv_cb->information - UIO_OFFSET(uio_p)))) { 617 618 list_del(&priv_cb->cb_list); 619 620 } else if ((priv_cb->information > 0) && 621 (priv_cb->information <= UIO_OFFSET(uio_p))) { 622 623 /* end of the message has been reached */ 624 list_del(&priv_cb->cb_list); 625 rets = 0; 626 mutex_exit(&dev->device_lock); 627 goto free; 628 } 629 /* 630 * else means that not full buffer will be read and do not 631 * remove message from deletion list 632 */ 633 } 634 DBG("pthi priv_cb->response_buffer size - %d\n", 635 priv_cb->response_buffer.size); 636 DBG("pthi priv_cb->information - %lu\n", 637 priv_cb->information); 638 mutex_exit(&dev->device_lock); 639 640 rets = uiomove(priv_cb->response_buffer.data, 641 min(uio_p->uio_resid, priv_cb->information), 642 UIO_READ, uio_p); 643 free: 644 DBG("free pthi cb memory.\n"); 645 kmem_free(priv_cb->request_buffer.data, priv_cb->request_buffer.size); 646 kmem_free(priv_cb->response_buffer.data, priv_cb->response_buffer.size); 647 kmem_free(priv_cb, sizeof (struct heci_cb_private)); 648 return (rets); 649 } 650 651 /* 652 * heci_start_read - the start read client message function. 653 * 654 * @dev: Device object for our driver 655 * @if_num: minor number 656 * @file_ext: private data of the file object 657 * 658 * @return 0 on success, <0 on failure. 659 */ 660 int 661 heci_start_read(struct iamt_heci_device *dev, int if_num, 662 struct heci_file_private *file_ext) 663 { 664 int rets = 0; 665 uint8_t i; 666 struct heci_cb_private *priv_cb = NULL; 667 668 if ((if_num < HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) { 669 DBG("received wrong function input param.\n"); 670 return (-ENODEV); 671 } 672 if (file_ext->state != HECI_FILE_CONNECTED) 673 return (-ENODEV); 674 675 mutex_enter(&dev->device_lock); 676 if (dev->heci_state != HECI_ENABLED) { 677 mutex_exit(&dev->device_lock); 678 return (-ENODEV); 679 } 680 mutex_exit(&dev->device_lock); 681 DBG("check if read is pending.\n"); 682 if ((file_ext->read_pending) || (file_ext->read_cb != NULL)) { 683 DBG("read is pending.\n"); 684 return (-EBUSY); 685 } 686 priv_cb = kmem_zalloc(sizeof (struct heci_cb_private), KM_SLEEP); 687 if (!priv_cb) 688 return (-ENOMEM); 689 690 DBG("allocation call back success\n" 691 "host client = %d, ME client = %d\n", 692 file_ext->host_client_id, file_ext->me_client_id); 693 mutex_enter(&dev->device_lock); 694 for (i = 0; i < dev->num_heci_me_clients; i++) { 695 if (dev->me_clients[i].client_id == file_ext->me_client_id) 696 break; 697 698 } 699 700 ASSERT(dev->me_clients[i].client_id == file_ext->me_client_id); 701 if (i == dev->num_heci_me_clients) { 702 rets = -ENODEV; 703 goto unlock; 704 } 705 706 priv_cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; 707 mutex_exit(&dev->device_lock); 708 priv_cb->response_buffer.data = 709 kmem_zalloc(priv_cb->response_buffer.size, KM_SLEEP); 710 if (!priv_cb->response_buffer.data) { 711 rets = -ENOMEM; 712 goto fail; 713 } 714 DBG("allocation call back data success.\n"); 715 priv_cb->major_file_operations = HECI_READ; 716 /* make sure information is zero before we start */ 717 priv_cb->information = 0; 718 priv_cb->file_private = (void *)file_ext; 719 file_ext->read_cb = priv_cb; 720 mutex_enter(&dev->device_lock); 721 if (dev->host_buffer_is_empty) { 722 dev->host_buffer_is_empty = 0; 723 if (!heci_send_flow_control(dev, file_ext)) { 724 rets = -ENODEV; 725 goto unlock; 726 } else { 727 list_add_tail(&priv_cb->cb_list, 728 &dev->read_list.heci_cb.cb_list); 729 } 730 } else { 731 list_add_tail(&priv_cb->cb_list, 732 &dev->ctrl_wr_list.heci_cb.cb_list); 733 } 734 mutex_exit(&dev->device_lock); 735 return (rets); 736 unlock: 737 mutex_exit(&dev->device_lock); 738 fail: 739 heci_free_cb_private(priv_cb); 740 return (rets); 741 } 742 743 /* 744 * pthi_write: write iamthif data to pthi client 745 * 746 * @dev: Device object for our driver 747 * @priv_cb: heci call back struct 748 * 749 * @return 0 on success, <0 on failure. 750 */ 751 int 752 pthi_write(struct iamt_heci_device *dev, 753 struct heci_cb_private *priv_cb) 754 { 755 int rets = 0; 756 struct heci_msg_hdr heci_hdr; 757 758 if ((!dev) || (!priv_cb)) 759 return (-ENODEV); 760 761 DBG("write data to pthi client.\n"); 762 763 dev->iamthif_state = HECI_IAMTHIF_WRITING; 764 dev->iamthif_current_cb = priv_cb; 765 dev->iamthif_file_object = priv_cb->file_object; 766 dev->iamthif_canceled = 0; 767 dev->iamthif_ioctl = 1; 768 dev->iamthif_msg_buf_size = priv_cb->request_buffer.size; 769 (void) memcpy(dev->iamthif_msg_buf, priv_cb->request_buffer.data, 770 priv_cb->request_buffer.size); 771 772 if (flow_ctrl_creds(dev, &dev->iamthif_file_ext) && 773 dev->host_buffer_is_empty) { 774 dev->host_buffer_is_empty = 0; 775 if (priv_cb->request_buffer.size > 776 (((dev->host_hw_state & H_CBD) >> 24) * 777 sizeof (uint32_t)) - sizeof (struct heci_msg_hdr)) { 778 heci_hdr.length = 779 (((dev->host_hw_state & H_CBD) >> 24) * 780 sizeof (uint32_t)) - sizeof (struct heci_msg_hdr); 781 heci_hdr.msg_complete = 0; 782 } else { 783 heci_hdr.length = priv_cb->request_buffer.size; 784 heci_hdr.msg_complete = 1; 785 } 786 787 heci_hdr.host_addr = dev->iamthif_file_ext.host_client_id; 788 heci_hdr.me_addr = dev->iamthif_file_ext.me_client_id; 789 heci_hdr.reserved = 0; 790 dev->iamthif_msg_buf_index += heci_hdr.length; 791 if (!heci_write_message(dev, &heci_hdr, 792 (unsigned char *)(dev->iamthif_msg_buf), 793 heci_hdr.length)) 794 return (-ENODEV); 795 796 if (heci_hdr.msg_complete) { 797 flow_ctrl_reduce(dev, &dev->iamthif_file_ext); 798 dev->iamthif_flow_control_pending = 1; 799 dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL; 800 DBG("add pthi cb to write waiting list\n"); 801 dev->iamthif_current_cb = priv_cb; 802 dev->iamthif_file_object = priv_cb->file_object; 803 list_add_tail(&priv_cb->cb_list, 804 &dev->write_waiting_list.heci_cb.cb_list); 805 } else { 806 DBG("message does not complete, " 807 "so add pthi cb to write list.\n"); 808 list_add_tail(&priv_cb->cb_list, 809 &dev->write_list.heci_cb.cb_list); 810 } 811 } else { 812 if (!(dev->host_buffer_is_empty)) 813 DBG("host buffer is not empty"); 814 815 DBG("No flow control credentials, " 816 "so add iamthif cb to write list.\n"); 817 list_add_tail(&priv_cb->cb_list, 818 &dev->write_list.heci_cb.cb_list); 819 } 820 return (rets); 821 } 822 823 /* 824 * iamthif_ioctl_send_msg - send cmd data to pthi client 825 * 826 * @dev: Device object for our driver 827 * 828 * @return 0 on success, <0 on failure. 829 */ 830 void 831 run_next_iamthif_cmd(struct iamt_heci_device *dev) 832 { 833 struct heci_file_private *file_ext_tmp; 834 struct heci_cb_private *priv_cb_pos = NULL; 835 struct heci_cb_private *priv_cb_next = NULL; 836 int status = 0; 837 838 if (!dev) 839 return; 840 841 dev->iamthif_msg_buf_size = 0; 842 dev->iamthif_msg_buf_index = 0; 843 dev->iamthif_canceled = 0; 844 dev->iamthif_ioctl = 1; 845 dev->iamthif_state = HECI_IAMTHIF_IDLE; 846 dev->iamthif_timer = 0; 847 dev->iamthif_file_object = NULL; 848 849 if (dev->pthi_cmd_list.status == 0 && 850 !list_empty(&dev->pthi_cmd_list.heci_cb.cb_list)) { 851 DBG("complete pthi cmd_list cb.\n"); 852 853 list_for_each_entry_safe(priv_cb_pos, priv_cb_next, 854 &dev->pthi_cmd_list.heci_cb.cb_list, cb_list, 855 struct heci_cb_private) { 856 857 list_del(&priv_cb_pos->cb_list); 858 file_ext_tmp = (struct heci_file_private *) 859 priv_cb_pos->file_private; 860 861 if ((file_ext_tmp != NULL) && 862 (file_ext_tmp == &dev->iamthif_file_ext)) { 863 status = pthi_write(dev, priv_cb_pos); 864 if (status != 0) { 865 DBG("pthi write failed status = %d\n", 866 status); 867 return; 868 } 869 break; 870 } 871 } 872 } 873 } 874 875 /* 876 * heci_free_cb_private - free heci_cb_private related memory 877 * 878 * @priv_cb: heci callback struct 879 */ 880 void 881 heci_free_cb_private(struct heci_cb_private *priv_cb) 882 { 883 if (priv_cb == NULL) 884 return; 885 886 kmem_free(priv_cb->request_buffer.data, priv_cb->request_buffer.size); 887 kmem_free(priv_cb->response_buffer.data, priv_cb->response_buffer.size); 888 kmem_free(priv_cb, sizeof (struct heci_cb_private)); 889 } 890 891 /* 892 * heci_fe_same_id - tell if file private data have same id 893 * 894 * @fe1: private data of 1. file object 895 * @fe2: private data of 2. file object 896 * 897 * @return !=0 - if ids are the same, 0 - if differ. 898 */ 899 static inline int heci_fe_same_id(struct heci_file_private *fe1, 900 struct heci_file_private *fe2) 901 { 902 return ((fe1->host_client_id == fe2->host_client_id) && 903 (fe1->me_client_id == fe2->me_client_id)); 904 } 905