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