openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

verinet.c (30206B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * Routines for accessing the network and sending RPC commands to/from
      8  * the PLI test-server.
      9  */
     10 
     11 #include <shared/bsl.h>
     12 
     13 #include <unistd.h>
     14 #include <stdarg.h>
     15 #include <assert.h>
     16 #include <sys/socket.h>
     17 #include <sys/time.h>
     18 #include <stdlib.h>
     19 #include <netinet/in.h>
     20 #ifndef VXWORKS
     21 #include <string.h>
     22 #include <netdb.h>
     23 #endif
     24 #include <arpa/inet.h>
     25 #include <errno.h>
     26 #include <ctype.h>
     27 
     28 #ifdef VXWORKS
     29 #include <vxWorks.h>
     30 #include <sockLib.h>
     31 #endif
     32 
     33 #include <sal/core/sync.h>
     34 #include <sal/appl/io.h>
     35 #include <soc/debug.h>	
     36 
     37 #include "verinet.h"
     38 
     39 #include <sim/pcid/pcid.h>
     40 #define _BCM_RPC_ERROR_COUNT_MAX (10)
     41 /*
     42  * One verinet structure per devNo (unit)
     43  */
     44 verinet_t verinet[N_VERINET_DEVICES];
     45 
     46 /*
     47  *  Write "n" bytes to a descriptor.
     48  */
     49 int writen(int fd, void *ptr, int nbytes)
     50 {
     51     int nleft, nwritten;
     52     nleft = nbytes;
     53     while (nleft > 0){
     54 	nwritten = write(fd, ptr, nleft);
     55 	if (nwritten <= 0)
     56 	    return(nwritten);               
     57 	nleft -= nwritten;
     58 	ptr = (char *)ptr + nwritten;
     59     }
     60     return(nbytes - nleft);
     61 }
     62 
     63 
     64 /*
     65  *  Read "n" bytes from a descriptor.
     66  */
     67 int readn(int fd, void* ptr, int nbytes)
     68 {
     69     int nleft, nread;
     70     nleft = nbytes;
     71     while (nleft > 0) {
     72 	nread = read(fd, ptr, nleft);
     73 	if (nread < 0)
     74 	    return(nread);          	/* error, return < 0 */
     75 	else if (nread == 0)
     76 	    break;                  	/* EOF */
     77 	nleft -= nread;
     78 	ptr = (char *)ptr + nread;
     79     }
     80     return(nbytes - nleft);         	/* return >= 0 */
     81 }
     82 
     83 /*
     84  * Get the port number to which a socket is bound.
     85  */
     86 
     87 int getsockport(int sock_fd)
     88 {
     89     struct sockaddr_in name;
     90     socklen_t name_len;
     91 
     92     name_len = sizeof (name);
     93 
     94     if (getsockname(sock_fd, (struct sockaddr *)&name, &name_len) < 0) {
     95 	perror("getsockname");
     96 	return 0;
     97     }
     98 
     99     return ntohs(name.sin_port);
    100 }
    101 
    102 /*
    103  * reads an RPC command.
    104  * Parameters:
    105  *  sockfd -socket file descriptor.
    106  * Returns:
    107  *	-1 on error (nothing returned in rpc_cmd_t *)
    108  *	 0 if no command is found (nothing returned in rpc_cmd_t *)
    109  *	 1 if command is found (returned in rpc_cmd_t *)
    110  */
    111 
    112 int get_command(int sockfd, struct timeval* tv, rpc_cmd_t* command)
    113 {
    114     int i;
    115     fd_set read_vect;
    116     uint32 swap;
    117 
    118     LOG_VERBOSE(BSL_LS_SYS_VERINET,
    119                 (BSL_META("get_command: sockfd=%d\n"),
    120                  sockfd));
    121 
    122     assert(sockfd > 2);		/* Verinet initialized? */
    123 
    124     /* Setup bitmap for read notification ... */
    125     FD_ZERO(&read_vect);
    126     FD_SET(sockfd, &read_vect);
    127 
    128     while (1) {
    129         if(select(sockfd+1,&read_vect,(fd_set*)0x0,(fd_set*)0x0,tv)<0){
    130             if (errno == EINTR) {
    131                 /* 
    132                  * Interrupted by a signal such as a GPROF alarm so
    133                  * restart the call
    134                  */
    135                 continue;
    136             }
    137             perror("get_command: select error");
    138             goto fail;
    139         } else {
    140             break;
    141         }
    142     }
    143     /*
    144      * Data ready to be read.
    145      */
    146     if( FD_ISSET(sockfd, &read_vect)){
    147 
    148 	/*
    149 	 * Read RPC opcode, argcount, status
    150 	 */
    151 #define SOCKET_GET_U32(sockfd, swap, where, what) \
    152     do { \
    153 	if(readn(sockfd, &(swap), sizeof(uint32)) < sizeof(uint32)) { \
    154 	    cli_out("get_command: could not read RPC %s\n", what); \
    155 	    goto fail; \
    156 	} \
    157 	(where) = ntohl(swap);  /* Convert to host order */ \
    158     } while (0)
    159 
    160         SOCKET_GET_U32(sockfd, swap, command->opcode, "opcode");
    161         SOCKET_GET_U32(sockfd, swap, command->argcount, "arg count");
    162 
    163         if (RPC_OP_USE_STRING(command->opcode)) {
    164             if (command->argcount > (sizeof(uint32) * MAX_RPC_ARGS)) {
    165                 cli_out("RPC string too long (get): %d\n", command->argcount);
    166                 goto fail;
    167             }
    168             SOCKET_GET_U32(sockfd, swap, command->args[0], "pkt address");
    169             /* coverity[tainted_data] */
    170             if (readn(sockfd, &command->args[1], command->argcount) <
    171                 command->argcount) {
    172                 cli_out("get_command: could not read all of string. %d.\n",
    173                        command->argcount);
    174                 goto fail;
    175             }
    176         } else {
    177             if (command->argcount > MAX_RPC_ARGS) {
    178                 cli_out("get_command: bogus argcount (%d) from rpc socket\n",
    179                        command->argcount);
    180                 goto fail;
    181             }
    182             /* Read each argument into command struct ... */
    183             for(i = 0; i < command->argcount; i++){
    184                 SOCKET_GET_U32(sockfd, swap, command->args[i], "argument");
    185             }
    186         }
    187 
    188         SOCKET_GET_U32(sockfd, swap, command->status, "status");
    189 
    190 #undef SOCKET_GET_U32
    191 
    192         LOG_INFO(BSL_LS_SYS_VERINET,
    193                  (BSL_META("get_command: opcode=0x%x nargs=%d status=%d\n"),
    194                   command->opcode, command->argcount, command->status));
    195 
    196 	return 1;
    197     }
    198 
    199     return 0;	/* Time expire with no command */
    200 
    201  fail:
    202     return -1;
    203 }
    204 
    205 
    206 /*
    207  * Non-blocking version of actual call made by PLI interface.
    208  * Note that the timeout is 0 which guarantees that the Verilog
    209  * model does not block.
    210  *
    211  * Returns:
    212  *	-1 on error (nothing returned in rpc_cmd_t *)
    213  *	 0 if no command is found (nothing returned in rpc_cmd_t *)
    214  *	 1 if command is found (returned in rpc_cmd_t *)
    215  */
    216 int poll_command(int sockfd, rpc_cmd_t* command)
    217 {
    218     struct timeval tv = {0,0};
    219     return get_command(sockfd,(struct timeval*)&tv,command);
    220 }
    221 
    222 /*
    223  * Blocking version of actual call made by PLI interface.
    224  *
    225  * Returns:
    226  *	-1 on error (nothing returned in rpc_cmd_t *)
    227  *	 0 on success
    228  */
    229 int wait_command(int sockfd, rpc_cmd_t* command)
    230 {
    231     return get_command(sockfd,(struct timeval*)0,command);
    232 }
    233 
    234 
    235 /*
    236  * Writes an RPC command to the server.
    237  * Parameters:
    238  * 1) sockfd-socket file descriptor.
    239  * 2) command -rpc_cmd_t filled in for the necessary command.
    240  *
    241  * Return values:
    242  *  RPC_OK on success
    243  *  RPC_FAIL on error
    244  */
    245 int write_command(int sockfd, rpc_cmd_t* command)
    246 {
    247     int i;
    248     uint8 write_buf[sizeof(uint32) * (MAX_RPC_ARGS + 4)];
    249     int write_cnt;
    250     uint32 swap;
    251     static int error_count = 0;
    252 
    253     LOG_INFO(BSL_LS_SYS_VERINET,
    254              (BSL_META("write_command: sockfd=%d opcode=0x%x nargs=%d status=%d\n"),
    255               sockfd, command->opcode, command->argcount, command->status));
    256 
    257     assert(sockfd > 2);	/* Verinet initialized? */
    258 
    259     /*
    260      * Each value is converted to network byte order before writing.
    261      * On some hosts (e.g. SPARC,MIPS, COLDFire which run in big-endian
    262      * mode, these calls are NOPS, but we include them here for
    263      * correctness and porting to other platforms).
    264      *
    265      * Data is saved in a buffer and written using one write to make
    266      * performance over the network about a ZILLION times faster.
    267      */
    268 
    269     write_cnt = 0;
    270 
    271     /* RPC opcode */
    272 #define STORE_U32(val, buf, swap, idx) \
    273     do { \
    274         swap = htonl(val); \
    275         sal_memcpy(&(buf[idx]), &(swap), sizeof(uint32)); \
    276         idx += sizeof(uint32); \
    277     } while(0)
    278 
    279     /* Store opcode and argcount */
    280     STORE_U32(command->opcode, write_buf, swap, write_cnt);
    281     STORE_U32(command->argcount, write_buf, swap, write_cnt);
    282 
    283     /* Each argument from command struct, unless as string */
    284 
    285     if (RPC_OP_USE_STRING(command->opcode)) {
    286         /* Arg 0 is address */
    287         STORE_U32(command->args[0], write_buf, swap, write_cnt);
    288         /* Here, arg count is a number of bytes */
    289         if ((command->argcount + write_cnt) > (sizeof(uint32) * MAX_RPC_ARGS)) {
    290             cli_out("RPC string too long (send0: %d\n", command->argcount);
    291             goto fail;
    292         }
    293         sal_memcpy(&write_buf[write_cnt], (uint8 *) &command->args[1],
    294                command->argcount);
    295         write_cnt += command->argcount;
    296     } else {
    297         if (command->argcount > MAX_RPC_ARGS) {
    298             cli_out("RPC: too many arguments. %d\n", command->argcount);
    299             goto fail;
    300         }
    301         for(i = 0; i < command->argcount; i++) {
    302             STORE_U32(command->args[i], write_buf, swap, write_cnt);
    303         }
    304     }
    305 
    306     /* Store status */
    307     STORE_U32(command->status, write_buf, swap, write_cnt);
    308 
    309 #undef STORE_U32
    310 
    311     /* Perform write */
    312     if (writen(sockfd, write_buf, write_cnt) < 0) {
    313 	cli_out("write_command: could not write RPC request.\n");
    314 	goto fail;
    315     }
    316 
    317     goto done;
    318 
    319     /* Failure */
    320  fail:
    321     error_count ++;
    322     if (error_count > _BCM_RPC_ERROR_COUNT_MAX) {
    323 	    cli_out("write_command: Too many write failures.\n");
    324         assert (0);
    325     } 
    326     return RPC_FAIL;
    327 
    328     /* Success */
    329  done:
    330     return RPC_OK;
    331 }
    332 
    333 /*
    334  * Creates an RPC command.
    335  * Generic routine used by all RPC command stubs below.
    336  * NOTE: this should be used the same way by all stubs since the
    337  * ordering of arguments is significant.
    338  */
    339 
    340 void make_rpc(rpc_cmd_t* command,
    341 	      uint32 opcode,
    342 	      uint32 status,
    343 	      uint32 argcount,
    344 	      ...)
    345 {
    346     int i;
    347     va_list ap;
    348     command->opcode = opcode;
    349     command->argcount = argcount;
    350     command->status = status;
    351     va_start(ap, argcount);
    352     for( i = 0; i < argcount; i++)
    353 	command->args[i] = va_arg(ap, uint32);
    354     va_end(ap);
    355 }
    356 
    357 
    358 /*
    359  * Creates an RPC command with data as a string.
    360  */
    361 
    362 void make_rpc_string(rpc_cmd_t* command,
    363                      uint32 opcode,
    364                      uint32 status,
    365                      uint32 addr,
    366                      uint8 *data,
    367                      uint32 len)
    368 {
    369     command->opcode = opcode;
    370     command->argcount = len;
    371     command->status = status;
    372     command->args[0] = addr;
    373     if (data) {
    374         sal_memcpy((uint8 *)&command->args[1], data, len);
    375     }
    376 }
    377 
    378 /*
    379  * Makes an RPC structure to be sent to the server for the client (request);
    380  * This is for the setmem(addr,data) call.
    381  */
    382 void make_rpc_setmem_req(rpc_cmd_t* cmd, uint32 addr, uint32 data)
    383 {
    384     make_rpc(cmd,
    385 	     RPC_DMAC_WRITE_REQ,
    386 	     RPC_OUTSTANDING,
    387 	     2,
    388 	     addr,
    389 	     data);
    390 }
    391 /*
    392  * Makes an RPC structure to be sent back to the client in response.
    393  * This is for the response to the client for setmem(addr,data).
    394  * Here we send the updated value of the data @ addr.
    395  */
    396 void make_rpc_setmem_resp(rpc_cmd_t* cmd, uint32 data)
    397 {
    398     make_rpc(cmd,
    399 	     RPC_DMAC_WRITE_RESP,
    400 	     RPC_OK,
    401 	     1,
    402 	     data);
    403 }
    404 
    405 
    406 /*
    407  * Makes an RPC structure to be sent to the server for the client (request);
    408  * this is for the getmem(addr) call.
    409  */
    410 void make_rpc_getmem_req(rpc_cmd_t* cmd, uint32 addr)
    411 {
    412     make_rpc(cmd,
    413 	     RPC_DMAC_READ_REQ,
    414 	     RPC_OUTSTANDING,
    415 	     1,
    416 	     addr);
    417 }
    418 
    419 /*
    420  * Makes an RPC response to send back to the client. This is for
    421  * a response to getmem(addr).
    422  */
    423 void make_rpc_getmem_resp(rpc_cmd_t* cmd, uint32 data)
    424 {
    425     make_rpc(cmd,
    426 	     RPC_DMAC_READ_RESP,
    427 	     RPC_OK,
    428 	     1,
    429 	     data);
    430 }
    431 
    432 
    433 
    434 /*
    435  * Makes an RPC structure to be sent to the server for the client (request);
    436  * This is for the pli_setreg() call.
    437  */
    438 void make_rpc_setreg_req(rpc_cmd_t* cmd,
    439 			 uint32 regtype, uint32 regnum, uint32 regval)
    440 {
    441     make_rpc(cmd,
    442 	     RPC_SETREG_REQ,
    443 	     RPC_OUTSTANDING,
    444 	     3,
    445 	     regnum,
    446 	     regval,
    447 	     regtype);
    448 }
    449 
    450 /*
    451  * Makes an RPC structure to be sent to the client from the server
    452  * (response); this is for the response to the pli_setreg() call.
    453  */
    454 
    455 void make_rpc_setreg_resp(rpc_cmd_t* cmd,
    456 			  uint32 regval)
    457 {
    458     make_rpc(cmd,
    459 	     RPC_SETREG_RESP,
    460 	     RPC_OK,
    461 	     1,
    462 	     regval);
    463 }
    464 
    465 
    466 /*
    467  * Makes an RPC structure to be sent to the server for the client (request);
    468  */
    469 void make_rpc_ioctl_req(rpc_cmd_t* cmd, uint32 op, uint32 p1, uint32 p2)
    470 {
    471 }
    472 
    473 
    474 /*
    475  * Makes an RPC structure to be sent to the server for the client (request);
    476  * this is for the pli_getreg() call.
    477  */
    478 void make_rpc_getreg_req(rpc_cmd_t* cmd,
    479 			 uint32 regtype, uint32 regnum)
    480 {
    481     make_rpc(cmd,
    482 	     RPC_GETREG_REQ,
    483 	     RPC_OUTSTANDING,
    484 	     2,
    485 	     regnum,
    486 	     regtype);
    487 }
    488 
    489 
    490 /*
    491  * Makes an RPC structure to be sent to the client from the server
    492  * (response); this is for the response to the pli_getreg() call.
    493  * NOTE: buf must be 32 byte in size.
    494  */
    495 void make_rpc_getreg_resp(rpc_cmd_t* cmd,
    496 			  uint32 status,
    497 			  uint32 regval,
    498 			  char* buf32byte)
    499 {
    500     uint32	w[8];
    501 
    502     /* Kludge: shove a 32 byte buffer into some integers.*/
    503 
    504     memcpy((char *) w, buf32byte, 32);	/* Get aligned on word boundary */
    505 
    506     make_rpc(cmd,
    507 	     RPC_GETREG_RESP,
    508 	     RPC_OK,
    509 	     10,
    510 	     status,
    511 	     regval,
    512 	     w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7]);
    513 }
    514 
    515 
    516 
    517 /*
    518  * Makes an RPC structure to be sent to the server for the client (request);
    519  * this is for the pli_interrupt() call.
    520  */
    521 void make_rpc_intr_req(rpc_cmd_t* cmd,
    522 		       uint32 cause)
    523 {
    524     make_rpc(cmd,
    525 	     RPC_SEND_INTR,
    526 	     RPC_OUTSTANDING,
    527 	     1,
    528 	     cause);
    529 }
    530 
    531 /*
    532  * Makes an RPC structure to be sent to the server for the client (request);
    533  * this is for the response to the pli_interrupt() call.
    534  */
    535 void make_rpc_intr_resp(rpc_cmd_t* cmd,
    536 			uint32 cause)
    537 {
    538     make_rpc(cmd,
    539 	     RPC_SEND_INTR,
    540 	     RPC_OK,
    541 	     1,
    542 	     cause);
    543 }
    544 
    545 
    546 /*
    547  * Makes an RPC disconnect request structure.
    548  */
    549 void make_rpc_disconnect_req(rpc_cmd_t* cmd)
    550 {
    551     make_rpc(cmd,
    552 	     RPC_DISCONNECT,
    553 	     RPC_OUTSTANDING,
    554 	     0,0,0);
    555 }
    556 
    557 /*
    558  * Makes an RPC registration request. This call will register the
    559  * client to receive interrupts on one port, and dma requests (r/w)
    560  * on another.
    561  */
    562 
    563 void make_rpc_register_req(rpc_cmd_t* cmd,
    564 			   int intPort,
    565 			   int dmacPort,
    566 			   uint32 netAddr)
    567 {
    568     make_rpc(cmd,
    569 	     RPC_REGISTER_CLIENT,
    570 	     RPC_OUTSTANDING,
    571 	     3,
    572 	     intPort,
    573 	     dmacPort,
    574 	     netAddr);
    575 }
    576 
    577 /*
    578  * RPC registration response: send RPC_OK on success.
    579  */
    580 void make_rpc_register_resp(rpc_cmd_t* cmd,
    581 			    uint32 status)
    582 {
    583     make_rpc(cmd,
    584 	     RPC_REGISTER_CLIENT,
    585 	     RPC_OK,
    586 	     1,
    587 	     status);
    588 }
    589 
    590 
    591 int pli_client_count(void)
    592 {
    593     char *s;
    594 
    595     /* Returns number of PLI clients expected to be running. */
    596     /* This should be set in the environment variable SOC_TARGET_COUNT. */
    597 
    598     s = getenv("SOC_TARGET_COUNT");
    599 
    600     return (s == NULL) ? 1 : atoi(s);
    601 }
    602 
    603 /*
    604  * Generic network routines for client and server.
    605  */
    606 
    607 /*
    608  * Connect a client to the server.
    609  * This performs the following PLI client-side initialization.
    610  *
    611  * 1) Initialize a lock for PLI setreg/getreg accesses
    612  * 2) Input connection host/port information from user.
    613  * 3) Setup DMA controller task to listen (locally) on dmaPort.
    614  * 4) Setup Interrupt Controller task to listen (locally) on intPort.
    615  * 5) Register an interrupt callback routine (passed in).
    616  * 6) Setup a local socket file descriptor to communicate with
    617  *    pliHost on the given pliPort.
    618  * 7) Register the client with the server on pliHost.
    619  *    The server may immediately start sending DMA and INTR requests.
    620  * Return:
    621  *    0 on success, a negative value on error.
    622  */
    623 int pli_client_attach(int devNo)
    624 {
    625     verinet_t *v = &verinet[devNo];
    626     struct sockaddr_in cli_addr;
    627     socklen_t cli_addr_size;
    628     struct sockaddr_in srv_addr;
    629 #ifndef VXWORKS
    630     struct hostent *hostentPtr = NULL;
    631 #endif
    632     rpc_cmd_t cmd;
    633     char tmp[80], *s;
    634     int rv = -1;
    635 
    636     memset(v, 0, sizeof (*v));
    637 
    638     v->devNo = devNo;
    639 
    640     v->sockfd = -1;
    641     v->skipTestInt = 1;
    642 
    643     v->pli_mutex = sal_mutex_create("PLI socket mutex");
    644 
    645     /* Setup target host */
    646     s = getenv("SOC_TARGET_SERVER");
    647     if (!s) {
    648 	snprintf(tmp, sizeof(tmp), "SOC_TARGET_SERVER%d", devNo);
    649 	s = getenv(tmp);
    650     }
    651     if(!s) {
    652 	snprintf(tmp, sizeof(tmp),
    653 		"Enter unit %d PLI server host"
    654 #ifdef VXWORKS
    655 		" address"
    656 #else
    657 		"name [localhost]"
    658 #endif
    659 		": ",
    660 		devNo);
    661 	sal_readline(tmp, v->pliHost, sizeof (v->pliHost), 0);
    662         if (sal_strlen(v->pliHost) == 0) {
    663             sal_strncpy(v->pliHost, "localhost", sizeof(v->pliHost) - 1);
    664         }
    665     } else {
    666 	if(strlen(s) >= sizeof(v->pliHost))
    667            strncpy(v->pliHost, s, sizeof(v->pliHost) - 1);
    668         else
    669            strncpy(v->pliHost, s, strlen(s));
    670     }    
    671     /* Setup target port */
    672     s = getenv("SOC_TARGET_PORT");
    673     if (!s) {
    674 	snprintf(tmp, sizeof(tmp), "SOC_TARGET_PORT%d", devNo);
    675 	s = getenv(tmp);
    676     }
    677     if(!s){
    678 	snprintf(tmp, sizeof(tmp), "Enter unit %d remote port: ", devNo);
    679 	sal_readline(tmp, tmp, sizeof (tmp), "2400");
    680 	v->pliPort = atoi(tmp);
    681     }
    682     else
    683 	v->pliPort = atoi(s);
    684 
    685     /*
    686      * Connect to host running Vera (ncsim)
    687      */
    688     memset((void *)&srv_addr, 0, sizeof(srv_addr));
    689 
    690 #ifdef VXWORKS
    691     if (!isdigit((unsigned) v->pliHost[0])) {
    692 	cli_out("pli_client_attach: can't resolve host names in vxworks\n");
    693     }
    694 
    695     srv_addr.sin_addr.s_addr = inet_addr(v->pliHost);
    696 #else
    697     hostentPtr = gethostbyname(v->pliHost);
    698     if(hostentPtr == NULL) {
    699 	cli_out("pli_client_attach: hostname lookup failed "
    700 	       "for host [%s].\n", v->pliHost);
    701 	perror("gethostbyname");
    702 	goto error;
    703     }
    704     memcpy(&srv_addr.sin_addr,hostentPtr->h_addr,4);
    705 #endif
    706 
    707     srv_addr.sin_family = AF_INET;
    708     srv_addr.sin_port = htons(v->pliPort);
    709 
    710     if ((v->sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    711 	perror("server: can't open stream socket");
    712 	goto error;
    713     }
    714 
    715 #ifdef VERINET_CUSTOM_SOCKET_HOOK 
    716        VERINET_CUSTOM_SOCKET_HOOK 
    717 #endif 
    718 
    719     if (connect(v->sockfd,
    720 		(struct sockaddr*)&srv_addr, sizeof(srv_addr)) < 0) {
    721 	cli_out("pli_client_attach: could not connect unit %d to [%s.%d] "
    722 	       "-service unavailable.\n",
    723 	       devNo, v->pliHost, v->pliPort);
    724 	perror("connect");
    725 	goto error;
    726     }
    727 
    728     /*
    729      * Get local host name to send back to server
    730      */
    731 
    732     cli_addr_size = sizeof (cli_addr);
    733     if (getsockname(v->sockfd, (struct sockaddr *)&cli_addr, &cli_addr_size) < 0) {
    734         perror("pli_client_attach: getsockname function failed.");
    735         goto error;
    736     }
    737     cli_addr.sin_addr.s_addr = htonl(cli_addr.sin_addr.s_addr);
    738 
    739     /*
    740      * Start INTC and DMAC tasks and register callback for ISR.
    741      */
    742 
    743     if (!v->jobsStarted) {
    744 	if (dmac_init(v) < 0) {
    745 	    goto error;
    746 	}
    747 
    748 	if (intr_init(v) < 0) {
    749 	    goto error;
    750 	}
    751 
    752 	v->jobsStarted = 1;
    753     }
    754 
    755     /*
    756      * Send REGISTER request to PLI server.
    757      */
    758     make_rpc_register_req(&cmd,
    759 			  v->intPort, v->dmaPort,
    760 			  cli_addr.sin_addr.s_addr);
    761 
    762     if (write_command(v->sockfd, &cmd) != RPC_OK) {
    763 	cli_out("pli_client_attach: could not send REGISTER request\n");
    764 	goto error;
    765     }
    766 
    767     if (wait_command(v->sockfd, &cmd) < 0)
    768 	goto error;
    769 
    770     if (cmd.opcode != RPC_REGISTER_CLIENT ||
    771 	cmd.status != RPC_OK) {
    772 	cli_out("pli_client_attach: PLI registration failed\n");
    773 	goto error;
    774     }
    775 
    776     return 0;
    777 
    778  error:
    779     if (v->sockfd >= 0) {
    780 	close(v->sockfd);
    781 	v->sockfd = -1;
    782     }
    783 
    784     return rv;
    785 }
    786 
    787 int pli_register_isr(int devNo, pli_isr_t isr, void *isr_data)
    788 {
    789     intr_set_vector(&verinet[devNo], isr, isr_data);
    790     return 0;
    791 }
    792 
    793 int pli_client_detach(int devNo)
    794 {
    795     verinet_t *v = &verinet[devNo];
    796 
    797     if (v->sockfd >= 0) {
    798 	disconnect(v->sockfd);
    799 	close(v->sockfd);
    800 	v->sockfd = -1;
    801     }
    802 
    803     return 0;
    804 }
    805 
    806 /*
    807  * Disconnect a client from the server.
    808  */
    809 void disconnect(int sockfd)
    810 {
    811     rpc_cmd_t command;
    812     make_rpc_disconnect_req(&command);
    813     cli_out("Disconnect: 0x%x\n", sockfd);
    814     write_command(sockfd, &command);
    815 }
    816 
    817 
    818 /*
    819  * Send an interrupt to a client. "cause" indicates the reason.
    820  */
    821 uint32 send_interrupt(int sockfd, uint32 cause)
    822 {
    823     rpc_cmd_t command;
    824     make_rpc_intr_req(&command,cause);
    825     if (write_command(sockfd, &command) != RPC_OK) {
    826         return -1;
    827     }
    828     if (wait_command(sockfd, &command) < 0)
    829 	return -1;
    830     return command.args[0];
    831 }
    832 
    833 
    834 
    835 
    836 /*
    837  * Register a client with the server. This will add the client to
    838  * the servers queue of service requests. We pass the network address
    839  * and two ports which are used for DMA r/w requests and interrupt
    840  * requests.
    841  */
    842 netconnection_t* register_client(int sockfd,
    843 				 uint32 intPort,
    844 				 uint32 dmaPort,
    845 				 uint32 netAddr)
    846 {
    847     int dmaSockFD = -1; /* DMA socket file descriptor */
    848     int intSockFD = -1; /* Interrupt file descriptor */
    849     netconnection_t *nc;
    850     struct sockaddr_in cli_addr; /* Client net address */
    851     
    852     memset(&cli_addr , 0 , sizeof(struct sockaddr_in)); 
    853 
    854     if((nc = (netconnection_t*)malloc(sizeof(netconnection_t))) == NULL)
    855 	return (netconnection_t*)0x0;
    856     
    857     nc->intsock = -1;
    858     nc->dmasock = -1;
    859     nc->piosock = -1;
    860 
    861 #if 0
    862     cli_out("register_client:s=%d irqPort=%d dmaPort=%d netAddr=%d.%d.%d.%d\n",
    863 	   sockfd, intPort, dmaPort,
    864 	   (netAddr & 0xff000000) >> 24,
    865 	   (netAddr & 0x00ff0000) >> 16,
    866 	   (netAddr & 0x0000ff00) >> 8,
    867 	   (netAddr & 0x000000ff));
    868 #endif
    869 
    870     /* Keep local copy of netaddress in native byte order */
    871     memcpy(&nc->inetaddr,&netAddr,4);
    872     /* Setup netaddr for client */
    873     netAddr = htonl(netAddr);
    874     memcpy(&cli_addr.sin_addr,&netAddr,4);
    875 
    876     cli_addr.sin_family = AF_INET;
    877     cli_addr.sin_port = htons(intPort);
    878 
    879     /* Setup interrupt socket */
    880     if((intSockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    881 	perror("server: can't open stream socket");
    882 	free(nc);
    883 	return (netconnection_t*)0x0;
    884     }
    885     /* Connect back to client */
    886     if(connect(intSockFD, (struct sockaddr*)&cli_addr, sizeof(cli_addr))< 0){
    887 	cli_out("Error: INTC connect failed to [0x%x.%d] -service unavailable.\n",
    888 	       netAddr, intPort);
    889 	perror("connect");
    890 	close(intSockFD);
    891 	free(nc);
    892 	return (netconnection_t*)0x0;
    893     }
    894 
    895     /* Setup DMA socket */
    896     cli_addr.sin_port = htons(dmaPort);
    897 
    898     if((dmaSockFD = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    899 	perror("server: can't open stream socket");
    900 	close(intSockFD);
    901 	free(nc);
    902 	return (netconnection_t*)0x0;
    903     }
    904   
    905     /* Connect back to client */
    906     if(connect(dmaSockFD, (struct sockaddr*)&cli_addr, sizeof(cli_addr))< 0){
    907 	cli_out("Error: DMAC connect failed to [0x%x.%d] -service unavailable.\n",
    908 	       netAddr, dmaPort);
    909 	perror("connect");
    910 	close(intSockFD);
    911 	close(dmaSockFD);
    912 	free(nc);
    913 	return (netconnection_t*)0x0;
    914     }
    915 
    916     /* Fill in fields */
    917     nc->intsock = intSockFD ;
    918     nc->dmasock = dmaSockFD ;
    919     nc->piosock = sockfd;
    920 
    921     return nc;
    922 }
    923 
    924 int unregister_client(netconnection_t *nc)
    925 {
    926     close(nc->intsock);
    927     close(nc->dmasock);
    928     close(nc->piosock);
    929     free(nc);
    930     return 0;
    931 }
    932 
    933 /*
    934  * Server PLI-level call to write to DMA memory.
    935  * Load the given memory address with some data on the client.
    936  */
    937 int dma_writemem(int sockfd, uint32 addr, uint32 data)
    938 {
    939     rpc_cmd_t cmd;
    940     make_rpc_setmem_req(&cmd,addr,data);
    941     if (write_command(sockfd, &cmd) != RPC_OK) {
    942         return RPC_FAIL;
    943     }
    944     if (wait_command(sockfd,&cmd) < 0) {
    945         return RPC_FAIL;
    946     }
    947     return RPC_OK;
    948 }
    949 
    950 
    951 /*
    952  * Server PLI-level client call to read DMA memory.
    953  * Returns the data at a given memory address on client.
    954  */
    955 int dma_readmem(int sockfd, uint32 addr, uint32 *value)
    956 {
    957     rpc_cmd_t cmd;
    958     make_rpc_getmem_req(&cmd,addr);
    959     if (write_command(sockfd, &cmd) != RPC_OK) {
    960         return RPC_FAIL;
    961     }
    962     if (wait_command(sockfd,&cmd) < 0) {
    963         return RPC_FAIL;
    964     }
    965     *value = cmd.args[0];
    966     return RPC_OK;
    967 }
    968 
    969 /*
    970  * Server PLI-level call to write to DMA memory as a string.
    971  */
    972 int dma_write_bytes(int sockfd, uint32 addr, uint8 *data, int len)
    973 {
    974     rpc_cmd_t cmd;
    975 
    976     make_rpc_string(&cmd, RPC_DMAC_WRITE_BYTES_REQ, RPC_OUTSTANDING,
    977                     addr, data, len);
    978     if (write_command(sockfd, &cmd) != RPC_OK) {
    979         return -1;
    980     }
    981     if (wait_command(sockfd, &cmd) < 0) {
    982         return -1;
    983     }
    984 
    985     return cmd.argcount;
    986 }
    987 
    988 
    989 /*
    990  * Server PLI-level client call to read DMA memory as a string.
    991  * Data is copied up to the max number of bytes to *data.
    992  */
    993 int dma_read_bytes(int sockfd, uint32 addr, uint8 *data, int len)
    994 {
    995     rpc_cmd_t cmd;
    996     
    997     make_rpc_string(&cmd, RPC_DMAC_READ_BYTES_REQ, RPC_OUTSTANDING,
    998                     addr, NULL, len);
    999     if (write_command(sockfd, &cmd) != RPC_OK) {
   1000         return -1;
   1001     }
   1002     if (wait_command(sockfd, &cmd) < 0) {
   1003         return -1;
   1004     }
   1005     /* coverity[tainted_data] */
   1006     memcpy(data, &cmd.args[1], cmd.argcount);
   1007 
   1008     return cmd.argcount;
   1009 }
   1010 
   1011 
   1012 /*
   1013  * Client Call: get a register on the simulator.
   1014  */
   1015 uint32 pli_getreg(int devNo, uint32 regtype, uint32 regnum)
   1016 {
   1017     int i ;
   1018     verinet_t *v = &verinet[devNo];
   1019     uint32 status = 0x0;
   1020     uint32 regval = 0x0;
   1021     char buf[32], *ptr;
   1022     rpc_cmd_t command;
   1023 
   1024     LOG_INFO(BSL_LS_SYS_VERINET,
   1025              (BSL_META("pli_getreg: regtype=0x%x regnum=0x%x\n"),
   1026               regtype, regnum));
   1027 
   1028     make_rpc_getreg_req(&command, regtype,regnum);
   1029 
   1030     sal_mutex_take(v->pli_mutex, sal_mutex_FOREVER);
   1031 
   1032     if(write_command(v->sockfd, &command) != RPC_OK) {
   1033 	cli_out("Error: pli_getreg write_command failed\n");
   1034 	sal_mutex_give(v->pli_mutex);
   1035 	return -1;
   1036     }
   1037 
   1038     if (wait_command(v->sockfd, &command) < 0) {
   1039 	sal_mutex_give(v->pli_mutex);
   1040 	return -1;
   1041     }
   1042 
   1043     sal_mutex_give(v->pli_mutex);
   1044 
   1045     status = command.args[0];
   1046     regval = command.args[1];
   1047     ptr = (char*)&command.args[2];
   1048     for(i = 0; i < 32; i++){
   1049 	buf[i] = *ptr++;
   1050     }
   1051 
   1052     LOG_INFO(BSL_LS_SYS_VERINET,
   1053              (BSL_META("pli_getreg: regval=0x%x diagbuf=%s\n"),
   1054               regval, buf));
   1055 
   1056     if(status == 0) /* Read succeeded */
   1057 	return regval;
   1058     else
   1059 	return -1; /* RPC failed */
   1060 }
   1061 
   1062 /*
   1063  * Client call: set a register on the simulator.
   1064  */
   1065 uint32 pli_setreg(int devNo, uint32 regtype, uint32 regnum, uint32 regval)
   1066 {
   1067     rpc_cmd_t command;
   1068     verinet_t *v = &verinet[devNo];
   1069 
   1070     make_rpc_setreg_req(&command,regtype,regnum,regval);
   1071 
   1072     LOG_INFO(BSL_LS_SYS_VERINET,
   1073              (BSL_META("pli_setreg: regtype=0x%x regnum=0x%x regval=0x%x\n"),
   1074               regtype, regnum, regval));
   1075 
   1076     sal_mutex_take(v->pli_mutex, sal_mutex_FOREVER);
   1077 
   1078     if(write_command(v->sockfd, &command) != RPC_OK) {
   1079 	cli_out("Error: pli_setreg write_command failed\n");
   1080 	sal_mutex_give(v->pli_mutex);
   1081 	return -1;
   1082     }
   1083 
   1084     if (wait_command(v->sockfd,&command) < 0) {
   1085 	sal_mutex_give(v->pli_mutex);
   1086 	return -1;
   1087     }
   1088 
   1089     sal_mutex_give(v->pli_mutex);
   1090 
   1091     return command.args[0];
   1092 }
   1093 
   1094 /*
   1095  * Client call: send packet to be transmitted into the switch
   1096  */
   1097 uint32 pli_send_packet(int devNo, uint32 src_port, uint32 count,
   1098 		       int len, unsigned char *buf)
   1099 {
   1100     verinet_t *v = &verinet[devNo];
   1101     rpc_cmd_t command;
   1102 
   1103     make_rpc(&command,RPC_SEND_PACKET,RPC_OK,3,src_port,count,len);
   1104 
   1105     if(write_command(v->sockfd, &command) != RPC_OK) {
   1106 	cli_out("Error: pli_send_packet cmd failed\n");
   1107 	return -1;
   1108     }
   1109     if (writen(v->sockfd,buf,len) != len) {
   1110 	cli_out("Error: pli_send_packet data failed\n");
   1111 	return -1;
   1112     }
   1113     return 0;
   1114 }
   1115 
   1116 /*
   1117  * Client call: enable port transmission
   1118  */
   1119 uint32 pli_tx_enable(int devNo, uint32 portmap)
   1120 {
   1121     verinet_t *v = &verinet[devNo];
   1122     rpc_cmd_t command;
   1123 
   1124     make_rpc(&command,RPC_TX_ENABLE,RPC_OK,1,portmap);
   1125 
   1126     if(write_command(v->sockfd, &command) != RPC_OK) {
   1127 	cli_out("Error: pli_tx_enable cmd failed\n");
   1128 	return -1;
   1129     }
   1130     return 0;
   1131 }
   1132 
   1133 /*
   1134  * Client call: tell testbench to shutdown
   1135  */
   1136 uint32 pli_shutdown(int devNo)
   1137 {
   1138     verinet_t *v = &verinet[devNo];
   1139     rpc_cmd_t command;
   1140 
   1141     make_rpc(&command,RPC_SHUTDOWN,RPC_OK,0);
   1142 
   1143     if(write_command(v->sockfd, &command) != RPC_OK) {
   1144 	cli_out("Error: pli_shutdown cmd failed\n");
   1145 	return -1;
   1146     }
   1147     return 0;
   1148 }
   1149 
   1150 
   1151 /*
   1152  * Send signal to simulation to activate
   1153  */
   1154 uint32 pli_sim_start(int devNo)
   1155 {
   1156     verinet_t *v = &verinet[devNo];
   1157     rpc_cmd_t command;
   1158 
   1159     make_rpc(&command, RPC_IOCTL_REQ, RPC_OK, 3, BCM_SIM_ACTIVATE, 0, 0);
   1160 
   1161     if(write_command(v->sockfd, &command) != RPC_OK) {
   1162 	cli_out("Error: pli_sim_start cmd failed\n");
   1163 	return -1;
   1164     }
   1165     return 0;
   1166 }
   1167 
   1168 
   1169 
   1170 int get_pkt_data(int sockfd, struct timeval* tv, uint32* data)
   1171 {
   1172     int i, len;
   1173     fd_set read_vect;
   1174     uint32 swap;
   1175 
   1176     LOG_VERBOSE(BSL_LS_SYS_VERINET,
   1177                 (BSL_META("get_pkt_data: sockfd=%d\n"),
   1178                  sockfd));
   1179 
   1180     assert(sockfd > 2);		/* Verinet initialized? */
   1181 
   1182     /* Setup bitmap for read notification ... */
   1183     FD_ZERO(&read_vect);
   1184     FD_SET(sockfd, &read_vect);
   1185 
   1186     while (1) {
   1187         if(select(sockfd+1,&read_vect,(fd_set*)0x0,(fd_set*)0x0,tv)<0){
   1188             if (errno == EINTR) {
   1189                 /* 
   1190                  * Interrupted by a signal such as a GPROF alarm so
   1191                  * restart the call
   1192                  */
   1193                 continue;
   1194             }
   1195             perror("get_command: select error");
   1196             goto fail;
   1197         } else {
   1198             break;
   1199         }
   1200     }
   1201     /*
   1202      * Data ready to be read.
   1203      */
   1204     if (FD_ISSET(sockfd, &read_vect)) {
   1205 	/*
   1206 	 * Read RPC opcode.
   1207 	 */
   1208 	if(readn(sockfd, &swap, sizeof(uint32)) < sizeof(uint32)){
   1209 	    goto fail;
   1210 	}
   1211 	/* Convert precious info to host byte order */
   1212         i=0;
   1213 	len = ntohl(swap);
   1214         data[i]=len;
   1215         /* coverity[tainted_data] */
   1216         while (len>0){ 
   1217             if (readn(sockfd, &swap, sizeof(uint32)) < sizeof(uint32)){
   1218                 cli_out("get_pkt_data: could not read DATA.\n");
   1219                 goto fail;
   1220             }
   1221             i++;
   1222             data[i]=ntohl(swap);
   1223             len-=4;
   1224         }
   1225 
   1226 	return 1;
   1227     }
   1228 
   1229  fail:
   1230     return -1;
   1231 }
   1232 
   1233 /*
   1234  * Perform an SCHANNEL operation. 
   1235  */
   1236 uint32 pli_schan(int devNo, uint32* words, int dw_write, int dw_read)
   1237 {
   1238     int i ;
   1239     verinet_t *v = &verinet[devNo];
   1240     uint32 status = 0x0;
   1241     rpc_cmd_t command;
   1242 
   1243     make_rpc(&command, RPC_SCHAN_REQ, RPC_OUTSTANDING, 0); 
   1244 
   1245     command.argcount = dw_write+2;
   1246     command.args[0] = dw_write; 
   1247     command.args[1] = dw_read; 
   1248 
   1249     for(i = 0; i < dw_write; i++) {
   1250         command.args[i+2] = words[i]; 
   1251     }   
   1252 
   1253     sal_mutex_take(v->pli_mutex, sal_mutex_FOREVER);
   1254 
   1255     if(write_command(v->sockfd, &command) != RPC_OK) {
   1256 	cli_out("Error: pli_schan write_command failed\n");
   1257 	sal_mutex_give(v->pli_mutex);
   1258 	return -1;
   1259     }
   1260     
   1261     if (wait_command(v->sockfd, &command) < 0) {
   1262 	sal_mutex_give(v->pli_mutex);
   1263 	return -1;
   1264     }
   1265 
   1266     sal_mutex_give(v->pli_mutex);
   1267 
   1268     /* Schannel operation response is the first argument */
   1269     status = command.args[0];
   1270     
   1271     for(i = 0; i < dw_read; i++){
   1272 	words[i] = command.args[i+1]; 
   1273     }
   1274     
   1275     if(status == 0) /* Read succeeded */
   1276 	return 0; 
   1277     else
   1278 	return -1; /* RPC failed */
   1279 }