xref: /onnv-gate/usr/src/grub/grub-0.97/netboot/undi.c (revision 12881:c53827a598ac)
18044SWilliam.Kucharski@Sun.COM /**************************************************************************
28044SWilliam.Kucharski@Sun.COM Etherboot -  BOOTP/TFTP Bootstrap Program
38044SWilliam.Kucharski@Sun.COM UNDI NIC driver for Etherboot
48044SWilliam.Kucharski@Sun.COM 
58044SWilliam.Kucharski@Sun.COM This file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk>
68044SWilliam.Kucharski@Sun.COM of Fen Systems Ltd. (http://www.fensystems.co.uk/).  All rights
78044SWilliam.Kucharski@Sun.COM reserved.
88044SWilliam.Kucharski@Sun.COM 
98044SWilliam.Kucharski@Sun.COM $Id: undi.c,v 1.8 2003/10/25 13:54:53 mcb30 Exp $
108044SWilliam.Kucharski@Sun.COM ***************************************************************************/
118044SWilliam.Kucharski@Sun.COM 
128044SWilliam.Kucharski@Sun.COM /*
138044SWilliam.Kucharski@Sun.COM  * This program is free software; you can redistribute it and/or
148044SWilliam.Kucharski@Sun.COM  * modify it under the terms of the GNU General Public License as
158044SWilliam.Kucharski@Sun.COM  * published by the Free Software Foundation; either version 2, or (at
168044SWilliam.Kucharski@Sun.COM  * your option) any later version.
178044SWilliam.Kucharski@Sun.COM  */
188044SWilliam.Kucharski@Sun.COM 
198044SWilliam.Kucharski@Sun.COM /* to get some global routines like printf */
208044SWilliam.Kucharski@Sun.COM #include "etherboot.h"
218044SWilliam.Kucharski@Sun.COM /* to get the interface to the body of the program */
228044SWilliam.Kucharski@Sun.COM #include "nic.h"
238044SWilliam.Kucharski@Sun.COM /* to get the PCI support functions, if this is a PCI NIC */
248044SWilliam.Kucharski@Sun.COM #include "pci.h"
258044SWilliam.Kucharski@Sun.COM /* UNDI and PXE defines.  Includes pxe.h. */
268044SWilliam.Kucharski@Sun.COM #include "undi.h"
278044SWilliam.Kucharski@Sun.COM /* 8259 PIC defines */
288044SWilliam.Kucharski@Sun.COM #include "pic8259.h"
298044SWilliam.Kucharski@Sun.COM #include "bootp.h"
308044SWilliam.Kucharski@Sun.COM #include "tftp.h"
318044SWilliam.Kucharski@Sun.COM #include "shared.h"
328044SWilliam.Kucharski@Sun.COM 
338044SWilliam.Kucharski@Sun.COM /* NIC specific static variables go here */
348044SWilliam.Kucharski@Sun.COM static undi_t undi = { NULL, NULL, NULL, NULL, NULL, NULL, NULL,
358044SWilliam.Kucharski@Sun.COM 		       NULL, NULL, 0, NULL, 0, NULL,
368044SWilliam.Kucharski@Sun.COM 		       0, 0, 0, 0,
378044SWilliam.Kucharski@Sun.COM 		       { 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, NULL },
388044SWilliam.Kucharski@Sun.COM 		       IRQ_NONE };
398044SWilliam.Kucharski@Sun.COM static undi_base_mem_data_t undi_base_mem_data;
408044SWilliam.Kucharski@Sun.COM 
418044SWilliam.Kucharski@Sun.COM #define UNDI_HEAP (void *)(512 << 10)
428044SWilliam.Kucharski@Sun.COM 
438044SWilliam.Kucharski@Sun.COM /* Function prototypes */
448044SWilliam.Kucharski@Sun.COM int allocate_base_mem_data ( void );
458044SWilliam.Kucharski@Sun.COM int free_base_mem_data ( void );
468044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_shutdown ( void );
478044SWilliam.Kucharski@Sun.COM int eb_pxenv_stop_undi ( void );
488044SWilliam.Kucharski@Sun.COM int undi_unload_base_code ( void );
498044SWilliam.Kucharski@Sun.COM int undi_full_shutdown ( void );
508044SWilliam.Kucharski@Sun.COM int eb_pxenv_get_cached_info (uint8_t, void **info);
518044SWilliam.Kucharski@Sun.COM 
528044SWilliam.Kucharski@Sun.COM /**************************************************************************
538044SWilliam.Kucharski@Sun.COM  * Utility functions
548044SWilliam.Kucharski@Sun.COM  **************************************************************************/
558044SWilliam.Kucharski@Sun.COM 
568044SWilliam.Kucharski@Sun.COM /* Checksum a block.
578044SWilliam.Kucharski@Sun.COM  */
588044SWilliam.Kucharski@Sun.COM 
checksum(void * block,size_t size)598044SWilliam.Kucharski@Sun.COM uint8_t checksum ( void *block, size_t size ) {
608044SWilliam.Kucharski@Sun.COM 	uint8_t sum = 0;
618044SWilliam.Kucharski@Sun.COM 	uint16_t i = 0;
628044SWilliam.Kucharski@Sun.COM 	for ( i = 0; i < size; i++ ) {
638044SWilliam.Kucharski@Sun.COM 		sum += ( ( uint8_t * ) block )[i];
648044SWilliam.Kucharski@Sun.COM 	}
658044SWilliam.Kucharski@Sun.COM 	return sum;
668044SWilliam.Kucharski@Sun.COM }
678044SWilliam.Kucharski@Sun.COM 
688044SWilliam.Kucharski@Sun.COM /* Print the status of a !PXE structure
698044SWilliam.Kucharski@Sun.COM  */
708044SWilliam.Kucharski@Sun.COM 
pxe_dump(void)718044SWilliam.Kucharski@Sun.COM void pxe_dump ( void ) {
728044SWilliam.Kucharski@Sun.COM #ifdef TRACE_UNDI
738044SWilliam.Kucharski@Sun.COM 	printf ( "API %hx:%hx St %hx:%hx UD %hx:%hx UC %hx:%hx "
748044SWilliam.Kucharski@Sun.COM 		 "BD %hx:%hx BC %hx:%hx\n",
758044SWilliam.Kucharski@Sun.COM 		 undi.pxe->EntryPointSP.segment, undi.pxe->EntryPointSP.offset,
768044SWilliam.Kucharski@Sun.COM 		 undi.pxe->Stack.Seg_Addr, undi.pxe->Stack.Seg_Size,
778044SWilliam.Kucharski@Sun.COM 		 undi.pxe->UNDIData.Seg_Addr, undi.pxe->UNDIData.Seg_Size,
788044SWilliam.Kucharski@Sun.COM 		 undi.pxe->UNDICode.Seg_Addr, undi.pxe->UNDICode.Seg_Size,
798044SWilliam.Kucharski@Sun.COM 		 undi.pxe->BC_Data.Seg_Addr, undi.pxe->BC_Data.Seg_Size,
808044SWilliam.Kucharski@Sun.COM 		 undi.pxe->BC_Code.Seg_Addr, undi.pxe->BC_Code.Seg_Size );
818044SWilliam.Kucharski@Sun.COM #endif
828044SWilliam.Kucharski@Sun.COM }
838044SWilliam.Kucharski@Sun.COM 
848044SWilliam.Kucharski@Sun.COM /* Allocate/free space for structures that must reside in base memory
858044SWilliam.Kucharski@Sun.COM  */
868044SWilliam.Kucharski@Sun.COM 
allocate_base_mem_data(void)878044SWilliam.Kucharski@Sun.COM int allocate_base_mem_data ( void ) {
888044SWilliam.Kucharski@Sun.COM 	/* In GRUB, anything is in base address, so we do not need
898044SWilliam.Kucharski@Sun.COM 	 * allocate anything */
908044SWilliam.Kucharski@Sun.COM 	undi.base_mem_data = &undi_base_mem_data;
918044SWilliam.Kucharski@Sun.COM 	memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) );
928044SWilliam.Kucharski@Sun.COM 	undi.undi_call_info = &undi.base_mem_data->undi_call_info;
938044SWilliam.Kucharski@Sun.COM 	undi.pxs = &undi.base_mem_data->pxs;
948044SWilliam.Kucharski@Sun.COM 	undi.xmit_data = &undi.base_mem_data->xmit_data;
958044SWilliam.Kucharski@Sun.COM 	undi.xmit_buffer = undi.base_mem_data->xmit_buffer;
968044SWilliam.Kucharski@Sun.COM #if 0				/* Etherboot Code */
978044SWilliam.Kucharski@Sun.COM 	/* Allocate space in base memory.
988044SWilliam.Kucharski@Sun.COM 	 * Initialise pointers to base memory structures.
998044SWilliam.Kucharski@Sun.COM 	 */
1008044SWilliam.Kucharski@Sun.COM 	if ( undi.base_mem_data == NULL ) {
1018044SWilliam.Kucharski@Sun.COM 		undi.base_mem_data =
1028044SWilliam.Kucharski@Sun.COM 			allot_base_memory ( sizeof(undi_base_mem_data_t) +
1038044SWilliam.Kucharski@Sun.COM 					    TRIVIAL_IRQ_HANDLER_SIZE );
1048044SWilliam.Kucharski@Sun.COM 		if ( undi.base_mem_data == NULL ) {
1058044SWilliam.Kucharski@Sun.COM 			printf ( "Failed to allocate base memory\n" );
1068044SWilliam.Kucharski@Sun.COM 			free_base_mem_data();
1078044SWilliam.Kucharski@Sun.COM 			return 0;
1088044SWilliam.Kucharski@Sun.COM 		}
1098044SWilliam.Kucharski@Sun.COM 		memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) );
1108044SWilliam.Kucharski@Sun.COM 		undi.undi_call_info = &undi.base_mem_data->undi_call_info;
1118044SWilliam.Kucharski@Sun.COM 		undi.pxs = &undi.base_mem_data->pxs;
1128044SWilliam.Kucharski@Sun.COM 		undi.xmit_data = &undi.base_mem_data->xmit_data;
1138044SWilliam.Kucharski@Sun.COM 		undi.xmit_buffer = undi.base_mem_data->xmit_buffer;
1148044SWilliam.Kucharski@Sun.COM 		copy_trivial_irq_handler ( undi.base_mem_data->irq_handler,
1158044SWilliam.Kucharski@Sun.COM 					   TRIVIAL_IRQ_HANDLER_SIZE );
1168044SWilliam.Kucharski@Sun.COM 	}
1178044SWilliam.Kucharski@Sun.COM #endif	/* Etherboot Code */
1188044SWilliam.Kucharski@Sun.COM 	return 1;
1198044SWilliam.Kucharski@Sun.COM }
1208044SWilliam.Kucharski@Sun.COM 
free_base_mem_data(void)1218044SWilliam.Kucharski@Sun.COM int free_base_mem_data ( void ) {
1228044SWilliam.Kucharski@Sun.COM 	/* Just pretend to free something :-) */
1238044SWilliam.Kucharski@Sun.COM 	undi.base_mem_data = NULL;
1248044SWilliam.Kucharski@Sun.COM 	undi.undi_call_info = NULL;
1258044SWilliam.Kucharski@Sun.COM 	undi.pxs = NULL;
1268044SWilliam.Kucharski@Sun.COM 	undi.xmit_data = NULL;
1278044SWilliam.Kucharski@Sun.COM 	undi.xmit_buffer = NULL;
1288044SWilliam.Kucharski@Sun.COM #if 0				/* Etherboot Code */
1298044SWilliam.Kucharski@Sun.COM 	if ( undi.base_mem_data != NULL ) {
1308044SWilliam.Kucharski@Sun.COM 		forget_base_memory ( undi.base_mem_data,
1318044SWilliam.Kucharski@Sun.COM 				     sizeof(undi_base_mem_data_t) +
1328044SWilliam.Kucharski@Sun.COM 				     TRIVIAL_IRQ_HANDLER_SIZE );
1338044SWilliam.Kucharski@Sun.COM 		undi.base_mem_data = NULL;
1348044SWilliam.Kucharski@Sun.COM 		undi.undi_call_info = NULL;
1358044SWilliam.Kucharski@Sun.COM 		undi.pxs = NULL;
1368044SWilliam.Kucharski@Sun.COM 		undi.xmit_data = NULL;
1378044SWilliam.Kucharski@Sun.COM 		undi.xmit_buffer = NULL;
1388044SWilliam.Kucharski@Sun.COM 		copy_trivial_irq_handler ( NULL, 0 );
1398044SWilliam.Kucharski@Sun.COM 	}
1408044SWilliam.Kucharski@Sun.COM #endif	/* Etherboot Code */
1418044SWilliam.Kucharski@Sun.COM 	return 1;
1428044SWilliam.Kucharski@Sun.COM }
1438044SWilliam.Kucharski@Sun.COM 
assemble_firing_squad(firing_squad_lineup_t * lineup,void * start,size_t size,firing_squad_shoot_t shoot)1448044SWilliam.Kucharski@Sun.COM void assemble_firing_squad ( firing_squad_lineup_t *lineup,
1458044SWilliam.Kucharski@Sun.COM 			     void *start, size_t size,
1468044SWilliam.Kucharski@Sun.COM 			     firing_squad_shoot_t shoot ) {
1478044SWilliam.Kucharski@Sun.COM 	int target;
1488044SWilliam.Kucharski@Sun.COM 	int index;
1498044SWilliam.Kucharski@Sun.COM 	int bit;
1508044SWilliam.Kucharski@Sun.COM 	int start_kb = virt_to_phys(start) >> 10;
1518044SWilliam.Kucharski@Sun.COM 	int end_kb = ( virt_to_phys(start+size) + (1<<10) - 1 ) >> 10;
1528044SWilliam.Kucharski@Sun.COM 
1538044SWilliam.Kucharski@Sun.COM 	for ( target = start_kb; target <= end_kb; target++ ) {
1548044SWilliam.Kucharski@Sun.COM 		index = FIRING_SQUAD_TARGET_INDEX ( target );
1558044SWilliam.Kucharski@Sun.COM 		bit = FIRING_SQUAD_TARGET_BIT ( target );
1568044SWilliam.Kucharski@Sun.COM 		lineup->targets[index] = ( shoot << bit ) |
1578044SWilliam.Kucharski@Sun.COM 			( lineup->targets[index] & ~( 1 << bit ) );
1588044SWilliam.Kucharski@Sun.COM 	}
1598044SWilliam.Kucharski@Sun.COM }
1608044SWilliam.Kucharski@Sun.COM 
shoot_targets(firing_squad_lineup_t * lineup)1618044SWilliam.Kucharski@Sun.COM void shoot_targets ( firing_squad_lineup_t *lineup ) {
1628044SWilliam.Kucharski@Sun.COM 	int shoot_this_target = 0;
1638044SWilliam.Kucharski@Sun.COM 	int shoot_last_target = 0;
1648044SWilliam.Kucharski@Sun.COM 	int start_target = 0;
1658044SWilliam.Kucharski@Sun.COM 	int target;
1668044SWilliam.Kucharski@Sun.COM 
1678044SWilliam.Kucharski@Sun.COM 	for ( target = 0; target <= 640; target++ ) {
1688044SWilliam.Kucharski@Sun.COM 		shoot_this_target = ( target == 640 ? 0 :
1698044SWilliam.Kucharski@Sun.COM 		      ( 1 << FIRING_SQUAD_TARGET_BIT(target) ) &
1708044SWilliam.Kucharski@Sun.COM 		      lineup->targets[FIRING_SQUAD_TARGET_INDEX(target)] );
1718044SWilliam.Kucharski@Sun.COM 		if ( shoot_this_target && !shoot_last_target ) {
1728044SWilliam.Kucharski@Sun.COM 			start_target = target;
1738044SWilliam.Kucharski@Sun.COM 		} else if ( shoot_last_target && !shoot_this_target ) {
1748044SWilliam.Kucharski@Sun.COM 			size_t range_size = ( target - start_target ) << 10;
1758044SWilliam.Kucharski@Sun.COM 			forget_base_memory ( phys_to_virt( start_target<<10 ),
1768044SWilliam.Kucharski@Sun.COM 					     range_size );
1778044SWilliam.Kucharski@Sun.COM 		}
1788044SWilliam.Kucharski@Sun.COM 		shoot_last_target = shoot_this_target;
1798044SWilliam.Kucharski@Sun.COM 	}
1808044SWilliam.Kucharski@Sun.COM }
1818044SWilliam.Kucharski@Sun.COM 
1828044SWilliam.Kucharski@Sun.COM /* Debug macros
1838044SWilliam.Kucharski@Sun.COM  */
1848044SWilliam.Kucharski@Sun.COM 
1858044SWilliam.Kucharski@Sun.COM #ifdef TRACE_UNDI
1868044SWilliam.Kucharski@Sun.COM #define DBG(...) printf ( __VA_ARGS__ )
1878044SWilliam.Kucharski@Sun.COM #else
1888044SWilliam.Kucharski@Sun.COM #define DBG(...)
1898044SWilliam.Kucharski@Sun.COM #endif
1908044SWilliam.Kucharski@Sun.COM 
1918044SWilliam.Kucharski@Sun.COM #define UNDI_STATUS(pxs) ( (pxs)->Status == PXENV_EXIT_SUCCESS ? \
1928044SWilliam.Kucharski@Sun.COM 			      "SUCCESS" : \
1938044SWilliam.Kucharski@Sun.COM 			      ( (pxs)->Status == PXENV_EXIT_FAILURE ? \
1948044SWilliam.Kucharski@Sun.COM 				"FAILURE" : "UNKNOWN" ) )
1958044SWilliam.Kucharski@Sun.COM 
1968044SWilliam.Kucharski@Sun.COM /**************************************************************************
1978044SWilliam.Kucharski@Sun.COM  * Base memory scanning functions
1988044SWilliam.Kucharski@Sun.COM  **************************************************************************/
1998044SWilliam.Kucharski@Sun.COM 
2008044SWilliam.Kucharski@Sun.COM /* Locate the $PnP structure indicating a PnP BIOS.
2018044SWilliam.Kucharski@Sun.COM  */
2028044SWilliam.Kucharski@Sun.COM 
hunt_pnp_bios(void)2038044SWilliam.Kucharski@Sun.COM int hunt_pnp_bios ( void ) {
2048044SWilliam.Kucharski@Sun.COM 	uint32_t off = 0x10000;
2058044SWilliam.Kucharski@Sun.COM 
2068044SWilliam.Kucharski@Sun.COM 	DBG ( "Hunting for PnP BIOS..." );
2078044SWilliam.Kucharski@Sun.COM 	while ( off > 0 ) {
2088044SWilliam.Kucharski@Sun.COM 		off -= 16;
2098044SWilliam.Kucharski@Sun.COM 		undi.pnp_bios = (pnp_bios_t *) phys_to_virt ( 0xf0000 + off );
2108044SWilliam.Kucharski@Sun.COM 		if ( undi.pnp_bios->signature == PNP_BIOS_SIGNATURE ) {
2118044SWilliam.Kucharski@Sun.COM 			DBG ( "found $PnP at f000:%hx...", off );
2128044SWilliam.Kucharski@Sun.COM 			if ( checksum(undi.pnp_bios,sizeof(pnp_bios_t)) !=0) {
2138044SWilliam.Kucharski@Sun.COM 				DBG ( "invalid checksum\n..." );
2148044SWilliam.Kucharski@Sun.COM 				continue;
2158044SWilliam.Kucharski@Sun.COM 			}
2168044SWilliam.Kucharski@Sun.COM 			DBG ( "ok\n" );
2178044SWilliam.Kucharski@Sun.COM 			return 1;
2188044SWilliam.Kucharski@Sun.COM 		}
2198044SWilliam.Kucharski@Sun.COM 	}
2208044SWilliam.Kucharski@Sun.COM 	DBG ( "none found\n" );
2218044SWilliam.Kucharski@Sun.COM 	undi.pnp_bios = NULL;
2228044SWilliam.Kucharski@Sun.COM 	return 0;
2238044SWilliam.Kucharski@Sun.COM }
2248044SWilliam.Kucharski@Sun.COM 
2258044SWilliam.Kucharski@Sun.COM /* Locate the !PXE structure indicating a loaded UNDI driver.
2268044SWilliam.Kucharski@Sun.COM  */
2278044SWilliam.Kucharski@Sun.COM 
hunt_pixie(void)2288044SWilliam.Kucharski@Sun.COM int hunt_pixie ( void ) {
2298044SWilliam.Kucharski@Sun.COM 	static uint32_t ptr = 0;
2308044SWilliam.Kucharski@Sun.COM 	pxe_t *pxe = NULL;
2318044SWilliam.Kucharski@Sun.COM 
2328044SWilliam.Kucharski@Sun.COM 	DBG ( "Hunting for pixies..." );
2338044SWilliam.Kucharski@Sun.COM 	if ( ptr == 0 ) ptr = 0xa0000;
2348044SWilliam.Kucharski@Sun.COM 	while ( ptr > 0x10000 ) {
2358044SWilliam.Kucharski@Sun.COM 		ptr -= 16;
2368044SWilliam.Kucharski@Sun.COM 		pxe = (pxe_t *) phys_to_virt ( ptr );
2378044SWilliam.Kucharski@Sun.COM 		if ( memcmp ( pxe->Signature, "!PXE", 4 ) == 0 ) {
2388044SWilliam.Kucharski@Sun.COM 			DBG ( "found !PXE at %x...", ptr );
2398044SWilliam.Kucharski@Sun.COM 			if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) {
2408044SWilliam.Kucharski@Sun.COM 				DBG ( "invalid checksum\n..." );
2418044SWilliam.Kucharski@Sun.COM 				continue;
2428044SWilliam.Kucharski@Sun.COM 			}
2438044SWilliam.Kucharski@Sun.COM 			if ( ptr < get_free_base_memory() ) {
2448044SWilliam.Kucharski@Sun.COM 				DBG ( "in free base memory!\n\n"
2458044SWilliam.Kucharski@Sun.COM 					 "WARNING: a valid !PXE structure was "
2468044SWilliam.Kucharski@Sun.COM 					 "found in an area of memory marked "
2478044SWilliam.Kucharski@Sun.COM 					 "as free!\n\n" );
2488044SWilliam.Kucharski@Sun.COM 				undi.pxe = pxe;
2498044SWilliam.Kucharski@Sun.COM 				pxe_dump();
2508044SWilliam.Kucharski@Sun.COM 				undi.pxe = NULL;
2518044SWilliam.Kucharski@Sun.COM 				DBG ( "\nIgnoring and continuing, but this "
2528044SWilliam.Kucharski@Sun.COM 					 "may cause problems later!\n\n" );
2538044SWilliam.Kucharski@Sun.COM 				continue;
2548044SWilliam.Kucharski@Sun.COM 			}
2558044SWilliam.Kucharski@Sun.COM 			DBG ( "ok\n" );
2568044SWilliam.Kucharski@Sun.COM 			undi.pxe = pxe;
2578044SWilliam.Kucharski@Sun.COM 			pxe_dump();
2588044SWilliam.Kucharski@Sun.COM 			DBG ( "Resetting pixie...\n" );
2598044SWilliam.Kucharski@Sun.COM 			undi_unload_base_code();
2608044SWilliam.Kucharski@Sun.COM 			eb_pxenv_stop_undi();
2618044SWilliam.Kucharski@Sun.COM 			pxe_dump();
2628044SWilliam.Kucharski@Sun.COM 			return 1;
2638044SWilliam.Kucharski@Sun.COM 		}
2648044SWilliam.Kucharski@Sun.COM 	}
2658044SWilliam.Kucharski@Sun.COM 	DBG ( "none found\n" );
2668044SWilliam.Kucharski@Sun.COM 	ptr = 0;
2678044SWilliam.Kucharski@Sun.COM 	return 0;
2688044SWilliam.Kucharski@Sun.COM }
2698044SWilliam.Kucharski@Sun.COM 
2708044SWilliam.Kucharski@Sun.COM /* Locate PCI PnP ROMs.
2718044SWilliam.Kucharski@Sun.COM  */
2728044SWilliam.Kucharski@Sun.COM 
hunt_rom(void)2738044SWilliam.Kucharski@Sun.COM int hunt_rom ( void ) {
2748044SWilliam.Kucharski@Sun.COM 	static uint32_t ptr = 0;
2758044SWilliam.Kucharski@Sun.COM 
2768044SWilliam.Kucharski@Sun.COM 	DBG ( "Hunting for ROMs..." );
2778044SWilliam.Kucharski@Sun.COM 	if ( ptr == 0 ) ptr = 0x100000;
2788044SWilliam.Kucharski@Sun.COM 	while ( ptr > 0x0c0000 ) {
2798044SWilliam.Kucharski@Sun.COM 		ptr -= 0x800;
2808044SWilliam.Kucharski@Sun.COM 		undi.rom = ( rom_t * ) phys_to_virt ( ptr );
2818044SWilliam.Kucharski@Sun.COM 		if ( undi.rom->signature == ROM_SIGNATURE ) {
2828044SWilliam.Kucharski@Sun.COM 			pcir_header_t *pcir_header = NULL;
2838044SWilliam.Kucharski@Sun.COM 			pnp_header_t *pnp_header = NULL;
2848044SWilliam.Kucharski@Sun.COM 
2858044SWilliam.Kucharski@Sun.COM 			DBG ( "found 55AA at %x...", ptr );
2868044SWilliam.Kucharski@Sun.COM 			if ( undi.rom->pcir_off == 0 ) {
2878044SWilliam.Kucharski@Sun.COM 				DBG ( "not a PCI ROM\n..." );
2888044SWilliam.Kucharski@Sun.COM 				continue;
2898044SWilliam.Kucharski@Sun.COM 			}
2908044SWilliam.Kucharski@Sun.COM 			pcir_header = (pcir_header_t*)( ( void * ) undi.rom +
2918044SWilliam.Kucharski@Sun.COM 							undi.rom->pcir_off );
2928044SWilliam.Kucharski@Sun.COM 			if ( pcir_header->signature != PCIR_SIGNATURE ) {
2938044SWilliam.Kucharski@Sun.COM 				DBG ( "invalid PCI signature\n..." );
2948044SWilliam.Kucharski@Sun.COM 				continue;
2958044SWilliam.Kucharski@Sun.COM 			}
2968044SWilliam.Kucharski@Sun.COM 			DBG ( "PCI:%hx:%hx...", pcir_header->vendor_id,
2978044SWilliam.Kucharski@Sun.COM 				 pcir_header->device_id );
2988044SWilliam.Kucharski@Sun.COM 			if ( ( pcir_header->vendor_id != undi.pci.vendor ) ||
2998044SWilliam.Kucharski@Sun.COM 			     ( pcir_header->device_id != undi.pci.dev_id ) ) {
3008044SWilliam.Kucharski@Sun.COM 				DBG ( "not me (%hx:%hx)\n...",
3018044SWilliam.Kucharski@Sun.COM 					 undi.pci.vendor,
3028044SWilliam.Kucharski@Sun.COM 					 undi.pci.dev_id );
3038044SWilliam.Kucharski@Sun.COM 				continue;
3048044SWilliam.Kucharski@Sun.COM 			}
3058044SWilliam.Kucharski@Sun.COM 			if ( undi.rom->pnp_off == 0 ) {
3068044SWilliam.Kucharski@Sun.COM 				DBG ( "not a PnP ROM\n..." );
3078044SWilliam.Kucharski@Sun.COM 				continue;
3088044SWilliam.Kucharski@Sun.COM 			}
3098044SWilliam.Kucharski@Sun.COM 			pnp_header = (pnp_header_t*)( ( void * ) undi.rom +
3108044SWilliam.Kucharski@Sun.COM 							 undi.rom->pnp_off );
3118044SWilliam.Kucharski@Sun.COM 			if ( pnp_header->signature != PNP_SIGNATURE ) {
3128044SWilliam.Kucharski@Sun.COM 				DBG ( "invalid $PnP signature\n..." );
3138044SWilliam.Kucharski@Sun.COM 				continue;
3148044SWilliam.Kucharski@Sun.COM 			}
3158044SWilliam.Kucharski@Sun.COM 			if ( checksum(pnp_header,sizeof(pnp_header_t)) != 0 ) {
3168044SWilliam.Kucharski@Sun.COM 				DBG ( "invalid PnP checksum\n..." );
3178044SWilliam.Kucharski@Sun.COM 				continue;
3188044SWilliam.Kucharski@Sun.COM 			}
3198044SWilliam.Kucharski@Sun.COM 			DBG ( "ok\n");
3208044SWilliam.Kucharski@Sun.COM 			printf ("ROM %s by %s\n",
3218044SWilliam.Kucharski@Sun.COM 				 pnp_header->product_str_off==0 ? "(unknown)" :
3228044SWilliam.Kucharski@Sun.COM 				 (void*)undi.rom+pnp_header->product_str_off,
3238044SWilliam.Kucharski@Sun.COM 				 pnp_header->manuf_str_off==0 ? "(unknown)" :
3248044SWilliam.Kucharski@Sun.COM 				 (void*)undi.rom+pnp_header->manuf_str_off );
3258044SWilliam.Kucharski@Sun.COM 			return 1;
3268044SWilliam.Kucharski@Sun.COM 		}
3278044SWilliam.Kucharski@Sun.COM 	}
3288044SWilliam.Kucharski@Sun.COM 	DBG ( "none found\n" );
3298044SWilliam.Kucharski@Sun.COM 	ptr = 0;
3308044SWilliam.Kucharski@Sun.COM 	undi.rom = NULL;
3318044SWilliam.Kucharski@Sun.COM 	return 0;
3328044SWilliam.Kucharski@Sun.COM }
3338044SWilliam.Kucharski@Sun.COM 
3348044SWilliam.Kucharski@Sun.COM /* Locate ROMs containing UNDI drivers.
3358044SWilliam.Kucharski@Sun.COM  */
3368044SWilliam.Kucharski@Sun.COM 
hunt_undi_rom(void)3378044SWilliam.Kucharski@Sun.COM int hunt_undi_rom ( void ) {
3388044SWilliam.Kucharski@Sun.COM 	while ( hunt_rom() ) {
3398044SWilliam.Kucharski@Sun.COM 		if ( undi.rom->undi_rom_id_off == 0 ) {
3408044SWilliam.Kucharski@Sun.COM 			DBG ( "Not a PXE ROM\n" );
3418044SWilliam.Kucharski@Sun.COM 			continue;
3428044SWilliam.Kucharski@Sun.COM 		}
3438044SWilliam.Kucharski@Sun.COM 		undi.undi_rom_id = (undi_rom_id_t *)
3448044SWilliam.Kucharski@Sun.COM 			( (void *)undi.rom + undi.rom->undi_rom_id_off );
3458044SWilliam.Kucharski@Sun.COM 		if ( undi.undi_rom_id->signature != UNDI_SIGNATURE ) {
3468044SWilliam.Kucharski@Sun.COM 			DBG ( "Invalid UNDI signature\n" );
3478044SWilliam.Kucharski@Sun.COM 			continue;
3488044SWilliam.Kucharski@Sun.COM 		}
3498044SWilliam.Kucharski@Sun.COM 		printf ( "Revision %d.%d.%d",
3508044SWilliam.Kucharski@Sun.COM 			 undi.undi_rom_id->undi_rev[2],
3518044SWilliam.Kucharski@Sun.COM 			 undi.undi_rom_id->undi_rev[1],
3528044SWilliam.Kucharski@Sun.COM 			 undi.undi_rom_id->undi_rev[0] );
3538044SWilliam.Kucharski@Sun.COM 		return 1;
3548044SWilliam.Kucharski@Sun.COM 	}
3558044SWilliam.Kucharski@Sun.COM 	return 0;
3568044SWilliam.Kucharski@Sun.COM }
3578044SWilliam.Kucharski@Sun.COM 
3588044SWilliam.Kucharski@Sun.COM /**************************************************************************
3598044SWilliam.Kucharski@Sun.COM  * Low-level UNDI API call wrappers
3608044SWilliam.Kucharski@Sun.COM  **************************************************************************/
3618044SWilliam.Kucharski@Sun.COM 
3628044SWilliam.Kucharski@Sun.COM /* Make a real-mode UNDI API call to the UNDI routine at
3638044SWilliam.Kucharski@Sun.COM  * routine_seg:routine_off, passing in three uint16 parameters on the
3648044SWilliam.Kucharski@Sun.COM  * real-mode stack.
3658044SWilliam.Kucharski@Sun.COM  * Calls the assembler wrapper routine __undi_call.
3668044SWilliam.Kucharski@Sun.COM  */
3678044SWilliam.Kucharski@Sun.COM 
_undi_call(uint16_t routine_seg,uint16_t routine_off,uint16_t st0,uint16_t st1,uint16_t st2)3688044SWilliam.Kucharski@Sun.COM static inline PXENV_EXIT_t _undi_call ( uint16_t routine_seg,
3698044SWilliam.Kucharski@Sun.COM 					uint16_t routine_off, uint16_t st0,
3708044SWilliam.Kucharski@Sun.COM 					uint16_t st1, uint16_t st2 ) {
3718044SWilliam.Kucharski@Sun.COM 	PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
3728044SWilliam.Kucharski@Sun.COM 
3738044SWilliam.Kucharski@Sun.COM 	undi.undi_call_info->routine.segment = routine_seg;
3748044SWilliam.Kucharski@Sun.COM 	undi.undi_call_info->routine.offset = routine_off;
3758044SWilliam.Kucharski@Sun.COM 	undi.undi_call_info->stack[0] = st0;
3768044SWilliam.Kucharski@Sun.COM 	undi.undi_call_info->stack[1] = st1;
3778044SWilliam.Kucharski@Sun.COM 	undi.undi_call_info->stack[2] = st2;
3788044SWilliam.Kucharski@Sun.COM 	ret = __undi_call ( SEGMENT( undi.undi_call_info ),
3798044SWilliam.Kucharski@Sun.COM 			    OFFSET( undi.undi_call_info ) );
3808044SWilliam.Kucharski@Sun.COM 
3818044SWilliam.Kucharski@Sun.COM 	/* UNDI API calls may rudely change the status of A20 and not
3828044SWilliam.Kucharski@Sun.COM 	 * bother to restore it afterwards.  Intel is known to be
3838044SWilliam.Kucharski@Sun.COM 	 * guilty of this.
3848044SWilliam.Kucharski@Sun.COM 	 *
3858044SWilliam.Kucharski@Sun.COM 	 * Note that we will return to this point even if A20 gets
3868044SWilliam.Kucharski@Sun.COM 	 * screwed up by the UNDI driver, because Etherboot always
3878044SWilliam.Kucharski@Sun.COM 	 * resides in an even megabyte of RAM.
3888044SWilliam.Kucharski@Sun.COM 	 */
3898044SWilliam.Kucharski@Sun.COM 	gateA20_set();
3908044SWilliam.Kucharski@Sun.COM 
3918044SWilliam.Kucharski@Sun.COM 	return ret;
3928044SWilliam.Kucharski@Sun.COM }
3938044SWilliam.Kucharski@Sun.COM 
3948044SWilliam.Kucharski@Sun.COM /* Make a real-mode call to the UNDI loader routine at
3958044SWilliam.Kucharski@Sun.COM  * routine_seg:routine_off, passing in the seg:off address of a
3968044SWilliam.Kucharski@Sun.COM  * pxenv_structure on the real-mode stack.
3978044SWilliam.Kucharski@Sun.COM  */
3988044SWilliam.Kucharski@Sun.COM 
undi_call_loader(void)3998044SWilliam.Kucharski@Sun.COM int undi_call_loader ( void ) {
4008044SWilliam.Kucharski@Sun.COM 	PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE;
4018044SWilliam.Kucharski@Sun.COM 
4028044SWilliam.Kucharski@Sun.COM 	pxenv_exit = _undi_call ( SEGMENT( undi.rom ),
4038044SWilliam.Kucharski@Sun.COM 				  undi.undi_rom_id->undi_loader_off,
4048044SWilliam.Kucharski@Sun.COM 				  OFFSET( undi.pxs ),
4058044SWilliam.Kucharski@Sun.COM 				  SEGMENT( undi.pxs ),
4068044SWilliam.Kucharski@Sun.COM 				  0 /* Unused for UNDI loader API */ );
4078044SWilliam.Kucharski@Sun.COM 	/* Return 1 for success, to be consistent with other routines */
4088044SWilliam.Kucharski@Sun.COM 	if ( pxenv_exit == PXENV_EXIT_SUCCESS ) return 1;
4098044SWilliam.Kucharski@Sun.COM 	DBG ( "UNDI loader call failed with status %#hx\n",
4108044SWilliam.Kucharski@Sun.COM 		 undi.pxs->Status );
4118044SWilliam.Kucharski@Sun.COM 	return 0;
4128044SWilliam.Kucharski@Sun.COM }
4138044SWilliam.Kucharski@Sun.COM 
4148044SWilliam.Kucharski@Sun.COM /* Make a real-mode UNDI API call, passing in the opcode and the
4158044SWilliam.Kucharski@Sun.COM  * seg:off address of a pxenv_structure on the real-mode stack.
4168044SWilliam.Kucharski@Sun.COM  *
4178044SWilliam.Kucharski@Sun.COM  * Two versions: undi_call() will automatically report any failure
4188044SWilliam.Kucharski@Sun.COM  * codes, undi_call_silent() will not.
4198044SWilliam.Kucharski@Sun.COM  */
4208044SWilliam.Kucharski@Sun.COM 
undi_call_silent(uint16_t opcode)4218044SWilliam.Kucharski@Sun.COM int undi_call_silent ( uint16_t opcode ) {
4228044SWilliam.Kucharski@Sun.COM 	PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE;
4238044SWilliam.Kucharski@Sun.COM 
4248044SWilliam.Kucharski@Sun.COM 	pxenv_exit = _undi_call ( undi.pxe->EntryPointSP.segment,
4258044SWilliam.Kucharski@Sun.COM 				  undi.pxe->EntryPointSP.offset,
4268044SWilliam.Kucharski@Sun.COM 				  opcode,
4278044SWilliam.Kucharski@Sun.COM 				  OFFSET( undi.pxs ),
4288044SWilliam.Kucharski@Sun.COM 				  SEGMENT( undi.pxs ) );
4298044SWilliam.Kucharski@Sun.COM 	/* Return 1 for success, to be consistent with other routines */
4308044SWilliam.Kucharski@Sun.COM 	return pxenv_exit == PXENV_EXIT_SUCCESS ? 1 : 0;
4318044SWilliam.Kucharski@Sun.COM }
4328044SWilliam.Kucharski@Sun.COM 
undi_call(uint16_t opcode)4338044SWilliam.Kucharski@Sun.COM int undi_call ( uint16_t opcode ) {
4348044SWilliam.Kucharski@Sun.COM 	if ( undi_call_silent ( opcode ) ) return 1;
4358044SWilliam.Kucharski@Sun.COM 	DBG ( "UNDI API call %#hx failed with status %#hx\n",
4368044SWilliam.Kucharski@Sun.COM 		 opcode, undi.pxs->Status );
4378044SWilliam.Kucharski@Sun.COM 	return 0;
4388044SWilliam.Kucharski@Sun.COM }
4398044SWilliam.Kucharski@Sun.COM 
4408044SWilliam.Kucharski@Sun.COM /**************************************************************************
4418044SWilliam.Kucharski@Sun.COM  * High-level UNDI API call wrappers
4428044SWilliam.Kucharski@Sun.COM  **************************************************************************/
4438044SWilliam.Kucharski@Sun.COM 
4448044SWilliam.Kucharski@Sun.COM /* Install the UNDI driver from a located UNDI ROM.
4458044SWilliam.Kucharski@Sun.COM  */
4468044SWilliam.Kucharski@Sun.COM 
undi_loader(void)4478044SWilliam.Kucharski@Sun.COM int undi_loader ( void ) {
4488044SWilliam.Kucharski@Sun.COM 	pxe_t *pxe = NULL;
4498044SWilliam.Kucharski@Sun.COM 
4508044SWilliam.Kucharski@Sun.COM 	/* AX contains PCI bus:devfn (PCI specification) */
4518044SWilliam.Kucharski@Sun.COM 	undi.pxs->loader.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn;
4528044SWilliam.Kucharski@Sun.COM 	/* BX and DX set to 0xffff for non-ISAPnP devices
4538044SWilliam.Kucharski@Sun.COM 	 * (BIOS boot specification)
4548044SWilliam.Kucharski@Sun.COM 	 */
4558044SWilliam.Kucharski@Sun.COM 	undi.pxs->loader.bx = 0xffff;
4568044SWilliam.Kucharski@Sun.COM 	undi.pxs->loader.dx = 0xffff;
4578044SWilliam.Kucharski@Sun.COM 	/* ES:DI points to PnP BIOS' $PnP structure
4588044SWilliam.Kucharski@Sun.COM 	 * (BIOS boot specification)
4598044SWilliam.Kucharski@Sun.COM 	 */
4608044SWilliam.Kucharski@Sun.COM 	undi.pxs->loader.es = 0xf000;
4618044SWilliam.Kucharski@Sun.COM 	undi.pxs->loader.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000;
4628044SWilliam.Kucharski@Sun.COM 
4638044SWilliam.Kucharski@Sun.COM 	/* Allocate space for UNDI driver's code and data segments */
4648044SWilliam.Kucharski@Sun.COM 	undi.driver_code_size = undi.undi_rom_id->code_size;
4658044SWilliam.Kucharski@Sun.COM 	undi.driver_code = UNDI_HEAP;
4668044SWilliam.Kucharski@Sun.COM 	if ( undi.driver_code == NULL ) {
4678044SWilliam.Kucharski@Sun.COM 		printf ( "Could not allocate %d bytes for UNDI code segment\n",
4688044SWilliam.Kucharski@Sun.COM 			 undi.driver_code_size );
4698044SWilliam.Kucharski@Sun.COM 		return 0;
4708044SWilliam.Kucharski@Sun.COM 	}
4718044SWilliam.Kucharski@Sun.COM 	undi.pxs->loader.undi_cs = SEGMENT( undi.driver_code );
4728044SWilliam.Kucharski@Sun.COM 
4738044SWilliam.Kucharski@Sun.COM 	undi.driver_data_size = undi.undi_rom_id->data_size;
4748044SWilliam.Kucharski@Sun.COM 	undi.driver_data = (void *)((((unsigned long)UNDI_HEAP + undi.undi_rom_id->code_size) | (1024 -1)) + 1);
4758044SWilliam.Kucharski@Sun.COM 	if ( undi.driver_data == NULL ) {
4768044SWilliam.Kucharski@Sun.COM 		printf ( "Could not allocate %d bytes for UNDI code segment\n",
4778044SWilliam.Kucharski@Sun.COM 			 undi.driver_data_size );
4788044SWilliam.Kucharski@Sun.COM 		return 0;
4798044SWilliam.Kucharski@Sun.COM 	}
4808044SWilliam.Kucharski@Sun.COM 	undi.pxs->loader.undi_ds = SEGMENT( undi.driver_data );
4818044SWilliam.Kucharski@Sun.COM 
4828044SWilliam.Kucharski@Sun.COM 	DBG ( "Installing UNDI driver code to %hx:0000, data at %hx:0000\n",
4838044SWilliam.Kucharski@Sun.COM 		undi.pxs->loader.undi_cs, undi.pxs->loader.undi_ds );
4848044SWilliam.Kucharski@Sun.COM 
4858044SWilliam.Kucharski@Sun.COM 	/* Do the API call to install the loader */
4868044SWilliam.Kucharski@Sun.COM 	if ( ! undi_call_loader () ) return 0;
4878044SWilliam.Kucharski@Sun.COM 
4888044SWilliam.Kucharski@Sun.COM 	pxe = VIRTUAL( undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off );
4898044SWilliam.Kucharski@Sun.COM 	DBG ( "UNDI driver created a pixie at %hx:%hx...",
4908044SWilliam.Kucharski@Sun.COM 		 undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off );
4918044SWilliam.Kucharski@Sun.COM 	if ( memcmp ( pxe->Signature, "!PXE", 4 ) != 0 ) {
4928044SWilliam.Kucharski@Sun.COM 		DBG ( "invalid signature\n" );
4938044SWilliam.Kucharski@Sun.COM 		return 0;
4948044SWilliam.Kucharski@Sun.COM 	}
4958044SWilliam.Kucharski@Sun.COM 	if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) {
4968044SWilliam.Kucharski@Sun.COM 		DBG ( "invalid checksum\n" );
4978044SWilliam.Kucharski@Sun.COM 		return 0;
4988044SWilliam.Kucharski@Sun.COM 	}
4998044SWilliam.Kucharski@Sun.COM 	DBG ( "ok\n" );
5008044SWilliam.Kucharski@Sun.COM 	undi.pxe = pxe;
5018044SWilliam.Kucharski@Sun.COM 	pxe_dump();
5028044SWilliam.Kucharski@Sun.COM 	return 1;
5038044SWilliam.Kucharski@Sun.COM }
5048044SWilliam.Kucharski@Sun.COM 
5058044SWilliam.Kucharski@Sun.COM /* Start the UNDI driver.
5068044SWilliam.Kucharski@Sun.COM  */
5078044SWilliam.Kucharski@Sun.COM 
eb_pxenv_start_undi(void)5088044SWilliam.Kucharski@Sun.COM int eb_pxenv_start_undi ( void ) {
5098044SWilliam.Kucharski@Sun.COM 	int success = 0;
5108044SWilliam.Kucharski@Sun.COM 
5118044SWilliam.Kucharski@Sun.COM 	/* AX contains PCI bus:devfn (PCI specification) */
5128044SWilliam.Kucharski@Sun.COM 	undi.pxs->start_undi.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn;
5138044SWilliam.Kucharski@Sun.COM 	/* BX and DX set to 0xffff for non-ISAPnP devices
5148044SWilliam.Kucharski@Sun.COM 	 * (BIOS boot specification)
5158044SWilliam.Kucharski@Sun.COM 	 */
5168044SWilliam.Kucharski@Sun.COM 	undi.pxs->start_undi.bx = 0xffff;
5178044SWilliam.Kucharski@Sun.COM 	undi.pxs->start_undi.dx = 0xffff;
5188044SWilliam.Kucharski@Sun.COM 	/* ES:DI points to PnP BIOS' $PnP structure
5198044SWilliam.Kucharski@Sun.COM 	 * (BIOS boot specification)
5208044SWilliam.Kucharski@Sun.COM 	 */
5218044SWilliam.Kucharski@Sun.COM 	undi.pxs->start_undi.es = 0xf000;
5228044SWilliam.Kucharski@Sun.COM 	undi.pxs->start_undi.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000;
5238044SWilliam.Kucharski@Sun.COM 
5248044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_START_UNDI => AX=%hx BX=%hx DX=%hx ES:DI=%hx:%hx\n",
5258044SWilliam.Kucharski@Sun.COM 	      undi.pxs->start_undi.ax,
5268044SWilliam.Kucharski@Sun.COM 	      undi.pxs->start_undi.bx, undi.pxs->start_undi.dx,
5278044SWilliam.Kucharski@Sun.COM 	      undi.pxs->start_undi.es, undi.pxs->start_undi.di );
5288044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_START_UNDI );
5298044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_START_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) );
5308044SWilliam.Kucharski@Sun.COM 	if ( success ) undi.prestarted = 1;
5318044SWilliam.Kucharski@Sun.COM 	return success;
5328044SWilliam.Kucharski@Sun.COM }
5338044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_startup(void)5348044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_startup ( void )	{
5358044SWilliam.Kucharski@Sun.COM 	int success = 0;
5368044SWilliam.Kucharski@Sun.COM 
5378044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_STARTUP => (void)\n" );
5388044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_STARTUP );
5398044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_STARTUP <= Status=%s\n", UNDI_STATUS(undi.pxs) );
5408044SWilliam.Kucharski@Sun.COM 	if ( success ) undi.started = 1;
5418044SWilliam.Kucharski@Sun.COM 	return success;
5428044SWilliam.Kucharski@Sun.COM }
5438044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_cleanup(void)5448044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_cleanup ( void ) {
5458044SWilliam.Kucharski@Sun.COM 	int success = 0;
5468044SWilliam.Kucharski@Sun.COM 
5478044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_CLEANUP => (void)\n" );
5488044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_CLEANUP );
5498044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_CLEANUP <= Status=%s\n", UNDI_STATUS(undi.pxs) );
5508044SWilliam.Kucharski@Sun.COM 	return success;
5518044SWilliam.Kucharski@Sun.COM }
5528044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_initialize(void)5538044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_initialize ( void ) {
5548044SWilliam.Kucharski@Sun.COM 	int success = 0;
5558044SWilliam.Kucharski@Sun.COM 
5568044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_initialize.ProtocolIni = 0;
5578044SWilliam.Kucharski@Sun.COM 	memset ( &undi.pxs->undi_initialize.reserved, 0,
5588044SWilliam.Kucharski@Sun.COM 		 sizeof ( undi.pxs->undi_initialize.reserved ) );
5598044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_INITIALIZE => ProtocolIni=%x\n" );
5608044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_INITIALIZE );
5618044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_INITIALIZE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
5628044SWilliam.Kucharski@Sun.COM 	if ( success ) undi.initialized = 1;
5638044SWilliam.Kucharski@Sun.COM 	return success;
5648044SWilliam.Kucharski@Sun.COM }
5658044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_shutdown(void)5668044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_shutdown ( void ) {
5678044SWilliam.Kucharski@Sun.COM 	int success = 0;
5688044SWilliam.Kucharski@Sun.COM 
5698044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_SHUTDOWN => (void)\n" );
5708044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_SHUTDOWN );
5718044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_SHUTDOWN <= Status=%s\n", UNDI_STATUS(undi.pxs) );
5728044SWilliam.Kucharski@Sun.COM 	if ( success ) {
5738044SWilliam.Kucharski@Sun.COM 		undi.initialized = 0;
5748044SWilliam.Kucharski@Sun.COM 		undi.started = 0;
5758044SWilliam.Kucharski@Sun.COM 	}
5768044SWilliam.Kucharski@Sun.COM 	return success;
5778044SWilliam.Kucharski@Sun.COM }
5788044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_open(void)5798044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_open ( void ) {
5808044SWilliam.Kucharski@Sun.COM 	int success = 0;
5818044SWilliam.Kucharski@Sun.COM 
5828044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_open.OpenFlag = 0;
5838044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST;
5848044SWilliam.Kucharski@Sun.COM 
5858044SWilliam.Kucharski@Sun.COM 	/* Multicast support not yet implemented */
5868044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount = 0;
5878044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_OPEN => OpenFlag=%hx PktFilter=%hx "
5888044SWilliam.Kucharski@Sun.COM 	      "MCastAddrCount=%hx\n",
5898044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_open.OpenFlag, undi.pxs->undi_open.PktFilter,
5908044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount );
5918044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_OPEN );
5928044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs) );
5938044SWilliam.Kucharski@Sun.COM 	if ( success ) undi.opened = 1;
5948044SWilliam.Kucharski@Sun.COM 	return success;
5958044SWilliam.Kucharski@Sun.COM }
5968044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_close(void)5978044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_close ( void ) {
5988044SWilliam.Kucharski@Sun.COM 	int success = 0;
5998044SWilliam.Kucharski@Sun.COM 
6008044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_CLOSE => (void)\n" );
6018044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_CLOSE );
6028044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
6038044SWilliam.Kucharski@Sun.COM 	if ( success ) undi.opened = 0;
6048044SWilliam.Kucharski@Sun.COM 	return success;
6058044SWilliam.Kucharski@Sun.COM }
6068044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_transmit_packet(void)6078044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_transmit_packet ( void ) {
6088044SWilliam.Kucharski@Sun.COM 	int success = 0;
6098044SWilliam.Kucharski@Sun.COM 	static const uint8_t broadcast[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
6108044SWilliam.Kucharski@Sun.COM 
6118044SWilliam.Kucharski@Sun.COM 	/* XMitFlag selects unicast / broadcast */
6128044SWilliam.Kucharski@Sun.COM 	if ( memcmp ( undi.xmit_data->destaddr, broadcast,
6138044SWilliam.Kucharski@Sun.COM 		      sizeof(broadcast) ) == 0 ) {
6148044SWilliam.Kucharski@Sun.COM 		undi.pxs->undi_transmit.XmitFlag = XMT_BROADCAST;
6158044SWilliam.Kucharski@Sun.COM 	} else {
6168044SWilliam.Kucharski@Sun.COM 		undi.pxs->undi_transmit.XmitFlag = XMT_DESTADDR;
6178044SWilliam.Kucharski@Sun.COM 	}
6188044SWilliam.Kucharski@Sun.COM 
6198044SWilliam.Kucharski@Sun.COM 	/* Zero reserved dwords */
6208044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_transmit.Reserved[0] = 0;
6218044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_transmit.Reserved[1] = 0;
6228044SWilliam.Kucharski@Sun.COM 
6238044SWilliam.Kucharski@Sun.COM 	/* Segment:offset pointer to DestAddr in base memory */
6248044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_transmit.DestAddr.segment =
6258044SWilliam.Kucharski@Sun.COM 		SEGMENT( undi.xmit_data->destaddr );
6268044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_transmit.DestAddr.offset =
6278044SWilliam.Kucharski@Sun.COM 		OFFSET( undi.xmit_data->destaddr );
6288044SWilliam.Kucharski@Sun.COM 
6298044SWilliam.Kucharski@Sun.COM 	/* Segment:offset pointer to TBD in base memory */
6308044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_transmit.TBD.segment = SEGMENT( &undi.xmit_data->tbd );
6318044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_transmit.TBD.offset = OFFSET( &undi.xmit_data->tbd );
6328044SWilliam.Kucharski@Sun.COM 
6338044SWilliam.Kucharski@Sun.COM 	/* Use only the "immediate" part of the TBD */
6348044SWilliam.Kucharski@Sun.COM 	undi.xmit_data->tbd.DataBlkCount = 0;
6358044SWilliam.Kucharski@Sun.COM 
6368044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_TRANSMIT_PACKET => Protocol=%hx XmitFlag=%hx ...\n"
6378044SWilliam.Kucharski@Sun.COM 	      "... DestAddr=%hx:%hx TBD=%hx:%hx ...\n",
6388044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_transmit.Protocol,
6398044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_transmit.XmitFlag,
6408044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_transmit.DestAddr.segment,
6418044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_transmit.DestAddr.offset,
6428044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_transmit.TBD.segment,
6438044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_transmit.TBD.offset );
6448044SWilliam.Kucharski@Sun.COM 	DBG ( "... TBD { ImmedLength=%hx Xmit=%hx:%hx DataBlkCount=%hx }\n",
6458044SWilliam.Kucharski@Sun.COM 	      undi.xmit_data->tbd.ImmedLength,
6468044SWilliam.Kucharski@Sun.COM 	      undi.xmit_data->tbd.Xmit.segment,
6478044SWilliam.Kucharski@Sun.COM 	      undi.xmit_data->tbd.Xmit.offset,
6488044SWilliam.Kucharski@Sun.COM 	      undi.xmit_data->tbd.DataBlkCount );
6498044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_TRANSMIT );
6508044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_TRANSMIT_PACKET <= Status=%s\n",
6518044SWilliam.Kucharski@Sun.COM 	      UNDI_STATUS(undi.pxs) );
6528044SWilliam.Kucharski@Sun.COM 	return success;
6538044SWilliam.Kucharski@Sun.COM }
6548044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_set_station_address(void)6558044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_set_station_address ( void ) {
6568044SWilliam.Kucharski@Sun.COM 	/* This will spuriously fail on some cards.  Ignore failures.
6578044SWilliam.Kucharski@Sun.COM 	 * We only ever use it to set the MAC address to the card's
6588044SWilliam.Kucharski@Sun.COM 	 * permanent value anyway, so it's a useless call (although we
6598044SWilliam.Kucharski@Sun.COM 	 * make it because PXE spec says we should).
6608044SWilliam.Kucharski@Sun.COM 	 */
6618044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_SET_STATION_ADDRESS => "
6628044SWilliam.Kucharski@Sun.COM 	      "StationAddress=%!\n",
6638044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_set_station_address.StationAddress );
6648044SWilliam.Kucharski@Sun.COM 	undi_call_silent ( PXENV_UNDI_SET_STATION_ADDRESS );
6658044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_SET_STATION_ADDRESS <= Status=%s\n",
6668044SWilliam.Kucharski@Sun.COM 	      UNDI_STATUS(undi.pxs) );
6678044SWilliam.Kucharski@Sun.COM 	return 1;
6688044SWilliam.Kucharski@Sun.COM }
6698044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_get_information(void)6708044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_get_information ( void ) {
6718044SWilliam.Kucharski@Sun.COM 	int success = 0;
6728044SWilliam.Kucharski@Sun.COM 	memset ( undi.pxs, 0, sizeof ( undi.pxs ) );
6738044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_GET_INFORMATION => (void)\n" );
6748044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_GET_INFORMATION );
6758044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_GET_INFORMATION <= Status=%s "
6768044SWilliam.Kucharski@Sun.COM 	      "BaseIO=%hx IntNumber=%hx ...\n"
6778044SWilliam.Kucharski@Sun.COM 	      "... MaxTranUnit=%hx HwType=%hx HwAddrlen=%hx ...\n"
6788044SWilliam.Kucharski@Sun.COM 	      "... CurrentNodeAddress=%! PermNodeAddress=%! ...\n"
6798044SWilliam.Kucharski@Sun.COM 	      "... ROMAddress=%hx RxBufCt=%hx TxBufCt=%hx\n",
6808044SWilliam.Kucharski@Sun.COM 	      UNDI_STATUS(undi.pxs),
6818044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.BaseIo,
6828044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.IntNumber,
6838044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.MaxTranUnit,
6848044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.HwType,
6858044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.HwAddrLen,
6868044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.CurrentNodeAddress,
6878044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.PermNodeAddress,
6888044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.ROMAddress,
6898044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.RxBufCt,
6908044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_information.TxBufCt );
6918044SWilliam.Kucharski@Sun.COM 	return success;
6928044SWilliam.Kucharski@Sun.COM }
6938044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_get_iface_info(void)6948044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_get_iface_info ( void ) {
6958044SWilliam.Kucharski@Sun.COM 	int success = 0;
6968044SWilliam.Kucharski@Sun.COM 
6978044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_GET_IFACE_INFO => (void)\n" );
6988044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_GET_IFACE_INFO );
6998044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_GET_IFACE_INFO <= Status=%s IfaceType=%s ...\n"
7008044SWilliam.Kucharski@Sun.COM 	      "... LinkSpeed=%x ServiceFlags=%x\n",
7018044SWilliam.Kucharski@Sun.COM 	      UNDI_STATUS(undi.pxs),
7028044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_iface_info.IfaceType,
7038044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_iface_info.LinkSpeed,
7048044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_get_iface_info.ServiceFlags );
7058044SWilliam.Kucharski@Sun.COM 	return success;
7068044SWilliam.Kucharski@Sun.COM }
7078044SWilliam.Kucharski@Sun.COM 
eb_pxenv_undi_isr(void)7088044SWilliam.Kucharski@Sun.COM int eb_pxenv_undi_isr ( void ) {
7098044SWilliam.Kucharski@Sun.COM 	int success = 0;
7108044SWilliam.Kucharski@Sun.COM 
7118044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_ISR => FuncFlag=%hx\n",
7128044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_isr.FuncFlag );
7138044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_UNDI_ISR );
7148044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNDI_ISR <= Status=%s FuncFlag=%hx BufferLength=%hx ...\n"
7158044SWilliam.Kucharski@Sun.COM 	      "... FrameLength=%hx FrameHeaderLength=%hx Frame=%hx:%hx "
7168044SWilliam.Kucharski@Sun.COM 	      "ProtType=%hhx ...\n... PktType=%hhx\n",
7178044SWilliam.Kucharski@Sun.COM 	      UNDI_STATUS(undi.pxs), undi.pxs->undi_isr.FuncFlag,
7188044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_isr.BufferLength,
7198044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_isr.FrameLength,
7208044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_isr.FrameHeaderLength,
7218044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_isr.Frame.segment,
7228044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_isr.Frame.offset,
7238044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_isr.ProtType,
7248044SWilliam.Kucharski@Sun.COM 	      undi.pxs->undi_isr.PktType );
7258044SWilliam.Kucharski@Sun.COM 	return success;
7268044SWilliam.Kucharski@Sun.COM }
7278044SWilliam.Kucharski@Sun.COM 
eb_pxenv_stop_undi(void)7288044SWilliam.Kucharski@Sun.COM int eb_pxenv_stop_undi ( void ) {
7298044SWilliam.Kucharski@Sun.COM 	int success = 0;
7308044SWilliam.Kucharski@Sun.COM 
7318044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_STOP_UNDI => (void)\n" );
7328044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_STOP_UNDI );
7338044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_STOP_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) );
7348044SWilliam.Kucharski@Sun.COM 	if ( success ) undi.prestarted = 0;
7358044SWilliam.Kucharski@Sun.COM 	return success;
7368044SWilliam.Kucharski@Sun.COM }
7378044SWilliam.Kucharski@Sun.COM 
eb_pxenv_unload_stack(void)7388044SWilliam.Kucharski@Sun.COM int eb_pxenv_unload_stack ( void ) {
7398044SWilliam.Kucharski@Sun.COM 	int success = 0;
7408044SWilliam.Kucharski@Sun.COM 
7418044SWilliam.Kucharski@Sun.COM 	memset ( undi.pxs, 0, sizeof ( undi.pxs ) );
7428044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNLOAD_STACK => (void)\n" );
7438044SWilliam.Kucharski@Sun.COM 	success = undi_call_silent ( PXENV_UNLOAD_STACK );
7448044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_UNLOAD_STACK <= Status=%s ...\n... (%s)\n",
7458044SWilliam.Kucharski@Sun.COM 	      UNDI_STATUS(undi.pxs),
7468044SWilliam.Kucharski@Sun.COM 	      ( undi.pxs->Status == PXENV_STATUS_SUCCESS ?
7478044SWilliam.Kucharski@Sun.COM 		"base-code is ready to be removed" :
7488044SWilliam.Kucharski@Sun.COM 		( undi.pxs->Status == PXENV_STATUS_FAILURE ?
7498044SWilliam.Kucharski@Sun.COM 		  "the size of free base memory has been changed" :
7508044SWilliam.Kucharski@Sun.COM 		  ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ?
7518044SWilliam.Kucharski@Sun.COM 		    "the NIC interrupt vector has been changed" :
7528044SWilliam.Kucharski@Sun.COM 		    "UNEXPECTED STATUS CODE" ) ) ) );
7538044SWilliam.Kucharski@Sun.COM 	return success;
7548044SWilliam.Kucharski@Sun.COM }
7558044SWilliam.Kucharski@Sun.COM 
eb_pxenv_stop_base(void)7568044SWilliam.Kucharski@Sun.COM int eb_pxenv_stop_base ( void ) {
7578044SWilliam.Kucharski@Sun.COM 	int success = 0;
7588044SWilliam.Kucharski@Sun.COM 
7598044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_STOP_BASE => (void)\n" );
7608044SWilliam.Kucharski@Sun.COM 	success = undi_call ( PXENV_STOP_BASE );
7618044SWilliam.Kucharski@Sun.COM 	DBG ( "PXENV_STOP_BASE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
7628044SWilliam.Kucharski@Sun.COM 	return success;
7638044SWilliam.Kucharski@Sun.COM }
7648044SWilliam.Kucharski@Sun.COM 
7658044SWilliam.Kucharski@Sun.COM /* Unload UNDI base code (if any present) and free memory.
7668044SWilliam.Kucharski@Sun.COM  */
undi_unload_base_code(void)7678044SWilliam.Kucharski@Sun.COM int undi_unload_base_code ( void ) {
7688044SWilliam.Kucharski@Sun.COM 	/* In GRUB, we do not allocate anything, but we still can call
7698044SWilliam.Kucharski@Sun.COM 	 * to free the base space */
7708044SWilliam.Kucharski@Sun.COM 	void *bc_code = VIRTUAL( undi.pxe->BC_Code.Seg_Addr, 0 );
7718044SWilliam.Kucharski@Sun.COM 	size_t bc_code_size = undi.pxe->BC_Code.Seg_Size;
7728044SWilliam.Kucharski@Sun.COM 	void *bc_data = VIRTUAL( undi.pxe->BC_Data.Seg_Addr, 0 );
7738044SWilliam.Kucharski@Sun.COM 	size_t bc_data_size = undi.pxe->BC_Data.Seg_Size;
7748044SWilliam.Kucharski@Sun.COM 	void *bc_stck = VIRTUAL( undi.pxe->Stack.Seg_Addr, 0 );
7758044SWilliam.Kucharski@Sun.COM 	size_t bc_stck_size = undi.pxe->Stack.Seg_Size;
7768044SWilliam.Kucharski@Sun.COM 	firing_squad_lineup_t lineup;
7778044SWilliam.Kucharski@Sun.COM 
7788044SWilliam.Kucharski@Sun.COM 	/* Don't unload if there is no base code present */
7798044SWilliam.Kucharski@Sun.COM 	if ( undi.pxe->BC_Code.Seg_Addr == 0 ) return 1;
7808044SWilliam.Kucharski@Sun.COM 
7818044SWilliam.Kucharski@Sun.COM 	/* Since we never start the base code, the only time we should
7828044SWilliam.Kucharski@Sun.COM 	 * reach this is if we were loaded via PXE.  There are many
7838044SWilliam.Kucharski@Sun.COM 	 * different and conflicting versions of the "correct" way to
7848044SWilliam.Kucharski@Sun.COM 	 * unload the PXE base code, several of which appear within
7858044SWilliam.Kucharski@Sun.COM 	 * the PXE specification itself.  This one seems to work for
7868044SWilliam.Kucharski@Sun.COM 	 * our purposes.
7878044SWilliam.Kucharski@Sun.COM 	 */
7888044SWilliam.Kucharski@Sun.COM 	eb_pxenv_stop_base();
7898044SWilliam.Kucharski@Sun.COM 	//eb_pxenv_unload_stack();
7908044SWilliam.Kucharski@Sun.COM /*	if ( ( undi.pxs->unload_stack.Status != PXENV_STATUS_SUCCESS ) &&
7918044SWilliam.Kucharski@Sun.COM 	     ( undi.pxs->unload_stack.Status != PXENV_STATUS_FAILURE ) ) {
7928044SWilliam.Kucharski@Sun.COM 		printf ( "Could not free memory allocated to PXE base code: "
7938044SWilliam.Kucharski@Sun.COM 			 "possible memory leak\n" );
7948044SWilliam.Kucharski@Sun.COM 		return 0;
7958044SWilliam.Kucharski@Sun.COM 		}*/
7968044SWilliam.Kucharski@Sun.COM 	/* Free data structures.  Forget what the PXE specification
7978044SWilliam.Kucharski@Sun.COM 	 * says about how to calculate the new size of base memory;
7988044SWilliam.Kucharski@Sun.COM 	 * basemem.c takes care of all that for us.  Note that we also
7998044SWilliam.Kucharski@Sun.COM 	 * have to free the stack (even though PXE spec doesn't say
8008044SWilliam.Kucharski@Sun.COM 	 * anything about it) because nothing else is going to do so.
8018044SWilliam.Kucharski@Sun.COM 	 *
8028044SWilliam.Kucharski@Sun.COM 	 * Structures will almost certainly not be kB-aligned and
8038044SWilliam.Kucharski@Sun.COM 	 * there's a reasonable chance that the UNDI code or data
8048044SWilliam.Kucharski@Sun.COM 	 * portions will lie in the same kB as the base code.  Since
8058044SWilliam.Kucharski@Sun.COM 	 * forget_base_memory works only in 1kB increments, this means
8068044SWilliam.Kucharski@Sun.COM 	 * we have to do some arcane trickery.
8078044SWilliam.Kucharski@Sun.COM 	 */
8088044SWilliam.Kucharski@Sun.COM 	memset ( &lineup, 0, sizeof(lineup) );
8098044SWilliam.Kucharski@Sun.COM 	if ( SEGMENT(bc_code) != 0 )
8108044SWilliam.Kucharski@Sun.COM 		assemble_firing_squad( &lineup, bc_code, bc_code_size, SHOOT );
8118044SWilliam.Kucharski@Sun.COM 	if ( SEGMENT(bc_data) != 0 )
8128044SWilliam.Kucharski@Sun.COM 		assemble_firing_squad( &lineup, bc_data, bc_data_size, SHOOT );
8138044SWilliam.Kucharski@Sun.COM 	if ( SEGMENT(bc_stck) != 0 )
8148044SWilliam.Kucharski@Sun.COM 		assemble_firing_squad( &lineup, bc_stck, bc_stck_size, SHOOT );
8158044SWilliam.Kucharski@Sun.COM 	/* Don't shoot any bits of the UNDI driver code or data */
8168044SWilliam.Kucharski@Sun.COM 	assemble_firing_squad ( &lineup,
8178044SWilliam.Kucharski@Sun.COM 				VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 0),
8188044SWilliam.Kucharski@Sun.COM 				undi.pxe->UNDICode.Seg_Size, DONTSHOOT );
8198044SWilliam.Kucharski@Sun.COM 	assemble_firing_squad ( &lineup,
8208044SWilliam.Kucharski@Sun.COM 				VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 0),
8218044SWilliam.Kucharski@Sun.COM 				undi.pxe->UNDIData.Seg_Size, DONTSHOOT );
8228044SWilliam.Kucharski@Sun.COM 	//shoot_targets ( &lineup );
8238044SWilliam.Kucharski@Sun.COM 	//undi.pxe->BC_Code.Seg_Addr = 0;
8248044SWilliam.Kucharski@Sun.COM 	//undi.pxe->BC_Data.Seg_Addr = 0;
8258044SWilliam.Kucharski@Sun.COM 	//undi.pxe->Stack.Seg_Addr = 0;
8268044SWilliam.Kucharski@Sun.COM 
8278044SWilliam.Kucharski@Sun.COM 	/* Free and reallocate our own base memory data structures, to
8288044SWilliam.Kucharski@Sun.COM 	 * allow the freed base-code blocks to be fully released.
8298044SWilliam.Kucharski@Sun.COM 	 */
8308044SWilliam.Kucharski@Sun.COM 	free_base_mem_data();
8318044SWilliam.Kucharski@Sun.COM 	if ( ! allocate_base_mem_data() ) {
8328044SWilliam.Kucharski@Sun.COM 		printf ( "FATAL: memory unaccountably lost\n" );
8338044SWilliam.Kucharski@Sun.COM 		while ( 1 ) {};
8348044SWilliam.Kucharski@Sun.COM 	}
8358044SWilliam.Kucharski@Sun.COM 
8368044SWilliam.Kucharski@Sun.COM 	return 1;
8378044SWilliam.Kucharski@Sun.COM }
8388044SWilliam.Kucharski@Sun.COM 
8398044SWilliam.Kucharski@Sun.COM /* UNDI full initialization
8408044SWilliam.Kucharski@Sun.COM  *
8418044SWilliam.Kucharski@Sun.COM  * This calls all the various UNDI initialization routines in sequence.
8428044SWilliam.Kucharski@Sun.COM  */
8438044SWilliam.Kucharski@Sun.COM 
undi_full_startup(void)8448044SWilliam.Kucharski@Sun.COM int undi_full_startup ( void ) {
8458044SWilliam.Kucharski@Sun.COM 	if ( ! eb_pxenv_start_undi() ) return 0;
8468044SWilliam.Kucharski@Sun.COM 	if ( ! eb_pxenv_undi_startup() ) return 0;
8478044SWilliam.Kucharski@Sun.COM 	if ( ! eb_pxenv_undi_initialize() ) return 0;
8488044SWilliam.Kucharski@Sun.COM 	if ( ! eb_pxenv_undi_get_information() ) return 0;
8498044SWilliam.Kucharski@Sun.COM 	undi.irq = undi.pxs->undi_get_information.IntNumber;
8508044SWilliam.Kucharski@Sun.COM 	if ( ! install_undi_irq_handler ( undi.irq, undi.pxe->EntryPointSP ) ) {
8518044SWilliam.Kucharski@Sun.COM 		undi.irq = IRQ_NONE;
8528044SWilliam.Kucharski@Sun.COM 		return 0;
8538044SWilliam.Kucharski@Sun.COM 	}
8548044SWilliam.Kucharski@Sun.COM 	memmove ( &undi.pxs->undi_set_station_address.StationAddress,
8558044SWilliam.Kucharski@Sun.COM 		  &undi.pxs->undi_get_information.PermNodeAddress,
8568044SWilliam.Kucharski@Sun.COM 		  sizeof (undi.pxs->undi_set_station_address.StationAddress) );
8578044SWilliam.Kucharski@Sun.COM 	if ( ! eb_pxenv_undi_set_station_address() ) return 0;
8588044SWilliam.Kucharski@Sun.COM 	if ( ! eb_pxenv_undi_open() ) return 0;
8598044SWilliam.Kucharski@Sun.COM 	/* install_undi_irq_handler leaves irq disabled */
8608044SWilliam.Kucharski@Sun.COM 	enable_irq ( undi.irq );
8618044SWilliam.Kucharski@Sun.COM 	return 1;
8628044SWilliam.Kucharski@Sun.COM }
8638044SWilliam.Kucharski@Sun.COM 
8648044SWilliam.Kucharski@Sun.COM /* UNDI full shutdown
8658044SWilliam.Kucharski@Sun.COM  *
8668044SWilliam.Kucharski@Sun.COM  * This calls all the various UNDI shutdown routines in sequence and
8678044SWilliam.Kucharski@Sun.COM  * also frees any memory that it can.
8688044SWilliam.Kucharski@Sun.COM  */
8698044SWilliam.Kucharski@Sun.COM 
undi_full_shutdown(void)8708044SWilliam.Kucharski@Sun.COM int undi_full_shutdown ( void ) {
8718044SWilliam.Kucharski@Sun.COM 	if ( undi.pxe != NULL ) {
8728044SWilliam.Kucharski@Sun.COM 		/* In case we didn't allocate the driver's memory in the first
8738044SWilliam.Kucharski@Sun.COM 		 * place, try to grab the code and data segments and sizes
8748044SWilliam.Kucharski@Sun.COM 		 * from the !PXE structure.
8758044SWilliam.Kucharski@Sun.COM 		 */
8768044SWilliam.Kucharski@Sun.COM 		if ( undi.driver_code == NULL ) {
8778044SWilliam.Kucharski@Sun.COM 			undi.driver_code = VIRTUAL(undi.pxe->UNDICode.Seg_Addr,
8788044SWilliam.Kucharski@Sun.COM 						   0 );
8798044SWilliam.Kucharski@Sun.COM 			undi.driver_code_size = undi.pxe->UNDICode.Seg_Size;
8808044SWilliam.Kucharski@Sun.COM 		}
8818044SWilliam.Kucharski@Sun.COM 		if ( undi.driver_data == NULL ) {
8828044SWilliam.Kucharski@Sun.COM 			undi.driver_data = VIRTUAL(undi.pxe->UNDIData.Seg_Addr,
8838044SWilliam.Kucharski@Sun.COM 						   0 );
8848044SWilliam.Kucharski@Sun.COM 			undi.driver_data_size = undi.pxe->UNDIData.Seg_Size;
8858044SWilliam.Kucharski@Sun.COM 		}
8868044SWilliam.Kucharski@Sun.COM 
8878044SWilliam.Kucharski@Sun.COM 		/* Ignore errors and continue in the hope of shutting
8888044SWilliam.Kucharski@Sun.COM 		 * down anyway
8898044SWilliam.Kucharski@Sun.COM 		 */
8908044SWilliam.Kucharski@Sun.COM 		if ( undi.opened ) eb_pxenv_undi_close();
8918044SWilliam.Kucharski@Sun.COM 		if ( undi.started ) {
8928044SWilliam.Kucharski@Sun.COM 			eb_pxenv_undi_cleanup();
8938044SWilliam.Kucharski@Sun.COM 			/* We may get spurious UNDI API errors at this
8948044SWilliam.Kucharski@Sun.COM 			 * point.  If startup() succeeded but
8958044SWilliam.Kucharski@Sun.COM 			 * initialize() failed then according to the
8968044SWilliam.Kucharski@Sun.COM 			 * spec, we should call shutdown().  However,
8978044SWilliam.Kucharski@Sun.COM 			 * some NICS will fail with a status code
8988044SWilliam.Kucharski@Sun.COM 			 * 0x006a (INVALID_STATE).
8998044SWilliam.Kucharski@Sun.COM 			 */
9008044SWilliam.Kucharski@Sun.COM 			eb_pxenv_undi_shutdown();
9018044SWilliam.Kucharski@Sun.COM 		}
9028044SWilliam.Kucharski@Sun.COM 		if ( undi.irq != IRQ_NONE ) {
9038044SWilliam.Kucharski@Sun.COM 			remove_undi_irq_handler ( undi.irq );
9048044SWilliam.Kucharski@Sun.COM 			undi.irq = IRQ_NONE;
9058044SWilliam.Kucharski@Sun.COM 		}
9068044SWilliam.Kucharski@Sun.COM 		undi_unload_base_code();
9078044SWilliam.Kucharski@Sun.COM 		if ( undi.prestarted ) {
9088044SWilliam.Kucharski@Sun.COM 			eb_pxenv_stop_undi();
9098044SWilliam.Kucharski@Sun.COM 			/* Success OR Failure indicates that memory
9108044SWilliam.Kucharski@Sun.COM 			 * can be freed.  Any other status code means
9118044SWilliam.Kucharski@Sun.COM 			 * that it can't.
9128044SWilliam.Kucharski@Sun.COM 			 */
9138044SWilliam.Kucharski@Sun.COM 			if (( undi.pxs->Status == PXENV_STATUS_KEEP_UNDI ) ||
9148044SWilliam.Kucharski@Sun.COM 			    ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ) ) {
9158044SWilliam.Kucharski@Sun.COM 				printf ("Could not free memory allocated to "
9168044SWilliam.Kucharski@Sun.COM 					"UNDI driver: possible memory leak\n");
9178044SWilliam.Kucharski@Sun.COM 				return 0;
9188044SWilliam.Kucharski@Sun.COM 			}
9198044SWilliam.Kucharski@Sun.COM 		}
9208044SWilliam.Kucharski@Sun.COM 	}
9218044SWilliam.Kucharski@Sun.COM 	/* Free memory allocated to UNDI driver */
9228044SWilliam.Kucharski@Sun.COM 	if ( undi.driver_code != NULL ) {
9238044SWilliam.Kucharski@Sun.COM 		/* Clear contents in order to eliminate !PXE and PXENV
9248044SWilliam.Kucharski@Sun.COM 		 * signatures to prevent spurious detection via base
9258044SWilliam.Kucharski@Sun.COM 		 * memory scan.
9268044SWilliam.Kucharski@Sun.COM 		 */
9278044SWilliam.Kucharski@Sun.COM 		memset ( undi.driver_code, 0, undi.driver_code_size );
9288044SWilliam.Kucharski@Sun.COM 		/* forget_base_memory ( undi.driver_code, undi.driver_code_size ); */
9298044SWilliam.Kucharski@Sun.COM 		undi.driver_code = NULL;
9308044SWilliam.Kucharski@Sun.COM 		undi.driver_code_size = 0;
9318044SWilliam.Kucharski@Sun.COM 	}
9328044SWilliam.Kucharski@Sun.COM 	if ( undi.driver_data != NULL ) {
9338044SWilliam.Kucharski@Sun.COM 		/* forget_base_memory ( undi.driver_data, undi.driver_data_size ); */
9348044SWilliam.Kucharski@Sun.COM 		undi.driver_data = NULL;
9358044SWilliam.Kucharski@Sun.COM 		undi.driver_data_size = 0;
9368044SWilliam.Kucharski@Sun.COM 	}
9378044SWilliam.Kucharski@Sun.COM 	/* !PXE structure now gone; memory freed */
9388044SWilliam.Kucharski@Sun.COM 	undi.pxe = NULL;
9398044SWilliam.Kucharski@Sun.COM 	return 1;
9408044SWilliam.Kucharski@Sun.COM }
9418044SWilliam.Kucharski@Sun.COM 
9428044SWilliam.Kucharski@Sun.COM /**************************************************************************
9438044SWilliam.Kucharski@Sun.COM POLL - Wait for a frame
9448044SWilliam.Kucharski@Sun.COM ***************************************************************************/
undi_poll(struct nic * nic,int retrieve)9458044SWilliam.Kucharski@Sun.COM static int undi_poll(struct nic *nic, int retrieve)
9468044SWilliam.Kucharski@Sun.COM {
9478044SWilliam.Kucharski@Sun.COM 	/* Fun, fun, fun.  UNDI drivers don't use polling; they use
9488044SWilliam.Kucharski@Sun.COM 	 * interrupts.  We therefore cheat and pretend that an
9498044SWilliam.Kucharski@Sun.COM 	 * interrupt has occurred every time undi_poll() is called.
9508044SWilliam.Kucharski@Sun.COM 	 * This isn't too much of a hack; PCI devices share IRQs and
9518044SWilliam.Kucharski@Sun.COM 	 * so the first thing that a proper ISR should do is call
9528044SWilliam.Kucharski@Sun.COM 	 * PXENV_UNDI_ISR to determine whether or not the UNDI NIC
9538044SWilliam.Kucharski@Sun.COM 	 * generated the interrupt; there is no harm done by spurious
9548044SWilliam.Kucharski@Sun.COM 	 * calls to PXENV_UNDI_ISR.  Similarly, we wouldn't be
9558044SWilliam.Kucharski@Sun.COM 	 * handling them any more rapidly than the usual rate of
9568044SWilliam.Kucharski@Sun.COM 	 * undi_poll() being called even if we did implement a full
9578044SWilliam.Kucharski@Sun.COM 	 * ISR.  So it should work.  Ha!
9588044SWilliam.Kucharski@Sun.COM 	 *
9598044SWilliam.Kucharski@Sun.COM 	 * Addendum (21/10/03).  Some cards don't play nicely with
9608044SWilliam.Kucharski@Sun.COM 	 * this trick, so instead of doing it the easy way we have to
9618044SWilliam.Kucharski@Sun.COM 	 * go to all the hassle of installing a genuine interrupt
9628044SWilliam.Kucharski@Sun.COM 	 * service routine and dealing with the wonderful 8259
9638044SWilliam.Kucharski@Sun.COM 	 * Programmable Interrupt Controller.  Joy.
9648044SWilliam.Kucharski@Sun.COM 	 *
9658044SWilliam.Kucharski@Sun.COM 	 * (02/01/2005). A real UNDI ISR is now implemented in,
9668044SWilliam.Kucharski@Sun.COM 	 * following Figure 3-4 in PXE spec 2.0.  The interrupt
9678044SWilliam.Kucharski@Sun.COM 	 * handler, undi_irq_handler, issues PXENV_UNDI_ISR_IN_START.
9688044SWilliam.Kucharski@Sun.COM 	 * If the interrupt is ours, the handler sends EOI and bumps the
9698044SWilliam.Kucharski@Sun.COM 	 * undi_irq_trigger_count. This polled routine is equivalent
9708044SWilliam.Kucharski@Sun.COM 	 * to the "driver strategy routine".
9718044SWilliam.Kucharski@Sun.COM 	 *
9728044SWilliam.Kucharski@Sun.COM 	 * Another issue is that upper layer await_*() does not handle
9738044SWilliam.Kucharski@Sun.COM 	 * coalesced packets. The UNDI implementation on broadcom chips
9748044SWilliam.Kucharski@Sun.COM 	 * appear to combine interrupts. If we loop through GET_NEXT,
9758044SWilliam.Kucharski@Sun.COM 	 * we may hand up coalesced packets, resulting in drops, and
9768044SWilliam.Kucharski@Sun.COM 	 * severe time delay. As a temperary hack, we return as soon as
9778044SWilliam.Kucharski@Sun.COM 	 * we get something, remembering where we were (IN_PROCESS
9788044SWilliam.Kucharski@Sun.COM 	 * or GET_NEXT). This assume packets are never broken up.
9798044SWilliam.Kucharski@Sun.COM 	 * XXX Need to fix upper layer to handle coalesced data.
9808044SWilliam.Kucharski@Sun.COM 	 */
9818044SWilliam.Kucharski@Sun.COM 
9828044SWilliam.Kucharski@Sun.COM 	static int undi_opcode = PXENV_UNDI_ISR_IN_PROCESS;
9838044SWilliam.Kucharski@Sun.COM 
9848044SWilliam.Kucharski@Sun.COM 	/* See if a hardware interrupt has occurred since the last poll().
9858044SWilliam.Kucharski@Sun.COM 	 */
9868044SWilliam.Kucharski@Sun.COM 	switch ( undi_opcode ) {
9878044SWilliam.Kucharski@Sun.COM 	case PXENV_UNDI_ISR_IN_PROCESS:
9888044SWilliam.Kucharski@Sun.COM 		if ( ! undi_irq_triggered ( undi.irq ) )
9898044SWilliam.Kucharski@Sun.COM 			return 0;
9908044SWilliam.Kucharski@Sun.COM 	default:
9918044SWilliam.Kucharski@Sun.COM 		break;
9928044SWilliam.Kucharski@Sun.COM 	}
9938044SWilliam.Kucharski@Sun.COM 
9948044SWilliam.Kucharski@Sun.COM 	/* We have an interrupt or there is something left from
9958044SWilliam.Kucharski@Sun.COM 	 * last poll. Either way, we need to call UNDI ISR.
9968044SWilliam.Kucharski@Sun.COM 	 */
9978044SWilliam.Kucharski@Sun.COM 	nic->packetlen = 0;
9988044SWilliam.Kucharski@Sun.COM 	undi.pxs->undi_isr.FuncFlag = undi_opcode;
9998044SWilliam.Kucharski@Sun.COM 	/* there is no good way to handle this error */
10008044SWilliam.Kucharski@Sun.COM 	if ( ! eb_pxenv_undi_isr() ) {
10018044SWilliam.Kucharski@Sun.COM 		printf ("undi isr call failed: opcode = %d\n", undi_opcode);
10028044SWilliam.Kucharski@Sun.COM 		return 0;
10038044SWilliam.Kucharski@Sun.COM 	}
10048044SWilliam.Kucharski@Sun.COM 	switch ( undi.pxs->undi_isr.FuncFlag ) {
10058044SWilliam.Kucharski@Sun.COM 	case PXENV_UNDI_ISR_OUT_DONE:
10068044SWilliam.Kucharski@Sun.COM 		/* Set opcode back to IN_PROCESS and wait for next intr */
10078044SWilliam.Kucharski@Sun.COM 		undi_opcode = PXENV_UNDI_ISR_IN_PROCESS;
10088044SWilliam.Kucharski@Sun.COM 		return 0;
10098044SWilliam.Kucharski@Sun.COM 	case PXENV_UNDI_ISR_OUT_TRANSMIT:
10108044SWilliam.Kucharski@Sun.COM 		/* We really don't care about transmission complete
10118044SWilliam.Kucharski@Sun.COM 		 * interrupts. Move on to next frame.
10128044SWilliam.Kucharski@Sun.COM 		 */
10138044SWilliam.Kucharski@Sun.COM 		undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT;
10148044SWilliam.Kucharski@Sun.COM 		return 0;
10158044SWilliam.Kucharski@Sun.COM 	case PXENV_UNDI_ISR_OUT_BUSY:
10168044SWilliam.Kucharski@Sun.COM 		/* This should never happen.
10178044SWilliam.Kucharski@Sun.COM 		 */
10188044SWilliam.Kucharski@Sun.COM 		undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT;
10198044SWilliam.Kucharski@Sun.COM 		printf ( "UNDI ISR thinks it's being re-entered!\n"
10208044SWilliam.Kucharski@Sun.COM 			 "Aborting receive\n" );
10218044SWilliam.Kucharski@Sun.COM 		return 0;
10228044SWilliam.Kucharski@Sun.COM 	case PXENV_UNDI_ISR_OUT_RECEIVE:
10238044SWilliam.Kucharski@Sun.COM 		/* Copy data to receive buffer and move on to next frame */
10248044SWilliam.Kucharski@Sun.COM 		undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT;
10258044SWilliam.Kucharski@Sun.COM 		memcpy ( nic->packet + nic->packetlen,
10268044SWilliam.Kucharski@Sun.COM 			 VIRTUAL( undi.pxs->undi_isr.Frame.segment,
10278044SWilliam.Kucharski@Sun.COM 				  undi.pxs->undi_isr.Frame.offset ),
10288044SWilliam.Kucharski@Sun.COM 			 undi.pxs->undi_isr.BufferLength );
10298044SWilliam.Kucharski@Sun.COM 		nic->packetlen += undi.pxs->undi_isr.BufferLength;
10308044SWilliam.Kucharski@Sun.COM 		break;
10318044SWilliam.Kucharski@Sun.COM 	default:
10328044SWilliam.Kucharski@Sun.COM 		undi_opcode = PXENV_UNDI_ISR_IN_PROCESS;
10338044SWilliam.Kucharski@Sun.COM 		printf ( "UNDI ISR returned bizzare status code %d\n",
10348044SWilliam.Kucharski@Sun.COM 			 undi.pxs->undi_isr.FuncFlag );
10358044SWilliam.Kucharski@Sun.COM 	}
10368044SWilliam.Kucharski@Sun.COM 
10378044SWilliam.Kucharski@Sun.COM 	return nic->packetlen > 0 ? 1 : 0;
10388044SWilliam.Kucharski@Sun.COM }
10398044SWilliam.Kucharski@Sun.COM 
10408044SWilliam.Kucharski@Sun.COM /**************************************************************************
10418044SWilliam.Kucharski@Sun.COM TRANSMIT - Transmit a frame
10428044SWilliam.Kucharski@Sun.COM ***************************************************************************/
undi_transmit(struct nic * nic,const char * d,unsigned int t,unsigned int s,const char * p)10438044SWilliam.Kucharski@Sun.COM static void undi_transmit(
10448044SWilliam.Kucharski@Sun.COM 	struct nic *nic,
10458044SWilliam.Kucharski@Sun.COM 	const char *d,			/* Destination */
10468044SWilliam.Kucharski@Sun.COM 	unsigned int t,			/* Type */
10478044SWilliam.Kucharski@Sun.COM 	unsigned int s,			/* size */
10488044SWilliam.Kucharski@Sun.COM 	const char *p)			/* Packet */
10498044SWilliam.Kucharski@Sun.COM {
10508044SWilliam.Kucharski@Sun.COM 	/* Inhibit compiler warning about unused parameter nic */
10518044SWilliam.Kucharski@Sun.COM 	if ( nic == NULL ) {};
10528044SWilliam.Kucharski@Sun.COM 
10538044SWilliam.Kucharski@Sun.COM 	/* Copy destination to buffer in base memory */
10548044SWilliam.Kucharski@Sun.COM 	memcpy ( undi.xmit_data->destaddr, d, sizeof(MAC_ADDR) );
10558044SWilliam.Kucharski@Sun.COM 
10568044SWilliam.Kucharski@Sun.COM 	/* Translate packet type to UNDI packet type */
10578044SWilliam.Kucharski@Sun.COM 	switch ( t ) {
10588044SWilliam.Kucharski@Sun.COM 	case IP :  undi.pxs->undi_transmit.Protocol = P_IP;   break;
10598044SWilliam.Kucharski@Sun.COM 	case ARP:  undi.pxs->undi_transmit.Protocol = P_ARP;  break;
10608044SWilliam.Kucharski@Sun.COM 	case RARP: undi.pxs->undi_transmit.Protocol = P_RARP; break;
10618044SWilliam.Kucharski@Sun.COM 	default: undi.pxs->undi_transmit.Protocol = P_UNKNOWN; break;
10628044SWilliam.Kucharski@Sun.COM 	}
10638044SWilliam.Kucharski@Sun.COM 
10648044SWilliam.Kucharski@Sun.COM 	/* Store packet length in TBD */
10658044SWilliam.Kucharski@Sun.COM 	undi.xmit_data->tbd.ImmedLength = s;
10668044SWilliam.Kucharski@Sun.COM 
10678044SWilliam.Kucharski@Sun.COM 	/* Check to see if data to be transmitted is currently in base
10688044SWilliam.Kucharski@Sun.COM 	 * memory.  If not, allocate temporary storage in base memory
10698044SWilliam.Kucharski@Sun.COM 	 * and copy it there.
10708044SWilliam.Kucharski@Sun.COM 	 */
10718044SWilliam.Kucharski@Sun.COM 	if ( SEGMENT( p ) <= 0xffff ) {
10728044SWilliam.Kucharski@Sun.COM 		undi.xmit_data->tbd.Xmit.segment = SEGMENT( p );
10738044SWilliam.Kucharski@Sun.COM 		undi.xmit_data->tbd.Xmit.offset = OFFSET( p );
10748044SWilliam.Kucharski@Sun.COM 	} else {
10758044SWilliam.Kucharski@Sun.COM 		memcpy ( undi.xmit_buffer, p, s );
10768044SWilliam.Kucharski@Sun.COM 		undi.xmit_data->tbd.Xmit.segment = SEGMENT( undi.xmit_buffer );
10778044SWilliam.Kucharski@Sun.COM 		undi.xmit_data->tbd.Xmit.offset = OFFSET( undi.xmit_buffer );
10788044SWilliam.Kucharski@Sun.COM 	}
10798044SWilliam.Kucharski@Sun.COM 
10808044SWilliam.Kucharski@Sun.COM 	eb_pxenv_undi_transmit_packet();
10818044SWilliam.Kucharski@Sun.COM }
10828044SWilliam.Kucharski@Sun.COM 
10838044SWilliam.Kucharski@Sun.COM /**************************************************************************
10848044SWilliam.Kucharski@Sun.COM DISABLE - Turn off ethernet interface
10858044SWilliam.Kucharski@Sun.COM ***************************************************************************/
undi_disable(struct dev * dev)10868044SWilliam.Kucharski@Sun.COM static void undi_disable(struct dev *dev)
10878044SWilliam.Kucharski@Sun.COM {
10888044SWilliam.Kucharski@Sun.COM 	/* Inhibit compiler warning about unused parameter dev */
10898044SWilliam.Kucharski@Sun.COM 	if ( dev == NULL ) {};
10908044SWilliam.Kucharski@Sun.COM 	undi_full_shutdown();
10918044SWilliam.Kucharski@Sun.COM 	free_base_mem_data();
10928044SWilliam.Kucharski@Sun.COM }
10938044SWilliam.Kucharski@Sun.COM 
10948044SWilliam.Kucharski@Sun.COM /**************************************************************************
10958044SWilliam.Kucharski@Sun.COM PROBE - Look for an adapter, this routine's visible to the outside
10968044SWilliam.Kucharski@Sun.COM ***************************************************************************/
10978044SWilliam.Kucharski@Sun.COM 
10988044SWilliam.Kucharski@Sun.COM /* Locate an UNDI driver by first scanning through base memory for an
10998044SWilliam.Kucharski@Sun.COM  * installed driver and then by scanning for UNDI ROMs and attempting
11008044SWilliam.Kucharski@Sun.COM  * to install their drivers.
11018044SWilliam.Kucharski@Sun.COM  */
11028044SWilliam.Kucharski@Sun.COM 
hunt_pixies_and_undi_roms(void)11038044SWilliam.Kucharski@Sun.COM int hunt_pixies_and_undi_roms ( void ) {
11048044SWilliam.Kucharski@Sun.COM 	static uint8_t hunt_type = HUNT_FOR_PIXIES;
11058044SWilliam.Kucharski@Sun.COM 
11068044SWilliam.Kucharski@Sun.COM 	if ( hunt_type == HUNT_FOR_PIXIES ) {
11078044SWilliam.Kucharski@Sun.COM 		if ( hunt_pixie() ) {
11088044SWilliam.Kucharski@Sun.COM 			return 1;
11098044SWilliam.Kucharski@Sun.COM 		}
11108044SWilliam.Kucharski@Sun.COM 	}
11118044SWilliam.Kucharski@Sun.COM 	hunt_type = HUNT_FOR_UNDI_ROMS;
11128044SWilliam.Kucharski@Sun.COM 	while ( hunt_undi_rom() ) {
11138044SWilliam.Kucharski@Sun.COM 		if ( undi_loader() ) {
11148044SWilliam.Kucharski@Sun.COM 			return 1;
11158044SWilliam.Kucharski@Sun.COM 		}
11168044SWilliam.Kucharski@Sun.COM 		undi_full_shutdown(); /* Free any allocated memory */
11178044SWilliam.Kucharski@Sun.COM 	}
11188044SWilliam.Kucharski@Sun.COM 	hunt_type = HUNT_FOR_PIXIES;
11198044SWilliam.Kucharski@Sun.COM 	return 0;
11208044SWilliam.Kucharski@Sun.COM }
11218044SWilliam.Kucharski@Sun.COM 
11228044SWilliam.Kucharski@Sun.COM /* The actual Etherboot probe routine.
11238044SWilliam.Kucharski@Sun.COM  */
11248044SWilliam.Kucharski@Sun.COM 
undi_probe(struct dev * dev,struct pci_device * pci)11258044SWilliam.Kucharski@Sun.COM static int undi_probe(struct dev *dev, struct pci_device *pci)
11268044SWilliam.Kucharski@Sun.COM {
11278044SWilliam.Kucharski@Sun.COM 	struct nic *nic = (struct nic *)dev;
11288044SWilliam.Kucharski@Sun.COM 
11298044SWilliam.Kucharski@Sun.COM 	/* Zero out global undi structure */
11308044SWilliam.Kucharski@Sun.COM 	memset ( &undi, 0, sizeof(undi) );
11318044SWilliam.Kucharski@Sun.COM 
11328044SWilliam.Kucharski@Sun.COM 	/* Store PCI parameters; we will need them to initialize the UNDI
11338044SWilliam.Kucharski@Sun.COM 	 * driver later.
11348044SWilliam.Kucharski@Sun.COM 	 */
11358044SWilliam.Kucharski@Sun.COM 	memcpy ( &undi.pci, pci, sizeof(undi.pci) );
11368044SWilliam.Kucharski@Sun.COM 
11378044SWilliam.Kucharski@Sun.COM 	/* Find the BIOS' $PnP structure */
11388044SWilliam.Kucharski@Sun.COM 	if ( ! hunt_pnp_bios() ) {
11398044SWilliam.Kucharski@Sun.COM 		printf ( "No PnP BIOS found; aborting\n" );
11408044SWilliam.Kucharski@Sun.COM 		return 0;
11418044SWilliam.Kucharski@Sun.COM 	}
11428044SWilliam.Kucharski@Sun.COM 
11438044SWilliam.Kucharski@Sun.COM 	/* Allocate base memory data structures */
11448044SWilliam.Kucharski@Sun.COM 	if ( ! allocate_base_mem_data() ) return 0;
11458044SWilliam.Kucharski@Sun.COM 
11468044SWilliam.Kucharski@Sun.COM 	/* Search thoroughly for UNDI drivers */
11478044SWilliam.Kucharski@Sun.COM 	for ( ; hunt_pixies_and_undi_roms(); undi_full_shutdown() ) {
11488044SWilliam.Kucharski@Sun.COM 		/* Try to initialise UNDI driver */
11498044SWilliam.Kucharski@Sun.COM 		DBG ( "Initializing UNDI driver.  Please wait...\n" );
11508044SWilliam.Kucharski@Sun.COM 		if ( ! undi_full_startup() ) {
11518044SWilliam.Kucharski@Sun.COM 			if ( undi.pxs->Status ==
11528044SWilliam.Kucharski@Sun.COM 			     PXENV_STATUS_UNDI_MEDIATEST_FAILED ) {
11538044SWilliam.Kucharski@Sun.COM 				DBG ( "Cable not connected (code %#hx)\n",
11548044SWilliam.Kucharski@Sun.COM 					 PXENV_STATUS_UNDI_MEDIATEST_FAILED );
11558044SWilliam.Kucharski@Sun.COM 			}
11568044SWilliam.Kucharski@Sun.COM 			continue;
11578044SWilliam.Kucharski@Sun.COM 		}
11588044SWilliam.Kucharski@Sun.COM 		/* Basic information: MAC, IO addr, IRQ */
11598044SWilliam.Kucharski@Sun.COM 		if ( ! eb_pxenv_undi_get_information() ) continue;
11608044SWilliam.Kucharski@Sun.COM 		DBG ( "Initialized UNDI NIC with IO %#hx, IRQ %d, MAC %!\n",
11618044SWilliam.Kucharski@Sun.COM 			 undi.pxs->undi_get_information.BaseIo,
11628044SWilliam.Kucharski@Sun.COM 			 undi.pxs->undi_get_information.IntNumber,
11638044SWilliam.Kucharski@Sun.COM 			 undi.pxs->undi_get_information.CurrentNodeAddress );
11648044SWilliam.Kucharski@Sun.COM 		/* Fill out MAC address in nic structure */
11658044SWilliam.Kucharski@Sun.COM 		memcpy ( nic->node_addr,
11668044SWilliam.Kucharski@Sun.COM 			 undi.pxs->undi_get_information.CurrentNodeAddress,
11678044SWilliam.Kucharski@Sun.COM 			 ETH_ALEN );
11688044SWilliam.Kucharski@Sun.COM 		/* More diagnostic information including link speed */
11698044SWilliam.Kucharski@Sun.COM 		if ( ! eb_pxenv_undi_get_iface_info() ) continue;
11708044SWilliam.Kucharski@Sun.COM 		printf ( "  NDIS type %s interface at %d Mbps\n",
11718044SWilliam.Kucharski@Sun.COM 			 undi.pxs->undi_get_iface_info.IfaceType,
11728044SWilliam.Kucharski@Sun.COM 			 undi.pxs->undi_get_iface_info.LinkSpeed / 1000000 );
11738044SWilliam.Kucharski@Sun.COM 		DBG ("UNDI Stack at %#hx:%#hx",UNDI_STACK_SEG, UNDI_STACK_OFF);
11748044SWilliam.Kucharski@Sun.COM 		dev->disable  = undi_disable;
11758044SWilliam.Kucharski@Sun.COM 		nic->poll     = undi_poll;
11768044SWilliam.Kucharski@Sun.COM 		nic->transmit = undi_transmit;
11778044SWilliam.Kucharski@Sun.COM 		return 1;
11788044SWilliam.Kucharski@Sun.COM 	}
11798044SWilliam.Kucharski@Sun.COM 	undi_disable ( dev ); /* To free base memory structures */
11808044SWilliam.Kucharski@Sun.COM 	return 0;
11818044SWilliam.Kucharski@Sun.COM }
11828044SWilliam.Kucharski@Sun.COM 
11838044SWilliam.Kucharski@Sun.COM /* UNDI driver states that it is suitable for any PCI NIC (i.e. any
11848044SWilliam.Kucharski@Sun.COM  * PCI device of class PCI_CLASS_NETWORK_ETHERNET).  If there are any
11858044SWilliam.Kucharski@Sun.COM  * obscure UNDI NICs that have the incorrect PCI class, add them to
11868044SWilliam.Kucharski@Sun.COM  * this list.
11878044SWilliam.Kucharski@Sun.COM  */
11888044SWilliam.Kucharski@Sun.COM static struct pci_id undi_nics[] = {
1189*12881SJakub.Jermar@Sun.COM 	PCI_ROM(0x10de, 0x0057, "ck804", "nVidia Corporation CK804 Ethernet"),
1190*12881SJakub.Jermar@Sun.COM 	PCI_ROM(0x10de, 0x0373, "mcp55", "nVidia Corporation MCP55 Ethernet")
11918044SWilliam.Kucharski@Sun.COM };
11928044SWilliam.Kucharski@Sun.COM 
11938044SWilliam.Kucharski@Sun.COM struct pci_driver undi_driver = {
11948044SWilliam.Kucharski@Sun.COM 	.type     = NIC_DRIVER,
11958044SWilliam.Kucharski@Sun.COM 	.name     = "UNDI",
11968044SWilliam.Kucharski@Sun.COM 	.probe    = undi_probe,
11978044SWilliam.Kucharski@Sun.COM 	.ids      = undi_nics,
11988044SWilliam.Kucharski@Sun.COM  	.id_count = sizeof(undi_nics)/sizeof(undi_nics[0]),
11998044SWilliam.Kucharski@Sun.COM 	.class    = PCI_CLASS_NETWORK_ETHERNET,
12008044SWilliam.Kucharski@Sun.COM };
12018044SWilliam.Kucharski@Sun.COM 
12028044SWilliam.Kucharski@Sun.COM /************************************************
12038044SWilliam.Kucharski@Sun.COM  * Code for reusing the BIOS provided pxe stack
12048044SWilliam.Kucharski@Sun.COM  */
12058044SWilliam.Kucharski@Sun.COM 
12068044SWilliam.Kucharski@Sun.COM /* Verify !PXE structure saved by pxeloader. */
undi_bios_pxe(void ** dhcpreply)12078044SWilliam.Kucharski@Sun.COM int undi_bios_pxe(void **dhcpreply)
12088044SWilliam.Kucharski@Sun.COM {
12098044SWilliam.Kucharski@Sun.COM 	pxe_t *pxe;
12108044SWilliam.Kucharski@Sun.COM 	uint16_t *ptr = (uint16_t *)0x7C80;
12118044SWilliam.Kucharski@Sun.COM 
12128044SWilliam.Kucharski@Sun.COM 	pxe = (pxe_t *) VIRTUAL(ptr[0], ptr[1]);
12138044SWilliam.Kucharski@Sun.COM 	if (memcmp(pxe->Signature, "!PXE", 4) != 0) {
12148044SWilliam.Kucharski@Sun.COM 		DBG ("invalid !PXE signature at %x:%x\n", ptr[0], ptr[1]);
12158044SWilliam.Kucharski@Sun.COM 		return 0;
12168044SWilliam.Kucharski@Sun.COM 	}
12178044SWilliam.Kucharski@Sun.COM 
12188044SWilliam.Kucharski@Sun.COM 	if (checksum(pxe, sizeof(pxe_t)) != 0) {
12198044SWilliam.Kucharski@Sun.COM 		DBG ("invalid checksum\n");
12208044SWilliam.Kucharski@Sun.COM 		return 0;
12218044SWilliam.Kucharski@Sun.COM 	}
12228044SWilliam.Kucharski@Sun.COM 
12238044SWilliam.Kucharski@Sun.COM 	/* Zero out global undi structure */
12248044SWilliam.Kucharski@Sun.COM 	memset (&undi, 0, sizeof(undi));
12258044SWilliam.Kucharski@Sun.COM 
12268044SWilliam.Kucharski@Sun.COM 	/* Allocate base memory data structures */
12278044SWilliam.Kucharski@Sun.COM 	if (! allocate_base_mem_data()) return 0;
12288044SWilliam.Kucharski@Sun.COM 
12298044SWilliam.Kucharski@Sun.COM 	undi.pxe = pxe;
12308044SWilliam.Kucharski@Sun.COM 	pxe_dump();
12318044SWilliam.Kucharski@Sun.COM 
12328044SWilliam.Kucharski@Sun.COM 	if (!eb_pxenv_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, dhcpreply)) {
12338044SWilliam.Kucharski@Sun.COM 		DBG ("failed to get cached DHCP reply\n");
12348044SWilliam.Kucharski@Sun.COM 		return 0;
12358044SWilliam.Kucharski@Sun.COM 	}
12368044SWilliam.Kucharski@Sun.COM 	return 1;
12378044SWilliam.Kucharski@Sun.COM }
12388044SWilliam.Kucharski@Sun.COM 
undi_pxe_disable(void)12398044SWilliam.Kucharski@Sun.COM void undi_pxe_disable(void)
12408044SWilliam.Kucharski@Sun.COM {
12418044SWilliam.Kucharski@Sun.COM 	/* full shutdown is problematic for some machines */
12428044SWilliam.Kucharski@Sun.COM 	(void) eb_pxenv_undi_shutdown();
12438044SWilliam.Kucharski@Sun.COM }
12448044SWilliam.Kucharski@Sun.COM 
12458044SWilliam.Kucharski@Sun.COM /*
12468044SWilliam.Kucharski@Sun.COM  * Various helper functions for dhcp and tftp
12478044SWilliam.Kucharski@Sun.COM  */
eb_pxenv_get_cached_info(uint8_t type,void ** info)12488044SWilliam.Kucharski@Sun.COM int eb_pxenv_get_cached_info (uint8_t type, void **info)
12498044SWilliam.Kucharski@Sun.COM {
12508044SWilliam.Kucharski@Sun.COM 	int success;
12518044SWilliam.Kucharski@Sun.COM 
12528044SWilliam.Kucharski@Sun.COM 	memset(undi.pxs, 0, sizeof (undi.pxs));
12538044SWilliam.Kucharski@Sun.COM 	/* Segment:offset pointer to DestAddr in base memory */
12548044SWilliam.Kucharski@Sun.COM 	undi.pxs->get_cached_info.PacketType = type;
12558044SWilliam.Kucharski@Sun.COM 	undi.pxs->get_cached_info.BufferSize = 0;
12568044SWilliam.Kucharski@Sun.COM 	undi.pxs->get_cached_info.Buffer.segment = 0;
12578044SWilliam.Kucharski@Sun.COM 	undi.pxs->get_cached_info.Buffer.offset = 0;
12588044SWilliam.Kucharski@Sun.COM 
12598044SWilliam.Kucharski@Sun.COM 	success = undi_call(PXENV_GET_CACHED_INFO);
12608044SWilliam.Kucharski@Sun.COM 	DBG ("PXENV_GET_CACHED_INFO <= Status=%s\n", UNDI_STATUS(undi.pxs));
12618044SWilliam.Kucharski@Sun.COM 
12628044SWilliam.Kucharski@Sun.COM 	*info = (void *)VIRTUAL(undi.pxs->get_cached_info.Buffer.segment,
12638044SWilliam.Kucharski@Sun.COM 	    undi.pxs->get_cached_info.Buffer.offset);
12648044SWilliam.Kucharski@Sun.COM 	return success;
12658044SWilliam.Kucharski@Sun.COM }
12668044SWilliam.Kucharski@Sun.COM 
12678044SWilliam.Kucharski@Sun.COM /* tftp help routines */
eb_pxenv_tftp_open(char * file,IP4_t serverip,IP4_t gatewayip,uint16_t * pktlen)12688044SWilliam.Kucharski@Sun.COM int eb_pxenv_tftp_open(char *file, IP4_t serverip, IP4_t gatewayip,
12698044SWilliam.Kucharski@Sun.COM     uint16_t *pktlen)
12708044SWilliam.Kucharski@Sun.COM {
12718044SWilliam.Kucharski@Sun.COM 	int success;
12728044SWilliam.Kucharski@Sun.COM 	memset(undi.pxs, 0, sizeof (undi.pxs));
12738044SWilliam.Kucharski@Sun.COM 	undi.pxs->tftp_open.ServerIPAddress = serverip;
12748044SWilliam.Kucharski@Sun.COM 	undi.pxs->tftp_open.GatewayIPAddress = gatewayip;
12758044SWilliam.Kucharski@Sun.COM 	undi.pxs->tftp_open.TFTPPort = htons(TFTP_PORT);
12768044SWilliam.Kucharski@Sun.COM 	undi.pxs->tftp_open.PacketSize = TFTP_MAX_PACKET;
12778044SWilliam.Kucharski@Sun.COM 	(void) sprintf(undi.pxs->tftp_open.FileName, "%s", file);
12788044SWilliam.Kucharski@Sun.COM 	success = undi_call(PXENV_TFTP_OPEN);
12798044SWilliam.Kucharski@Sun.COM 	DBG ("PXENV_TFTP_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs));
12808044SWilliam.Kucharski@Sun.COM 	*pktlen = undi.pxs->tftp_open.PacketSize;
12818044SWilliam.Kucharski@Sun.COM 	return success;
12828044SWilliam.Kucharski@Sun.COM }
12838044SWilliam.Kucharski@Sun.COM 
eb_pxenv_tftp_read(uint8_t * buf,uint16_t * len)12848044SWilliam.Kucharski@Sun.COM int eb_pxenv_tftp_read(uint8_t *buf, uint16_t *len)
12858044SWilliam.Kucharski@Sun.COM {
12868044SWilliam.Kucharski@Sun.COM 	static int tftp_count = 0;
12878044SWilliam.Kucharski@Sun.COM 
12888044SWilliam.Kucharski@Sun.COM 	int success;
12898044SWilliam.Kucharski@Sun.COM 	memset(undi.pxs, 0, sizeof (undi.pxs));
12908044SWilliam.Kucharski@Sun.COM 	undi.pxs->tftp_read.Buffer.segment = SEGMENT(buf);
12918044SWilliam.Kucharski@Sun.COM 	undi.pxs->tftp_read.Buffer.offset = OFFSET(buf);
12928044SWilliam.Kucharski@Sun.COM 	success = undi_call(PXENV_TFTP_READ);
12938044SWilliam.Kucharski@Sun.COM 	DBG ("PXENV_TFTP_READ <= Status=%s\n", UNDI_STATUS(undi.pxs));
12948044SWilliam.Kucharski@Sun.COM 	*len = undi.pxs->tftp_read.BufferSize;
12958044SWilliam.Kucharski@Sun.COM 	tftp_count++;
12968044SWilliam.Kucharski@Sun.COM 	if ((tftp_count % 1000) == 0)
12978044SWilliam.Kucharski@Sun.COM 		noisy_printf(".");
12988044SWilliam.Kucharski@Sun.COM 	return success;
12998044SWilliam.Kucharski@Sun.COM }
13008044SWilliam.Kucharski@Sun.COM 
eb_pxenv_tftp_close(void)13018044SWilliam.Kucharski@Sun.COM int eb_pxenv_tftp_close(void)
13028044SWilliam.Kucharski@Sun.COM {
13038044SWilliam.Kucharski@Sun.COM 	int success;
13048044SWilliam.Kucharski@Sun.COM 	memset(undi.pxs, 0, sizeof (undi.pxs));
13058044SWilliam.Kucharski@Sun.COM 	success = undi_call(PXENV_TFTP_CLOSE);
13068044SWilliam.Kucharski@Sun.COM 	DBG ("PXENV_TFTP_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs));
13078044SWilliam.Kucharski@Sun.COM 	return success;
13088044SWilliam.Kucharski@Sun.COM }
13098044SWilliam.Kucharski@Sun.COM 
eb_pxenv_tftp_get_fsize(char * file,IP4_t serverip,IP4_t gatewayip,uint32_t * fsize)13108044SWilliam.Kucharski@Sun.COM int eb_pxenv_tftp_get_fsize(char *file, IP4_t serverip, IP4_t gatewayip,
13118044SWilliam.Kucharski@Sun.COM     uint32_t *fsize)
13128044SWilliam.Kucharski@Sun.COM {
13138044SWilliam.Kucharski@Sun.COM 	int success;
13148044SWilliam.Kucharski@Sun.COM 	memset(undi.pxs, 0, sizeof (undi.pxs));
13158044SWilliam.Kucharski@Sun.COM 	undi.pxs->tftp_open.ServerIPAddress = serverip;
13168044SWilliam.Kucharski@Sun.COM 	undi.pxs->tftp_open.GatewayIPAddress = gatewayip;
13178044SWilliam.Kucharski@Sun.COM 	(void) sprintf(undi.pxs->tftp_open.FileName, "%s", file);
13188044SWilliam.Kucharski@Sun.COM 	success = undi_call(PXENV_TFTP_GET_FSIZE);
13198044SWilliam.Kucharski@Sun.COM 	DBG ("PXENV_TFTP_GET_FSIZE <= Status=%s\n", UNDI_STATUS(undi.pxs));
13208044SWilliam.Kucharski@Sun.COM 	*fsize = undi.pxs->tftp_get_fsize.FileSize;
13218044SWilliam.Kucharski@Sun.COM 	return success;
13228044SWilliam.Kucharski@Sun.COM }
1323