Initial import from FreeBSD RELENG_4:
[games.git] / sys / dev / atm / hfa / fore_command.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/dev/hfa/fore_command.c,v 1.6 1999/08/28 00:41:49 peter Exp $
27  *
28  */
29
30 /*
31  * FORE Systems 200-Series Adapter Support
32  * ---------------------------------------
33  *
34  * Command queue management
35  *
36  */
37
38 #include <dev/hfa/fore_include.h>
39
40 #ifndef lint
41 __RCSID("@(#) $FreeBSD: src/sys/dev/hfa/fore_command.c,v 1.6 1999/08/28 00:41:49 peter Exp $");
42 #endif
43
44 /*
45  * Local variables
46  */
47 static struct t_atm_cause       fore_cause = {
48         T_ATM_ITU_CODING,
49         T_ATM_LOC_USER,
50         T_ATM_CAUSE_TEMPORARY_FAILURE,
51         {0, 0, 0, 0}
52 };
53
54
55 /*
56  * Allocate Command Queue Data Structures
57  *
58  * Arguments:
59  *      fup             pointer to device unit structure
60  *
61  * Returns:
62  *      0               allocations successful
63  *      else            allocation failed
64  */
65 int
66 fore_cmd_allocate(fup)
67         Fore_unit       *fup;
68 {
69         caddr_t         memp;
70
71         /*
72          * Allocate non-cacheable memory for command status words
73          */
74         memp = atm_dev_alloc(sizeof(Q_status) * CMD_QUELEN,
75                         QSTAT_ALIGN, ATM_DEV_NONCACHE);
76         if (memp == NULL) {
77                 return (1);
78         }
79         fup->fu_cmd_stat = (Q_status *) memp;
80
81         memp = DMA_GET_ADDR(fup->fu_cmd_stat, sizeof(Q_status) * CMD_QUELEN,
82                         QSTAT_ALIGN, ATM_DEV_NONCACHE);
83         if (memp == NULL) {
84                 return (1);
85         }
86         fup->fu_cmd_statd = (Q_status *) memp;
87
88         /*
89          * Allocate memory for statistics buffer
90          */
91         memp = atm_dev_alloc(sizeof(Fore_stats), FORE_STATS_ALIGN, 0);
92         if (memp == NULL) {
93                 return (1);
94         }
95         fup->fu_stats = (Fore_stats *) memp;
96
97 #ifdef FORE_PCI
98         /*
99          * Allocate memory for PROM buffer
100          */
101         memp = atm_dev_alloc(sizeof(Fore_prom), FORE_PROM_ALIGN, 0);
102         if (memp == NULL) {
103                 return (1);
104         }
105         fup->fu_prom = (Fore_prom *) memp;
106 #endif
107
108         return (0);
109 }
110
111
112 /*
113  * Command Queue Initialization
114  *
115  * Allocate and initialize the host-resident command queue structures
116  * and then initialize the CP-resident queue structures.
117  * 
118  * Called at interrupt level.
119  *
120  * Arguments:
121  *      fup             pointer to device unit structure
122  *
123  * Returns:
124  *      none
125  */
126 void
127 fore_cmd_initialize(fup)
128         Fore_unit       *fup;
129 {
130         Aali            *aap = fup->fu_aali;
131         Cmd_queue       *cqp;
132         H_cmd_queue     *hcp;
133         Q_status        *qsp;
134         Q_status        *qsp_dma;
135         int             i;
136
137         /*
138          * Point to CP-resident command queue
139          */
140         cqp = (Cmd_queue *)(fup->fu_ram + CP_READ(aap->aali_cmd_q));
141
142         /*
143          * Point to host-resident command queue structures
144          */
145         hcp = fup->fu_cmd_q;
146         qsp = fup->fu_cmd_stat;
147         qsp_dma = fup->fu_cmd_statd;
148
149         /*
150          * Loop thru all queue entries and do whatever needs doing
151          */
152         for (i = 0; i < CMD_QUELEN; i++) {
153
154                 /*
155                  * Set queue status word to free
156                  */
157                 *qsp = QSTAT_FREE;
158
159                 /*
160                  * Set up host queue entry and link into ring
161                  */
162                 hcp->hcq_cpelem = cqp;
163                 hcp->hcq_status = qsp;
164                 if (i == (CMD_QUELEN - 1))
165                         hcp->hcq_next = fup->fu_cmd_q;
166                 else
167                         hcp->hcq_next = hcp + 1;
168
169                 /*
170                  * Now let the CP into the game
171                  */
172                 cqp->cmdq_status = (CP_dma) CP_WRITE(qsp_dma);
173
174                 /*
175                  * Bump all queue pointers
176                  */
177                 hcp++;
178                 qsp++;
179                 qsp_dma++;
180                 cqp++;
181         }
182
183         /*
184          * Initialize queue pointers
185          */
186         fup->fu_cmd_head = fup->fu_cmd_tail = fup->fu_cmd_q;
187
188         return;
189 }
190
191
192 /*
193  * Drain Command Queue
194  *
195  * This function will process and free all completed entries at the head 
196  * of the command queue. 
197  *
198  * May be called in interrupt state.  
199  * Must be called with interrupts locked out.
200  *
201  * Arguments:
202  *      fup             pointer to device unit structure
203  *
204  * Returns:
205  *      none
206  */
207 void
208 fore_cmd_drain(fup)
209         Fore_unit       *fup;
210 {
211         H_cmd_queue     *hcp;
212         Fore_vcc        *fvp;
213
214         /*
215          * Process each completed entry
216          */
217         while (*fup->fu_cmd_head->hcq_status & QSTAT_COMPLETED) {
218
219                 hcp = fup->fu_cmd_head;
220
221                 /*
222                  * Process command completion
223                  */
224                 switch (hcp->hcq_code) {
225
226                 case CMD_ACT_VCCIN:
227                 case CMD_ACT_VCCOUT:
228                         fvp = hcp->hcq_arg;
229                         if (*hcp->hcq_status & QSTAT_ERROR) {
230                                 /*
231                                  * VCC activation failed - just abort vcc
232                                  */
233                                 if (fvp)
234                                         atm_cm_abort(fvp->fv_connvc,
235                                                 &fore_cause);
236                                 fup->fu_pif.pif_cmderrors++;
237                         } else {
238                                 /*
239                                  * Successful VCC activation
240                                  */
241                                 if (fvp) {
242                                         fvp->fv_state = CVS_ACTIVE;
243                                         fup->fu_open_vcc++;
244                                 }
245                         }
246                         break;
247
248                 case CMD_DACT_VCCIN:
249                 case CMD_DACT_VCCOUT:
250                         fvp = hcp->hcq_arg;
251                         if (*hcp->hcq_status & QSTAT_ERROR) {
252                                 /*
253                                  * VCC dactivation failed - whine
254                                  */
255                                 log(LOG_ERR, 
256                                    "fore_cmd_drain: DACT failed, vcc=(%d,%d)\n",
257                                         fvp->fv_connvc->cvc_vcc->vc_vpi,
258                                         fvp->fv_connvc->cvc_vcc->vc_vci);
259                                 fup->fu_pif.pif_cmderrors++;
260                         } else {
261                                 /*
262                                  * Successful VCC dactivation - so what?
263                                  */
264                         }
265                         break;
266
267                 case CMD_GET_STATS:
268                         if (*hcp->hcq_status & QSTAT_ERROR) {
269                                 /*
270                                  * Couldn't get stats
271                                  */
272                                 fup->fu_pif.pif_cmderrors++;
273                                 fup->fu_stats_ret = EIO;
274                         } else {
275                                 /*
276                                  * Stats are now in unit buffer
277                                  */
278                                 fup->fu_stats_ret = 0;
279                         }
280                         DMA_FREE_ADDR(fup->fu_stats, fup->fu_statsd,
281                                 sizeof(Fore_cp_stats), 0);
282                         fup->fu_flags &= ~FUF_STATCMD;
283
284                         /*
285                          * Flush received stats data
286                          */
287 #ifdef VAC
288                         if (vac)
289                                 vac_pageflush((addr_t)fup->fu_stats);
290 #endif
291
292 #if BYTE_ORDER == LITTLE_ENDIAN
293                         /*
294                          * Little endian machines receives the stats in
295                          * wrong byte order. Instead of swapping in user
296                          * land, swap here so that everything going out
297                          * of the kernel is in correct host order.
298                          */
299                         {
300                                 u_long *bp = (u_long *)fup->fu_stats;
301                                 int     loop;
302
303                                 for ( loop = 0; loop < sizeof(Fore_cp_stats)/
304                                     sizeof(long); loop++, bp++ )
305                                         *bp = ntohl(*bp);
306                         }
307 #endif  /* BYTE_ORDER == LITTLE_ENDIAN */
308
309                         /*
310                          * Poke whoever is waiting on the stats
311                          */
312                         wakeup((caddr_t)&fup->fu_stats);
313                         break;
314
315 #ifdef FORE_PCI
316                 case CMD_GET_PROM:
317                         if (*hcp->hcq_status & QSTAT_ERROR) {
318                                 /*
319                                  * Couldn't get PROM data
320                                  */
321                                 fup->fu_pif.pif_cmderrors++;
322                                 log(LOG_ERR, 
323                                     "fore_cmd_drain: %s%d: GET_PROM failed\n",
324                                         fup->fu_pif.pif_name,
325                                         fup->fu_pif.pif_unit);
326                         } else {
327                                 Fore_prom       *fp = fup->fu_prom;
328
329                                 /*
330                                  * Flush received PROM data
331                                  */
332 #ifdef VAC
333                                 if (vac)
334                                         vac_pageflush((addr_t)fp);
335 #endif
336                                 /*
337                                  * Copy PROM info into config areas
338                                  */
339                                 KM_COPY(&fp->pr_mac[2],
340                                         &fup->fu_pif.pif_macaddr,
341                                         sizeof(struct mac_addr));
342                                 fup->fu_config.ac_macaddr = 
343                                         fup->fu_pif.pif_macaddr;
344                                 snprintf(fup->fu_config.ac_hard_vers,
345                                     sizeof(fup->fu_config.ac_hard_vers),
346                                         "%ld.%ld.%ld",
347                                         (fp->pr_hwver >> 16) & 0xff,
348                                         (fp->pr_hwver >> 8) & 0xff,
349                                         fp->pr_hwver & 0xff);
350                                 fup->fu_config.ac_serial = fp->pr_serno;
351                         }
352
353                         DMA_FREE_ADDR(fup->fu_prom, fup->fu_promd,
354                                 sizeof(Fore_prom), 0);
355                         break;
356 #endif  /* FORE_PCI */
357
358                 default:
359                         log(LOG_ERR, "fore_cmd_drain: unknown command %ld\n",
360                                 hcp->hcq_code);
361                 }
362
363                 /*
364                  * Mark this entry free for use and bump head pointer
365                  * to the next entry in the queue
366                  */
367                 *hcp->hcq_status = QSTAT_FREE;
368                 fup->fu_cmd_head = hcp->hcq_next;
369         }
370
371         return;
372 }
373
374
375 /*
376  * Free Command Queue Data Structures
377  *
378  * Arguments:
379  *      fup             pointer to device unit structure
380  *
381  * Returns:
382  *      none
383  */
384 void
385 fore_cmd_free(fup)
386         Fore_unit       *fup;
387 {
388         H_cmd_queue     *hcp;
389
390         /*
391          * Deal with any commands left on the queue
392          */
393         if (fup->fu_flags & CUF_INITED) {
394                 while (*fup->fu_cmd_head->hcq_status != QSTAT_FREE) {
395                         hcp = fup->fu_cmd_head;
396
397                         switch (hcp->hcq_code) {
398
399                         case CMD_GET_STATS:
400                                 /*
401                                  * Just in case someone is sleeping on this
402                                  */
403                                 fup->fu_stats_ret = EIO;
404                                 wakeup((caddr_t)&fup->fu_stats);
405                                 break;
406                         }
407
408                         *hcp->hcq_status = QSTAT_FREE;
409                         fup->fu_cmd_head = hcp->hcq_next;
410                 }
411         }
412
413         /*
414          * Free the statistics buffer
415          */
416         if (fup->fu_stats) {
417                 atm_dev_free(fup->fu_stats);
418                 fup->fu_stats = NULL;
419         }
420
421 #ifdef FORE_PCI
422         /*
423          * Free the PROM buffer
424          */
425         if (fup->fu_prom) {
426                 atm_dev_free(fup->fu_prom);
427                 fup->fu_prom = NULL;
428         }
429 #endif
430
431         /*
432          * Free the status words
433          */
434         if (fup->fu_cmd_stat) {
435                 if (fup->fu_cmd_statd) {
436                         DMA_FREE_ADDR(fup->fu_cmd_stat, fup->fu_cmd_statd,
437                                 sizeof(Q_status) * CMD_QUELEN,
438                                 ATM_DEV_NONCACHE);
439                 }
440                 atm_dev_free((volatile void *)fup->fu_cmd_stat);
441                 fup->fu_cmd_stat = NULL;
442                 fup->fu_cmd_statd = NULL;
443         }
444
445         return;
446 }
447