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