📄 c7000.c
字号:
/* Do the IO and wait for write to complete. */ if ((rc = c7000_doio(cup)) != 0) { CPrintk(0, "c7000: c7000_send_disc: failed with rc = %d for unit 0x%x\n", rc, cup->devno); return(-1); } return(0);}/* Resolve the race condition based on the link identifier value. The adapter microcode assigns the identifiers. A higher value implies that the race was lost. A side effect of this function is that ccp->linkid is set to the link identifier to be used for this connection (provided that 0 is returned).*/static intc7000_resolve_race(struct c7000_unit *cup, int local_linkid, int remote_linkid){ struct c7000_controller *ccp = cup->cntlp; CPrintk(1, "c7000: c7000_resolve_race: for unit 0x%x, local linkid %d, remote linkid %d\n", cup->devno, local_linkid, remote_linkid); /* This local link identifier should not be zero.. */ if (local_linkid == 0) { CPrintk(0, "c7000: c7000_resolve_race: error for unit 0x%x, local linkid is null\n", cup->devno); return(-1); } /* This indicates that there is no race. Just use our local link identifier. */ if (remote_linkid == 0) { ccp->linkid = local_linkid; return(0); } /* Send a connection confirm message if we lost the race to the winning link identifier. Either way, save the winning link identifier. */ if (local_linkid > remote_linkid) { if (c7000_conn_confrm(&ccp->cunits[C7000_WR], cup->control_blk.correlator, remote_linkid) != 0) { CPrintk(0, "c7000: c7000_resolve_race: failed for unit 0x%x\n", cup->devno); return(-1); } ccp->linkid = remote_linkid; } else { ccp->linkid = local_linkid; } return(0);}/* Get connected by processing the connection request/response/confirm control messages. A connection request has already been sent by calling function c7000_send_conn.*/static intc7000_get_conn(struct c7000_unit *cup){ struct c7000_controller *ccp = cup->cntlp; int rc; int cont = 1; int remote_linkid = 0; int local_linkid = 0; CPrintk(1, "c7000: c7000_get_conn: read the connected message for unit 0x%x\n", cup->devno); ccp->linkid = 0; while (cont == 1) { /* Build the read channel program. */ c7000_bld_readctl_chpgm(cup); /* Start the channel program to read a control message. */ if ((rc = c7000_doio(cup)) != 0) { CPrintk(0, "c7000: c7000_get_conn: failed with rc = %d for unit 0x%x\n", rc, cup->devno); return(-1); } /* Process the control message that was received based on the command code. */ CPrintk(1, "c7000: c7000_get_conn: received command %d for unit 0x%x\n", cup->control_blk.cmd, cup->devno); switch(cup->control_blk.cmd) { /* Save the remote link_id in the message for a check in c7000_resolve_race. */ case C7000_CONN_REQ: remote_linkid = cup->control_blk.link_id; break; /* A connection response received. Resolve the network race condition (if any) by comparing the link identifier values. */ case C7000_CONN_RESP: if (cup->control_blk.ret_code != 0) { CPrintk(0, "c7000: c7000_get_conn: failed for unit 0x%x , connection response return code %d\n", cup->devno, cup->control_blk.ret_code); return(-1); } local_linkid = cup->control_blk.link_id; if (c7000_resolve_race(cup, local_linkid, remote_linkid) != 0) return(-1); break; /* Got a confirmation to our connection request. Disconnect the remote link identifier (if any). Break out of the loop. */ case C7000_CONN_CONFRM: if (remote_linkid != 0) { if (c7000_send_disc(&ccp->cunits[C7000_WR], remote_linkid) != 0) { CPrintk(0, "c7000: c7000_get_conn: send disconnect failed for unit 0x%x\n", cup->devno); return(-1); } } cont = 0; break; /* Got a disconnect to our connection request. Break out of the loop. */ case C7000_DISCONN: cont = 0; break; /* Anything else must be an error. Return with an error immediately. */ default: CPrintk(0, "c7000: c7000_get_conn: failed for unit 0x%x unexpected command %d\n", cup->devno, cup->control_blk.cmd); return(-1); } } /* Be sure that we now have a link identifier. */ if (ccp->linkid == 0) return(-1); return(0);}/* Get statistics method.*/struct net_device_stats *c7000_stats(struct net_device *dev){ struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; return(&ccp->stats);}/* Open method.*/static intc7000_open(struct net_device *dev){ int i; struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; int rc; unsigned long parm; __u8 flags = 0x00; c7000_set_busy(dev); /* Allocate space for the unit buffers. */ if (c7000_alloc_buffers(dev) == -1) { CPrintk(0, "c7000: c7000_open: can not allocate buffer space for base unit 0x%lx\n", dev->base_addr); c7000_free_buffers(dev); /* free partially allocated buffers */ c7000_clear_busy(dev); return(-ENOMEM); } /* Perform the initialization for all units. */ for (i = 0; i < NUNITS; i++) { cup = &ccp->cunits[i]; /* Initialize task queue structure used for the bottom half routine. */ cup->tq.sync = 0; cup->tq.routine = (void *)(void *)c7000_irq_bh; cup->tq.data = cup; cup->state = C7000_HALT; init_waitqueue_head(&cup->wait); CPrintk(1, "c7000: c7000_open: issuing halt to unit 0x%x\n", cup->devno); /* Issue a halt I/O to the unit */ if ((rc = c7000_haltio(cup)) != 0) { CPrintk(0, "c7000: c7000_open: halt_IO failed with rc = %d for unit 0x%x\n", rc, cup->devno); continue; } cup->IO_active = 0; cup->flag_a = 0; cup->sigsmod = 0x00; CPrintk(1, "c7000: c7000_open: halt complete for unit 0x%x\n", cup->devno); } /* On each subchannel send a sense id. */ for (i = 0; i < NUNITS; i++) { cup = &ccp->cunits[i]; /* Build SENSE ID channel program. */ c7000_bld_senseid_chpgm(cup); /* Issue the start I/O for SENSE ID channel program. */ CPrintk(1, "c7000: c7000_open: issuing SENSEID to unit 0x%x\n", cup->devno); if ((rc = c7000_doio(cup)) != 0) { CPrintk(0, "c7000: c7000_open: SENSEID failed with rc = %d for unit 0x%x\n", rc, cup->devno); c7000_clear_busy(dev); return(-EIO); } CPrintk(1, "c7000: c7000_open: SENSEID complete for unit 0x%x\n", cup->devno); } /* Send the system validation control message. */ cup = &ccp->cunits[C7000_WR]; if (c7000_send_sysval(cup) != 0) { CPrintk(0, "c7000: c7000_open: can not send sysval for unit 0x%x\n", cup->devno); c7000_clear_busy(dev); return(-EIO); } CPrintk(1, "c7000: c7000_open: successfully sent sysval for unit 0x%x\n", cup->devno); /* Get the system validation response message. */ cup = &ccp->cunits[C7000_RD]; if (c7000_get_sysval_resp(cup) != 0) { CPrintk(0, "c7000: c7000_open: can not read sysval response for unit 0x%x\n", cup->devno); c7000_clear_busy(dev); return(-EIO); } CPrintk(1, "c7000: c7000_open: successfully received sysval reply for unit 0x%x\n", cup->devno); ccp->cunits[C7000_RD].state = ccp->cunits[C7000_WR].state = C7000_CONNECT; cup = &ccp->cunits[C7000_WR]; /* Send a connection request. */ if (c7000_send_conn(cup) != 0) { CPrintk(0, "c7000: c7000_open: connection failed for unit 0x%x\n", cup->devno); c7000_clear_busy(dev); return(-EIO); } cup = &ccp->cunits[C7000_RD]; /* Get the response to our connection request Note that a network race may occur. This is handled in c7000_get_conn. */ if (c7000_get_conn(cup) != 0) { CPrintk(0, "c7000: c7000_open: unit 0x%x has connected\n", cup->devno); c7000_clear_busy(dev); return(-EIO); } CPrintk(1, "c7000: c7000_open: successfully received connection request for unit 0x%x\n", cup->devno); ccp->cunits[C7000_RD].state = ccp->cunits[C7000_WR].state = C7000_READY; /* Clear the interface statistics. */ memset(&ccp->stats, '\0', sizeof(struct net_device_stats)); if ((rc = c7000_bld_read_chain(cup)) != 0) { c7000_clear_busy(dev); return(rc); } /* Start the C7000_READ channel program but do not wait for it's completion. */ cup->state = C7000_READ; parm = (unsigned long)cup; set_bit(0, (void *)&cup->IO_active); if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { CPrintk(0, "c7000: c7000_open: READ failed with return code %d for unit 0x%x\n", rc, cup->devno); c7000_error(cup->cntlp); clear_bit(0, (void *)&cup->IO_active); c7000_clear_busy(dev); return(-EIO); } netif_start_queue(dev); CPrintk(0, "c7000: c7000_open: base unit 0x%lx is opened\n", dev->base_addr); c7000_clear_busy(dev); MOD_INC_USE_COUNT; /* increment module usage count */ return(0);}/* Stop method.*/static intc7000_stop(struct net_device *dev){ int i; struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; int rc; c7000_set_busy(dev); /* Send a disconnect message. */ ccp->cunits[C7000_RD].state = ccp->cunits[C7000_WR].state = C7000_DISC; cup = &ccp->cunits[C7000_WR]; if (c7000_send_disc(cup, ccp->linkid) != 0) { CPrintk(0, "c7000: c7000_stop: send of disconnect message failed for unit 0x%x\n", cup->devno); } CPrintk(1, "c7000: c7000_stop: successfully sent disconnect message to unit 0x%x\n", cup->devno); /* Issue a halt I/O to all units. */ for (i = 0; i < NUNITS; i++) { cup = &ccp->cunits[i]; cup->state = C7000_STOP; CPrintk(1, "c7000: c7000_stop: issuing halt to unit 0x%x\n", cup->devno); if ((rc = c7000_haltio(cup)) != 0) { CPrintk(0, "c7000: c7000_stop: halt_IO failed with rc = %d for unit 0x%x\n", rc, cup->devno); continue; } CPrintk(1, "c7000: c7000_stop: halt complete for unit 0x%x\n", cup->devno); } c7000_free_buffers(dev); CPrintk(0, "c7000: c7000_stop: base unit 0x%lx is stopped\n", dev->base_addr); MOD_DEC_USE_COUNT; /* Decrement module usage count */ return(0);}/* Configure the interface.*/static intc7000_config(struct net_device *dev, struct ifmap *map){ CPrintk(1, "c7000: c7000_config: entered for base unit 0x%lx\n", dev->base_addr); return(0);}/* Transmit a packet.*/static intc7000_xmit(struct sk_buff *skb, struct net_device *dev){ struct c7000_controller *ccp = (struct c7000_controller *)dev->priv; struct c7000_unit *cup; unsigned long saveflags; unsigned long parm; __u8 flags = 0x00; struct c7000_buffer *buf, *pbuf; int rc; CPrintk(1, "c7000: c7000_xmit: entered for base unit 0x%lx\n", dev->base_addr); /* When the skb pointer is NULL return. */ if (skb == NULL) { CPrintk(0, "c7000: c7000_xmit: skb pointer is null for base unit 0x%lx\n", dev->base_addr); ccp->stats.tx_dropped++; return(-EIO); } cup = &ccp->cunits[C7000_WR]; /* Lock the irq. */ s390irq_spin_lock_irqsave(cup->irq, saveflags); /* When the device transmission busy flag is on , no data can be sent. Unlock the irq and return EBUSY. */ if (c7000_check_busy(dev)) { CPrintk(1, "c7000: c7000_xmit: c7000_check_busy returns true for base unit 0x%lx\n", dev->base_addr); s390irq_spin_unlock_irqrestore(cup->irq, saveflags); return(-EBUSY); } /* Set the device transmission busy flag on atomically. */ if (c7000_ts_busy(TB_TX, dev)) { CPrintk(1, "c7000: c7000_xmit: c7000_ts_busy returns true for base unit 0x%lx\n", dev->base_addr); s390irq_spin_unlock_irqrestore(cup->irq, saveflags); return(-EBUSY); } CPrintk(1, "c7000: c7000_xmit: set TB_TX for unit 0x%x\n", cup->devno); /* Obtain a free buffer. If none are free then mark tbusy with TB_NOBUFFER and return EBUSY. */ if ((buf = c7000_get_buffer(cup)) == NULL) { CPrintk(1, "c7000: c7000_xmit: setting TB_NOBUFFER for base unit 0x%lx\n", dev->base_addr); c7000_setbit_busy(TB_NOBUFFER, dev); c7000_clearbit_busy(TB_TX, dev); s390irq_spin_unlock_irqrestore(cup->irq, saveflags); return(-EBUSY); } CPrintk(1, "c7000: c7000_xmit: Got buffer for unit 0x%x\n", cup->devno); /* Save the length of the skb data and then copy it to the buffer. Queue the buffer on the processing list. */ buf->len = skb->len; memcpy(buf->data, skb->data, skb->len); memset(buf->data + C7000_DATAL + C7000_READHDRL, '\0', C7000_READFFL); pbuf = cup->proc_tail; c7000_queue_buffer(cup, buf); /* Chain the buffer to the running channel program. */ if (test_bit(0, (void *)&cup->IO_active) && pbuf != NULL) { c7000_bld_wrt_chpgm(cup, buf); pbuf->ccws[2].cda = (__u32)virt_to_phys(&buf->ccws[0]); } /* Free the socket buffer. */ dev_kfree_skb(skb); /* If the unit is not currently doing IO, build a channel program and start the IO for the buffers on the processing chain. */ if (test_and_set_bit(0, (void *)&cup->IO_active) == 0) { CPrintk(1, "c7000: c7000_xmit: start IO for unit 0x%x\n", cup->devno); c7000_bld_wrt_chain(cup); parm = (unsigned long)cup; cup->state = C7000_WRITE; if ((rc = do_IO(cup->irq, &cup->proc_head->ccws[0], parm, 0xff, flags)) != 0) { CPrintk(0, "c7000: c7000_xmit: do_IO failed with return code %d for unit 0x%x\n", rc, cup->devno); c7000_error(cup->cntlp); c7000_clearbit_busy(TB_TX, dev); s390irq_spin_unlock_irqrestore(cup->irq, saveflags); return(-EIO); } dev->trans_start = jiffies; CPrintk(1, "c7000: c7000_xmit: do_IO succeeds for unit 0x%x\n", cup->devno); } /* If the free chain is now NULL, set the TB_NOBUFFER flag. */ if (cup->free == NULL) { CPrintk(1, "c7000: c7000_xmit: setting TB_NOBUFFER for base unit 0x%lx\n", dev->base_addr); c7000_setbit_busy(TB_NOBUFFER, dev); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -