diff options
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/Makefile | 2 | ||||
-rw-r--r-- | drivers/s390/net/claw.c | 485 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_fsms.c | 5 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_main.c | 39 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_mpc.c | 17 | ||||
-rw-r--r-- | drivers/s390/net/lcs.c | 33 | ||||
-rw-r--r-- | drivers/s390/net/netiucv.c | 16 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core.h | 8 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 165 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_offl.c | 699 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_offl.h | 76 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_sys.c | 4 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 99 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 129 |
14 files changed, 487 insertions, 1290 deletions
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 6382c04..96eddb3 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o obj-$(CONFIG_SMSGIUCV) += smsgiucv.o obj-$(CONFIG_LCS) += lcs.o cu3088.o obj-$(CONFIG_CLAW) += claw.o cu3088.o -qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o qeth_core_offl.o +qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o obj-$(CONFIG_QETH) += qeth.o qeth_l2-y += qeth_l2_main.o obj-$(CONFIG_QETH_L2) += qeth_l2.o diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index f5e6185..30a43cc 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -60,6 +60,9 @@ * 1.25 Added Packing support * 1.5 */ + +#define KMSG_COMPONENT "claw" + #include <asm/ccwdev.h> #include <asm/ccwgroup.h> #include <asm/debug.h> @@ -94,7 +97,7 @@ CLAW uses the s390dbf file system see claw_trace and claw_setup */ - +static char version[] __initdata = "CLAW driver"; static char debug_buffer[255]; /** * Debug Facility Stuff @@ -206,20 +209,30 @@ static struct net_device_stats *claw_stats(struct net_device *dev); static int pages_to_order_of_mag(int num_of_pages); static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr); /* sysfs Functions */ -static ssize_t claw_hname_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t claw_hname_write(struct device *dev, struct device_attribute *attr, +static ssize_t claw_hname_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t claw_hname_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); -static ssize_t claw_adname_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t claw_adname_write(struct device *dev, struct device_attribute *attr, +static ssize_t claw_adname_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t claw_adname_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); -static ssize_t claw_apname_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t claw_apname_write(struct device *dev, struct device_attribute *attr, +static ssize_t claw_apname_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t claw_apname_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); -static ssize_t claw_wbuff_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t claw_wbuff_write(struct device *dev, struct device_attribute *attr, +static ssize_t claw_wbuff_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t claw_wbuff_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); -static ssize_t claw_rbuff_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t claw_rbuff_write(struct device *dev, struct device_attribute *attr, +static ssize_t claw_rbuff_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t claw_rbuff_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); static int claw_add_files(struct device *dev); static void claw_remove_files(struct device *dev); @@ -298,8 +311,8 @@ claw_probe(struct ccwgroup_device *cgdev) if (rc) { probe_error(cgdev); put_device(&cgdev->dev); - printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n", - dev_name(&cgdev->cdev[0]->dev), __func__, __LINE__); + dev_err(&cgdev->dev, "Creating the /proc files for a new" + " CLAW device failed\n"); CLAW_DBF_TEXT_(2, setup, "probex%d", rc); return rc; } @@ -335,6 +348,8 @@ claw_tx(struct sk_buff *skb, struct net_device *dev) rc=claw_hw_tx( skb, dev, 1 ); spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags); CLAW_DBF_TEXT_(4, trace, "clawtx%d", rc); + if (rc) + rc = NETDEV_TX_BUSY; return rc; } /* end of claw_tx */ @@ -496,7 +511,8 @@ claw_open(struct net_device *dev) ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CLAW_TIMER) != 0x00)) { - printk(KERN_INFO "%s: remote side is not ready\n", dev->name); + dev_info(&privptr->channel[READ].cdev->dev, + "%s: remote side is not ready\n", dev->name); CLAW_DBF_TEXT(2, trace, "notrdy"); for ( i = 0; i < 2; i++) { @@ -582,10 +598,9 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4, trace, "clawirq"); /* Bypass all 'unsolicited interrupts' */ if (!cdev->dev.driver_data) { - printk(KERN_WARNING "claw: unsolicited interrupt for device:" - "%s received c-%02x d-%02x\n", - dev_name(&cdev->dev), irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + dev_warn(&cdev->dev, "An uninitialized CLAW device received an" + " IRQ, c-%02x d-%02x\n", + irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); CLAW_DBF_TEXT(2, trace, "badirq"); return; } @@ -597,8 +612,7 @@ claw_irq_handler(struct ccw_device *cdev, else if (privptr->channel[WRITE].cdev == cdev) p_ch = &privptr->channel[WRITE]; else { - printk(KERN_WARNING "claw: Can't determine channel for " - "interrupt, device %s\n", dev_name(&cdev->dev)); + dev_warn(&cdev->dev, "The device is not a CLAW device\n"); CLAW_DBF_TEXT(2, trace, "badchan"); return; } @@ -612,7 +626,8 @@ claw_irq_handler(struct ccw_device *cdev, /* Check for good subchannel return code, otherwise info message */ if (irb->scsw.cmd.cstat && !(irb->scsw.cmd.cstat & SCHN_STAT_PCI)) { - printk(KERN_INFO "%s: subchannel check for device: %04x -" + dev_info(&cdev->dev, + "%s: subchannel check for device: %04x -" " Sch Stat %02x Dev Stat %02x CPA - %04x\n", dev->name, p_ch->devno, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, @@ -651,7 +666,7 @@ claw_irq_handler(struct ccw_device *cdev, wake_up(&p_ch->wait); /* wake claw_open (READ)*/ } else if (p_ch->flag == CLAW_WRITE) { p_ch->claw_state = CLAW_START_WRITE; - /* send SYSTEM_VALIDATE */ + /* send SYSTEM_VALIDATE */ claw_strt_read(dev, LOCK_NO); claw_send_control(dev, SYSTEM_VALIDATE_REQUEST, @@ -659,10 +674,9 @@ claw_irq_handler(struct ccw_device *cdev, p_env->host_name, p_env->adapter_name); } else { - printk(KERN_WARNING "claw: unsolicited " - "interrupt for device:" - "%s received c-%02x d-%02x\n", - dev_name(&cdev->dev), + dev_warn(&cdev->dev, "The CLAW device received" + " an unexpected IRQ, " + "c-%02x d-%02x\n", irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); return; @@ -677,8 +691,8 @@ claw_irq_handler(struct ccw_device *cdev, (p_ch->irb->ecw[0] & 0x40) == 0x40 || (p_ch->irb->ecw[0]) == 0) { privptr->stats.rx_errors++; - printk(KERN_INFO "%s: Restart is " - "required after remote " + dev_info(&cdev->dev, + "%s: Restart is required after remote " "side recovers \n", dev->name); } @@ -713,11 +727,13 @@ claw_irq_handler(struct ccw_device *cdev, return; case CLAW_START_WRITE: if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { - printk(KERN_INFO "%s: Unit Check Occured in " + dev_info(&cdev->dev, + "%s: Unit Check Occured in " "write channel\n", dev->name); clear_bit(0, (void *)&p_ch->IO_active); if (p_ch->irb->ecw[0] & 0x80) { - printk(KERN_INFO "%s: Resetting Event " + dev_info(&cdev->dev, + "%s: Resetting Event " "occurred:\n", dev->name); init_timer(&p_ch->timer); p_ch->timer.function = @@ -725,7 +741,8 @@ claw_irq_handler(struct ccw_device *cdev, p_ch->timer.data = (unsigned long)p_ch; p_ch->timer.expires = jiffies + 10*HZ; add_timer(&p_ch->timer); - printk(KERN_INFO "%s: write connection " + dev_info(&cdev->dev, + "%s: write connection " "restarting\n", dev->name); } CLAW_DBF_TEXT(4, trace, "rstrtwrt"); @@ -733,9 +750,10 @@ claw_irq_handler(struct ccw_device *cdev, } if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) { clear_bit(0, (void *)&p_ch->IO_active); - printk(KERN_INFO "%s: Unit Exception " - "Occured in write channel\n", - dev->name); + dev_info(&cdev->dev, + "%s: Unit Exception " + "occurred in write channel\n", + dev->name); } if (!((p_ch->irb->scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS) || (p_ch->irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND) || @@ -757,8 +775,9 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4, trace, "StWtExit"); return; default: - printk(KERN_WARNING "%s: wrong selection code - irq " - "state=%d\n", dev->name, p_ch->claw_state); + dev_warn(&cdev->dev, + "The CLAW device for %s received an unexpected IRQ\n", + dev->name); CLAW_DBF_TEXT(2, trace, "badIRQ"); return; } @@ -910,8 +929,10 @@ claw_release(struct net_device *dev) if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { - printk(KERN_WARNING "%s: channel problems during close - " - "read: %02x - write: %02x\n", + dev_warn(&privptr->channel[READ].cdev->dev, + "Deactivating %s completed with incorrect" + " subchannel status " + "(read %02x, write %02x)\n", dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); @@ -1012,7 +1033,7 @@ static int pages_to_order_of_mag(int num_of_pages) { int order_of_mag=1; /* assume 2 pages */ - int nump=2; + int nump; CLAW_DBF_TEXT_(5, trace, "pages%d", num_of_pages); if (num_of_pages == 1) {return 0; } /* magnitude of 0 = 1 page */ @@ -1076,8 +1097,8 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, } if ( privptr-> p_read_active_first ==NULL ) { - privptr-> p_read_active_first= p_first; /* set new first */ - privptr-> p_read_active_last = p_last; /* set new last */ + privptr->p_read_active_first = p_first; /* set new first */ + privptr->p_read_active_last = p_last; /* set new last */ } else { @@ -1113,7 +1134,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, privptr->p_read_active_last->r_TIC_2.cda= (__u32)__pa(&p_first->read); } - /* chain in new set of blocks */ + /* chain in new set of blocks */ privptr->p_read_active_last->next = p_first; privptr->p_read_active_last=p_last; } /* end of if ( privptr-> p_read_active_first ==NULL) */ @@ -1135,21 +1156,18 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code) case -EBUSY: /* BUSY is a transient state no action needed */ break; case -ENODEV: - printk(KERN_EMERG "%s: Missing device called " - "for IO ENODEV\n", dev_name(&cdev->dev)); - break; - case -EIO: - printk(KERN_EMERG "%s: Status pending... EIO \n", - dev_name(&cdev->dev)); + dev_err(&cdev->dev, "The remote channel adapter is not" + " available\n"); break; case -EINVAL: - printk(KERN_EMERG "%s: Invalid Dev State EINVAL \n", - dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "The status of the remote channel adapter" + " is not valid\n"); break; default: - printk(KERN_EMERG "%s: Unknown error in " - "Do_IO %d\n", dev_name(&cdev->dev), - return_code); + dev_err(&cdev->dev, "The common device layer" + " returned error code %d\n", + return_code); } } CLAW_DBF_TEXT(4, trace, "ccwret"); @@ -1163,42 +1181,37 @@ static void ccw_check_unit_check(struct chbk * p_ch, unsigned char sense ) { struct net_device *ndev = p_ch->ndev; + struct device *dev = &p_ch->cdev->dev; CLAW_DBF_TEXT(4, trace, "unitchek"); - printk(KERN_INFO "%s: Unit Check with sense byte:0x%04x\n", - ndev->name, sense); - - if (sense & 0x40) { - if (sense & 0x01) { - printk(KERN_WARNING "%s: Interface disconnect or " - "Selective reset " - "occurred (remote side)\n", ndev->name); - } - else { - printk(KERN_WARNING "%s: System reset occured" - " (remote side)\n", ndev->name); - } - } - else if (sense & 0x20) { - if (sense & 0x04) { - printk(KERN_WARNING "%s: Data-streaming " - "timeout)\n", ndev->name); - } - else { - printk(KERN_WARNING "%s: Data-transfer parity" - " error\n", ndev->name); - } - } - else if (sense & 0x10) { - if (sense & 0x20) { - printk(KERN_WARNING "%s: Hardware malfunction " - "(remote side)\n", ndev->name); - } - else { - printk(KERN_WARNING "%s: read-data parity error " - "(remote side)\n", ndev->name); - } - } + dev_warn(dev, "The communication peer of %s disconnected\n", + ndev->name); + + if (sense & 0x40) { + if (sense & 0x01) { + dev_warn(dev, "The remote channel adapter for" + " %s has been reset\n", + ndev->name); + } + } else if (sense & 0x20) { + if (sense & 0x04) { + dev_warn(dev, "A data streaming timeout occurred" + " for %s\n", + ndev->name); + } else if (sense & 0x10) { + dev_warn(dev, "The remote channel adapter for %s" + " is faulty\n", + ndev->name); + } else { + dev_warn(dev, "A data transfer parity error occurred" + " for %s\n", + ndev->name); + } + } else if (sense & 0x10) { + dev_warn(dev, "A read data parity error occurred" + " for %s\n", + ndev->name); + } } /* end of ccw_check_unit_check */ @@ -1235,7 +1248,7 @@ find_link(struct net_device *dev, char *host_name, char *ws_name ) break; } - return 0; + return rc; } /* end of find_link */ /*-------------------------------------------------------------------* @@ -1347,7 +1360,10 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) privptr->p_write_free_chain=p_this_ccw->next; p_this_ccw->next=NULL; --privptr->write_free_count; /* -1 */ - bytesInThisBuffer=len_of_data; + if (len_of_data >= privptr->p_env->write_size) + bytesInThisBuffer = privptr->p_env->write_size; + else + bytesInThisBuffer = len_of_data; memcpy( p_this_ccw->p_buffer,pDataAddress, bytesInThisBuffer); len_of_data-=bytesInThisBuffer; pDataAddress+=(unsigned long)bytesInThisBuffer; @@ -1375,7 +1391,7 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid) */ if (p_first_ccw!=NULL) { - /* setup ending ccw sequence for this segment */ + /* setup ending ccw sequence for this segment */ pEnd=privptr->p_end_ccw; if (pEnd->write1) { pEnd->write1=0x00; /* second end ccw is now active */ @@ -1697,10 +1713,11 @@ init_ccw_bk(struct net_device *dev) p_buf-> w_TIC_1.flags = 0; p_buf-> w_TIC_1.count = 0; - if (((unsigned long)p_buff+privptr->p_env->write_size) >= + if (((unsigned long)p_buff + + privptr->p_env->write_size) >= ((unsigned long)(p_buff+2* - (privptr->p_env->write_size) -1) & PAGE_MASK)) { - p_buff= p_buff+privptr->p_env->write_size; + (privptr->p_env->write_size) - 1) & PAGE_MASK)) { + p_buff = p_buff+privptr->p_env->write_size; } } } @@ -1840,15 +1857,16 @@ init_ccw_bk(struct net_device *dev) p_buf->header.opcode=0xff; p_buf->header.flag=CLAW_PENDING; - if (((unsigned long)p_buff+privptr->p_env->read_size) >= - ((unsigned long)(p_buff+2*(privptr->p_env->read_size) -1) - & PAGE_MASK) ) { + if (((unsigned long)p_buff+privptr->p_env->read_size) >= + ((unsigned long)(p_buff+2*(privptr->p_env->read_size) + -1) + & PAGE_MASK)) { p_buff= p_buff+privptr->p_env->read_size; } else { p_buff= (void *)((unsigned long) - (p_buff+2*(privptr->p_env->read_size) -1) + (p_buff+2*(privptr->p_env->read_size)-1) & PAGE_MASK) ; } } /* for read_buffers */ @@ -1856,24 +1874,28 @@ init_ccw_bk(struct net_device *dev) else { /* read Size >= PAGE_SIZE */ for (i=0 ; i< privptr->p_env->read_buffers ; i++) { p_buff = (void *)__get_free_pages(__GFP_DMA, - (int)pages_to_order_of_mag(privptr->p_buff_pages_perread) ); + (int)pages_to_order_of_mag( + privptr->p_buff_pages_perread)); if (p_buff==NULL) { free_pages((unsigned long)privptr->p_buff_ccw, - (int)pages_to_order_of_mag(privptr->p_buff_ccw_num)); + (int)pages_to_order_of_mag(privptr-> + p_buff_ccw_num)); /* free the write pages */ p_buf=privptr->p_buff_write; while (p_buf!=NULL) { - free_pages((unsigned long)p_buf->p_buffer, - (int)pages_to_order_of_mag( - privptr->p_buff_pages_perwrite )); + free_pages( + (unsigned long)p_buf->p_buffer, + (int)pages_to_order_of_mag( + privptr->p_buff_pages_perwrite)); p_buf=p_buf->next; } /* free any read pages already alloc */ p_buf=privptr->p_buff_read; while (p_buf!=NULL) { - free_pages((unsigned long)p_buf->p_buffer, - (int)pages_to_order_of_mag( - privptr->p_buff_pages_perread )); + free_pages( + (unsigned long)p_buf->p_buffer, + (int)pages_to_order_of_mag( + privptr->p_buff_pages_perread)); p_buf=p_buf->next; } privptr->p_buff_ccw=NULL; @@ -2003,7 +2025,7 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) tdev = &privptr->channel[READ].cdev->dev; memcpy( &temp_host_name, p_env->host_name, 8); memcpy( &temp_ws_name, p_env->adapter_name , 8); - printk(KERN_INFO "%s: CLAW device %.8s: " + dev_info(tdev, "%s: CLAW device %.8s: " "Received Control Packet\n", dev->name, temp_ws_name); if (privptr->release_pend==1) { @@ -2022,32 +2044,30 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) if (p_ctlbk->version != CLAW_VERSION_ID) { claw_snd_sys_validate_rsp(dev, p_ctlbk, CLAW_RC_WRONG_VERSION); - printk("%s: %d is wrong version id. " - "Expected %d\n", - dev->name, p_ctlbk->version, - CLAW_VERSION_ID); + dev_warn(tdev, "The communication peer of %s" + " uses an incorrect API version %d\n", + dev->name, p_ctlbk->version); } p_sysval = (struct sysval *)&(p_ctlbk->data); - printk("%s: Recv Sys Validate Request: " - "Vers=%d,link_id=%d,Corr=%d,WS name=%." - "8s,Host name=%.8s\n", - dev->name, p_ctlbk->version, - p_ctlbk->linkid, - p_ctlbk->correlator, - p_sysval->WS_name, - p_sysval->host_name); + dev_info(tdev, "%s: Recv Sys Validate Request: " + "Vers=%d,link_id=%d,Corr=%d,WS name=%.8s," + "Host name=%.8s\n", + dev->name, p_ctlbk->version, + p_ctlbk->linkid, + p_ctlbk->correlator, + p_sysval->WS_name, + p_sysval->host_name); if (memcmp(temp_host_name, p_sysval->host_name, 8)) { claw_snd_sys_validate_rsp(dev, p_ctlbk, CLAW_RC_NAME_MISMATCH); CLAW_DBF_TEXT(2, setup, "HSTBAD"); CLAW_DBF_TEXT_(2, setup, "%s", p_sysval->host_name); CLAW_DBF_TEXT_(2, setup, "%s", temp_host_name); - printk(KERN_INFO "%s: Host name mismatch\n", - dev->name); - printk(KERN_INFO "%s: Received :%s: " - "expected :%s: \n", - dev->name, + dev_warn(tdev, + "Host name %s for %s does not match the" + " remote adapter name %s\n", p_sysval->host_name, + dev->name, temp_host_name); } if (memcmp(temp_ws_name, p_sysval->WS_name, 8)) { @@ -2056,35 +2076,38 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) CLAW_DBF_TEXT(2, setup, "WSNBAD"); CLAW_DBF_TEXT_(2, setup, "%s", p_sysval->WS_name); CLAW_DBF_TEXT_(2, setup, "%s", temp_ws_name); - printk(KERN_INFO "%s: WS name mismatch\n", - dev->name); - printk(KERN_INFO "%s: Received :%s: " - "expected :%s: \n", - dev->name, - p_sysval->WS_name, - temp_ws_name); + dev_warn(tdev, "Adapter name %s for %s does not match" + " the remote host name %s\n", + p_sysval->WS_name, + dev->name, + temp_ws_name); } if ((p_sysval->write_frame_size < p_env->write_size) && (p_env->packing == 0)) { claw_snd_sys_validate_rsp(dev, p_ctlbk, CLAW_RC_HOST_RCV_TOO_SMALL); - printk(KERN_INFO "%s: host write size is too " - "small\n", dev->name); + dev_warn(tdev, + "The local write buffer is smaller than the" + " remote read buffer\n"); CLAW_DBF_TEXT(2, setup, "wrtszbad"); } if ((p_sysval->read_frame_size < p_env->read_size) && (p_env->packing == 0)) { claw_snd_sys_validate_rsp(dev, p_ctlbk, CLAW_RC_HOST_RCV_TOO_SMALL); - printk(KERN_INFO "%s: host read size is too " - "small\n", dev->name); + dev_warn(tdev, + "The local read buffer is smaller than the" + " remote write buffer\n"); CLAW_DBF_TEXT(2, setup, "rdsizbad"); } claw_snd_sys_validate_rsp(dev, p_ctlbk, 0); - printk(KERN_INFO "%s: CLAW device %.8s: System validate " - "completed.\n", dev->name, temp_ws_name); - printk("%s: sys Validate Rsize:%d Wsize:%d\n", dev->name, - p_sysval->read_frame_size, p_sysval->write_frame_size); + dev_info(tdev, + "CLAW device %.8s: System validate" + " completed.\n", temp_ws_name); + dev_info(tdev, + "%s: sys Validate Rsize:%d Wsize:%d\n", + dev->name, p_sysval->read_frame_size, + p_sysval->write_frame_size); privptr->system_validate_comp = 1; if (strncmp(p_env->api_type, WS_APPL_NAME_PACKED, 6) == 0) p_env->packing = PACKING_ASK; @@ -2092,8 +2115,10 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) break; case SYSTEM_VALIDATE_RESPONSE: p_sysval = (struct sysval *)&(p_ctlbk->data); - printk("%s: Recv Sys Validate Resp: Vers=%d,Corr=%d,RC=%d," - "WS name=%.8s,Host name=%.8s\n", + dev_info(tdev, + "Settings for %s validated (version=%d, " + "remote device=%d, rc=%d, adapter name=%.8s, " + "host name=%.8s)\n", dev->name, p_ctlbk->version, p_ctlbk->correlator, @@ -2102,41 +2127,39 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) p_sysval->host_name); switch (p_ctlbk->rc) { case 0: - printk(KERN_INFO "%s: CLAW device " - "%.8s: System validate " - "completed.\n", - dev->name, temp_ws_name); + dev_info(tdev, "%s: CLAW device " + "%.8s: System validate completed.\n", + dev->name, temp_ws_name); if (privptr->system_validate_comp == 0) claw_strt_conn_req(dev); privptr->system_validate_comp = 1; break; case CLAW_RC_NAME_MISMATCH: - printk(KERN_INFO "%s: Sys Validate " - "Resp : Host, WS name is " - "mismatch\n", - dev->name); + dev_warn(tdev, "Validating %s failed because of" + " a host or adapter name mismatch\n", + dev->name); break; case CLAW_RC_WRONG_VERSION: - printk(KERN_INFO "%s: Sys Validate " - "Resp : Wrong version\n", + dev_warn(tdev, "Validating %s failed because of a" + " version conflict\n", dev->name); break; case CLAW_RC_HOST_RCV_TOO_SMALL: - printk(KERN_INFO "%s: Sys Validate " - "Resp : bad frame size\n", + dev_warn(tdev, "Validating %s failed because of a" + " frame size conflict\n", dev->name); break; default: - printk(KERN_INFO "%s: Sys Validate " - "error code=%d \n", - dev->name, p_ctlbk->rc); + dev_warn(tdev, "The communication peer of %s rejected" + " the connection\n", + dev->name); break; } break; case CONNECTION_REQUEST: p_connect = (struct conncmd *)&(p_ctlbk->data); - printk(KERN_INFO "%s: Recv Conn Req: Vers=%d,link_id=%d," + dev_info(tdev, "%s: Recv Conn Req: Vers=%d,link_id=%d," "Corr=%d,HOST appl=%.8s,WS appl=%.8s\n", dev->name, p_ctlbk->version, @@ -2146,21 +2169,21 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) p_connect->WS_name); if (privptr->active_link_ID != 0) { claw_snd_disc(dev, p_ctlbk); - printk(KERN_INFO "%s: Conn Req error : " - "already logical link is active \n", + dev_info(tdev, "%s rejected a connection request" + " because it is already active\n", dev->name); } if (p_ctlbk->linkid != 1) { claw_snd_disc(dev, p_ctlbk); - printk(KERN_INFO "%s: Conn Req error : " - "req logical link id is not 1\n", + dev_info(tdev, "%s rejected a request to open multiple" + " connections\n", dev->name); } rc = find_link(dev, p_connect->host_name, p_connect->WS_name); if (rc != 0) { claw_snd_disc(dev, p_ctlbk); - printk(KERN_INFO "%s: Conn Resp error: " - "req appl name does not match\n", + dev_info(tdev, "%s rejected a connection request" + " because of a type mismatch\n", dev->name); } claw_send_control(dev, @@ -2172,7 +2195,7 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) p_env->packing = PACK_SEND; claw_snd_conn_req(dev, 0); } - printk(KERN_INFO "%s: CLAW device %.8s: Connection " + dev_info(tdev, "%s: CLAW device %.8s: Connection " "completed link_id=%d.\n", dev->name, temp_ws_name, p_ctlbk->linkid); @@ -2182,7 +2205,7 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) break; case CONNECTION_RESPONSE: p_connect = (struct conncmd *)&(p_ctlbk->data); - printk(KERN_INFO "%s: Revc Conn Resp: Vers=%d,link_id=%d," + dev_info(tdev, "%s: Recv Conn Resp: Vers=%d,link_id=%d," "Corr=%d,RC=%d,Host appl=%.8s, WS appl=%.8s\n", dev->name, p_ctlbk->version, @@ -2193,16 +2216,18 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) p_connect->WS_name); if (p_ctlbk->rc != 0) { - printk(KERN_INFO "%s: Conn Resp error: rc=%d \n", - dev->name, p_ctlbk->rc); + dev_warn(tdev, "The communication peer of %s rejected" + " a connection request\n", + dev->name); return 1; } rc = find_link(dev, p_connect->host_name, p_connect->WS_name); if (rc != 0) { claw_snd_disc(dev, p_ctlbk); - printk(KERN_INFO "%s: Conn Resp error: " - "req appl name does not match\n", + dev_warn(tdev, "The communication peer of %s" + " rejected a connection " + "request because of a type mismatch\n", dev->name); } /* should be until CONNECTION_CONFIRM */ @@ -2210,7 +2235,8 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) break; case CONNECTION_CONFIRM: p_connect = (struct conncmd *)&(p_ctlbk->data); - printk(KERN_INFO "%s: Recv Conn Confirm:Vers=%d,link_id=%d," + dev_info(tdev, + "%s: Recv Conn Confirm:Vers=%d,link_id=%d," "Corr=%d,Host appl=%.8s,WS appl=%.8s\n", dev->name, p_ctlbk->version, @@ -2221,21 +2247,21 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) if (p_ctlbk->linkid == -(privptr->active_link_ID)) { privptr->active_link_ID = p_ctlbk->linkid; if (p_env->packing > PACKING_ASK) { - printk(KERN_INFO "%s: Confirmed Now packing\n", - dev->name); + dev_info(tdev, + "%s: Confirmed Now packing\n", dev->name); p_env->packing = DO_PACKED; } p_ch = &privptr->channel[WRITE]; wake_up(&p_ch->wait); } else { - printk(KERN_INFO "%s: Conn confirm: " - "unexpected linkid=%d \n", + dev_warn(tdev, "Activating %s failed because of" + " an incorrect link ID=%d\n", dev->name, p_ctlbk->linkid); claw_snd_disc(dev, p_ctlbk); } break; case DISCONNECT: - printk(KERN_INFO "%s: Disconnect: " + dev_info(tdev, "%s: Disconnect: " "Vers=%d,link_id=%d,Corr=%d\n", dev->name, p_ctlbk->version, p_ctlbk->linkid, p_ctlbk->correlator); @@ -2247,12 +2273,13 @@ claw_process_control( struct net_device *dev, struct ccwbk * p_ccw) privptr->active_link_ID = 0; break; case CLAW_ERROR: - printk(KERN_INFO "%s: CLAW ERROR detected\n", + dev_warn(tdev, "The communication peer of %s failed\n", dev->name); break; default: - printk(KERN_INFO "%s: Unexpected command code=%d \n", - dev->name, p_ctlbk->command); + dev_warn(tdev, "The communication peer of %s sent" + " an unknown command code\n", + dev->name); break; } @@ -2294,12 +2321,14 @@ claw_send_control(struct net_device *dev, __u8 type, __u8 link, memcpy(&p_sysval->host_name, local_name, 8); memcpy(&p_sysval->WS_name, remote_name, 8); if (privptr->p_env->packing > 0) { - p_sysval->read_frame_size=DEF_PACK_BUFSIZE; - p_sysval->write_frame_size=DEF_PACK_BUFSIZE; + p_sysval->read_frame_size = DEF_PACK_BUFSIZE; + p_sysval->write_frame_size = DEF_PACK_BUFSIZE; } else { /* how big is the biggest group of packets */ - p_sysval->read_frame_size=privptr->p_env->read_size; - p_sysval->write_frame_size=privptr->p_env->write_size; + p_sysval->read_frame_size = + privptr->p_env->read_size; + p_sysval->write_frame_size = + privptr->p_env->write_size; } memset(&p_sysval->reserved, 0x00, 4); break; @@ -2485,7 +2514,6 @@ unpack_read(struct net_device *dev ) p_dev = &privptr->channel[READ].cdev->dev; p_env = privptr->p_env; p_this_ccw=privptr->p_read_active_first; - i=0; while (p_this_ccw!=NULL && p_this_ccw->header.flag!=CLAW_PENDING) { pack_off = 0; p = 0; @@ -2511,8 +2539,10 @@ unpack_read(struct net_device *dev ) mtc_this_frm=1; if (p_this_ccw->header.length!= privptr->p_env->read_size ) { - printk(KERN_INFO " %s: Invalid frame detected " - "length is %02x\n" , + dev_warn(p_dev, + "The communication peer of %s" + " sent a faulty" + " frame of length %02x\n", dev->name, p_this_ccw->header.length); } } @@ -2544,7 +2574,7 @@ unpack_next: goto NextFrame; p_packd = p_this_ccw->p_buffer+pack_off; p_packh = (struct clawph *) p_packd; - if ((p_packh->len == 0) || /* all done with this frame? */ + if ((p_packh->len == 0) || /* done with this frame? */ (p_packh->flag != 0)) goto NextFrame; bytes_to_mov = p_packh->len; @@ -2594,9 +2624,9 @@ unpack_next: netif_rx(skb); } else { + dev_info(p_dev, "Allocating a buffer for" + " incoming data failed\n"); privptr->stats.rx_dropped++; - printk(KERN_WARNING "%s: %s() low on memory\n", - dev->name,__func__); } privptr->mtc_offset=0; privptr->mtc_logical_link=-1; @@ -2720,8 +2750,8 @@ claw_strt_out_IO( struct net_device *dev ) if (test_and_set_bit(0, (void *)&p_ch->IO_active) == 0) { parm = (unsigned long) p_ch; CLAW_DBF_TEXT(2, trace, "StWrtIO"); - rc = ccw_device_start (p_ch->cdev,&p_first_ccw->write, parm, - 0xff, 0); + rc = ccw_device_start(p_ch->cdev, &p_first_ccw->write, parm, + 0xff, 0); if (rc != 0) { ccw_check_return_code(p_ch->cdev, rc); } @@ -2816,22 +2846,26 @@ claw_free_netdevice(struct net_device * dev, int free_dev) * Initialize everything of the net device except the name and the * channel structs. */ +static const struct net_device_ops claw_netdev_ops = { + .ndo_open = claw_open, + .ndo_stop = claw_release, + .ndo_get_stats = claw_stats, + .ndo_start_xmit = claw_tx, + .ndo_change_mtu = claw_change_mtu, +}; + static void claw_init_netdevice(struct net_device * dev) { CLAW_DBF_TEXT(2, setup, "init_dev"); CLAW_DBF_TEXT_(2, setup, "%s", dev->name); dev->mtu = CLAW_DEFAULT_MTU_SIZE; - dev->hard_start_xmit = claw_tx; - dev->open = claw_open; - dev->stop = claw_release; - dev->get_stats = claw_stats; - dev->change_mtu = claw_change_mtu; dev->hard_header_len = 0; dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = 1300; dev->flags = IFF_POINTOPOINT | IFF_NOARP; + dev->netdev_ops = &claw_netdev_ops; CLAW_DBF_TEXT(2, setup, "initok"); return; } @@ -2880,8 +2914,8 @@ claw_new_device(struct ccwgroup_device *cgdev) int ret; struct ccw_dev_id dev_id; - printk(KERN_INFO "claw: add for %s\n", - dev_name(&cgdev->cdev[READ]->dev)); + dev_info(&cgdev->dev, "add for %s\n", + dev_name(&cgdev->cdev[READ]->dev)); CLAW_DBF_TEXT(2, setup, "new_dev"); privptr = cgdev->dev.driver_data; cgdev->cdev[READ]->dev.driver_data = privptr; @@ -2897,29 +2931,28 @@ claw_new_device(struct ccwgroup_device *cgdev) if (ret == 0) ret = add_channel(cgdev->cdev[1],1,privptr); if (ret != 0) { - printk(KERN_WARNING - "add channel failed with ret = %d\n", ret); + dev_warn(&cgdev->dev, "Creating a CLAW group device" + " failed with error code %d\n", ret); goto out; } ret = ccw_device_set_online(cgdev->cdev[READ]); if (ret != 0) { - printk(KERN_WARNING - "claw: ccw_device_set_online %s READ failed " - "with ret = %d\n", dev_name(&cgdev->cdev[READ]->dev), - ret); + dev_warn(&cgdev->dev, + "Setting the read subchannel online" + " failed with error code %d\n", ret); goto out; } ret = ccw_device_set_online(cgdev->cdev[WRITE]); if (ret != 0) { - printk(KERN_WARNING - "claw: ccw_device_set_online %s WRITE failed " - "with ret = %d\n", dev_name(&cgdev->cdev[WRITE]->dev), - ret); + dev_warn(&cgdev->dev, + "Setting the write subchannel online " + "failed with error code %d\n", ret); goto out; } dev = alloc_netdev(0,"claw%d",claw_init_netdevice); if (!dev) { - printk(KERN_WARNING "%s:alloc_netdev failed\n",__func__); + dev_warn(&cgdev->dev, + "Activating the CLAW device failed\n"); goto out; } dev->ml_priv = privptr; @@ -2947,13 +2980,13 @@ claw_new_device(struct ccwgroup_device *cgdev) privptr->channel[WRITE].ndev = dev; privptr->p_env->ndev = dev; - printk(KERN_INFO "%s:readsize=%d writesize=%d " + dev_info(&cgdev->dev, "%s:readsize=%d writesize=%d " "readbuffer=%d writebuffer=%d read=0x%04x write=0x%04x\n", dev->name, p_env->read_size, p_env->write_size, p_env->read_buffers, p_env->write_buffers, p_env->devno[READ], p_env->devno[WRITE]); - printk(KERN_INFO "%s:host_name:%.8s, adapter_name " + dev_info(&cgdev->dev, "%s:host_name:%.8s, adapter_name " ":%.8s api_type: %.8s\n", dev->name, p_env->host_name, p_env->adapter_name , p_env->api_type); @@ -2997,8 +3030,8 @@ claw_shutdown_device(struct ccwgroup_device *cgdev) ndev = priv->channel[READ].ndev; if (ndev) { /* Close the device */ - printk(KERN_INFO - "%s: shuting down \n",ndev->name); + dev_info(&cgdev->dev, "%s: shutting down \n", + ndev->name); if (ndev->flags & IFF_RUNNING) ret = claw_release(ndev); ndev->flags &=~IFF_RUNNING; @@ -3023,8 +3056,7 @@ claw_remove_device(struct ccwgroup_device *cgdev) CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev)); priv = cgdev->dev.driver_data; BUG_ON(!priv); - printk(KERN_INFO "claw: %s() called %s will be removed.\n", - __func__, dev_name(&cgdev->cdev[0]->dev)); + dev_info(&cgdev->dev, " will be removed.\n"); if (cgdev->state == CCWGROUP_ONLINE) claw_shutdown_device(cgdev); claw_remove_files(&cgdev->dev); @@ -3063,7 +3095,8 @@ claw_hname_show(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -claw_hname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +claw_hname_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env * p_env; @@ -3100,7 +3133,8 @@ claw_adname_show(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -claw_adname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +claw_adname_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env * p_env; @@ -3138,7 +3172,8 @@ claw_apname_show(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -claw_apname_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +claw_apname_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env * p_env; @@ -3185,7 +3220,8 @@ claw_wbuff_show(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -claw_wbuff_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +claw_wbuff_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env * p_env; @@ -3226,7 +3262,8 @@ claw_rbuff_show(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -claw_rbuff_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +claw_rbuff_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct claw_privbk *priv; struct claw_env *p_env; @@ -3289,7 +3326,7 @@ claw_cleanup(void) { unregister_cu3088_discipline(&claw_group_driver); claw_unregister_debug_facility(); - printk(KERN_INFO "claw: Driver unloaded\n"); + pr_info("Driver unloaded\n"); } @@ -3303,12 +3340,12 @@ static int __init claw_init(void) { int ret = 0; - printk(KERN_INFO "claw: starting driver\n"); + pr_info("Loading %s\n", version); ret = claw_register_debug_facility(); if (ret) { - printk(KERN_WARNING "claw: %s() debug_register failed %d\n", - __func__,ret); + pr_err("Registering with the S/390 debug feature" + " failed with error code %d\n", ret); return ret; } CLAW_DBF_TEXT(2, setup, "init_mod"); @@ -3316,8 +3353,8 @@ claw_init(void) if (ret) { CLAW_DBF_TEXT(2, setup, "init_bad"); claw_unregister_debug_facility(); - printk(KERN_WARNING "claw; %s() cu3088 register failed %d\n", - __func__,ret); + pr_err("Registering with the cu3088 device driver failed " + "with error code %d\n", ret); } return ret; } diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index f29c708..4ded9ac 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c @@ -410,9 +410,8 @@ static void chx_rx(fsm_instance *fi, int event, void *arg) priv->stats.rx_length_errors++; goto again; } - block_len -= 2; - if (block_len > 0) { - *((__u16 *)skb->data) = block_len; + if (block_len > 2) { + *((__u16 *)skb->data) = block_len - 2; ctcm_unpack_skb(ch, skb); } again: diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 2678573..77f4033 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -105,7 +105,8 @@ void ctcm_unpack_skb(struct channel *ch, struct sk_buff *pskb) return; } pskb->protocol = ntohs(header->type); - if (header->length <= LL_HEADER_LENGTH) { + if ((header->length <= LL_HEADER_LENGTH) || + (len <= LL_HEADER_LENGTH)) { if (!(ch->logflags & LOG_FLAG_ILLEGALSIZE)) { CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, "%s(%s): Illegal packet size %d(%d,%d)" @@ -167,11 +168,9 @@ void ctcm_unpack_skb(struct channel *ch, struct sk_buff *pskb) if (len > 0) { skb_pull(pskb, header->length); if (skb_tailroom(pskb) < LL_HEADER_LENGTH) { - if (!(ch->logflags & LOG_FLAG_OVERRUN)) { - CTCM_DBF_DEV_NAME(TRACE, dev, - "Overrun in ctcm_unpack_skb"); - ch->logflags |= LOG_FLAG_OVERRUN; - } + CTCM_DBF_DEV_NAME(TRACE, dev, + "Overrun in ctcm_unpack_skb"); + ch->logflags |= LOG_FLAG_OVERRUN; return; } skb_put(pskb, LL_HEADER_LENGTH); @@ -906,11 +905,11 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) } if (ctcm_test_and_set_busy(dev)) - return -EBUSY; + return NETDEV_TX_BUSY; dev->trans_start = jiffies; if (ctcm_transmit_skb(priv->channel[WRITE], skb) != 0) - return 1; + return NETDEV_TX_BUSY; return 0; } @@ -1099,12 +1098,24 @@ static void ctcm_free_netdevice(struct net_device *dev) struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv); +static const struct net_device_ops ctcm_netdev_ops = { + .ndo_open = ctcm_open, + .ndo_stop = ctcm_close, + .ndo_get_stats = ctcm_stats, + .ndo_change_mtu = ctcm_change_mtu, + .ndo_start_xmit = ctcm_tx, +}; + +static const struct net_device_ops ctcm_mpc_netdev_ops = { + .ndo_open = ctcm_open, + .ndo_stop = ctcm_close, + .ndo_get_stats = ctcm_stats, + .ndo_change_mtu = ctcm_change_mtu, + .ndo_start_xmit = ctcmpc_tx, +}; + void static ctcm_dev_setup(struct net_device *dev) { - dev->open = ctcm_open; - dev->stop = ctcm_close; - dev->get_stats = ctcm_stats; - dev->change_mtu = ctcm_change_mtu; dev->type = ARPHRD_SLIP; dev->tx_queue_len = 100; dev->flags = IFF_POINTOPOINT | IFF_NOARP; @@ -1157,12 +1168,12 @@ static struct net_device *ctcm_init_netdevice(struct ctcm_priv *priv) dev->mtu = MPC_BUFSIZE_DEFAULT - TH_HEADER_LENGTH - PDU_HEADER_LENGTH; - dev->hard_start_xmit = ctcmpc_tx; + dev->netdev_ops = &ctcm_mpc_netdev_ops; dev->hard_header_len = TH_HEADER_LENGTH + PDU_HEADER_LENGTH; priv->buffer_size = MPC_BUFSIZE_DEFAULT; } else { dev->mtu = CTCM_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2; - dev->hard_start_xmit = ctcm_tx; + dev->netdev_ops = &ctcm_netdev_ops; dev->hard_header_len = LL_HEADER_LENGTH + 2; } diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index 3db5f84..781e18b 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -393,7 +393,6 @@ int ctc_mpc_alloc_channel(int port_num, void (*callback)(int, int)) } else { /* there are problems...bail out */ /* there may be a state mismatch so restart */ - grp->port_persist = 1; fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); grp->allocchan_callback_retries = 0; } @@ -699,11 +698,9 @@ static void ctcmpc_send_sweep_resp(struct channel *rch) return; done: - if (rc != 0) { - grp->in_sweep = 0; - ctcm_clear_busy_do(dev); - fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); - } + grp->in_sweep = 0; + ctcm_clear_busy_do(dev); + fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); return; } @@ -1118,7 +1115,6 @@ static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb) if (unlikely(fsm_getstate(grp->fsm) != MPCG_STATE_READY)) goto done; - pdu_last_seen = 0; while ((pskb->len > 0) && !pdu_last_seen) { curr_pdu = (struct pdu *)pskb->data; @@ -1396,8 +1392,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) CTCM_FUNTAIL, dev->name); if ((grp->saved_state != MPCG_STATE_RESET) || /* dealloc_channel has been called */ - ((grp->saved_state == MPCG_STATE_RESET) && - (grp->port_persist == 0))) + (grp->port_persist == 0)) fsm_deltimer(&priv->restart_timer); wch = priv->channel[WRITE]; @@ -1917,10 +1912,8 @@ static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg) if (priv) grp = priv->mpcg; - if (grp == NULL) { - fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); + if (grp == NULL) return; - } for (direction = READ; direction <= WRITE; direction++) { struct channel *ch = priv->channel[direction]; diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 49c3bfa..a45bc24 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -39,6 +39,7 @@ #include <linux/in.h> #include <linux/igmp.h> #include <linux/delay.h> +#include <linux/kthread.h> #include <net/arp.h> #include <net/ip.h> @@ -1259,7 +1260,6 @@ lcs_register_mc_addresses(void *data) struct in_device *in4_dev; card = (struct lcs_card *) data; - daemonize("regipm"); if (!lcs_do_run_thread(card, LCS_SET_MC_THREAD)) return 0; @@ -1562,7 +1562,7 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, if (skb == NULL) { card->stats.tx_dropped++; card->stats.tx_errors++; - return -EIO; + return 0; } if (card->state != DEV_STATE_UP) { dev_kfree_skb(skb); @@ -1587,7 +1587,7 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, card->tx_buffer = lcs_get_buffer(&card->write); if (card->tx_buffer == NULL) { card->stats.tx_dropped++; - rc = -EBUSY; + rc = NETDEV_TX_BUSY; goto out; } card->tx_buffer->callback = lcs_txbuffer_cb; @@ -1753,11 +1753,10 @@ lcs_start_kernel_thread(struct work_struct *work) struct lcs_card *card = container_of(work, struct lcs_card, kernel_thread_starter); LCS_DBF_TEXT(5, trace, "krnthrd"); if (lcs_do_start_thread(card, LCS_RECOVERY_THREAD)) - kernel_thread(lcs_recovery, (void *) card, SIGCHLD); + kthread_run(lcs_recovery, card, "lcs_recover"); #ifdef CONFIG_IP_MULTICAST if (lcs_do_start_thread(card, LCS_SET_MC_THREAD)) - kernel_thread(lcs_register_mc_addresses, - (void *) card, SIGCHLD); + kthread_run(lcs_register_mc_addresses, card, "regipm"); #endif } @@ -2101,6 +2100,20 @@ lcs_register_netdev(struct ccwgroup_device *ccwgdev) /** * lcs_new_device will be called by setting the group device online. */ +static const struct net_device_ops lcs_netdev_ops = { + .ndo_open = lcs_open_device, + .ndo_stop = lcs_stop_device, + .ndo_get_stats = lcs_getstats, + .ndo_start_xmit = lcs_start_xmit, +}; + +static const struct net_device_ops lcs_mc_netdev_ops = { + .ndo_open = lcs_open_device, + .ndo_stop = lcs_stop_device, + .ndo_get_stats = lcs_getstats, + .ndo_start_xmit = lcs_start_xmit, + .ndo_set_multicast_list = lcs_set_multicast_list, +}; static int lcs_new_device(struct ccwgroup_device *ccwgdev) @@ -2168,14 +2181,11 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) goto out; card->dev = dev; card->dev->ml_priv = card; - card->dev->open = lcs_open_device; - card->dev->stop = lcs_stop_device; - card->dev->hard_start_xmit = lcs_start_xmit; - card->dev->get_stats = lcs_getstats; + card->dev->netdev_ops = &lcs_netdev_ops; memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH); #ifdef CONFIG_IP_MULTICAST if (!lcs_check_multicast_support(card)) - card->dev->set_multicast_list = lcs_set_multicast_list; + card->dev->netdev_ops = &lcs_mc_netdev_ops; #endif netdev_out: lcs_set_allowed_threads(card,0xffffffff); @@ -2258,7 +2268,6 @@ lcs_recovery(void *ptr) int rc; card = (struct lcs_card *) ptr; - daemonize("lcs_recover"); LCS_DBF_TEXT(4, trace, "recover1"); if (!lcs_do_run_thread(card, LCS_RECOVERY_THREAD)) diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 930e2fc..be716e4 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1312,7 +1312,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) if (netiucv_test_and_set_busy(dev)) { IUCV_DBF_TEXT(data, 2, "EBUSY from netiucv_tx\n"); - return -EBUSY; + return NETDEV_TX_BUSY; } dev->trans_start = jiffies; rc = netiucv_transmit_skb(privptr->conn, skb) != 0; @@ -1876,20 +1876,24 @@ static void netiucv_free_netdevice(struct net_device *dev) /** * Initialize a net device. (Called from kernel in alloc_netdev()) */ +static const struct net_device_ops netiucv_netdev_ops = { + .ndo_open = netiucv_open, + .ndo_stop = netiucv_close, + .ndo_get_stats = netiucv_stats, + .ndo_start_xmit = netiucv_tx, + .ndo_change_mtu = netiucv_change_mtu, +}; + static void netiucv_setup_netdevice(struct net_device *dev) { dev->mtu = NETIUCV_MTU_DEFAULT; - dev->hard_start_xmit = netiucv_tx; - dev->open = netiucv_open; - dev->stop = netiucv_close; - dev->get_stats = netiucv_stats; - dev->change_mtu = netiucv_change_mtu; dev->destructor = netiucv_free_netdevice; dev->hard_header_len = NETIUCV_HDRLEN; dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT; dev->flags = IFF_POINTOPOINT | IFF_NOARP; + dev->netdev_ops = &netiucv_netdev_ops; } /** diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index e0c4557..447e1d1 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -134,6 +134,7 @@ struct qeth_perf_stats { unsigned int sg_skbs_rx; unsigned int sg_frags_rx; unsigned int sg_alloc_page_rx; + unsigned int tx_csum; }; /* Routing stuff */ @@ -403,7 +404,6 @@ struct qeth_qdio_q { /* possible types of qeth large_send support */ enum qeth_large_send_types { QETH_LARGE_SEND_NO, - QETH_LARGE_SEND_EDDP, QETH_LARGE_SEND_TSO, }; @@ -838,11 +838,9 @@ int qeth_get_cast_type(struct qeth_card *, struct sk_buff *); int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, - struct sk_buff *, struct qeth_hdr *, int, - struct qeth_eddp_context *, int, int); + struct sk_buff *, struct qeth_hdr *, int, int, int); int qeth_do_send_packet(struct qeth_card *, struct qeth_qdio_out_q *, - struct sk_buff *, struct qeth_hdr *, - int, struct qeth_eddp_context *); + struct sk_buff *, struct qeth_hdr *, int); int qeth_core_get_stats_count(struct net_device *); void qeth_core_get_ethtool_stats(struct net_device *, struct ethtool_stats *, u64 *); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d1b5beb..c827d69 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -17,7 +17,6 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/ip.h> -#include <linux/ipv6.h> #include <linux/tcp.h> #include <linux/mii.h> #include <linux/kthread.h> @@ -26,7 +25,6 @@ #include <asm/io.h> #include "qeth_core.h" -#include "qeth_core_offl.h" struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = { /* define dbf - Name, Pages, Areas, Maxlen, Level, View, Handle */ @@ -285,17 +283,6 @@ int qeth_set_large_send(struct qeth_card *card, netif_tx_disable(card->dev); card->options.large_send = type; switch (card->options.large_send) { - case QETH_LARGE_SEND_EDDP: - if (card->info.type != QETH_CARD_TYPE_IQD) { - card->dev->features |= NETIF_F_TSO | NETIF_F_SG | - NETIF_F_HW_CSUM; - } else { - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | - NETIF_F_HW_CSUM); - card->options.large_send = QETH_LARGE_SEND_NO; - rc = -EOPNOTSUPP; - } - break; case QETH_LARGE_SEND_TSO: if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { card->dev->features |= NETIF_F_TSO | NETIF_F_SG | @@ -956,7 +943,6 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, dev_kfree_skb_any(skb); skb = skb_dequeue(&buf->skb_list); } - qeth_eddp_buf_release_contexts(buf); for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(queue->card); ++i) { if (buf->buffer->element[i].addr && buf->is_header[i]) kmem_cache_free(qeth_core_header_cache, @@ -1690,7 +1676,7 @@ int qeth_send_control_data(struct qeth_card *card, int len, int rc; unsigned long flags; struct qeth_reply *reply = NULL; - unsigned long timeout; + unsigned long timeout, event_timeout; struct qeth_ipa_cmd *cmd; QETH_DBF_TEXT(TRACE, 2, "sendctl"); @@ -1715,9 +1701,10 @@ int qeth_send_control_data(struct qeth_card *card, int len, qeth_prepare_control_data(card, len, iob); if (IS_IPA(iob->data)) - timeout = jiffies + QETH_IPA_TIMEOUT; + event_timeout = QETH_IPA_TIMEOUT; else - timeout = jiffies + QETH_TIMEOUT; + event_timeout = QETH_TIMEOUT; + timeout = jiffies + event_timeout; QETH_DBF_TEXT(TRACE, 6, "noirqpnd"); spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); @@ -1745,7 +1732,7 @@ int qeth_send_control_data(struct qeth_card *card, int len, if ((cmd->hdr.command == IPA_CMD_SETIP) && (cmd->hdr.prot_version == QETH_PROT_IPV4)) { if (!wait_event_timeout(reply->wait_q, - atomic_read(&reply->received), timeout)) + atomic_read(&reply->received), event_timeout)) goto time_err; } else { while (!atomic_read(&reply->received)) { @@ -2693,40 +2680,21 @@ static int qeth_handle_send_error(struct qeth_card *card, struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err) { int sbalf15 = buffer->buffer->element[15].flags & 0xff; - int cc = qdio_err & 3; QETH_DBF_TEXT(TRACE, 6, "hdsnderr"); qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); - switch (cc) { - case 0: - if (qdio_err) { - QETH_DBF_TEXT(TRACE, 1, "lnkfail"); - QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); - QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", - (u16)qdio_err, (u8)sbalf15); - return QETH_SEND_ERROR_LINK_FAILURE; - } + + if (!qdio_err) return QETH_SEND_ERROR_NONE; - case 2: - if (qdio_err & QDIO_ERROR_SIGA_BUSY) { - QETH_DBF_TEXT(TRACE, 1, "SIGAcc2B"); - QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); - return QETH_SEND_ERROR_KICK_IT; - } - if ((sbalf15 >= 15) && (sbalf15 <= 31)) - return QETH_SEND_ERROR_RETRY; - return QETH_SEND_ERROR_LINK_FAILURE; - /* look at qdio_error and sbalf 15 */ - case 1: - QETH_DBF_TEXT(TRACE, 1, "SIGAcc1"); - QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); - return QETH_SEND_ERROR_LINK_FAILURE; - case 3: - default: - QETH_DBF_TEXT(TRACE, 1, "SIGAcc3"); - QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); - return QETH_SEND_ERROR_KICK_IT; - } + + if ((sbalf15 >= 15) && (sbalf15 <= 31)) + return QETH_SEND_ERROR_RETRY; + + QETH_DBF_TEXT(TRACE, 1, "lnkfail"); + QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card)); + QETH_DBF_TEXT_(TRACE, 1, "%04x %02x", + (u16)qdio_err, (u8)sbalf15); + return QETH_SEND_ERROR_LINK_FAILURE; } /* @@ -2862,10 +2830,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; if (rc) { + queue->card->stats.tx_errors += count; + /* ignore temporary SIGA errors without busy condition */ + if (rc == QDIO_ERROR_SIGA_TARGET) + return; QETH_DBF_TEXT(TRACE, 2, "flushbuf"); QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card)); - queue->card->stats.tx_errors += count; + /* this must not happen under normal circumstances. if it * happens something is really wrong -> recover */ qeth_schedule_recovery(queue->card); @@ -2940,13 +2912,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev, } for (i = first_element; i < (first_element + count); ++i) { buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; - /*we only handle the KICK_IT error by doing a recovery */ - if (qeth_handle_send_error(card, buffer, qdio_error) - == QETH_SEND_ERROR_KICK_IT){ - netif_stop_queue(card->dev); - qeth_schedule_recovery(card); - return; - } + qeth_handle_send_error(card, buffer, qdio_error); qeth_clear_output_buffer(queue, buffer); } atomic_sub(count, &queue->used_buffers); @@ -3187,11 +3153,9 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, int qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, int elements_needed, - struct qeth_eddp_context *ctx, int offset, int hd_len) + int offset, int hd_len) { struct qeth_qdio_out_buffer *buffer; - int buffers_needed = 0; - int flush_cnt = 0; int index; /* spin until we get the queue ... */ @@ -3206,27 +3170,11 @@ int qeth_do_send_packet_fast(struct qeth_card *card, */ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) goto out; - if (ctx == NULL) - queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % + queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q; - else { - buffers_needed = qeth_eddp_check_buffers_for_context(queue, - ctx); - if (buffers_needed < 0) - goto out; - queue->next_buf_to_fill = - (queue->next_buf_to_fill + buffers_needed) % - QDIO_MAX_BUFFERS_PER_Q; - } atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); - if (ctx == NULL) { - qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); - qeth_flush_buffers(queue, index, 1); - } else { - flush_cnt = qeth_eddp_fill_buffer(queue, ctx, index); - WARN_ON(buffers_needed != flush_cnt); - qeth_flush_buffers(queue, index, flush_cnt); - } + qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len); + qeth_flush_buffers(queue, index, 1); return 0; out: atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); @@ -3236,7 +3184,7 @@ EXPORT_SYMBOL_GPL(qeth_do_send_packet_fast); int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, - int elements_needed, struct qeth_eddp_context *ctx) + int elements_needed) { struct qeth_qdio_out_buffer *buffer; int start_index; @@ -3262,53 +3210,32 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, qeth_switch_to_packing_if_needed(queue); if (queue->do_pack) { do_pack = 1; - if (ctx == NULL) { - /* does packet fit in current buffer? */ - if ((QETH_MAX_BUFFER_ELEMENTS(card) - - buffer->next_element_to_fill) < elements_needed) { - /* ... no -> set state PRIMED */ - atomic_set(&buffer->state, - QETH_QDIO_BUF_PRIMED); - flush_count++; - queue->next_buf_to_fill = - (queue->next_buf_to_fill + 1) % - QDIO_MAX_BUFFERS_PER_Q; - buffer = &queue->bufs[queue->next_buf_to_fill]; - /* we did a step forward, so check buffer state - * again */ - if (atomic_read(&buffer->state) != - QETH_QDIO_BUF_EMPTY){ - qeth_flush_buffers(queue, start_index, + /* does packet fit in current buffer? */ + if ((QETH_MAX_BUFFER_ELEMENTS(card) - + buffer->next_element_to_fill) < elements_needed) { + /* ... no -> set state PRIMED */ + atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + flush_count++; + queue->next_buf_to_fill = + (queue->next_buf_to_fill + 1) % + QDIO_MAX_BUFFERS_PER_Q; + buffer = &queue->bufs[queue->next_buf_to_fill]; + /* we did a step forward, so check buffer state + * again */ + if (atomic_read(&buffer->state) != + QETH_QDIO_BUF_EMPTY) { + qeth_flush_buffers(queue, start_index, flush_count); - atomic_set(&queue->state, + atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); - return -EBUSY; - } - } - } else { - /* check if we have enough elements (including following - * free buffers) to handle eddp context */ - if (qeth_eddp_check_buffers_for_context(queue, ctx) - < 0) { - rc = -EBUSY; - goto out; + return -EBUSY; } } } - if (ctx == NULL) - tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0); - else { - tmp = qeth_eddp_fill_buffer(queue, ctx, - queue->next_buf_to_fill); - if (tmp < 0) { - rc = -EBUSY; - goto out; - } - } + tmp = qeth_fill_buffer(queue, buffer, skb, hdr, -1, 0); queue->next_buf_to_fill = (queue->next_buf_to_fill + tmp) % QDIO_MAX_BUFFERS_PER_Q; flush_count += tmp; -out: if (flush_count) qeth_flush_buffers(queue, start_index, flush_count); else if (!atomic_read(&queue->set_pci_flags_count)) @@ -4327,6 +4254,7 @@ static struct { /* 30 */{"tx count"}, {"tx do_QDIO time"}, {"tx do_QDIO count"}, + {"tx csum"}, }; int qeth_core_get_stats_count(struct net_device *dev) @@ -4378,6 +4306,7 @@ void qeth_core_get_ethtool_stats(struct net_device *dev, data[30] = card->perf_stats.outbound_cnt; data[31] = card->perf_stats.outbound_do_qdio_time; data[32] = card->perf_stats.outbound_do_qdio_cnt; + data[33] = card->perf_stats.tx_csum; } EXPORT_SYMBOL_GPL(qeth_core_get_ethtool_stats); diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c index 4080126..e69de29 100644 --- a/drivers/s390/net/qeth_core_offl.c +++ b/drivers/s390/net/qeth_core_offl.c @@ -1,699 +0,0 @@ -/* - * drivers/s390/net/qeth_core_offl.c - * - * Copyright IBM Corp. 2007 - * Author(s): Thomas Spatzier <tspat@de.ibm.com>, - * Frank Blaschka <frank.blaschka@de.ibm.com> - */ - -#include <linux/errno.h> -#include <linux/ip.h> -#include <linux/inetdevice.h> -#include <linux/netdevice.h> -#include <linux/kernel.h> -#include <linux/tcp.h> -#include <net/tcp.h> -#include <linux/skbuff.h> - -#include <net/ip.h> -#include <net/ip6_checksum.h> - -#include "qeth_core.h" -#include "qeth_core_mpc.h" -#include "qeth_core_offl.h" - -int qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue, - struct qeth_eddp_context *ctx) -{ - int index = queue->next_buf_to_fill; - int elements_needed = ctx->num_elements; - int elements_in_buffer; - int skbs_in_buffer; - int buffers_needed = 0; - - QETH_DBF_TEXT(TRACE, 5, "eddpcbfc"); - while (elements_needed > 0) { - buffers_needed++; - if (atomic_read(&queue->bufs[index].state) != - QETH_QDIO_BUF_EMPTY) - return -EBUSY; - - elements_in_buffer = QETH_MAX_BUFFER_ELEMENTS(queue->card) - - queue->bufs[index].next_element_to_fill; - skbs_in_buffer = elements_in_buffer / ctx->elements_per_skb; - elements_needed -= skbs_in_buffer * ctx->elements_per_skb; - index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; - } - return buffers_needed; -} - -static void qeth_eddp_free_context(struct qeth_eddp_context *ctx) -{ - int i; - - QETH_DBF_TEXT(TRACE, 5, "eddpfctx"); - for (i = 0; i < ctx->num_pages; ++i) - free_page((unsigned long)ctx->pages[i]); - kfree(ctx->pages); - kfree(ctx->elements); - kfree(ctx); -} - - -static void qeth_eddp_get_context(struct qeth_eddp_context *ctx) -{ - atomic_inc(&ctx->refcnt); -} - -void qeth_eddp_put_context(struct qeth_eddp_context *ctx) -{ - if (atomic_dec_return(&ctx->refcnt) == 0) - qeth_eddp_free_context(ctx); -} -EXPORT_SYMBOL_GPL(qeth_eddp_put_context); - -void qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf) -{ - struct qeth_eddp_context_reference *ref; - - QETH_DBF_TEXT(TRACE, 6, "eddprctx"); - while (!list_empty(&buf->ctx_list)) { - ref = list_entry(buf->ctx_list.next, - struct qeth_eddp_context_reference, list); - qeth_eddp_put_context(ref->ctx); - list_del(&ref->list); - kfree(ref); - } -} - -static int qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf, - struct qeth_eddp_context *ctx) -{ - struct qeth_eddp_context_reference *ref; - - QETH_DBF_TEXT(TRACE, 6, "eddprfcx"); - ref = kmalloc(sizeof(struct qeth_eddp_context_reference), GFP_ATOMIC); - if (ref == NULL) - return -ENOMEM; - qeth_eddp_get_context(ctx); - ref->ctx = ctx; - list_add_tail(&ref->list, &buf->ctx_list); - return 0; -} - -int qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue, - struct qeth_eddp_context *ctx, int index) -{ - struct qeth_qdio_out_buffer *buf = NULL; - struct qdio_buffer *buffer; - int elements = ctx->num_elements; - int element = 0; - int flush_cnt = 0; - int must_refcnt = 1; - int i; - - QETH_DBF_TEXT(TRACE, 5, "eddpfibu"); - while (elements > 0) { - buf = &queue->bufs[index]; - if (atomic_read(&buf->state) != QETH_QDIO_BUF_EMPTY) { - /* normally this should not happen since we checked for - * available elements in qeth_check_elements_for_context - */ - if (element == 0) - return -EBUSY; - else { - QETH_DBF_MESSAGE(2, "could only partially fill" - "eddp buffer!\n"); - goto out; - } - } - /* check if the whole next skb fits into current buffer */ - if ((QETH_MAX_BUFFER_ELEMENTS(queue->card) - - buf->next_element_to_fill) - < ctx->elements_per_skb){ - /* no -> go to next buffer */ - atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); - index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q; - flush_cnt++; - /* new buffer, so we have to add ctx to buffer'ctx_list - * and increment ctx's refcnt */ - must_refcnt = 1; - continue; - } - if (must_refcnt) { - must_refcnt = 0; - if (qeth_eddp_buf_ref_context(buf, ctx)) { - goto out_check; - } - } - buffer = buf->buffer; - /* fill one skb into buffer */ - for (i = 0; i < ctx->elements_per_skb; ++i) { - if (ctx->elements[element].length != 0) { - buffer->element[buf->next_element_to_fill]. - addr = ctx->elements[element].addr; - buffer->element[buf->next_element_to_fill]. - length = ctx->elements[element].length; - buffer->element[buf->next_element_to_fill]. - flags = ctx->elements[element].flags; - buf->next_element_to_fill++; - } - element++; - elements--; - } - } -out_check: - if (!queue->do_pack) { - QETH_DBF_TEXT(TRACE, 6, "fillbfnp"); - /* set state to PRIMED -> will be flushed */ - if (buf->next_element_to_fill > 0) { - atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); - flush_cnt++; - } - } else { - if (queue->card->options.performance_stats) - queue->card->perf_stats.skbs_sent_pack++; - QETH_DBF_TEXT(TRACE, 6, "fillbfpa"); - if (buf->next_element_to_fill >= - QETH_MAX_BUFFER_ELEMENTS(queue->card)) { - /* - * packed buffer if full -> set state PRIMED - * -> will be flushed - */ - atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); - flush_cnt++; - } - } -out: - return flush_cnt; -} - -static void qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, - struct qeth_eddp_data *eddp, int data_len) -{ - u8 *page; - int page_remainder; - int page_offset; - int pkt_len; - struct qeth_eddp_element *element; - - QETH_DBF_TEXT(TRACE, 5, "eddpcrsh"); - page = ctx->pages[ctx->offset >> PAGE_SHIFT]; - page_offset = ctx->offset % PAGE_SIZE; - element = &ctx->elements[ctx->num_elements]; - pkt_len = eddp->nhl + eddp->thl + data_len; - /* FIXME: layer2 and VLAN !!! */ - if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) - pkt_len += ETH_HLEN; - if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) - pkt_len += VLAN_HLEN; - /* does complete packet fit in current page ? */ - page_remainder = PAGE_SIZE - page_offset; - if (page_remainder < (sizeof(struct qeth_hdr) + pkt_len)) { - /* no -> go to start of next page */ - ctx->offset += page_remainder; - page = ctx->pages[ctx->offset >> PAGE_SHIFT]; - page_offset = 0; - } - memcpy(page + page_offset, &eddp->qh, sizeof(struct qeth_hdr)); - element->addr = page + page_offset; - element->length = sizeof(struct qeth_hdr); - ctx->offset += sizeof(struct qeth_hdr); - page_offset += sizeof(struct qeth_hdr); - /* add mac header (?) */ - if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { - memcpy(page + page_offset, &eddp->mac, ETH_HLEN); - element->length += ETH_HLEN; - ctx->offset += ETH_HLEN; - page_offset += ETH_HLEN; - } - /* add VLAN tag */ - if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) { - memcpy(page + page_offset, &eddp->vlan, VLAN_HLEN); - element->length += VLAN_HLEN; - ctx->offset += VLAN_HLEN; - page_offset += VLAN_HLEN; - } - /* add network header */ - memcpy(page + page_offset, (u8 *)&eddp->nh, eddp->nhl); - element->length += eddp->nhl; - eddp->nh_in_ctx = page + page_offset; - ctx->offset += eddp->nhl; - page_offset += eddp->nhl; - /* add transport header */ - memcpy(page + page_offset, (u8 *)&eddp->th, eddp->thl); - element->length += eddp->thl; - eddp->th_in_ctx = page + page_offset; - ctx->offset += eddp->thl; -} - -static void qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, - int len, __wsum *hcsum) -{ - struct skb_frag_struct *frag; - int left_in_frag; - int copy_len; - u8 *src; - - QETH_DBF_TEXT(TRACE, 5, "eddpcdtc"); - if (skb_shinfo(eddp->skb)->nr_frags == 0) { - skb_copy_from_linear_data_offset(eddp->skb, eddp->skb_offset, - dst, len); - *hcsum = csum_partial(eddp->skb->data + eddp->skb_offset, len, - *hcsum); - eddp->skb_offset += len; - } else { - while (len > 0) { - if (eddp->frag < 0) { - /* we're in skb->data */ - left_in_frag = (eddp->skb->len - - eddp->skb->data_len) - - eddp->skb_offset; - src = eddp->skb->data + eddp->skb_offset; - } else { - frag = &skb_shinfo(eddp->skb)->frags[ - eddp->frag]; - left_in_frag = frag->size - eddp->frag_offset; - src = (u8 *)((page_to_pfn(frag->page) << - PAGE_SHIFT) + frag->page_offset + - eddp->frag_offset); - } - if (left_in_frag <= 0) { - eddp->frag++; - eddp->frag_offset = 0; - continue; - } - copy_len = min(left_in_frag, len); - memcpy(dst, src, copy_len); - *hcsum = csum_partial(src, copy_len, *hcsum); - dst += copy_len; - eddp->frag_offset += copy_len; - eddp->skb_offset += copy_len; - len -= copy_len; - } - } -} - -static void qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx, - struct qeth_eddp_data *eddp, int data_len, __wsum hcsum) -{ - u8 *page; - int page_remainder; - int page_offset; - struct qeth_eddp_element *element; - int first_lap = 1; - - QETH_DBF_TEXT(TRACE, 5, "eddpcsdt"); - page = ctx->pages[ctx->offset >> PAGE_SHIFT]; - page_offset = ctx->offset % PAGE_SIZE; - element = &ctx->elements[ctx->num_elements]; - while (data_len) { - page_remainder = PAGE_SIZE - page_offset; - if (page_remainder < data_len) { - qeth_eddp_copy_data_tcp(page + page_offset, eddp, - page_remainder, &hcsum); - element->length += page_remainder; - if (first_lap) - element->flags = SBAL_FLAGS_FIRST_FRAG; - else - element->flags = SBAL_FLAGS_MIDDLE_FRAG; - ctx->num_elements++; - element++; - data_len -= page_remainder; - ctx->offset += page_remainder; - page = ctx->pages[ctx->offset >> PAGE_SHIFT]; - page_offset = 0; - element->addr = page + page_offset; - } else { - qeth_eddp_copy_data_tcp(page + page_offset, eddp, - data_len, &hcsum); - element->length += data_len; - if (!first_lap) - element->flags = SBAL_FLAGS_LAST_FRAG; - ctx->num_elements++; - ctx->offset += data_len; - data_len = 0; - } - first_lap = 0; - } - ((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum); -} - -static __wsum qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, - int data_len) -{ - __wsum phcsum; /* pseudo header checksum */ - - QETH_DBF_TEXT(TRACE, 5, "eddpckt4"); - eddp->th.tcp.h.check = 0; - /* compute pseudo header checksum */ - phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr, - eddp->thl + data_len, IPPROTO_TCP, 0); - /* compute checksum of tcp header */ - return csum_partial(&eddp->th, eddp->thl, phcsum); -} - -static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, - int data_len) -{ - __be32 proto; - __wsum phcsum; /* pseudo header checksum */ - - QETH_DBF_TEXT(TRACE, 5, "eddpckt6"); - eddp->th.tcp.h.check = 0; - /* compute pseudo header checksum */ - phcsum = csum_partial(&eddp->nh.ip6.h.saddr, - sizeof(struct in6_addr), 0); - phcsum = csum_partial(&eddp->nh.ip6.h.daddr, - sizeof(struct in6_addr), phcsum); - proto = htonl(IPPROTO_TCP); - phcsum = csum_partial(&proto, sizeof(u32), phcsum); - return phcsum; -} - -static struct qeth_eddp_data *qeth_eddp_create_eddp_data(struct qeth_hdr *qh, - u8 *nh, u8 nhl, u8 *th, u8 thl) -{ - struct qeth_eddp_data *eddp; - - QETH_DBF_TEXT(TRACE, 5, "eddpcrda"); - eddp = kzalloc(sizeof(struct qeth_eddp_data), GFP_ATOMIC); - if (eddp) { - eddp->nhl = nhl; - eddp->thl = thl; - memcpy(&eddp->qh, qh, sizeof(struct qeth_hdr)); - memcpy(&eddp->nh, nh, nhl); - memcpy(&eddp->th, th, thl); - eddp->frag = -1; /* initially we're in skb->data */ - } - return eddp; -} - -static void __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, - struct qeth_eddp_data *eddp) -{ - struct tcphdr *tcph; - int data_len; - __wsum hcsum; - - QETH_DBF_TEXT(TRACE, 5, "eddpftcp"); - eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl; - if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { - eddp->skb_offset += sizeof(struct ethhdr); - if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) - eddp->skb_offset += VLAN_HLEN; - } - tcph = tcp_hdr(eddp->skb); - while (eddp->skb_offset < eddp->skb->len) { - data_len = min((int)skb_shinfo(eddp->skb)->gso_size, - (int)(eddp->skb->len - eddp->skb_offset)); - /* prepare qdio hdr */ - if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { - eddp->qh.hdr.l2.pkt_length = data_len + ETH_HLEN + - eddp->nhl + eddp->thl; - if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) - eddp->qh.hdr.l2.pkt_length += VLAN_HLEN; - } else - eddp->qh.hdr.l3.length = data_len + eddp->nhl + - eddp->thl; - /* prepare ip hdr */ - if (eddp->skb->protocol == htons(ETH_P_IP)) { - eddp->nh.ip4.h.tot_len = htons(data_len + eddp->nhl + - eddp->thl); - eddp->nh.ip4.h.check = 0; - eddp->nh.ip4.h.check = - ip_fast_csum((u8 *)&eddp->nh.ip4.h, - eddp->nh.ip4.h.ihl); - } else - eddp->nh.ip6.h.payload_len = htons(data_len + - eddp->thl); - /* prepare tcp hdr */ - if (data_len == (eddp->skb->len - eddp->skb_offset)) { - /* last segment -> set FIN and PSH flags */ - eddp->th.tcp.h.fin = tcph->fin; - eddp->th.tcp.h.psh = tcph->psh; - } - if (eddp->skb->protocol == htons(ETH_P_IP)) - hcsum = qeth_eddp_check_tcp4_hdr(eddp, data_len); - else - hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len); - /* fill the next segment into the context */ - qeth_eddp_create_segment_hdrs(ctx, eddp, data_len); - qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum); - if (eddp->skb_offset >= eddp->skb->len) - break; - /* prepare headers for next round */ - if (eddp->skb->protocol == htons(ETH_P_IP)) - eddp->nh.ip4.h.id = htons(ntohs(eddp->nh.ip4.h.id) + 1); - eddp->th.tcp.h.seq = htonl(ntohl(eddp->th.tcp.h.seq) + - data_len); - } -} - -static int qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, - struct sk_buff *skb, struct qeth_hdr *qhdr) -{ - struct qeth_eddp_data *eddp = NULL; - - QETH_DBF_TEXT(TRACE, 5, "eddpficx"); - /* create our segmentation headers and copy original headers */ - if (skb->protocol == htons(ETH_P_IP)) - eddp = qeth_eddp_create_eddp_data(qhdr, - skb_network_header(skb), - ip_hdrlen(skb), - skb_transport_header(skb), - tcp_hdrlen(skb)); - else - eddp = qeth_eddp_create_eddp_data(qhdr, - skb_network_header(skb), - sizeof(struct ipv6hdr), - skb_transport_header(skb), - tcp_hdrlen(skb)); - - if (eddp == NULL) { - QETH_DBF_TEXT(TRACE, 2, "eddpfcnm"); - return -ENOMEM; - } - if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { - skb_set_mac_header(skb, sizeof(struct qeth_hdr)); - memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN); - if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) { - eddp->vlan[0] = skb->protocol; - eddp->vlan[1] = htons(vlan_tx_tag_get(skb)); - } - } - /* the next flags will only be set on the last segment */ - eddp->th.tcp.h.fin = 0; - eddp->th.tcp.h.psh = 0; - eddp->skb = skb; - /* begin segmentation and fill context */ - __qeth_eddp_fill_context_tcp(ctx, eddp); - kfree(eddp); - return 0; -} - -static void qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, - struct sk_buff *skb, int hdr_len) -{ - int skbs_per_page; - - QETH_DBF_TEXT(TRACE, 5, "eddpcanp"); - /* can we put multiple skbs in one page? */ - skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->gso_size + hdr_len); - if (skbs_per_page > 1) { - ctx->num_pages = (skb_shinfo(skb)->gso_segs + 1) / - skbs_per_page + 1; - ctx->elements_per_skb = 1; - } else { - /* no -> how many elements per skb? */ - ctx->elements_per_skb = (skb_shinfo(skb)->gso_size + hdr_len + - PAGE_SIZE) >> PAGE_SHIFT; - ctx->num_pages = ctx->elements_per_skb * - (skb_shinfo(skb)->gso_segs + 1); - } - ctx->num_elements = ctx->elements_per_skb * - (skb_shinfo(skb)->gso_segs + 1); -} - -static struct qeth_eddp_context *qeth_eddp_create_context_generic( - struct qeth_card *card, struct sk_buff *skb, int hdr_len) -{ - struct qeth_eddp_context *ctx = NULL; - u8 *addr; - int i; - - QETH_DBF_TEXT(TRACE, 5, "creddpcg"); - /* create the context and allocate pages */ - ctx = kzalloc(sizeof(struct qeth_eddp_context), GFP_ATOMIC); - if (ctx == NULL) { - QETH_DBF_TEXT(TRACE, 2, "ceddpcn1"); - return NULL; - } - ctx->type = QETH_LARGE_SEND_EDDP; - qeth_eddp_calc_num_pages(ctx, skb, hdr_len); - if (ctx->elements_per_skb > QETH_MAX_BUFFER_ELEMENTS(card)) { - QETH_DBF_TEXT(TRACE, 2, "ceddpcis"); - kfree(ctx); - return NULL; - } - ctx->pages = kcalloc(ctx->num_pages, sizeof(u8 *), GFP_ATOMIC); - if (ctx->pages == NULL) { - QETH_DBF_TEXT(TRACE, 2, "ceddpcn2"); - kfree(ctx); - return NULL; - } - for (i = 0; i < ctx->num_pages; ++i) { - addr = (u8 *)get_zeroed_page(GFP_ATOMIC); - if (addr == NULL) { - QETH_DBF_TEXT(TRACE, 2, "ceddpcn3"); - ctx->num_pages = i; - qeth_eddp_free_context(ctx); - return NULL; - } - ctx->pages[i] = addr; - } - ctx->elements = kcalloc(ctx->num_elements, - sizeof(struct qeth_eddp_element), GFP_ATOMIC); - if (ctx->elements == NULL) { - QETH_DBF_TEXT(TRACE, 2, "ceddpcn4"); - qeth_eddp_free_context(ctx); - return NULL; - } - /* reset num_elements; will be incremented again in fill_buffer to - * reflect number of actually used elements */ - ctx->num_elements = 0; - return ctx; -} - -static struct qeth_eddp_context *qeth_eddp_create_context_tcp( - struct qeth_card *card, struct sk_buff *skb, - struct qeth_hdr *qhdr) -{ - struct qeth_eddp_context *ctx = NULL; - - QETH_DBF_TEXT(TRACE, 5, "creddpct"); - if (skb->protocol == htons(ETH_P_IP)) - ctx = qeth_eddp_create_context_generic(card, skb, - (sizeof(struct qeth_hdr) + - ip_hdrlen(skb) + - tcp_hdrlen(skb))); - else if (skb->protocol == htons(ETH_P_IPV6)) - ctx = qeth_eddp_create_context_generic(card, skb, - sizeof(struct qeth_hdr) + sizeof(struct ipv6hdr) + - tcp_hdrlen(skb)); - else - QETH_DBF_TEXT(TRACE, 2, "cetcpinv"); - - if (ctx == NULL) { - QETH_DBF_TEXT(TRACE, 2, "creddpnl"); - return NULL; - } - if (qeth_eddp_fill_context_tcp(ctx, skb, qhdr)) { - QETH_DBF_TEXT(TRACE, 2, "ceddptfe"); - qeth_eddp_free_context(ctx); - return NULL; - } - atomic_set(&ctx->refcnt, 1); - return ctx; -} - -struct qeth_eddp_context *qeth_eddp_create_context(struct qeth_card *card, - struct sk_buff *skb, struct qeth_hdr *qhdr, - unsigned char sk_protocol) -{ - QETH_DBF_TEXT(TRACE, 5, "creddpc"); - switch (sk_protocol) { - case IPPROTO_TCP: - return qeth_eddp_create_context_tcp(card, skb, qhdr); - default: - QETH_DBF_TEXT(TRACE, 2, "eddpinvp"); - } - return NULL; -} -EXPORT_SYMBOL_GPL(qeth_eddp_create_context); - -void qeth_tso_fill_header(struct qeth_card *card, struct qeth_hdr *qhdr, - struct sk_buff *skb) -{ - struct qeth_hdr_tso *hdr = (struct qeth_hdr_tso *)qhdr; - struct tcphdr *tcph = tcp_hdr(skb); - struct iphdr *iph = ip_hdr(skb); - struct ipv6hdr *ip6h = ipv6_hdr(skb); - - QETH_DBF_TEXT(TRACE, 5, "tsofhdr"); - - /*fix header to TSO values ...*/ - hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; - /*set values which are fix for the first approach ...*/ - hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); - hdr->ext.imb_hdr_no = 1; - hdr->ext.hdr_type = 1; - hdr->ext.hdr_version = 1; - hdr->ext.hdr_len = 28; - /*insert non-fix values */ - hdr->ext.mss = skb_shinfo(skb)->gso_size; - hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4); - hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len - - sizeof(struct qeth_hdr_tso)); - tcph->check = 0; - if (skb->protocol == ETH_P_IPV6) { - ip6h->payload_len = 0; - tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, - 0, IPPROTO_TCP, 0); - } else { - /*OSA want us to set these values ...*/ - tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, - 0, IPPROTO_TCP, 0); - iph->tot_len = 0; - iph->check = 0; - } -} -EXPORT_SYMBOL_GPL(qeth_tso_fill_header); - -void qeth_tx_csum(struct sk_buff *skb) -{ - int tlen; - if (skb->protocol == htons(ETH_P_IP)) { - tlen = ntohs(ip_hdr(skb)->tot_len) - (ip_hdr(skb)->ihl << 2); - switch (ip_hdr(skb)->protocol) { - case IPPROTO_TCP: - tcp_hdr(skb)->check = 0; - tcp_hdr(skb)->check = csum_tcpudp_magic( - ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, - tlen, ip_hdr(skb)->protocol, - skb_checksum(skb, skb_transport_offset(skb), - tlen, 0)); - break; - case IPPROTO_UDP: - udp_hdr(skb)->check = 0; - udp_hdr(skb)->check = csum_tcpudp_magic( - ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, - tlen, ip_hdr(skb)->protocol, - skb_checksum(skb, skb_transport_offset(skb), - tlen, 0)); - break; - } - } else if (skb->protocol == htons(ETH_P_IPV6)) { - switch (ipv6_hdr(skb)->nexthdr) { - case IPPROTO_TCP: - tcp_hdr(skb)->check = 0; - tcp_hdr(skb)->check = csum_ipv6_magic( - &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - ipv6_hdr(skb)->payload_len, - ipv6_hdr(skb)->nexthdr, - skb_checksum(skb, skb_transport_offset(skb), - ipv6_hdr(skb)->payload_len, 0)); - break; - case IPPROTO_UDP: - udp_hdr(skb)->check = 0; - udp_hdr(skb)->check = csum_ipv6_magic( - &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - ipv6_hdr(skb)->payload_len, - ipv6_hdr(skb)->nexthdr, - skb_checksum(skb, skb_transport_offset(skb), - ipv6_hdr(skb)->payload_len, 0)); - break; - } - } -} -EXPORT_SYMBOL_GPL(qeth_tx_csum); diff --git a/drivers/s390/net/qeth_core_offl.h b/drivers/s390/net/qeth_core_offl.h index 86bf7df..e69de29 100644 --- a/drivers/s390/net/qeth_core_offl.h +++ b/drivers/s390/net/qeth_core_offl.h @@ -1,76 +0,0 @@ -/* - * drivers/s390/net/qeth_core_offl.h - * - * Copyright IBM Corp. 2007 - * Author(s): Thomas Spatzier <tspat@de.ibm.com>, - * Frank Blaschka <frank.blaschka@de.ibm.com> - */ - -#ifndef __QETH_CORE_OFFL_H__ -#define __QETH_CORE_OFFL_H__ - -struct qeth_eddp_element { - u32 flags; - u32 length; - void *addr; -}; - -struct qeth_eddp_context { - atomic_t refcnt; - enum qeth_large_send_types type; - int num_pages; /* # of allocated pages */ - u8 **pages; /* pointers to pages */ - int offset; /* offset in ctx during creation */ - int num_elements; /* # of required 'SBALEs' */ - struct qeth_eddp_element *elements; /* array of 'SBALEs' */ - int elements_per_skb; /* # of 'SBALEs' per skb **/ -}; - -struct qeth_eddp_context_reference { - struct list_head list; - struct qeth_eddp_context *ctx; -}; - -struct qeth_eddp_data { - struct qeth_hdr qh; - struct ethhdr mac; - __be16 vlan[2]; - union { - struct { - struct iphdr h; - u8 options[40]; - } ip4; - struct { - struct ipv6hdr h; - } ip6; - } nh; - u8 nhl; - void *nh_in_ctx; /* address of nh within the ctx */ - union { - struct { - struct tcphdr h; - u8 options[40]; - } tcp; - } th; - u8 thl; - void *th_in_ctx; /* address of th within the ctx */ - struct sk_buff *skb; - int skb_offset; - int frag; - int frag_offset; -} __attribute__ ((packed)); - -extern struct qeth_eddp_context *qeth_eddp_create_context(struct qeth_card *, - struct sk_buff *, struct qeth_hdr *, unsigned char); -extern void qeth_eddp_put_context(struct qeth_eddp_context *); -extern int qeth_eddp_fill_buffer(struct qeth_qdio_out_q *, - struct qeth_eddp_context *, int); -extern void qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *); -extern int qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *, - struct qeth_eddp_context *); - -void qeth_tso_fill_header(struct qeth_card *, struct qeth_hdr *, - struct sk_buff *); -void qeth_tx_csum(struct sk_buff *skb); - -#endif /* __QETH_CORE_EDDP_H__ */ diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index c26e842..568465d 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -427,8 +427,6 @@ static ssize_t qeth_dev_large_send_show(struct device *dev, switch (card->options.large_send) { case QETH_LARGE_SEND_NO: return sprintf(buf, "%s\n", "no"); - case QETH_LARGE_SEND_EDDP: - return sprintf(buf, "%s\n", "EDDP"); case QETH_LARGE_SEND_TSO: return sprintf(buf, "%s\n", "TSO"); default: @@ -449,8 +447,6 @@ static ssize_t qeth_dev_large_send_store(struct device *dev, tmp = strsep((char **) &buf, "\n"); if (!strcmp(tmp, "no")) { type = QETH_LARGE_SEND_NO; - } else if (!strcmp(tmp, "EDDP")) { - type = QETH_LARGE_SEND_EDDP; } else if (!strcmp(tmp, "TSO")) { type = QETH_LARGE_SEND_TSO; } else { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 07ab8a5..172031b 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -21,7 +21,6 @@ #include <linux/ip.h> #include "qeth_core.h" -#include "qeth_core_offl.h" static int qeth_l2_set_offline(struct ccwgroup_device *); static int qeth_l2_stop(struct net_device *); @@ -328,6 +327,10 @@ static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) struct qeth_vlan_vid *id; QETH_DBF_TEXT_(TRACE, 4, "aid:%d", vid); + if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { + QETH_DBF_TEXT(TRACE, 3, "aidREC"); + return; + } id = kmalloc(sizeof(struct qeth_vlan_vid), GFP_ATOMIC); if (id) { id->vid = vid; @@ -344,6 +347,10 @@ static void qeth_l2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) struct qeth_card *card = dev->ml_priv; QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid); + if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { + QETH_DBF_TEXT(TRACE, 3, "kidREC"); + return; + } spin_lock_bh(&card->vlanlock); list_for_each_entry(id, &card->vid_list, list) { if (id->vid == vid) { @@ -379,7 +386,8 @@ static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) dev_close(card->dev); rtnl_unlock(); } - if (!card->use_hard_stop) { + if (!card->use_hard_stop || + recovery_mode) { __u8 *mac = &card->dev->dev_addr[0]; rc = qeth_l2_send_delmac(card, mac); QETH_DBF_TEXT_(SETUP, 2, "Lerr%d", rc); @@ -388,7 +396,8 @@ static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) } if (card->state == CARD_STATE_SOFTSETUP) { qeth_l2_process_vlans(card, 1); - if (!card->use_hard_stop) + if (!card->use_hard_stop || + recovery_mode) qeth_l2_del_all_mc(card); qeth_clear_ipacmd_list(card); card->state = CARD_STATE_HARDSETUP; @@ -593,6 +602,10 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) } QETH_DBF_TEXT_(TRACE, 3, "%s", CARD_BUS_ID(card)); QETH_DBF_HEX(TRACE, 3, addr->sa_data, OSA_ADDR_LEN); + if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { + QETH_DBF_TEXT(TRACE, 3, "setmcREC"); + return -ERESTARTSYS; + } rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]); if (!rc) rc = qeth_l2_send_setmac(card, addr->sa_data); @@ -608,6 +621,9 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) return ; QETH_DBF_TEXT(TRACE, 3, "setmulti"); + if (qeth_threads_running(card, QETH_RECOVER_THREAD) && + (card->state != CARD_STATE_UP)) + return; qeth_l2_del_all_mc(card); spin_lock_bh(&card->mclock); for (dm = dev->mc_list; dm; dm = dm->next) @@ -634,8 +650,6 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct qeth_qdio_out_q *queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; int tx_bytes = skb->len; - enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; - struct qeth_eddp_context *ctx = NULL; int data_offset = -1; int elements_needed = 0; int hd_len = 0; @@ -655,14 +669,10 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } netif_stop_queue(dev); - if (skb_is_gso(skb)) - large_send = QETH_LARGE_SEND_EDDP; - if (card->info.type == QETH_CARD_TYPE_OSN) hdr = (struct qeth_hdr *)skb->data; else { - if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && - (skb_shinfo(skb)->nr_frags == 0)) { + if (card->info.type == QETH_CARD_TYPE_IQD) { new_skb = skb; data_offset = ETH_HLEN; hd_len = ETH_HLEN; @@ -689,59 +699,26 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - if (large_send == QETH_LARGE_SEND_EDDP) { - ctx = qeth_eddp_create_context(card, new_skb, hdr, - skb->sk->sk_protocol); - if (ctx == NULL) { - QETH_DBF_MESSAGE(2, "could not create eddp context\n"); - goto tx_drop; - } - } else { - elements = qeth_get_elements_no(card, (void *)hdr, new_skb, + elements = qeth_get_elements_no(card, (void *)hdr, new_skb, elements_needed); - if (!elements) { - if (data_offset >= 0) - kmem_cache_free(qeth_core_header_cache, hdr); - goto tx_drop; - } + if (!elements) { + if (data_offset >= 0) + kmem_cache_free(qeth_core_header_cache, hdr); + goto tx_drop; } - if ((large_send == QETH_LARGE_SEND_NO) && - (skb->ip_summed == CHECKSUM_PARTIAL)) - qeth_tx_csum(new_skb); - if (card->info.type != QETH_CARD_TYPE_IQD) rc = qeth_do_send_packet(card, queue, new_skb, hdr, - elements, ctx); + elements); else rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, - elements, ctx, data_offset, hd_len); + elements, data_offset, hd_len); if (!rc) { card->stats.tx_packets++; card->stats.tx_bytes += tx_bytes; if (new_skb != skb) dev_kfree_skb_any(skb); - if (card->options.performance_stats) { - if (large_send != QETH_LARGE_SEND_NO) { - card->perf_stats.large_send_bytes += tx_bytes; - card->perf_stats.large_send_cnt++; - } - if (skb_shinfo(new_skb)->nr_frags > 0) { - card->perf_stats.sg_skbs_sent++; - /* nr_frags + skb->data */ - card->perf_stats.sg_frags_sent += - skb_shinfo(new_skb)->nr_frags + 1; - } - } - - if (ctx != NULL) { - qeth_eddp_put_context(ctx); - dev_kfree_skb_any(new_skb); - } } else { - if (ctx != NULL) - qeth_eddp_put_context(ctx); - if (data_offset >= 0) kmem_cache_free(qeth_core_header_cache, hdr); @@ -878,30 +855,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) return; } -static int qeth_l2_ethtool_set_tso(struct net_device *dev, u32 data) -{ - struct qeth_card *card = dev->ml_priv; - - if (data) { - if (card->options.large_send == QETH_LARGE_SEND_NO) { - card->options.large_send = QETH_LARGE_SEND_EDDP; - dev->features |= NETIF_F_TSO; - } - } else { - dev->features &= ~NETIF_F_TSO; - card->options.large_send = QETH_LARGE_SEND_NO; - } - return 0; -} - static struct ethtool_ops qeth_l2_ethtool_ops = { .get_link = ethtool_op_get_link, - .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_hw_csum, - .get_sg = ethtool_op_get_sg, - .set_sg = ethtool_op_set_sg, - .get_tso = ethtool_op_get_tso, - .set_tso = qeth_l2_ethtool_set_tso, .get_strings = qeth_core_get_strings, .get_ethtool_stats = qeth_core_get_ethtool_stats, .get_stats_count = qeth_core_get_stats_count, diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 3d04920..0ba3817 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -19,15 +19,15 @@ #include <linux/etherdevice.h> #include <linux/mii.h> #include <linux/ip.h> -#include <linux/reboot.h> +#include <linux/ipv6.h> #include <linux/inetdevice.h> #include <linux/igmp.h> #include <net/ip.h> #include <net/arp.h> +#include <net/ip6_checksum.h> #include "qeth_l3.h" -#include "qeth_core_offl.h" static int qeth_l3_set_offline(struct ccwgroup_device *); static int qeth_l3_recover(void *); @@ -1038,7 +1038,7 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card) rc = qeth_query_setadapterparms(card); if (rc) { QETH_DBF_MESSAGE(2, "%s couldn't set adapter parameters: " - "0x%x\n", card->gdev->dev.bus_id, rc); + "0x%x\n", dev_name(&card->gdev->dev), rc); return rc; } if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) { @@ -1838,6 +1838,10 @@ static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) unsigned long flags; QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid); + if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { + QETH_DBF_TEXT(TRACE, 3, "kidREC"); + return; + } spin_lock_irqsave(&card->vlanlock, flags); /* unregister IP addresses of vlan device */ qeth_l3_free_vlan_addresses(card, vid); @@ -2101,6 +2105,9 @@ static void qeth_l3_set_multicast_list(struct net_device *dev) struct qeth_card *card = dev->ml_priv; QETH_DBF_TEXT(TRACE, 3, "setmulti"); + if (qeth_threads_running(card, QETH_RECOVER_THREAD) && + (card->state != CARD_STATE_UP)) + return; qeth_l3_delete_mc_addresses(card); qeth_l3_add_multicast_ipv4(card); #ifdef CONFIG_QETH_IPV6 @@ -2577,12 +2584,63 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, } } +static void qeth_tso_fill_header(struct qeth_card *card, + struct qeth_hdr *qhdr, struct sk_buff *skb) +{ + struct qeth_hdr_tso *hdr = (struct qeth_hdr_tso *)qhdr; + struct tcphdr *tcph = tcp_hdr(skb); + struct iphdr *iph = ip_hdr(skb); + struct ipv6hdr *ip6h = ipv6_hdr(skb); + + /*fix header to TSO values ...*/ + hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; + /*set values which are fix for the first approach ...*/ + hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); + hdr->ext.imb_hdr_no = 1; + hdr->ext.hdr_type = 1; + hdr->ext.hdr_version = 1; + hdr->ext.hdr_len = 28; + /*insert non-fix values */ + hdr->ext.mss = skb_shinfo(skb)->gso_size; + hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4); + hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len - + sizeof(struct qeth_hdr_tso)); + tcph->check = 0; + if (skb->protocol == ETH_P_IPV6) { + ip6h->payload_len = 0; + tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + 0, IPPROTO_TCP, 0); + } else { + /*OSA want us to set these values ...*/ + tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + 0, IPPROTO_TCP, 0); + iph->tot_len = 0; + iph->check = 0; + } +} + +static void qeth_tx_csum(struct sk_buff *skb) +{ + __wsum csum; + int offset; + + skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb)); + offset = skb->csum_start - skb_headroom(skb); + BUG_ON(offset >= skb_headlen(skb)); + csum = skb_checksum(skb, offset, skb->len - offset, 0); + + offset += skb->csum_offset; + BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb)); + *(__sum16 *)(skb->data + offset) = csum_fold(csum); +} + static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { int rc; u16 *tag; struct qeth_hdr *hdr = NULL; int elements_needed = 0; + int elems; struct qeth_card *card = dev->ml_priv; struct sk_buff *new_skb = NULL; int ipv = qeth_get_ip_version(skb); @@ -2591,8 +2649,8 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) [qeth_get_priority_queue(card, skb, ipv, cast_type)]; int tx_bytes = skb->len; enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; - struct qeth_eddp_context *ctx = NULL; int data_offset = -1; + int nr_frags; if ((card->info.type == QETH_CARD_TYPE_IQD) && (skb->protocol != htons(ETH_P_IPV6)) && @@ -2615,6 +2673,12 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_is_gso(skb)) large_send = card->options.large_send; + else + if (skb->ip_summed == CHECKSUM_PARTIAL) { + qeth_tx_csum(skb); + if (card->options.performance_stats) + card->perf_stats.tx_csum++; + } if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && (skb_shinfo(skb)->nr_frags == 0)) { @@ -2661,12 +2725,13 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); /* fix hardware limitation: as long as we do not have sbal - * chaining we can not send long frag lists so we temporary - * switch to EDDP + * chaining we can not send long frag lists */ if ((large_send == QETH_LARGE_SEND_TSO) && - ((skb_shinfo(new_skb)->nr_frags + 2) > 16)) - large_send = QETH_LARGE_SEND_EDDP; + ((skb_shinfo(new_skb)->nr_frags + 2) > 16)) { + if (skb_linearize(new_skb)) + goto tx_drop; + } if ((large_send == QETH_LARGE_SEND_TSO) && (cast_type == RTN_UNSPEC)) { @@ -2689,37 +2754,22 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } } - if (large_send == QETH_LARGE_SEND_EDDP) { - /* new_skb is not owned by a socket so we use skb to get - * the protocol - */ - ctx = qeth_eddp_create_context(card, new_skb, hdr, - skb->sk->sk_protocol); - if (ctx == NULL) { - QETH_DBF_MESSAGE(2, "could not create eddp context\n"); - goto tx_drop; - } - } else { - int elems = qeth_get_elements_no(card, (void *)hdr, new_skb, + elems = qeth_get_elements_no(card, (void *)hdr, new_skb, elements_needed); - if (!elems) { - if (data_offset >= 0) - kmem_cache_free(qeth_core_header_cache, hdr); - goto tx_drop; - } - elements_needed += elems; + if (!elems) { + if (data_offset >= 0) + kmem_cache_free(qeth_core_header_cache, hdr); + goto tx_drop; } - - if ((large_send == QETH_LARGE_SEND_NO) && - (new_skb->ip_summed == CHECKSUM_PARTIAL)) - qeth_tx_csum(new_skb); + elements_needed += elems; + nr_frags = skb_shinfo(new_skb)->nr_frags; if (card->info.type != QETH_CARD_TYPE_IQD) rc = qeth_do_send_packet(card, queue, new_skb, hdr, - elements_needed, ctx); + elements_needed); else rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, - elements_needed, ctx, data_offset, 0); + elements_needed, data_offset, 0); if (!rc) { card->stats.tx_packets++; @@ -2731,22 +2781,13 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) card->perf_stats.large_send_bytes += tx_bytes; card->perf_stats.large_send_cnt++; } - if (skb_shinfo(new_skb)->nr_frags > 0) { + if (nr_frags) { card->perf_stats.sg_skbs_sent++; /* nr_frags + skb->data */ - card->perf_stats.sg_frags_sent += - skb_shinfo(new_skb)->nr_frags + 1; + card->perf_stats.sg_frags_sent += nr_frags + 1; } } - - if (ctx != NULL) { - qeth_eddp_put_context(ctx); - dev_kfree_skb_any(new_skb); - } } else { - if (ctx != NULL) - qeth_eddp_put_context(ctx); - if (data_offset >= 0) kmem_cache_free(qeth_core_header_cache, hdr); @@ -2841,7 +2882,7 @@ static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data) if (data) { if (card->options.large_send == QETH_LARGE_SEND_NO) { if (card->info.type == QETH_CARD_TYPE_IQD) - card->options.large_send = QETH_LARGE_SEND_EDDP; + return -EPERM; else card->options.large_send = QETH_LARGE_SEND_TSO; dev->features |= NETIF_F_TSO; |