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