From: Peter Tiedemann , Frank Pavlic cio/qeth changes: - Add new api to common i/o layer for qeth 1920 device support. - Add 1920 device support to qeth. Signed-off-by: Martin Schwidefsky Signed-off-by: Andrew Morton --- 25-akpm/drivers/s390/cio/chsc.c | 109 +++++++++++++++++++++++++++++++++- 25-akpm/drivers/s390/cio/chsc.h | 14 ++++ 25-akpm/drivers/s390/cio/device_ops.c | 11 +++ 25-akpm/drivers/s390/net/qeth.h | 2 25-akpm/drivers/s390/net/qeth_main.c | 48 +++++++++++++- 25-akpm/drivers/s390/net/qeth_sys.c | 14 +++- 25-akpm/include/asm-s390/ccwdev.h | 1 7 files changed, 189 insertions(+), 10 deletions(-) diff -puN drivers/s390/cio/chsc.c~s390-qeth-1920-device-support drivers/s390/cio/chsc.c --- 25/drivers/s390/cio/chsc.c~s390-qeth-1920-device-support Thu Mar 24 15:29:02 2005 +++ 25-akpm/drivers/s390/cio/chsc.c Thu Mar 24 15:29:02 2005 @@ -1,7 +1,7 @@ /* * drivers/s390/cio/chsc.c * S/390 common I/O routines -- channel subsystem call - * $Revision: 1.118 $ + * $Revision: 1.119 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -887,6 +887,27 @@ chp_status_write(struct device *dev, con static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write); +static ssize_t +chp_type_show(struct device *dev, char *buf) +{ + struct channel_path *chp = container_of(dev, struct channel_path, dev); + + if (!chp) + return 0; + return sprintf(buf, "%x\n", chp->desc.desc); +} + +static DEVICE_ATTR(type, 0444, chp_type_show, NULL); + +static struct attribute * chp_attrs[] = { + &dev_attr_status.attr, + &dev_attr_type.attr, + NULL, +}; + +static struct attribute_group chp_attr_group = { + .attrs = chp_attrs, +}; static void chp_release(struct device *dev) @@ -897,6 +918,68 @@ chp_release(struct device *dev) kfree(cp); } +static int +chsc_determine_channel_path_description(int chpid, + struct channel_path_desc *desc) +{ + int ccode, ret; + + struct { + struct chsc_header request; + u32 : 24; + u32 first_chpid : 8; + u32 : 24; + u32 last_chpid : 8; + u32 zeroes1; + struct chsc_header response; + u32 zeroes2; + struct channel_path_desc desc; + } *scpd_area; + + scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!scpd_area) + return -ENOMEM; + + scpd_area->request = (struct chsc_header) { + .length = 0x0010, + .code = 0x0002, + }; + + scpd_area->first_chpid = chpid; + scpd_area->last_chpid = chpid; + + ccode = chsc(scpd_area); + if (ccode > 0) { + ret = (ccode == 3) ? -ENODEV : -EBUSY; + goto out; + } + + switch (scpd_area->response.code) { + case 0x0001: /* Success. */ + memcpy(desc, &scpd_area->desc, + sizeof(struct channel_path_desc)); + ret = 0; + break; + case 0x0003: /* Invalid block. */ + case 0x0007: /* Invalid format. */ + case 0x0008: /* Other invalid block. */ + CIO_CRW_EVENT(2, "Error in chsc request block!\n"); + ret = -EINVAL; + break; + case 0x0004: /* Command not provided in model. */ + CIO_CRW_EVENT(2, "Model does not provide scpd\n"); + ret = -EOPNOTSUPP; + break; + default: + CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", + scpd_area->response.code); + ret = -EIO; + } +out: + free_page((unsigned long)scpd_area); + return ret; +} + /* * Entries for chpids on the system bus. * This replaces /proc/chpids. @@ -921,6 +1004,11 @@ new_channel_path(int chpid) }; snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid); + /* Obtain channel path description and fill it in. */ + ret = chsc_determine_channel_path_description(chpid, &chp->desc); + if (ret) + goto out_free; + /* make it known to the system */ ret = device_register(&chp->dev); if (ret) { @@ -928,7 +1016,7 @@ new_channel_path(int chpid) __func__, chpid); goto out_free; } - ret = device_create_file(&chp->dev, &dev_attr_status); + ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group); if (ret) { device_unregister(&chp->dev); goto out_free; @@ -940,6 +1028,23 @@ out_free: return ret; } +void * +chsc_get_chp_desc(struct subchannel *sch, int chp_no) +{ + struct channel_path *chp; + struct channel_path_desc *desc; + + chp = chps[sch->schib.pmcw.chpid[chp_no]]; + if (!chp) + return NULL; + desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); + if (!desc) + return NULL; + memcpy(desc, &chp->desc, sizeof(struct channel_path_desc)); + return desc; +} + + static int __init chsc_alloc_sei_area(void) { diff -puN drivers/s390/cio/chsc.h~s390-qeth-1920-device-support drivers/s390/cio/chsc.h --- 25/drivers/s390/cio/chsc.h~s390-qeth-1920-device-support Thu Mar 24 15:29:02 2005 +++ 25-akpm/drivers/s390/cio/chsc.h Thu Mar 24 15:29:02 2005 @@ -12,9 +12,21 @@ struct chsc_header { u16 code; }; +struct channel_path_desc { + u8 flags; + u8 lsn; + u8 desc; + u8 chpid; + u8 swla; + u8 zeroes; + u8 chla; + u8 chpp; +}; + struct channel_path { int id; int state; + struct channel_path_desc desc; struct device dev; }; @@ -49,4 +61,6 @@ extern struct css_chsc_char css_chsc_cha extern int chsc_determine_css_characteristics(void); extern int css_characteristics_avail; + +extern void *chsc_get_chp_desc(struct subchannel*, int); #endif diff -puN drivers/s390/cio/device_ops.c~s390-qeth-1920-device-support drivers/s390/cio/device_ops.c --- 25/drivers/s390/cio/device_ops.c~s390-qeth-1920-device-support Thu Mar 24 15:29:02 2005 +++ 25-akpm/drivers/s390/cio/device_ops.c Thu Mar 24 15:29:02 2005 @@ -24,6 +24,7 @@ #include "cio.h" #include "cio_debug.h" #include "css.h" +#include "chsc.h" #include "device.h" #include "qdio.h" @@ -559,6 +560,15 @@ out_unlock: return ret; } +void * +ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no) +{ + struct subchannel *sch; + + sch = to_subchannel(cdev->dev.parent); + return chsc_get_chp_desc(sch, chp_no); +} + // FIXME: these have to go: int @@ -589,4 +599,5 @@ EXPORT_SYMBOL(read_conf_data); EXPORT_SYMBOL(read_dev_chars); EXPORT_SYMBOL(_ccw_device_get_subchannel_number); EXPORT_SYMBOL(_ccw_device_get_device_number); +EXPORT_SYMBOL_GPL(ccw_device_get_chp_desc); EXPORT_SYMBOL_GPL(read_conf_data_lpm); diff -puN drivers/s390/net/qeth.h~s390-qeth-1920-device-support drivers/s390/net/qeth.h --- 25/drivers/s390/net/qeth.h~s390-qeth-1920-device-support Thu Mar 24 15:29:02 2005 +++ 25-akpm/drivers/s390/net/qeth.h Thu Mar 24 15:29:02 2005 @@ -24,7 +24,7 @@ #include "qeth_mpc.h" -#define VERSION_QETH_H "$Revision: 1.132 $" +#define VERSION_QETH_H "$Revision: 1.135 $" #ifdef CONFIG_QETH_IPV6 #define QETH_VERSION_IPV6 ":IPv6" diff -puN drivers/s390/net/qeth_main.c~s390-qeth-1920-device-support drivers/s390/net/qeth_main.c --- 25/drivers/s390/net/qeth_main.c~s390-qeth-1920-device-support Thu Mar 24 15:29:02 2005 +++ 25-akpm/drivers/s390/net/qeth_main.c Thu Mar 24 15:29:02 2005 @@ -1071,6 +1071,35 @@ qeth_setup_card(struct qeth_card *card) } static int +is_1920_device (struct qeth_card *card) +{ + int single_queue = 0; + struct ccw_device *ccwdev; + struct channelPath_dsc { + u8 flags; + u8 lsn; + u8 desc; + u8 chpid; + u8 swla; + u8 zeroes; + u8 chla; + u8 chpp; + } *chp_dsc; + + QETH_DBF_TEXT(setup, 2, "chk_1920"); + + ccwdev = card->data.ccwdev; + chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0); + if (chp_dsc != NULL) { + /* CHPP field bit 6 == 1 -> single queue */ + single_queue = ((chp_dsc->chpp & 0x02) == 0x02); + kfree(chp_dsc); + } + QETH_DBF_TEXT_(setup, 2, "rc:%x", single_queue); + return single_queue; +} + +static int qeth_determine_card_type(struct qeth_card *card) { int i = 0; @@ -1081,7 +1110,14 @@ qeth_determine_card_type(struct qeth_car if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) && (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) { card->info.type = known_devices[i][4]; - card->qdio.no_out_queues = known_devices[i][8]; + if (is_1920_device(card)) { + PRINT_INFO("Priority Queueing not able " + "due to hardware limitations!\n"); + card->qdio.no_out_queues = 1; + card->qdio.default_out_queue = 0; + } else { + card->qdio.no_out_queues = known_devices[i][8]; + } card->info.is_multicast_different = known_devices[i][9]; return 0; } @@ -1112,6 +1148,10 @@ qeth_probe_device(struct ccwgroup_device QETH_DBF_TEXT_(setup, 2, "1err%d", -ENOMEM); return -ENOMEM; } + card->read.ccwdev = gdev->cdev[0]; + card->write.ccwdev = gdev->cdev[1]; + card->data.ccwdev = gdev->cdev[2]; + if ((rc = qeth_setup_card(card))){ QETH_DBF_TEXT_(setup, 2, "2err%d", rc); put_device(dev); @@ -1130,9 +1170,6 @@ qeth_probe_device(struct ccwgroup_device qeth_free_card(card); return rc; } - card->read.ccwdev = gdev->cdev[0]; - card->write.ccwdev = gdev->cdev[1]; - card->data.ccwdev = gdev->cdev[2]; if ((rc = qeth_determine_card_type(card))){ PRINT_WARN("%s: not a valid card type\n", __func__); QETH_DBF_TEXT_(setup, 2, "3err%d", rc); @@ -3642,8 +3679,9 @@ qeth_get_priority_queue(struct qeth_card /* TODO: IPv6!!! */ } return card->qdio.default_out_queue; + case 1: /* fallthrough for single-out-queue 1920-device */ default: - return 0; + return card->qdio.default_out_queue; } } diff -puN drivers/s390/net/qeth_sys.c~s390-qeth-1920-device-support drivers/s390/net/qeth_sys.c --- 25/drivers/s390/net/qeth_sys.c~s390-qeth-1920-device-support Thu Mar 24 15:29:02 2005 +++ 25-akpm/drivers/s390/net/qeth_sys.c Thu Mar 24 15:29:02 2005 @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.49 $) + * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.51 $) * * Linux on zSeries OSA Express and HiperSockets support * This file contains code related to sysfs. @@ -20,7 +20,7 @@ #include "qeth_mpc.h" #include "qeth_fs.h" -const char *VERSION_QETH_SYS_C = "$Revision: 1.49 $"; +const char *VERSION_QETH_SYS_C = "$Revision: 1.51 $"; /*****************************************************************************/ /* */ @@ -249,6 +249,16 @@ qeth_dev_prioqing_store(struct device *d (card->state != CARD_STATE_RECOVER)) return -EPERM; + /* check if 1920 devices are supported , + * if though we have to permit priority queueing + */ + if (card->qdio.no_out_queues == 1) { + PRINT_WARN("Priority queueing disabled due " + "to hardware limitations!\n"); + card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; + return -EPERM; + } + tmp = strsep((char **) &buf, "\n"); if (!strcmp(tmp, "prio_queueing_prec")) card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC; diff -puN include/asm-s390/ccwdev.h~s390-qeth-1920-device-support include/asm-s390/ccwdev.h --- 25/include/asm-s390/ccwdev.h~s390-qeth-1920-device-support Thu Mar 24 15:29:02 2005 +++ 25-akpm/include/asm-s390/ccwdev.h Thu Mar 24 15:29:02 2005 @@ -188,4 +188,5 @@ extern int _ccw_device_get_subchannel_nu extern struct device *s390_root_dev_register(const char *); extern void s390_root_dev_unregister(struct device *); +extern void *ccw_device_get_chp_desc(struct ccw_device *, int); #endif /* _S390_CCWDEV_H_ */ _