Commit 0dc80d7c authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: network driver.

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

s390 network driver changes:
 - ctc/lcs/qeth: prevent a ccw-device to be grouped multiple times.
 - icuv: clear correct field in iucv_register_program if no userid is specified.
 - lcs: fix online/offline cycle again.
 - lcs: fix ungrouping of lcs group device. The channels of the lcs card
   should be offline afterwards.
 - lcs: don't do netif_stop_queue if no tx buffer is available, just
   return -EBUSY and drop the packets.
parent ba0ce578
/* /*
* drivers/s390/cio/ccwgroup.c * drivers/s390/cio/ccwgroup.c
* bus driver for ccwgroup * bus driver for ccwgroup
* $Revision: 1.24 $ * $Revision: 1.25 $
* *
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation * IBM Corporation
...@@ -102,8 +102,10 @@ ccwgroup_release (struct device *dev) ...@@ -102,8 +102,10 @@ ccwgroup_release (struct device *dev)
gdev = to_ccwgroupdev(dev); gdev = to_ccwgroupdev(dev);
for (i = 0; i < gdev->count; i++) for (i = 0; i < gdev->count; i++) {
gdev->cdev[i]->dev.driver_data = NULL;
put_device(&gdev->cdev[i]->dev); put_device(&gdev->cdev[i]->dev);
}
kfree(gdev); kfree(gdev);
} }
...@@ -155,6 +157,7 @@ ccwgroup_create(struct device *root, ...@@ -155,6 +157,7 @@ ccwgroup_create(struct device *root,
struct ccwgroup_device *gdev; struct ccwgroup_device *gdev;
int i; int i;
int rc; int rc;
int del_drvdata;
if (argc > 256) /* disallow dumb users */ if (argc > 256) /* disallow dumb users */
return -EINVAL; return -EINVAL;
...@@ -166,6 +169,7 @@ ccwgroup_create(struct device *root, ...@@ -166,6 +169,7 @@ ccwgroup_create(struct device *root,
memset(gdev, 0, sizeof(*gdev) + argc*sizeof(gdev->cdev[0])); memset(gdev, 0, sizeof(*gdev) + argc*sizeof(gdev->cdev[0]));
atomic_set(&gdev->onoff, 0); atomic_set(&gdev->onoff, 0);
del_drvdata = 0;
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
...@@ -177,7 +181,15 @@ ccwgroup_create(struct device *root, ...@@ -177,7 +181,15 @@ ccwgroup_create(struct device *root,
rc = -EINVAL; rc = -EINVAL;
goto error; goto error;
} }
/* Don't allow a device to belong to more than one group. */
if (gdev->cdev[i]->dev.driver_data) {
rc = -EINVAL;
goto error;
}
} }
for (i = 0; i < argc; i++)
gdev->cdev[i]->dev.driver_data = gdev;
del_drvdata = 1;
*gdev = (struct ccwgroup_device) { *gdev = (struct ccwgroup_device) {
.creator_id = creator_id, .creator_id = creator_id,
...@@ -212,9 +224,11 @@ ccwgroup_create(struct device *root, ...@@ -212,9 +224,11 @@ ccwgroup_create(struct device *root,
device_unregister(&gdev->dev); device_unregister(&gdev->dev);
error: error:
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
if (gdev->cdev[i]) if (gdev->cdev[i]) {
put_device(&gdev->cdev[i]->dev); put_device(&gdev->cdev[i]->dev);
if (del_drvdata)
gdev->cdev[i]->dev.driver_data = NULL;
}
kfree(gdev); kfree(gdev);
return rc; return rc;
...@@ -399,40 +413,14 @@ static inline struct ccwgroup_device * ...@@ -399,40 +413,14 @@ static inline struct ccwgroup_device *
__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
{ {
struct ccwgroup_device *gdev; struct ccwgroup_device *gdev;
struct list_head *entry;
struct device *dev;
int i, found;
/*
* Find groupdevice cdev belongs to.
* Unfortunately, we can't use bus_for_each_dev() because of the
* semaphore (and return value of fn() is int).
*/
if (!get_bus(&ccwgroup_bus_type))
return NULL;
gdev = NULL;
down_read(&ccwgroup_bus_type.subsys.rwsem);
list_for_each(entry, &ccwgroup_bus_type.devices.list) {
dev = get_device(container_of(entry, struct device, bus_list));
found = 0;
if (!dev)
continue;
gdev = to_ccwgroupdev(dev);
for (i = 0; i < gdev->count && (!found); i++) {
if (gdev->cdev[i] == cdev)
found = 1;
}
if (found)
break;
put_device(dev);
gdev = NULL;
}
up_read(&ccwgroup_bus_type.subsys.rwsem);
put_bus(&ccwgroup_bus_type);
if (cdev->dev.driver_data) {
gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
if (get_device(&gdev->dev))
return gdev; return gdev;
return NULL;
}
return NULL;
} }
void void
......
/* /*
* $Id: ctcmain.c,v 1.57 2004/03/02 15:34:01 mschwide Exp $ * $Id: ctcmain.c,v 1.58 2004/03/24 10:51:56 ptiedem Exp $
* *
* CTC / ESCON network driver * CTC / ESCON network driver
* *
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.57 $ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.58 $
* *
*/ */
...@@ -319,7 +319,7 @@ static void ...@@ -319,7 +319,7 @@ static void
print_banner(void) print_banner(void)
{ {
static int printed = 0; static int printed = 0;
char vbuf[] = "$Revision: 1.57 $"; char vbuf[] = "$Revision: 1.58 $";
char *version = vbuf; char *version = vbuf;
if (printed) if (printed)
...@@ -2067,7 +2067,8 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) ...@@ -2067,7 +2067,8 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
return; return;
} }
priv = cdev->dev.driver_data; priv = ((struct ccwgroup_device *)cdev->dev.driver_data)
->dev.driver_data;
/* Try to extract channel from driver data. */ /* Try to extract channel from driver data. */
if (priv->channel[READ]->cdev == cdev) if (priv->channel[READ]->cdev == cdev)
...@@ -2963,8 +2964,6 @@ ctc_probe_device(struct ccwgroup_device *cgdev) ...@@ -2963,8 +2964,6 @@ ctc_probe_device(struct ccwgroup_device *cgdev)
cgdev->cdev[0]->handler = ctc_irq_handler; cgdev->cdev[0]->handler = ctc_irq_handler;
cgdev->cdev[1]->handler = ctc_irq_handler; cgdev->cdev[1]->handler = ctc_irq_handler;
cgdev->dev.driver_data = priv; cgdev->dev.driver_data = priv;
cgdev->cdev[0]->dev.driver_data = priv;
cgdev->cdev[1]->dev.driver_data = priv;
return 0; return 0;
} }
......
/* /*
* $Id: iucv.c,v 1.26 2004/03/10 11:55:31 braunu Exp $ * $Id: iucv.c,v 1.27 2004/03/22 07:43:43 braunu Exp $
* *
* IUCV network driver * IUCV network driver
* *
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.26 $ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.27 $
* *
*/ */
...@@ -351,7 +351,7 @@ do { \ ...@@ -351,7 +351,7 @@ do { \
static void static void
iucv_banner(void) iucv_banner(void)
{ {
char vbuf[] = "$Revision: 1.26 $"; char vbuf[] = "$Revision: 1.27 $";
char *version = vbuf; char *version = vbuf;
if ((version = strchr(version, ':'))) { if ((version = strchr(version, ':'))) {
...@@ -374,14 +374,14 @@ iucv_init(void) ...@@ -374,14 +374,14 @@ iucv_init(void)
{ {
int ret; int ret;
if (iucv_external_int_buffer)
return 0;
if (!MACHINE_IS_VM) { if (!MACHINE_IS_VM) {
printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n"); printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n");
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
} }
if (iucv_external_int_buffer)
return 0;
ret = bus_register(&iucv_bus); ret = bus_register(&iucv_bus);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "IUCV: failed to register bus.\n"); printk(KERN_ERR "IUCV: failed to register bus.\n");
...@@ -830,7 +830,7 @@ iucv_register_program (__u8 pgmname[16], ...@@ -830,7 +830,7 @@ iucv_register_program (__u8 pgmname[16],
memset (new_handler->id.mask, 0xFF, memset (new_handler->id.mask, 0xFF,
sizeof (new_handler->id.mask)); sizeof (new_handler->id.mask));
} }
memset (new_handler->id.mask, 0x00, memset (new_handler->id.userid, 0x00,
sizeof (new_handler->id.userid)); sizeof (new_handler->id.userid));
} }
/* fill in the rest of handler */ /* fill in the rest of handler */
......
This diff is collapsed.
...@@ -6,18 +6,35 @@ ...@@ -6,18 +6,35 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#define VERSION_LCS_H "$Revision: 1.13 $" #define VERSION_LCS_H "$Revision: 1.15 $"
#define LCS_DBF_TEXT(level, name, text) \ #define LCS_DBF_TEXT(level, name, text) \
do { \ do { \
debug_text_event(lcs_dbf_##name, level, text); \ debug_text_event(lcs_dbf_##name, level, text); \
} while (0) } while (0)
#define LCS_DBF_HEX(level,name,addr,len) \
do { \
debug_event(lcs_dbf_##name,level,(void*)(addr),len); \
} while (0)
#define LCS_DBF_TEXT_(level,name,text...) \
do { \
sprintf(debug_buffer, text); \
debug_text_event(lcs_dbf_##name,level, debug_buffer);\
} while (0)
/** /**
* some more definitions for debug or output stuff * some more definitions for debug or output stuff
*/ */
#define PRINTK_HEADER " lcs: " #define PRINTK_HEADER " lcs: "
/**
* sysfs related stuff
*/
#define CARD_FROM_DEV(cdev) \
(struct lcs_card *) \
((struct ccwgroup_device *)cdev->dev.driver_data)->dev.driver_data;
/** /**
* CCW commands used in this driver * CCW commands used in this driver
*/ */
...@@ -123,6 +140,7 @@ enum lcs_channel_states { ...@@ -123,6 +140,7 @@ enum lcs_channel_states {
CH_STATE_STOPPED, CH_STATE_STOPPED,
CH_STATE_RUNNING, CH_STATE_RUNNING,
CH_STATE_SUSPENDED, CH_STATE_SUSPENDED,
CH_STATE_CLEARED,
}; };
/** /**
...@@ -131,6 +149,7 @@ enum lcs_channel_states { ...@@ -131,6 +149,7 @@ enum lcs_channel_states {
enum lcs_dev_states { enum lcs_dev_states {
DEV_STATE_DOWN, DEV_STATE_DOWN,
DEV_STATE_UP, DEV_STATE_UP,
DEV_STATE_RECOVER,
}; };
/** /**
......
/* /*
* $Id: netiucv.c,v 1.45 2004/03/15 08:48:48 braunu Exp $ * $Id: netiucv.c,v 1.47 2004/03/22 07:41:42 braunu Exp $
* *
* IUCV network driver * IUCV network driver
* *
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* RELEASE-TAG: IUCV network driver $Revision: 1.45 $ * RELEASE-TAG: IUCV network driver $Revision: 1.47 $
* *
*/ */
...@@ -764,7 +764,7 @@ conn_action_start(fsm_instance *fi, int event, void *arg) ...@@ -764,7 +764,7 @@ conn_action_start(fsm_instance *fi, int event, void *arg)
{ {
struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_event *ev = (struct iucv_event *)arg;
struct iucv_connection *conn = ev->conn; struct iucv_connection *conn = ev->conn;
__u16 msglimit;
int rc; int rc;
pr_debug("%s() called\n", __FUNCTION__); pr_debug("%s() called\n", __FUNCTION__);
...@@ -793,10 +793,11 @@ conn_action_start(fsm_instance *fi, int event, void *arg) ...@@ -793,10 +793,11 @@ conn_action_start(fsm_instance *fi, int event, void *arg)
fsm_newstate(fi, CONN_STATE_SETUPWAIT); fsm_newstate(fi, CONN_STATE_SETUPWAIT);
rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic,
conn->userid, iucv_host, 0, NULL, NULL, conn->handle, conn->userid, iucv_host, 0, NULL, &msglimit, conn->handle,
conn); conn);
switch (rc) { switch (rc) {
case 0: case 0:
conn->netdev->tx_queue_len = msglimit;
return; return;
case 11: case 11:
printk(KERN_NOTICE printk(KERN_NOTICE
...@@ -1911,7 +1912,7 @@ static struct device_driver netiucv_driver = { ...@@ -1911,7 +1912,7 @@ static struct device_driver netiucv_driver = {
static void static void
netiucv_banner(void) netiucv_banner(void)
{ {
char vbuf[] = "$Revision: 1.45 $"; char vbuf[] = "$Revision: 1.47 $";
char *version = vbuf; char *version = vbuf;
if ((version = strchr(version, ':'))) { if ((version = strchr(version, ':'))) {
......
...@@ -755,7 +755,7 @@ qeth_get_cards_problem(struct ccw_device *cdev, unsigned char *buffer, ...@@ -755,7 +755,7 @@ qeth_get_cards_problem(struct ccw_device *cdev, unsigned char *buffer,
int problem = 0; int problem = 0;
struct qeth_card *card; struct qeth_card *card;
card = cdev->dev.driver_data; card = CARD_FROM_CDEV(cdev);
if (atomic_read(&card->shutdown_phase)) if (atomic_read(&card->shutdown_phase))
return 0; return 0;
...@@ -6105,7 +6105,7 @@ qeth_interrupt_handler_read(struct ccw_device *cdev, unsigned long intparm, ...@@ -6105,7 +6105,7 @@ qeth_interrupt_handler_read(struct ccw_device *cdev, unsigned long intparm,
sprintf(dbf_text, "%4x", rqparam); sprintf(dbf_text, "%4x", rqparam);
QETH_DBF_TEXT4(0, trace, dbf_text); QETH_DBF_TEXT4(0, trace, dbf_text);
card = cdev->dev.driver_data; card = CARD_FROM_CDEV(cdev);
if (!card) if (!card)
return; return;
...@@ -6231,7 +6231,7 @@ qeth_interrupt_handler_write(struct ccw_device *cdev, unsigned long intparm, ...@@ -6231,7 +6231,7 @@ qeth_interrupt_handler_write(struct ccw_device *cdev, unsigned long intparm,
sprintf(dbf_text, "%4x", rqparam); sprintf(dbf_text, "%4x", rqparam);
QETH_DBF_TEXT4(0, trace, dbf_text); QETH_DBF_TEXT4(0, trace, dbf_text);
card = cdev->dev.driver_data; card = CARD_FROM_CDEV(cdev);
if (!card) if (!card)
return; return;
...@@ -6343,7 +6343,7 @@ qeth_interrupt_handler_qdio(struct ccw_device *cdev, unsigned long intparm, ...@@ -6343,7 +6343,7 @@ qeth_interrupt_handler_qdio(struct ccw_device *cdev, unsigned long intparm,
sprintf(dbf_text, "%4x", rqparam); sprintf(dbf_text, "%4x", rqparam);
QETH_DBF_TEXT4(0, trace, dbf_text); QETH_DBF_TEXT4(0, trace, dbf_text);
card = cdev->dev.driver_data; card = CARD_FROM_CDEV(cdev);
if (!card) if (!card)
return; return;
...@@ -10620,13 +10620,10 @@ qeth_probe_device(struct ccwgroup_device *gdev) ...@@ -10620,13 +10620,10 @@ qeth_probe_device(struct ccwgroup_device *gdev)
card->gdev = gdev; card->gdev = gdev;
gdev->cdev[0]->handler = qeth_interrupt_handler_read; gdev->cdev[0]->handler = qeth_interrupt_handler_read;
gdev->cdev[0]->dev.driver_data = card;
gdev->cdev[1]->handler = qeth_interrupt_handler_write; gdev->cdev[1]->handler = qeth_interrupt_handler_write;
gdev->cdev[1]->dev.driver_data = card;
gdev->cdev[2]->handler = qeth_interrupt_handler_qdio; gdev->cdev[2]->handler = qeth_interrupt_handler_qdio;
gdev->cdev[2]->dev.driver_data = card;
ret = __qeth_create_attributes(&gdev->dev); ret = __qeth_create_attributes(&gdev->dev);
if (ret != 0) if (ret != 0)
......
...@@ -696,6 +696,8 @@ struct sparebufs { ...@@ -696,6 +696,8 @@ struct sparebufs {
#define CARD_RDEV_ID(card) card->gdev->cdev[0]->dev.bus_id #define CARD_RDEV_ID(card) card->gdev->cdev[0]->dev.bus_id
#define CARD_WDEV_ID(card) card->gdev->cdev[1]->dev.bus_id #define CARD_WDEV_ID(card) card->gdev->cdev[1]->dev.bus_id
#define CARD_DDEV_ID(card) card->gdev->cdev[2]->dev.bus_id #define CARD_DDEV_ID(card) card->gdev->cdev[2]->dev.bus_id
#define CARD_FROM_CDEV(cdev) (struct qeth_card *) \
((struct ccwgroup_device *) cdev->dev.driver_data)->dev.driver_data
#define SENSE_COMMAND_REJECT_BYTE 0 #define SENSE_COMMAND_REJECT_BYTE 0
#define SENSE_COMMAND_REJECT_FLAG 0x80 #define SENSE_COMMAND_REJECT_FLAG 0x80
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment