📄 riocmd.c
字号:
/*** -----------------------------------------------------------------------------**** Perle Specialix driver for Linux** ported from the existing SCO driver source** * * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.**** Module : riocmd.c** SID : 1.2** Last Modified : 11/6/98 10:33:41** Retrieved : 11/6/98 10:33:49**** ident @(#)riocmd.c 1.2**** -----------------------------------------------------------------------------*/#ifdef SCCS_LABELSstatic char *_riocmd_c_sccs_ = "@(#)riocmd.c 1.2";#endif#include <linux/module.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/tty.h>#include <asm/io.h>#include <asm/system.h>#include <asm/string.h>#include <asm/semaphore.h>#include <linux/termios.h>#include <linux/serial.h>#include <linux/generic_serial.h>#include "linux_compat.h"#include "rio_linux.h"#include "typdef.h"#include "pkt.h"#include "daemon.h"#include "rio.h"#include "riospace.h"#include "top.h"#include "cmdpkt.h"#include "map.h"#include "riotypes.h"#include "rup.h"#include "port.h"#include "riodrvr.h"#include "rioinfo.h"#include "func.h"#include "errors.h"#include "pci.h"#include "parmmap.h"#include "unixrup.h"#include "board.h"#include "host.h"#include "error.h"#include "phb.h"#include "link.h"#include "cmdblk.h"#include "route.h"#include "control.h"#include "cirrus.h"static struct IdentifyRta IdRta;static struct KillNeighbour KillUnit;intRIOFoadRta(struct Host *HostP, struct Map *MapP){ struct CmdBlk *CmdBlkP; rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA: GetCmdBlk failed\n"); return -ENXIO; } CmdBlkP->Packet.dest_unit = MapP->ID; CmdBlkP->Packet.dest_port = BOOT_RUP; CmdBlkP->Packet.src_unit = 0; CmdBlkP->Packet.src_port = BOOT_RUP; CmdBlkP->Packet.len = 0x84; CmdBlkP->Packet.data[0] = IFOAD; CmdBlkP->Packet.data[1] = 0; CmdBlkP->Packet.data[2] = IFOAD_MAGIC & 0xFF; CmdBlkP->Packet.data[3] = (IFOAD_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { rio_dprintk (RIO_DEBUG_CMD, "FOAD RTA: Failed to queue foad command\n"); return -EIO; } return 0;}intRIOZombieRta(struct Host *HostP, struct Map *MapP){ struct CmdBlk *CmdBlkP; rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA: GetCmdBlk failed\n"); return -ENXIO; } CmdBlkP->Packet.dest_unit = MapP->ID; CmdBlkP->Packet.dest_port = BOOT_RUP; CmdBlkP->Packet.src_unit = 0; CmdBlkP->Packet.src_port = BOOT_RUP; CmdBlkP->Packet.len = 0x84; CmdBlkP->Packet.data[0] = ZOMBIE; CmdBlkP->Packet.data[1] = 0; CmdBlkP->Packet.data[2] = ZOMBIE_MAGIC & 0xFF; CmdBlkP->Packet.data[3] = (ZOMBIE_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { rio_dprintk (RIO_DEBUG_CMD, "ZOMBIE RTA: Failed to queue zombie command\n"); return -EIO; } return 0;}intRIOCommandRta(struct rio_info *p, uint RtaUnique, int (* func)(struct Host *HostP, struct Map *MapP)){ uint Host; rio_dprintk (RIO_DEBUG_CMD, "Command RTA 0x%x func 0x%x\n", RtaUnique, (int)func); if ( !RtaUnique ) return(0); for ( Host = 0; Host < p->RIONumHosts; Host++ ) { uint Rta; struct Host *HostP = &p->RIOHosts[Host]; for ( Rta = 0; Rta < RTAS_PER_HOST; Rta++ ) { struct Map *MapP = &HostP->Mapping[Rta]; if ( MapP->RtaUniqueNum == RtaUnique ) { uint Link; /* ** now, lets just check we have a route to it... ** IF the routing stuff is working, then one of the ** topology entries for this unit will have a legit ** route *somewhere*. We care not where - if its got ** any connections, we can get to it. */ for ( Link = 0; Link < LINKS_PER_UNIT; Link++ ) { if ( MapP->Topology[Link].Unit <= (uchar)MAX_RUP ) { /* ** Its worth trying the operation... */ return (*func)( HostP, MapP ); } } } } } return -ENXIO;}intRIOIdentifyRta(struct rio_info *p, caddr_t arg){ uint Host; if ( copyin( (int)arg, (caddr_t)&IdRta, sizeof(IdRta) ) == COPYFAIL ) { rio_dprintk (RIO_DEBUG_CMD, "RIO_IDENTIFY_RTA copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return -EFAULT; } for ( Host = 0 ; Host < p->RIONumHosts; Host++ ) { uint Rta; struct Host *HostP = &p->RIOHosts[Host]; for ( Rta = 0; Rta < RTAS_PER_HOST; Rta++ ) { struct Map *MapP = &HostP->Mapping[Rta]; if ( MapP->RtaUniqueNum == IdRta.RtaUnique ) { uint Link; /* ** now, lets just check we have a route to it... ** IF the routing stuff is working, then one of the ** topology entries for this unit will have a legit ** route *somewhere*. We care not where - if its got ** any connections, we can get to it. */ for ( Link = 0; Link < LINKS_PER_UNIT; Link++ ) { if ( MapP->Topology[Link].Unit <= (uchar)MAX_RUP ) { /* ** Its worth trying the operation... */ struct CmdBlk *CmdBlkP; rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA\n"); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA: GetCmdBlk failed\n"); return -ENXIO; } CmdBlkP->Packet.dest_unit = MapP->ID; CmdBlkP->Packet.dest_port = BOOT_RUP; CmdBlkP->Packet.src_unit = 0; CmdBlkP->Packet.src_port = BOOT_RUP; CmdBlkP->Packet.len = 0x84; CmdBlkP->Packet.data[0] = IDENTIFY; CmdBlkP->Packet.data[1] = 0; CmdBlkP->Packet.data[2] = IdRta.ID; if ( RIOQueueCmdBlk( HostP, MapP->ID-1, CmdBlkP) == RIO_FAIL ) { rio_dprintk (RIO_DEBUG_CMD, "IDENTIFY RTA: Failed to queue command\n"); return -EIO; } return 0; } } } } } return -ENOENT;}intRIOKillNeighbour(struct rio_info *p, caddr_t arg){ uint Host; uint ID; struct Host *HostP; struct CmdBlk *CmdBlkP; rio_dprintk (RIO_DEBUG_CMD, "KILL HOST NEIGHBOUR\n"); if ( copyin( (int)arg, (caddr_t)&KillUnit, sizeof(KillUnit) ) == COPYFAIL ) { rio_dprintk (RIO_DEBUG_CMD, "RIO_KILL_NEIGHBOUR copy failed\n"); p->RIOError.Error = COPYIN_FAILED; return -EFAULT; } if ( KillUnit.Link > 3 ) return -ENXIO; CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { rio_dprintk (RIO_DEBUG_CMD, "UFOAD: GetCmdBlk failed\n"); return -ENXIO; } CmdBlkP->Packet.dest_unit = 0; CmdBlkP->Packet.src_unit = 0; CmdBlkP->Packet.dest_port = BOOT_RUP; CmdBlkP->Packet.src_port = BOOT_RUP; CmdBlkP->Packet.len = 0x84; CmdBlkP->Packet.data[0] = UFOAD; CmdBlkP->Packet.data[1] = KillUnit.Link; CmdBlkP->Packet.data[2] = UFOAD_MAGIC & 0xFF; CmdBlkP->Packet.data[3] = (UFOAD_MAGIC >> 8) & 0xFF; for ( Host = 0; Host < p->RIONumHosts; Host++ ) { ID = 0; HostP = &p->RIOHosts[Host]; if ( HostP->UniqueNum == KillUnit.UniqueNum ) { if ( RIOQueueCmdBlk( HostP, RTAS_PER_HOST+KillUnit.Link, CmdBlkP) == RIO_FAIL ) { rio_dprintk (RIO_DEBUG_CMD, "UFOAD: Failed queue command\n"); return -EIO; } return 0; } for ( ID=0; ID < RTAS_PER_HOST; ID++ ) { if ( HostP->Mapping[ID].RtaUniqueNum == KillUnit.UniqueNum ) { CmdBlkP->Packet.dest_unit = ID+1; if ( RIOQueueCmdBlk( HostP, ID, CmdBlkP) == RIO_FAIL ) { rio_dprintk (RIO_DEBUG_CMD, "UFOAD: Failed queue command\n"); return -EIO; } return 0; } } } RIOFreeCmdBlk( CmdBlkP ); return -ENXIO;}intRIOSuspendBootRta(struct Host *HostP, int ID, int Link){ struct CmdBlk *CmdBlkP; rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link); CmdBlkP = RIOGetCmdBlk(); if ( !CmdBlkP ) { rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: GetCmdBlk failed\n"); return -ENXIO; } CmdBlkP->Packet.dest_unit = ID; CmdBlkP->Packet.dest_port = BOOT_RUP; CmdBlkP->Packet.src_unit = 0; CmdBlkP->Packet.src_port = BOOT_RUP; CmdBlkP->Packet.len = 0x84; CmdBlkP->Packet.data[0] = IWAIT; CmdBlkP->Packet.data[1] = Link; CmdBlkP->Packet.data[2] = IWAIT_MAGIC & 0xFF; CmdBlkP->Packet.data[3] = (IWAIT_MAGIC >> 8) & 0xFF; if ( RIOQueueCmdBlk( HostP, ID - 1, CmdBlkP) == RIO_FAIL ) { rio_dprintk (RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: Failed to queue iwait command\n"); return -EIO; } return 0;}intRIOFoadWakeup(struct rio_info *p){ int port; register struct Port *PortP; unsigned long flags; for ( port=0; port<RIO_PORTS; port++) { PortP = p->RIOPortp[port]; rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->Config = 0; PortP->State = 0; PortP->InUse = NOT_INUSE; PortP->PortState = 0; PortP->FlushCmdBodge = 0; PortP->ModemLines = 0; PortP->ModemState = 0; PortP->CookMode = 0; PortP->ParamSem = 0; PortP->Mapped = 0; PortP->WflushFlag = 0; PortP->MagicFlags = 0; PortP->RxDataStart = 0; PortP->TxBufferIn = 0; PortP->TxBufferOut = 0; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } return(0);}/*** Incoming command on the COMMAND_RUP to be processed.*/static intRIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP){ struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data; struct Port *PortP; struct UnixRup *UnixRupP; ushort SysPort; ushort ReportedModemStatus; ushort rup; ushort subCommand; unsigned long flags; func_enter ();#ifdef CHECK CheckHost( Host ); CheckHostP( HostP ); CheckPacketP( PacketP );#endif /* ** 16 port RTA note: ** Command rup packets coming from the RTA will have pkt->data[1] (which ** translates to PktCmdP->PhbNum) set to the host port number for the ** particular unit. To access the correct BaseSysPort for a 16 port RTA, ** we can use PhbNum to get the rup number for the appropriate 8 port ** block (for the first block, this should be equal to 'Rup'). */ rup = RBYTE(PktCmdP->PhbNum) / (ushort)PORTS_PER_RTA; UnixRupP = &HostP->UnixRups[rup]; SysPort = UnixRupP->BaseSysPort + (RBYTE(PktCmdP->PhbNum) % (ushort)PORTS_PER_RTA); rio_dprintk (RIO_DEBUG_CMD, "Command on rup %d, port %d\n", rup, SysPort);#ifdef CHECK CheckRup( rup ); CheckUnixRupP( UnixRupP );#endif if ( UnixRupP->BaseSysPort == NO_PORT ) { rio_dprintk (RIO_DEBUG_CMD, "OBSCURE ERROR!\n"); rio_dprintk (RIO_DEBUG_CMD, "Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n"); rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: Host number %d, name ``%s''\n", HostP-p->RIOHosts, HostP->Name ); rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup); if ( Rup >= (ushort)MAX_RUP ) { rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name); } else rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name); rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Destination 0x%x:0x%x\n", PacketP->dest_unit, PacketP->dest_port ); rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Source 0x%x:0x%x\n", PacketP->src_unit, PacketP->src_port ); rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Length 0x%x (%d)\n", PacketP->len,PacketP->len ); rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Control 0x%x (%d)\n", PacketP->control, PacketP->control); rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Check 0x%x (%d)\n", PacketP->csum, PacketP->csum ); rio_dprintk (RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, " "Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command ); return TRUE; }#ifdef CHECK CheckSysPort( SysPort );#endif PortP = p->RIOPortp[ SysPort ]; rio_spin_lock_irqsave(&PortP->portSem, flags); switch( RBYTE(PktCmdP->Command) ) { case BREAK_RECEIVED: rio_dprintk (RIO_DEBUG_CMD, "Received a break!\n"); /* If the current line disc. is not multi-threading and the current processor is not the default, reset rup_intr and return FALSE to ensure that the command packet is not freed. */ /* Call tmgr HANGUP HERE */ /* Fix this later when every thing works !!!! RAMRAJ */ gs_got_break (&PortP->gs); break; case COMPLETE: rio_dprintk (RIO_DEBUG_CMD, "Command complete on phb %d host %d\n", RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts); subCommand = 1; switch (RBYTE(PktCmdP->SubCommand)) { case MEMDUMP : rio_dprintk (RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", RBYTE(PktCmdP->SubCommand), RWORD(PktCmdP->SubAddr)); break; case READ_REGISTER : rio_dprintk (RIO_DEBUG_CMD, "Read register (0x%x)\n", RWORD(PktCmdP->SubAddr)); p->CdRegister = (RBYTE(PktCmdP->ModemStatus) & MSVR1_HOST); break; default : subCommand = 0; break; } if (subCommand) break; rio_dprintk (RIO_DEBUG_CMD, "New status is 0x%x was 0x%x\n", RBYTE(PktCmdP->PortStatus),PortP->PortState); if (PortP->PortState != RBYTE(PktCmdP->PortStatus)) { rio_dprintk (RIO_DEBUG_CMD, "Mark status & wakeup\n"); PortP->PortState = RBYTE(PktCmdP->PortStatus); /* What should we do here ... wakeup( &PortP->PortState ); */ } else rio_dprintk (RIO_DEBUG_CMD, "No change\n"); /* FALLTHROUGH */ case MODEM_STATUS: /* ** Knock out the tbusy and tstop bits, as these are not relevant ** to the check for modem status change (they're just there because ** it's a convenient place to put them!). */ ReportedModemStatus = RBYTE(PktCmdP->ModemStatus); if ((PortP->ModemState & MSVR1_HOST) == (ReportedModemStatus & MSVR1_HOST)) { rio_dprintk (RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState); /* ** Update ModemState just in case tbusy or tstop states have ** changed. */ PortP->ModemState = ReportedModemStatus; } else { rio_dprintk (RIO_DEBUG_CMD, "Modem status change from 0x%x to 0x%x\n", PortP->ModemState, ReportedModemStatus); PortP->ModemState = ReportedModemStatus;#ifdef MODEM_SUPPORT if ( PortP->Mapped ) { /***********************************************************\ *************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -