Added soon-to-be-requisite missing include.
[gpxe.git] / src / interface / pxe / pxe.c
1 /** @file
2  *
3  * 
4  *
5  */
6
7 /*
8  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of the
13  * License, or any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "dev.h"
26 #include "pxe.h"
27
28 /* Global pointer to currently installed PXE stack */
29 pxe_stack_t *pxe_stack = NULL;
30
31 /* Various startup/shutdown routines.  The startup/shutdown call
32  * sequence is incredibly badly defined in the Intel PXE spec, for
33  * example:
34  *
35  *   PXENV_UNDI_INITIALIZE says that the parameters used to initialize
36  *   the adaptor should be those supplied to the most recent
37  *   PXENV_UNDI_STARTUP call.  PXENV_UNDI_STARTUP takes no parameters.
38  *
39  *   PXENV_UNDI_CLEANUP says that the rest of the API will not be
40  *   available after making this call.  Figure 3-3 ("Early UNDI API
41  *   usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
42  *   call to the supposedly now unavailable PXENV_STOP_UNDI.
43  *
44  *   PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
45  *   occupied by the PXE stack.  Figure 4-3 ("PXE IPL") shows a call
46  *   to PXENV_STOP_UNDI being made after the call to
47  *   PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
48  *   should have been freed (and, potentially, zeroed).
49  *
50  *   Nothing, anywhere, seems to mention who's responsible for freeing
51  *   up the base memory allocated for the stack segment.  It's not
52  *   even clear whether or not this is expected to be in free base
53  *   memory rather than claimed base memory.
54  *
55  * Consequently, we adopt a rather defensive strategy, designed to
56  * work with any conceivable sequence of initialisation or shutdown
57  * calls.  We have only two things that we care about:
58  *
59  *   1. Have we hooked INT 1A and INT 15,E820(etc.)?
60  *   2. Is the NIC initialised?
61  *
62  * The NIC should never be initialised without the vectors being
63  * hooked, similarly the vectors should never be unhooked with the NIC
64  * still initialised.  We do, however, want to be able to have the
65  * vectors hooked with the NIC shutdown.  We therefore have three
66  * possible states:
67  *
68  *   1. Ready to unload: interrupts unhooked, NIC shutdown.
69  *   2. Midway: interrupts hooked, NIC shutdown.
70  *   3. Fully ready: interrupts hooked, NIC initialised.
71  *
72  * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
73  * these, and the call pxe_ensure_state() to ensure that the stack is
74  * in the specified state.  All our PXE API call implementations
75  * should use this call to ensure that the state is as required for
76  * that PXE API call.  This enables us to cope with whatever the
77  * end-user's interpretation of the PXE spec may be.  It even allows
78  * for someone calling e.g. PXENV_START_UNDI followed by
79  * PXENV_UDP_WRITE, without bothering with any of the intervening
80  * calls.
81  *
82  * pxe_ensure_state() returns 1 for success, 0 for failure.  In the
83  * event of failure (which can arise from e.g. asking for state READY
84  * when we don't know where our NIC is), the error code
85  * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
86  * The macros ENSURE_XXX() can be used to achieve this without lots of
87  * duplicated code.
88  */
89
90 /* pxe_[un]hook_stack are architecture-specific and provided in
91  * pxe_callbacks.c
92  */
93
94 int pxe_initialise_nic ( void ) {
95         if ( pxe_stack->state >= READY ) return 1;
96
97 #warning "device probing mechanism has completely changed"
98 #if 0
99
100         /* Check if NIC is initialised.  dev.disable is set to 0
101          * when disable() is called, so we use this.
102          */
103         if ( dev.disable ) {
104                 /* NIC may have been initialised independently
105                  * (e.g. when we set up the stack prior to calling the
106                  * NBP).
107                  */
108                 pxe_stack->state = READY;
109                 return 1;
110         }
111
112         /* If we already have a NIC defined, reuse that one with
113          * PROBE_AWAKE.  If one was specifed via PXENV_START_UNDI, try
114          * that one first.  Otherwise, set PROBE_FIRST.
115          */
116
117         if ( dev.state.pci.dev.use_specified == 1 ) {
118                 dev.how_probe = PROBE_NEXT;
119                 DBG ( " initialising NIC specified via START_UNDI" );
120         } else if ( dev.state.pci.dev.driver ) {
121                 DBG ( " reinitialising NIC" );
122                 dev.how_probe = PROBE_AWAKE;
123         } else {
124                 DBG ( " probing for any NIC" );
125                 dev.how_probe = PROBE_FIRST;
126         }
127
128         /* Call probe routine to bring up the NIC */
129         if ( eth_probe ( &dev ) != PROBE_WORKED ) {
130                 DBG ( " failed" );
131                 return 0;
132         }
133 #endif
134         
135
136         pxe_stack->state = READY;
137         return 1;
138 }
139
140 int pxe_shutdown_nic ( void ) {
141         if ( pxe_stack->state <= MIDWAY ) return 1;
142
143         eth_irq ( DISABLE );
144         disable ( &dev );
145         pxe_stack->state = MIDWAY;
146         return 1;
147 }
148
149 int ensure_pxe_state ( pxe_stack_state_t wanted ) {
150         int success = 1;
151
152         if ( ! pxe_stack ) return 0;
153         if ( wanted >= MIDWAY )
154                 success = success & hook_pxe_stack();
155         if ( wanted > MIDWAY ) {
156                 success = success & pxe_initialise_nic();
157         } else {
158                 success = success & pxe_shutdown_nic();
159         }
160         if ( wanted < MIDWAY )
161                 success = success & unhook_pxe_stack();
162         return success;
163 }
164
165 /* API call dispatcher
166  *
167  * Status: complete
168  */
169 PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any ) {
170         PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
171
172         /* Set default status in case child routine fails to do so */
173         any->Status = PXENV_STATUS_FAILURE;
174
175         DBG ( "[" );
176
177         /* Hand off to relevant API routine */
178         switch ( opcode ) {
179         case PXENV_START_UNDI:
180                 ret = pxenv_start_undi ( &any->start_undi );
181                 break;
182         case PXENV_UNDI_STARTUP:
183                 ret = pxenv_undi_startup ( &any->undi_startup );
184                 break;
185         case PXENV_UNDI_CLEANUP:
186                 ret = pxenv_undi_cleanup ( &any->undi_cleanup );
187                 break;
188         case PXENV_UNDI_INITIALIZE:
189                 ret = pxenv_undi_initialize ( &any->undi_initialize );
190                 break;
191         case PXENV_UNDI_RESET_ADAPTER:
192                 ret = pxenv_undi_reset_adapter ( &any->undi_reset_adapter );
193                 break;
194         case PXENV_UNDI_SHUTDOWN:
195                 ret = pxenv_undi_shutdown ( &any->undi_shutdown );
196                 break;
197         case PXENV_UNDI_OPEN:
198                 ret = pxenv_undi_open ( &any->undi_open );
199                 break;
200         case PXENV_UNDI_CLOSE:
201                 ret = pxenv_undi_close ( &any->undi_close );
202                 break;
203         case PXENV_UNDI_TRANSMIT:
204                 ret = pxenv_undi_transmit ( &any->undi_transmit );
205                 break;
206         case PXENV_UNDI_SET_MCAST_ADDRESS:
207                 ret = pxenv_undi_set_mcast_address (
208                                                 &any->undi_set_mcast_address );
209                 break;
210         case PXENV_UNDI_SET_STATION_ADDRESS:
211                 ret = pxenv_undi_set_station_address (
212                                               &any->undi_set_station_address );
213                 break;
214         case PXENV_UNDI_SET_PACKET_FILTER:
215                 ret = pxenv_undi_set_packet_filter (
216                                                 &any->undi_set_packet_filter );
217                 break;
218         case PXENV_UNDI_GET_INFORMATION:
219                 ret = pxenv_undi_get_information (
220                                                &any->undi_get_information );
221                 break;
222         case PXENV_UNDI_GET_STATISTICS:
223                 ret = pxenv_undi_get_statistics ( &any->undi_get_statistics );
224                 break;
225         case PXENV_UNDI_CLEAR_STATISTICS:
226                 ret = pxenv_undi_clear_statistics (
227                                                  &any->undi_clear_statistics );
228                 break;
229         case PXENV_UNDI_INITIATE_DIAGS:
230                 ret = pxenv_undi_initiate_diags ( &any->undi_initiate_diags );
231                                                  
232                 break;
233         case PXENV_UNDI_FORCE_INTERRUPT:
234                 ret = pxenv_undi_force_interrupt (
235                                                &any->undi_force_interrupt );
236                 break;
237         case PXENV_UNDI_GET_MCAST_ADDRESS:
238                 ret = pxenv_undi_get_mcast_address (
239                                              &any->undi_get_mcast_address );
240                 break;
241         case PXENV_UNDI_GET_NIC_TYPE:
242                 ret = pxenv_undi_get_nic_type ( &any->undi_get_nic_type );
243                 break;
244         case PXENV_UNDI_GET_IFACE_INFO:
245                 ret = pxenv_undi_get_iface_info ( &any->undi_get_iface_info );
246                 break;
247         case PXENV_UNDI_ISR:
248                 ret = pxenv_undi_isr ( &any->undi_isr );
249                 break;
250         case PXENV_STOP_UNDI:
251                 ret = pxenv_stop_undi ( &any->stop_undi );
252                 break;
253         case PXENV_TFTP_OPEN:
254                 ret = pxenv_tftp_open ( &any->tftp_open );
255                 break;
256         case PXENV_TFTP_CLOSE:
257                 ret = pxenv_tftp_close ( &any->tftp_close );
258                 break;
259         case PXENV_TFTP_READ:
260                 ret = pxenv_tftp_read ( &any->tftp_read );
261                 break;
262         case PXENV_TFTP_READ_FILE:
263                 ret = pxenv_tftp_read_file ( &any->tftp_read_file );
264                 break;
265         case PXENV_TFTP_GET_FSIZE:
266                 ret = pxenv_tftp_get_fsize ( &any->tftp_get_fsize );
267                 break;
268         case PXENV_UDP_OPEN:
269                 ret = pxenv_udp_open ( &any->udp_open );
270                 break;
271         case PXENV_UDP_CLOSE:
272                 ret = pxenv_udp_close ( &any->udp_close );
273                 break;
274         case PXENV_UDP_READ:
275                 ret = pxenv_udp_read ( &any->udp_read );
276                 break;
277         case PXENV_UDP_WRITE:
278                 ret = pxenv_udp_write ( &any->udp_write );
279                 break;
280         case PXENV_UNLOAD_STACK:
281                 ret = pxenv_unload_stack ( &any->unload_stack );
282                 break;
283         case PXENV_GET_CACHED_INFO:
284                 ret = pxenv_get_cached_info ( &any->get_cached_info );
285                 break;
286         case PXENV_RESTART_TFTP:
287                 ret = pxenv_restart_tftp ( &any->restart_tftp );
288                 break;
289         case PXENV_START_BASE:
290                 ret = pxenv_start_base ( &any->start_base );
291                 break;
292         case PXENV_STOP_BASE:
293                 ret = pxenv_stop_base ( &any->stop_base );
294                 break;
295                 
296         default:
297                 DBG ( "PXENV_UNKNOWN_%hx", opcode );
298                 any->Status = PXENV_STATUS_UNSUPPORTED;
299                 ret = PXENV_EXIT_FAILURE;
300                 break;
301         }
302
303         if ( any->Status != PXENV_STATUS_SUCCESS ) {
304                 DBG ( " %hx", any->Status );
305         }
306         if ( ret != PXENV_EXIT_SUCCESS ) {
307                 DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
308         }
309         DBG ( "]" );
310
311         return ret;
312 }