Merge commit 'v2.6.31-rc8' into core/locking
[linux-block.git] / drivers / staging / heci / io_heci.c
CommitLineData
d52b3d9c
MO
1/*
2 * Part of Intel(R) Manageability Engine Interface Linux driver
3 *
4 * Copyright (c) 2003 - 2008 Intel Corp.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer,
12 * without modification.
13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
14 * substantially similar to the "NO WARRANTY" disclaimer below
15 * ("Disclaimer") and any redistribution must be conditioned upon
16 * including a substantially similar Disclaimer requirement for further
17 * binary redistribution.
18 * 3. Neither the names of the above-listed copyright holders nor the names
19 * of any contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * Alternatively, this software may be distributed under the terms of the
23 * GNU General Public License ("GPL") version 2 as published by the Free
24 * Software Foundation.
25 *
26 * NO WARRANTY
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
36 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGES.
38 *
39 */
40
41#include <linux/module.h>
42#include <linux/moduleparam.h>
43#include <linux/kernel.h>
44#include <linux/slab.h>
45#include <linux/fs.h>
46#include <linux/errno.h>
47#include <linux/types.h>
48#include <linux/fcntl.h>
49#include <linux/aio.h>
50#include <linux/pci.h>
51#include <linux/reboot.h>
52#include <linux/poll.h>
53#include <linux/init.h>
54#include <linux/kdev_t.h>
55#include <linux/ioctl.h>
56#include <linux/cdev.h>
57#include <linux/list.h>
58#include <linux/unistd.h>
59#include <linux/delay.h>
d52b3d9c
MO
60
61#include "heci_data_structures.h"
62#include "heci.h"
63#include "heci_interface.h"
64#include "heci_version.h"
65
66
67/**
68 * heci_ioctl_get_version - the get driver version IOCTL function
69 *
70 * @dev: Device object for our driver
71 * @if_num: minor number
72 * @*u_msg: pointer to user data struct in user space
73 * @k_msg: data in kernel on the stack
74 * @file_ext: private data of the file object
75 *
76 * returns 0 on success, <0 on failure.
77 */
78int heci_ioctl_get_version(struct iamt_heci_device *dev, int if_num,
c4739ea6 79 struct heci_message_data __user *u_msg,
d52b3d9c
MO
80 struct heci_message_data k_msg,
81 struct heci_file_private *file_ext)
82{
83 int rets = 0;
84 struct heci_driver_version *version;
85 struct heci_message_data res_msg;
86
87 if ((if_num != HECI_MINOR_NUMBER) || (!dev)
88 || (!file_ext))
89 return -ENODEV;
90
91 if (k_msg.size < (sizeof(struct heci_driver_version) - 2)) {
92 DBG("user buffer less than heci_driver_version.\n");
93 return -EMSGSIZE;
94 }
95
96 res_msg.data = kmalloc(sizeof(struct heci_driver_version), GFP_KERNEL);
97 if (!res_msg.data) {
98 DBG("failed allocation response buffer size = %d.\n",
99 (int) sizeof(struct heci_driver_version));
100 return -ENOMEM;
101 }
102
103 version = (struct heci_driver_version *) res_msg.data;
104 version->major = MAJOR_VERSION;
105 version->minor = MINOR_VERSION;
106 version->hotfix = QUICK_FIX_NUMBER;
107 version->build = VER_BUILD;
108 res_msg.size = sizeof(struct heci_driver_version);
109 if (k_msg.size < sizeof(struct heci_driver_version))
110 res_msg.size -= 2;
111
112 rets = file_ext->status;
113 /* now copy the data to user space */
36e84467 114 if (copy_to_user((void __user *)k_msg.data, res_msg.data, res_msg.size)) {
d52b3d9c
MO
115 rets = -EFAULT;
116 goto end;
117 }
118 if (put_user(res_msg.size, &u_msg->size)) {
119 rets = -EFAULT;
120 goto end;
121 }
122end:
123 kfree(res_msg.data);
124 return rets;
125}
126
127/**
128 * heci_ioctl_connect_client - the connect to fw client IOCTL function
129 *
130 * @dev: Device object for our driver
131 * @if_num: minor number
132 * @*u_msg: pointer to user data struct in user space
133 * @k_msg: data in kernel on the stack
134 * @file_ext: private data of the file object
135 *
136 * returns 0 on success, <0 on failure.
137 */
138int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num,
c4739ea6 139 struct heci_message_data __user *u_msg,
d52b3d9c
MO
140 struct heci_message_data k_msg,
141 struct file *file)
142{
143 int rets = 0;
144 struct heci_message_data req_msg, res_msg;
145 struct heci_cb_private *priv_cb = NULL;
146 struct heci_client *client;
147 struct heci_file_private *file_ext;
148 struct heci_file_private *file_pos = NULL;
149 struct heci_file_private *file_next = NULL;
150 long timeout = 15; /*15 second */
151 __u8 i;
152 int err = 0;
153
154 if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file))
155 return -ENODEV;
156
157 file_ext = file->private_data;
158 if (!file_ext)
159 return -ENODEV;
160
161 if (k_msg.size != sizeof(struct guid)) {
162 DBG("user buffer size is not equal to size of struct "
163 "guid(16).\n");
164 return -EMSGSIZE;
165 }
166
167 if (!k_msg.data)
168 return -EIO;
169
170 req_msg.data = kmalloc(sizeof(struct guid), GFP_KERNEL);
171 res_msg.data = kmalloc(sizeof(struct heci_client), GFP_KERNEL);
172
173 if (!res_msg.data) {
174 DBG("failed allocation response buffer size = %d.\n",
175 (int) sizeof(struct heci_client));
176 kfree(req_msg.data);
177 return -ENOMEM;
178 }
179 if (!req_msg.data) {
180 DBG("failed allocation request buffer size = %d.\n",
181 (int) sizeof(struct guid));
182 kfree(res_msg.data);
183 return -ENOMEM;
184 }
185 req_msg.size = sizeof(struct guid);
186 res_msg.size = sizeof(struct heci_client);
187
188 /* copy the message to kernel space -
189 * use a pointer already copied into kernel space
190 */
36e84467 191 if (copy_from_user(req_msg.data, (void __user *)k_msg.data, k_msg.size)) {
d52b3d9c
MO
192 rets = -EFAULT;
193 goto end;
194 }
195 /* buffered ioctl cb */
196 priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
197 if (!priv_cb) {
198 rets = -ENOMEM;
199 goto end;
200 }
201 INIT_LIST_HEAD(&priv_cb->cb_list);
202 priv_cb->response_buffer.data = res_msg.data;
203 priv_cb->response_buffer.size = res_msg.size;
204 priv_cb->request_buffer.data = req_msg.data;
205 priv_cb->request_buffer.size = req_msg.size;
206 priv_cb->major_file_operations = HECI_IOCTL;
207 spin_lock_bh(&dev->device_lock);
208 if (dev->heci_state != HECI_ENABLED) {
209 rets = -ENODEV;
210 spin_unlock_bh(&dev->device_lock);
211 goto end;
212 }
213 if ((file_ext->state != HECI_FILE_INITIALIZING) &&
214 (file_ext->state != HECI_FILE_DISCONNECTED)) {
215 rets = -EBUSY;
216 spin_unlock_bh(&dev->device_lock);
217 goto end;
218 }
219
220 /* find ME client we're trying to connect to */
221 for (i = 0; i < dev->num_heci_me_clients; i++) {
222 if (memcmp((struct guid *)req_msg.data,
223 &dev->me_clients[i].props.protocol_name,
224 sizeof(struct guid)) == 0) {
225 if (dev->me_clients[i].props.fixed_address == 0) {
226 file_ext->me_client_id =
227 dev->me_clients[i].client_id;
228 file_ext->state = HECI_FILE_CONNECTING;
229 }
230 break;
231 }
232 }
233 /* if we're connecting to PTHI client so we will use the exist
234 * connection
235 */
236 if (memcmp((struct guid *)req_msg.data, &heci_pthi_guid,
237 sizeof(struct guid)) == 0) {
238 if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) {
239 rets = -ENODEV;
240 spin_unlock_bh(&dev->device_lock);
241 goto end;
242 }
243 dev->heci_host_clients[file_ext->host_client_id / 8] &=
244 ~(1 << (file_ext->host_client_id % 8));
245 list_for_each_entry_safe(file_pos,
246 file_next, &dev->file_list, link) {
247 if (heci_fe_same_id(file_ext, file_pos)) {
248 DBG("remove file private data node host"
249 " client = %d, ME client = %d.\n",
250 file_pos->host_client_id,
251 file_pos->me_client_id);
252 list_del(&file_pos->link);
253 }
254
255 }
256 DBG("free file private data memory.\n");
257 kfree(file_ext);
258 file_ext = NULL;
259 file->private_data = &dev->iamthif_file_ext;
260 client = (struct heci_client *) res_msg.data;
261 client->max_msg_length =
262 dev->me_clients[i].props.max_msg_length;
263 client->protocol_version =
264 dev->me_clients[i].props.protocol_version;
265 rets = dev->iamthif_file_ext.status;
266 spin_unlock_bh(&dev->device_lock);
267
268 /* now copy the data to user space */
36e84467
DX
269 if (copy_to_user((void __user *)k_msg.data,
270 res_msg.data, res_msg.size)) {
d52b3d9c
MO
271 rets = -EFAULT;
272 goto end;
273 }
274 if (put_user(res_msg.size, &u_msg->size)) {
275 rets = -EFAULT;
276 goto end;
277 }
278 goto end;
279 }
171df638
DX
280 spin_unlock_bh(&dev->device_lock);
281
d52b3d9c 282 spin_lock(&file_ext->file_lock);
171df638 283 spin_lock_bh(&dev->device_lock);
d52b3d9c
MO
284 if (file_ext->state != HECI_FILE_CONNECTING) {
285 rets = -ENODEV;
d52b3d9c 286 spin_unlock_bh(&dev->device_lock);
171df638 287 spin_unlock(&file_ext->file_lock);
d52b3d9c
MO
288 goto end;
289 }
d52b3d9c
MO
290 /* prepare the output buffer */
291 client = (struct heci_client *) res_msg.data;
292 client->max_msg_length = dev->me_clients[i].props.max_msg_length;
293 client->protocol_version = dev->me_clients[i].props.protocol_version;
294 if (dev->host_buffer_is_empty
295 && !other_client_is_connecting(dev, file_ext)) {
296 dev->host_buffer_is_empty = 0;
297 if (!heci_connect(dev, file_ext)) {
298 rets = -ENODEV;
299 spin_unlock_bh(&dev->device_lock);
afcf462a 300 spin_unlock(&file_ext->file_lock);
d52b3d9c
MO
301 goto end;
302 } else {
303 file_ext->timer_count = HECI_CONNECT_TIMEOUT;
304 priv_cb->file_private = file_ext;
305 list_add_tail(&priv_cb->cb_list,
306 &dev->ctrl_rd_list.heci_cb.
307 cb_list);
308 }
309
310
311 } else {
312 priv_cb->file_private = file_ext;
313 DBG("add connect cb to control write list.\n");
314 list_add_tail(&priv_cb->cb_list,
315 &dev->ctrl_wr_list.heci_cb.cb_list);
316 }
317 spin_unlock_bh(&dev->device_lock);
171df638 318 spin_unlock(&file_ext->file_lock);
d52b3d9c
MO
319 err = wait_event_timeout(dev->wait_recvd_msg,
320 (HECI_FILE_CONNECTED == file_ext->state
321 || HECI_FILE_DISCONNECTED == file_ext->state),
322 timeout * HZ);
323
afcf462a 324 spin_lock_bh(&dev->device_lock);
d52b3d9c 325 if (HECI_FILE_CONNECTED == file_ext->state) {
afcf462a 326 spin_unlock_bh(&dev->device_lock);
d52b3d9c
MO
327 DBG("successfully connected to FW client.\n");
328 rets = file_ext->status;
329 /* now copy the data to user space */
36e84467
DX
330 if (copy_to_user((void __user *)k_msg.data,
331 res_msg.data, res_msg.size)) {
d52b3d9c
MO
332 rets = -EFAULT;
333 goto end;
334 }
335 if (put_user(res_msg.size, &u_msg->size)) {
336 rets = -EFAULT;
337 goto end;
338 }
339 goto end;
340 } else {
341 DBG("failed to connect to FW client.file_ext->state = %d.\n",
342 file_ext->state);
afcf462a 343 spin_unlock_bh(&dev->device_lock);
d52b3d9c
MO
344 if (!err) {
345 DBG("wait_event_interruptible_timeout failed on client"
346 " connect message fw response message.\n");
347 }
348 rets = -EFAULT;
349 goto remove_list;
350 }
351
352remove_list:
353 if (priv_cb) {
354 spin_lock_bh(&dev->device_lock);
355 heci_flush_list(&dev->ctrl_rd_list, file_ext);
356 heci_flush_list(&dev->ctrl_wr_list, file_ext);
357 spin_unlock_bh(&dev->device_lock);
358 }
359end:
360 DBG("free connect cb memory.");
361 kfree(req_msg.data);
362 kfree(res_msg.data);
363 kfree(priv_cb);
364 return rets;
365}
366
367/**
368 * heci_ioctl_wd - the wd IOCTL function
369 *
370 * @dev: Device object for our driver
371 * @if_num: minor number
372 * @k_msg: data in kernel on the stack
373 * @file_ext: private data of the file object
374 *
375 * returns 0 on success, <0 on failure.
376 */
377int heci_ioctl_wd(struct iamt_heci_device *dev, int if_num,
378 struct heci_message_data k_msg,
379 struct heci_file_private *file_ext)
380{
381 int rets = 0;
382 struct heci_message_data req_msg; /*in kernel on the stack */
383
384 if (if_num != HECI_MINOR_NUMBER)
385 return -ENODEV;
386
387 spin_lock(&file_ext->file_lock);
388 if (k_msg.size != HECI_WATCHDOG_DATA_SIZE) {
389 DBG("user buffer has invalid size.\n");
390 spin_unlock(&file_ext->file_lock);
391 return -EMSGSIZE;
392 }
393 spin_unlock(&file_ext->file_lock);
394
395 req_msg.data = kmalloc(HECI_WATCHDOG_DATA_SIZE, GFP_KERNEL);
396 if (!req_msg.data) {
397 DBG("failed allocation request buffer size = %d.\n",
398 HECI_WATCHDOG_DATA_SIZE);
399 return -ENOMEM;
400 }
401 req_msg.size = HECI_WATCHDOG_DATA_SIZE;
402
403 /* copy the message to kernel space - use a pointer already
404 * copied into kernel space
405 */
36e84467
DX
406 if (copy_from_user(req_msg.data,
407 (void __user *)k_msg.data, req_msg.size)) {
d52b3d9c
MO
408 rets = -EFAULT;
409 goto end;
410 }
411 spin_lock_bh(&dev->device_lock);
412 if (dev->heci_state != HECI_ENABLED) {
413 rets = -ENODEV;
414 spin_unlock_bh(&dev->device_lock);
415 goto end;
416 }
417
418 if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) {
419 rets = -ENODEV;
420 spin_unlock_bh(&dev->device_lock);
421 goto end;
422 }
423 if (!dev->asf_mode) {
424 rets = -EIO;
425 spin_unlock_bh(&dev->device_lock);
426 goto end;
427 }
428
429 memcpy(&dev->wd_data[HECI_WD_PARAMS_SIZE], req_msg.data,
430 HECI_WATCHDOG_DATA_SIZE);
431
432 dev->wd_timeout = (req_msg.data[1] << 8) + req_msg.data[0];
433 dev->wd_pending = 0;
434 dev->wd_due_counter = 1; /* next timer */
435 if (dev->wd_timeout == 0) {
436 memcpy(dev->wd_data, heci_stop_wd_params,
437 HECI_WD_PARAMS_SIZE);
438 } else {
439 memcpy(dev->wd_data, heci_start_wd_params,
440 HECI_WD_PARAMS_SIZE);
441 mod_timer(&dev->wd_timer, jiffies);
442 }
443 spin_unlock_bh(&dev->device_lock);
444end:
445 kfree(req_msg.data);
446 return rets;
447}
448
449
450/**
451 * heci_ioctl_bypass_wd - the bypass_wd IOCTL function
452 *
453 * @dev: Device object for our driver
454 * @if_num: minor number
455 * @k_msg: data in kernel on the stack
456 * @file_ext: private data of the file object
457 *
458 * returns 0 on success, <0 on failure.
459 */
460int heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num,
461 struct heci_message_data k_msg,
462 struct heci_file_private *file_ext)
463{
464 __u8 flag = 0;
465 int rets = 0;
466
467 if (if_num != HECI_MINOR_NUMBER)
468 return -ENODEV;
469
470 spin_lock(&file_ext->file_lock);
471 if (k_msg.size < 1) {
472 DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE.\n");
473 spin_unlock(&file_ext->file_lock);
474 return -EMSGSIZE;
475 }
476 spin_unlock(&file_ext->file_lock);
36e84467 477 if (copy_from_user(&flag, (void __user *)k_msg.data, 1)) {
d52b3d9c
MO
478 rets = -EFAULT;
479 goto end;
480 }
481
482 spin_lock_bh(&dev->device_lock);
483 flag = flag ? (1) : (0);
484 dev->wd_bypass = flag;
485 spin_unlock_bh(&dev->device_lock);
486end:
487 return rets;
488}
489
490/**
491 * find_pthi_read_list_entry - finds a PTHIlist entry for current file
492 *
493 * @dev: Device object for our driver
494 * @file: pointer to file object
495 *
496 * returns returned a list entry on success, NULL on failure.
497 */
498struct heci_cb_private *find_pthi_read_list_entry(
499 struct iamt_heci_device *dev,
500 struct file *file)
501{
502 struct heci_file_private *file_ext_temp;
503 struct heci_cb_private *priv_cb_pos = NULL;
504 struct heci_cb_private *priv_cb_next = NULL;
505
506 if ((dev->pthi_read_complete_list.status == 0) &&
507 !list_empty(&dev->pthi_read_complete_list.heci_cb.cb_list)) {
508 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
509 &dev->pthi_read_complete_list.heci_cb.cb_list, cb_list) {
510 file_ext_temp = (struct heci_file_private *)
511 priv_cb_pos->file_private;
512 if ((file_ext_temp != NULL) &&
513 (file_ext_temp == &dev->iamthif_file_ext) &&
514 (priv_cb_pos->file_object == file))
515 return priv_cb_pos;
516 }
517 }
518 return NULL;
519}
520
521/**
522 * pthi_read - read data from pthi client
523 *
524 * @dev: Device object for our driver
525 * @if_num: minor number
526 * @file: pointer to file object
527 * @*ubuf: pointer to user data in user space
528 * @length: data length to read
529 * @offset: data read offset
530 *
531 * returns
532 * returned data length on success,
533 * zero if no data to read,
534 * negative on failure.
535 */
536int pthi_read(struct iamt_heci_device *dev, int if_num, struct file *file,
c4739ea6 537 char __user *ubuf, size_t length, loff_t *offset)
d52b3d9c
MO
538{
539 int rets = 0;
540 struct heci_cb_private *priv_cb = NULL;
541 struct heci_file_private *file_ext = file->private_data;
542 __u8 i;
543 unsigned long currtime = get_seconds();
544
545 if ((if_num != HECI_MINOR_NUMBER) || (!dev))
546 return -ENODEV;
547
548 if ((file_ext == NULL) || (file_ext != &dev->iamthif_file_ext))
549 return -ENODEV;
550
551 spin_lock_bh(&dev->device_lock);
552 for (i = 0; i < dev->num_heci_me_clients; i++) {
553 if (dev->me_clients[i].client_id ==
554 dev->iamthif_file_ext.me_client_id)
555 break;
556 }
557 BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id);
558 if ((i == dev->num_heci_me_clients)
559 || (dev->me_clients[i].client_id !=
560 dev->iamthif_file_ext.me_client_id)) {
561 DBG("PTHI client not found.\n");
562 spin_unlock_bh(&dev->device_lock);
563 return -ENODEV;
564 }
565 priv_cb = find_pthi_read_list_entry(dev, file);
566 if (!priv_cb) {
567 spin_unlock_bh(&dev->device_lock);
568 return 0; /* No more data to read */
569 } else {
570 if (priv_cb &&
571 (currtime - priv_cb->read_time > IAMTHIF_READ_TIMER)) {
572 /* 15 sec for the message has expired */
573 list_del(&priv_cb->cb_list);
574 spin_unlock_bh(&dev->device_lock);
575 rets = -ETIMEDOUT;
576 goto free;
577 }
578 /* if the whole message will fit remove it from the list */
579 if ((priv_cb->information >= *offset) &&
580 (length >= (priv_cb->information - *offset)))
581 list_del(&priv_cb->cb_list);
582 else if ((priv_cb->information > 0) &&
583 (priv_cb->information <= *offset)) {
584 /* end of the message has been reached */
585 list_del(&priv_cb->cb_list);
586 rets = 0;
587 spin_unlock_bh(&dev->device_lock);
588 goto free;
589 }
590 /* else means that not full buffer will be read and do not
591 * remove message from deletion list
592 */
593 }
594 DBG("pthi priv_cb->response_buffer size - %d\n",
595 priv_cb->response_buffer.size);
596 DBG("pthi priv_cb->information - %lu\n",
597 priv_cb->information);
598 spin_unlock_bh(&dev->device_lock);
599
600 /* length is being turncated to PAGE_SIZE, however,
601 * the information may be longer */
602 length = length < (priv_cb->information - *offset) ?
603 length : (priv_cb->information - *offset);
604
605 if (copy_to_user(ubuf,
606 priv_cb->response_buffer.data + *offset,
607 length))
608 rets = -EFAULT;
609 else {
610 rets = length;
611 if ((*offset + length) < priv_cb->information) {
612 *offset += length;
613 goto out;
614 }
615 }
616free:
617 DBG("free pthi cb memory.\n");
618 *offset = 0;
619 heci_free_cb_private(priv_cb);
620out:
621 return rets;
622}
623
624/**
625 * heci_start_read - the start read client message function.
626 *
627 * @dev: Device object for our driver
628 * @if_num: minor number
629 * @file_ext: private data of the file object
630 *
631 * returns 0 on success, <0 on failure.
632 */
633int heci_start_read(struct iamt_heci_device *dev, int if_num,
634 struct heci_file_private *file_ext)
635{
636 int rets = 0;
637 __u8 i;
638 struct heci_cb_private *priv_cb = NULL;
639
640 if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) {
641 DBG("received wrong function input param.\n");
642 return -ENODEV;
643 }
afcf462a
DX
644
645 spin_lock_bh(&dev->device_lock);
72abd228 646 if (file_ext->state != HECI_FILE_CONNECTED) {
afcf462a 647 spin_unlock_bh(&dev->device_lock);
d52b3d9c 648 return -ENODEV;
72abd228 649 }
d52b3d9c 650
d52b3d9c
MO
651 if (dev->heci_state != HECI_ENABLED) {
652 spin_unlock_bh(&dev->device_lock);
653 return -ENODEV;
654 }
655 spin_unlock_bh(&dev->device_lock);
656 DBG("check if read is pending.\n");
58b25a63 657 spin_lock_bh(&file_ext->read_io_lock);
d52b3d9c
MO
658 if ((file_ext->read_pending) || (file_ext->read_cb != NULL)) {
659 DBG("read is pending.\n");
58b25a63 660 spin_unlock_bh(&file_ext->read_io_lock);
d52b3d9c
MO
661 return -EBUSY;
662 }
58b25a63 663 spin_unlock_bh(&file_ext->read_io_lock);
72abd228 664
d52b3d9c
MO
665 priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL);
666 if (!priv_cb)
667 return -ENOMEM;
668
58b25a63 669 spin_lock_bh(&file_ext->read_io_lock);
d52b3d9c
MO
670 DBG("allocation call back success\n"
671 "host client = %d, ME client = %d\n",
672 file_ext->host_client_id, file_ext->me_client_id);
58b25a63 673 spin_unlock_bh(&file_ext->read_io_lock);
72abd228 674
d52b3d9c 675 spin_lock_bh(&dev->device_lock);
58b25a63 676 spin_lock_bh(&file_ext->read_io_lock);
d52b3d9c
MO
677 for (i = 0; i < dev->num_heci_me_clients; i++) {
678 if (dev->me_clients[i].client_id == file_ext->me_client_id)
679 break;
680
681 }
682
683 BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id);
58b25a63 684 spin_unlock_bh(&file_ext->read_io_lock);
d52b3d9c
MO
685 if (i == dev->num_heci_me_clients) {
686 rets = -ENODEV;
687 goto unlock;
688 }
689
690 priv_cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
691 spin_unlock_bh(&dev->device_lock);
692 priv_cb->response_buffer.data =
693 kmalloc(priv_cb->response_buffer.size, GFP_KERNEL);
694 if (!priv_cb->response_buffer.data) {
695 rets = -ENOMEM;
696 goto fail;
697 }
698 DBG("allocation call back data success.\n");
699 priv_cb->major_file_operations = HECI_READ;
700 /* make sure information is zero before we start */
701 priv_cb->information = 0;
702 priv_cb->file_private = (void *) file_ext;
d52b3d9c 703 spin_lock_bh(&dev->device_lock);
58b25a63 704 spin_lock_bh(&file_ext->read_io_lock);
72abd228 705 file_ext->read_cb = priv_cb;
d52b3d9c
MO
706 if (dev->host_buffer_is_empty) {
707 dev->host_buffer_is_empty = 0;
708 if (!heci_send_flow_control(dev, file_ext)) {
709 rets = -ENODEV;
58b25a63 710 spin_unlock_bh(&file_ext->read_io_lock);
d52b3d9c
MO
711 goto unlock;
712 } else {
713 list_add_tail(&priv_cb->cb_list,
714 &dev->read_list.heci_cb.cb_list);
715 }
716 } else {
717 list_add_tail(&priv_cb->cb_list,
718 &dev->ctrl_wr_list.heci_cb.cb_list);
719 }
58b25a63 720 spin_unlock_bh(&file_ext->read_io_lock);
d52b3d9c
MO
721 spin_unlock_bh(&dev->device_lock);
722 return rets;
723unlock:
724 spin_unlock_bh(&dev->device_lock);
725fail:
726 heci_free_cb_private(priv_cb);
727 return rets;
728}
729
730/**
731 * pthi_write - write iamthif data to pthi client
732 *
733 * @dev: Device object for our driver
734 * @priv_cb: heci call back struct
735 *
736 * returns 0 on success, <0 on failure.
737 */
738int pthi_write(struct iamt_heci_device *dev,
739 struct heci_cb_private *priv_cb)
740{
741 int rets = 0;
742 struct heci_msg_hdr heci_hdr;
743
744 if ((!dev) || (!priv_cb))
745 return -ENODEV;
746
747 DBG("write data to pthi client.\n");
748
749 dev->iamthif_state = HECI_IAMTHIF_WRITING;
750 dev->iamthif_current_cb = priv_cb;
751 dev->iamthif_file_object = priv_cb->file_object;
752 dev->iamthif_canceled = 0;
753 dev->iamthif_ioctl = 1;
754 dev->iamthif_msg_buf_size = priv_cb->request_buffer.size;
755 memcpy(dev->iamthif_msg_buf, priv_cb->request_buffer.data,
756 priv_cb->request_buffer.size);
757
758 if (flow_ctrl_creds(dev, &dev->iamthif_file_ext) &&
759 dev->host_buffer_is_empty) {
760 dev->host_buffer_is_empty = 0;
761 if (priv_cb->request_buffer.size >
762 (((dev->host_hw_state & H_CBD) >> 24) *
763 sizeof(__u32)) - sizeof(struct heci_msg_hdr)) {
764 heci_hdr.length =
765 (((dev->host_hw_state & H_CBD) >> 24) *
766 sizeof(__u32)) - sizeof(struct heci_msg_hdr);
767 heci_hdr.msg_complete = 0;
768 } else {
769 heci_hdr.length = priv_cb->request_buffer.size;
770 heci_hdr.msg_complete = 1;
771 }
772
773 heci_hdr.host_addr = dev->iamthif_file_ext.host_client_id;
774 heci_hdr.me_addr = dev->iamthif_file_ext.me_client_id;
775 heci_hdr.reserved = 0;
776 dev->iamthif_msg_buf_index += heci_hdr.length;
777 if (!heci_write_message(dev, &heci_hdr,
778 (unsigned char *)(dev->iamthif_msg_buf),
779 heci_hdr.length))
780 return -ENODEV;
781
782 if (heci_hdr.msg_complete) {
783 flow_ctrl_reduce(dev, &dev->iamthif_file_ext);
784 dev->iamthif_flow_control_pending = 1;
785 dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL;
786 DBG("add pthi cb to write waiting list\n");
787 dev->iamthif_current_cb = priv_cb;
788 dev->iamthif_file_object = priv_cb->file_object;
789 list_add_tail(&priv_cb->cb_list,
790 &dev->write_waiting_list.heci_cb.cb_list);
791 } else {
792 DBG("message does not complete, "
793 "so add pthi cb to write list.\n");
794 list_add_tail(&priv_cb->cb_list,
795 &dev->write_list.heci_cb.cb_list);
796 }
797 } else {
798 if (!(dev->host_buffer_is_empty))
799 DBG("host buffer is not empty");
800
801 DBG("No flow control credentials, "
802 "so add iamthif cb to write list.\n");
803 list_add_tail(&priv_cb->cb_list,
804 &dev->write_list.heci_cb.cb_list);
805 }
806 return rets;
807}
808
809/**
810 * iamthif_ioctl_send_msg - send cmd data to pthi client
811 *
812 * @dev: Device object for our driver
813 *
814 * returns 0 on success, <0 on failure.
815 */
816void run_next_iamthif_cmd(struct iamt_heci_device *dev)
817{
818 struct heci_file_private *file_ext_tmp;
819 struct heci_cb_private *priv_cb_pos = NULL;
820 struct heci_cb_private *priv_cb_next = NULL;
821 int status = 0;
822
823 if (!dev)
824 return;
825
826 dev->iamthif_msg_buf_size = 0;
827 dev->iamthif_msg_buf_index = 0;
828 dev->iamthif_canceled = 0;
829 dev->iamthif_ioctl = 1;
830 dev->iamthif_state = HECI_IAMTHIF_IDLE;
831 dev->iamthif_timer = 0;
832 dev->iamthif_file_object = NULL;
833
834 if (dev->pthi_cmd_list.status == 0 &&
835 !list_empty(&dev->pthi_cmd_list.heci_cb.cb_list)) {
836 DBG("complete pthi cmd_list cb.\n");
837
838 list_for_each_entry_safe(priv_cb_pos, priv_cb_next,
839 &dev->pthi_cmd_list.heci_cb.cb_list, cb_list) {
840 list_del(&priv_cb_pos->cb_list);
841 file_ext_tmp = (struct heci_file_private *)
842 priv_cb_pos->file_private;
843
844 if ((file_ext_tmp != NULL) &&
845 (file_ext_tmp == &dev->iamthif_file_ext)) {
846 status = pthi_write(dev, priv_cb_pos);
847 if (status != 0) {
848 DBG("pthi write failed status = %d\n",
849 status);
850 return;
851 }
852 break;
853 }
854 }
855 }
856}
857
858/**
859 * heci_free_cb_private - free heci_cb_private related memory
860 *
861 * @priv_cb: heci callback struct
862 */
863void heci_free_cb_private(struct heci_cb_private *priv_cb)
864{
865 if (priv_cb == NULL)
866 return;
867
868 kfree(priv_cb->request_buffer.data);
869 kfree(priv_cb->response_buffer.data);
870 kfree(priv_cb);
871}
872