summaryrefslogtreecommitdiff
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c3
-rw-r--r--drivers/s390/block/dasd_alias.c3
-rw-r--r--drivers/s390/block/dasd_devmap.c2
-rw-r--r--drivers/s390/block/dasd_eckd.c310
-rw-r--r--drivers/s390/block/dasd_eckd.h1
-rw-r--r--drivers/s390/block/dcssblk.c8
-rw-r--r--drivers/s390/block/scm_blk.c10
-rw-r--r--drivers/s390/char/keyboard.c7
-rw-r--r--drivers/s390/char/sclp.c12
-rw-r--r--drivers/s390/char/vmlogrdr.c7
-rw-r--r--drivers/s390/cio/vfio_ccw_drv.c2
-rw-r--r--drivers/s390/crypto/zcrypt_api.c10
-rw-r--r--drivers/s390/net/ctcm_fsms.c19
-rw-r--r--drivers/s390/net/ctcm_main.c42
-rw-r--r--drivers/s390/net/ctcm_mpc.c46
-rw-r--r--drivers/s390/net/lcs.c8
-rw-r--r--drivers/s390/net/netiucv.c34
-rw-r--r--drivers/s390/net/qeth_core.h3
-rw-r--r--drivers/s390/net/qeth_core_main.c213
-rw-r--r--drivers/s390/net/qeth_core_mpc.c16
-rw-r--r--drivers/s390/net/qeth_core_mpc.h20
-rw-r--r--drivers/s390/net/qeth_core_sys.c2
-rw-r--r--drivers/s390/net/qeth_l2_main.c61
-rw-r--r--drivers/s390/net/qeth_l3.h1
-rw-r--r--drivers/s390/net/qeth_l3_main.c65
-rw-r--r--drivers/s390/net/qeth_l3_sys.c11
26 files changed, 476 insertions, 440 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 0f1fe4ff7f51..670ac0a4ef49 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -3921,7 +3921,6 @@ EXPORT_SYMBOL(dasd_schedule_requeue);
int dasd_generic_pm_freeze(struct ccw_device *cdev)
{
struct dasd_device *device = dasd_device_from_cdev(cdev);
- int rc;
if (IS_ERR(device))
return PTR_ERR(device);
@@ -3930,7 +3929,7 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
set_bit(DASD_FLAG_SUSPENDED, &device->flags);
if (device->discipline->freeze)
- rc = device->discipline->freeze(device);
+ device->discipline->freeze(device);
/* disallow new I/O */
dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 1e560188dd13..0e0e622eadc3 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -754,7 +754,6 @@ static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
struct alias_pav_group *pavgroup;
struct dasd_device *device, *temp;
struct dasd_eckd_private *private;
- int rc;
unsigned long flags;
LIST_HEAD(active);
@@ -785,7 +784,7 @@ static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
device = list_first_entry(&active, struct dasd_device,
alias_list);
spin_unlock_irqrestore(&lcu->lock, flags);
- rc = dasd_flush_device_queue(device);
+ dasd_flush_device_queue(device);
spin_lock_irqsave(&lcu->lock, flags);
/*
* only move device around if it wasn't moved away while we
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 7c7351276d2e..779dce069cc5 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -150,7 +150,7 @@ static int __init dasd_busid(char *str, int *id0, int *id1, int *devno)
/* Old style 0xXXXX or XXXX */
if (!kstrtouint(str, 16, &val)) {
*id0 = *id1 = 0;
- if (val < 0 || val > 0xffff)
+ if (val > 0xffff)
return -EINVAL;
*devno = val;
return 0;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 122456e4db89..c3e5ad641b0b 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -213,10 +213,8 @@ static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head)
geo->head |= head;
}
-static int
-check_XRC (struct ccw1 *de_ccw,
- struct DE_eckd_data *data,
- struct dasd_device *device)
+static int check_XRC(struct ccw1 *ccw, struct DE_eckd_data *data,
+ struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
int rc;
@@ -224,7 +222,7 @@ check_XRC (struct ccw1 *de_ccw,
if (!private->rdc_data.facilities.XRC_supported)
return 0;
- /* switch on System Time Stamp - needed for XRC Support */
+ /* switch on System Time Stamp - needed for XRC Support */
data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
@@ -233,24 +231,30 @@ check_XRC (struct ccw1 *de_ccw,
if (rc == -EOPNOTSUPP || rc == -EACCES)
rc = 0;
- de_ccw->count = sizeof(struct DE_eckd_data);
- de_ccw->flags |= CCW_FLAG_SLI;
+ if (ccw) {
+ ccw->count = sizeof(struct DE_eckd_data);
+ ccw->flags |= CCW_FLAG_SLI;
+ }
+
return rc;
}
static int
define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
- unsigned int totrk, int cmd, struct dasd_device *device)
+ unsigned int totrk, int cmd, struct dasd_device *device,
+ int blksize)
{
struct dasd_eckd_private *private = device->private;
- u32 begcyl, endcyl;
u16 heads, beghead, endhead;
+ u32 begcyl, endcyl;
int rc = 0;
- ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
- ccw->flags = 0;
- ccw->count = 16;
- ccw->cda = (__u32) __pa(data);
+ if (ccw) {
+ ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
+ ccw->flags = 0;
+ ccw->count = 16;
+ ccw->cda = (__u32)__pa(data);
+ }
memset(data, 0, sizeof(struct DE_eckd_data));
switch (cmd) {
@@ -269,18 +273,24 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
data->mask.perm = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE;
break;
+ case DASD_ECKD_CCW_READ_TRACK:
+ case DASD_ECKD_CCW_READ_TRACK_DATA:
+ data->mask.perm = 0x1;
+ data->attributes.operation = private->attrib.operation;
+ data->blk_size = 0;
+ break;
case DASD_ECKD_CCW_WRITE:
case DASD_ECKD_CCW_WRITE_MT:
case DASD_ECKD_CCW_WRITE_KD:
case DASD_ECKD_CCW_WRITE_KD_MT:
data->mask.perm = 0x02;
data->attributes.operation = private->attrib.operation;
- rc = check_XRC (ccw, data, device);
+ rc = check_XRC(ccw, data, device);
break;
case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT:
data->attributes.operation = DASD_BYPASS_CACHE;
- rc = check_XRC (ccw, data, device);
+ rc = check_XRC(ccw, data, device);
break;
case DASD_ECKD_CCW_ERASE:
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -288,7 +298,18 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
data->mask.perm = 0x3;
data->mask.auth = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE;
- rc = check_XRC (ccw, data, device);
+ rc = check_XRC(ccw, data, device);
+ break;
+ case DASD_ECKD_CCW_WRITE_FULL_TRACK:
+ data->mask.perm = 0x03;
+ data->attributes.operation = private->attrib.operation;
+ data->blk_size = 0;
+ break;
+ case DASD_ECKD_CCW_WRITE_TRACK_DATA:
+ data->mask.perm = 0x02;
+ data->attributes.operation = private->attrib.operation;
+ data->blk_size = blksize;
+ rc = check_XRC(ccw, data, device);
break;
default:
dev_err(&device->cdev->dev,
@@ -325,36 +346,26 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
return rc;
}
-static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
- struct dasd_device *device)
-{
- struct dasd_eckd_private *private = device->private;
- int rc;
-
- if (!private->rdc_data.facilities.XRC_supported)
- return 0;
-
- /* switch on System Time Stamp - needed for XRC Support */
- pfxdata->define_extent.ga_extended |= 0x08; /* 'Time Stamp Valid' */
- pfxdata->define_extent.ga_extended |= 0x02; /* 'Extended Parameter' */
- pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */
-
- rc = get_phys_clock(&pfxdata->define_extent.ep_sys_time);
- /* Ignore return code if sync clock is switched off. */
- if (rc == -EOPNOTSUPP || rc == -EACCES)
- rc = 0;
- return rc;
-}
-static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
- unsigned int rec_on_trk, int count, int cmd,
- struct dasd_device *device, unsigned int reclen,
- unsigned int tlf)
+static void locate_record_ext(struct ccw1 *ccw, struct LRE_eckd_data *data,
+ unsigned int trk, unsigned int rec_on_trk,
+ int count, int cmd, struct dasd_device *device,
+ unsigned int reclen, unsigned int tlf)
{
struct dasd_eckd_private *private = device->private;
int sector;
int dn, d;
+ if (ccw) {
+ ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD_EXT;
+ ccw->flags = 0;
+ if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK)
+ ccw->count = 22;
+ else
+ ccw->count = 20;
+ ccw->cda = (__u32)__pa(data);
+ }
+
memset(data, 0, sizeof(*data));
sector = 0;
if (rec_on_trk) {
@@ -481,14 +492,12 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
unsigned int trk, unsigned int totrk, int cmd,
struct dasd_device *basedev, struct dasd_device *startdev,
- unsigned char format, unsigned int rec_on_trk, int count,
+ unsigned int format, unsigned int rec_on_trk, int count,
unsigned int blksize, unsigned int tlf)
{
struct dasd_eckd_private *basepriv, *startpriv;
- struct DE_eckd_data *dedata;
struct LRE_eckd_data *lredata;
- u32 begcyl, endcyl;
- u16 heads, beghead, endhead;
+ struct DE_eckd_data *dedata;
int rc = 0;
basepriv = basedev->private;
@@ -527,98 +536,19 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
pfxdata->validity.hyper_pav = 1;
}
- /* define extend data (mostly)*/
- switch (cmd) {
- case DASD_ECKD_CCW_READ_HOME_ADDRESS:
- case DASD_ECKD_CCW_READ_RECORD_ZERO:
- case DASD_ECKD_CCW_READ:
- case DASD_ECKD_CCW_READ_MT:
- case DASD_ECKD_CCW_READ_CKD:
- case DASD_ECKD_CCW_READ_CKD_MT:
- case DASD_ECKD_CCW_READ_KD:
- case DASD_ECKD_CCW_READ_KD_MT:
- dedata->mask.perm = 0x1;
- dedata->attributes.operation = basepriv->attrib.operation;
- break;
- case DASD_ECKD_CCW_READ_COUNT:
- dedata->mask.perm = 0x1;
- dedata->attributes.operation = DASD_BYPASS_CACHE;
- break;
- case DASD_ECKD_CCW_READ_TRACK:
- case DASD_ECKD_CCW_READ_TRACK_DATA:
- dedata->mask.perm = 0x1;
- dedata->attributes.operation = basepriv->attrib.operation;
- dedata->blk_size = 0;
- break;
- case DASD_ECKD_CCW_WRITE:
- case DASD_ECKD_CCW_WRITE_MT:
- case DASD_ECKD_CCW_WRITE_KD:
- case DASD_ECKD_CCW_WRITE_KD_MT:
- dedata->mask.perm = 0x02;
- dedata->attributes.operation = basepriv->attrib.operation;
- rc = check_XRC_on_prefix(pfxdata, basedev);
- break;
- case DASD_ECKD_CCW_WRITE_CKD:
- case DASD_ECKD_CCW_WRITE_CKD_MT:
- dedata->attributes.operation = DASD_BYPASS_CACHE;
- rc = check_XRC_on_prefix(pfxdata, basedev);
- break;
- case DASD_ECKD_CCW_ERASE:
- case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
- case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
- dedata->mask.perm = 0x3;
- dedata->mask.auth = 0x1;
- dedata->attributes.operation = DASD_BYPASS_CACHE;
- rc = check_XRC_on_prefix(pfxdata, basedev);
- break;
- case DASD_ECKD_CCW_WRITE_FULL_TRACK:
- dedata->mask.perm = 0x03;
- dedata->attributes.operation = basepriv->attrib.operation;
- dedata->blk_size = 0;
- break;
- case DASD_ECKD_CCW_WRITE_TRACK_DATA:
- dedata->mask.perm = 0x02;
- dedata->attributes.operation = basepriv->attrib.operation;
- dedata->blk_size = blksize;
- rc = check_XRC_on_prefix(pfxdata, basedev);
- break;
- default:
- DBF_DEV_EVENT(DBF_ERR, basedev,
- "PFX LRE unknown opcode 0x%x", cmd);
- BUG();
- return -EINVAL;
- }
-
- dedata->attributes.mode = 0x3; /* ECKD */
-
- if ((basepriv->rdc_data.cu_type == 0x2105 ||
- basepriv->rdc_data.cu_type == 0x2107 ||
- basepriv->rdc_data.cu_type == 0x1750)
- && !(basepriv->uses_cdl && trk < 2))
- dedata->ga_extended |= 0x40; /* Regular Data Format Mode */
-
- heads = basepriv->rdc_data.trk_per_cyl;
- begcyl = trk / heads;
- beghead = trk % heads;
- endcyl = totrk / heads;
- endhead = totrk % heads;
-
- /* check for sequential prestage - enhance cylinder range */
- if (dedata->attributes.operation == DASD_SEQ_PRESTAGE ||
- dedata->attributes.operation == DASD_SEQ_ACCESS) {
-
- if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl)
- endcyl += basepriv->attrib.nr_cyl;
- else
- endcyl = (basepriv->real_cyl - 1);
- }
+ rc = define_extent(NULL, dedata, trk, totrk, cmd, basedev, blksize);
- set_ch_t(&dedata->beg_ext, begcyl, beghead);
- set_ch_t(&dedata->end_ext, endcyl, endhead);
+ /*
+ * For some commands the System Time Stamp is set in the define extent
+ * data when XRC is supported. The validity of the time stamp must be
+ * reflected in the prefix data as well.
+ */
+ if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02)
+ pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */
if (format == 1) {
- fill_LRE_data(lredata, trk, rec_on_trk, count, cmd,
- basedev, blksize, tlf);
+ locate_record_ext(NULL, lredata, trk, rec_on_trk, count, cmd,
+ basedev, blksize, tlf);
}
return rc;
@@ -1887,7 +1817,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
ccw = cqr->cpaddr;
/* Define extent for the first 3 tracks. */
define_extent(ccw++, cqr->data, 0, 2,
- DASD_ECKD_CCW_READ_COUNT, device);
+ DASD_ECKD_CCW_READ_COUNT, device, 0);
LO_data = cqr->data + sizeof(struct DE_eckd_data);
/* Locate record for the first 4 records on track 0. */
ccw[-1].flags |= CCW_FLAG_CC;
@@ -2266,7 +2196,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
count, 0, 0);
} else {
define_extent(ccw++, data, fdata->start_unit, fdata->stop_unit,
- DASD_ECKD_CCW_READ_COUNT, startdev);
+ DASD_ECKD_CCW_READ_COUNT, startdev, 0);
data += sizeof(struct DE_eckd_data);
ccw[-1].flags |= CCW_FLAG_CC;
@@ -2420,7 +2350,7 @@ dasd_eckd_build_format(struct dasd_device *base,
} else {
define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
- DASD_ECKD_CCW_WRITE_CKD, startdev);
+ DASD_ECKD_CCW_WRITE_CKD, startdev, 0);
/* grant subsystem permission to format R0 */
if (r0_perm)
((struct DE_eckd_data *) data)
@@ -2444,7 +2374,7 @@ dasd_eckd_build_format(struct dasd_device *base,
} else {
define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
- DASD_ECKD_CCW_WRITE_RECORD_ZERO, startdev);
+ DASD_ECKD_CCW_WRITE_RECORD_ZERO, startdev, 0);
data += sizeof(struct DE_eckd_data);
}
ccw[-1].flags |= CCW_FLAG_CC;
@@ -2463,7 +2393,7 @@ dasd_eckd_build_format(struct dasd_device *base,
} else {
define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
- DASD_ECKD_CCW_WRITE_CKD, startdev);
+ DASD_ECKD_CCW_WRITE_CKD, startdev, 0);
data += sizeof(struct DE_eckd_data);
}
ccw[-1].flags |= CCW_FLAG_CC;
@@ -3187,7 +3117,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
sizeof(struct PFX_eckd_data));
} else {
if (define_extent(ccw++, cqr->data, first_trk,
- last_trk, cmd, basedev) == -EAGAIN) {
+ last_trk, cmd, basedev, 0) == -EAGAIN) {
/* Clock not in sync and XRC is enabled.
* Try again later.
*/
@@ -3509,12 +3439,19 @@ static int prepare_itcw(struct itcw *itcw,
dedata->mask.perm = 0x02;
dedata->attributes.operation = basepriv->attrib.operation;
dedata->blk_size = blksize;
- rc = check_XRC_on_prefix(&pfxdata, basedev);
+ rc = check_XRC(NULL, dedata, basedev);
dedata->ga_extended |= 0x42;
lredata->operation.orientation = 0x0;
lredata->operation.operation = 0x3F;
lredata->extended_operation = 0x23;
lredata->auxiliary.check_bytes = 0x2;
+ /*
+ * If XRC is supported the System Time Stamp is set. The
+ * validity of the time stamp must be reflected in the prefix
+ * data as well.
+ */
+ if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02)
+ pfxdata.validity.time_stamp = 1; /* 'Time Stamp Valid' */
pfx_cmd = DASD_ECKD_CCW_PFX;
break;
case DASD_ECKD_CCW_READ_COUNT_MT:
@@ -3842,25 +3779,28 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
return cqr;
}
-static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
- struct dasd_block *block,
- struct request *req)
+static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
+ struct dasd_block *block,
+ struct request *req)
{
- unsigned long *idaws;
+ sector_t start_padding_sectors, end_sector_offset, end_padding_sectors;
+ unsigned int seg_len, len_to_track_end;
+ unsigned int cidaw, cplength, datasize;
+ sector_t first_trk, last_trk, sectors;
+ struct dasd_eckd_private *base_priv;
struct dasd_device *basedev;
- struct dasd_ccw_req *cqr;
- struct ccw1 *ccw;
struct req_iterator iter;
+ struct dasd_ccw_req *cqr;
+ unsigned int first_offs;
+ unsigned int trkcount;
+ unsigned long *idaws;
+ unsigned int size;
+ unsigned char cmd;
struct bio_vec bv;
+ struct ccw1 *ccw;
+ int use_prefix;
+ void *data;
char *dst;
- unsigned char cmd;
- unsigned int trkcount;
- unsigned int seg_len, len_to_track_end;
- unsigned int first_offs;
- unsigned int cidaw, cplength, datasize;
- sector_t first_trk, last_trk, sectors;
- sector_t start_padding_sectors, end_sector_offset, end_padding_sectors;
- unsigned int pfx_datasize;
/*
* raw track access needs to be mutiple of 64k and on 64k boundary
@@ -3878,8 +3818,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
DBF_DEV_EVENT(DBF_ERR, basedev,
"raw write not track aligned (%lu,%lu) req %p",
start_padding_sectors, end_padding_sectors, req);
- cqr = ERR_PTR(-EINVAL);
- goto out;
+ return ERR_PTR(-EINVAL);
}
first_trk = blk_rq_pos(req) / DASD_RAW_SECTORS_PER_TRACK;
@@ -3892,10 +3831,8 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
cmd = DASD_ECKD_CCW_READ_TRACK;
else if (rq_data_dir(req) == WRITE)
cmd = DASD_ECKD_CCW_WRITE_FULL_TRACK;
- else {
- cqr = ERR_PTR(-EINVAL);
- goto out;
- }
+ else
+ return ERR_PTR(-EINVAL);
/*
* Raw track based I/O needs IDAWs for each page,
@@ -3903,38 +3840,46 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
*/
cidaw = trkcount * DASD_RAW_BLOCK_PER_TRACK;
- /* 1x prefix + one read/write ccw per track */
- cplength = 1 + trkcount;
-
/*
- * struct PFX_eckd_data has up to 2 byte as extended parameter
- * this is needed for write full track and has to be mentioned
- * separately
- * add 8 instead of 2 to keep 8 byte boundary
+ * struct PFX_eckd_data and struct LRE_eckd_data can have up to 2 bytes
+ * of extended parameter. This is needed for write full track.
*/
- pfx_datasize = sizeof(struct PFX_eckd_data) + 8;
+ base_priv = basedev->private;
+ use_prefix = base_priv->features.feature[8] & 0x01;
+ if (use_prefix) {
+ cplength = 1 + trkcount;
+ size = sizeof(struct PFX_eckd_data) + 2;
+ } else {
+ cplength = 2 + trkcount;
+ size = sizeof(struct DE_eckd_data) +
+ sizeof(struct LRE_eckd_data) + 2;
+ }
+ size = ALIGN(size, 8);
- datasize = pfx_datasize + cidaw * sizeof(unsigned long long);
+ datasize = size + cidaw * sizeof(unsigned long long);
/* Allocate the ccw request. */
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
datasize, startdev);
if (IS_ERR(cqr))
- goto out;
+ return cqr;
+
ccw = cqr->cpaddr;
+ data = cqr->data;
- if (prefix_LRE(ccw++, cqr->data, first_trk, last_trk, cmd,
- basedev, startdev, 1 /* format */, first_offs + 1,
- trkcount, 0, 0) == -EAGAIN) {
- /* Clock not in sync and XRC is enabled.
- * Try again later.
- */
- dasd_sfree_request(cqr, startdev);
- cqr = ERR_PTR(-EAGAIN);
- goto out;
+ if (use_prefix) {
+ prefix_LRE(ccw++, data, first_trk, last_trk, cmd, basedev,
+ startdev, 1, first_offs + 1, trkcount, 0, 0);
+ } else {
+ define_extent(ccw++, data, first_trk, last_trk, cmd, basedev, 0);
+ ccw[-1].flags |= CCW_FLAG_CC;
+
+ data += sizeof(struct DE_eckd_data);
+ locate_record_ext(ccw++, data, first_trk, first_offs + 1,
+ trkcount, cmd, basedev, 0, 0);
}
- idaws = (unsigned long *)(cqr->data + pfx_datasize);
+ idaws = (unsigned long *)(cqr->data + size);
len_to_track_end = 0;
if (start_padding_sectors) {
ccw[-1].flags |= CCW_FLAG_CC;
@@ -3984,9 +3929,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
- if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN)
- cqr = NULL;
-out:
return cqr;
}
@@ -4096,7 +4038,7 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags);
private->count++;
if ((base->features & DASD_FEATURE_USERAW))
- cqr = dasd_raw_build_cp(startdev, block, req);
+ cqr = dasd_eckd_build_cp_raw(startdev, block, req);
else
cqr = dasd_eckd_build_cp(startdev, block, req);
if (IS_ERR(cqr))
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index e2a710c250a5..fb1f537d986a 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -29,6 +29,7 @@
#define DASD_ECKD_CCW_SNID 0x34
#define DASD_ECKD_CCW_RSSD 0x3e
#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
+#define DASD_ECKD_CCW_LOCATE_RECORD_EXT 0x4b
#define DASD_ECKD_CCW_SNSS 0x54
#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
#define DASD_ECKD_CCW_WRITE_MT 0x85
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 06eb1de52d1c..68bae4f6bd88 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pfn_t.h>
+#include <linux/uio.h>
#include <linux/dax.h>
#include <asm/extmem.h>
#include <asm/io.h>
@@ -43,8 +44,15 @@ static const struct block_device_operations dcssblk_devops = {
.release = dcssblk_release,
};
+static size_t dcssblk_dax_copy_from_iter(struct dax_device *dax_dev,
+ pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
+{
+ return copy_from_iter(addr, bytes, i);
+}
+
static const struct dax_operations dcssblk_dax_ops = {
.direct_access = dcssblk_dax_direct_access,
+ .copy_from_iter = dcssblk_dax_copy_from_iter,
};
struct dcssblk_dev_info {
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c
index 42018a20f2b7..0071febac9e6 100644
--- a/drivers/s390/block/scm_blk.c
+++ b/drivers/s390/block/scm_blk.c
@@ -278,7 +278,7 @@ struct scm_queue {
spinlock_t lock;
};
-static int scm_blk_request(struct blk_mq_hw_ctx *hctx,
+static blk_status_t scm_blk_request(struct blk_mq_hw_ctx *hctx,
const struct blk_mq_queue_data *qd)
{
struct scm_device *scmdev = hctx->queue->queuedata;
@@ -290,7 +290,7 @@ static int scm_blk_request(struct blk_mq_hw_ctx *hctx,
spin_lock(&sq->lock);
if (!scm_permit_request(bdev, req)) {
spin_unlock(&sq->lock);
- return BLK_MQ_RQ_QUEUE_BUSY;
+ return BLK_STS_RESOURCE;
}
scmrq = sq->scmrq;
@@ -299,7 +299,7 @@ static int scm_blk_request(struct blk_mq_hw_ctx *hctx,
if (!scmrq) {
SCM_LOG(5, "no request");
spin_unlock(&sq->lock);
- return BLK_MQ_RQ_QUEUE_BUSY;
+ return BLK_STS_RESOURCE;
}
scm_request_init(bdev, scmrq);
sq->scmrq = scmrq;
@@ -315,7 +315,7 @@ static int scm_blk_request(struct blk_mq_hw_ctx *hctx,
sq->scmrq = NULL;
spin_unlock(&sq->lock);
- return BLK_MQ_RQ_QUEUE_BUSY;
+ return BLK_STS_RESOURCE;
}
blk_mq_start_request(req);
@@ -324,7 +324,7 @@ static int scm_blk_request(struct blk_mq_hw_ctx *hctx,
sq->scmrq = NULL;
}
spin_unlock(&sq->lock);
- return BLK_MQ_RQ_QUEUE_OK;
+ return BLK_STS_OK;
}
static int scm_blk_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index ba0e4f93503d..186d05e4c767 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -433,12 +433,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
case KDSKBSENT:
if (!perm)
return -EPERM;
- len = strnlen_user(u_kbs->kb_string, sizeof(u_kbs->kb_string));
- if (!len)
- return -EFAULT;
- if (len > sizeof(u_kbs->kb_string))
- return -EINVAL;
- p = memdup_user_nul(u_kbs->kb_string, len);
+ p = strndup_user(u_kbs->kb_string, sizeof(u_kbs->kb_string));
if (IS_ERR(p))
return PTR_ERR(p);
kfree(kbd->func_table[kb_func]);
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 9c471ea1b99c..6111c1fa2d1e 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -1096,26 +1096,26 @@ static const struct dev_pm_ops sclp_pm_ops = {
.restore = sclp_restore,
};
-static ssize_t sclp_show_console_pages(struct device_driver *dev, char *buf)
+static ssize_t con_pages_show(struct device_driver *dev, char *buf)
{
return sprintf(buf, "%i\n", sclp_console_pages);
}
-static DRIVER_ATTR(con_pages, S_IRUSR, sclp_show_console_pages, NULL);
+static DRIVER_ATTR_RO(con_pages);
-static ssize_t sclp_show_con_drop(struct device_driver *dev, char *buf)
+static ssize_t con_drop_show(struct device_driver *dev, char *buf)
{
return sprintf(buf, "%i\n", sclp_console_drop);
}
-static DRIVER_ATTR(con_drop, S_IRUSR, sclp_show_con_drop, NULL);
+static DRIVER_ATTR_RO(con_drop);
-static ssize_t sclp_show_console_full(struct device_driver *dev, char *buf)
+static ssize_t con_full_show(struct device_driver *dev, char *buf)
{
return sprintf(buf, "%lu\n", sclp_console_full);
}
-static DRIVER_ATTR(con_full, S_IRUSR, sclp_show_console_full, NULL);
+static DRIVER_ATTR_RO(con_full);
static struct attribute *sclp_drv_attrs[] = {
&driver_attr_con_pages.attr,
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 57974a1e0e03..b19020b9efff 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -641,10 +641,8 @@ static ssize_t vmlogrdr_recording_store(struct device * dev,
static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);
-static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
- char *buf)
+static ssize_t recording_status_show(struct device_driver *driver, char *buf)
{
-
static const char cp_command[] = "QUERY RECORDING ";
int len;
@@ -652,8 +650,7 @@ static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
len = strlen(buf);
return len;
}
-static DRIVER_ATTR(recording_status, 0444, vmlogrdr_recording_status_show,
- NULL);
+static DRIVER_ATTR_RO(recording_status);
static struct attribute *vmlogrdr_drv_attrs[] = {
&driver_attr_recording_status.attr,
NULL,
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index a25367ebaa89..82f05c4b8c52 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -69,12 +69,10 @@ out_unlock:
static void vfio_ccw_sch_io_todo(struct work_struct *work)
{
struct vfio_ccw_private *private;
- struct subchannel *sch;
struct irb *irb;
private = container_of(work, struct vfio_ccw_private, io_work);
irb = &private->irb;
- sch = private->sch;
if (scsw_is_solicited(&irb->scsw)) {
cp_update_scsw(&private->cp, &irb->scsw);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index b1c27e28859b..b5f4006198b9 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -94,7 +94,7 @@ static inline int zcrypt_process_rescan(void)
atomic_set(&zcrypt_rescan_req, 0);
atomic_inc(&zcrypt_rescan_count);
ap_bus_force_rescan();
- ZCRYPT_DBF(DBF_INFO, "rescan count=%07d",
+ ZCRYPT_DBF(DBF_INFO, "rescan count=%07d\n",
atomic_inc_return(&zcrypt_rescan_count));
return 1;
}
@@ -822,7 +822,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
rc = zcrypt_rsa_modexpo(&mex);
} while (rc == -EAGAIN);
if (rc) {
- ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d", rc);
+ ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc);
return rc;
}
return put_user(mex.outputdatalength, &umex->outputdatalength);
@@ -841,7 +841,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
rc = zcrypt_rsa_crt(&crt);
} while (rc == -EAGAIN);
if (rc) {
- ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d", rc);
+ ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc);
return rc;
}
return put_user(crt.outputdatalength, &ucrt->outputdatalength);
@@ -860,7 +860,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
rc = zcrypt_send_cprb(&xcRB);
} while (rc == -EAGAIN);
if (rc)
- ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d", rc);
+ ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d\n", rc);
if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
return -EFAULT;
return rc;
@@ -879,7 +879,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
rc = zcrypt_send_ep11_cprb(&xcrb);
} while (rc == -EAGAIN);
if (rc)
- ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d", rc);
+ ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc);
if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb)))
return -EFAULT;
return rc;
diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c
index 730d9619400e..570ae3b7adf6 100644
--- a/drivers/s390/net/ctcm_fsms.c
+++ b/drivers/s390/net/ctcm_fsms.c
@@ -217,7 +217,7 @@ void ctcm_purge_skb_queue(struct sk_buff_head *q)
CTCM_DBF_TEXT(TRACE, CTC_DBF_DEBUG, __func__);
while ((skb = skb_dequeue(q))) {
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
}
}
@@ -271,7 +271,7 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg)
priv->stats.tx_bytes += 2;
first = 0;
}
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
}
spin_lock(&ch->collect_lock);
@@ -297,7 +297,7 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg)
skb_put(ch->trans_skb, skb->len), skb->len);
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len - LL_HEADER_LENGTH;
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
i++;
}
@@ -1248,7 +1248,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
priv->stats.tx_bytes += 2;
first = 0;
}
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
}
spin_lock(&ch->collect_lock);
@@ -1279,7 +1279,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
__func__, data_space);
while ((skb = skb_dequeue(&ch->collect_queue))) {
- memcpy(skb_put(ch->trans_skb, skb->len), skb->data, skb->len);
+ skb_put_data(ch->trans_skb, skb->data, skb->len);
p_header = (struct pdu *)
(skb_tail_pointer(ch->trans_skb) - skb->len);
p_header->pdu_flag = 0x00;
@@ -1298,7 +1298,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
data_space -= skb->len;
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
peekskb = skb_peek(&ch->collect_queue);
if (peekskb->len > data_space)
@@ -1431,13 +1431,12 @@ static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg)
break;
case MPCG_STATE_FLOWC:
case MPCG_STATE_READY:
- memcpy(skb_put(new_skb, block_len),
- skb->data, block_len);
+ skb_put_data(new_skb, skb->data, block_len);
skb_queue_tail(&ch->io_queue, new_skb);
tasklet_schedule(&ch->ch_tasklet);
break;
default:
- memcpy(skb_put(new_skb, len), skb->data, len);
+ skb_put_data(new_skb, skb->data, len);
skb_queue_tail(&ch->io_queue, new_skb);
tasklet_hi_schedule(&ch->ch_tasklet);
break;
@@ -1796,7 +1795,7 @@ static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg)
fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
goto done;
} else {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
skb_queue_tail(&wch->io_queue, skb);
}
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 198842ce6876..1563b1458e44 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -483,7 +483,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
spin_unlock_irqrestore(&ch->collect_lock, saveflags);
return -EBUSY;
} else {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
header.length = l;
header.type = be16_to_cpu(skb->protocol);
header.unused = 0;
@@ -500,7 +500,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Protect skb against beeing free'd by upper
* layers.
*/
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
ch->prof.txlen += skb->len;
header.length = skb->len + LL_HEADER_LENGTH;
header.type = be16_to_cpu(skb->protocol);
@@ -517,14 +517,14 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
if (hi) {
nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!nskb) {
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
skb_pull(skb, LL_HEADER_LENGTH + 2);
ctcm_clear_busy(ch->netdev);
return -ENOMEM;
} else {
- memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
- atomic_inc(&nskb->users);
- atomic_dec(&skb->users);
+ skb_put_data(nskb, skb->data, skb->len);
+ refcount_inc(&nskb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
skb = nskb;
}
@@ -542,7 +542,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Remove our header. It gets added
* again on retransmit.
*/
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
skb_pull(skb, LL_HEADER_LENGTH + 2);
ctcm_clear_busy(ch->netdev);
return -ENOMEM;
@@ -553,7 +553,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
ch->ccw[1].count = skb->len;
skb_copy_from_linear_data(skb,
skb_put(ch->trans_skb, skb->len), skb->len);
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
ccw_idx = 0;
} else {
@@ -638,7 +638,7 @@ static void ctcmpc_send_sweep_req(struct channel *rch)
header->th.th_seq_num = 0x00;
header->sw.th_last_seq = ch->th_seq_num;
- memcpy(skb_put(sweep_skb, TH_SWEEP_LENGTH), header, TH_SWEEP_LENGTH);
+ skb_put_data(sweep_skb, header, TH_SWEEP_LENGTH);
kfree(header);
@@ -679,7 +679,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
if ((fsm_getstate(ch->fsm) != CTC_STATE_TXIDLE) || grp->in_sweep) {
spin_lock_irqsave(&ch->collect_lock, saveflags);
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
p_header = kmalloc(PDU_HEADER_LENGTH, gfp_type());
if (!p_header) {
@@ -716,7 +716,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Protect skb against beeing free'd by upper
* layers.
*/
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
/*
* IDAL support in CTCM is broken, so we have to
@@ -728,9 +728,9 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
if (!nskb) {
goto nomem_exit;
} else {
- memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
- atomic_inc(&nskb->users);
- atomic_dec(&skb->users);
+ skb_put_data(nskb, skb->data, skb->len);
+ refcount_inc(&nskb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
skb = nskb;
}
@@ -809,8 +809,8 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
skb_reset_tail_pointer(ch->trans_skb);
ch->trans_skb->len = 0;
ch->ccw[1].count = skb->len;
- memcpy(skb_put(ch->trans_skb, skb->len), skb->data, skb->len);
- atomic_dec(&skb->users);
+ skb_put_data(ch->trans_skb, skb->data, skb->len);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
ccw_idx = 0;
CTCM_PR_DBGDATA("%s(%s): trans_skb len: %04x\n"
@@ -855,7 +855,7 @@ nomem_exit:
"%s(%s): MEMORY allocation ERROR\n",
CTCM_FUNTAIL, ch->id);
rc = -ENOMEM;
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
done:
@@ -960,7 +960,7 @@ static int ctcmpc_tx(struct sk_buff *skb, struct net_device *dev)
}
newskb->protocol = skb->protocol;
skb_reserve(newskb, TH_HEADER_LENGTH + PDU_HEADER_LENGTH);
- memcpy(skb_put(newskb, skb->len), skb->data, skb->len);
+ skb_put_data(newskb, skb->data, skb->len);
dev_kfree_skb_any(skb);
skb = newskb;
}
@@ -1770,15 +1770,15 @@ static struct ccwgroup_driver ctcm_group_driver = {
.restore = ctcm_pm_resume,
};
-static ssize_t ctcm_driver_group_store(struct device_driver *ddrv,
- const char *buf, size_t count)
+static ssize_t group_store(struct device_driver *ddrv, const char *buf,
+ size_t count)
{
int err;
err = ccwgroup_create_dev(ctcm_root_dev, &ctcm_group_driver, 2, buf);
return err ? err : count;
}
-static DRIVER_ATTR(group, 0200, NULL, ctcm_driver_group_store);
+static DRIVER_ATTR_WO(group);
static struct attribute *ctcm_drv_attrs[] = {
&driver_attr_group.attr,
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c
index c103fc7efe9f..f8be39634f03 100644
--- a/drivers/s390/net/ctcm_mpc.c
+++ b/drivers/s390/net/ctcm_mpc.c
@@ -667,7 +667,7 @@ static void ctcmpc_send_sweep_resp(struct channel *rch)
header->th.th_seq_num = 0x00;
header->sw.th_last_seq = ch->th_seq_num;
- memcpy(skb_put(sweep_skb, TH_SWEEP_LENGTH), header, TH_SWEEP_LENGTH);
+ skb_put_data(sweep_skb, header, TH_SWEEP_LENGTH);
kfree(header);
@@ -974,9 +974,8 @@ void mpc_channel_action(struct channel *ch, int direction, int action)
skb_reset_tail_pointer(ch->xid_skb);
ch->xid_skb->len = 0;
- memcpy(skb_put(ch->xid_skb, grp->xid_skb->len),
- grp->xid_skb->data,
- grp->xid_skb->len);
+ skb_put_data(ch->xid_skb, grp->xid_skb->data,
+ grp->xid_skb->len);
ch->xid->xid2_dlc_type =
((CHANNEL_DIRECTION(ch->flags) == CTCM_READ)
@@ -1149,7 +1148,7 @@ static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
goto done;
}
- memcpy(skb_put(skb, new_len), pskb->data, new_len);
+ skb_put_data(skb, pskb->data, new_len);
skb_reset_mac_header(skb);
skb->dev = pskb->dev;
@@ -1297,16 +1296,15 @@ struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv)
/* base xid for all channels in group */
grp->xid_skb_data = grp->xid_skb->data;
grp->xid_th = (struct th_header *)grp->xid_skb->data;
- memcpy(skb_put(grp->xid_skb, TH_HEADER_LENGTH),
- &thnorm, TH_HEADER_LENGTH);
+ skb_put_data(grp->xid_skb, &thnorm, TH_HEADER_LENGTH);
grp->xid = (struct xid2 *)skb_tail_pointer(grp->xid_skb);
- memcpy(skb_put(grp->xid_skb, XID2_LENGTH), &init_xid, XID2_LENGTH);
+ skb_put_data(grp->xid_skb, &init_xid, XID2_LENGTH);
grp->xid->xid2_adj_id = jiffies | 0xfff00000;
grp->xid->xid2_sender_id = jiffies;
grp->xid_id = skb_tail_pointer(grp->xid_skb);
- memcpy(skb_put(grp->xid_skb, 4), "VTAM", 4);
+ skb_put_data(grp->xid_skb, "VTAM", 4);
grp->rcvd_xid_skb =
__dev_alloc_skb(MPC_BUFSIZE_DEFAULT, GFP_ATOMIC|GFP_DMA);
@@ -1318,8 +1316,7 @@ struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv)
}
grp->rcvd_xid_data = grp->rcvd_xid_skb->data;
grp->rcvd_xid_th = (struct th_header *)grp->rcvd_xid_skb->data;
- memcpy(skb_put(grp->rcvd_xid_skb, TH_HEADER_LENGTH),
- &thnorm, TH_HEADER_LENGTH);
+ skb_put_data(grp->rcvd_xid_skb, &thnorm, TH_HEADER_LENGTH);
grp->saved_xid2 = NULL;
priv->xid = grp->xid;
priv->mpcg = grp;
@@ -1410,8 +1407,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg)
skb_reset_tail_pointer(grp->rcvd_xid_skb);
grp->rcvd_xid_skb->len = 0;
grp->rcvd_xid_th = (struct th_header *)grp->rcvd_xid_skb->data;
- memcpy(skb_put(grp->rcvd_xid_skb, TH_HEADER_LENGTH), &thnorm,
- TH_HEADER_LENGTH);
+ skb_put_data(grp->rcvd_xid_skb, &thnorm, TH_HEADER_LENGTH);
if (grp->send_qllc_disc == 1) {
grp->send_qllc_disc = 0;
@@ -1590,8 +1586,7 @@ static int mpc_validate_xid(struct mpcg_info *mpcginfo)
grp->saved_xid2 =
(struct xid2 *)skb_tail_pointer(grp->rcvd_xid_skb);
- memcpy(skb_put(grp->rcvd_xid_skb,
- XID2_LENGTH), xid, XID2_LENGTH);
+ skb_put_data(grp->rcvd_xid_skb, xid, XID2_LENGTH);
grp->rcvd_xid_skb->data = grp->rcvd_xid_data;
skb_reset_tail_pointer(grp->rcvd_xid_skb);
@@ -1908,17 +1903,15 @@ static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg)
if (fsm_getstate(ch->fsm) == CH_XID7_PENDING1) {
fsm_newstate(ch->fsm, CH_XID7_PENDING2);
ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD;
- memcpy(skb_put(ch->xid_skb,
- TH_HEADER_LENGTH),
- &thdummy, TH_HEADER_LENGTH);
+ skb_put_data(ch->xid_skb, &thdummy,
+ TH_HEADER_LENGTH);
send = 1;
}
} else if (fsm_getstate(ch->fsm) < CH_XID7_PENDING2) {
fsm_newstate(ch->fsm, CH_XID7_PENDING2);
ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL;
- memcpy(skb_put(ch->xid_skb,
- TH_HEADER_LENGTH),
- &thnorm, TH_HEADER_LENGTH);
+ skb_put_data(ch->xid_skb, &thnorm,
+ TH_HEADER_LENGTH);
send = 1;
}
} else {
@@ -1926,17 +1919,16 @@ static void mpc_action_doxid7(fsm_instance *fsm, int event, void *arg)
if (grp->roll == YSIDE) {
if (fsm_getstate(ch->fsm) < CH_XID7_PENDING4) {
fsm_newstate(ch->fsm, CH_XID7_PENDING4);
- memcpy(skb_put(ch->xid_skb,
- TH_HEADER_LENGTH),
- &thnorm, TH_HEADER_LENGTH);
+ skb_put_data(ch->xid_skb, &thnorm,
+ TH_HEADER_LENGTH);
ch->ccw[8].cmd_code = CCW_CMD_WRITE_CTL;
send = 1;
}
} else if (fsm_getstate(ch->fsm) == CH_XID7_PENDING3) {
fsm_newstate(ch->fsm, CH_XID7_PENDING4);
ch->ccw[8].cmd_code = CCW_CMD_SENSE_CMD;
- memcpy(skb_put(ch->xid_skb, TH_HEADER_LENGTH),
- &thdummy, TH_HEADER_LENGTH);
+ skb_put_data(ch->xid_skb, &thdummy,
+ TH_HEADER_LENGTH);
send = 1;
}
}
@@ -2122,7 +2114,7 @@ static int mpc_send_qllc_discontact(struct net_device *dev)
return -ENOMEM;
}
- memcpy(skb_put(skb, new_len), qllcptr, new_len);
+ skb_put_data(skb, qllcptr, new_len);
kfree(qllcptr);
if (skb_headroom(skb) < 4) {
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 211b31d9f157..619da81dca70 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1796,7 +1796,7 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len)
card->stats.rx_dropped++;
return;
}
- memcpy(skb_put(skb, skb_len), skb_data, skb_len);
+ skb_put_data(skb, skb_data, skb_len);
skb->protocol = card->lan_type_trans(skb, card->dev);
card->stats.rx_bytes += skb_len;
card->stats.rx_packets++;
@@ -2411,14 +2411,14 @@ static struct ccwgroup_driver lcs_group_driver = {
.restore = lcs_restore,
};
-static ssize_t lcs_driver_group_store(struct device_driver *ddrv,
- const char *buf, size_t count)
+static ssize_t group_store(struct device_driver *ddrv, const char *buf,
+ size_t count)
{
int err;
err = ccwgroup_create_dev(lcs_root_dev, &lcs_group_driver, 2, buf);
return err ? err : count;
}
-static DRIVER_ATTR(group, 0200, NULL, lcs_driver_group_store);
+static DRIVER_ATTR_WO(group);
static struct attribute *lcs_drv_attrs[] = {
&driver_attr_group.attr,
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index fa732bd86729..7e0e6a4019f3 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -743,7 +743,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
conn->prof.tx_pending--;
if (single_flag) {
if ((skb = skb_dequeue(&conn->commit_queue))) {
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
if (privptr) {
privptr->stats.tx_packets++;
privptr->stats.tx_bytes +=
@@ -759,15 +759,14 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
spin_lock_irqsave(&conn->collect_lock, saveflags);
while ((skb = skb_dequeue(&conn->collect_queue))) {
header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN;
- memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,
- NETIUCV_HDRLEN);
+ skb_put_data(conn->tx_buff, &header, NETIUCV_HDRLEN);
skb_copy_from_linear_data(skb,
skb_put(conn->tx_buff, skb->len),
skb->len);
txbytes += skb->len;
txpackets++;
stat_maxcq++;
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
}
if (conn->collect_len > conn->prof.maxmulti)
@@ -780,7 +779,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
}
header.next = 0;
- memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
+ skb_put_data(conn->tx_buff, &header, NETIUCV_HDRLEN);
conn->prof.send_stamp = jiffies;
txmsg.class = 0;
txmsg.tag = 0;
@@ -959,7 +958,7 @@ static void netiucv_purge_skb_queue(struct sk_buff_head *q)
struct sk_buff *skb;
while ((skb = skb_dequeue(q))) {
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
}
}
@@ -1177,7 +1176,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
IUCV_DBF_TEXT(data, 2,
"EBUSY from netiucv_transmit_skb\n");
} else {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
skb_queue_tail(&conn->collect_queue, skb);
conn->collect_len += l;
rc = 0;
@@ -1201,8 +1200,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
return rc;
} else {
skb_reserve(nskb, NETIUCV_HDRLEN);
- memcpy(skb_put(nskb, skb->len),
- skb->data, skb->len);
+ skb_put_data(nskb, skb->data, skb->len);
}
copied = 1;
}
@@ -1212,7 +1210,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
header.next = nskb->len + NETIUCV_HDRLEN;
memcpy(skb_push(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
header.next = 0;
- memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
+ skb_put_data(nskb, &header, NETIUCV_HDRLEN);
fsm_newstate(conn->fsm, CONN_STATE_TX);
conn->prof.send_stamp = jiffies;
@@ -1247,7 +1245,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
} else {
if (copied)
dev_kfree_skb(skb);
- atomic_inc(&nskb->users);
+ refcount_inc(&nskb->users);
skb_queue_tail(&conn->commit_queue, nskb);
}
}
@@ -2020,8 +2018,8 @@ out_netdev:
return NULL;
}
-static ssize_t conn_write(struct device_driver *drv,
- const char *buf, size_t count)
+static ssize_t connection_store(struct device_driver *drv, const char *buf,
+ size_t count)
{
char username[9];
char userdata[17];
@@ -2082,11 +2080,10 @@ out_free_ndev:
netiucv_free_netdevice(dev);
return rc;
}
+static DRIVER_ATTR_WO(connection);
-static DRIVER_ATTR(connection, 0200, NULL, conn_write);
-
-static ssize_t remove_write (struct device_driver *drv,
- const char *buf, size_t count)
+static ssize_t remove_store(struct device_driver *drv, const char *buf,
+ size_t count)
{
struct iucv_connection *cp;
struct net_device *ndev;
@@ -2132,8 +2129,7 @@ static ssize_t remove_write (struct device_driver *drv,
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
return -EINVAL;
}
-
-static DRIVER_ATTR(remove, 0200, NULL, remove_write);
+static DRIVER_ATTR_WO(remove);
static struct attribute * netiucv_drv_attrs[] = {
&driver_attr_connection.attr,
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 30bc6105aac3..7a0ffc71b25d 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -659,6 +659,7 @@ struct qeth_card_info {
int max_mtu;
int broadcast_capable;
int unique_id;
+ bool layer_enforced;
struct qeth_card_blkt blkt;
enum qeth_ipa_promisc_modes promisc_mode;
__u32 diagass_support;
@@ -696,6 +697,7 @@ struct qeth_osn_info {
};
enum qeth_discipline_id {
+ QETH_DISCIPLINE_UNDETERMINED = -1,
QETH_DISCIPLINE_LAYER3 = 0,
QETH_DISCIPLINE_LAYER2 = 1,
};
@@ -984,6 +986,7 @@ struct qeth_cmd_buffer *qeth_get_setassparms_cmd(struct qeth_card *,
int qeth_set_features(struct net_device *, netdev_features_t);
int qeth_recover_features(struct net_device *);
netdev_features_t qeth_fix_features(struct net_device *, netdev_features_t);
+int qeth_vm_request_mac(struct qeth_card *card);
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index fc6d85f2b38d..4792cabb862e 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -27,6 +27,9 @@
#include <asm/io.h>
#include <asm/sysinfo.h>
#include <asm/compat.h>
+#include <asm/diag.h>
+#include <asm/cio.h>
+#include <asm/ccwdev.h>
#include "qeth_core.h"
@@ -1239,7 +1242,7 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf)
iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR);
}
}
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
skb = skb_dequeue(&buf->skb_list);
}
@@ -1723,6 +1726,25 @@ static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd)
(prcd[0x11] == _ascebc['M']));
}
+/* Determine whether the device requires a specific layer discipline */
+static enum qeth_discipline_id qeth_enforce_discipline(struct qeth_card *card)
+{
+ if (card->info.type == QETH_CARD_TYPE_OSM ||
+ card->info.type == QETH_CARD_TYPE_OSN) {
+ QETH_DBF_TEXT(SETUP, 3, "force l2");
+ return QETH_DISCIPLINE_LAYER2;
+ }
+
+ /* virtual HiperSocket is L3 only: */
+ if (card->info.guestlan && card->info.type == QETH_CARD_TYPE_IQD) {
+ QETH_DBF_TEXT(SETUP, 3, "force l3");
+ return QETH_DISCIPLINE_LAYER3;
+ }
+
+ QETH_DBF_TEXT(SETUP, 3, "force no");
+ return QETH_DISCIPLINE_UNDETERMINED;
+}
+
static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd)
{
QETH_DBF_TEXT(SETUP, 2, "cfgblkt");
@@ -3347,6 +3369,28 @@ static void qeth_handle_send_error(struct qeth_card *card,
(u16)qdio_err, (u8)sbalf15);
}
+/**
+ * qeth_prep_flush_pack_buffer - Prepares flushing of a packing buffer.
+ * @queue: queue to check for packing buffer
+ *
+ * Returns number of buffers that were prepared for flush.
+ */
+static int qeth_prep_flush_pack_buffer(struct qeth_qdio_out_q *queue)
+{
+ struct qeth_qdio_out_buffer *buffer;
+
+ buffer = queue->bufs[queue->next_buf_to_fill];
+ if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
+ (buffer->next_element_to_fill > 0)) {
+ /* it's a packing buffer */
+ atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
+ queue->next_buf_to_fill =
+ (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q;
+ return 1;
+ }
+ return 0;
+}
+
/*
* Switched to packing state if the number of used buffers on a queue
* reaches a certain limit.
@@ -3373,9 +3417,6 @@ static void qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
*/
static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
{
- struct qeth_qdio_out_buffer *buffer;
- int flush_count = 0;
-
if (queue->do_pack) {
if (atomic_read(&queue->used_buffers)
<= QETH_LOW_WATERMARK_PACK) {
@@ -3384,42 +3425,9 @@ static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
if (queue->card->options.performance_stats)
queue->card->perf_stats.sc_p_dp++;
queue->do_pack = 0;
- /* flush packing buffers */
- buffer = queue->bufs[queue->next_buf_to_fill];
- if ((atomic_read(&buffer->state) ==
- QETH_QDIO_BUF_EMPTY) &&
- (buffer->next_element_to_fill > 0)) {
- 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;
- }
+ return qeth_prep_flush_pack_buffer(queue);
}
}
- return flush_count;
-}
-
-
-/*
- * Called to flush a packing buffer if no more pci flags are on the queue.
- * Checks if there is a packing buffer and prepares it to be flushed.
- * In that case returns 1, otherwise zero.
- */
-static int qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
-{
- struct qeth_qdio_out_buffer *buffer;
-
- buffer = queue->bufs[queue->next_buf_to_fill];
- if ((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
- (buffer->next_element_to_fill > 0)) {
- /* it's a packing buffer */
- atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
- queue->next_buf_to_fill =
- (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q;
- return 1;
- }
return 0;
}
@@ -3532,8 +3540,7 @@ static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
flush_cnt += qeth_switch_to_nonpacking_if_needed(queue);
if (!flush_cnt &&
!atomic_read(&queue->set_pci_flags_count))
- flush_cnt +=
- qeth_flush_buffers_on_no_pci(queue);
+ flush_cnt += qeth_prep_flush_pack_buffer(queue);
if (queue->card->options.performance_stats &&
q_was_packing)
queue->card->perf_stats.bufs_sent_pack +=
@@ -3968,7 +3975,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
int flush_cnt = 0, hdr_len, large_send = 0;
buffer = buf->buffer;
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
/*check first on TSO ....*/
@@ -4099,7 +4106,8 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
flush_count);
atomic_set(&queue->state,
QETH_OUT_Q_UNLOCKED);
- return -EBUSY;
+ rc = -EBUSY;
+ goto out;
}
}
}
@@ -4118,19 +4126,21 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
* In that case we will enter this loop
*/
while (atomic_dec_return(&queue->state)) {
- flush_count = 0;
start_index = queue->next_buf_to_fill;
/* check if we can go back to non-packing state */
- flush_count += qeth_switch_to_nonpacking_if_needed(queue);
+ tmp = qeth_switch_to_nonpacking_if_needed(queue);
/*
* check if we need to flush a packing buffer to get a pci
* flag out on the queue
*/
- if (!flush_count && !atomic_read(&queue->set_pci_flags_count))
- flush_count += qeth_flush_buffers_on_no_pci(queue);
- if (flush_count)
- qeth_flush_buffers(queue, start_index, flush_count);
+ if (!tmp && !atomic_read(&queue->set_pci_flags_count))
+ tmp = qeth_prep_flush_pack_buffer(queue);
+ if (tmp) {
+ qeth_flush_buffers(queue, start_index, tmp);
+ flush_count += tmp;
+ }
}
+out:
/* at this point the queue is UNLOCKED again */
if (queue->card->options.performance_stats && do_pack)
queue->card->perf_stats.bufs_sent_pack += flush_count;
@@ -4199,8 +4209,7 @@ int qeth_change_mtu(struct net_device *dev, int new_mtu)
sprintf(dbf_text, "%8x", new_mtu);
QETH_CARD_TEXT(card, 4, dbf_text);
- if ((!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) &&
- (!qeth_mtu_is_valid(card, new_mtu)))
+ if (!qeth_mtu_is_valid(card, new_mtu))
return -EINVAL;
dev->mtu = new_mtu;
return 0;
@@ -4767,6 +4776,64 @@ static int qeth_query_card_info(struct qeth_card *card,
(void *)carrier_info);
}
+/**
+ * qeth_vm_request_mac() - Request a hypervisor-managed MAC address
+ * @card: pointer to a qeth_card
+ *
+ * Returns
+ * 0, if a MAC address has been set for the card's netdevice
+ * a return code, for various error conditions
+ */
+int qeth_vm_request_mac(struct qeth_card *card)
+{
+ struct diag26c_mac_resp *response;
+ struct diag26c_mac_req *request;
+ struct ccw_dev_id id;
+ int rc;
+
+ QETH_DBF_TEXT(SETUP, 2, "vmreqmac");
+
+ if (!card->dev)
+ return -ENODEV;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL | GFP_DMA);
+ response = kzalloc(sizeof(*response), GFP_KERNEL | GFP_DMA);
+ if (!request || !response) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ ccw_device_get_id(CARD_DDEV(card), &id);
+ request->resp_buf_len = sizeof(*response);
+ request->resp_version = DIAG26C_VERSION2;
+ request->op_code = DIAG26C_GET_MAC;
+ request->devno = id.devno;
+
+ rc = diag26c(request, response, DIAG26C_MAC_SERVICES);
+ if (rc)
+ goto out;
+
+ if (request->resp_buf_len < sizeof(*response) ||
+ response->version != request->resp_version) {
+ rc = -EIO;
+ QETH_DBF_TEXT(SETUP, 2, "badresp");
+ QETH_DBF_HEX(SETUP, 2, &request->resp_buf_len,
+ sizeof(request->resp_buf_len));
+ } else if (!is_valid_ether_addr(response->mac)) {
+ rc = -EINVAL;
+ QETH_DBF_TEXT(SETUP, 2, "badmac");
+ QETH_DBF_HEX(SETUP, 2, response->mac, ETH_ALEN);
+ } else {
+ ether_addr_copy(card->dev->dev_addr, response->mac);
+ }
+
+out:
+ kfree(response);
+ kfree(request);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(qeth_vm_request_mac);
+
static inline int qeth_get_qdio_q_format(struct qeth_card *card)
{
if (card->info.type == QETH_CARD_TYPE_IQD)
@@ -5144,12 +5211,11 @@ static inline int qeth_create_skb_frag(struct qeth_qdio_buffer *qethbuffer,
skb_reserve(*pskb, ETH_HLEN);
if (data_len <= QETH_RX_PULL_LEN) {
- memcpy(skb_put(*pskb, data_len), element->addr + offset,
- data_len);
+ skb_put_data(*pskb, element->addr + offset, data_len);
} else {
get_page(page);
- memcpy(skb_put(*pskb, QETH_RX_PULL_LEN),
- element->addr + offset, QETH_RX_PULL_LEN);
+ skb_put_data(*pskb, element->addr + offset,
+ QETH_RX_PULL_LEN);
skb_fill_page_desc(*pskb, *pfrag, page,
offset + QETH_RX_PULL_LEN,
data_len - QETH_RX_PULL_LEN);
@@ -5245,8 +5311,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
&skb, offset, &frag, data_len))
goto no_mem;
} else {
- memcpy(skb_put(skb, data_len), data_ptr,
- data_len);
+ skb_put_data(skb, data_ptr, data_len);
}
}
skb_len -= data_len;
@@ -5501,6 +5566,7 @@ int qeth_core_load_discipline(struct qeth_card *card,
enum qeth_discipline_id discipline)
{
int rc = 0;
+
mutex_lock(&qeth_mod_mutex);
switch (discipline) {
case QETH_DISCIPLINE_LAYER3:
@@ -5511,7 +5577,10 @@ int qeth_core_load_discipline(struct qeth_card *card,
card->discipline = try_then_request_module(
symbol_get(qeth_l2_discipline), "qeth_l2");
break;
+ default:
+ break;
}
+
if (!card->discipline) {
dev_err(&card->gdev->dev, "There is no kernel module to "
"support discipline %d\n", discipline);
@@ -5614,6 +5683,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
struct qeth_card *card;
struct device *dev;
int rc;
+ enum qeth_discipline_id enforced_disc;
unsigned long flags;
char dbf_name[DBF_NAME_LEN];
@@ -5661,10 +5731,15 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
goto err_card;
}
- switch (card->info.type) {
- case QETH_CARD_TYPE_OSN:
- case QETH_CARD_TYPE_OSM:
- rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
+ qeth_determine_capabilities(card);
+ enforced_disc = qeth_enforce_discipline(card);
+ switch (enforced_disc) {
+ case QETH_DISCIPLINE_UNDETERMINED:
+ gdev->dev.type = &qeth_generic_devtype;
+ break;
+ default:
+ card->info.layer_enforced = true;
+ rc = qeth_core_load_discipline(card, enforced_disc);
if (rc)
goto err_card;
@@ -5675,16 +5750,11 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
if (rc)
goto err_disc;
break;
- default:
- gdev->dev.type = &qeth_generic_devtype;
- break;
}
write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
list_add_tail(&card->list, &qeth_core_card_list.list);
write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);
-
- qeth_determine_capabilities(card);
return 0;
err_disc:
@@ -5721,7 +5791,7 @@ static int qeth_core_set_online(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
int rc = 0;
- int def_discipline;
+ enum qeth_discipline_id def_discipline;
if (!card->discipline) {
if (card->info.type == QETH_CARD_TYPE_IQD)
@@ -5800,8 +5870,8 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
.restore = qeth_core_restore,
};
-static ssize_t qeth_core_driver_group_store(struct device_driver *ddrv,
- const char *buf, size_t count)
+static ssize_t group_store(struct device_driver *ddrv, const char *buf,
+ size_t count)
{
int err;
@@ -5810,7 +5880,7 @@ static ssize_t qeth_core_driver_group_store(struct device_driver *ddrv,
return err ? err : count;
}
-static DRIVER_ATTR(group, 0200, NULL, qeth_core_driver_group_store);
+static DRIVER_ATTR_WO(group);
static struct attribute *qeth_drv_attrs[] = {
&driver_attr_group.attr,
@@ -6406,11 +6476,8 @@ netdev_features_t qeth_fix_features(struct net_device *dev,
features &= ~NETIF_F_IP_CSUM;
if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
features &= ~NETIF_F_RXCSUM;
- if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
+ if (!qeth_is_supported(card, IPA_OUTBOUND_TSO))
features &= ~NETIF_F_TSO;
- dev_info(&card->gdev->dev, "Outbound TSO not supported on %s\n",
- QETH_CARD_IFNAME(card));
- }
/* if the card isn't up, remove features that require hw changes */
if (card->state == CARD_STATE_DOWN ||
card->state == CARD_STATE_RECOVER)
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c
index beb4bdc26de5..6dd7d05e5693 100644
--- a/drivers/s390/net/qeth_core_mpc.c
+++ b/drivers/s390/net/qeth_core_mpc.c
@@ -167,13 +167,21 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
{IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"},
{IPA_RC_UNKNOWN_ERROR, "IPA command failed - reason unknown"},
{IPA_RC_UNSUPPORTED_COMMAND, "Command not supported"},
+ {IPA_RC_TRACE_ALREADY_ACTIVE, "trace already active"},
+ {IPA_RC_INVALID_FORMAT, "invalid format or length"},
{IPA_RC_DUP_IPV6_REMOTE, "ipv6 address already registered remote"},
+ {IPA_RC_SBP_IQD_NOT_CONFIGURED, "Not configured for bridgeport"},
{IPA_RC_DUP_IPV6_HOME, "ipv6 address already registered"},
{IPA_RC_UNREGISTERED_ADDR, "Address not registered"},
{IPA_RC_NO_ID_AVAILABLE, "No identifiers available"},
{IPA_RC_ID_NOT_FOUND, "Identifier not found"},
+ {IPA_RC_SBP_IQD_ANO_DEV_PRIMARY, "Primary bridgeport exists already"},
+ {IPA_RC_SBP_IQD_CURRENT_SECOND, "Bridgeport is currently secondary"},
+ {IPA_RC_SBP_IQD_LIMIT_SECOND, "Limit of secondary bridgeports reached"},
{IPA_RC_INVALID_IP_VERSION, "IP version incorrect"},
+ {IPA_RC_SBP_IQD_CURRENT_PRIMARY, "Bridgeport is currently primary"},
{IPA_RC_LAN_FRAME_MISMATCH, "LAN and frame mismatch"},
+ {IPA_RC_SBP_IQD_NO_QDIO_QUEUES, "QDIO queues not established"},
{IPA_RC_L2_UNSUPPORTED_CMD, "Unsupported layer 2 command"},
{IPA_RC_L2_DUP_MAC, "Duplicate MAC address"},
{IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"},
@@ -185,6 +193,14 @@ static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
{IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"},
{IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"},
{IPA_RC_L2_VLAN_ID_NOT_FOUND, "L2 vlan id not found"},
+ {IPA_RC_SBP_OSA_NOT_CONFIGURED, "Not configured for bridgeport"},
+ {IPA_RC_SBP_OSA_OS_MISMATCH, "OS mismatch"},
+ {IPA_RC_SBP_OSA_ANO_DEV_PRIMARY, "Primary bridgeport exists already"},
+ {IPA_RC_SBP_OSA_CURRENT_SECOND, "Bridgeport is currently secondary"},
+ {IPA_RC_SBP_OSA_LIMIT_SECOND, "Limit of secondary bridgeports reached"},
+ {IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN, "Not authorized by zManager"},
+ {IPA_RC_SBP_OSA_CURRENT_PRIMARY, "Bridgeport is currently primary"},
+ {IPA_RC_SBP_OSA_NO_QDIO_QUEUES, "QDIO queues not established"},
{IPA_RC_DATA_MISMATCH, "Data field mismatch (v4/v6 mixed)"},
{IPA_RC_INVALID_MTU_SIZE, "Invalid MTU size"},
{IPA_RC_INVALID_LANTYPE, "Invalid LAN type"},
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 4accb0a61ce0..912e0107de8f 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -142,12 +142,18 @@ enum qeth_ipa_return_codes {
IPA_RC_TRACE_ALREADY_ACTIVE = 0x0005,
IPA_RC_INVALID_FORMAT = 0x0006,
IPA_RC_DUP_IPV6_REMOTE = 0x0008,
+ IPA_RC_SBP_IQD_NOT_CONFIGURED = 0x000C,
IPA_RC_DUP_IPV6_HOME = 0x0010,
IPA_RC_UNREGISTERED_ADDR = 0x0011,
IPA_RC_NO_ID_AVAILABLE = 0x0012,
IPA_RC_ID_NOT_FOUND = 0x0013,
+ IPA_RC_SBP_IQD_ANO_DEV_PRIMARY = 0x0014,
+ IPA_RC_SBP_IQD_CURRENT_SECOND = 0x0018,
+ IPA_RC_SBP_IQD_LIMIT_SECOND = 0x001C,
IPA_RC_INVALID_IP_VERSION = 0x0020,
+ IPA_RC_SBP_IQD_CURRENT_PRIMARY = 0x0024,
IPA_RC_LAN_FRAME_MISMATCH = 0x0040,
+ IPA_RC_SBP_IQD_NO_QDIO_QUEUES = 0x00EB,
IPA_RC_L2_UNSUPPORTED_CMD = 0x2003,
IPA_RC_L2_DUP_MAC = 0x2005,
IPA_RC_L2_ADDR_TABLE_FULL = 0x2006,
@@ -159,6 +165,14 @@ enum qeth_ipa_return_codes {
IPA_RC_L2_INVALID_VLAN_ID = 0x2015,
IPA_RC_L2_DUP_VLAN_ID = 0x2016,
IPA_RC_L2_VLAN_ID_NOT_FOUND = 0x2017,
+ IPA_RC_SBP_OSA_NOT_CONFIGURED = 0x2B0C,
+ IPA_RC_SBP_OSA_OS_MISMATCH = 0x2B10,
+ IPA_RC_SBP_OSA_ANO_DEV_PRIMARY = 0x2B14,
+ IPA_RC_SBP_OSA_CURRENT_SECOND = 0x2B18,
+ IPA_RC_SBP_OSA_LIMIT_SECOND = 0x2B1C,
+ IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN = 0x2B20,
+ IPA_RC_SBP_OSA_CURRENT_PRIMARY = 0x2B24,
+ IPA_RC_SBP_OSA_NO_QDIO_QUEUES = 0x2BEB,
IPA_RC_DATA_MISMATCH = 0xe001,
IPA_RC_INVALID_MTU_SIZE = 0xe002,
IPA_RC_INVALID_LANTYPE = 0xe003,
@@ -187,12 +201,16 @@ enum qeth_ipa_return_codes {
#define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL
#define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR
+/* for SETBRIDGEPORT (double occupancies) */
+#define IPA_RC_SBP_IQD_OS_MISMATCH IPA_RC_DUP_IPV6_HOME
+#define IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN IPA_RC_INVALID_IP_VERSION
+
/* IPA function flags; each flag marks availability of respective function */
enum qeth_ipa_funcs {
IPA_ARP_PROCESSING = 0x00000001L,
IPA_INBOUND_CHECKSUM = 0x00000002L,
IPA_OUTBOUND_CHECKSUM = 0x00000004L,
- IPA_IP_FRAGMENTATION = 0x00000008L,
+ /* RESERVED = 0x00000008L,*/
IPA_FILTERING = 0x00000010L,
IPA_IPV6 = 0x00000020L,
IPA_MULTICASTING = 0x00000040L,
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index db6a285d41e0..6d255c22656d 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -413,7 +413,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
if (card->options.layer2 == newdis)
goto out;
- if (card->info.type == QETH_CARD_TYPE_OSM) {
+ if (card->info.layer_enforced) {
/* fixed layer, can't switch */
rc = -EOPNOTSUPP;
goto out;
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index bd2df62a5cdf..ad110abfdd47 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -21,6 +21,7 @@
#include <linux/hash.h>
#include <linux/hashtable.h>
#include <linux/string.h>
+#include <asm/setup.h>
#include "qeth_core.h"
#include "qeth_l2.h"
@@ -505,9 +506,19 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
int rc = 0;
char vendor_pre[] = {0x02, 0x00, 0x00};
- QETH_DBF_TEXT(SETUP, 2, "doL2init");
+ QETH_DBF_TEXT(SETUP, 2, "l2reqmac");
QETH_DBF_TEXT_(SETUP, 2, "doL2%s", CARD_BUS_ID(card));
+ if (MACHINE_IS_VM) {
+ rc = qeth_vm_request_mac(card);
+ if (!rc)
+ goto out;
+ QETH_DBF_MESSAGE(2, "z/VM MAC Service failed on device %s: x%x\n",
+ CARD_BUS_ID(card), rc);
+ QETH_DBF_TEXT_(SETUP, 2, "err%04x", rc);
+ /* fall back to alternative mechanism: */
+ }
+
if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) {
rc = qeth_query_setadapterparms(card);
if (rc) {
@@ -528,11 +539,12 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
QETH_DBF_TEXT_(SETUP, 2, "1err%04x", rc);
return rc;
}
- QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, OSA_ADDR_LEN);
} else {
eth_random_addr(card->dev->dev_addr);
memcpy(card->dev->dev_addr, vendor_pre, 3);
}
+out:
+ QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, card->dev->addr_len);
return 0;
}
@@ -759,8 +771,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb,
sizeof(struct qeth_hdr));
if (!new_skb)
goto tx_drop;
- hdr = (struct qeth_hdr *)skb_push(new_skb,
- sizeof(struct qeth_hdr));
+ hdr = skb_push(new_skb, sizeof(struct qeth_hdr));
skb_set_mac_header(new_skb, sizeof(struct qeth_hdr));
qeth_l2_fill_header(card, hdr, new_skb, cast_type);
if (new_skb->ip_summed == CHECKSUM_PARTIAL)
@@ -1017,6 +1028,13 @@ static int qeth_l2_start_ipassists(struct qeth_card *card)
return 0;
}
+static void qeth_l2_trace_features(struct qeth_card *card)
+{
+ QETH_CARD_TEXT(card, 2, "l2featur");
+ QETH_CARD_HEX(card, 2, &card->options.sbp.supported_funcs,
+ sizeof(card->options.sbp.supported_funcs));
+}
+
static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
@@ -1040,6 +1058,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
dev_info(&card->gdev->dev,
"The device represents a Bridge Capable Port\n");
qeth_trace_features(card);
+ qeth_l2_trace_features(card);
if (!card->dev && qeth_l2_setup_netdev(card)) {
rc = -ENODEV;
@@ -1643,27 +1662,27 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
if ((is_iqd && (cbctl->ipa_rc == IPA_RC_SUCCESS)) ||
(!is_iqd && (cbctl->ipa_rc == cbctl->cmd_rc)))
switch (cbctl->cmd_rc) {
- case 0x0000:
+ case IPA_RC_SUCCESS:
rc = 0;
break;
- case 0x2B04:
- case 0x0004:
+ case IPA_RC_L2_UNSUPPORTED_CMD:
+ case IPA_RC_UNSUPPORTED_COMMAND:
rc = -EOPNOTSUPP;
break;
- case 0x2B0C:
- case 0x000C: /* Not configured as bridge Port */
+ case IPA_RC_SBP_OSA_NOT_CONFIGURED:
+ case IPA_RC_SBP_IQD_NOT_CONFIGURED:
rc = -ENODEV; /* maybe not the best code here? */
dev_err(&card->gdev->dev,
"The device is not configured as a Bridge Port\n");
break;
- case 0x2B10:
- case 0x0010: /* OS mismatch */
+ case IPA_RC_SBP_OSA_OS_MISMATCH:
+ case IPA_RC_SBP_IQD_OS_MISMATCH:
rc = -EPERM;
dev_err(&card->gdev->dev,
"A Bridge Port is already configured by a different operating system\n");
break;
- case 0x2B14:
- case 0x0014: /* Another device is Primary */
+ case IPA_RC_SBP_OSA_ANO_DEV_PRIMARY:
+ case IPA_RC_SBP_IQD_ANO_DEV_PRIMARY:
switch (setcmd) {
case IPA_SBP_SET_PRIMARY_BRIDGE_PORT:
rc = -EEXIST;
@@ -1679,26 +1698,26 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
rc = -EIO;
}
break;
- case 0x2B18:
- case 0x0018: /* This device is currently Secondary */
+ case IPA_RC_SBP_OSA_CURRENT_SECOND:
+ case IPA_RC_SBP_IQD_CURRENT_SECOND:
rc = -EBUSY;
dev_err(&card->gdev->dev,
"The device is already a secondary Bridge Port\n");
break;
- case 0x2B1C:
- case 0x001C: /* Limit for Secondary devices reached */
+ case IPA_RC_SBP_OSA_LIMIT_SECOND:
+ case IPA_RC_SBP_IQD_LIMIT_SECOND:
rc = -EEXIST;
dev_err(&card->gdev->dev,
"The LAN cannot have more secondary Bridge Ports\n");
break;
- case 0x2B24:
- case 0x0024: /* This device is currently Primary */
+ case IPA_RC_SBP_OSA_CURRENT_PRIMARY:
+ case IPA_RC_SBP_IQD_CURRENT_PRIMARY:
rc = -EBUSY;
dev_err(&card->gdev->dev,
"The device is already a primary Bridge Port\n");
break;
- case 0x2B20:
- case 0x0020: /* Not authorized by zManager */
+ case IPA_RC_SBP_OSA_NOT_AUTHD_BY_ZMAN:
+ case IPA_RC_SBP_IQD_NOT_AUTHD_BY_ZMAN:
rc = -EACCES;
dev_err(&card->gdev->dev,
"The device is not authorized to be a Bridge Port\n");
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 26f79533e62e..9b5e439f18cf 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -65,6 +65,7 @@ struct qeth_ipato_entry {
int mask_bits;
};
+extern const struct attribute_group *qeth_l3_attr_groups[];
void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *);
int qeth_l3_string_to_ipaddr(const char *, enum qeth_prot_versions, __u8 *);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index d8df1e635163..3062cde33a3d 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -956,31 +956,6 @@ static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card)
return rc;
}
-static int qeth_l3_start_ipa_ip_fragmentation(struct qeth_card *card)
-{
- int rc;
-
- QETH_CARD_TEXT(card, 3, "ipaipfrg");
-
- if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) {
- dev_info(&card->gdev->dev,
- "Hardware IP fragmentation not supported on %s\n",
- QETH_CARD_IFNAME(card));
- return -EOPNOTSUPP;
- }
-
- rc = qeth_send_simple_setassparms(card, IPA_IP_FRAGMENTATION,
- IPA_CMD_ASS_START, 0);
- if (rc) {
- dev_warn(&card->gdev->dev,
- "Starting IP fragmentation support for %s failed\n",
- QETH_CARD_IFNAME(card));
- } else
- dev_info(&card->gdev->dev,
- "Hardware IP fragmentation enabled \n");
- return rc;
-}
-
static int qeth_l3_start_ipa_source_mac(struct qeth_card *card)
{
int rc;
@@ -1060,9 +1035,6 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
QETH_CARD_TEXT(card, 3, "softipv6");
- if (card->info.type == QETH_CARD_TYPE_IQD)
- goto out;
-
rc = qeth_query_ipassists(card, QETH_PROT_IPV6);
if (rc) {
dev_err(&card->gdev->dev,
@@ -1070,6 +1042,10 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
QETH_CARD_IFNAME(card));
return rc;
}
+
+ if (card->info.type == QETH_CARD_TYPE_IQD)
+ goto out;
+
rc = qeth_send_simple_setassparms(card, IPA_IPV6,
IPA_CMD_ASS_START, 3);
if (rc) {
@@ -1171,7 +1147,6 @@ static int qeth_l3_start_ipassists(struct qeth_card *card)
if (qeth_set_access_ctrl_online(card, 0))
return -EIO;
qeth_l3_start_ipa_arp_processing(card); /* go on*/
- qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/
qeth_l3_start_ipa_source_mac(card); /* go on*/
qeth_l3_start_ipa_vlan(card); /* go on*/
qeth_l3_start_ipa_multicast(card); /* go on*/
@@ -2702,8 +2677,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
use_tso = skb_is_gso(skb) &&
(qeth_get_ip_protocol(skb) == IPPROTO_TCP) && (ipv == 4);
- if ((card->info.type == QETH_CARD_TYPE_IQD) &&
- !skb_is_nonlinear(skb)) {
+ if (card->info.type == QETH_CARD_TYPE_IQD) {
new_skb = skb;
data_offset = ETH_HLEN;
hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC);
@@ -2716,12 +2690,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
+ VLAN_HLEN);
if (!new_skb)
goto tx_drop;
- }
- if (card->info.type == QETH_CARD_TYPE_IQD) {
- if (data_offset < 0)
- skb_pull(new_skb, ETH_HLEN);
- } else {
if (ipv == 4) {
skb_pull(new_skb, ETH_HLEN);
}
@@ -2760,16 +2729,14 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
}
if (use_tso) {
- hdr = (struct qeth_hdr *)skb_push(new_skb,
- sizeof(struct qeth_hdr_tso));
+ hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso));
memset(hdr, 0, sizeof(struct qeth_hdr_tso));
qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type);
qeth_tso_fill_header(card, hdr, new_skb);
hdr_elements++;
} else {
if (data_offset < 0) {
- hdr = (struct qeth_hdr *)skb_push(new_skb,
- sizeof(struct qeth_hdr));
+ hdr = skb_push(new_skb, sizeof(struct qeth_hdr));
qeth_l3_fill_header(card, hdr, new_skb, ipv,
cast_type);
} else {
@@ -3036,14 +3003,21 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
return register_netdev(card->dev);
}
+static const struct device_type qeth_l3_devtype = {
+ .name = "qeth_layer3",
+ .groups = qeth_l3_attr_groups,
+};
+
static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
int rc;
- rc = qeth_l3_create_device_attributes(&gdev->dev);
- if (rc)
- return rc;
+ if (gdev->dev.type == &qeth_generic_devtype) {
+ rc = qeth_l3_create_device_attributes(&gdev->dev);
+ if (rc)
+ return rc;
+ }
hash_init(card->ip_htable);
hash_init(card->ip_mc_htable);
card->options.layer2 = 0;
@@ -3055,7 +3029,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
{
struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
- qeth_l3_remove_device_attributes(&cgdev->dev);
+ if (cgdev->dev.type == &qeth_generic_devtype)
+ qeth_l3_remove_device_attributes(&cgdev->dev);
qeth_set_allowed_threads(card, 0, 1);
wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
@@ -3311,7 +3286,7 @@ static int qeth_l3_control_event(struct qeth_card *card,
}
struct qeth_discipline qeth_l3_discipline = {
- .devtype = &qeth_generic_devtype,
+ .devtype = &qeth_l3_devtype,
.start_poll = qeth_qdio_start_poll,
.input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
.output_handler = (qdio_handler_t *) qeth_qdio_output_handler,
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index ff29a4b416b4..f2f94f59e0fa 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -1049,3 +1049,14 @@ void qeth_l3_remove_device_attributes(struct device *dev)
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
}
+
+const struct attribute_group *qeth_l3_attr_groups[] = {
+ &qeth_device_attr_group,
+ &qeth_device_blkt_group,
+ /* l3 specific, see l3_{create,remove}_device_attributes(): */
+ &qeth_l3_device_attr_group,
+ &qeth_device_ipato_group,
+ &qeth_device_vipa_group,
+ &qeth_device_rxip_group,
+NULL,
+};