From: Philip Homburg Date: Mon, 23 Apr 2007 14:49:20 +0000 (+0000) Subject: Initial convertion to asynchronous sends for communicating with ethernet X-Git-Tag: v3.1.4~403 X-Git-Url: http://zhaoyanbai.com/repos/%22../static/icons/index.html?a=commitdiff_plain;h=0bd4c5ee7d3412cb37eb757902d234d4a17f9efb;p=minix.git Initial convertion to asynchronous sends for communicating with ethernet drivers. --- diff --git a/servers/inet/generic/eth.c b/servers/inet/generic/eth.c index 59a17dc33..75e3c3985 100644 --- a/servers/inet/generic/eth.c +++ b/servers/inet/generic/eth.c @@ -100,7 +100,8 @@ PUBLIC void eth_init() eth_fd_table[i].ef_flags= EFF_EMPTY; for (i=0; ietp_getstat) + { + printf( + "eth_ioctl: pending eth_get_stat request, suspending caller\n"); + assert(!(eth_fd->ef_flags & EFF_IOCTL_IP)); + eth_fd->ef_flags |= EFF_IOCTL_IP; + return NW_SUSPEND; + } + acc= bf_memreq(sizeof(nwio_ethstat_t)); compare (bf_bufsize(acc), ==, sizeof(*ethstat)); @@ -356,6 +366,20 @@ ioreq_t req; { result= eth_get_stat(eth_port, ðstat->nwes_stat); + if (result == SUSPEND) + { + printf( + "eth_ioctl: eth_get_stat returned SUSPEND\n"); + eth_fd->ef_ioctl_req= req; + assert(!(eth_fd->ef_flags & + EFF_IOCTL_IP)); + eth_fd->ef_flags |= EFF_IOCTL_IP; +printf("eth_ioctl: setting etp_getstat in port %d to %p\n", + eth_port-eth_port_table, acc); + eth_port->etp_getstat= acc; + acc= NULL; + return NW_SUSPEND; + } if (result != NW_OK) { bf_afree(acc); @@ -993,8 +1017,18 @@ eth_port_t *vlan_port; PUBLIC void eth_restart_ioctl(eth_port) eth_port_t *eth_port; { - int i; + int i, r; eth_fd_t *eth_fd; + acc_t *acc; + + printf("in eth_restart_ioctl\n"); + + /* eth_restart_ioctl is called on too occasions: when a device + * driver registers with inet and when a eth_get_stat call has + * completed. We assume the second option when etp_getstat is + * not equal to zero at the start of the call. + */ + acc= eth_port->etp_getstat; for (i= 0, eth_fd= eth_fd_table; ief_ioctl_req != NWIOGETHSTAT) continue; +printf("eth_restart_ioctl: etp_getstat in port %d is %p\n", + eth_port-eth_port_table, acc); + + if (acc != NULL) + { + printf("eth_restart_ioctl: completed getstat\n"); + acc->acc_linkC++; + r= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, 0, + acc, TRUE); + if (r >= 0) + reply_thr_put(eth_fd, NW_OK, TRUE); + eth_fd->ef_flags &= ~EFF_IOCTL_IP; + continue; + } + + { static int count; if (++count > 5) ip_panic(("too many restarts")); } + eth_fd->ef_flags &= ~EFF_IOCTL_IP; eth_ioctl(i, eth_fd->ef_ioctl_req); } + + if (acc != NULL) + { +printf("eth_restart_ioctl: clearing etp_getstat in port %d\n", + eth_port-eth_port_table); + assert(acc == eth_port->etp_getstat); + + bf_afree(acc); + eth_port->etp_getstat= NULL; + } } PRIVATE void packet2user (eth_fd, pack, exp_time) diff --git a/servers/inet/generic/eth_int.h b/servers/inet/generic/eth_int.h index d5a4c28b3..b8354dbb7 100644 --- a/servers/inet/generic/eth_int.h +++ b/servers/inet/generic/eth_int.h @@ -21,6 +21,7 @@ typedef struct eth_port int etp_flags; ether_addr_t etp_ethaddr; acc_t *etp_wr_pack, *etp_rd_pack; + acc_t *etp_getstat; struct eth_fd *etp_sendq_head; struct eth_fd *etp_sendq_tail; struct eth_fd *etp_type_any; diff --git a/servers/inet/generic/ip_ioctl.c b/servers/inet/generic/ip_ioctl.c index bbfaf247a..d726d7738 100644 --- a/servers/inet/generic/ip_ioctl.c +++ b/servers/inet/generic/ip_ioctl.c @@ -426,6 +426,15 @@ ioreq_t req; return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, EBADIOCTL, (acc_t *)0, TRUE); } + + if (!(ip_port->ip_flags & IPF_IPADDRSET)) + { + ip_fd->if_ioctl= req; + ip_fd->if_flags |= IFF_IOCTL_IP; + printf("ip_ioctl: suspending ARP request\n"); + return NW_SUSPEND; + } + result= arp_ioctl(ip_port->ip_dl.dl_eth.de_port, ip_fd->if_srfd, req, ip_fd->if_get_userdata, ip_fd->if_put_userdata); diff --git a/servers/inet/inet.c b/servers/inet/inet.c index 9ce7db78c..d7fefa9e4 100644 --- a/servers/inet/inet.c +++ b/servers/inet/inet.c @@ -35,7 +35,7 @@ from DL_ETH: | m_type | DL_PORT | DL_PROC | DL_COUNT | DL_STAT | DL_TIME | |_______________|___________|_________|__________|____________|_________| | | | | | | | -| DL_INIT_REPLY | minor dev | proc nr | rd_count | 0 | stat | time | +| DL_CONF_REPLY | minor dev | proc nr | rd_count | 0 | stat | time | |_______________|___________|_________|__________|____________|_________| | | | | | | | | DL_TASK_REPLY | minor dev | proc nr | rd_count | err | stat | time | @@ -95,7 +95,7 @@ PUBLIC void main() { mq_t *mq; int r; - int source, timerand, fd; + int source, m_type, timerand, fd; struct fssignon device; #ifdef __minix_vmd struct systaskinfo info; @@ -229,6 +229,7 @@ PUBLIC void main() } reset_time(); source= mq->mq_mess.m_source; + m_type= mq->mq_mess.m_type; if (source == FS_PROC_NR) { sr_rec(mq); @@ -240,25 +241,26 @@ PUBLIC void main() mq_free(mq); } #else /* Minix 3 */ - else if (mq->mq_mess.m_type == SYN_ALARM) + else if (m_type == SYN_ALARM) { clck_tick(&mq->mq_mess); mq_free(mq); } - else if (mq->mq_mess.m_type == PROC_EVENT) + else if (m_type == PROC_EVENT) { /* signaled */ /* probably SIGTERM */ mq_free(mq); } - else if (mq->mq_mess.m_type & NOTIFY_MESSAGE) + else if (m_type & NOTIFY_MESSAGE) { /* A driver is (re)started. */ eth_check_drivers(&mq->mq_mess); mq_free(mq); } #endif - else if (mq->mq_mess.m_type == DL_TASK_REPLY) + else if (m_type == DL_CONF_REPLY || m_type == DL_TASK_REPLY || + m_type == DL_NAME_REPLY || m_type == DL_STAT_REPLY) { eth_rec(&mq->mq_mess); mq_free(mq); diff --git a/servers/inet/inet_config.c b/servers/inet/inet_config.c index 5c1b68caa..b8794c0f0 100644 --- a/servers/inet/inet_config.c +++ b/servers/inet/inet_config.c @@ -23,6 +23,9 @@ Copyright 1995 Philip Homburg #include #include #include "inet_config.h" +#include "inet.h" + +THIS_FILE struct eth_conf eth_conf[IP_PORT_MAX]; struct psip_conf psip_conf[IP_PORT_MAX]; @@ -213,6 +216,13 @@ void read_conf(void) struct ip_conf *icp; struct stat st; + { static int first= 1; + if (!first) ip_panic(( "read_conf: called a second time" )); + first= 0; + *(u8_t *)0 = 0xcc; /* INT 3 */ + } + + /* Open the configuration file. */ if ((cfg_fd= open(PATH_INET_CONF, O_RDONLY)) == -1) fatal(PATH_INET_CONF); diff --git a/servers/inet/mnx_eth.c b/servers/inet/mnx_eth.c index 44bb82e3f..859dc7099 100644 --- a/servers/inet/mnx_eth.c +++ b/servers/inet/mnx_eth.c @@ -25,11 +25,15 @@ static int recv_debug= 0; FORWARD _PROTOTYPE( void setup_read, (eth_port_t *eth_port) ); FORWARD _PROTOTYPE( void read_int, (eth_port_t *eth_port, int count) ); +FORWARD _PROTOTYPE( void eth_issue_send, (eth_port_t *eth_port) ); FORWARD _PROTOTYPE( void write_int, (eth_port_t *eth_port) ); FORWARD _PROTOTYPE( void eth_recvev, (event_t *ev, ev_arg_t ev_arg) ); FORWARD _PROTOTYPE( void eth_sendev, (event_t *ev, ev_arg_t ev_arg) ); FORWARD _PROTOTYPE( eth_port_t *find_port, (message *m) ); FORWARD _PROTOTYPE( void eth_restart, (eth_port_t *eth_port, int tasknr) ); +FORWARD _PROTOTYPE( void send_getstat, (eth_port_t *eth_port) ); + +FORWARD _PROTOTYPE( int asynsend, (endpoint_t dst, message *mp) ); PUBLIC void osdep_eth_init() { @@ -51,6 +55,11 @@ PUBLIC void osdep_eth_init() eth_port->etp_osdep.etp_rd_iovec[j].iov_grant= -1; eth_port->etp_osdep.etp_rd_vec_grant= -1; + eth_port->etp_osdep.etp_state= OEPS_INIT; + eth_port->etp_osdep.etp_flags= OEPF_EMPTY; + eth_port->etp_osdep.etp_stat_gid= -1; + eth_port->etp_osdep.etp_stat_buf= NULL; + if (eth_is_vlan(ecp)) continue; @@ -120,8 +129,11 @@ PUBLIC void osdep_eth_init() r= ENXIO; else { - r= send(eth_port->etp_osdep.etp_task, &mess); - if (r<0) + assert(eth_port->etp_osdep.etp_state == OEPS_INIT); + r= asynsend(eth_port->etp_osdep.etp_task, &mess); + if (r == OK) + eth_port->etp_osdep.etp_state= OEPS_CONF_SENT; + else { printf( "osdep_eth_init: unable to send to ethernet task, error= %d\n", @@ -129,41 +141,7 @@ PUBLIC void osdep_eth_init() } } - if (r == OK) - { - r= receive(eth_port->etp_osdep.etp_task, &mess); - if (r<0) - { - printf( - "osdep_eth_init: unable to receive from ethernet task, error= %d\n", - r); - } - } - - if (r == OK) - { - r= mess.m3_i1; - if (r == ENXIO) - { - printf( - "osdep_eth_init: no ethernet device at task=%d,port=%d\n", - eth_port->etp_osdep.etp_task, - eth_port->etp_osdep.etp_port); - } - else if (r < 0) - { - ip_panic(( - "osdep_eth_init: DL_INIT returned error %d\n", - r)); - } - else if (mess.m3_i1 != eth_port->etp_osdep.etp_port) - { - ip_panic(( - "osdep_eth_init: got reply for wrong port (got %d, expected %d)\n", - mess.m3_i1, - eth_port->etp_osdep.etp_port)); - } - } + r= ENXIO; sr_add_minor(if2minor(ecp->ec_ifno, ETH_DEV_OFF), i, eth_open, eth_close, eth_read, @@ -177,6 +155,7 @@ PUBLIC void osdep_eth_init() if (r == OK) { eth_port->etp_ethaddr= *(ether_addr_t *)mess.m3_ca1; + printf("osdep_eth_init: setting EPF_GOT_ADDR\n"); eth_port->etp_flags |= EPF_GOT_ADDR; setup_read (eth_port); } @@ -214,6 +193,7 @@ PUBLIC void osdep_eth_init() if (rep->etp_flags & EPF_GOT_ADDR) { eth_port->etp_ethaddr= rep->etp_ethaddr; + printf("osdep_eth_init: setting EPF_GOT_ADDR\n"); eth_port->etp_flags |= EPF_GOT_ADDR; } @@ -237,9 +217,6 @@ acc_t *pack; { eth_port_t *loc_port; message mess1, block_msg; - int i, pack_size; - acc_t *pack_ptr; - iovec_s_t *iovec; u8_t *eth_dst_ptr; int multicast, r; ev_arg_t ev_arg; @@ -250,202 +227,214 @@ acc_t *pack; assert(eth_port->etp_wr_pack == NULL); eth_port->etp_wr_pack= pack; - iovec= eth_port->etp_osdep.etp_wr_iovec; - pack_size= 0; - for (i=0, pack_ptr= pack; iacc_next) + if (eth_port->etp_osdep.etp_state != OEPS_IDLE) { - r= cpf_setgrant_direct(iovec[i].iov_grant, - eth_port->etp_osdep.etp_task, - (vir_bytes)ptr2acc_data(pack_ptr), - (vir_bytes)pack_ptr->acc_length, - CPF_READ); - if (r != 0) - { - ip_panic(( - "eth_write_port: cpf_setgrant_direct failed: %d\n", - errno)); - } - pack_size += iovec[i].iov_size= pack_ptr->acc_length; + eth_port->etp_osdep.etp_flags |= OEPF_NEED_SEND; + return; } - if (i>= IOVEC_NR) + + + eth_issue_send(eth_port); +} + +PRIVATE int notification_count; + +PUBLIC void eth_rec(m) +message *m; +{ + int i, r, m_type, stat; + eth_port_t *loc_port, *vlan_port; + char *drivername; + struct eth_conf *ecp; + + m_type= m->m_type; + if (m_type == DL_NAME_REPLY) { - pack= bf_pack(pack); /* packet is too fragmented */ - eth_port->etp_wr_pack= pack; - pack_size= 0; - for (i=0, pack_ptr= pack; iacc_next) + drivername= m->m3_ca1; + printf("eth_rec: got name: %s\n", drivername); + + notification_count= 0; + + /* Re-init ethernet interfaces */ + for (i= 0, ecp= eth_conf, loc_port= eth_port_table; + ietp_osdep.etp_task, - (vir_bytes)ptr2acc_data(pack_ptr), - (vir_bytes)pack_ptr->acc_length, - CPF_READ); - if (r != 0) + if (eth_is_vlan(ecp)) + continue; + + if (strcmp(ecp->ec_task, drivername) != 0) { - ip_panic(( - "eth_write_port: cpf_setgrant_direct failed: %d\n", - errno)); + /* Wrong driver */ + continue; } - pack_size += iovec[i].iov_size= pack_ptr->acc_length; + eth_restart(loc_port, m->m_source); } + return; } - assert (i< IOVEC_NR); - assert (pack_size >= ETH_MIN_PACK_SIZE); + assert(m_type == DL_CONF_REPLY || m_type == DL_TASK_REPLY || + m_type == DL_STAT_REPLY); - r= cpf_setgrant_direct(eth_port->etp_osdep.etp_wr_vec_grant, - eth_port->etp_osdep.etp_task, - (vir_bytes)iovec, - (vir_bytes)(i * sizeof(iovec[0])), - CPF_READ); - if (r != 0) + for (i=0, loc_port= eth_port_table; ietp_osdep.etp_port == m->DL_PORT && + loc_port->etp_osdep.etp_task == m->m_source) + break; + } + if (i >= eth_conf_nr) + { + printf("eth_rec: bad port %d in message type 0x%x from %d\n", + m->DL_PORT, m_type, m->m_source); + return; } - mess1.DL_COUNT= i; - mess1.DL_GRANT= eth_port->etp_osdep.etp_wr_vec_grant; - mess1.m_type= DL_WRITEV_S; - - mess1.DL_PORT= eth_port->etp_osdep.etp_port; - mess1.DL_PROC= this_proc; - mess1.DL_MODE= DL_NOMODE; - for (;;) + if (loc_port->etp_osdep.etp_state == OEPS_CONF_SENT) { - r= sendrec(eth_port->etp_osdep.etp_task, &mess1); - if (r != ELOCKED) - break; + if (m_type == DL_TASK_REPLY) + { + stat= m->DL_STAT & 0xffff; - /* ethernet task is sending to this task, I hope */ - r= receive(eth_port->etp_osdep.etp_task, &block_msg); - if (r < 0) - ip_panic(("unable to receive")); + if (stat & DL_PACK_SEND) + write_int(loc_port); + if (stat & DL_PACK_RECV) + read_int(loc_port, m->DL_COUNT); + return; + } - loc_port= eth_port; - if (loc_port->etp_osdep.etp_port != block_msg.DL_PORT || - loc_port->etp_osdep.etp_task != block_msg.m_source) + if (m_type != DL_CONF_REPLY) { - loc_port= find_port(&block_msg); + printf( + "eth_rec: got bad message type 0x%x from %d in CONF state\n", + m_type, m->m_source); + return; } - assert(block_msg.DL_STAT & (DL_PACK_SEND|DL_PACK_RECV)); - if (block_msg.DL_STAT & DL_PACK_SEND) + + r= m->m3_i1; + if (r == ENXIO) + { + printf( + "eth_rec(conf_reply): no ethernet device at task=%d,port=%d\n", + loc_port->etp_osdep.etp_task, + loc_port->etp_osdep.etp_port); + return; + } + if (r < 0) { - assert(loc_port != eth_port); - loc_port->etp_osdep.etp_sendrepl= block_msg; - ev_arg.ev_ptr= loc_port; - assert(!loc_port->etp_osdep.etp_send_ev); - loc_port->etp_osdep.etp_send_ev= 1; - ev_enqueue(&loc_port->etp_sendev, eth_sendev, ev_arg); + ip_panic(("eth_rec: DL_INIT returned error %d\n", r)); + return; } - if (block_msg.DL_STAT & DL_PACK_RECV) + + loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_CONF; + loc_port->etp_osdep.etp_state= OEPS_IDLE; + loc_port->etp_flags |= EPF_ENABLED; + + loc_port->etp_ethaddr= *(ether_addr_t *)m->m3_ca1; + if (!(loc_port->etp_flags & EPF_GOT_ADDR)) { - if (recv_debug) + loc_port->etp_flags |= EPF_GOT_ADDR; + printf("eth_rec: calling eth_restart_ioctl\n"); + eth_restart_ioctl(loc_port); + + /* Also update any VLANs on this device */ + for (i=0, vlan_port= eth_port_table; ietp_flags & EPF_ENABLED)) + continue; + if (vlan_port->etp_vlan_port != loc_port) + continue; + + vlan_port->etp_ethaddr= loc_port->etp_ethaddr; + vlan_port->etp_flags |= EPF_GOT_ADDR; + eth_restart_ioctl(vlan_port); } - loc_port->etp_osdep.etp_recvrepl= block_msg; - ev_arg.ev_ptr= loc_port; - ev_enqueue(&loc_port->etp_osdep.etp_recvev, - eth_recvev, ev_arg); } - } + if (!(loc_port->etp_flags & EPF_READ_IP)) + setup_read (loc_port); - if (r < 0) - { - printf("eth_write_port: sendrec to %d failed: %d\n", - eth_port->etp_osdep.etp_task, r); - return; - } + if (loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND) + { + printf("eth_rec(conf): OEPF_NEED_SEND is set\n"); + } + if (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV) + { + printf("eth_rec(conf): OEPF_NEED_RECV is set\n"); + } + if (loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT) + { + printf("eth_rec(conf): OEPF_NEED_STAT is set\n"); + } - if (mess1.m_type != DL_TASK_REPLY || - mess1.DL_PORT != eth_port->etp_osdep.etp_port || - mess1.DL_PROC != this_proc) - { - printf( -"eth_write_port: ignoring bad message (type = 0x%x, port = %d, proc = %d) from %d\n", - mess1.m_type, mess1.DL_PORT, mess1.DL_PROC, - mess1.m_source); return; } - - assert(mess1.m_type == DL_TASK_REPLY && - mess1.DL_PORT == eth_port->etp_osdep.etp_port && - mess1.DL_PROC == this_proc); - assert((mess1.DL_STAT >> 16) == OK); - - if (mess1.DL_STAT & DL_PACK_RECV) + if (loc_port->etp_osdep.etp_state == OEPS_GETSTAT_SENT) { - if (recv_debug) + if (m_type != DL_STAT_REPLY) { printf( - "eth_write_port(mess1): eth%d got DL_PACK_RECV\n", - mess1.DL_PORT); + "eth_rec: got bad message type 0x%x from %d in GETSTAT state\n", + m_type, m->m_source); + return; } - eth_port->etp_osdep.etp_recvrepl= mess1; - ev_arg.ev_ptr= eth_port; - ev_enqueue(ð_port->etp_osdep.etp_recvev, eth_recvev, - ev_arg); - } - if (!(mess1.DL_STAT & DL_PACK_SEND)) - { - /* Packet is not yet sent. */ - return; - } - /* If the port is in promiscuous mode or the packet is - * broad- or multicast, enqueue the reply packet. - */ - eth_dst_ptr= (u8_t *)ptr2acc_data(pack); - multicast= (*eth_dst_ptr & 1); /* low order bit indicates multicast */ - if (multicast || (eth_port->etp_osdep.etp_recvconf & NWEO_EN_PROMISC)) - { - eth_port->etp_osdep.etp_sendrepl= mess1; - ev_arg.ev_ptr= eth_port; - assert(!eth_port->etp_osdep.etp_send_ev); - eth_port->etp_osdep.etp_send_ev= 1; - ev_enqueue(ð_port->etp_sendev, eth_sendev, ev_arg); + r= m->DL_STAT; + if (r != OK) + { + ip_warning(("eth_rec: DL_STAT returned error %d\n", + r)); + return; + } + + loc_port->etp_osdep.etp_state= OEPS_IDLE; + loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_STAT; - /* Pretend that we didn't get a reply. */ + assert(loc_port->etp_osdep.etp_stat_gid != -1); + cpf_revoke(loc_port->etp_osdep.etp_stat_gid); + loc_port->etp_osdep.etp_stat_gid= -1; + loc_port->etp_osdep.etp_stat_buf= NULL; + + /* Finish ioctl */ + assert(loc_port->etp_flags & EPF_GOT_ADDR); + eth_restart_ioctl(loc_port); + + if (loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND) + { + printf("eth_rec(stat): OEPF_NEED_SEND is set\n"); + } + if (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV) + { + printf("eth_rec(stat): OEPF_NEED_RECV is set\n"); + } + if (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF) + { + printf("eth_rec(stat): OEPF_NEED_CONF is set\n"); + } +#if 0 + if (loc_port->etp_osdep.etp_state == OEPS_IDLE && + (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF)) + { + eth_set_rec_conf(loc_port, + loc_port->etp_osdep.etp_recvconf); + } +#endif return; } + assert(loc_port->etp_osdep.etp_state == OEPS_IDLE || + loc_port->etp_osdep.etp_state == OEPS_RECV_SENT || + loc_port->etp_osdep.etp_state == OEPS_SEND_SENT || + (printf("etp_state = %d\n", loc_port->etp_osdep.etp_state), 0)); + loc_port->etp_osdep.etp_state= OEPS_IDLE; - /* packet is sent */ - bf_afree(eth_port->etp_wr_pack); - eth_port->etp_wr_pack= NULL; -} - -PUBLIC void eth_rec(m) -message *m; -{ - int i; - eth_port_t *loc_port; - int stat; - - assert(m->m_type == DL_TASK_REPLY); - +#if 0 /* Ethernet driver is not trusted */ set_time (m->DL_CLCK); - - for (i=0, loc_port= eth_port_table; ietp_osdep.etp_port == m->DL_PORT && - loc_port->etp_osdep.etp_task == m->m_source) - break; - } - if (i == eth_conf_nr) - { - ip_panic(("message from unknown source: %d:%d", - m->m_source, m->DL_PORT)); - } +#endif stat= m->DL_STAT & 0xffff; +#if 0 if (!(stat & (DL_PACK_SEND|DL_PACK_RECV))) printf("eth_rec: neither DL_PACK_SEND nor DL_PACK_RECV\n"); +#endif if (stat & DL_PACK_SEND) write_int(loc_port); if (stat & DL_PACK_RECV) @@ -457,53 +446,54 @@ message *m; } read_int(loc_port, m->DL_COUNT); } + + if (loc_port->etp_osdep.etp_state == OEPS_IDLE && + loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND) + { + loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_SEND; + if (loc_port->etp_wr_pack) + eth_issue_send(loc_port); + } + if (loc_port->etp_osdep.etp_state == OEPS_IDLE && + (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV)) + { + printf("eth_rec: OEPF_NEED_RECV is set\n"); + loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_RECV; + if (!(loc_port->etp_flags & EPF_READ_IP)) + setup_read (loc_port); + } + if (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF) + { + printf("eth_rec: OEPF_NEED_CONF is set\n"); + } + if (loc_port->etp_osdep.etp_state == OEPS_IDLE && + (loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT)) + { + send_getstat(loc_port); + } } PUBLIC void eth_check_drivers(m) message *m; { int i, r, tasknr; - struct eth_conf *ecp; - eth_port_t *eth_port; - char *drivername; tasknr= m->m_source; - printf("eth_check_drivers: got a notification from %d\n", tasknr); - + if (notification_count < 100) + { + notification_count++; + printf("eth_check_drivers: got a notification #%d from %d\n", + notification_count, tasknr); + } + m->m_type= DL_GETNAME; - r= sendrec(tasknr, m); + r= asynsend(tasknr, m); if (r != OK) { - printf("eth_check_drivers: sendrec to %d failed: %d\n", + printf("eth_check_drivers: asynsend to %d failed: %d\n", tasknr, r); return; } - if (m->m_type != DL_NAME_REPLY) - { - printf( - "eth_check_drivers: got bad getname reply (%d) from %d\n", - m->m_type, tasknr); - return; - } - - drivername= m->m3_ca1; - printf("eth_check_drivers: got name: %s\n", drivername); - - /* Re-init ethernet interfaces */ - for (i= 0, ecp= eth_conf, eth_port= eth_port_table; - iec_task, drivername) != 0) - { - /* Wrong driver */ - continue; - } - - eth_restart(eth_port, tasknr); - } } PUBLIC int eth_get_stat(eth_port, eth_stat) @@ -512,10 +502,12 @@ eth_stat_t *eth_stat; { int r; cp_grant_id_t gid; - message mess, mlocked; assert(!eth_port->etp_vlan); + if (eth_port->etp_osdep.etp_flags & OEPF_NEED_STAT) + ip_panic(( "eth_get_stat: getstat already in progress" )); + gid= cpf_grant_direct(eth_port->etp_osdep.etp_task, (vir_bytes)eth_stat, sizeof(*eth_stat), CPF_WRITE); if (gid == -1) @@ -523,43 +515,19 @@ eth_stat_t *eth_stat; ip_panic(( "eth_get_stat: cpf_grant_direct failed: %d\n", errno)); } + assert(eth_port->etp_osdep.etp_stat_gid == -1); + eth_port->etp_osdep.etp_stat_gid= gid; + eth_port->etp_osdep.etp_stat_buf= eth_stat; - mess.m_type= DL_GETSTAT_S; - mess.DL_PORT= eth_port->etp_osdep.etp_port; - mess.DL_PROC= this_proc; - mess.DL_GRANT= gid; - - for (;;) - { - r= sendrec(eth_port->etp_osdep.etp_task, &mess); - if (r != ELOCKED) - break; - - r= receive(eth_port->etp_osdep.etp_task, &mlocked); - assert(r == OK); - - compare(mlocked.m_type, ==, DL_TASK_REPLY); - eth_rec(&mlocked); - } - cpf_revoke(gid); - - if (r != OK) + if (eth_port->etp_osdep.etp_state != OEPS_IDLE) { - printf("eth_get_stat: sendrec to %d failed: %d\n", - eth_port->etp_osdep.etp_task, r); - return EIO; + eth_port->etp_osdep.etp_flags |= OEPF_NEED_STAT; + return SUSPEND; } - assert(mess.m_type == DL_TASK_REPLY); - - r= mess.DL_STAT >> 16; - assert (r == 0); + send_getstat(eth_port); - if (mess.DL_STAT) - { - eth_rec(&mess); - } - return OK; + return SUSPEND; } PUBLIC void eth_set_rec_conf (eth_port, flags) @@ -579,6 +547,15 @@ u32_t flags; return; } + if (eth_port->etp_osdep.etp_state != OEPS_IDLE) + { + printf( + "eth_set_rec_conf: setting OEPF_NEED_CONF, state = %d\n", + eth_port->etp_osdep.etp_state); + eth_port->etp_osdep.etp_flags |= OEPF_NEED_CONF; + return; + } + eth_port->etp_osdep.etp_recvconf= flags; dl_flags= DL_NOMODE; if (flags & NWEO_EN_BROAD) @@ -593,35 +570,99 @@ u32_t flags; mess.DL_PROC= this_proc; mess.DL_MODE= dl_flags; - do + assert(eth_port->etp_osdep.etp_state == OEPS_IDLE); + r= asynsend(eth_port->etp_osdep.etp_task, &mess); + eth_port->etp_osdep.etp_state= OEPS_CONF_SENT; + + if (r < 0) { - r= sendrec(eth_port->etp_osdep.etp_task, &mess); - if (r == ELOCKED) /* etp_task is sending to this task, - I hope */ + printf("eth_set_rec_conf: asynsend to %d failed: %d\n", + eth_port->etp_osdep.etp_task, r); + return; + } +} + +PRIVATE void eth_issue_send(eth_port) +eth_port_t *eth_port; +{ + int i, r, pack_size; + acc_t *pack, *pack_ptr; + iovec_s_t *iovec; + message m; + + iovec= eth_port->etp_osdep.etp_wr_iovec; + pack= eth_port->etp_wr_pack; + pack_size= 0; + for (i=0, pack_ptr= pack; iacc_next) + { + r= cpf_setgrant_direct(iovec[i].iov_grant, + eth_port->etp_osdep.etp_task, + (vir_bytes)ptr2acc_data(pack_ptr), + (vir_bytes)pack_ptr->acc_length, + CPF_READ); + if (r != 0) { - if (receive (eth_port->etp_osdep.etp_task, - &repl_mess)< 0) + ip_panic(( + "eth_write_port: cpf_setgrant_direct failed: %d\n", + errno)); + } + pack_size += iovec[i].iov_size= pack_ptr->acc_length; + } + if (i>= IOVEC_NR) + { + pack= bf_pack(pack); /* packet is too fragmented */ + eth_port->etp_wr_pack= pack; + pack_size= 0; + for (i=0, pack_ptr= pack; iacc_next) + { + r= cpf_setgrant_direct(iovec[i].iov_grant, + eth_port->etp_osdep.etp_task, + (vir_bytes)ptr2acc_data(pack_ptr), + (vir_bytes)pack_ptr->acc_length, + CPF_READ); + if (r != 0) { - ip_panic(("unable to receive")); + ip_panic(( + "eth_write_port: cpf_setgrant_direct failed: %d\n", + errno)); } - - compare(repl_mess.m_type, ==, DL_TASK_REPLY); - eth_rec(&repl_mess); + pack_size += iovec[i].iov_size= pack_ptr->acc_length; } - } while (r == ELOCKED); - - if (r < 0) + } + assert (i< IOVEC_NR); + assert (pack_size >= ETH_MIN_PACK_SIZE); + + r= cpf_setgrant_direct(eth_port->etp_osdep.etp_wr_vec_grant, + eth_port->etp_osdep.etp_task, + (vir_bytes)iovec, + (vir_bytes)(i * sizeof(iovec[0])), + CPF_READ); + if (r != 0) { - printf("eth_set_rec_conf: sendrec to %d failed: %d\n", - eth_port->etp_osdep.etp_task, r); - return; + ip_panic(( + "eth_write_port: cpf_setgrant_direct failed: %d\n", + errno)); } + m.DL_COUNT= i; + m.DL_GRANT= eth_port->etp_osdep.etp_wr_vec_grant; + m.m_type= DL_WRITEV_S; + + m.DL_PORT= eth_port->etp_osdep.etp_port; + m.DL_PROC= this_proc; + m.DL_MODE= DL_NOMODE; + + assert(eth_port->etp_osdep.etp_state == OEPS_IDLE); + r= asynsend(eth_port->etp_osdep.etp_task, &m); - assert (mess.m_type == DL_CONF_REPLY); - if (mess.m3_i1 != eth_port->etp_osdep.etp_port) + if (r < 0) { - ip_panic(("got reply for wrong port")); + printf("eth_issue_send: send to %d failed: %d\n", + eth_port->etp_osdep.etp_task, r); + return; } + eth_port->etp_osdep.etp_state= OEPS_SEND_SENT; } PRIVATE void write_int(eth_port) @@ -708,181 +749,68 @@ eth_port_t *eth_port; assert(!eth_port->etp_vlan); assert(!(eth_port->etp_flags & (EPF_READ_IP|EPF_READ_SP))); - do + if (eth_port->etp_osdep.etp_state != OEPS_IDLE) { - assert (!eth_port->etp_rd_pack); + printf("setup_read: setting OEPF_NEED_RECV\n"); + eth_port->etp_osdep.etp_flags |= OEPF_NEED_RECV; - iovec= eth_port->etp_osdep.etp_rd_iovec; - pack= bf_memreq (ETH_MAX_PACK_SIZE_TAGGED); + return; + } - for (i=0, pack_ptr= pack; iacc_next) - { - r= cpf_setgrant_direct(iovec[i].iov_grant, - eth_port->etp_osdep.etp_task, - (vir_bytes)ptr2acc_data(pack_ptr), - (vir_bytes)pack_ptr->acc_length, - CPF_WRITE); - if (r != 0) - { - ip_panic(( - "mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n", - errno)); - } - iovec[i].iov_size= (vir_bytes)pack_ptr->acc_length; - } - assert (!pack_ptr); + assert (!eth_port->etp_rd_pack); - r= cpf_setgrant_direct(eth_port->etp_osdep.etp_rd_vec_grant, + iovec= eth_port->etp_osdep.etp_rd_iovec; + pack= bf_memreq (ETH_MAX_PACK_SIZE_TAGGED); + + for (i=0, pack_ptr= pack; iacc_next) + { + r= cpf_setgrant_direct(iovec[i].iov_grant, eth_port->etp_osdep.etp_task, - (vir_bytes)iovec, - (vir_bytes)(i * sizeof(iovec[0])), - CPF_READ); + (vir_bytes)ptr2acc_data(pack_ptr), + (vir_bytes)pack_ptr->acc_length, + CPF_WRITE); if (r != 0) { ip_panic(( "mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n", errno)); } + iovec[i].iov_size= (vir_bytes)pack_ptr->acc_length; + } + assert (!pack_ptr); - mess1.m_type= DL_READV_S; - mess1.DL_PORT= eth_port->etp_osdep.etp_port; - mess1.DL_PROC= this_proc; - mess1.DL_COUNT= i; - mess1.DL_GRANT= eth_port->etp_osdep.etp_rd_vec_grant; - - for (;;) - { - if (recv_debug) - { - printf("eth%d: sending DL_READV_S\n", - mess1.DL_PORT); - } - r= sendrec(eth_port->etp_osdep.etp_task, &mess1); - if (r != ELOCKED) - break; - - /* ethernet task is sending to this task, I hope */ - r= receive(eth_port->etp_osdep.etp_task, &block_msg); - if (r < 0) - ip_panic(("unable to receive")); - - loc_port= eth_port; - if (loc_port->etp_osdep.etp_port != block_msg.DL_PORT || - loc_port->etp_osdep.etp_task != - block_msg.m_source) - { - loc_port= find_port(&block_msg); - } - assert(block_msg.DL_STAT & - (DL_PACK_SEND|DL_PACK_RECV)); - if (block_msg.DL_STAT & DL_PACK_SEND) - { - loc_port->etp_osdep.etp_sendrepl= - block_msg; - ev_arg.ev_ptr= loc_port; - assert(!loc_port->etp_osdep.etp_send_ev); - loc_port->etp_osdep.etp_send_ev= 1; - ev_enqueue(&loc_port->etp_sendev, - eth_sendev, ev_arg); - } - if (block_msg.DL_STAT & DL_PACK_RECV) - { - if (recv_debug) - { - printf( - "setup_read(block_msg): eth%d got DL_PACK_RECV\n", - block_msg.DL_PORT); - } - assert(loc_port != eth_port); - loc_port->etp_osdep.etp_recvrepl= block_msg; - ev_arg.ev_ptr= loc_port; - ev_enqueue(&loc_port->etp_osdep.etp_recvev, - eth_recvev, ev_arg); - } - } - - if (r < 0) - { - printf("mnx_eth`setup_read: sendrec to %d failed: %d\n", - eth_port->etp_osdep.etp_task, r); - eth_port->etp_rd_pack= pack; - eth_port->etp_flags |= EPF_READ_IP; - continue; - } - - if (mess1.m_type != DL_TASK_REPLY || - mess1.DL_PORT != eth_port->etp_osdep.etp_port || - mess1.DL_PROC != this_proc) - { - printf("mnx_eth`setup_read: bad type, port or proc\n"); - printf("got type %d, port %d, proc %d\n", - mess1.m_type, mess1.DL_PORT, mess1.DL_PROC); - continue; - } + r= cpf_setgrant_direct(eth_port->etp_osdep.etp_rd_vec_grant, + eth_port->etp_osdep.etp_task, + (vir_bytes)iovec, + (vir_bytes)(i * sizeof(iovec[0])), + CPF_READ); + if (r != 0) + { + ip_panic(( + "mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n", + errno)); + } - if ((mess1.DL_STAT >> 16) != OK) - { - printf( - "mnx_eth`setup_read: bad value in DL_STAT: 0x%x\n", - mess1.DL_STAT); - mess1.DL_STAT= 0; - } + mess1.m_type= DL_READV_S; + mess1.DL_PORT= eth_port->etp_osdep.etp_port; + mess1.DL_PROC= this_proc; + mess1.DL_COUNT= i; + mess1.DL_GRANT= eth_port->etp_osdep.etp_rd_vec_grant; - if (mess1.DL_STAT & DL_PACK_RECV) - { - if (recv_debug) - { - printf( - "setup_read(mess1): eth%d: got DL_PACK_RECV\n", - mess1.DL_PORT); - } + assert(eth_port->etp_osdep.etp_state == OEPS_IDLE); - if (mess1.DL_COUNT < ETH_MIN_PACK_SIZE) - { - printf( - "mnx_eth`setup_read: packet size too small (%d)\n", - mess1.DL_COUNT); - bf_afree(pack); - } - else - { - /* packet received */ - pack_ptr= bf_cut(pack, 0, mess1.DL_COUNT); - bf_afree(pack); - - assert(!no_ethWritePort); - no_ethWritePort= 1; - eth_arrive(eth_port, pack_ptr, mess1.DL_COUNT); - assert(no_ethWritePort); - no_ethWritePort= 0; - } - } - else - { - /* no packet received */ - eth_port->etp_rd_pack= pack; - eth_port->etp_flags |= EPF_READ_IP; - } + r= asynsend(eth_port->etp_osdep.etp_task, &mess1); + eth_port->etp_osdep.etp_state= OEPS_RECV_SENT; - if (mess1.DL_STAT & DL_PACK_SEND) - { - if (eth_port->etp_osdep.etp_send_ev) - { - printf( - "mnx_eth`setup_read: etp_send_ev is set, ignoring DL_PACK_SEND\n"); - } - else - { - eth_port->etp_osdep.etp_sendrepl= mess1; - ev_arg.ev_ptr= eth_port; - assert(!eth_port->etp_osdep.etp_send_ev); - eth_port->etp_osdep.etp_send_ev= 1; - ev_enqueue(ð_port->etp_sendev, eth_sendev, - ev_arg); - } - } - } while (!(eth_port->etp_flags & EPF_READ_IP)); + if (r < 0) + { + printf( + "mnx_eth`setup_read: asynsend to %d failed: %d\n", + eth_port->etp_osdep.etp_task, r); + } + eth_port->etp_rd_pack= pack; + eth_port->etp_flags |= EPF_READ_IP; eth_port->etp_flags |= EPF_READ_SP; } @@ -958,15 +886,58 @@ int tasknr; { int i, r; unsigned flags, dl_flags; + cp_grant_id_t gid; message mess; - eth_port_t *loc_port; printf("eth_restart: restarting eth%d, task %d, port %d\n", eth_port-eth_port_table, tasknr, eth_port->etp_osdep.etp_port); + if (eth_port->etp_osdep.etp_task == tasknr) + { + printf( + "eth_restart: task number did not change. Aborting restart\n"); + return; + } eth_port->etp_osdep.etp_task= tasknr; + switch(eth_port->etp_osdep.etp_state) + { + case OEPS_CONF_SENT: + case OEPS_RECV_SENT: + case OEPS_SEND_SENT: + /* We can safely ignore the pending CONF, RECV, and SEND + * requests. + */ + eth_port->etp_osdep.etp_state= OEPS_IDLE; + break; + case OEPS_GETSTAT_SENT: + /* Set the OEPF_NEED_STAT to trigger a new request */ + eth_port->etp_osdep.etp_flags |= OEPF_NEED_STAT; + eth_port->etp_osdep.etp_state= OEPS_IDLE; + break; + } + + /* If there is a pending GETSTAT request then we have to create a + * new grant. + */ + if (eth_port->etp_osdep.etp_flags & OEPF_NEED_STAT) + { + assert(eth_port->etp_osdep.etp_stat_gid != -1); + cpf_revoke(eth_port->etp_osdep.etp_stat_gid); + + gid= cpf_grant_direct(eth_port->etp_osdep.etp_task, + (vir_bytes)eth_port->etp_osdep.etp_stat_buf, + sizeof(*eth_port->etp_osdep.etp_stat_buf), CPF_WRITE); + if (gid == -1) + { + ip_panic(( + "eth_restart: cpf_grant_direct failed: %d\n", + errno)); + } + eth_port->etp_osdep.etp_stat_gid= gid; + } + flags= eth_port->etp_osdep.etp_recvconf; dl_flags= DL_NOMODE; if (flags & NWEO_EN_BROAD) @@ -980,57 +951,16 @@ int tasknr; mess.DL_PROC= this_proc; mess.DL_MODE= dl_flags; - r= sendrec(eth_port->etp_osdep.etp_task, &mess); - /* YYY */ + compare(eth_port->etp_osdep.etp_state, ==, OEPS_IDLE); + r= asynsend(eth_port->etp_osdep.etp_task, &mess); if (r<0) { printf( - "eth_restart: sendrec to ethernet task %d failed: %d\n", + "eth_restart: send to ethernet task %d failed: %d\n", eth_port->etp_osdep.etp_task, r); return; } - - if (mess.m3_i1 == ENXIO) - { - printf( - "osdep_eth_init: no ethernet device at task=%d,port=%d\n", - eth_port->etp_osdep.etp_task, - eth_port->etp_osdep.etp_port); - return; - } - if (mess.m3_i1 < 0) - ip_panic(("osdep_eth_init: DL_INIT returned error %d\n", - mess.m3_i1)); - - if (mess.m3_i1 != eth_port->etp_osdep.etp_port) - { - ip_panic(( -"osdep_eth_init: got reply for wrong port (got %d, expected %d)\n", - mess.m3_i1, eth_port->etp_osdep.etp_port)); - } - - eth_port->etp_flags |= EPF_ENABLED; - - eth_port->etp_ethaddr= *(ether_addr_t *)mess.m3_ca1; - if (!(eth_port->etp_flags & EPF_GOT_ADDR)) - { - eth_port->etp_flags |= EPF_GOT_ADDR; - eth_restart_ioctl(eth_port); - - /* Also update any VLANs on this device */ - for (i=0, loc_port= eth_port_table; ietp_flags & EPF_ENABLED)) - continue; - if (loc_port->etp_vlan_port != eth_port) - continue; - - loc_port->etp_ethaddr= eth_port->etp_ethaddr; - loc_port->etp_flags |= EPF_GOT_ADDR; - eth_restart_ioctl(loc_port); - } - } + eth_port->etp_osdep.etp_state= OEPS_CONF_SENT; if (eth_port->etp_wr_pack) { @@ -1044,7 +974,76 @@ int tasknr; eth_port->etp_rd_pack= NULL; eth_port->etp_flags &= ~(EPF_READ_IP|EPF_READ_SP); } - setup_read (eth_port); + +} + +PRIVATE void send_getstat(eth_port) +eth_port_t *eth_port; +{ + int r; + message mess; + + mess.m_type= DL_GETSTAT_S; + mess.DL_PORT= eth_port->etp_osdep.etp_port; + mess.DL_PROC= this_proc; + mess.DL_GRANT= eth_port->etp_osdep.etp_stat_gid; + + assert(eth_port->etp_osdep.etp_state == OEPS_IDLE); + + r= asynsend(eth_port->etp_osdep.etp_task, &mess); + eth_port->etp_osdep.etp_state= OEPS_GETSTAT_SENT; + + if (r != OK) + ip_panic(( "eth_get_stat: asynsend failed: %d", r)); +} + +PRIVATE asynmsg_t *msgtable= NULL; +PRIVATE size_t msgtable_n= 0; + +PRIVATE int asynsend(dst, mp) +endpoint_t dst; +message *mp; +{ + int i; + unsigned flags; + + if (msgtable == NULL) + { + printf("asynsend: allocating msg table\n"); + msgtable_n= 5; + msgtable= malloc(msgtable_n * sizeof(msgtable[0])); + for (i= 0; i= msgtable_n) + ip_panic(( "asynsend: should resize table" )); + msgtable[i].dst= dst; + msgtable[i].msg= *mp; + msgtable[i].flags= AMF_VALID; /* Has to be last. The kernel + * scans this table while we are + * sleeping. + */ + + /* Tell the kernel to rescan the table */ + return senda(msgtable, msgtable_n); } /* diff --git a/servers/inet/osdep_eth.h b/servers/inet/osdep_eth.h index 0bfec142f..c19c3171f 100644 --- a/servers/inet/osdep_eth.h +++ b/servers/inet/osdep_eth.h @@ -16,6 +16,8 @@ Copyright 1995 Philip Homburg typedef struct osdep_eth_port { + int etp_state; + int etp_flags; int etp_task; int etp_port; int etp_recvconf; @@ -27,8 +29,31 @@ typedef struct osdep_eth_port event_t etp_recvev; message etp_sendrepl; message etp_recvrepl; + cp_grant_id_t etp_stat_gid; + eth_stat_t *etp_stat_buf; } osdep_eth_port_t; +#define OEPS_INIT 0 /* Not initialized */ +#define OEPS_CONF_SENT 1 /* Conf. request has been sent */ +#define OEPS_IDLE 2 /* Device is ready to accept requests */ +#define OEPS_RECV_SENT 3 /* Recv. request has been sent */ +#define OEPS_SEND_SENT 4 /* Send request has been sent */ +#define OEPS_GETSTAT_SENT 5 /* GETSTAT request has been sent */ + +#define OEPF_EMPTY 0 +#define OEPF_NEED_RECV 1 /* Issue recv. request when the state becomes + * idle + */ +#define OEPF_NEED_SEND 2 /* Issue send request when the state becomes + * idle + */ +#define OEPF_NEED_CONF 4 /* Issue conf request when the state becomes + * idle + */ +#define OEPF_NEED_STAT 8 /* Issue getstat request when the state becomes + * idle + */ + #endif /* INET__OSDEP_ETH_H */ /*