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