📄 c7000.c
字号:
/* Dequeue a buffer from the start of the bh routine chain.*/struct c7000_buffer *c7000_dequeue_bh_buffer(struct c7000_unit *cup){ struct c7000_buffer *buf = cup->bh_head; if (buf == NULL) return(NULL); cup->bh_head = buf->next; if (cup->bh_head == NULL) cup->bh_tail = NULL; buf->next = NULL; return(buf);}/* Build up a list of buffers to read. Each buffer is described by one c7000_buffer structure. The c7000_buffer structure contains a channel segment that will read that one buffer. The channel program segments are chained together via TIC CCWS.*/static intc7000_bld_read_chain(struct c7000_unit *cup){ struct c7000_buffer *buf, *pbuf = NULL; struct c7000_rd_header *head; int num = 0; while (cup->free != NULL) { /* Obtain a buffer for a read channel segment. */ if ((buf = c7000_get_buffer(cup)) == NULL) { CPrintk(0, "c7000: c7000_bld_read_chain: can not obtain a read buffer for unit 0x%x\n", cup->devno); return(-ENOMEM); } num++; buf->len = 0; /* Clear out the read header flag. */ head = (struct c7000_rd_header *)(buf->data + C7000_DATAL); head->flag = 0x00; c7000_queue_buffer(cup, buf); /* Build the read channel program segment. */ c7000_bld_read_chpgm(cup, buf); /* Chain the prior (if any) channel program segment to this one. */ if (pbuf != NULL) pbuf->ccws[3].cda = pbuf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[0]); pbuf = buf; } CPrintk(1, "c7000: c7000_bld_read_chain: chained %d buffers for unit 0x%x\n", num, cup->devno); return(0);}/* Build up a list of buffers to write. Each buffer is described by one c7000_buffer structure. The c7000_buffer structure contains a channel segment that will write that one buffer. The channel program segments are chained together via TIC CCWS.*/static voidc7000_bld_wrt_chain(struct c7000_unit *cup){ struct c7000_buffer *buf = cup->proc_head, *pbuf = NULL; int num = 0; while (buf != NULL) { c7000_bld_wrt_chpgm(cup, buf); /* Chain the channel program segments together. */ if (pbuf != NULL) pbuf->ccws[2].cda = (__u32)virt_to_phys(&buf->ccws[0]); pbuf = buf; buf = buf->next; num++; } CPrintk(1, "c7000: c7000_bld_wrt_chain: chained %d buffers for unit 0x%x\n", num, cup->devno); return;}/* Interrupt handler bottom half (bh) routine. Process all of the buffers on the c7000_unit bh chain. The bh chain is populated by the interrupt routine when a READ channel program completes on a buffer.*/static voidc7000_irq_bh(struct c7000_unit *cup){ struct c7000_buffer *buf, *pbuf; struct c7000_rd_header *head; struct sk_buff *skb; struct c7000_controller *ccp; struct net_device *dev; int rc; __u16 data_length; unsigned long parm; __u8 flags = 0x00; unsigned long saveflags; ccp = cup->cntlp; dev = ccp->dev; s390irq_spin_lock_irqsave(cup->irq, saveflags); /* Process all buffers sent to bh by the interrupt routine. */ while (cup->bh_head != NULL) { buf = c7000_dequeue_bh_buffer(cup); /* Deference the data as a c7000 header. */ head = (struct c7000_rd_header *)(buf->data + C7000_DATAL); /* If it is a control message, release the buffer and continue the loop. */ if (C7000_LINKID(head->cmd) == 0) { CPrintk(0, "c7000: c7000_irq_bh: unexpected control command %d on unit 0x%x\n", head->cmd, cup->devno); c7000_release_buffer(cup, buf); continue; } /* Allocate a socket buffer. */ data_length = head->len; skb = dev_alloc_skb(data_length); /* Copy the data to the skb. Send it to the upper layers. */ if (skb != NULL) { memcpy(skb_put(skb, data_length), buf->data, data_length); skb->dev = dev; skb->protocol = htons(ETH_P_IP); skb->pkt_type = PACKET_HOST; skb->mac.raw = skb->data; skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb); ccp->stats.rx_packets++; ccp->stats.rx_bytes += skb->len; } else { CPrintk(0, "c7000: c7000_irq_bh: can not allocate a skb for unit 0x%x\n", cup->devno); ccp->stats.rx_dropped++; } /* Rechain the buffer on the processing list. */ head->flag = 0x00; buf->len = 0; pbuf = cup->proc_tail; c7000_queue_buffer(cup, buf); /* Rechain the buffer on the running channel program. */ buf->ccws[3].cda = buf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[6]); if (pbuf != NULL) pbuf->ccws[3].cda = pbuf->ccws[5].cda = (__u32)virt_to_phys(&buf->ccws[0]); } /* Restart the READ channel program if IO_active is 0. */ if (test_and_set_bit(0, (void *)&cup->IO_active) == 0) { if ((rc = c7000_bld_read_chain(cup)) != 0) { CPrintk(0, "c7000: c7000_irq_bh: can not build read chain for unit 0x%x, return code %d\n", cup->devno, rc); c7000_error(cup->cntlp); clear_bit(C7000_BH_ACTIVE, (void *)&cup->flag_a); s390irq_spin_unlock_irqrestore(cup->irq, saveflags); return; } parm = (unsigned long)cup; cup->state = C7000_READ; if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { CPrintk(0, "c7000: c7000_irq_bh: can not start READ IO to unit 0x%x, return code %d\n", cup->devno, rc); c7000_error(cup->cntlp); clear_bit(C7000_BH_ACTIVE, (void *)&cup->flag_a); s390irq_spin_unlock_irqrestore(cup->irq, saveflags); return; } CPrintk(1, "c7000: c7000_irq_bh: started READ IO to unit 0x%x\n", cup->devno); } /* Clear the bh active indication. */ clear_bit(C7000_BH_ACTIVE, (void *)&cup->flag_a); s390irq_spin_unlock_irqrestore(cup->irq, saveflags); return;}/* Send a system validate control command to a unit.*/static intc7000_send_sysval(struct c7000_unit *cup){ int rc; struct c7000_controller *ccp = cup->cntlp; struct c7000_control_blk *ctlblkp = &(cup->control_blk); CPrintk(1, "c7000: c7000_send_sysval: send sysval for device 0x%x\n", cup->devno); /* Build the system validate control message. */ memset(ctlblkp, '\0', sizeof(struct c7000_control_blk)); ctlblkp->cmd = C7000_SYS_VALIDATE; ctlblkp->correlator = 0; ctlblkp->link_id = ccp->linkid; ctlblkp->ver = ccp->version; memcpy(ctlblkp->hostname, ccp->lhost, NAMLEN); memcpy(ctlblkp->unitname, ccp->uhost, NAMLEN); ctlblkp->rdsize = C7000_DATAL; ctlblkp->wrtsize = C7000_DATAL; /* Build the channel program. */ c7000_bld_wrtctl_chpgm(cup); /* Do the IO and wait for write to complete. */ if ((rc = c7000_doio(cup)) != 0) { CPrintk(0, "c7000: c7000_send_sysval failed with rc = %d for unit 0x%x\n", rc, cup->devno); return(-1); } return(0);}/* Send a system validate response control command to a unit.*/static intc7000_send_sysval_resp(struct c7000_unit *cup, unsigned char correlator, int ret_code){ int rc; struct c7000_controller *ccp = cup->cntlp; struct c7000_control_blk *ctlblkp = &(cup->control_blk); CPrintk(1, "c7000: c7000_send_sysval_resp: send sysval response for device 0x%x\n", cup->devno); /* Build the system validate response control message. */ memset(ctlblkp, '\0', sizeof(struct c7000_control_blk)); ctlblkp->cmd = C7000_SYS_VALIDATE_RESP; ctlblkp->correlator = correlator; ctlblkp->ret_code = ret_code; ctlblkp->link_id = ccp->linkid; ctlblkp->ver = ccp->version; memcpy(ctlblkp->hostname, ccp->lhost, NAMLEN); memcpy(ctlblkp->unitname, ccp->uhost, NAMLEN); ctlblkp->rdsize = C7000_DATAL; ctlblkp->wrtsize = C7000_DATAL; /* Build the channel program. */ c7000_bld_wrtctl_chpgm(cup); /* Do the IO and wait for write to complete. */ if ((rc = c7000_doio(cup)) != 0) { CPrintk(0, "c7000: c7000_send_sysval_resp failed with rc = %d for unit 0x%x\n", rc, cup->devno); return(-1); } return(0);}/* Check the information read in a SYS_VALIDATE control message.*/static intc7000_checkinfo(struct c7000_unit *cup){ struct c7000_controller *ccp = cup->cntlp; struct c7000_control_blk *ctlblkp = &cup->control_blk; int ret_code = 0; if (memcmp(ccp->lhost, ctlblkp->hostname, NAMLEN) || memcmp(ccp->uhost, ctlblkp->unitname, NAMLEN)) ret_code = Err_Names_not_Matched; if (ctlblkp->ver != ccp->version) ret_code = Err_Wrong_Version; if ((ctlblkp->rdsize < C7000_DATAL) || (ctlblkp->wrtsize < C7000_DATAL)) ret_code = Err_Wrong_Frame_Size; if (ret_code != 0) CPrintk(0, "c7000: c7000_checkinfo: ret_code %d for device 0x%x\n", ret_code, cup->devno); return(ret_code);}/* Keep reading until a sysval response comes in or an error.*/static intc7000_get_sysval_resp(struct c7000_unit *cup){ struct c7000_controller *ccp = cup->cntlp; int resp = 1; int req = 1; int rc; int ret_code = 0; CPrintk(1, "c7000: c7000_get_sysval_resp: get sysval response for unit 0x%x\n", cup->devno); /* Wait for the response to C7000_SYS_VALIDATE and for an inbound C7000_SYS_VALIDATE. */ while (resp || req) { /* Build the read channel program. */ c7000_bld_readctl_chpgm(cup); if ((rc = c7000_doio(cup)) != 0) { CPrintk(0, "c7000: c7000_get_sysval_resp: failed with rc = %d for unit 0x%x\n", rc, cup->devno); return(-1); } /* Process the control message. */ switch (cup->control_blk.cmd) { /* Check that response is positive and return with success. Otherwise, return with an error. */ case C7000_SYS_VALIDATE_RESP: if (cup->control_blk.ret_code == 0) resp = 0; else { CPrintk(0, "c7000: c7000_get_sysval_resp: receive sysval response for device 0x%x, return code %d\n", cup->devno, cup->control_blk.ret_code); return(-1); } break; /* Check that the request is reasonable and send a SYS_VALIDATE_RESP. Otherwise, return with an error. */ case C7000_SYS_VALIDATE: CPrintk(1, "c7000: c7000_get_sysval_resp: receive sysval for device 0x%x\n", cup->devno); req = 0; ret_code = c7000_checkinfo(cup); if (c7000_send_sysval_resp(&ccp->cunits[C7000_WR], cup->control_blk.correlator, ret_code) != 0) return(-1); if (ret_code != 0) return(-1); break; /* Anything else is unexpected and will result in a return with an error. */ default: CPrintk(0, "c7000: c7000_get_sysval_resp: receive unexpected command for device 0x%x, command %d\n", cup->devno, cup->control_blk.cmd); return(-1); break; } } return(0);}/* Send a connection confirm control message.*/static intc7000_conn_confrm(struct c7000_unit *cup, unsigned char correlator, int linkid){ int rc; struct c7000_controller *ccp = cup->cntlp; struct c7000_control_blk *ctlblkp = &(cup->control_blk); CPrintk(1, "c7000: c7000_conn_confrm: send the connection confirmation message for unit 0x%x\n", cup->devno); /* Build the connection confirm control message. */ memset(ctlblkp, '\0', sizeof(struct c7000_control_blk)); ctlblkp->cmd = C7000_CONN_CONFRM; ctlblkp->ver = ccp->version; ctlblkp->link_id = linkid; ctlblkp->correlator = correlator; ctlblkp->rdsize = 0; ctlblkp->wrtsize = 0; memcpy(ctlblkp->hostname, ccp->lappl, NAMLEN); memcpy(ctlblkp->unitname, ccp->uappl, NAMLEN); /* Build the channel program. */ c7000_bld_wrtctl_chpgm(cup); /* Do the IO and wait for write to complete. */ if ((rc = c7000_doio(cup)) != 0) { CPrintk(0, "c7000: c7000_conn_confrm: failed with rc = %d for unit 0x%x\n", rc, cup->devno); return(-1); } return(0);}/* Send a connection request control message.*/static intc7000_send_conn(struct c7000_unit *cup){ int rc; struct c7000_controller *ccp = cup->cntlp; struct c7000_control_blk *ctlblkp = &(cup->control_blk); CPrintk(1, "c7000: c7000_send_conn: send the connection request message for unit 0x%x\n", cup->devno); /* Build the connection request control message. */ memset(ctlblkp, '\0', sizeof(struct c7000_control_blk)); ctlblkp->cmd = C7000_CONN_REQ; ctlblkp->ver = ccp->version; ctlblkp->link_id = 0; ctlblkp->correlator = 0; ctlblkp->rdsize = C7000_DATAL; ctlblkp->wrtsize = C7000_DATAL; memcpy(ctlblkp->hostname, ccp->lappl, NAMLEN); memcpy(ctlblkp->unitname, ccp->uappl, NAMLEN); /* Build the channel program. */ c7000_bld_wrtctl_chpgm(cup); /* Do the IO and wait for write to complete. */ if ((rc = c7000_doio(cup)) != 0) { CPrintk(0, "c7000: c7000_send_conn: failed with rc = %d for unit 0x%x\n", rc, cup->devno); return(-1); } return(0);}/* Send a disconnect control message to the link with the value of linkid.*/static intc7000_send_disc(struct c7000_unit *cup, int linkid){ int rc; struct c7000_controller *ccp = cup->cntlp; struct c7000_control_blk *ctlblkp = &(cup->control_blk); CPrintk(1, "c7000: c7000_send_disc: send disconnect message for unit 0x%x\n", cup->devno); /* Build the disconnect control message. */ memset(ctlblkp, '\0', sizeof(struct c7000_control_blk)); ctlblkp->cmd = C7000_DISCONN; ctlblkp->ver = ccp->version; ctlblkp->link_id = linkid; ctlblkp->correlator = 0; ctlblkp->rdsize = C7000_DATAL; ctlblkp->wrtsize = C7000_DATAL; memcpy(ctlblkp->hostname, ccp->lappl, NAMLEN); memcpy(ctlblkp->unitname, ccp->uappl, NAMLEN); /* Build the channel program. */ c7000_bld_wrtctl_chpgm(cup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -