rioroute.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,045 行 · 第 1/3 页

C
1,045
字号
			 ** Send the ID (entry) to this RTA. The ID number is implicit as			 ** the offset into the table. It is worth noting at this stage			 ** that offset zero in the table contains the entries for the			 ** RTA with ID 1!!!!			 */			PktReplyP->Command = ROUTE_ALLOCATE;			PktReplyP->IDNum = ThisUnit + 1;			if (RtaType == TYPE_RTA16) {				if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE)					/*					 ** Adjust the phb and tx pkt dest_units for 2nd block of 8					 ** only if the RTA has ports associated (SLOT_IN_USE)					 */					RIOFixPhbs(p, HostP, ThisUnit2);				PktReplyP->IDNum2 = ThisUnit2 + 1;				rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2);			} else {				PktReplyP->IDNum2 = ROUTE_NO_ID;				rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum);			}			HostP->Copy("RT_ALLOCAT", PktReplyP->CommandText, 10);			RIOQueueCmdBlk(HostP, Rup, CmdBlkP);			/*			 ** If this is a freshly booted RTA, then we need to re-open			 ** the ports, if any where open, so that data may once more			 ** flow around the system!			 */			if ((HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) && (HostP->Mapping[ThisUnit].SysPort != NO_PORT)) {				/*				 ** look at the ports associated with this beast and				 ** see if any where open. If they was, then re-open				 ** them, using the info from the tty flags.				 */				for (port = 0; port < PORTS_PER_RTA; port++) {					PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort];					if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {						rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n");						rio_spin_lock_irqsave(&PortP->portSem, flags);						PortP->MagicFlags |= MAGIC_REBOOT;						rio_spin_unlock_irqrestore(&PortP->portSem, flags);					}				}				if (RtaType == TYPE_RTA16) {					for (port = 0; port < PORTS_PER_RTA; port++) {						PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort];						if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {							rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n");							rio_spin_lock_irqsave(&PortP->portSem, flags);							PortP->MagicFlags |= MAGIC_REBOOT;							rio_spin_unlock_irqrestore(&PortP->portSem, flags);						}					}				}			}			/*			 ** keep a copy of the module types!			 */			HostP->UnixRups[ThisUnit].ModTypes = Mod;			if (RtaType == TYPE_RTA16)				HostP->UnixRups[ThisUnit2].ModTypes = Mod;			/*			 ** If either of the modules on this unit is read-only or write-only			 ** or none-xprint, then we need to transfer that info over to the			 ** relevant ports.			 */			if (HostP->Mapping[ThisUnit].SysPort != NO_PORT) {				for (port = 0; port < PORTS_PER_MODULE; port++) {					p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;					p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];					p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;					p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];				}				if (RtaType == TYPE_RTA16) {					for (port = 0; port < PORTS_PER_MODULE; port++) {						p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;						p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];						p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;						p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];					}				}			}			/*			 ** Job done, get on with the interrupts!			 */			return 1;		}	}	/*	 ** There is no table entry for this RTA at all.	 **	 ** Lets check to see if we actually booted this unit - if not,	 ** then we reset it and it will go round the loop of being booted	 ** we can then worry about trying to fit it into the table.	 */	for (ThisUnit = 0; ThisUnit < HostP->NumExtraBooted; ThisUnit++)		if (HostP->ExtraUnits[ThisUnit] == RtaUniq)			break;	if (ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS) {		/*		 ** if the unit wasn't in the table, and the table wasn't full, then		 ** we reset the unit, because we didn't boot it.		 ** However, if the table is full, it could be that we did boot		 ** this unit, and so we won't reboot it, because it isn't really		 ** all that disasterous to keep the old bins in most cases. This		 ** is a rather tacky feature, but we are on the edge of reallity		 ** here, because the implication is that someone has connected		 ** 16+MAX_EXTRA_UNITS onto one host.		 */		static int UnknownMesgDone = 0;		if (!UnknownMesgDone) {			if (!p->RIONoMessage)				printk(KERN_DEBUG "rio: One or more unknown RTAs are being updated.\n");			UnknownMesgDone = 1;		}		PktReplyP->Command = ROUTE_FOAD;		HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7);	} else {		/*		 ** we did boot it (as an extra), and there may now be a table		 ** slot free (because of a delete), so we will try to make		 ** a tentative entry for it, so that the configurator can see it		 ** and fill in the details for us.		 */		if (RtaType == TYPE_RTA16) {			if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0) {				RIODefaultName(p, HostP, ThisUnit);				rio_fill_host_slot(ThisUnit, ThisUnit2, RtaUniq, HostP);			}		} else {			if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) {				RIODefaultName(p, HostP, ThisUnit);				rio_fill_host_slot(ThisUnit, 0, RtaUniq, HostP);			}		}		PktReplyP->Command = ROUTE_USED;		HostP->Copy("RT_USED", PktReplyP->CommandText, 7);	}	RIOQueueCmdBlk(HostP, Rup, CmdBlkP);	return 1;}void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit){	unsigned short link, port;	struct Port *PortP;	unsigned long flags;	int PortN = HostP->Mapping[unit].SysPort;	rio_dprintk(RIO_DEBUG_ROUTE, "RIOFixPhbs unit %d sysport %d\n", unit, PortN);	if (PortN != -1) {		unsigned short dest_unit = HostP->Mapping[unit].ID2;		/*		 ** Get the link number used for the 1st 8 phbs on this unit.		 */		PortP = p->RIOPortp[HostP->Mapping[dest_unit - 1].SysPort];		link = readw(&PortP->PhbP->link);		for (port = 0; port < PORTS_PER_RTA; port++, PortN++) {			unsigned short dest_port = port + 8;			u16 *TxPktP;			struct PKT *Pkt;			PortP = p->RIOPortp[PortN];			rio_spin_lock_irqsave(&PortP->portSem, flags);			/*			 ** If RTA is not powered on, the tx packets will be			 ** unset, so go no further.			 */			if (PortP->TxStart == 0) {				rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n");				rio_spin_unlock_irqrestore(&PortP->portSem, flags);				break;			}			/*			 ** For the second slot of a 16 port RTA, the driver needs to			 ** sort out the phb to port mappings. The dest_unit for this			 ** group of 8 phbs is set to the dest_unit of the accompanying			 ** 8 port block. The dest_port of the second unit is set to			 ** be in the range 8-15 (i.e. 8 is added). Thus, for a 16 port			 ** RTA with IDs 5 and 6, traffic bound for port 6 of unit 6			 ** (being the second map ID) will be sent to dest_unit 5, port			 ** 14. When this RTA is deleted, dest_unit for ID 6 will be			 ** restored, and the dest_port will be reduced by 8.			 ** Transmit packets also have a destination field which needs			 ** adjusting in the same manner.			 ** Note that the unit/port bytes in 'dest' are swapped.			 ** We also need to adjust the phb and rup link numbers for the			 ** second block of 8 ttys.			 */			for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) {				/*				 ** *TxPktP is the pointer to the transmit packet on the host				 ** card. This needs to be translated into a 32 bit pointer				 ** so it can be accessed from the driver.				 */				Pkt = (struct PKT *) RIO_PTR(HostP->Caddr, readw(TxPktP));				/*				 ** If the packet is used, reset it.				 */				Pkt = (struct PKT *) ((unsigned long) Pkt & ~PKT_IN_USE);				writeb(dest_unit, &Pkt->dest_unit);				writeb(dest_port, &Pkt->dest_port);			}			rio_dprintk(RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", readw(&PortP->PhbP->destination) & 0xff, (readw(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port);			writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination);			writew(link, &PortP->PhbP->link);			rio_spin_unlock_irqrestore(&PortP->portSem, flags);		}		/*		 ** Now make sure the range of ports to be serviced includes		 ** the 2nd 8 on this 16 port RTA.		 */		if (link > 3)			return;		if (((unit * 8) + 7) > readw(&HostP->LinkStrP[link].last_port)) {			rio_dprintk(RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7);			writew((unit * 8) + 7, &HostP->LinkStrP[link].last_port);		}	}}/*** Check to see if the new disconnection has isolated this unit.** If it has, then invalidate all its link information, and tell** the world about it. This is done to ensure that the configurator** only gets up-to-date information about what is going on.*/static int RIOCheckIsolated(struct rio_info *p, struct Host *HostP, unsigned int UnitId){	unsigned long flags;	rio_spin_lock_irqsave(&HostP->HostLock, flags);	if (RIOCheck(HostP, UnitId)) {		rio_dprintk(RIO_DEBUG_ROUTE, "Unit %d is NOT isolated\n", UnitId);		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);		return (0);	}	RIOIsolate(p, HostP, UnitId);	RIOSetChange(p);	rio_spin_unlock_irqrestore(&HostP->HostLock, flags);	return 1;}/*** Invalidate all the link interconnectivity of this unit, and of** all the units attached to it. This will mean that the entire** subnet will re-introduce itself.*/static int RIOIsolate(struct rio_info *p, struct Host *HostP, unsigned int UnitId){	unsigned int link, unit;	UnitId--;		/* this trick relies on the Unit Id being UNSIGNED! */	if (UnitId >= MAX_RUP)	/* dontcha just lurv unsigned maths! */		return (0);	if (HostP->Mapping[UnitId].Flags & BEEN_HERE)		return (0);	HostP->Mapping[UnitId].Flags |= BEEN_HERE;	if (p->RIOPrintDisabled == DO_PRINT)		rio_dprintk(RIO_DEBUG_ROUTE, "RIOMesgIsolated %s", HostP->Mapping[UnitId].Name);	for (link = 0; link < LINKS_PER_UNIT; link++) {		unit = HostP->Mapping[UnitId].Topology[link].Unit;		HostP->Mapping[UnitId].Topology[link].Unit = ROUTE_DISCONNECT;		HostP->Mapping[UnitId].Topology[link].Link = NO_LINK;		RIOIsolate(p, HostP, unit);	}	HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;	return 1;}static int RIOCheck(struct Host *HostP, unsigned int UnitId){	unsigned char link;/* 	rio_dprint(RIO_DEBUG_ROUTE, ("Check to see if unit %d has a route to the host\n",UnitId)); */	rio_dprintk(RIO_DEBUG_ROUTE, "RIOCheck : UnitID = %d\n", UnitId);	if (UnitId == HOST_ID) {		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated - it IS the host!\n", UnitId)); */		return 1;	}	UnitId--;	if (UnitId >= MAX_RUP) {		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d - ignored.\n", UnitId)); */		return 0;	}	for (link = 0; link < LINKS_PER_UNIT; link++) {		if (HostP->Mapping[UnitId].Topology[link].Unit == HOST_ID) {			/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected directly to host via link (%c).\n", 			   UnitId, 'A'+link)); */			return 1;		}	}	if (HostP->Mapping[UnitId].Flags & BEEN_HERE) {		/* rio_dprint(RIO_DEBUG_ROUTE, ("Been to Unit %d before - ignoring\n", UnitId)); */		return 0;	}	HostP->Mapping[UnitId].Flags |= BEEN_HERE;	for (link = 0; link < LINKS_PER_UNIT; link++) {		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d check link (%c)\n", UnitId,'A'+link)); */		if (RIOCheck(HostP, HostP->Mapping[UnitId].Topology[link].Unit)) {			/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected to something that knows the host via link (%c)\n", UnitId,link+'A')); */			HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;			return 1;		}	}	HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;	/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d DOESNT KNOW THE HOST!\n", UnitId)); */	return 0;}/*** Returns the type of unit (host, 16/8 port RTA)*/unsigned int GetUnitType(unsigned int Uniq){	switch ((Uniq >> 28) & 0xf) {	case RIO_AT:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?