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 clock_t tm; 340 tm = ddi_get_lbolt(); 341 err = cv_timedwait(&dev->wait_recvd_msg, 342 &dev->device_lock, tm + timeout * HZ); 343 } 344 mutex_exit(&dev->device_lock); 345 346 if (HECI_FILE_CONNECTED == file_ext->state) { 347 DBG("successfully connected to FW client." 348 " me_client_id:%d, host_client_id:%d\n", 349 file_ext->me_client_id, 350 file_ext->host_client_id); 351 rets = file_ext->status; 352 /* now copy the data to user space */ 353 if (ddi_copyout(res_msg.data, k_msg.data, res_msg.size, mode)) { 354 rets = -EFAULT; 355 goto end; 356 } 357 if (ddi_copyout(&res_msg.size, &u_msg->size, 358 sizeof (uint32_t), mode)) { 359 rets = -EFAULT; 360 goto end; 361 } 362 goto end; 363 } else { 364 DBG("failed to connect to FW client.file_ext->state = %d," 365 " me_client_id:%d, host_client_id:%d\n", 366 file_ext->state, file_ext->me_client_id, 367 file_ext->host_client_id); 368 if (!err) { 369 DBG("wait_event_interruptible_timeout failed on client" 370 " connect message fw response message.\n"); 371 } 372 rets = -EFAULT; 373 goto remove_list; 374 } 375 376 remove_list: 377 if (priv_cb) { 378 mutex_enter(&dev->device_lock); 379 heci_flush_list(&dev->ctrl_rd_list, file_ext); 380 heci_flush_list(&dev->ctrl_wr_list, file_ext); 381 mutex_exit(&dev->device_lock); 382 } 383 end: 384 DBG("free connect cb memory."); 385 kmem_free(req_msg.data, sizeof (struct guid)); 386 req_msg.data = NULL; 387 kmem_free(res_msg.data, sizeof (struct heci_client)); 388 res_msg.data = NULL; 389 if (priv_cb) { 390 kmem_free(priv_cb, sizeof (struct heci_cb_private)); 391 priv_cb = NULL; 392 } 393 return (rets); 394 } 395 396 /* 397 * heci_ioctl_wd - the wd IOCTL function 398 * 399 * @dev: Device object for our driver 400 * @if_num: minor number 401 * @k_msg: data in kernel on the stack 402 * @file_ext: private data of the file object 403 * 404 * @return 0 on success, <0 on failure. 405 */ 406 int 407 heci_ioctl_wd(struct iamt_heci_device *dev, int if_num, 408 struct heci_message_data k_msg, 409 struct heci_file_private *file_ext, int mode) 410 { 411 int rets = 0; 412 struct heci_message_data req_msg; /* in kernel on the stack */ 413 414 if (if_num < HECI_MINOR_NUMBER) 415 return (-ENODEV); 416 417 mutex_enter(&file_ext->file_lock); 418 if (k_msg.size != HECI_WATCHDOG_DATA_SIZE) { 419 DBG("user buffer has invalid size.\n"); 420 mutex_exit(&file_ext->file_lock); 421 return (-EMSGSIZE); 422 } 423 mutex_exit(&file_ext->file_lock); 424 425 req_msg.data = kmem_zalloc(HECI_WATCHDOG_DATA_SIZE, KM_SLEEP); 426 if (!req_msg.data) { 427 DBG("failed allocation request buffer size = %d.\n", 428 HECI_WATCHDOG_DATA_SIZE); 429 return (-ENOMEM); 430 } 431 req_msg.size = HECI_WATCHDOG_DATA_SIZE; 432 433 /* 434 * copy the message to kernel space - use a pointer already 435 * copied into kernel space 436 */ 437 if (ddi_copyin(k_msg.data, req_msg.data, k_msg.size, mode)) { 438 rets = -EFAULT; 439 goto end; 440 } 441 mutex_enter(&dev->device_lock); 442 if (dev->heci_state != HECI_ENABLED) { 443 rets = -ENODEV; 444 mutex_exit(&dev->device_lock); 445 goto end; 446 } 447 448 if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) { 449 rets = -ENODEV; 450 mutex_exit(&dev->device_lock); 451 goto end; 452 } 453 if (!dev->asf_mode) { 454 rets = -EIO; 455 mutex_exit(&dev->device_lock); 456 goto end; 457 } 458 459 (void) memcpy(&dev->wd_data[HECI_WD_PARAMS_SIZE], req_msg.data, 460 HECI_WATCHDOG_DATA_SIZE); 461 462 dev->wd_timeout = (req_msg.data[1] << 8) + req_msg.data[0]; 463 dev->wd_pending = 0; 464 dev->wd_due_counter = 1; /* next timer */ 465 if (dev->wd_timeout == 0) { 466 (void) memcpy(dev->wd_data, &stop_wd_params, 467 HECI_WD_PARAMS_SIZE); 468 } else { 469 (void) memcpy(dev->wd_data, &start_wd_params, 470 HECI_WD_PARAMS_SIZE); 471 dev->wd_timer = timeout(heci_wd_timer, dev, 1); 472 } 473 mutex_exit(&dev->device_lock); 474 end: 475 kmem_free(req_msg.data, HECI_WATCHDOG_DATA_SIZE); 476 return (rets); 477 } 478 479 480 /* 481 * heci_ioctl_bypass_wd - the bypass_wd IOCTL function 482 * 483 * @dev: Device object for our driver 484 * @if_num: minor number 485 * @k_msg: data in kernel on the stack 486 * @file_ext: private data of the file object 487 * 488 * @return 0 on success, <0 on failure. 489 */ 490 int 491 heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num, 492 struct heci_message_data k_msg, 493 struct heci_file_private *file_ext, int mode) 494 { 495 uint8_t flag = 0; 496 int rets = 0; 497 498 if (if_num < HECI_MINOR_NUMBER) 499 return (-ENODEV); 500 501 mutex_enter(&file_ext->file_lock); 502 if (k_msg.size < 1) { 503 DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE.\n"); 504 mutex_exit(&file_ext->file_lock); 505 return (-EMSGSIZE); 506 } 507 mutex_exit(&file_ext->file_lock); 508 if (ddi_copyin(k_msg.data, &flag, 1, mode)) { 509 rets = -EFAULT; 510 goto end; 511 } 512 513 mutex_enter(&dev->device_lock); 514 flag = flag ? (1) : (0); 515 dev->wd_bypass = flag; 516 mutex_exit(&dev->device_lock); 517 end: 518 return (rets); 519 } 520 521 /* 522 * find_pthi_read_list_entry - finds a PTHIlist entry for current file 523 * 524 * @dev: Device object for our driver 525 * @file: pointer to file object 526 * 527 * @return returned a list entry on success, NULL on failure. 528 */ 529 struct heci_cb_private * 530 find_pthi_read_list_entry( 531 struct iamt_heci_device *dev, 532 struct heci_file *file) 533 { 534 struct heci_file_private *file_ext_temp; 535 struct heci_cb_private *priv_cb_pos = NULL; 536 struct heci_cb_private *priv_cb_next = NULL; 537 538 if ((dev->pthi_read_complete_list.status == 0) && 539 !list_empty(&dev->pthi_read_complete_list.heci_cb.cb_list)) { 540 541 list_for_each_entry_safe(priv_cb_pos, priv_cb_next, 542 &dev->pthi_read_complete_list.heci_cb.cb_list, cb_list, 543 struct heci_cb_private) { 544 545 file_ext_temp = (struct heci_file_private *) 546 priv_cb_pos->file_private; 547 if ((file_ext_temp != NULL) && 548 (file_ext_temp == &dev->iamthif_file_ext) && 549 (priv_cb_pos->file_object == file)) 550 return (priv_cb_pos); 551 } 552 } 553 return (NULL); 554 } 555 556 /* 557 * pthi_read - read data from pthi client 558 * 559 * @dev: Device object for our driver 560 * @if_num: minor number 561 * @file: pointer to file object 562 * @*ubuf: pointer to user data in user space 563 * @length: data length to read 564 * @offset: data read offset 565 * 566 * @return 567 * returned data length on success, 568 * zero if no data to read, 569 * negative on failure. 570 */ 571 int 572 pthi_read(struct iamt_heci_device *dev, int if_num, struct heci_file *file, 573 struct uio *uio_p) 574 { 575 576 int rets = 0; 577 struct heci_cb_private *priv_cb = NULL; 578 struct heci_file_private *file_ext = file->private_data; 579 uint8_t i; 580 unsigned long currtime = ddi_get_time(); 581 582 if ((if_num < HECI_MINOR_NUMBER) || (!dev)) 583 return (-ENODEV); 584 585 if ((file_ext == NULL) || (file_ext != &dev->iamthif_file_ext)) 586 return (-ENODEV); 587 588 mutex_enter(&dev->device_lock); 589 for (i = 0; i < dev->num_heci_me_clients; i++) { 590 if (dev->me_clients[i].client_id == 591 dev->iamthif_file_ext.me_client_id) 592 break; 593 } 594 ASSERT(dev->me_clients[i].client_id == file_ext->me_client_id); 595 if ((i == dev->num_heci_me_clients) || 596 (dev->me_clients[i].client_id != 597 dev->iamthif_file_ext.me_client_id)) { 598 DBG("PTHI client not found.\n"); 599 mutex_exit(&dev->device_lock); 600 return (-ENODEV); 601 } 602 priv_cb = find_pthi_read_list_entry(dev, file); 603 if (!priv_cb) { 604 mutex_exit(&dev->device_lock); 605 return (0); /* No more data to read */ 606 } else { 607 if (priv_cb && 608 (currtime - priv_cb->read_time > IAMTHIF_READ_TIMER)) { 609 /* 15 sec for the message has expired */ 610 list_del(&priv_cb->cb_list); 611 mutex_exit(&dev->device_lock); 612 rets = -ETIMEDOUT; 613 goto free; 614 } 615 /* if the whole message will fit remove it from the list */ 616 if ((priv_cb->information >= UIO_OFFSET(uio_p)) && 617 (UIO_LENGTH(uio_p) >= 618 (priv_cb->information - UIO_OFFSET(uio_p)))) { 619 620 list_del(&priv_cb->cb_list); 621 622 } else if ((priv_cb->information > 0) && 623 (priv_cb->information <= UIO_OFFSET(uio_p))) { 624 625 /* end of the message has been reached */ 626 list_del(&priv_cb->cb_list); 627 rets = 0; 628 mutex_exit(&dev->device_lock); 629 goto free; 630 } 631 /* 632 * else means that not full buffer will be read and do not 633 * remove message from deletion list 634 */ 635 } 636 DBG("pthi priv_cb->response_buffer size - %d\n", 637 priv_cb->response_buffer.size); 638 DBG("pthi priv_cb->information - %lu\n", 639 priv_cb->information); 640 mutex_exit(&dev->device_lock); 641 642 rets = uiomove(priv_cb->response_buffer.data, 643 min(uio_p->uio_resid, priv_cb->information), 644 UIO_READ, uio_p); 645 free: 646 DBG("free pthi cb memory.\n"); 647 kmem_free(priv_cb->request_buffer.data, priv_cb->request_buffer.size); 648 kmem_free(priv_cb->response_buffer.data, priv_cb->response_buffer.size); 649 kmem_free(priv_cb, sizeof (struct heci_cb_private)); 650 return (rets); 651 } 652 653 /* 654 * heci_start_read - the start read client message function. 655 * 656 * @dev: Device object for our driver 657 * @if_num: minor number 658 * @file_ext: private data of the file object 659 * 660 * @return 0 on success, <0 on failure. 661 */ 662 int 663 heci_start_read(struct iamt_heci_device *dev, int if_num, 664 struct heci_file_private *file_ext) 665 { 666 int rets = 0; 667 uint8_t i; 668 struct heci_cb_private *priv_cb = NULL; 669 670 if ((if_num < HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) { 671 DBG("received wrong function input param.\n"); 672 return (-ENODEV); 673 } 674 if (file_ext->state != HECI_FILE_CONNECTED) 675 return (-ENODEV); 676 677 mutex_enter(&dev->device_lock); 678 if (dev->heci_state != HECI_ENABLED) { 679 mutex_exit(&dev->device_lock); 680 return (-ENODEV); 681 } 682 mutex_exit(&dev->device_lock); 683 DBG("check if read is pending.\n"); 684 if ((file_ext->read_pending) || (file_ext->read_cb != NULL)) { 685 DBG("read is pending.\n"); 686 return (-EBUSY); 687 } 688 priv_cb = kmem_zalloc(sizeof (struct heci_cb_private), KM_SLEEP); 689 if (!priv_cb) 690 return (-ENOMEM); 691 692 DBG("allocation call back success\n" 693 "host client = %d, ME client = %d\n", 694 file_ext->host_client_id, file_ext->me_client_id); 695 mutex_enter(&dev->device_lock); 696 for (i = 0; i < dev->num_heci_me_clients; i++) { 697 if (dev->me_clients[i].client_id == file_ext->me_client_id) 698 break; 699 700 } 701 702 ASSERT(dev->me_clients[i].client_id == file_ext->me_client_id); 703 if (i == dev->num_heci_me_clients) { 704 rets = -ENODEV; 705 goto unlock; 706 } 707 708 priv_cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; 709 mutex_exit(&dev->device_lock); 710 priv_cb->response_buffer.data = 711 kmem_zalloc(priv_cb->response_buffer.size, KM_SLEEP); 712 if (!priv_cb->response_buffer.data) { 713 rets = -ENOMEM; 714 goto fail; 715 } 716 DBG("allocation call back data success.\n"); 717 priv_cb->major_file_operations = HECI_READ; 718 /* make sure information is zero before we start */ 719 priv_cb->information = 0; 720 priv_cb->file_private = (void *)file_ext; 721 file_ext->read_cb = priv_cb; 722 mutex_enter(&dev->device_lock); 723 if (dev->host_buffer_is_empty) { 724 dev->host_buffer_is_empty = 0; 725 if (!heci_send_flow_control(dev, file_ext)) { 726 rets = -ENODEV; 727 goto unlock; 728 } else { 729 list_add_tail(&priv_cb->cb_list, 730 &dev->read_list.heci_cb.cb_list); 731 } 732 } else { 733 list_add_tail(&priv_cb->cb_list, 734 &dev->ctrl_wr_list.heci_cb.cb_list); 735 } 736 mutex_exit(&dev->device_lock); 737 return (rets); 738 unlock: 739 mutex_exit(&dev->device_lock); 740 fail: 741 heci_free_cb_private(priv_cb); 742 return (rets); 743 } 744 745 /* 746 * pthi_write: write iamthif data to pthi client 747 * 748 * @dev: Device object for our driver 749 * @priv_cb: heci call back struct 750 * 751 * @return 0 on success, <0 on failure. 752 */ 753 int 754 pthi_write(struct iamt_heci_device *dev, 755 struct heci_cb_private *priv_cb) 756 { 757 int rets = 0; 758 struct heci_msg_hdr heci_hdr; 759 760 if ((!dev) || (!priv_cb)) 761 return (-ENODEV); 762 763 DBG("write data to pthi client.\n"); 764 765 dev->iamthif_state = HECI_IAMTHIF_WRITING; 766 dev->iamthif_current_cb = priv_cb; 767 dev->iamthif_file_object = priv_cb->file_object; 768 dev->iamthif_canceled = 0; 769 dev->iamthif_ioctl = 1; 770 dev->iamthif_msg_buf_size = priv_cb->request_buffer.size; 771 (void) memcpy(dev->iamthif_msg_buf, priv_cb->request_buffer.data, 772 priv_cb->request_buffer.size); 773 774 if (flow_ctrl_creds(dev, &dev->iamthif_file_ext) && 775 dev->host_buffer_is_empty) { 776 dev->host_buffer_is_empty = 0; 777 if (priv_cb->request_buffer.size > 778 (((dev->host_hw_state & H_CBD) >> 24) * 779 sizeof (uint32_t)) - sizeof (struct heci_msg_hdr)) { 780 heci_hdr.length = 781 (((dev->host_hw_state & H_CBD) >> 24) * 782 sizeof (uint32_t)) - sizeof (struct heci_msg_hdr); 783 heci_hdr.msg_complete = 0; 784 } else { 785 heci_hdr.length = priv_cb->request_buffer.size; 786 heci_hdr.msg_complete = 1; 787 } 788 789 heci_hdr.host_addr = dev->iamthif_file_ext.host_client_id; 790 heci_hdr.me_addr = dev->iamthif_file_ext.me_client_id; 791 heci_hdr.reserved = 0; 792 dev->iamthif_msg_buf_index += heci_hdr.length; 793 if (!heci_write_message(dev, &heci_hdr, 794 (unsigned char *)(dev->iamthif_msg_buf), 795 heci_hdr.length)) 796 return (-ENODEV); 797 798 if (heci_hdr.msg_complete) { 799 flow_ctrl_reduce(dev, &dev->iamthif_file_ext); 800 dev->iamthif_flow_control_pending = 1; 801 dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL; 802 DBG("add pthi cb to write waiting list\n"); 803 dev->iamthif_current_cb = priv_cb; 804 dev->iamthif_file_object = priv_cb->file_object; 805 list_add_tail(&priv_cb->cb_list, 806 &dev->write_waiting_list.heci_cb.cb_list); 807 } else { 808 DBG("message does not complete, " 809 "so add pthi cb to write list.\n"); 810 list_add_tail(&priv_cb->cb_list, 811 &dev->write_list.heci_cb.cb_list); 812 } 813 } else { 814 if (!(dev->host_buffer_is_empty)) 815 DBG("host buffer is not empty"); 816 817 DBG("No flow control credentials, " 818 "so add iamthif cb to write list.\n"); 819 list_add_tail(&priv_cb->cb_list, 820 &dev->write_list.heci_cb.cb_list); 821 } 822 return (rets); 823 } 824 825 /* 826 * iamthif_ioctl_send_msg - send cmd data to pthi client 827 * 828 * @dev: Device object for our driver 829 * 830 * @return 0 on success, <0 on failure. 831 */ 832 void 833 run_next_iamthif_cmd(struct iamt_heci_device *dev) 834 { 835 struct heci_file_private *file_ext_tmp; 836 struct heci_cb_private *priv_cb_pos = NULL; 837 struct heci_cb_private *priv_cb_next = NULL; 838 int status = 0; 839 840 if (!dev) 841 return; 842 843 dev->iamthif_msg_buf_size = 0; 844 dev->iamthif_msg_buf_index = 0; 845 dev->iamthif_canceled = 0; 846 dev->iamthif_ioctl = 1; 847 dev->iamthif_state = HECI_IAMTHIF_IDLE; 848 dev->iamthif_timer = 0; 849 dev->iamthif_file_object = NULL; 850 851 if (dev->pthi_cmd_list.status == 0 && 852 !list_empty(&dev->pthi_cmd_list.heci_cb.cb_list)) { 853 DBG("complete pthi cmd_list cb.\n"); 854 855 list_for_each_entry_safe(priv_cb_pos, priv_cb_next, 856 &dev->pthi_cmd_list.heci_cb.cb_list, cb_list, 857 struct heci_cb_private) { 858 859 list_del(&priv_cb_pos->cb_list); 860 file_ext_tmp = (struct heci_file_private *) 861 priv_cb_pos->file_private; 862 863 if ((file_ext_tmp != NULL) && 864 (file_ext_tmp == &dev->iamthif_file_ext)) { 865 status = pthi_write(dev, priv_cb_pos); 866 if (status != 0) { 867 DBG("pthi write failed status = %d\n", 868 status); 869 return; 870 } 871 break; 872 } 873 } 874 } 875 } 876 877 /* 878 * heci_free_cb_private - free heci_cb_private related memory 879 * 880 * @priv_cb: heci callback struct 881 */ 882 void 883 heci_free_cb_private(struct heci_cb_private *priv_cb) 884 { 885 if (priv_cb == NULL) 886 return; 887 888 kmem_free(priv_cb->request_buffer.data, priv_cb->request_buffer.size); 889 kmem_free(priv_cb->response_buffer.data, priv_cb->response_buffer.size); 890 kmem_free(priv_cb, sizeof (struct heci_cb_private)); 891 } 892 893 /* 894 * heci_fe_same_id - tell if file private data have same id 895 * 896 * @fe1: private data of 1. file object 897 * @fe2: private data of 2. file object 898 * 899 * @return !=0 - if ids are the same, 0 - if differ. 900 */ 901 static inline int heci_fe_same_id(struct heci_file_private *fe1, 902 struct heci_file_private *fe2) 903 { 904 return ((fe1->host_client_id == fe2->host_client_id) && 905 (fe1->me_client_id == fe2->me_client_id)); 906 } 907