📄 c7000.c
字号:
c7000_clearbit_busy(TB_TX, dev); s390irq_spin_unlock_irqrestore(cup->irq, saveflags); CPrintk(1, "c7000: c7000_xmit: exits for unit 0x%x\n", cup->devno); return(0);}/* Handle an ioctl from a user process.*/static intc7000_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ CPrintk(1, "c7000: c7000_ioctl: entered for base unit 0x%lx with cmd %d\n", dev->base_addr, cmd); return(0);}/* Analyze the interrupt status and return a value that identifies the type.*/static enum c7000_ruptc7000_check_csw(devstat_t *devstat){ /* Check for channel detected conditions (except PCI). */ if ((devstat->cstat & ~SCHN_STAT_PCI) != 0) { CPrintk(0, "c7000: c7000_check_csw: channel status 0x%x for unit 0x%x\n", devstat->cstat, devstat->devno); return(C7000_CHANERR); } /* Fast path the normal cases. */ if (devstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) return(C7000_NORMAL); if (devstat->cstat == SCHN_STAT_PCI) return(C7000_NORMAL); /* Check for exceptions. */ if (devstat->dstat & DEV_STAT_UNIT_CHECK) { CPrintk(0, "c7000: c7000_check_csw: unit check for unit 0x%x, sense byte0 0x%2.2x\n", devstat->devno, devstat->ii.sense.data[0]); if (devstat->ii.sense.data[0] == C7000_BOX_RESET) return(C7000_UCK_RESET); else return(C7000_UCK); } else if (devstat->dstat & DEV_STAT_UNIT_EXCEP) { CPrintk(0, "c7000: c7000_check_csw: unit exception for unit 0x%x\n", devstat->devno); return(C7000_UE); } else if (devstat->dstat & DEV_STAT_ATTENTION) { CPrintk(0, "c7000: c7000_check_csw: attention for unit 0x%x\n", devstat->devno); return(C7000_ATTN); } else if (devstat->dstat & DEV_STAT_BUSY) { CPrintk(0, "c7000: c7000_check_csw: busy for unit 0x%x\n", devstat->devno); return(C7000_BUSY); } else { CPrintk(0, "c7000: c7000_check_csw: channel status 0x%2.2x , device status 0x%2.2x, devstat flags 0x%8.8x for unit 0x%x\n", devstat->cstat, devstat->dstat, devstat->flag, devstat->devno); return(C7000_OTHER); } /* NOT REACHED */}/* Retry the last CCW chain to the unit.*/static voidc7000_retry_io(struct c7000_unit *cup){ int rc; unsigned long parm; __u8 flags = 0x00; ccw1_t *ccwp; if (++cup->retries > C7000_MAX_RETRIES) { c7000_error(cup->cntlp); CPrintk(0, "c7000: c7000_retry_io: retry IO for unit 0x%x exceeds maximum retry count\n", cup->devno); return; } set_bit(0, (void *)&cup->IO_active); parm = (unsigned long)cup; if (cup->state == C7000_READ || cup->state == C7000_WRITE) ccwp = &cup->proc_head->ccws[0]; else ccwp = &cup->ccws[0]; if ((rc = do_IO(cup->irq, ccwp, parm, 0xff, flags)) != 0) { CPrintk(0, "c7000: c7000_retry_io: can not retry IO for unit 0x%x, return code %d\n", cup->devno, rc); clear_bit(0, (void *)&cup->IO_active); c7000_error(cup->cntlp); } CPrintk(1, "c7000: c7000_retry_io: retry IO for unit 0x%x, retry count %d\n", cup->devno, cup->retries); return;}/* Process a read interrupt by scanning the list of buffers for ones that have completed and queue them for the bottom half to process.*/static voidc7000_proc_rintr(struct c7000_unit *cup){ struct c7000_buffer *buf; struct c7000_rd_header *head; int num_read = 0; while (cup->proc_head != NULL) { head = (struct c7000_rd_header *)(cup->proc_head->data + C7000_DATAL); /* The flag byte in the read header will be set to FLAG_FF when the buffer has been read. */ if (head->flag != FLAG_FF) break; /* Dequeue the buffer from the proc chain and enqueue it on the bh chain for the bh routine to process. */ buf = c7000_dequeue_buffer(cup); c7000_queue_bh_buffer(cup, buf); num_read++; } CPrintk(1, "c7000: c7000_proc_rintr: %d buffers read for unit 0x%x\n", num_read, cup->devno); return;}/* Process all completed buffers on the proc chain. A buffer is completed if it's READFF flag is FLAG_FF.*/static intc7000_proc_wintr(struct c7000_unit *cup){ struct c7000_controller *ccp = cup->cntlp; struct c7000_buffer *buf; int num_write = 0; if (cup->proc_head == NULL) { CPrintk(0, "c7000: c7000_proc_wintr: unexpected NULL processing chain pointer for unit 0x%x\n", cup->devno); return(num_write); } while (cup->proc_head != NULL) { /* Check if the buffer has completed. */ if (*(cup->proc_head->data + C7000_DATAL + C7000_READHDRL) != FLAG_FF) break; /* Remove buffer from top of processing chain. Place it on free list. */ buf = c7000_dequeue_buffer(cup); ccp->stats.tx_bytes += buf->len; ccp->stats.tx_packets++; c7000_release_buffer(cup, buf); num_write++; } CPrintk(1, "c7000: c7000_proc_wintr: %d buffers written for unit 0x%x\n", num_write, cup->devno); return(num_write);}/* Interrupt handler.*/static voidc7000_intr(int irq, void *initparm, struct pt_regs *regs){ devstat_t *devstat = ((devstat_t *) initparm); struct c7000_unit *cup = NULL; struct c7000_controller *ccp = NULL; struct net_device *dev = NULL; unsigned long parm; __u8 flags = 0x00; int rc; /* Discard unsolicited interrupts */ if (devstat->intparm == 0) { CPrintk(0, "c7000: c7000_intr: unsolicited interrupt for device 0x%x, cstat = 0x%2.2x, dstat = 0x%2.2x, flag = 0x%8.8x\n", devstat->devno, devstat->cstat, devstat->dstat, devstat->flag); return; } /* Obtain the c7000_unit structure pointer. */ cup = (struct c7000_unit *)(devstat->intparm); /* Obtain the c7000_controller structure and device structure pointers. */ if (cup == NULL) { CPrintk(0, "c7000: c7000_intr: c7000_unit pointer is NULL in devstat\n"); return; } ccp = cup->cntlp; if (ccp == NULL) { CPrintk(0, "c7000: c7000_intr: c7000_cntlp pointer is NULL in c7000_unit structure %p for unit 0x%x\n", cup, cup->devno); return; } dev = ccp->dev; if (dev == NULL) { CPrintk(0, "c7000: c7000_intr: device pointer is NULL in c7000_controller structure %p for unit 0x%x\n", ccp, cup->devno); return; } /* Finite state machine (fsm) handling. */ CPrintk(1, "c7000: c7000_intr: entered with state %d flag 0x%8.8x for unit 0x%x\n", cup->state, devstat->flag, cup->devno); switch(cup->state) { /* Not expected to be here when in INIT state. */ case C7000_INIT: break; /* Enter state C7000_SID and wakeup the sleeping process in c7000_open. */ case C7000_HALT: if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0) break; cup->state = C7000_SID; wake_up(&cup->wait); break; /* Enter state C7000_SYSVAL and wakeup the sleeping process in c7000_open. */ case C7000_SID: if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0) break; if (c7000_check_csw(devstat) != 0) { c7000_retry_io(cup); if (cup->state == C7000_ERROR) wake_up(&cup->wait); break; } cup->retries = 0; cup->state = C7000_SYSVAL; wake_up(&cup->wait); break; /* Wakeup the sleeping process in c7000_open. */ case C7000_SYSVAL: if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0) break; if (c7000_check_csw(devstat) != 0) { c7000_retry_io(cup); if (cup->state == C7000_ERROR) wake_up(&cup->wait); break; } cup->retries = 0; wake_up(&cup->wait); break; /* Wakeup the sleeping process in c7000_open. */ case C7000_CONNECT: if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0) break; if (c7000_check_csw(devstat) != 0) { c7000_retry_io(cup); if (cup->state == C7000_ERROR) wake_up(&cup->wait); break; } cup->retries = 0; wake_up(&cup->wait); break; /* Not expected to be entered here. */ case C7000_READY: break; /* Process the data that was just read. */ case C7000_READ: if ((devstat->flag & (DEVSTAT_PCI | DEVSTAT_FINAL_STATUS)) == 0) break; CPrintk(1, "c7000: c7000_intr: process read interrupt for unit 0x%x , devstat flag = 0x%8.8x\n", cup->devno, devstat->flag); /* Check for serious errors. */ if (c7000_check_csw(devstat) != 0) { ccp->stats.rx_errors++; c7000_error(cup->cntlp); break; } /* Build the bottom half buffer list. */ c7000_proc_rintr(cup); /* When final status is received clear the IO active bit. */ if (devstat->flag & DEVSTAT_FINAL_STATUS) { clear_bit(0, (void *)&cup->IO_active); } /* If there are free buffers redrive the IO. */ if ((devstat->flag & DEVSTAT_FINAL_STATUS) && (cup->free != NULL)) { c7000_bld_read_chain(cup); 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) { clear_bit(0, (void *)&cup->IO_active); CPrintk(0, "c7000: c7000_intr: do_IO failed with return code %d for unit 0x%x\n", rc, cup->devno); c7000_error(cup->cntlp); break; } CPrintk(1, "c7000: c7000_intr: started read io for unit 0x%x\n", cup->devno); } /* Initiate bottom half routine to process data that was read. */ if (test_and_set_bit(C7000_BH_ACTIVE, (void *)&cup->flag_a) == 0) { queue_task(&cup->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } break; /* Free the transmitted buffers and restart the channel process (if necessary). */ case C7000_WRITE: if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0) break; if (c7000_check_csw(devstat) != 0) { ccp->stats.tx_errors++; c7000_error(cup->cntlp); break; } /* If at least one buffer was freed, clear the NOBUFFER indication. */ if (c7000_proc_wintr(cup) != 0) { c7000_clearbit_busy(TB_NOBUFFER, dev); } /* Restart the channel program if there are more buffers on the processing chain. */ if (cup->proc_head != NULL) { c7000_bld_wrt_chain(cup); 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_intr: do_IO failed with return code %d for unit 0x%x\n", rc, cup->devno); clear_bit(0, (void *)&cup->IO_active); c7000_error(cup->cntlp); break; } dev->trans_start = jiffies; } else { clear_bit(0, (void *)&cup->IO_active); cup->state = C7000_READY; } break; /* Disconnect message completed. Wakeup the sleeping process in c7000_stop. */ case C7000_DISC: if ((devstat->flag & DEVSTAT_FINAL_STATUS) == 0) break; if (c7000_check_csw(devstat) != 0) { c7000_retry_io(cup); if (cup->state == C7000_ERROR) wake_up(&cup->wait); break; } cup->retries = 0; wake_up(&cup->wait); break; /* Subchannel is now halted. Wakeup the sleeping process in c7000_stop. Set the state to C7000_STOPPED. */ case C7000_STOP: cup->state = C7000_STOPPED; wake_up(&cup->wait); break; /* When in error state, stay there until the interface is recycled. */ case C7000_ERROR: break; /* Should not reach here */ default: CPrintk(0, "c7000: c7000_intr: entered default case for unit 0x%x, state %d\n", cup->devno, cup->state); break; } CPrintk(1, "c7000: c7000_intr: exited with state %d for unit 0x%x\n", cup->state, cup->devno); return;}/* Fill in system validation name padding it with blanks.*/static voidc7000_fill_name(char *dst, char *src){ char *tmp = dst; int i; for (i = 0; i < NAMLEN; i++, tmp++) *tmp = ' '; for (i = 0; i < NAMLEN && *src != '\0'; i++) *dst++ = *src++; return;}/* Initialization routine called when the device is registered.*/static intc7000_init(struct net_device *dev){ struct c7000_controller *ccp; int i; int unitaddr; int irq; /* Find the position of base_addr in the bases array. */ for (i = 0; i < MAX_C7000; i++) if (bases[i] == dev->base_addr) break; if (i == MAX_C7000) return(-ENODEV); /* Make sure it is a C7000 type of device. */ if (c7000_check_devices(dev->base_addr) != 0) { CPrintk(0, "c7000: c7000_init: b
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -