1 /* dev.c - dm9601eth.device by Chris Hodges
6 #include "dm9601eth.class.h"
8 AROS_UFH3(DEVBASETYPEPTR
, devInit
,
9 AROS_UFHA(DEVBASETYPEPTR
, base
, D0
),
10 AROS_UFHA(BPTR
, seglist
, A0
),
11 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
15 KPRINTF(10, ("devInit base: 0x%08lx seglist: 0x%08lx SysBase: 0x%08lx\n",
16 base
, seglist
, SysBase
));
18 base
->np_Library
.lib_Node
.ln_Type
= NT_DEVICE
;
19 base
->np_Library
.lib_Node
.ln_Name
= DEVNAME
;
20 base
->np_Library
.lib_Flags
= LIBF_SUMUSED
|LIBF_CHANGED
;
21 base
->np_Library
.lib_Version
= VERSION_NUMBER
;
22 base
->np_Library
.lib_Revision
= REVISION_NUMBER
;
23 base
->np_Library
.lib_IdString
= VERSION_STRING
;
26 base
->np_SegList
= seglist
;
28 if((base
->np_UtilityBase
= OpenLibrary("utility.library", 0)))
30 KPRINTF(10, ("devInit: Ok\n"));
31 KPRINTF(10, ("devInit: openCnt = %ld\n", base
->np_Library
.lib_OpenCnt
));
44 #define UtilityBase base->np_UtilityBase
46 AROS_LH3(DEVBASETYPEPTR
, devOpen
,
47 AROS_LHA(struct IOSana2Req
*, ioreq
, A1
),
48 AROS_LHA(ULONG
, unit
, D0
),
49 AROS_LHA(ULONG
, flags
, D1
),
50 DEVBASETYPEPTR
, base
, 1, dev
)
54 struct NepClassEth
*ncp
;
55 struct TagItem
*taglist
;
57 KPRINTF(10, ("devOpen ioreq: 0x%08lx unit: %ld flags: 0x%08lx base: 0x%08lx\n",
58 ioreq
, unit
, flags
, base
));
60 ++base
->np_Library
.lib_OpenCnt
;
61 base
->np_Library
.lib_Flags
&= ~LIBF_DELEXP
;
63 KPRINTF(10, ("devOpen: openCnt = %ld\n", base
->np_Library
.lib_OpenCnt
));
64 /* Damn f*cking programs which leave this field to zero! */
65 if(ioreq
->ios2_Req
.io_Message
.mn_Length
&& (ioreq
->ios2_Req
.io_Message
.mn_Length
< sizeof(struct IOSana2Req
)))
67 KPRINTF(20, ("devOpen: invalid MN_LENGTH (%ld < %ld)!\n",
68 ioreq
->ios2_Req
.io_Message
.mn_Length
, sizeof(struct IOSana2Req
)));
70 ioreq
->ios2_Req
.io_Error
= IOERR_BADLENGTH
;
72 /* Default to open failure. */
73 ioreq
->ios2_Req
.io_Error
= IOERR_OPENFAIL
;
75 ioreq
->ios2_Req
.io_Unit
= NULL
;
76 ncp
= (struct NepClassEth
*) base
->np_ClsBase
->nh_Units
.lh_Head
;
77 while(ncp
->ncp_Unit
.unit_MsgPort
.mp_Node
.ln_Succ
)
79 if(ncp
->ncp_UnitNo
== unit
)
81 if(ncp
->ncp_OpenFlags
& SANA2OPF_MINE
)
83 ioreq
->ios2_Req
.io_Error
= IOERR_UNITBUSY
;
85 ioreq
->ios2_Req
.io_Unit
= (struct Unit
*) ncp
;
89 ncp
= (struct NepClassEth
*) ncp
->ncp_Unit
.unit_MsgPort
.mp_Node
.ln_Succ
;
92 if(!ioreq
->ios2_Req
.io_Unit
)
94 ioreq
->ios2_Req
.io_Error
= IOERR_OPENFAIL
;
95 KPRINTF(20, ("devOpen: could not open unit!\n"));
97 ncp
->ncp_OpenFlags
|= flags
;
99 /* Got taglist? (don't fail if not available!) */
100 taglist
= (struct TagItem
*) ioreq
->ios2_BufferManagement
;
103 struct BufMan
*bufman
;
105 bufman
= (struct BufMan
*) AllocVec(sizeof(struct BufMan
), MEMF_CLEAR
|MEMF_PUBLIC
);
108 /* Get copyfrom routines */
109 bufman
->bm_CopyFromBuf
= (APTR
) GetTagData(S2_CopyFromBuff
, (IPTR
) NULL
, taglist
);
110 bufman
->bm_CopyToBuf
= (APTR
) GetTagData(S2_CopyToBuff
, (IPTR
) NULL
, taglist
);
112 /* This is new SANA-II V2 addition */
113 bufman
->bm_PacketFilter
= (APTR
) GetTagData(S2_PacketFilter
, (IPTR
) NULL
, taglist
);
115 /* These are new SANA-II V3 addition */
116 bufman
->bm_DMACopyFromBuf32
= (APTR
) GetTagData(S2_DMACopyFromBuff32
, (IPTR
) NULL
, taglist
);
117 bufman
->bm_DMACopyToBuf32
= (APTR
) GetTagData(S2_DMACopyToBuff32
, (IPTR
) NULL
, taglist
);
119 /* Init the list for CMD_READ requests */
120 NewList((struct List
*) &bufman
->bm_RXQueue
);
122 /* Add the new bufman to global bufmanlist */
123 KPRINTF(5, ("Open_Unit: added bufman at 0x%08lx\n", bufman
));
125 AddHead((struct List
*) &ncp
->ncp_BufManList
, (struct Node
*) bufman
);
128 ioreq
->ios2_BufferManagement
= bufman
;
130 KPRINTF(5, ("Open_Unit:\n"
131 "copyfrombuf: 0x%08lx copytobuf: 0x%08lx packetfilter: 0x%08lx\n"
132 "dmacopyfrombuf32: 0x%08lx dmacopytobuf32: 0x%08lx\n",
133 bufman
->bm_CopyFromBuf
, bufman
->bm_CopyToBuf
, bufman
->bm_PacketFilter
,
134 bufman
->bm_DMACopyFromBuf32
, bufman
->bm_DMACopyToBuf32
));
137 ioreq
->ios2_Req
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
138 ioreq
->ios2_Req
.io_Error
= 0;
139 ioreq
->ios2_Req
.io_Unit
->unit_OpenCnt
++;
142 //ncp->ncp_DenyRequests = FALSE;
148 ioreq
->ios2_Req
.io_Unit
= (APTR
) -1;
149 ioreq
->ios2_Req
.io_Device
= (APTR
) -1;
150 base
->np_Library
.lib_OpenCnt
--;
158 AROS_LH1(BPTR
, devClose
,
159 AROS_LHA(struct IOSana2Req
*, ioreq
, A1
),
160 DEVBASETYPEPTR
, base
, 2, dev
)
165 struct NepClassEth
*ncp
= (struct NepClassEth
*) ioreq
->ios2_Req
.io_Unit
;
166 struct BufMan
*bufman
;
168 KPRINTF(10, ("devClose ioreq: 0x%08lx base: 0x%08lx\n", ioreq
, base
));
172 //ncp->ncp_DenyRequests = TRUE;
174 ncp
->ncp_Unit
.unit_OpenCnt
--;
175 if(ncp
->ncp_Unit
.unit_OpenCnt
== 1)
177 ncp
->ncp_OpenFlags
= 0; // clear all flags, if all units are closed
180 ioreq
->ios2_Req
.io_Unit
= (APTR
) -1;
181 ioreq
->ios2_Req
.io_Device
= (APTR
) -1;
183 bufman
= ioreq
->ios2_BufferManagement
;
186 KPRINTF(5, ("Close_Unit: remove bufman at 0x%08lx\n", bufman
));
187 ioreq
->ios2_BufferManagement
= NULL
;
190 Remove((struct Node
*) bufman
);
195 if(--base
->np_Library
.lib_OpenCnt
== 0)
197 if(base
->np_Library
.lib_Flags
& LIBF_DELEXP
)
199 KPRINTF(5, ("devClose: calling expunge...\n"));
200 ret
= AROS_LC1(BPTR
, devExpunge
,
201 AROS_LCA(DEVBASETYPEPTR
, base
, D0
),
202 DEVBASETYPEPTR
, base
, 3, dev
);
206 KPRINTF(5, ("devClose: lib_OpenCnt = %ld\n", base
->np_Library
.lib_OpenCnt
));
214 AROS_LH1(BPTR
, devExpunge
,
215 AROS_LHA(DEVBASETYPEPTR
, extralh
, D0
),
216 DEVBASETYPEPTR
, base
, 3, dev
)
222 KPRINTF(10, ("devExpunge base: 0x%08lx\n", base
));
226 if(base
->np_Library
.lib_OpenCnt
== 0)
228 KPRINTF(5, ("devExpunge: Unloading...\n"));
230 CloseLibrary(base
->np_UtilityBase
);
232 ret
= base
->np_SegList
;
234 KPRINTF(5, ("devExpunge: removing device node 0x%08lx\n",
235 &base
->np_Library
.lib_Node
));
236 Remove(&base
->np_Library
.lib_Node
);
238 KPRINTF(5, ("devExpunge: FreeMem()...\n"));
239 FreeMem((char *) base
- base
->np_Library
.lib_NegSize
,
240 (ULONG
) (base
->np_Library
.lib_NegSize
+ base
->np_Library
.lib_PosSize
));
242 KPRINTF(5, ("devExpunge: Unloading done! " DEVNAME
" expunged!\n\n"));
248 KPRINTF(5, ("devExpunge: Could not expunge, LIBF_DELEXP set!\n"));
249 base
->np_Library
.lib_Flags
|= LIBF_DELEXP
;
257 AROS_LH0(DEVBASETYPEPTR
, devReserved
,
258 DEVBASETYPEPTR
, base
, 4, dev
)
267 *======================================================================
268 * cmdRead(ioreq, base)
269 *======================================================================
271 * This is the device CMD_READ routine.
273 * First it check if nic is in proper state and if user passed arguments
274 * are valid. If everything is ok, the request is linked to queue of
275 * pending read requests.
277 * The request is replied only when packet matching it's ios2_PacketType
278 * arrive, or if user abort the request with AbortIO().
282 WORD
cmdRead(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
284 struct BufMan
*bufman
;
285 KPRINTF(1, ("CMD_READ ioreq: 0x%08lx type: %lu\n", ioreq
, ioreq
->ios2_PacketType
));
288 if(!(ncp
->ncp_StateFlags
& DDF_CONFIGURED
))
290 return deverror(S2ERR_BAD_STATE
, S2WERR_NOT_CONFIGURED
);
294 if(!(ncp
->ncp_StateFlags
& DDF_ONLINE
))
296 return deverror(S2ERR_OUTOFSERVICE
, S2WERR_UNIT_OFFLINE
);
299 /* Valid bufman? Got copytobuf routine? */
300 bufman
= ioreq
->ios2_BufferManagement
;
301 if((!bufman
) || (!bufman
->bm_CopyToBuf
))
303 return deverror(S2ERR_BAD_ARGUMENT
, S2WERR_NULL_POINTER
);
307 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
309 /* Add to this ioreq's bufman rxqueue */
311 AddTail((struct List
*) &bufman
->bm_RXQueue
, (struct Node
*) ioreq
);
313 /* Don't reply the ioreq, it's pending
320 *======================================================================
321 * cmdWrite(ioreq, base)
322 *======================================================================
324 * This is the device CMD_WRITE routine.
326 * First it check if nic is in proper state and if user passed arguments
327 * are valid. If everything is ok, the request is linked to queue of
328 * pending write requests.
330 * The request is replied as soon as the write has been processed or if
331 * user abort the request with AbortIO().
335 WORD
cmdWrite(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
337 struct BufMan
*bufman
;
340 KPRINTF(1, ("CMD_WRITE ioreq: 0x%08lx type: %lu len: %lu\n",
341 ioreq
, ioreq
->ios2_PacketType
, ioreq
->ios2_DataLength
));
344 if(!(ncp
->ncp_StateFlags
& DDF_CONFIGURED
))
346 return deverror(S2ERR_BAD_STATE
, S2WERR_NOT_CONFIGURED
);
350 if(!(ncp
->ncp_StateFlags
& DDF_ONLINE
))
352 return deverror(S2ERR_OUTOFSERVICE
, S2WERR_UNIT_OFFLINE
);
355 /* Valid bufman? got copyfrombuf routine? */
356 bufman
= ioreq
->ios2_BufferManagement
;
357 if((!bufman
) || (!bufman
->bm_CopyFromBuf
))
359 return deverror(S2ERR_BAD_ARGUMENT
, S2WERR_NULL_POINTER
);
362 /* Check packet size */
363 size
= (ioreq
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) ? RAWPKT_SIZE
: ETHERPKT_SIZE
;
364 if(ioreq
->ios2_DataLength
> size
)
366 /* Trigger any tx or generic error events */
367 nDoEvent(ncp
, S2EVENT_ERROR
|S2EVENT_TX
);
368 return deverror(S2ERR_MTU_EXCEEDED
, S2WERR_GENERIC_ERROR
);
372 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
374 AddTail(&ncp
->ncp_WriteQueue
, &ioreq
->ios2_Req
.io_Message
.mn_Node
);
375 if(ncp
->ncp_Unit
.unit_MsgPort
.mp_SigTask
)
377 Signal(ncp
->ncp_Unit
.unit_MsgPort
.mp_SigTask
, 1L<<(ncp
->ncp_Unit
.unit_MsgPort
.mp_SigBit
));
380 /* Don't reply the ioreq, it's pending */
386 *======================================================================
387 * cmdFlush(ioreq, base)
388 *======================================================================
390 * This is the device CMD_FLUSH routine.
392 * This routine abort all pending read, write and event requests.
396 WORD
cmdFlush(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
398 struct BufMan
*bufman
;
400 KPRINTF(1, ("CMD_FLUSH ioreq: 0x%08lx\n", ioreq
));
402 bufman
= ioreq
->ios2_BufferManagement
;
406 AbortRW(ncp
, bufman
, deverror(IOERR_ABORTED
, S2WERR_GENERIC_ERROR
));
407 AbortList(ncp
, &ncp
->ncp_EventList
, bufman
, deverror(IOERR_ABORTED
, S2WERR_GENERIC_ERROR
));
417 *======================================================================
418 * cmdDeviceQuery(ioreq, base)
419 *======================================================================
421 * This is the device S2_DEVICEQUERY routine.
423 * This routine return various parameters for this network interface.
428 const struct Sana2DeviceQuery DeviceQueryBlock
[] =
431 sizeof(struct Sana2DeviceQuery
), sizeof(struct Sana2DeviceQuery
),
441 WORD
cmdDeviceQuery(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
443 struct Sana2DeviceQuery
*query
;
445 KPRINTF(1, ("S2_DEVICEQUERY ioreq: 0x%08lx\n", ioreq
));
448 query
= (struct Sana2DeviceQuery
*) ioreq
->ios2_StatData
;
451 return deverror(S2ERR_BAD_ARGUMENT
, S2WERR_NULL_POINTER
);
454 /* Enough space to store the info ? */
455 if(query
->SizeAvailable
< sizeof(struct Sana2DeviceQuery
))
457 KPRINTF(1, ("S2_DEVICEQUERY: too small buffer supplied! (%lu / %lu)\n",
458 query
->SizeAvailable
, sizeof(struct Sana2DeviceQuery
)));
460 query
->SizeSupplied
= 0;
461 return deverror(S2ERR_BAD_ARGUMENT
, S2WERR_BAD_STATDATA
);
464 CopyMem(&((struct Sana2DeviceQuery
*) DeviceQueryBlock
)->SizeSupplied
, &query
->SizeSupplied
, sizeof(struct Sana2DeviceQuery
) - sizeof(ULONG
));
471 *======================================================================
472 * cmdGetStationAddress(ioreq, base)
473 *======================================================================
475 * This is the device S2_GETSTATIONADDRESS routine.
477 * This routine return current and default interface hardware addresses.
481 WORD
cmdGetStationAddress(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
485 KPRINTF(1, ("S2_GETSTATIONADDRESS ioreq: 0x%08lx\n", ioreq
));
487 /* Source address = current station address
488 Dest address = default station address
490 for(cnt
= 0; cnt
< ETHER_ADDR_SIZE
; cnt
++)
492 ioreq
->ios2_SrcAddr
[cnt
] = ncp
->ncp_MacAddress
[cnt
];
493 ioreq
->ios2_DstAddr
[cnt
] = ncp
->ncp_ROMAddress
[cnt
];
497 for(; cnt
< SANA2_MAX_ADDR_BYTES
; cnt
++)
499 ioreq
->ios2_SrcAddr
[cnt
] = 0;
500 ioreq
->ios2_DstAddr
[cnt
] = 0;
507 WORD
cmdConfigInterface(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
511 KPRINTF(1, ("S2_CONFIGINTERFACE ioreq: 0x%08lx\n", ioreq
));
513 /* This stuff must be atomic */
515 if(ncp
->ncp_StateFlags
& DDF_CONFIGURED
)
518 /* Error, already configured */
519 return deverror(S2ERR_BAD_STATE
, S2WERR_IS_CONFIGURED
);
522 /* Check for valid address */
523 if(ioreq
->ios2_SrcAddr
[0] & 0x80)
526 return deverror(S2ERR_BAD_ADDRESS
, S2WERR_SRC_ADDRESS
);
529 /* Copy the address */
530 for(cnt
= 0; cnt
< ETHER_ADDR_SIZE
; cnt
++)
532 ncp
->ncp_MacAddress
[cnt
] = ioreq
->ios2_SrcAddr
[cnt
];
536 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
537 PutMsg(&ncp
->ncp_Unit
.unit_MsgPort
, (struct Message
*) ioreq
);
539 /* Don't reply the ioreq, it's pending */
544 WORD
cmdAddMulticastAddress(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
547 KPRINTF(1, ("S2_ADDMULTICASTADDRESS 0x%08lx%04lx\n",
548 ((ULONG
*) ioreq
->ios2_SrcAddr
)[0], ((UWORD
*) ioreq
->ios2_SrcAddr
)[2]));
550 return AddMCastRange(ncp
, ioreq
, ioreq
->ios2_SrcAddr
, ioreq
->ios2_SrcAddr
);
553 WORD
cmdDelMulticastAddress(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
555 KPRINTF(1, ("S2_DELMULTICASTADDRESS 0x%08lx%04lx\n",
556 ((ULONG
*) ioreq
->ios2_SrcAddr
)[0], ((UWORD
*) ioreq
->ios2_SrcAddr
)[2]));
558 return DelMCastRange(ncp
, ioreq
, ioreq
->ios2_SrcAddr
, ioreq
->ios2_SrcAddr
);
561 WORD
cmdAddMulticastAddresses(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
563 KPRINTF(1, ("S2_ADDMULTICASTADDRESSES 0x%08lx%04lx - 0x%08lx%04lx\n",
564 ((ULONG
*) ioreq
->ios2_SrcAddr
)[0], ((UWORD
*) ioreq
->ios2_SrcAddr
)[2],
565 ((ULONG
*) ioreq
->ios2_DstAddr
)[0], ((UWORD
*) ioreq
->ios2_DstAddr
)[2]));
567 return AddMCastRange(ncp
, ioreq
, ioreq
->ios2_SrcAddr
, ioreq
->ios2_DstAddr
);
570 WORD
cmdDelMulticastAddresses(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
572 KPRINTF(1, ("S2_DELMULTICASTADDRESSES 0x%08lx%04lx - 0x%08lx%04lx\n",
573 ((ULONG
*) ioreq
->ios2_SrcAddr
)[0], ((UWORD
*) ioreq
->ios2_SrcAddr
)[2],
574 ((ULONG
*) ioreq
->ios2_DstAddr
)[0], ((UWORD
*) ioreq
->ios2_DstAddr
)[2]));
576 return DelMCastRange(ncp
, ioreq
, ioreq
->ios2_SrcAddr
, ioreq
->ios2_DstAddr
);
579 #define mcmp(a,b) (memcmp(a,b,ETHER_ADDR_SIZE)==0)
581 WORD
AddMCastRange(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
, UBYTE
*lower
, UBYTE
*upper
)
583 struct MulticastAddressRange
*mar
;
586 /* Valid multicast addresses? */
587 if(((lower
[0] & 1) == 0) || ((upper
[0] & 1) == 0))
589 return deverror(S2ERR_BAD_ADDRESS
, S2WERR_BAD_MULTICAST
);
592 /* Lock access to list */
595 /* Find matching node */
596 mar
= (struct MulticastAddressRange
*) ncp
->ncp_Multicasts
.lh_Head
;
597 while(mar
->mar_Node
.ln_Succ
)
599 if(mcmp(lower
, mar
->mar_LowerAddr
) &&
600 mcmp(upper
, mar
->mar_UpperAddr
))
604 mar
= (struct MulticastAddressRange
*) mar
->mar_Node
.ln_Succ
;
607 if(!mar
->mar_Node
.ln_Succ
)
610 mar
= AllocVec(sizeof(struct MulticastAddressRange
), MEMF_CLEAR
|MEMF_PUBLIC
);
614 return deverror(S2ERR_NO_RESOURCES
, S2WERR_GENERIC_ERROR
);
616 for(cnt
= 0; cnt
< ETHER_ADDR_SIZE
; cnt
++)
618 mar
->mar_LowerAddr
[cnt
] = *lower
++;
619 mar
->mar_UpperAddr
[cnt
] = *upper
++;
621 mar
->mar_UseCount
= 1;
622 AddTail(&ncp
->ncp_Multicasts
, (struct Node
*) mar
);
626 UpdateMulticastHash(ncp
);
629 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
630 PutMsg(&ncp
->ncp_Unit
.unit_MsgPort
, (struct Message
*) ioreq
);
632 /* Don't reply the ioreq, it's pending */
642 WORD
DelMCastRange(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
, UBYTE
*lower
, UBYTE
*upper
)
644 struct MulticastAddressRange
*mar
;
646 /* Lock access to list */
649 /* Find matching node */
650 mar
= (struct MulticastAddressRange
*) ncp
->ncp_Multicasts
.lh_Head
;
651 while(mar
->mar_Node
.ln_Succ
)
653 if(mcmp(lower
, mar
->mar_LowerAddr
) &&
654 mcmp(upper
, mar
->mar_UpperAddr
))
656 if(!--mar
->mar_UseCount
)
658 Remove((struct Node
*) mar
);
662 UpdateMulticastHash(ncp
);
664 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
665 PutMsg(&ncp
->ncp_Unit
.unit_MsgPort
, (struct Message
*) ioreq
);
667 /* Don't reply the ioreq, it's pending */
673 mar
= (struct MulticastAddressRange
*) mar
->mar_Node
.ln_Succ
;
677 /* Return with failure */
678 return deverror(S2ERR_BAD_STATE
, S2WERR_BAD_MULTICAST
);
682 *===========================================================================
683 * Calculate 32 bit crc
684 *===========================================================================
686 * - for each bit: if (crcbit=1 XOR databit=1) then crc=(crc XOR polynomial).
687 * - polynomial is correct when data bits range 0-x, crc bits range 31-0.
688 * - crc wraps at 32 bits.
690 * crc = calc_crc(addr)
693 #define CRC_MASK 0x04c11db7U
695 ULONG
ether_crc(LONG length
, UBYTE
*data
)
708 for(bit
= 0; bit
< 8; bit
++, c
>>= 1)
710 crc
= (crc
<< 1) ^ (((crc
< 0) ^ (c
& 1)) ? CRC_MASK
: 0);
718 *================================================================
720 *================================================================
722 * calculate multicast hash table and send it to nic
725 * as of 1.2beta4 multicasts can be a address range, also single
726 * addresses are defined with lower = upper.
728 * multicasts list must be locked!
730 *==============================================================
731 * hash multicast address
732 *==============================================================
733 * The nic does not compare multicast addresses directly, but
734 * instead uses a bitfield of 64 bits - each bit corresponds
735 * to a 6 bit hash code for the multicast address. If the bit
736 * is set then any multicast address that matches the hash code
739 * The hash code is generated by taking the upper 6 bits of the
740 * 32 bit crc of the multicast address.
743 void UpdateMulticastHash(struct NepClassEth
*ncp
)
745 struct MulticastAddressRange
*mar
;
746 UBYTE addr
[ETHER_ADDR_SIZE
];
748 KPRINTF(1, ("nic_update_multicasts\n"));
750 /* Is promiscuous mode? */
751 if(ncp
->ncp_OpenFlags
& SANA2OPF_PROM
)
753 /* "Promiscuous Physical." ... "In addition, the multicast hashing
754 array must be set to all 1's so that all multicast addresses are
756 memset(ncp
->ncp_MulticastArray
, 0xff, sizeof(ncp
->ncp_MulticastArray
));
758 /* Clear all multicast bits */
759 memset(ncp
->ncp_MulticastArray
, 0x00, sizeof(ncp
->ncp_MulticastArray
));
760 mar
= (struct MulticastAddressRange
*) ncp
->ncp_Multicasts
.lh_Head
;
761 while(mar
->mar_Node
.ln_Succ
)
763 memcpy(addr
, mar
->mar_LowerAddr
, ETHER_ADDR_SIZE
);
767 hash
= ether_crc(ETHER_ADDR_SIZE
, addr
) >> 26;
768 ncp
->ncp_MulticastArray
[hash
>>3] |= 1<<(hash
& 7);
769 if(mcmp(addr
, mar
->mar_UpperAddr
))
780 mar
= (struct MulticastAddressRange
*) mar
->mar_Node
.ln_Succ
;
785 WORD
cmdMulticast(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
787 KPRINTF(1, ("S2_MULTICAST ioreq: 0x%08lx to: 0x%08lx%04lx\n",
789 ((ULONG
*) ioreq
->ios2_DstAddr
)[0], ((UWORD
*) ioreq
->ios2_DstAddr
)[2]));
791 /* Is dest a multicast address? */
792 if(ioreq
->ios2_DstAddr
[0] & 1)
794 return cmdWrite(ncp
, ioreq
);
797 /* Trigger any tx or generic error events */
798 nDoEvent(ncp
, S2EVENT_ERROR
|S2EVENT_TX
);
800 /* Wasn't a multicast addr */
801 return deverror(S2ERR_BAD_ADDRESS
, S2WERR_BAD_MULTICAST
);
804 WORD
cmdBroadcast(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
807 KPRINTF(1, ("S2_BROADCAST ioreq: 0x%08lx\n", ioreq
));
809 /* Dest address = broadcast */
810 for(cnt
= 0; cnt
< ETHER_ADDR_SIZE
; cnt
++)
812 ioreq
->ios2_DstAddr
[cnt
] = 0xff;
814 return cmdWrite(ncp
, ioreq
);
818 WORD
cmdTrackType(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
820 struct PacketTypeStats
*pts
;
822 KPRINTF(1, ("S2_TRACKTYPE ioreq: 0x%08lx type: %lu\n",
823 ioreq
, ioreq
->ios2_PacketType
));
826 /* Find matching node */
827 pts
= (struct PacketTypeStats
*) ncp
->ncp_TrackList
.lh_Head
;
828 while(pts
->pts_Node
.ln_Succ
)
830 /* Our packet type? */
831 if(pts
->pts_PacketType
== ioreq
->ios2_PacketType
)
834 return deverror(S2ERR_BAD_STATE
, S2WERR_ALREADY_TRACKED
);
836 pts
= (struct PacketTypeStats
*) pts
->pts_Node
.ln_Succ
;
839 /* Alloc tracking node */
840 pts
= (struct PacketTypeStats
*) AllocVec(sizeof(struct PacketTypeStats
), MEMF_CLEAR
|MEMF_PUBLIC
);
843 return deverror(S2ERR_NO_RESOURCES
, S2WERR_NOT_TRACKED
);
845 /* Set up tracking node */
846 pts
->pts_PacketType
= ioreq
->ios2_PacketType
;
848 /* Add the new node to tracklist */
849 AddTail((struct List
*) &ncp
->ncp_TrackList
, (struct Node
*) pts
);
851 if(pts
->pts_PacketType
== 2048)
853 ncp
->ncp_TypeStats2048
= &pts
->pts_Stats
;
855 else if(pts
->pts_PacketType
== 2054)
857 ncp
->ncp_TypeStats2054
= &pts
->pts_Stats
;
866 WORD
cmdUntrackType(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
868 struct PacketTypeStats
*pts
;
869 KPRINTF(1, ("S2_UNTRACKTYPE ioreq: 0x%08lx type: %lu\n",
870 ioreq
, ioreq
->ios2_PacketType
));
873 /* Find matching node */
874 pts
= (struct PacketTypeStats
*) ncp
->ncp_TrackList
.lh_Head
;
875 while(pts
->pts_Node
.ln_Succ
)
877 /* Our packet type? */
878 if(pts
->pts_PacketType
== ioreq
->ios2_PacketType
)
880 Remove(&pts
->pts_Node
);
882 if(pts
->pts_PacketType
== 2048)
884 ncp
->ncp_TypeStats2048
= NULL
;
886 else if(pts
->pts_PacketType
== 2054)
888 ncp
->ncp_TypeStats2054
= NULL
;
895 pts
= (struct PacketTypeStats
*) pts
->pts_Node
.ln_Succ
;
899 return deverror(S2ERR_BAD_STATE
, S2WERR_NOT_TRACKED
);
903 WORD
cmdGetTypeStats(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
905 struct Sana2PacketTypeStats
*tostats
;
906 struct Sana2PacketTypeStats
*fromstats
;
908 KPRINTF(1, ("S2_GETTYPESTATS ioreq: 0x%08lx type: %lu\n",
909 ioreq
, ioreq
->ios2_PacketType
));
912 tostats
= (struct Sana2PacketTypeStats
*) ioreq
->ios2_StatData
;
915 return deverror(S2ERR_BAD_ARGUMENT
, S2WERR_NULL_POINTER
);
919 fromstats
= FindPacketTypeStats(ncp
, ioreq
->ios2_PacketType
);
923 CopyMem(fromstats
, tostats
, sizeof(struct Sana2PacketTypeStats
));
932 return deverror(S2ERR_BAD_STATE
, S2WERR_NOT_TRACKED
);
936 WORD
cmdGetSpecialStats(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
938 struct Sana2SpecialStatHeader
*stats
;
939 struct Sana2SpecialStatRecord
*record
;
942 KPRINTF(1, ("S2_GETSPECIALSTATS ioreq: 0x%08lx\n", ioreq
));
945 stats
= (struct Sana2SpecialStatHeader
*) ioreq
->ios2_StatData
;
948 return deverror(S2ERR_BAD_ARGUMENT
, S2WERR_NULL_POINTER
);
951 stats
->RecordCountSupplied
= 0;
952 maxcount
= stats
->RecordCountMax
;
953 record
= (struct Sana2SpecialStatRecord
*) (stats
+ 1);
957 stats
->RecordCountSupplied
++;
959 record
->Type
= S2SS_ETHERNET_BADMULTICAST
;
960 record
->Count
= ncp
->ncp_BadMulticasts
;
961 record
->String
= "bad multicasts";
966 stats
->RecordCountSupplied
++;
968 record
->Type
= S2SS_ETHERNET_RETRIES
;
969 record
->Count
= ncp
->ncp_Retries
;
970 record
->String
= "retries";
980 WORD
cmdGetGlobalStats(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
982 struct Sana2DeviceStats
*stats
;
984 KPRINTF(1, ("S2_GETGLOBALSTATS ioreq: 0x%08lx\n", ioreq
));
987 stats
= (struct Sana2DeviceStats
*) ioreq
->ios2_StatData
;
990 return deverror(S2ERR_BAD_ARGUMENT
, S2WERR_NULL_POINTER
);
993 CopyMem(&ncp
->ncp_DeviceStats
, stats
, sizeof(struct Sana2DeviceStats
));
1000 #define KNOWN_EVENTS (S2EVENT_ERROR | \
1008 WORD
cmdOnEvent(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
1010 KPRINTF(1, ("S2_ONEVENT ioreq: 0x%08lx mask: 0x%08lx\n", ioreq
,
1011 ioreq
->ios2_WireError
));
1013 /* Do we know the requested events? */
1014 if(ioreq
->ios2_WireError
& (~KNOWN_EVENTS
))
1016 return deverror(S2ERR_NOT_SUPPORTED
, S2WERR_BAD_EVENT
);
1019 /* If online return S2EVENT_ONLINE immediately
1020 If offline return S2EVENT_OFFLINE immediately. */
1021 if(ncp
->ncp_StateFlags
& DDF_ONLINE
)
1023 if(ioreq
->ios2_WireError
& S2EVENT_ONLINE
)
1025 ioreq
->ios2_WireError
= S2EVENT_ONLINE
;
1027 /* Return success */
1031 if(ioreq
->ios2_WireError
& S2EVENT_OFFLINE
)
1033 ioreq
->ios2_WireError
= S2EVENT_OFFLINE
;
1035 /* Return success */
1040 /* Must be queued */
1041 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
1043 /* Queue the ioreq */
1045 AddTail((struct List
*) &ncp
->ncp_EventList
, (struct Node
*) ioreq
);
1048 /* Don't reply the ioreq, it's pending */
1049 return RC_DONTREPLY
;
1053 WORD
cmdReadOrphan(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
1055 struct BufMan
*bufman
;
1057 KPRINTF(1, ("S2_READORPHAN ioreq: 0x%08lx type: %lu\n", ioreq
,
1058 ioreq
->ios2_PacketType
));
1061 if(!(ncp
->ncp_StateFlags
& DDF_CONFIGURED
))
1063 return deverror(S2ERR_BAD_STATE
, S2WERR_NOT_CONFIGURED
);
1067 if(!(ncp
->ncp_StateFlags
& DDF_ONLINE
))
1069 return deverror(S2ERR_OUTOFSERVICE
, S2WERR_UNIT_OFFLINE
);
1072 /* Valid bufman? got copytobuf routine? */
1073 bufman
= ioreq
->ios2_BufferManagement
;
1074 if((!bufman
) || (!bufman
->bm_CopyToBuf
))
1076 return deverror(S2ERR_BAD_ARGUMENT
, S2WERR_NULL_POINTER
);
1079 /* Must be queued */
1080 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
1082 /* Queue the ioreq */
1084 AddTail((struct List
*) &ncp
->ncp_OrphanQueue
, (struct Node
*) ioreq
);
1087 /* Don't reply the ioreq, it's pending */
1088 return RC_DONTREPLY
;
1092 WORD
cmdOnline(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
1094 KPRINTF(1, ("S2_ONLINE ioreq: 0x%08lx\n", ioreq
));
1097 /* Already online? */
1098 if(!(ncp
->ncp_StateFlags
& DDF_ONLINE
))
1101 if(!(ncp
->ncp_StateFlags
& DDF_CONFIGURED
))
1104 return deverror(S2ERR_BAD_STATE
, S2WERR_NOT_CONFIGURED
);
1107 /* Mark no longer offline */
1108 ncp
->ncp_StateFlags
&= ~DDF_OFFLINE
;
1110 /* Must be queued */
1111 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
1112 PutMsg(&ncp
->ncp_Unit
.unit_MsgPort
, (struct Message
*) ioreq
);
1115 /* Don't reply the ioreq, it's pending */
1116 return RC_DONTREPLY
;
1120 /* Return success */
1125 WORD
cmdOffline(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
1128 KPRINTF(1, ("S2_OFFLINE ioreq: 0x%08lx\n", ioreq
));
1131 /* Mark being offline */
1132 ncp
->ncp_StateFlags
|= DDF_OFFLINE
;
1134 /* Already offline? */
1135 if(ncp
->ncp_StateFlags
& DDF_ONLINE
)
1137 /* Mark no longer online */
1138 ncp
->ncp_StateFlags
&= ~DDF_ONLINE
;
1140 /* *DO NOT* abort pending read & write requests.
1141 Miami dies a horrible death if this is enabled!
1143 if(ioreq
->ios2_BufferManagement
)
1145 AbortRW(ncp
, ioreq
->ios2_BufferManagement
, deverror(S2ERR_OUTOFSERVICE
, S2WERR_UNIT_OFFLINE
));
1148 /* Trigger any OFFLINE events */
1149 nDoEvent(ncp
, S2EVENT_OFFLINE
);
1151 /* Must be queued */
1152 ioreq
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
1153 PutMsg(&ncp
->ncp_Unit
.unit_MsgPort
, (struct Message
*) ioreq
);
1155 /* Don't reply the ioreq, it's pending */
1156 return RC_DONTREPLY
;
1160 /* Return success */
1165 AROS_LH1(void, devBeginIO
,
1166 AROS_LHA(struct IOSana2Req
*, ioreq
, A1
),
1167 DEVBASETYPEPTR
, base
, 5, dev
)
1171 struct NepClassEth
*ncp
= (struct NepClassEth
*) ioreq
->ios2_Req
.io_Unit
;
1172 WORD ret
= IOERR_NOCMD
;
1174 KPRINTF(1, ("devBeginIO ioreq: 0x%08lx base: 0x%08lx cmd: %lu\n", ioreq
, base
, ioreq
->ios2_Req
.io_Command
));
1176 ioreq
->ios2_Req
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
1177 ioreq
->ios2_Req
.io_Error
= 0;
1179 if(ioreq
->ios2_Req
.io_Command
< NSCMD_DEVICEQUERY
)
1181 switch(ioreq
->ios2_Req
.io_Command
)
1184 ret
= cmdRead(ncp
, ioreq
);
1188 ret
= cmdFlush(ncp
, ioreq
);
1192 ret
= cmdWrite(ncp
, ioreq
);
1195 case S2_GETSTATIONADDRESS
:
1196 ret
= cmdGetStationAddress(ncp
, ioreq
);
1199 case S2_DEVICEQUERY
:
1200 ret
= cmdDeviceQuery(ncp
, ioreq
);
1203 case S2_CONFIGINTERFACE
:
1204 ret
= cmdConfigInterface(ncp
, ioreq
);
1207 case S2_ADDMULTICASTADDRESS
:
1208 ret
= cmdAddMulticastAddress(ncp
, ioreq
);
1211 case S2_DELMULTICASTADDRESS
:
1212 ret
= cmdDelMulticastAddress(ncp
, ioreq
);
1216 ret
= cmdMulticast(ncp
, ioreq
);
1220 ret
= cmdBroadcast(ncp
, ioreq
);
1224 ret
= cmdTrackType(ncp
, ioreq
);
1227 case S2_UNTRACKTYPE
:
1228 ret
= cmdUntrackType(ncp
, ioreq
);
1231 case S2_GETTYPESTATS
:
1232 ret
= cmdGetTypeStats(ncp
, ioreq
);
1235 case S2_GETSPECIALSTATS
:
1236 ret
= cmdGetSpecialStats(ncp
, ioreq
);
1239 case S2_GETGLOBALSTATS
:
1240 ret
= cmdGetGlobalStats(ncp
, ioreq
);
1244 ret
= cmdOnEvent(ncp
, ioreq
);
1248 ret
= cmdReadOrphan(ncp
, ioreq
);
1252 ret
= cmdOnline(ncp
, ioreq
);
1256 ret
= cmdOffline(ncp
, ioreq
);
1264 switch(ioreq
->ios2_Req
.io_Command
)
1266 case NSCMD_DEVICEQUERY
:
1267 ret
= cmdNSDeviceQuery(ncp
, (struct IOStdReq
*) ioreq
);
1270 case S2_ADDMULTICASTADDRESSES
:
1271 ret
= cmdAddMulticastAddresses(ncp
, ioreq
);
1274 case S2_DELMULTICASTADDRESSES
:
1275 ret
= cmdDelMulticastAddresses(ncp
, ioreq
);
1284 if(ret
!= RC_DONTREPLY
)
1286 KPRINTF(1, ("TermIO\n"));
1289 /* Set error codes */
1290 ioreq
->ios2_Req
.io_Error
= ret
& 0xff;
1292 /* Terminate the iorequest */
1299 AROS_LH1(LONG
, devAbortIO
,
1300 AROS_LHA(struct IOSana2Req
*, ioreq
, A1
),
1301 DEVBASETYPEPTR
, base
, 6, dev
)
1305 struct NepClassEth
*ncp
= (struct NepClassEth
*) ioreq
->ios2_Req
.io_Unit
;
1306 struct BufMan
*worknode
, *nextnode
;
1308 KPRINTF(5, ("devAbortIO ioreq: 0x%08lx\n", ioreq
));
1310 /* Is it pending? */
1312 if(ioreq
->ios2_Req
.io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
1315 switch (ioreq
->ios2_Req
.io_Command
)
1318 /* Check all nodes in dd_bufmanlist until we succeed to abort or run out of nodes. */
1319 worknode
= (struct BufMan
*) ncp
->ncp_BufManList
.lh_Head
;
1320 while((nextnode
= (struct BufMan
*) (((struct Node
*) worknode
)->ln_Succ
)))
1322 if(AbortReq(ncp
, &worknode
->bm_RXQueue
, ioreq
) == S2ERR_NO_ERROR
)
1324 /* Success, break out */
1327 worknode
= nextnode
;
1332 AbortReq(ncp
, &ncp
->ncp_OrphanQueue
, ioreq
);
1338 AbortReq(ncp
, &ncp
->ncp_WriteQueue
, ioreq
);
1341 // these commands may dispatch their ioreq to the USB task; catch from the message port
1344 case S2_CONFIGINTERFACE
:
1345 case S2_ADDMULTICASTADDRESS
:
1346 case S2_DELMULTICASTADDRESS
:
1347 case S2_ADDMULTICASTADDRESSES
:
1348 case S2_DELMULTICASTADDRESSES
:
1349 AbortReq(ncp
, &ncp
->ncp_Unit
.unit_MsgPort
.mp_MsgList
, ioreq
);
1353 AbortReq(ncp
, &ncp
->ncp_EventList
, ioreq
);
1357 KPRINTF(1, ("devAbortIO: not READ, READORPHAN, WRITE, MULTICAST, BROADCAST or ONEVENT\n"));
1371 const UWORD NSDSupported
[] =
1373 CMD_FLUSH
, CMD_READ
, CMD_WRITE
,
1375 S2_GETSTATIONADDRESS
,
1377 S2_ADDMULTICASTADDRESS
, S2_DELMULTICASTADDRESS
,
1378 S2_MULTICAST
, S2_BROADCAST
,
1379 S2_TRACKTYPE
, S2_UNTRACKTYPE
,
1380 S2_GETTYPESTATS
, S2_GETSPECIALSTATS
, S2_GETGLOBALSTATS
,
1383 S2_ONLINE
, S2_OFFLINE
,
1385 S2_ADDMULTICASTADDRESSES
, S2_DELMULTICASTADDRESSES
,
1389 WORD
cmdNSDeviceQuery(struct NepClassEth
*ncp
, struct IOStdReq
*ioreq
)
1391 struct my_NSDeviceQueryResult
*query
;
1393 query
= (struct my_NSDeviceQueryResult
*) ioreq
->io_Data
;
1395 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%08lx query: 0x%08lx\n", ioreq
, query
));
1402 (ioreq
->io_Length
< sizeof(struct my_NSDeviceQueryResult
)) ||
1403 (query
->DevQueryFormat
!= 0) ||
1404 (query
->SizeAvailable
!= 0))
1406 /* Return error. This is special handling, since iorequest is only
1407 guaranteed to be sizeof(struct IOStdReq). If we'd let our
1408 devBeginIO dispatcher return the error, it would trash some
1409 memory past end of the iorequest (ios2_WireError field).
1411 ioreq
->io_Error
= IOERR_NOCMD
;
1412 TermIO(ncp
, (struct IOSana2Req
*) ioreq
);
1414 /* Don't reply, we already did.
1416 return RC_DONTREPLY
;
1419 ioreq
->io_Actual
= query
->SizeAvailable
1420 = sizeof(struct my_NSDeviceQueryResult
);
1421 query
->DeviceType
= NSDEVTYPE_SANA2
;
1422 query
->DeviceSubType
= 0;
1423 query
->SupportedCommands
= NSDSupported
;
1425 /* Return success (note that this will NOT poke ios2_WireError).
1431 *======================================================================
1432 * AbortReq(list, ioreq, base)
1433 *======================================================================
1435 * Locate an IO request in a linked list and abort it if found.
1439 LONG
AbortReq(struct NepClassEth
*ncp
, struct List
*list
, struct IOSana2Req
*ioreq
)
1443 for(node
= list
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
1445 if(node
== (struct Node
*) ioreq
)
1447 //KPRINTF(1, ("AbortReq: aborted 0x%08lx\n", ioreq));
1449 Remove(&ioreq
->ios2_Req
.io_Message
.mn_Node
);
1450 ioreq
->ios2_Req
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
1451 ioreq
->ios2_Req
.io_Error
= IOERR_ABORTED
;
1452 ReplyMsg(&ioreq
->ios2_Req
.io_Message
);
1454 return S2ERR_NO_ERROR
;
1458 return S2ERR_BAD_STATE
;
1464 *===========================================================
1465 * TermIO(ioreq, base)
1466 *===========================================================
1468 * Return completed ioreq to sender.
1472 void TermIO(struct NepClassEth
*ncp
, struct IOSana2Req
*ioreq
)
1474 ioreq
->ios2_Req
.io_Message
.mn_Node
.ln_Type
= NT_FREEMSG
;
1476 /* If not quick I/O, reply the message
1478 if(!(ioreq
->ios2_Req
.io_Flags
& IOF_QUICK
))
1480 ReplyMsg(&ioreq
->ios2_Req
.io_Message
);
1485 *======================================================================
1486 * AbortList(list, bufman, error, base)
1487 *======================================================================
1489 * Aborts all pending ioreqs in given list with io_Error & ios2_WireError
1492 * error is deverror() macro packed error number.
1496 void AbortList(struct NepClassEth
*ncp
, struct List
*list
, struct BufMan
*bufman
, WORD error
)
1498 struct IOSana2Req
*ioreq
, *nextioreq
;
1502 for(ioreq
= (struct IOSana2Req
*) list
->lh_Head
;
1503 (nextioreq
= (struct IOSana2Req
*) ioreq
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
);
1506 if(ioreq
->ios2_BufferManagement
== bufman
)
1508 Remove(&ioreq
->ios2_Req
.io_Message
.mn_Node
);
1509 /*ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;*/
1510 ioreq
->ios2_Req
.io_Error
= error
& 0xff;
1511 ioreq
->ios2_WireError
= error
>> 8;
1512 ReplyMsg(&ioreq
->ios2_Req
.io_Message
);
1518 while((ioreq
= (struct IOSana2Req
*) RemHead(list
)))
1520 /* ioreq->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;*/
1521 ioreq
->ios2_Req
.io_Error
= error
& 0xff;
1522 ioreq
->ios2_WireError
= error
>> 8;
1523 ReplyMsg(&ioreq
->ios2_Req
.io_Message
);
1530 *======================================================================
1531 * AbortRW(bufman, error, base)
1532 *======================================================================
1534 * Aborts all pending reads and writes with io_Error & ios2_WireError
1537 * error is deverror() macro packed error number.
1541 void AbortRW(struct NepClassEth
*ncp
, struct BufMan
*bufman
, WORD error
)
1543 AbortList(ncp
, &bufman
->bm_RXQueue
, NULL
, error
);
1544 AbortList(ncp
, &ncp
->ncp_OrphanQueue
, bufman
, error
);
1545 AbortList(ncp
, &ncp
->ncp_WriteQueue
, bufman
, error
);
1548 struct Sana2PacketTypeStats
* FindPacketTypeStats(struct NepClassEth
*ncp
, ULONG packettype
)
1550 struct PacketTypeStats
*pts
;
1555 return ncp
->ncp_TypeStats2048
;
1559 return ncp
->ncp_TypeStats2054
;
1563 /* Find matching node - slowly */
1564 pts
= (struct PacketTypeStats
*) ncp
->ncp_TrackList
.lh_Head
;
1565 while(pts
->pts_Node
.ln_Succ
)
1567 /* Our packet type? */
1568 if(pts
->pts_PacketType
== packettype
)
1570 return &pts
->pts_Stats
;
1572 pts
= (struct PacketTypeStats
*) pts
->pts_Node
.ln_Succ
;