summaryrefslogtreecommitdiff
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c5
-rw-r--r--drivers/s390/block/dasd_3990_erp.c10
-rw-r--r--drivers/s390/block/dasd_alias.c6
-rw-r--r--drivers/s390/block/dasd_eckd.c104
-rw-r--r--drivers/s390/block/dasd_eer.c2
-rw-r--r--drivers/s390/block/dasd_fba.c14
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/s390/char/Kconfig11
-rw-r--r--drivers/s390/char/Makefile4
-rw-r--r--drivers/s390/char/con3215.c4
-rw-r--r--drivers/s390/char/con3270.c2331
-rw-r--r--drivers/s390/char/diag_ftp.c4
-rw-r--r--drivers/s390/char/fs3270.c124
-rw-r--r--drivers/s390/char/raw3270.c376
-rw-r--r--drivers/s390/char/raw3270.h227
-rw-r--r--drivers/s390/char/sclp_early.c2
-rw-r--r--drivers/s390/char/sclp_ftp.c6
-rw-r--r--drivers/s390/char/tty3270.c1963
-rw-r--r--drivers/s390/char/tty3270.h15
-rw-r--r--drivers/s390/cio/css.c25
-rw-r--r--drivers/s390/cio/css.h2
-rw-r--r--drivers/s390/cio/device.c17
-rw-r--r--drivers/s390/cio/scm.c2
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.c365
-rw-r--r--drivers/s390/cio/vfio_ccw_cp.h3
-rw-r--r--drivers/s390/cio/vfio_ccw_drv.c2
-rw-r--r--drivers/s390/cio/vfio_ccw_fsm.c2
-rw-r--r--drivers/s390/crypto/ap_bus.c4
-rw-r--r--drivers/s390/crypto/vfio_ap_ops.c116
-rw-r--r--drivers/s390/crypto/zcrypt_api.c6
-rw-r--r--drivers/s390/net/ctcm_fsms.c32
-rw-r--r--drivers/s390/net/ctcm_main.c16
-rw-r--r--drivers/s390/net/ctcm_mpc.c15
-rw-r--r--drivers/s390/net/ism.h19
-rw-r--r--drivers/s390/net/ism_drv.c376
-rw-r--r--drivers/s390/net/qeth_core_main.c14
-rw-r--r--drivers/s390/net/qeth_core_sys.c78
-rw-r--r--drivers/s390/net/qeth_ethtool.c6
-rw-r--r--drivers/s390/net/qeth_l2_main.c53
-rw-r--r--drivers/s390/net/qeth_l2_sys.c28
-rw-r--r--drivers/s390/net/qeth_l3_main.c7
-rw-r--r--drivers/s390/net/qeth_l3_sys.c83
-rw-r--r--drivers/s390/virtio/virtio_ccw.c46
43 files changed, 3119 insertions, 3408 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 5a6d9c15395f..a9c2a8d76c45 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -3978,7 +3978,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
ccw = cqr->cpaddr;
ccw->cmd_code = CCW_CMD_RDC;
- ccw->cda = (__u32)(addr_t) cqr->data;
+ ccw->cda = (__u32)virt_to_phys(cqr->data);
ccw->flags = 0;
ccw->count = rdc_buffer_size;
cqr->startdev = device;
@@ -4022,8 +4022,7 @@ char *dasd_get_sense(struct irb *irb)
if (scsw_is_tm(&irb->scsw) && (irb->scsw.tm.fcxs == 0x01)) {
if (irb->scsw.tm.tcw)
- tsb = tcw_get_tsb((struct tcw *)(unsigned long)
- irb->scsw.tm.tcw);
+ tsb = tcw_get_tsb(phys_to_virt(irb->scsw.tm.tcw));
if (tsb && tsb->length == 64 && tsb->flags)
switch (tsb->flags & 0x07) {
case 1: /* tsa_iostat */
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 81d283b3cd3b..9fd36c468706 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -220,7 +220,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
memset(ccw, 0, sizeof(struct ccw1));
ccw->cmd_code = CCW_CMD_DCTL;
ccw->count = 4;
- ccw->cda = (__u32)(addr_t) DCTL_data;
+ ccw->cda = (__u32)virt_to_phys(DCTL_data);
dctl_cqr->flags = erp->flags;
dctl_cqr->function = dasd_3990_erp_DCTL;
dctl_cqr->refers = erp;
@@ -1714,7 +1714,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
ccw->flags = CCW_FLAG_CC;
ccw->count = 16;
- ccw->cda = (__u32)(addr_t) DE_data;
+ ccw->cda = (__u32)virt_to_phys(DE_data);
/* create LO ccw */
ccw++;
@@ -1722,7 +1722,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
ccw->flags = CCW_FLAG_CC;
ccw->count = 16;
- ccw->cda = (__u32)(addr_t) LO_data;
+ ccw->cda = (__u32)virt_to_phys(LO_data);
/* TIC to the failed ccw */
ccw++;
@@ -2419,7 +2419,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
tcw = erp->cpaddr;
tsb = (struct tsb *) &tcw[1];
*tcw = *((struct tcw *)cqr->cpaddr);
- tcw->tsb = (long)tsb;
+ tcw->tsb = virt_to_phys(tsb);
} else if (ccw->cmd_code == DASD_ECKD_CCW_PSF) {
/* PSF cannot be chained from NOOP/TIC */
erp->cpaddr = cqr->cpaddr;
@@ -2430,7 +2430,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
ccw->flags = CCW_FLAG_CC;
ccw++;
ccw->cmd_code = CCW_CMD_TIC;
- ccw->cda = (long)(cqr->cpaddr);
+ ccw->cda = (__u32)virt_to_phys(cqr->cpaddr);
}
erp->flags = cqr->flags;
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index b6b938aa6615..c9740ae88d1a 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -443,7 +443,7 @@ static int read_unit_address_configuration(struct dasd_device *device,
ccw->cmd_code = DASD_ECKD_CCW_PSF;
ccw->count = sizeof(struct dasd_psf_prssd_data);
ccw->flags |= CCW_FLAG_CC;
- ccw->cda = (__u32)(addr_t) prssdp;
+ ccw->cda = (__u32)virt_to_phys(prssdp);
/* Read Subsystem Data - feature codes */
memset(lcu->uac, 0, sizeof(*(lcu->uac)));
@@ -451,7 +451,7 @@ static int read_unit_address_configuration(struct dasd_device *device,
ccw++;
ccw->cmd_code = DASD_ECKD_CCW_RSSD;
ccw->count = sizeof(*(lcu->uac));
- ccw->cda = (__u32)(addr_t) lcu->uac;
+ ccw->cda = (__u32)virt_to_phys(lcu->uac);
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
@@ -747,7 +747,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu,
ccw->cmd_code = DASD_ECKD_CCW_RSCK;
ccw->flags = CCW_FLAG_SLI;
ccw->count = 16;
- ccw->cda = (__u32)(addr_t) cqr->data;
+ ccw->cda = (__u32)virt_to_phys(cqr->data);
((char *)cqr->data)[0] = reason;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 5d0b9991e91a..1a69f97e88fb 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -288,7 +288,7 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
ccw->flags = 0;
ccw->count = 16;
- ccw->cda = (__u32)__pa(data);
+ ccw->cda = (__u32)virt_to_phys(data);
}
memset(data, 0, sizeof(struct DE_eckd_data));
@@ -398,7 +398,7 @@ static void locate_record_ext(struct ccw1 *ccw, struct LRE_eckd_data *data,
ccw->count = 22;
else
ccw->count = 20;
- ccw->cda = (__u32)__pa(data);
+ ccw->cda = (__u32)virt_to_phys(data);
}
memset(data, 0, sizeof(*data));
@@ -544,11 +544,11 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
ccw->flags = 0;
if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK) {
ccw->count = sizeof(*pfxdata) + 2;
- ccw->cda = (__u32) __pa(pfxdata);
+ ccw->cda = (__u32)virt_to_phys(pfxdata);
memset(pfxdata, 0, sizeof(*pfxdata) + 2);
} else {
ccw->count = sizeof(*pfxdata);
- ccw->cda = (__u32) __pa(pfxdata);
+ ccw->cda = (__u32)virt_to_phys(pfxdata);
memset(pfxdata, 0, sizeof(*pfxdata));
}
@@ -615,7 +615,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, unsigned int trk,
ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
ccw->flags = 0;
ccw->count = 16;
- ccw->cda = (__u32) __pa(data);
+ ccw->cda = (__u32)virt_to_phys(data);
memset(data, 0, sizeof(struct LO_eckd_data));
sector = 0;
@@ -830,7 +830,7 @@ static void dasd_eckd_fill_rcd_cqr(struct dasd_device *device,
ccw = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_RCD;
ccw->flags = 0;
- ccw->cda = (__u32)(addr_t)rcd_buffer;
+ ccw->cda = (__u32)virt_to_phys(rcd_buffer);
ccw->count = DASD_ECKD_RCD_DATA_SIZE;
cqr->magic = DASD_ECKD_MAGIC;
@@ -858,7 +858,7 @@ static void read_conf_cb(struct dasd_ccw_req *cqr, void *data)
if (cqr->status != DASD_CQR_DONE) {
ccw = cqr->cpaddr;
- rcd_buffer = (__u8 *)((addr_t) ccw->cda);
+ rcd_buffer = phys_to_virt(ccw->cda);
memset(rcd_buffer, 0, sizeof(*rcd_buffer));
rcd_buffer[0] = 0xE5;
@@ -1547,7 +1547,7 @@ static int dasd_eckd_read_features(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_PSF;
ccw->count = sizeof(struct dasd_psf_prssd_data);
ccw->flags |= CCW_FLAG_CC;
- ccw->cda = (__u32)(addr_t) prssdp;
+ ccw->cda = (__u32)virt_to_phys(prssdp);
/* Read Subsystem Data - feature codes */
features = (struct dasd_rssd_features *) (prssdp + 1);
@@ -1556,7 +1556,7 @@ static int dasd_eckd_read_features(struct dasd_device *device)
ccw++;
ccw->cmd_code = DASD_ECKD_CCW_RSSD;
ccw->count = sizeof(struct dasd_rssd_features);
- ccw->cda = (__u32)(addr_t) features;
+ ccw->cda = (__u32)virt_to_phys(features);
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1616,7 +1616,7 @@ static int dasd_eckd_read_vol_info(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_PSF;
ccw->count = sizeof(*prssdp);
ccw->flags |= CCW_FLAG_CC;
- ccw->cda = (__u32)(addr_t)prssdp;
+ ccw->cda = (__u32)virt_to_phys(prssdp);
/* Read Subsystem Data - Volume Storage Query */
vsq = (struct dasd_rssd_vsq *)(prssdp + 1);
@@ -1626,7 +1626,7 @@ static int dasd_eckd_read_vol_info(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_RSSD;
ccw->count = sizeof(*vsq);
ccw->flags |= CCW_FLAG_SLI;
- ccw->cda = (__u32)(addr_t)vsq;
+ ccw->cda = (__u32)virt_to_phys(vsq);
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1801,7 +1801,7 @@ static int dasd_eckd_read_ext_pool_info(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_PSF;
ccw->count = sizeof(*prssdp);
ccw->flags |= CCW_FLAG_CC;
- ccw->cda = (__u32)(addr_t)prssdp;
+ ccw->cda = (__u32)virt_to_phys(prssdp);
lcq = (struct dasd_rssd_lcq *)(prssdp + 1);
memset(lcq, 0, sizeof(*lcq));
@@ -1810,7 +1810,7 @@ static int dasd_eckd_read_ext_pool_info(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_RSSD;
ccw->count = sizeof(*lcq);
ccw->flags |= CCW_FLAG_SLI;
- ccw->cda = (__u32)(addr_t)lcq;
+ ccw->cda = (__u32)virt_to_phys(lcq);
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1907,7 +1907,7 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device,
}
ccw = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_PSF;
- ccw->cda = (__u32)(addr_t)psf_ssc_data;
+ ccw->cda = (__u32)virt_to_phys(psf_ssc_data);
ccw->count = 66;
cqr->startdev = device;
@@ -2262,7 +2262,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
ccw->flags = 0;
ccw->count = 8;
- ccw->cda = (__u32)(addr_t) count_data;
+ ccw->cda = (__u32)virt_to_phys(count_data);
ccw++;
count_data++;
}
@@ -2276,7 +2276,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
ccw->flags = 0;
ccw->count = 8;
- ccw->cda = (__u32)(addr_t) count_data;
+ ccw->cda = (__u32)virt_to_phys(count_data);
cqr->block = NULL;
cqr->startdev = device;
@@ -2647,7 +2647,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
ccw->flags = CCW_FLAG_SLI;
ccw->count = 8;
- ccw->cda = (__u32)(addr_t) fmt_buffer;
+ ccw->cda = (__u32)virt_to_phys(fmt_buffer);
ccw++;
fmt_buffer++;
}
@@ -2857,7 +2857,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
ccw->flags = CCW_FLAG_SLI;
ccw->count = 8;
- ccw->cda = (__u32)(addr_t) ect;
+ ccw->cda = (__u32)virt_to_phys(ect);
ccw++;
}
if ((intensity & ~0x08) & 0x04) { /* erase track */
@@ -2872,7 +2872,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
ccw->flags = CCW_FLAG_SLI;
ccw->count = 8;
- ccw->cda = (__u32)(addr_t) ect;
+ ccw->cda = (__u32)virt_to_phys(ect);
} else { /* write remaining records */
for (i = 0; i < rpt; i++) {
ect = (struct eckd_count *) data;
@@ -2907,7 +2907,7 @@ dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
DASD_ECKD_CCW_WRITE_CKD_MT;
ccw->flags = CCW_FLAG_SLI;
ccw->count = 8;
- ccw->cda = (__u32)(addr_t) ect;
+ ccw->cda = (__u32)virt_to_phys(ect);
ccw++;
}
}
@@ -3821,7 +3821,7 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block,
}
ccw = cqr->cpaddr;
- ccw->cda = (__u32)(addr_t)cqr->data;
+ ccw->cda = (__u32)virt_to_phys(cqr->data);
ccw->cmd_code = DASD_ECKD_CCW_DSO;
ccw->count = size;
@@ -4090,11 +4090,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
ccw->cmd_code = rcmd;
ccw->count = count;
if (idal_is_needed(dst, blksize)) {
- ccw->cda = (__u32)(addr_t) idaws;
+ ccw->cda = (__u32)virt_to_phys(idaws);
ccw->flags = CCW_FLAG_IDA;
idaws = idal_create_words(idaws, dst, blksize);
} else {
- ccw->cda = (__u32)(addr_t) dst;
+ ccw->cda = (__u32)virt_to_phys(dst);
ccw->flags = 0;
}
ccw++;
@@ -4228,7 +4228,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
ccw[-1].flags |= CCW_FLAG_CC;
ccw->cmd_code = cmd;
ccw->count = len_to_track_end;
- ccw->cda = (__u32)(addr_t)idaws;
+ ccw->cda = (__u32)virt_to_phys(idaws);
ccw->flags = CCW_FLAG_IDA;
ccw++;
recid += count;
@@ -4244,7 +4244,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
* idaw ends
*/
if (!idaw_dst) {
- if (__pa(dst) & (IDA_BLOCK_SIZE-1)) {
+ if ((__u32)virt_to_phys(dst) & (IDA_BLOCK_SIZE - 1)) {
dasd_sfree_request(cqr, startdev);
return ERR_PTR(-ERANGE);
} else
@@ -4264,7 +4264,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
* idal_create_words will handle cases where idaw_len
* is larger then IDA_BLOCK_SIZE
*/
- if (!(__pa(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE-1)))
+ if (!((__u32)virt_to_phys(idaw_dst + idaw_len) & (IDA_BLOCK_SIZE - 1)))
end_idaw = 1;
/* We also need to end the idaw at track end */
if (!len_to_track_end) {
@@ -4817,7 +4817,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
ccw->count = 57326;
/* 64k map to one track */
len_to_track_end = 65536 - start_padding_sectors * 512;
- ccw->cda = (__u32)(addr_t)idaws;
+ ccw->cda = (__u32)virt_to_phys(idaws);
ccw->flags |= CCW_FLAG_IDA;
ccw->flags |= CCW_FLAG_SLI;
ccw++;
@@ -4836,7 +4836,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
ccw->count = 57326;
/* 64k map to one track */
len_to_track_end = 65536;
- ccw->cda = (__u32)(addr_t)idaws;
+ ccw->cda = (__u32)virt_to_phys(idaws);
ccw->flags |= CCW_FLAG_IDA;
ccw->flags |= CCW_FLAG_SLI;
ccw++;
@@ -4893,9 +4893,9 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
ccw++;
if (dst) {
if (ccw->flags & CCW_FLAG_IDA)
- cda = *((char **)((addr_t) ccw->cda));
+ cda = *((char **)phys_to_virt(ccw->cda));
else
- cda = (char *)((addr_t) ccw->cda);
+ cda = phys_to_virt(ccw->cda);
if (dst != cda) {
if (rq_data_dir(req) == READ)
memcpy(dst, cda, bv.bv_len);
@@ -5045,7 +5045,7 @@ dasd_eckd_release(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_RELEASE;
ccw->flags |= CCW_FLAG_SLI;
ccw->count = 32;
- ccw->cda = (__u32)(addr_t) cqr->data;
+ ccw->cda = (__u32)virt_to_phys(cqr->data);
cqr->startdev = device;
cqr->memdev = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -5100,7 +5100,7 @@ dasd_eckd_reserve(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_RESERVE;
ccw->flags |= CCW_FLAG_SLI;
ccw->count = 32;
- ccw->cda = (__u32)(addr_t) cqr->data;
+ ccw->cda = (__u32)virt_to_phys(cqr->data);
cqr->startdev = device;
cqr->memdev = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -5154,7 +5154,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_SLCK;
ccw->flags |= CCW_FLAG_SLI;
ccw->count = 32;
- ccw->cda = (__u32)(addr_t) cqr->data;
+ ccw->cda = (__u32)virt_to_phys(cqr->data);
cqr->startdev = device;
cqr->memdev = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -5215,7 +5215,7 @@ static int dasd_eckd_snid(struct dasd_device *device,
ccw->cmd_code = DASD_ECKD_CCW_SNID;
ccw->flags |= CCW_FLAG_SLI;
ccw->count = 12;
- ccw->cda = (__u32)(addr_t) cqr->data;
+ ccw->cda = (__u32)virt_to_phys(cqr->data);
cqr->startdev = device;
cqr->memdev = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -5282,7 +5282,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
ccw->cmd_code = DASD_ECKD_CCW_PSF;
ccw->count = sizeof(struct dasd_psf_prssd_data);
ccw->flags |= CCW_FLAG_CC;
- ccw->cda = (__u32)(addr_t) prssdp;
+ ccw->cda = (__u32)virt_to_phys(prssdp);
/* Read Subsystem Data - Performance Statistics */
stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
@@ -5291,7 +5291,7 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
ccw++;
ccw->cmd_code = DASD_ECKD_CCW_RSSD;
ccw->count = sizeof(struct dasd_rssd_perf_stats_t);
- ccw->cda = (__u32)(addr_t) stats;
+ ccw->cda = (__u32)virt_to_phys(stats);
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
@@ -5435,7 +5435,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
ccw->cmd_code = DASD_ECKD_CCW_PSF;
ccw->count = usrparm.psf_data_len;
ccw->flags |= CCW_FLAG_CC;
- ccw->cda = (__u32)(addr_t) psf_data;
+ ccw->cda = (__u32)virt_to_phys(psf_data);
ccw++;
@@ -5443,7 +5443,7 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp)
ccw->cmd_code = DASD_ECKD_CCW_RSSD;
ccw->count = usrparm.rssd_result_len;
ccw->flags = CCW_FLAG_SLI ;
- ccw->cda = (__u32)(addr_t) rssd_result;
+ ccw->cda = (__u32)virt_to_phys(rssd_result);
rc = dasd_sleep_on(cqr);
if (rc)
@@ -5512,9 +5512,9 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
/* get pointer to data (consider IDALs) */
if (from->flags & CCW_FLAG_IDA)
- datap = (char *) *((addr_t *) (addr_t) from->cda);
+ datap = (char *)*((addr_t *)phys_to_virt(from->cda));
else
- datap = (char *) ((addr_t) from->cda);
+ datap = phys_to_virt(from->cda);
/* dump data (max 128 bytes) */
for (count = 0; count < from->count && count < 128; count++) {
@@ -5585,7 +5585,7 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
len += sprintf(page + len, PRINTK_HEADER
" device %s: Failing CCW: %p\n",
dev_name(&device->cdev->dev),
- (void *) (addr_t) irb->scsw.cmd.cpa);
+ phys_to_virt(irb->scsw.cmd.cpa));
if (irb->esw.esw0.erw.cons) {
for (sl = 0; sl < 4; sl++) {
len += sprintf(page + len, PRINTK_HEADER
@@ -5632,8 +5632,7 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device,
/* print failing CCW area (maximum 4) */
/* scsw->cda is either valid or zero */
from = ++to;
- fail = (struct ccw1 *)(addr_t)
- irb->scsw.cmd.cpa; /* failing CCW */
+ fail = phys_to_virt(irb->scsw.cmd.cpa); /* failing CCW */
if (from < fail - 2) {
from = fail - 2; /* there is a gap - print header */
printk(KERN_ERR PRINTK_HEADER "......\n");
@@ -5687,13 +5686,12 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device,
len += sprintf(page + len, PRINTK_HEADER
" device %s: Failing TCW: %p\n",
dev_name(&device->cdev->dev),
- (void *) (addr_t) irb->scsw.tm.tcw);
+ phys_to_virt(irb->scsw.tm.tcw));
tsb = NULL;
sense = NULL;
if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs & 0x01))
- tsb = tcw_get_tsb(
- (struct tcw *)(unsigned long)irb->scsw.tm.tcw);
+ tsb = tcw_get_tsb(phys_to_virt(irb->scsw.tm.tcw));
if (tsb) {
len += sprintf(page + len, PRINTK_HEADER
@@ -5917,7 +5915,7 @@ retry:
ccw->count = sizeof(struct dasd_psf_prssd_data);
ccw->flags |= CCW_FLAG_CC;
ccw->flags |= CCW_FLAG_SLI;
- ccw->cda = (__u32)(addr_t) prssdp;
+ ccw->cda = (__u32)virt_to_phys(prssdp);
/* Read Subsystem Data - message buffer */
message_buf = (struct dasd_rssd_messages *) (prssdp + 1);
@@ -5927,7 +5925,7 @@ retry:
ccw->cmd_code = DASD_ECKD_CCW_RSSD;
ccw->count = sizeof(struct dasd_rssd_messages);
ccw->flags |= CCW_FLAG_SLI;
- ccw->cda = (__u32)(addr_t) message_buf;
+ ccw->cda = (__u32)virt_to_phys(message_buf);
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
@@ -6008,14 +6006,14 @@ static int dasd_eckd_query_host_access(struct dasd_device *device,
ccw->count = sizeof(struct dasd_psf_prssd_data);
ccw->flags |= CCW_FLAG_CC;
ccw->flags |= CCW_FLAG_SLI;
- ccw->cda = (__u32)(addr_t) prssdp;
+ ccw->cda = (__u32)virt_to_phys(prssdp);
/* Read Subsystem Data - query host access */
ccw++;
ccw->cmd_code = DASD_ECKD_CCW_RSSD;
ccw->count = sizeof(struct dasd_psf_query_host_access);
ccw->flags |= CCW_FLAG_SLI;
- ccw->cda = (__u32)(addr_t) host_access;
+ ccw->cda = (__u32)virt_to_phys(host_access);
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
@@ -6351,7 +6349,7 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
psf_cuir->ssid = device->path[pos].ssid;
ccw = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_PSF;
- ccw->cda = (__u32)(addr_t)psf_cuir;
+ ccw->cda = (__u32)virt_to_phys(psf_cuir);
ccw->flags = CCW_FLAG_SLI;
ccw->count = sizeof(struct dasd_psf_cuir_response);
@@ -6956,8 +6954,10 @@ dasd_eckd_init(void)
return -ENOMEM;
dasd_vol_info_req = kmalloc(sizeof(*dasd_vol_info_req),
GFP_KERNEL | GFP_DMA);
- if (!dasd_vol_info_req)
+ if (!dasd_vol_info_req) {
+ kfree(dasd_reserve_req);
return -ENOMEM;
+ }
pe_handler_worker = kmalloc(sizeof(*pe_handler_worker),
GFP_KERNEL | GFP_DMA);
if (!pe_handler_worker) {
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index d4d31cd11d26..a4cc772208a6 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -491,7 +491,7 @@ int dasd_eer_enable(struct dasd_device *device)
ccw->cmd_code = DASD_ECKD_CCW_SNSS;
ccw->count = SNSS_DATA_SIZE;
ccw->flags = 0;
- ccw->cda = (__u32)(addr_t) cqr->data;
+ ccw->cda = (__u32)virt_to_phys(cqr->data);
cqr->buildclk = get_tod_clock();
cqr->status = DASD_CQR_FILLED;
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index cddfb01a3dca..bcb67fa747a7 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -83,7 +83,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
ccw->flags = 0;
ccw->count = 16;
- ccw->cda = (__u32) __pa(data);
+ ccw->cda = (__u32)virt_to_phys(data);
memset(data, 0, sizeof (struct DE_fba_data));
if (rw == WRITE)
(data->mask).perm = 0x0;
@@ -103,7 +103,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
ccw->cmd_code = DASD_FBA_CCW_LOCATE;
ccw->flags = 0;
ccw->count = 8;
- ccw->cda = (__u32) __pa(data);
+ ccw->cda = (__u32)virt_to_phys(data);
memset(data, 0, sizeof (struct LO_fba_data));
if (rw == WRITE)
data->operation.cmd = 0x5;
@@ -262,7 +262,7 @@ static void ccw_write_zero(struct ccw1 *ccw, int count)
ccw->cmd_code = DASD_FBA_CCW_WRITE;
ccw->flags |= CCW_FLAG_SLI;
ccw->count = count;
- ccw->cda = (__u32) (addr_t) dasd_fba_zero_page;
+ ccw->cda = (__u32)virt_to_phys(dasd_fba_zero_page);
}
/*
@@ -528,11 +528,11 @@ static struct dasd_ccw_req *dasd_fba_build_cp_regular(
ccw->cmd_code = cmd;
ccw->count = block->bp_block;
if (idal_is_needed(dst, blksize)) {
- ccw->cda = (__u32)(addr_t) idaws;
+ ccw->cda = (__u32)virt_to_phys(idaws);
ccw->flags = CCW_FLAG_IDA;
idaws = idal_create_words(idaws, dst, blksize);
} else {
- ccw->cda = (__u32)(addr_t) dst;
+ ccw->cda = (__u32)virt_to_phys(dst);
ccw->flags = 0;
}
ccw++;
@@ -590,9 +590,9 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
ccw++;
if (dst) {
if (ccw->flags & CCW_FLAG_IDA)
- cda = *((char **)((addr_t) ccw->cda));
+ cda = *((char **)phys_to_virt(ccw->cda));
else
- cda = (char *)((addr_t) ccw->cda);
+ cda = phys_to_virt(ccw->cda);
if (dst != cda) {
if (rq_data_dir(req) == READ)
memcpy(dst, cda, bv.bv_len);
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index b392b9f5482e..c09f2e053bf8 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -864,8 +864,6 @@ dcssblk_submit_bio(struct bio *bio)
unsigned long source_addr;
unsigned long bytes_done;
- bio = bio_split_to_limits(bio);
-
bytes_done = 0;
dev_info = bio->bi_bdev->bd_disk->private_data;
if (dev_info == NULL)
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 7d1749b0d378..80c4e5101c97 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -5,17 +5,10 @@ comment "S/390 character device drivers"
config TN3270
def_tristate y
prompt "Support for locally attached 3270 terminals"
- depends on CCW
+ depends on CCW && TTY
help
Include support for IBM 3270 terminals.
-config TN3270_TTY
- def_tristate y
- prompt "Support for tty input/output on 3270 terminals"
- depends on TN3270 && TTY
- help
- Include support for using an IBM 3270 terminal as a Linux tty.
-
config TN3270_FS
def_tristate m
prompt "Support for fullscreen applications on 3270 terminals"
@@ -26,7 +19,7 @@ config TN3270_FS
config TN3270_CONSOLE
def_bool y
prompt "Support for console on 3270 terminal"
- depends on TN3270=y && TN3270_TTY=y
+ depends on TN3270=y
help
Include support for using an IBM 3270 terminal as a Linux system
console. Available only if 3270 support is compiled in statically.
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index ce32270082f5..b0f6b3201636 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -21,9 +21,7 @@ obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
sclp_early.o sclp_early_core.o sclp_sd.o
-obj-$(CONFIG_TN3270) += raw3270.o
-obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
-obj-$(CONFIG_TN3270_TTY) += tty3270.o
+obj-$(CONFIG_TN3270) += raw3270.o con3270.o
obj-$(CONFIG_TN3270_FS) += fs3270.o
obj-$(CONFIG_TN3215) += con3215.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 72ba83c1bc79..0b05cd76b7d0 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -629,7 +629,7 @@ static int raw3215_startup(struct raw3215_info *raw)
if (tty_port_initialized(&raw->port))
return 0;
raw->line_pos = 0;
- tty_port_set_initialized(&raw->port, 1);
+ tty_port_set_initialized(&raw->port, true);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_try_io(raw);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -659,7 +659,7 @@ static void raw3215_shutdown(struct raw3215_info *raw)
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
remove_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_RUNNING);
- tty_port_set_initialized(&raw->port, 1);
+ tty_port_set_initialized(&raw->port, true);
}
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 10f6a37fb153..d9983550062d 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -1,518 +1,2075 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * IBM/3270 Driver - console view.
+ * IBM/3270 Driver - tty functions.
*
- * Author(s):
- * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- * Copyright IBM Corp. 2003, 2009
+ * Author(s):
+ * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * -- Copyright IBM Corp. 2003
*/
#include <linux/module.h>
-#include <linux/console.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
#include <linux/init.h>
+#include <linux/console.h>
#include <linux/interrupt.h>
-#include <linux/list.h>
+#include <linux/workqueue.h>
#include <linux/panic_notifier.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/err.h>
#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/memblock.h>
+#include <linux/compat.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
-#include <asm/cpcmd.h>
#include <asm/ebcdic.h>
+#include <asm/cpcmd.h>
+#include <linux/uaccess.h>
#include "raw3270.h"
-#include "tty3270.h"
-#include "ctrlchar.h"
+#include "keyboard.h"
+
+#define TTY3270_CHAR_BUF_SIZE 256
+#define TTY3270_OUTPUT_BUFFER_SIZE 4096
+#define TTY3270_SCREEN_PAGES 8 /* has to be power-of-two */
+#define TTY3270_RECALL_SIZE 16 /* has to be power-of-two */
+#define TTY3270_STATUS_AREA_SIZE 40
+
+static struct tty_driver *tty3270_driver;
+static int tty3270_max_index;
+static struct raw3270_fn tty3270_fn;
+
+#define TTY3270_HIGHLIGHT_BLINK 1
+#define TTY3270_HIGHLIGHT_REVERSE 2
+#define TTY3270_HIGHLIGHT_UNDERSCORE 4
+
+struct tty3270_attribute {
+ unsigned char alternate_charset:1; /* Graphics charset */
+ unsigned char highlight:3; /* Blink/reverse/underscore */
+ unsigned char f_color:4; /* Foreground color */
+ unsigned char b_color:4; /* Background color */
+};
-#define CON3270_OUTPUT_BUFFER_SIZE 1024
-#define CON3270_STRING_PAGES 4
+struct tty3270_cell {
+ unsigned char character;
+ struct tty3270_attribute attributes;
+};
-static struct raw3270_fn con3270_fn;
+struct tty3270_line {
+ struct tty3270_cell *cells;
+ int len;
+ int dirty;
+};
-static bool auto_update = true;
-module_param(auto_update, bool, 0);
+static const unsigned char sfq_read_partition[] = {
+ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81
+};
+
+#define ESCAPE_NPAR 8
/*
- * Main 3270 console view data structure.
+ * The main tty view data structure.
+ * FIXME:
+ * 1) describe line orientation & lines list concept against screen
+ * 2) describe conversion of screen to lines
+ * 3) describe line format.
*/
-struct con3270 {
+struct tty3270 {
struct raw3270_view view;
- struct list_head freemem; /* list of free memory for strings. */
+ struct tty_port port;
/* Output stuff. */
- struct list_head lines; /* list of lines. */
- struct list_head update; /* list of lines to update. */
- int line_nr; /* line number for next update. */
- int nr_lines; /* # lines in list. */
+ unsigned char wcc; /* Write control character. */
int nr_up; /* # lines up in history. */
unsigned long update_flags; /* Update indication bits. */
- struct string *cline; /* current output line. */
- struct string *status; /* last line of display. */
- struct raw3270_request *write; /* single write request. */
- struct timer_list timer;
+ struct raw3270_request *write; /* Single write request. */
+ struct timer_list timer; /* Output delay timer. */
+ char *converted_line; /* RAW 3270 data stream */
+ unsigned int line_view_start; /* Start of visible area */
+ unsigned int line_write_start; /* current write position */
+ unsigned int oops_line; /* line counter used when print oops */
+
+ /* Current tty screen. */
+ unsigned int cx, cy; /* Current output position. */
+ struct tty3270_attribute attributes;
+ struct tty3270_attribute saved_attributes;
+ int allocated_lines;
+ struct tty3270_line *screen;
/* Input stuff. */
- struct string *input; /* input string for read request. */
- struct raw3270_request *read; /* single read request. */
- struct raw3270_request *kreset; /* single keyboard reset request. */
- struct tasklet_struct readlet; /* tasklet to issue read request. */
+ char *prompt; /* Output string for input area. */
+ char *input; /* Input string for read request. */
+ struct raw3270_request *read; /* Single read request. */
+ struct raw3270_request *kreset; /* Single keyboard reset request. */
+ struct raw3270_request *readpartreq;
+ unsigned char inattr; /* Visible/invisible input. */
+ int throttle, attn; /* tty throttle/unthrottle. */
+ struct tasklet_struct readlet; /* Tasklet to issue read request. */
+ struct tasklet_struct hanglet; /* Tasklet to hang up the tty. */
+ struct kbd_data *kbd; /* key_maps stuff. */
+
+ /* Escape sequence parsing. */
+ int esc_state, esc_ques, esc_npar;
+ int esc_par[ESCAPE_NPAR];
+ unsigned int saved_cx, saved_cy;
+
+ /* Command recalling. */
+ char **rcl_lines; /* Array of recallable lines */
+ int rcl_write_index; /* Write index of recallable items */
+ int rcl_read_index; /* Read index of recallable items */
+
+ /* Character array for put_char/flush_chars. */
+ unsigned int char_count;
+ char char_buf[TTY3270_CHAR_BUF_SIZE];
};
-static struct con3270 *condev;
-
-/* con3270->update_flags. See con3270_update for details. */
-#define CON_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */
-#define CON_UPDATE_LIST 2 /* Update lines in tty3270->update. */
-#define CON_UPDATE_STATUS 4 /* Update status line. */
-#define CON_UPDATE_ALL 8 /* Recreate screen. */
+/* tty3270->update_flags. See tty3270_update for details. */
+#define TTY_UPDATE_INPUT 0x1 /* Update input line. */
+#define TTY_UPDATE_STATUS 0x2 /* Update status line. */
+#define TTY_UPDATE_LINES 0x4 /* Update visible screen lines */
+#define TTY_UPDATE_ALL 0x7 /* Recreate screen. */
-static void con3270_update(struct timer_list *);
+#define TTY3270_INPUT_AREA_ROWS 2
/*
* Setup timeout for a device. On timeout trigger an update.
*/
-static void con3270_set_timer(struct con3270 *cp, int expires)
+static void tty3270_set_timer(struct tty3270 *tp, int expires)
{
- if (expires == 0)
- del_timer(&cp->timer);
- else
- mod_timer(&cp->timer, jiffies + expires);
+ mod_timer(&tp->timer, jiffies + expires);
}
-/*
- * The status line is the last line of the screen. It shows the string
- * "console view" in the lower left corner and "Running"/"More..."/"Holding"
- * in the lower right corner of the screen.
- */
-static void
-con3270_update_status(struct con3270 *cp)
+static int tty3270_tty_rows(struct tty3270 *tp)
{
- char *str;
+ return tp->view.rows - TTY3270_INPUT_AREA_ROWS;
+}
- str = (cp->nr_up != 0) ? "History" : "Running";
- memcpy(cp->status->string + 24, str, 7);
- codepage_convert(cp->view.ascebc, cp->status->string + 24, 7);
- cp->update_flags |= CON_UPDATE_STATUS;
+static char *tty3270_add_ba(struct tty3270 *tp, char *cp, char order, int x, int y)
+{
+ *cp++ = order;
+ raw3270_buffer_address(tp->view.dev, cp, x, y);
+ return cp + 2;
}
-static void
-con3270_create_status(struct con3270 *cp)
+static char *tty3270_add_ra(struct tty3270 *tp, char *cp, int x, int y, char c)
+{
+ cp = tty3270_add_ba(tp, cp, TO_RA, x, y);
+ *cp++ = c;
+ return cp;
+}
+
+static char *tty3270_add_sa(struct tty3270 *tp, char *cp, char attr, char value)
+{
+ *cp++ = TO_SA;
+ *cp++ = attr;
+ *cp++ = value;
+ return cp;
+}
+
+static char *tty3270_add_ge(struct tty3270 *tp, char *cp, char c)
+{
+ *cp++ = TO_GE;
+ *cp++ = c;
+ return cp;
+}
+
+static char *tty3270_add_sf(struct tty3270 *tp, char *cp, char type)
+{
+ *cp++ = TO_SF;
+ *cp++ = type;
+ return cp;
+}
+
+static int tty3270_line_increment(struct tty3270 *tp, unsigned int line, unsigned int incr)
+{
+ return (line + incr) & (tp->allocated_lines - 1);
+}
+
+static struct tty3270_line *tty3270_get_write_line(struct tty3270 *tp, unsigned int num)
{
- static const unsigned char blueprint[] =
- { TO_SBA, 0, 0, TO_SF,TF_LOG,TO_SA,TAT_COLOR, TAC_GREEN,
- 'c','o','n','s','o','l','e',' ','v','i','e','w',
- TO_RA,0,0,0,'R','u','n','n','i','n','g',TO_SF,TF_LOG };
+ return tp->screen + tty3270_line_increment(tp, tp->line_write_start, num);
+}
+
+static struct tty3270_line *tty3270_get_view_line(struct tty3270 *tp, unsigned int num)
+{
+ return tp->screen + tty3270_line_increment(tp, tp->line_view_start, num - tp->nr_up);
+}
- cp->status = alloc_string(&cp->freemem, sizeof(blueprint));
- /* Copy blueprint to status line */
- memcpy(cp->status->string, blueprint, sizeof(blueprint));
- /* Set TO_RA addresses. */
- raw3270_buffer_address(cp->view.dev, cp->status->string + 1,
- cp->view.cols * (cp->view.rows - 1));
- raw3270_buffer_address(cp->view.dev, cp->status->string + 21,
- cp->view.cols * cp->view.rows - 8);
- /* Convert strings to ebcdic. */
- codepage_convert(cp->view.ascebc, cp->status->string + 8, 12);
- codepage_convert(cp->view.ascebc, cp->status->string + 24, 7);
+static int tty3270_input_size(int cols)
+{
+ return cols * 2 - 11;
+}
+
+static void tty3270_update_prompt(struct tty3270 *tp, char *input)
+{
+ strcpy(tp->prompt, input);
+ tp->update_flags |= TTY_UPDATE_INPUT;
+ tty3270_set_timer(tp, 1);
}
/*
- * Set output offsets to 3270 datastream fragment of a console string.
+ * The input line are the two last lines of the screen.
*/
-static void
-con3270_update_string(struct con3270 *cp, struct string *s, int nr)
+static int tty3270_add_prompt(struct tty3270 *tp)
{
- if (s->len < 4) {
- /* This indicates a bug, but printing a warning would
- * cause a deadlock. */
- return;
+ int count = 0;
+ char *cp;
+
+ cp = tp->converted_line;
+ cp = tty3270_add_ba(tp, cp, TO_SBA, 0, -2);
+ *cp++ = tp->view.ascebc['>'];
+
+ if (*tp->prompt) {
+ cp = tty3270_add_sf(tp, cp, TF_INMDT);
+ count = min_t(int, strlen(tp->prompt),
+ tp->view.cols * 2 - TTY3270_STATUS_AREA_SIZE - 2);
+ memcpy(cp, tp->prompt, count);
+ cp += count;
+ } else {
+ cp = tty3270_add_sf(tp, cp, tp->inattr);
}
- if (s->string[s->len - 4] != TO_RA)
- return;
- raw3270_buffer_address(cp->view.dev, s->string + s->len - 3,
- cp->view.cols * (nr + 1));
+ *cp++ = TO_IC;
+ /* Clear to end of input line. */
+ if (count < tp->view.cols * 2 - 11)
+ cp = tty3270_add_ra(tp, cp, -TTY3270_STATUS_AREA_SIZE, -1, 0);
+ return cp - tp->converted_line;
+}
+
+static char *tty3270_ebcdic_convert(struct tty3270 *tp, char *d, char *s)
+{
+ while (*s)
+ *d++ = tp->view.ascebc[(int)*s++];
+ return d;
}
/*
- * Rebuild update list to print all lines.
+ * The status line is the last line of the screen. It shows the string
+ * "Running"/"History X" in the lower right corner of the screen.
*/
-static void
-con3270_rebuild_update(struct con3270 *cp)
+static int tty3270_add_status(struct tty3270 *tp)
{
- struct string *s, *n;
- int nr;
+ char *cp = tp->converted_line;
+ int len;
+
+ cp = tty3270_add_ba(tp, cp, TO_SBA, -TTY3270_STATUS_AREA_SIZE, -1);
+ cp = tty3270_add_sf(tp, cp, TF_LOG);
+ cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, TAC_GREEN);
+ cp = tty3270_ebcdic_convert(tp, cp, " 7");
+ cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_REVER);
+ cp = tty3270_ebcdic_convert(tp, cp, "PrevPg");
+ cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_RESET);
+ cp = tty3270_ebcdic_convert(tp, cp, " 8");
+ cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_REVER);
+ cp = tty3270_ebcdic_convert(tp, cp, "NextPg");
+ cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_RESET);
+ cp = tty3270_ebcdic_convert(tp, cp, " 12");
+ cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_REVER);
+ cp = tty3270_ebcdic_convert(tp, cp, "Recall");
+ cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_RESET);
+ cp = tty3270_ebcdic_convert(tp, cp, " ");
+ if (tp->nr_up) {
+ len = sprintf(cp, "History %d", -tp->nr_up);
+ codepage_convert(tp->view.ascebc, cp, len);
+ cp += len;
+ } else {
+ cp = tty3270_ebcdic_convert(tp, cp, oops_in_progress ? "Crashed" : "Running");
+ }
+ cp = tty3270_add_sf(tp, cp, TF_LOG);
+ cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, TAC_RESET);
+ return cp - (char *)tp->converted_line;
+}
- /*
- * Throw away update list and create a new one,
- * containing all lines that will fit on the screen.
- */
- list_for_each_entry_safe(s, n, &cp->update, update)
- list_del_init(&s->update);
- nr = cp->view.rows - 2 + cp->nr_up;
- list_for_each_entry_reverse(s, &cp->lines, list) {
- if (nr < cp->view.rows - 1)
- list_add(&s->update, &cp->update);
- if (--nr < 0)
- break;
+static void tty3270_blank_screen(struct tty3270 *tp)
+{
+ struct tty3270_line *line;
+ int i;
+
+ for (i = 0; i < tty3270_tty_rows(tp); i++) {
+ line = tty3270_get_write_line(tp, i);
+ line->len = 0;
+ line->dirty = 1;
}
- cp->line_nr = 0;
- cp->update_flags |= CON_UPDATE_LIST;
+ tp->nr_up = 0;
}
/*
- * Alloc string for size bytes. Free strings from history if necessary.
+ * Write request completion callback.
*/
-static struct string *
-con3270_alloc_string(struct con3270 *cp, size_t size)
+static void tty3270_write_callback(struct raw3270_request *rq, void *data)
{
- struct string *s, *n;
+ struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
- s = alloc_string(&cp->freemem, size);
- if (s)
- return s;
- list_for_each_entry_safe(s, n, &cp->lines, list) {
- list_del(&s->list);
- if (!list_empty(&s->update))
- list_del(&s->update);
- cp->nr_lines--;
- if (free_string(&cp->freemem, s) >= size)
- break;
+ if (rq->rc != 0) {
+ /* Write wasn't successful. Refresh all. */
+ tp->update_flags = TTY_UPDATE_ALL;
+ tty3270_set_timer(tp, 1);
}
- s = alloc_string(&cp->freemem, size);
- BUG_ON(!s);
- if (cp->nr_up != 0 && cp->nr_up + cp->view.rows > cp->nr_lines) {
- cp->nr_up = cp->nr_lines - cp->view.rows + 1;
- con3270_rebuild_update(cp);
- con3270_update_status(cp);
+ raw3270_request_reset(rq);
+ xchg(&tp->write, rq);
+}
+
+static int tty3270_required_length(struct tty3270 *tp, struct tty3270_line *line)
+{
+ unsigned char f_color, b_color, highlight;
+ struct tty3270_cell *cell;
+ int i, flen = 3; /* Prefix (TO_SBA). */
+
+ flen += line->len;
+ highlight = 0;
+ f_color = TAC_RESET;
+ b_color = TAC_RESET;
+
+ for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
+ if (cell->attributes.highlight != highlight) {
+ flen += 3; /* TO_SA to switch highlight. */
+ highlight = cell->attributes.highlight;
+ }
+ if (cell->attributes.f_color != f_color) {
+ flen += 3; /* TO_SA to switch color. */
+ f_color = cell->attributes.f_color;
+ }
+ if (cell->attributes.b_color != b_color) {
+ flen += 3; /* TO_SA to switch color. */
+ b_color = cell->attributes.b_color;
+ }
+ if (cell->attributes.alternate_charset)
+ flen += 1; /* TO_GE to switch to graphics extensions */
}
- return s;
+ if (highlight)
+ flen += 3; /* TO_SA to reset hightlight. */
+ if (f_color != TAC_RESET)
+ flen += 3; /* TO_SA to reset color. */
+ if (b_color != TAC_RESET)
+ flen += 3; /* TO_SA to reset color. */
+ if (line->len < tp->view.cols)
+ flen += 4; /* Postfix (TO_RA). */
+
+ return flen;
+}
+
+static char *tty3270_add_reset_attributes(struct tty3270 *tp, struct tty3270_line *line,
+ char *cp, struct tty3270_attribute *attr, int lineno)
+{
+ if (attr->highlight)
+ cp = tty3270_add_sa(tp, cp, TAT_EXTHI, TAX_RESET);
+ if (attr->f_color != TAC_RESET)
+ cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, TAX_RESET);
+ if (attr->b_color != TAC_RESET)
+ cp = tty3270_add_sa(tp, cp, TAT_BGCOLOR, TAX_RESET);
+ if (line->len < tp->view.cols)
+ cp = tty3270_add_ra(tp, cp, 0, lineno + 1, 0);
+ return cp;
+}
+
+static char tty3270_graphics_translate(struct tty3270 *tp, char ch)
+{
+ switch (ch) {
+ case 'q': /* - */
+ return 0xa2;
+ case 'x': /* '|' */
+ return 0x85;
+ case 'l': /* |- */
+ return 0xc5;
+ case 't': /* |_ */
+ return 0xc6;
+ case 'u': /* _| */
+ return 0xd6;
+ case 'k': /* -| */
+ return 0xd5;
+ case 'j':
+ return 0xd4;
+ case 'm':
+ return 0xc4;
+ case 'n': /* + */
+ return 0xd3;
+ case 'v':
+ return 0xc7;
+ case 'w':
+ return 0xd7;
+ default:
+ return ch;
+ }
+}
+
+static char *tty3270_add_attributes(struct tty3270 *tp, struct tty3270_line *line,
+ struct tty3270_attribute *attr, char *cp, int lineno)
+{
+ const unsigned char colors[16] = {
+ [0] = TAC_DEFAULT,
+ [1] = TAC_RED,
+ [2] = TAC_GREEN,
+ [3] = TAC_YELLOW,
+ [4] = TAC_BLUE,
+ [5] = TAC_PINK,
+ [6] = TAC_TURQ,
+ [7] = TAC_WHITE,
+ [9] = TAC_DEFAULT
+ };
+
+ const unsigned char highlights[8] = {
+ [TTY3270_HIGHLIGHT_BLINK] = TAX_BLINK,
+ [TTY3270_HIGHLIGHT_REVERSE] = TAX_REVER,
+ [TTY3270_HIGHLIGHT_UNDERSCORE] = TAX_UNDER,
+ };
+
+ struct tty3270_cell *cell;
+ int c, i;
+
+ cp = tty3270_add_ba(tp, cp, TO_SBA, 0, lineno);
+
+ for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
+ if (cell->attributes.highlight != attr->highlight) {
+ attr->highlight = cell->attributes.highlight;
+ cp = tty3270_add_sa(tp, cp, TAT_EXTHI, highlights[attr->highlight]);
+ }
+ if (cell->attributes.f_color != attr->f_color) {
+ attr->f_color = cell->attributes.f_color;
+ cp = tty3270_add_sa(tp, cp, TAT_FGCOLOR, colors[attr->f_color]);
+ }
+ if (cell->attributes.b_color != attr->b_color) {
+ attr->b_color = cell->attributes.b_color;
+ cp = tty3270_add_sa(tp, cp, TAT_BGCOLOR, colors[attr->b_color]);
+ }
+ c = cell->character;
+ if (cell->attributes.alternate_charset)
+ cp = tty3270_add_ge(tp, cp, tty3270_graphics_translate(tp, c));
+ else
+ *cp++ = tp->view.ascebc[c];
+ }
+ return cp;
+}
+
+static void tty3270_reset_attributes(struct tty3270_attribute *attr)
+{
+ attr->highlight = TAX_RESET;
+ attr->f_color = TAC_RESET;
+ attr->b_color = TAC_RESET;
}
/*
- * Write completion callback.
+ * Convert a tty3270_line to a 3270 data fragment usable for output.
*/
-static void
-con3270_write_callback(struct raw3270_request *rq, void *data)
+static unsigned int tty3270_convert_line(struct tty3270 *tp, struct tty3270_line *line, int lineno)
{
- raw3270_request_reset(rq);
- xchg(&((struct con3270 *) rq->view)->write, rq);
+ struct tty3270_attribute attr;
+ int flen;
+ char *cp;
+
+ /* Determine how long the fragment will be. */
+ flen = tty3270_required_length(tp, line);
+ if (flen > PAGE_SIZE)
+ return 0;
+ /* Write 3270 data fragment. */
+ tty3270_reset_attributes(&attr);
+ cp = tty3270_add_attributes(tp, line, &attr, tp->converted_line, lineno);
+ cp = tty3270_add_reset_attributes(tp, line, cp, &attr, lineno);
+ return cp - (char *)tp->converted_line;
+}
+
+static void tty3270_update_lines_visible(struct tty3270 *tp, struct raw3270_request *rq)
+{
+ struct tty3270_line *line;
+ int len, i;
+
+ for (i = 0; i < tty3270_tty_rows(tp); i++) {
+ line = tty3270_get_view_line(tp, i);
+ if (!line->dirty)
+ continue;
+ len = tty3270_convert_line(tp, line, i);
+ if (raw3270_request_add_data(rq, tp->converted_line, len))
+ break;
+ line->dirty = 0;
+ }
+ if (i == tty3270_tty_rows(tp)) {
+ for (i = 0; i < tp->allocated_lines; i++)
+ tp->screen[i].dirty = 0;
+ tp->update_flags &= ~TTY_UPDATE_LINES;
+ }
+}
+
+static void tty3270_update_lines_all(struct tty3270 *tp, struct raw3270_request *rq)
+{
+ struct tty3270_line *line;
+ char buf[4];
+ int len, i;
+
+ for (i = 0; i < tp->allocated_lines; i++) {
+ line = tty3270_get_write_line(tp, i + tp->cy + 1);
+ if (!line->dirty)
+ continue;
+ len = tty3270_convert_line(tp, line, tp->oops_line);
+ if (raw3270_request_add_data(rq, tp->converted_line, len))
+ break;
+ line->dirty = 0;
+ if (++tp->oops_line >= tty3270_tty_rows(tp))
+ tp->oops_line = 0;
+ }
+
+ if (i == tp->allocated_lines) {
+ if (tp->oops_line < tty3270_tty_rows(tp)) {
+ tty3270_add_ra(tp, buf, 0, tty3270_tty_rows(tp), 0);
+ if (raw3270_request_add_data(rq, buf, sizeof(buf)))
+ return;
+ }
+ tp->update_flags &= ~TTY_UPDATE_LINES;
+ }
}
/*
- * Update console display.
+ * Update 3270 display.
*/
-static void
-con3270_update(struct timer_list *t)
+static void tty3270_update(struct timer_list *t)
{
- struct con3270 *cp = from_timer(cp, t, timer);
+ struct tty3270 *tp = from_timer(tp, t, timer);
struct raw3270_request *wrq;
- char wcc, prolog[6];
- unsigned long flags;
- unsigned long updated;
- struct string *s, *n;
- int rc;
+ u8 cmd = TC_WRITE;
+ int rc, len;
- if (!auto_update && !raw3270_view_active(&cp->view))
- return;
- if (cp->view.dev)
- raw3270_activate_view(&cp->view);
-
- wrq = xchg(&cp->write, 0);
+ wrq = xchg(&tp->write, 0);
if (!wrq) {
- con3270_set_timer(cp, 1);
+ tty3270_set_timer(tp, 1);
return;
}
- spin_lock_irqsave(&cp->view.lock, flags);
- updated = 0;
- if (cp->update_flags & CON_UPDATE_ALL) {
- con3270_rebuild_update(cp);
- con3270_update_status(cp);
- cp->update_flags = CON_UPDATE_ERASE | CON_UPDATE_LIST |
- CON_UPDATE_STATUS;
- }
- if (cp->update_flags & CON_UPDATE_ERASE) {
- /* Use erase write alternate to initialize display. */
- raw3270_request_set_cmd(wrq, TC_EWRITEA);
- updated |= CON_UPDATE_ERASE;
- } else
- raw3270_request_set_cmd(wrq, TC_WRITE);
+ spin_lock_irq(&tp->view.lock);
+ if (tp->update_flags == TTY_UPDATE_ALL)
+ cmd = TC_EWRITEA;
- wcc = TW_NONE;
- raw3270_request_add_data(wrq, &wcc, 1);
+ raw3270_request_set_cmd(wrq, cmd);
+ raw3270_request_add_data(wrq, &tp->wcc, 1);
+ tp->wcc = TW_NONE;
/*
* Update status line.
*/
- if (cp->update_flags & CON_UPDATE_STATUS)
- if (raw3270_request_add_data(wrq, cp->status->string,
- cp->status->len) == 0)
- updated |= CON_UPDATE_STATUS;
-
- if (cp->update_flags & CON_UPDATE_LIST) {
- prolog[0] = TO_SBA;
- prolog[3] = TO_SA;
- prolog[4] = TAT_COLOR;
- prolog[5] = TAC_TURQ;
- raw3270_buffer_address(cp->view.dev, prolog + 1,
- cp->view.cols * cp->line_nr);
- raw3270_request_add_data(wrq, prolog, 6);
- /* Write strings in the update list to the screen. */
- list_for_each_entry_safe(s, n, &cp->update, update) {
- if (s != cp->cline)
- con3270_update_string(cp, s, cp->line_nr);
- if (raw3270_request_add_data(wrq, s->string,
- s->len) != 0)
- break;
- list_del_init(&s->update);
- if (s != cp->cline)
- cp->line_nr++;
- }
- if (list_empty(&cp->update))
- updated |= CON_UPDATE_LIST;
+ if (tp->update_flags & TTY_UPDATE_STATUS) {
+ len = tty3270_add_status(tp);
+ if (raw3270_request_add_data(wrq, tp->converted_line, len) == 0)
+ tp->update_flags &= ~TTY_UPDATE_STATUS;
+ }
+
+ /*
+ * Write input line.
+ */
+ if (tp->update_flags & TTY_UPDATE_INPUT) {
+ len = tty3270_add_prompt(tp);
+ if (raw3270_request_add_data(wrq, tp->converted_line, len) == 0)
+ tp->update_flags &= ~TTY_UPDATE_INPUT;
+ }
+
+ if (tp->update_flags & TTY_UPDATE_LINES) {
+ if (oops_in_progress)
+ tty3270_update_lines_all(tp, wrq);
+ else
+ tty3270_update_lines_visible(tp, wrq);
}
- wrq->callback = con3270_write_callback;
- rc = raw3270_start(&cp->view, wrq);
+
+ wrq->callback = tty3270_write_callback;
+ rc = raw3270_start(&tp->view, wrq);
if (rc == 0) {
- cp->update_flags &= ~updated;
- if (cp->update_flags)
- con3270_set_timer(cp, 1);
+ if (tp->update_flags)
+ tty3270_set_timer(tp, 1);
} else {
raw3270_request_reset(wrq);
- xchg(&cp->write, wrq);
+ xchg(&tp->write, wrq);
}
- spin_unlock_irqrestore(&cp->view.lock, flags);
+ spin_unlock_irq(&tp->view.lock);
}
/*
- * Read tasklet.
+ * Command recalling.
*/
-static void
-con3270_read_tasklet(unsigned long data)
+static void tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
+{
+ char *p;
+
+ if (len <= 0)
+ return;
+ p = tp->rcl_lines[tp->rcl_write_index++];
+ tp->rcl_write_index &= TTY3270_RECALL_SIZE - 1;
+ memcpy(p, input, len);
+ p[len] = '\0';
+ tp->rcl_read_index = tp->rcl_write_index;
+}
+
+static void tty3270_rcl_backward(struct kbd_data *kbd)
+{
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
+ int i = 0;
+
+ spin_lock_irq(&tp->view.lock);
+ if (tp->inattr == TF_INPUT) {
+ do {
+ tp->rcl_read_index--;
+ tp->rcl_read_index &= TTY3270_RECALL_SIZE - 1;
+ } while (!*tp->rcl_lines[tp->rcl_read_index] &&
+ i++ < TTY3270_RECALL_SIZE - 1);
+ tty3270_update_prompt(tp, tp->rcl_lines[tp->rcl_read_index]);
+ }
+ spin_unlock_irq(&tp->view.lock);
+}
+
+/*
+ * Deactivate tty view.
+ */
+static void tty3270_exit_tty(struct kbd_data *kbd)
+{
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
+
+ raw3270_deactivate_view(&tp->view);
+}
+
+static void tty3270_redraw(struct tty3270 *tp)
+{
+ int i;
+
+ for (i = 0; i < tty3270_tty_rows(tp); i++)
+ tty3270_get_view_line(tp, i)->dirty = 1;
+ tp->update_flags = TTY_UPDATE_ALL;
+ tty3270_set_timer(tp, 1);
+}
+
+/*
+ * Scroll forward in history.
+ */
+static void tty3270_scroll_forward(struct kbd_data *kbd)
+{
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
+
+ spin_lock_irq(&tp->view.lock);
+
+ if (tp->nr_up >= tty3270_tty_rows(tp))
+ tp->nr_up -= tty3270_tty_rows(tp) / 2;
+ else
+ tp->nr_up = 0;
+ tty3270_redraw(tp);
+ spin_unlock_irq(&tp->view.lock);
+}
+
+/*
+ * Scroll backward in history.
+ */
+static void tty3270_scroll_backward(struct kbd_data *kbd)
+{
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
+
+ spin_lock_irq(&tp->view.lock);
+ tp->nr_up += tty3270_tty_rows(tp) / 2;
+ if (tp->nr_up > tp->allocated_lines - tty3270_tty_rows(tp))
+ tp->nr_up = tp->allocated_lines - tty3270_tty_rows(tp);
+ tty3270_redraw(tp);
+ spin_unlock_irq(&tp->view.lock);
+}
+
+/*
+ * Pass input line to tty.
+ */
+static void tty3270_read_tasklet(unsigned long data)
{
+ struct raw3270_request *rrq = (struct raw3270_request *)data;
static char kreset_data = TW_KR;
- struct raw3270_request *rrq;
- struct con3270 *cp;
- unsigned long flags;
- int nr_up, deactivate;
-
- rrq = (struct raw3270_request *)data;
- cp = (struct con3270 *) rrq->view;
- spin_lock_irqsave(&cp->view.lock, flags);
- nr_up = cp->nr_up;
- deactivate = 0;
- /* Check aid byte. */
- switch (cp->input->string[0]) {
- case 0x7d: /* enter: jump to bottom. */
- nr_up = 0;
- break;
- case 0xf3: /* PF3: deactivate the console view. */
- deactivate = 1;
+ struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
+ char *input;
+ int len;
+
+ spin_lock_irq(&tp->view.lock);
+ /*
+ * Two AID keys are special: For 0x7d (enter) the input line
+ * has to be emitted to the tty and for 0x6d the screen
+ * needs to be redrawn.
+ */
+ input = NULL;
+ len = 0;
+ switch (tp->input[0]) {
+ case AID_ENTER:
+ /* Enter: write input to tty. */
+ input = tp->input + 6;
+ len = tty3270_input_size(tp->view.cols) - 6 - rrq->rescnt;
+ if (tp->inattr != TF_INPUTN)
+ tty3270_rcl_add(tp, input, len);
+ if (tp->nr_up > 0)
+ tp->nr_up = 0;
+ /* Clear input area. */
+ tty3270_update_prompt(tp, "");
+ tty3270_set_timer(tp, 1);
break;
- case 0x6d: /* clear: start from scratch. */
- cp->update_flags = CON_UPDATE_ALL;
- con3270_set_timer(cp, 1);
+ case AID_CLEAR:
+ /* Display has been cleared. Redraw. */
+ tp->update_flags = TTY_UPDATE_ALL;
+ tty3270_set_timer(tp, 1);
+ if (!list_empty(&tp->readpartreq->list))
+ break;
+ raw3270_start_request(&tp->view, tp->readpartreq, TC_WRITESF,
+ (char *)sfq_read_partition, sizeof(sfq_read_partition));
break;
- case 0xf7: /* PF7: do a page up in the console log. */
- nr_up += cp->view.rows - 2;
- if (nr_up + cp->view.rows - 1 > cp->nr_lines) {
- nr_up = cp->nr_lines - cp->view.rows + 1;
- if (nr_up < 0)
- nr_up = 0;
- }
+ case AID_READ_PARTITION:
+ raw3270_read_modified_cb(tp->readpartreq, tp->input);
break;
- case 0xf8: /* PF8: do a page down in the console log. */
- nr_up -= cp->view.rows - 2;
- if (nr_up < 0)
- nr_up = 0;
+ default:
break;
}
- if (nr_up != cp->nr_up) {
- cp->nr_up = nr_up;
- con3270_rebuild_update(cp);
- con3270_update_status(cp);
- con3270_set_timer(cp, 1);
- }
- spin_unlock_irqrestore(&cp->view.lock, flags);
+ spin_unlock_irq(&tp->view.lock);
/* Start keyboard reset command. */
- raw3270_request_reset(cp->kreset);
- raw3270_request_set_cmd(cp->kreset, TC_WRITE);
- raw3270_request_add_data(cp->kreset, &kreset_data, 1);
- raw3270_start(&cp->view, cp->kreset);
+ raw3270_start_request(&tp->view, tp->kreset, TC_WRITE, &kreset_data, 1);
- if (deactivate)
- raw3270_deactivate_view(&cp->view);
+ while (len-- > 0)
+ kbd_keycode(tp->kbd, *input++);
+ /* Emit keycode for AID byte. */
+ kbd_keycode(tp->kbd, 256 + tp->input[0]);
raw3270_request_reset(rrq);
- xchg(&cp->read, rrq);
- raw3270_put_view(&cp->view);
+ xchg(&tp->read, rrq);
+ raw3270_put_view(&tp->view);
}
/*
* Read request completion callback.
*/
-static void
-con3270_read_callback(struct raw3270_request *rq, void *data)
+static void tty3270_read_callback(struct raw3270_request *rq, void *data)
{
+ struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
+
raw3270_get_view(rq->view);
/* Schedule tasklet to pass input to tty. */
- tasklet_schedule(&((struct con3270 *) rq->view)->readlet);
+ tasklet_schedule(&tp->readlet);
}
/*
- * Issue a read request. Called only from interrupt function.
+ * Issue a read request. Call with device lock.
*/
-static void
-con3270_issue_read(struct con3270 *cp)
+static void tty3270_issue_read(struct tty3270 *tp, int lock)
{
struct raw3270_request *rrq;
int rc;
- rrq = xchg(&cp->read, 0);
+ rrq = xchg(&tp->read, 0);
if (!rrq)
/* Read already scheduled. */
return;
- rrq->callback = con3270_read_callback;
- rrq->callback_data = cp;
+ rrq->callback = tty3270_read_callback;
+ rrq->callback_data = tp;
raw3270_request_set_cmd(rrq, TC_READMOD);
- raw3270_request_set_data(rrq, cp->input->string, cp->input->len);
+ raw3270_request_set_data(rrq, tp->input, tty3270_input_size(tp->view.cols));
/* Issue the read modified request. */
- rc = raw3270_start_irq(&cp->view, rrq);
- if (rc)
+ if (lock)
+ rc = raw3270_start(&tp->view, rrq);
+ else
+ rc = raw3270_start_irq(&tp->view, rrq);
+ if (rc) {
raw3270_request_reset(rrq);
+ xchg(&tp->read, rrq);
+ }
}
/*
- * Switch to the console view.
+ * Hang up the tty
*/
-static int
-con3270_activate(struct raw3270_view *view)
+static void tty3270_hangup_tasklet(unsigned long data)
{
- struct con3270 *cp;
+ struct tty3270 *tp = (struct tty3270 *)data;
+
+ tty_port_tty_hangup(&tp->port, true);
+ raw3270_put_view(&tp->view);
+}
- cp = (struct con3270 *) view;
- cp->update_flags = CON_UPDATE_ALL;
- con3270_set_timer(cp, 1);
+/*
+ * Switch to the tty view.
+ */
+static int tty3270_activate(struct raw3270_view *view)
+{
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
+
+ tp->update_flags = TTY_UPDATE_ALL;
+ tty3270_set_timer(tp, 1);
return 0;
}
-static void
-con3270_deactivate(struct raw3270_view *view)
+static void tty3270_deactivate(struct raw3270_view *view)
{
- struct con3270 *cp;
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
- cp = (struct con3270 *) view;
- del_timer(&cp->timer);
+ del_timer(&tp->timer);
}
-static void
-con3270_irq(struct con3270 *cp, struct raw3270_request *rq, struct irb *irb)
+static void tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
{
/* Handle ATTN. Schedule tasklet to read aid. */
- if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION)
- con3270_issue_read(cp);
+ if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
+ if (!tp->throttle)
+ tty3270_issue_read(tp, 0);
+ else
+ tp->attn = 1;
+ }
if (rq) {
- if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
+ if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
rq->rc = -EIO;
- else
+ raw3270_get_view(&tp->view);
+ tasklet_schedule(&tp->hanglet);
+ } else {
/* Normal end. Copy residual count. */
rq->rescnt = irb->scsw.cmd.count;
+ }
} else if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
/* Interrupt without an outstanding request -> update all */
- cp->update_flags = CON_UPDATE_ALL;
- con3270_set_timer(cp, 1);
+ tp->update_flags = TTY_UPDATE_ALL;
+ tty3270_set_timer(tp, 1);
+ }
+}
+
+/*
+ * Allocate tty3270 structure.
+ */
+static struct tty3270 *tty3270_alloc_view(void)
+{
+ struct tty3270 *tp;
+
+ tp = kzalloc(sizeof(*tp), GFP_KERNEL);
+ if (!tp)
+ goto out_err;
+
+ tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
+ if (IS_ERR(tp->write))
+ goto out_tp;
+ tp->read = raw3270_request_alloc(0);
+ if (IS_ERR(tp->read))
+ goto out_write;
+ tp->kreset = raw3270_request_alloc(1);
+ if (IS_ERR(tp->kreset))
+ goto out_read;
+ tp->readpartreq = raw3270_request_alloc(sizeof(sfq_read_partition));
+ if (IS_ERR(tp->readpartreq))
+ goto out_reset;
+ tp->kbd = kbd_alloc();
+ if (!tp->kbd)
+ goto out_readpartreq;
+
+ tty_port_init(&tp->port);
+ timer_setup(&tp->timer, tty3270_update, 0);
+ tasklet_init(&tp->readlet, tty3270_read_tasklet,
+ (unsigned long)tp->read);
+ tasklet_init(&tp->hanglet, tty3270_hangup_tasklet,
+ (unsigned long)tp);
+ return tp;
+
+out_readpartreq:
+ raw3270_request_free(tp->readpartreq);
+out_reset:
+ raw3270_request_free(tp->kreset);
+out_read:
+ raw3270_request_free(tp->read);
+out_write:
+ raw3270_request_free(tp->write);
+out_tp:
+ kfree(tp);
+out_err:
+ return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * Free tty3270 structure.
+ */
+static void tty3270_free_view(struct tty3270 *tp)
+{
+ kbd_free(tp->kbd);
+ raw3270_request_free(tp->kreset);
+ raw3270_request_free(tp->read);
+ raw3270_request_free(tp->write);
+ free_page((unsigned long)tp->converted_line);
+ tty_port_destroy(&tp->port);
+ kfree(tp);
+}
+
+/*
+ * Allocate tty3270 screen.
+ */
+static struct tty3270_line *tty3270_alloc_screen(struct tty3270 *tp, unsigned int rows,
+ unsigned int cols, int *allocated_out)
+{
+ struct tty3270_line *screen;
+ int allocated, lines;
+
+ allocated = __roundup_pow_of_two(rows) * TTY3270_SCREEN_PAGES;
+ screen = kcalloc(allocated, sizeof(struct tty3270_line), GFP_KERNEL);
+ if (!screen)
+ goto out_err;
+ for (lines = 0; lines < allocated; lines++) {
+ screen[lines].cells = kcalloc(cols, sizeof(struct tty3270_cell), GFP_KERNEL);
+ if (!screen[lines].cells)
+ goto out_screen;
+ }
+ *allocated_out = allocated;
+ return screen;
+out_screen:
+ while (lines--)
+ kfree(screen[lines].cells);
+ kfree(screen);
+out_err:
+ return ERR_PTR(-ENOMEM);
+}
+
+static char **tty3270_alloc_recall(int cols)
+{
+ char **lines;
+ int i;
+
+ lines = kmalloc_array(TTY3270_RECALL_SIZE, sizeof(char *), GFP_KERNEL);
+ if (!lines)
+ return NULL;
+ for (i = 0; i < TTY3270_RECALL_SIZE; i++) {
+ lines[i] = kcalloc(1, tty3270_input_size(cols) + 1, GFP_KERNEL);
+ if (!lines[i])
+ break;
}
+
+ if (i == TTY3270_RECALL_SIZE)
+ return lines;
+
+ while (i--)
+ kfree(lines[i]);
+ kfree(lines);
+ return NULL;
}
-/* Console view to a 3270 device. */
-static struct raw3270_fn con3270_fn = {
- .activate = con3270_activate,
- .deactivate = con3270_deactivate,
- .intv = (void *) con3270_irq
+static void tty3270_free_recall(char **lines)
+{
+ int i;
+
+ for (i = 0; i < TTY3270_RECALL_SIZE; i++)
+ kfree(lines[i]);
+ kfree(lines);
+}
+
+/*
+ * Free tty3270 screen.
+ */
+static void tty3270_free_screen(struct tty3270_line *screen, int old_lines)
+{
+ int lines;
+
+ for (lines = 0; lines < old_lines; lines++)
+ kfree(screen[lines].cells);
+ kfree(screen);
+}
+
+/*
+ * Resize tty3270 screen
+ */
+static void tty3270_resize(struct raw3270_view *view,
+ int new_model, int new_rows, int new_cols,
+ int old_model, int old_rows, int old_cols)
+{
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
+ struct tty3270_line *screen, *oscreen;
+ char **old_rcl_lines, **new_rcl_lines;
+ char *old_prompt, *new_prompt;
+ char *old_input, *new_input;
+ struct tty_struct *tty;
+ struct winsize ws;
+ int new_allocated, old_allocated = tp->allocated_lines;
+
+ if (old_model == new_model &&
+ old_cols == new_cols &&
+ old_rows == new_rows) {
+ spin_lock_irq(&tp->view.lock);
+ tty3270_redraw(tp);
+ spin_unlock_irq(&tp->view.lock);
+ return;
+ }
+
+ new_input = kzalloc(tty3270_input_size(new_cols), GFP_KERNEL | GFP_DMA);
+ if (!new_input)
+ return;
+ new_prompt = kzalloc(tty3270_input_size(new_cols), GFP_KERNEL);
+ if (!new_prompt)
+ goto out_input;
+ screen = tty3270_alloc_screen(tp, new_rows, new_cols, &new_allocated);
+ if (IS_ERR(screen))
+ goto out_prompt;
+ new_rcl_lines = tty3270_alloc_recall(new_cols);
+ if (!new_rcl_lines)
+ goto out_screen;
+
+ /* Switch to new output size */
+ spin_lock_irq(&tp->view.lock);
+ tty3270_blank_screen(tp);
+ oscreen = tp->screen;
+ tp->screen = screen;
+ tp->allocated_lines = new_allocated;
+ tp->view.rows = new_rows;
+ tp->view.cols = new_cols;
+ tp->view.model = new_model;
+ tp->update_flags = TTY_UPDATE_ALL;
+ old_input = tp->input;
+ old_prompt = tp->prompt;
+ old_rcl_lines = tp->rcl_lines;
+ tp->input = new_input;
+ tp->prompt = new_prompt;
+ tp->rcl_lines = new_rcl_lines;
+ tp->rcl_read_index = 0;
+ tp->rcl_write_index = 0;
+ spin_unlock_irq(&tp->view.lock);
+ tty3270_free_screen(oscreen, old_allocated);
+ kfree(old_input);
+ kfree(old_prompt);
+ tty3270_free_recall(old_rcl_lines);
+ tty3270_set_timer(tp, 1);
+ /* Informat tty layer about new size */
+ tty = tty_port_tty_get(&tp->port);
+ if (!tty)
+ return;
+ ws.ws_row = tty3270_tty_rows(tp);
+ ws.ws_col = tp->view.cols;
+ tty_do_resize(tty, &ws);
+ tty_kref_put(tty);
+ return;
+out_screen:
+ tty3270_free_screen(screen, new_rows);
+out_prompt:
+ kfree(new_prompt);
+out_input:
+ kfree(new_input);
+}
+
+/*
+ * Unlink tty3270 data structure from tty.
+ */
+static void tty3270_release(struct raw3270_view *view)
+{
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
+ struct tty_struct *tty = tty_port_tty_get(&tp->port);
+
+ if (tty) {
+ tty->driver_data = NULL;
+ tty_port_tty_set(&tp->port, NULL);
+ tty_hangup(tty);
+ raw3270_put_view(&tp->view);
+ tty_kref_put(tty);
+ }
+}
+
+/*
+ * Free tty3270 data structure
+ */
+static void tty3270_free(struct raw3270_view *view)
+{
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
+
+ del_timer_sync(&tp->timer);
+ tty3270_free_screen(tp->screen, tp->allocated_lines);
+ free_page((unsigned long)tp->converted_line);
+ kfree(tp->input);
+ kfree(tp->prompt);
+ tty3270_free_view(tp);
+}
+
+/*
+ * Delayed freeing of tty3270 views.
+ */
+static void tty3270_del_views(void)
+{
+ int i;
+
+ for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) {
+ struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i);
+
+ if (!IS_ERR(view))
+ raw3270_del_view(view);
+ }
+}
+
+static struct raw3270_fn tty3270_fn = {
+ .activate = tty3270_activate,
+ .deactivate = tty3270_deactivate,
+ .intv = (void *)tty3270_irq,
+ .release = tty3270_release,
+ .free = tty3270_free,
+ .resize = tty3270_resize
};
-static inline void
-con3270_cline_add(struct con3270 *cp)
+static int
+tty3270_create_view(int index, struct tty3270 **newtp)
+{
+ struct tty3270 *tp;
+ int rc;
+
+ if (tty3270_max_index < index + 1)
+ tty3270_max_index = index + 1;
+
+ /* Allocate tty3270 structure on first open. */
+ tp = tty3270_alloc_view();
+ if (IS_ERR(tp))
+ return PTR_ERR(tp);
+
+ rc = raw3270_add_view(&tp->view, &tty3270_fn,
+ index + RAW3270_FIRSTMINOR,
+ RAW3270_VIEW_LOCK_IRQ);
+ if (rc)
+ goto out_free_view;
+
+ tp->screen = tty3270_alloc_screen(tp, tp->view.rows, tp->view.cols,
+ &tp->allocated_lines);
+ if (IS_ERR(tp->screen)) {
+ rc = PTR_ERR(tp->screen);
+ goto out_put_view;
+ }
+
+ tp->converted_line = (void *)__get_free_page(GFP_KERNEL);
+ if (!tp->converted_line) {
+ rc = -ENOMEM;
+ goto out_free_screen;
+ }
+
+ tp->input = kzalloc(tty3270_input_size(tp->view.cols), GFP_KERNEL | GFP_DMA);
+ if (!tp->input) {
+ rc = -ENOMEM;
+ goto out_free_converted_line;
+ }
+
+ tp->prompt = kzalloc(tty3270_input_size(tp->view.cols), GFP_KERNEL);
+ if (!tp->prompt) {
+ rc = -ENOMEM;
+ goto out_free_input;
+ }
+
+ tp->rcl_lines = tty3270_alloc_recall(tp->view.cols);
+ if (!tp->rcl_lines) {
+ rc = -ENOMEM;
+ goto out_free_prompt;
+ }
+
+ /* Create blank line for every line in the tty output area. */
+ tty3270_blank_screen(tp);
+
+ tp->kbd->port = &tp->port;
+ tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
+ tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
+ tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
+ tp->kbd->fn_handler[KVAL(K_CONS)] = tty3270_rcl_backward;
+ kbd_ascebc(tp->kbd, tp->view.ascebc);
+
+ raw3270_activate_view(&tp->view);
+ raw3270_put_view(&tp->view);
+ *newtp = tp;
+ return 0;
+
+out_free_prompt:
+ kfree(tp->prompt);
+out_free_input:
+ kfree(tp->input);
+out_free_converted_line:
+ free_page((unsigned long)tp->converted_line);
+out_free_screen:
+ tty3270_free_screen(tp->screen, tp->view.rows);
+out_put_view:
+ raw3270_put_view(&tp->view);
+ raw3270_del_view(&tp->view);
+out_free_view:
+ tty3270_free_view(tp);
+ return rc;
+}
+
+/*
+ * This routine is called whenever a 3270 tty is opened first time.
+ */
+static int
+tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct raw3270_view *view;
+ struct tty3270 *tp;
+ int rc;
+
+ /* Check if the tty3270 is already there. */
+ view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR);
+ if (IS_ERR(view)) {
+ rc = tty3270_create_view(tty->index, &tp);
+ if (rc)
+ return rc;
+ } else {
+ tp = container_of(view, struct tty3270, view);
+ tty->driver_data = tp;
+ tp->inattr = TF_INPUT;
+ }
+
+ tty->winsize.ws_row = tty3270_tty_rows(tp);
+ tty->winsize.ws_col = tp->view.cols;
+ rc = tty_port_install(&tp->port, driver, tty);
+ if (rc) {
+ raw3270_put_view(&tp->view);
+ return rc;
+ }
+ tty->driver_data = tp;
+ return 0;
+}
+
+/*
+ * This routine is called whenever a 3270 tty is opened.
+ */
+static int tty3270_open(struct tty_struct *tty, struct file *filp)
+{
+ struct tty3270 *tp = tty->driver_data;
+ struct tty_port *port = &tp->port;
+
+ port->count++;
+ tty_port_tty_set(port, tty);
+ return 0;
+}
+
+/*
+ * This routine is called when the 3270 tty is closed. We wait
+ * for the remaining request to be completed. Then we clean up.
+ */
+static void tty3270_close(struct tty_struct *tty, struct file *filp)
{
- if (!list_empty(&cp->cline->list))
- /* Already added. */
+ struct tty3270 *tp = tty->driver_data;
+
+ if (tty->count > 1)
return;
- list_add_tail(&cp->cline->list, &cp->lines);
- cp->nr_lines++;
- con3270_rebuild_update(cp);
+ if (tp)
+ tty_port_tty_set(&tp->port, NULL);
+}
+
+static void tty3270_cleanup(struct tty_struct *tty)
+{
+ struct tty3270 *tp = tty->driver_data;
+
+ if (tp) {
+ tty->driver_data = NULL;
+ raw3270_put_view(&tp->view);
+ }
+}
+
+/*
+ * We always have room.
+ */
+static unsigned int tty3270_write_room(struct tty_struct *tty)
+{
+ return INT_MAX;
}
-static inline void
-con3270_cline_insert(struct con3270 *cp, unsigned char c)
+/*
+ * Insert character into the screen at the current position with the
+ * current color and highlight. This function does NOT do cursor movement.
+ */
+static void tty3270_put_character(struct tty3270 *tp, char ch)
{
- cp->cline->string[cp->cline->len++] =
- cp->view.ascebc[(c < ' ') ? ' ' : c];
- if (list_empty(&cp->cline->update)) {
- list_add_tail(&cp->cline->update, &cp->update);
- cp->update_flags |= CON_UPDATE_LIST;
+ struct tty3270_line *line;
+ struct tty3270_cell *cell;
+
+ line = tty3270_get_write_line(tp, tp->cy);
+ if (line->len <= tp->cx) {
+ while (line->len < tp->cx) {
+ cell = line->cells + line->len;
+ cell->character = ' ';
+ cell->attributes = tp->attributes;
+ line->len++;
+ }
+ line->len++;
}
+ cell = line->cells + tp->cx;
+ cell->character = ch;
+ cell->attributes = tp->attributes;
+ line->dirty = 1;
+}
+
+/*
+ * Do carriage return.
+ */
+static void tty3270_cr(struct tty3270 *tp)
+{
+ tp->cx = 0;
}
-static inline void
-con3270_cline_end(struct con3270 *cp)
+/*
+ * Do line feed.
+ */
+static void tty3270_lf(struct tty3270 *tp)
{
- struct string *s;
- unsigned int size;
+ struct tty3270_line *line;
+ int i;
- /* Copy cline. */
- size = (cp->cline->len < cp->view.cols - 5) ?
- cp->cline->len + 4 : cp->view.cols;
- s = con3270_alloc_string(cp, size);
- memcpy(s->string, cp->cline->string, cp->cline->len);
- if (cp->cline->len < cp->view.cols - 5) {
- s->string[s->len - 4] = TO_RA;
- s->string[s->len - 1] = 0;
+ if (tp->cy < tty3270_tty_rows(tp) - 1) {
+ tp->cy++;
} else {
- while (--size >= cp->cline->len)
- s->string[size] = cp->view.ascebc[' '];
+ tp->line_view_start = tty3270_line_increment(tp, tp->line_view_start, 1);
+ tp->line_write_start = tty3270_line_increment(tp, tp->line_write_start, 1);
+ for (i = 0; i < tty3270_tty_rows(tp); i++)
+ tty3270_get_view_line(tp, i)->dirty = 1;
+ }
+
+ line = tty3270_get_write_line(tp, tp->cy);
+ line->len = 0;
+ line->dirty = 1;
+}
+
+static void tty3270_ri(struct tty3270 *tp)
+{
+ if (tp->cy > 0)
+ tp->cy--;
+}
+
+static void tty3270_reset_cell(struct tty3270 *tp, struct tty3270_cell *cell)
+{
+ cell->character = ' ';
+ tty3270_reset_attributes(&cell->attributes);
+}
+
+/*
+ * Insert characters at current position.
+ */
+static void tty3270_insert_characters(struct tty3270 *tp, int n)
+{
+ struct tty3270_line *line;
+ int k;
+
+ line = tty3270_get_write_line(tp, tp->cy);
+ while (line->len < tp->cx)
+ tty3270_reset_cell(tp, &line->cells[line->len++]);
+ if (n > tp->view.cols - tp->cx)
+ n = tp->view.cols - tp->cx;
+ k = min_t(int, line->len - tp->cx, tp->view.cols - tp->cx - n);
+ while (k--)
+ line->cells[tp->cx + n + k] = line->cells[tp->cx + k];
+ line->len += n;
+ if (line->len > tp->view.cols)
+ line->len = tp->view.cols;
+ while (n-- > 0) {
+ line->cells[tp->cx + n].character = ' ';
+ line->cells[tp->cx + n].attributes = tp->attributes;
+ }
+}
+
+/*
+ * Delete characters at current position.
+ */
+static void tty3270_delete_characters(struct tty3270 *tp, int n)
+{
+ struct tty3270_line *line;
+ int i;
+
+ line = tty3270_get_write_line(tp, tp->cy);
+ if (line->len <= tp->cx)
+ return;
+ if (line->len - tp->cx <= n) {
+ line->len = tp->cx;
+ return;
+ }
+ for (i = tp->cx; i + n < line->len; i++)
+ line->cells[i] = line->cells[i + n];
+ line->len -= n;
+}
+
+/*
+ * Erase characters at current position.
+ */
+static void tty3270_erase_characters(struct tty3270 *tp, int n)
+{
+ struct tty3270_line *line;
+ struct tty3270_cell *cell;
+
+ line = tty3270_get_write_line(tp, tp->cy);
+ while (line->len > tp->cx && n-- > 0) {
+ cell = line->cells + tp->cx++;
+ tty3270_reset_cell(tp, cell);
+ }
+ tp->cx += n;
+ tp->cx = min_t(int, tp->cx, tp->view.cols - 1);
+}
+
+/*
+ * Erase line, 3 different cases:
+ * Esc [ 0 K Erase from current position to end of line inclusive
+ * Esc [ 1 K Erase from beginning of line to current position inclusive
+ * Esc [ 2 K Erase entire line (without moving cursor)
+ */
+static void tty3270_erase_line(struct tty3270 *tp, int mode)
+{
+ struct tty3270_line *line;
+ struct tty3270_cell *cell;
+ int i, start, end;
+
+ line = tty3270_get_write_line(tp, tp->cy);
+
+ switch (mode) {
+ case 0:
+ start = tp->cx;
+ end = tp->view.cols;
+ break;
+ case 1:
+ start = 0;
+ end = tp->cx;
+ break;
+ case 2:
+ start = 0;
+ end = tp->view.cols;
+ break;
+ default:
+ return;
+ }
+
+ for (i = start; i < end; i++) {
+ cell = line->cells + i;
+ tty3270_reset_cell(tp, cell);
+ cell->attributes.b_color = tp->attributes.b_color;
+ }
+
+ if (line->len <= end)
+ line->len = end;
+}
+
+/*
+ * Erase display, 3 different cases:
+ * Esc [ 0 J Erase from current position to bottom of screen inclusive
+ * Esc [ 1 J Erase from top of screen to current position inclusive
+ * Esc [ 2 J Erase entire screen (without moving the cursor)
+ */
+static void tty3270_erase_display(struct tty3270 *tp, int mode)
+{
+ struct tty3270_line *line;
+ int i, start, end;
+
+ switch (mode) {
+ case 0:
+ tty3270_erase_line(tp, 0);
+ start = tp->cy + 1;
+ end = tty3270_tty_rows(tp);
+ break;
+ case 1:
+ start = 0;
+ end = tp->cy;
+ tty3270_erase_line(tp, 1);
+ break;
+ case 2:
+ start = 0;
+ end = tty3270_tty_rows(tp);
+ break;
+ default:
+ return;
+ }
+ for (i = start; i < end; i++) {
+ line = tty3270_get_write_line(tp, i);
+ line->len = 0;
+ line->dirty = 1;
+ }
+}
+
+/*
+ * Set attributes found in an escape sequence.
+ * Esc [ <attr> ; <attr> ; ... m
+ */
+static void tty3270_set_attributes(struct tty3270 *tp)
+{
+ int i, attr;
+
+ for (i = 0; i <= tp->esc_npar; i++) {
+ attr = tp->esc_par[i];
+ switch (attr) {
+ case 0: /* Reset */
+ tty3270_reset_attributes(&tp->attributes);
+ break;
+ /* Highlight. */
+ case 4: /* Start underlining. */
+ tp->attributes.highlight = TTY3270_HIGHLIGHT_UNDERSCORE;
+ break;
+ case 5: /* Start blink. */
+ tp->attributes.highlight = TTY3270_HIGHLIGHT_BLINK;
+ break;
+ case 7: /* Start reverse. */
+ tp->attributes.highlight = TTY3270_HIGHLIGHT_REVERSE;
+ break;
+ case 24: /* End underlining */
+ tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_UNDERSCORE;
+ break;
+ case 25: /* End blink. */
+ tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_BLINK;
+ break;
+ case 27: /* End reverse. */
+ tp->attributes.highlight &= ~TTY3270_HIGHLIGHT_REVERSE;
+ break;
+ /* Foreground color. */
+ case 30: /* Black */
+ case 31: /* Red */
+ case 32: /* Green */
+ case 33: /* Yellow */
+ case 34: /* Blue */
+ case 35: /* Magenta */
+ case 36: /* Cyan */
+ case 37: /* White */
+ case 39: /* Black */
+ tp->attributes.f_color = attr - 30;
+ break;
+ /* Background color. */
+ case 40: /* Black */
+ case 41: /* Red */
+ case 42: /* Green */
+ case 43: /* Yellow */
+ case 44: /* Blue */
+ case 45: /* Magenta */
+ case 46: /* Cyan */
+ case 47: /* White */
+ case 49: /* Black */
+ tp->attributes.b_color = attr - 40;
+ break;
+ }
+ }
+}
+
+static inline int tty3270_getpar(struct tty3270 *tp, int ix)
+{
+ return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1;
+}
+
+static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
+{
+ struct tty3270_line *line;
+ struct tty3270_cell *cell;
+ int max_cx = max(0, cx);
+ int max_cy = max(0, cy);
+
+ tp->cx = min_t(int, tp->view.cols - 1, max_cx);
+ line = tty3270_get_write_line(tp, tp->cy);
+ while (line->len < tp->cx) {
+ cell = line->cells + line->len;
+ cell->character = ' ';
+ cell->attributes = tp->attributes;
+ line->len++;
+ }
+ tp->cy = min_t(int, tty3270_tty_rows(tp) - 1, max_cy);
+}
+
+/*
+ * Process escape sequences. Known sequences:
+ * Esc 7 Save Cursor Position
+ * Esc 8 Restore Cursor Position
+ * Esc [ Pn ; Pn ; .. m Set attributes
+ * Esc [ Pn ; Pn H Cursor Position
+ * Esc [ Pn ; Pn f Cursor Position
+ * Esc [ Pn A Cursor Up
+ * Esc [ Pn B Cursor Down
+ * Esc [ Pn C Cursor Forward
+ * Esc [ Pn D Cursor Backward
+ * Esc [ Pn G Cursor Horizontal Absolute
+ * Esc [ Pn X Erase Characters
+ * Esc [ Ps J Erase in Display
+ * Esc [ Ps K Erase in Line
+ * // FIXME: add all the new ones.
+ *
+ * Pn is a numeric parameter, a string of zero or more decimal digits.
+ * Ps is a selective parameter.
+ */
+static void tty3270_escape_sequence(struct tty3270 *tp, char ch)
+{
+ enum { ES_NORMAL, ES_ESC, ES_SQUARE, ES_PAREN, ES_GETPARS };
+
+ if (tp->esc_state == ES_NORMAL) {
+ if (ch == 0x1b)
+ /* Starting new escape sequence. */
+ tp->esc_state = ES_ESC;
+ return;
+ }
+ if (tp->esc_state == ES_ESC) {
+ tp->esc_state = ES_NORMAL;
+ switch (ch) {
+ case '[':
+ tp->esc_state = ES_SQUARE;
+ break;
+ case '(':
+ tp->esc_state = ES_PAREN;
+ break;
+ case 'E':
+ tty3270_cr(tp);
+ tty3270_lf(tp);
+ break;
+ case 'M':
+ tty3270_ri(tp);
+ break;
+ case 'D':
+ tty3270_lf(tp);
+ break;
+ case 'Z': /* Respond ID. */
+ kbd_puts_queue(&tp->port, "\033[?6c");
+ break;
+ case '7': /* Save cursor position. */
+ tp->saved_cx = tp->cx;
+ tp->saved_cy = tp->cy;
+ tp->saved_attributes = tp->attributes;
+ break;
+ case '8': /* Restore cursor position. */
+ tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
+ tp->attributes = tp->saved_attributes;
+ break;
+ case 'c': /* Reset terminal. */
+ tp->cx = 0;
+ tp->cy = 0;
+ tp->saved_cx = 0;
+ tp->saved_cy = 0;
+ tty3270_reset_attributes(&tp->attributes);
+ tty3270_reset_attributes(&tp->saved_attributes);
+ tty3270_erase_display(tp, 2);
+ break;
+ }
+ return;
+ }
+
+ switch (tp->esc_state) {
+ case ES_PAREN:
+ tp->esc_state = ES_NORMAL;
+ switch (ch) {
+ case 'B':
+ tp->attributes.alternate_charset = 0;
+ break;
+ case '0':
+ tp->attributes.alternate_charset = 1;
+ break;
+ }
+ return;
+ case ES_SQUARE:
+ tp->esc_state = ES_GETPARS;
+ memset(tp->esc_par, 0, sizeof(tp->esc_par));
+ tp->esc_npar = 0;
+ tp->esc_ques = (ch == '?');
+ if (tp->esc_ques)
+ return;
+ fallthrough;
+ case ES_GETPARS:
+ if (ch == ';' && tp->esc_npar < ESCAPE_NPAR - 1) {
+ tp->esc_npar++;
+ return;
+ }
+ if (ch >= '0' && ch <= '9') {
+ tp->esc_par[tp->esc_npar] *= 10;
+ tp->esc_par[tp->esc_npar] += ch - '0';
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ tp->esc_state = ES_NORMAL;
+ if (ch == 'n' && !tp->esc_ques) {
+ if (tp->esc_par[0] == 5) /* Status report. */
+ kbd_puts_queue(&tp->port, "\033[0n");
+ else if (tp->esc_par[0] == 6) { /* Cursor report. */
+ char buf[40];
+
+ sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
+ kbd_puts_queue(&tp->port, buf);
+ }
+ return;
+ }
+ if (tp->esc_ques)
+ return;
+ switch (ch) {
+ case 'm':
+ tty3270_set_attributes(tp);
+ break;
+ case 'H': /* Set cursor position. */
+ case 'f':
+ tty3270_goto_xy(tp, tty3270_getpar(tp, 1) - 1,
+ tty3270_getpar(tp, 0) - 1);
+ break;
+ case 'd': /* Set y position. */
+ tty3270_goto_xy(tp, tp->cx, tty3270_getpar(tp, 0) - 1);
+ break;
+ case 'A': /* Cursor up. */
+ case 'F':
+ tty3270_goto_xy(tp, tp->cx, tp->cy - tty3270_getpar(tp, 0));
+ break;
+ case 'B': /* Cursor down. */
+ case 'e':
+ case 'E':
+ tty3270_goto_xy(tp, tp->cx, tp->cy + tty3270_getpar(tp, 0));
+ break;
+ case 'C': /* Cursor forward. */
+ case 'a':
+ tty3270_goto_xy(tp, tp->cx + tty3270_getpar(tp, 0), tp->cy);
+ break;
+ case 'D': /* Cursor backward. */
+ tty3270_goto_xy(tp, tp->cx - tty3270_getpar(tp, 0), tp->cy);
+ break;
+ case 'G': /* Set x position. */
+ case '`':
+ tty3270_goto_xy(tp, tty3270_getpar(tp, 0), tp->cy);
+ break;
+ case 'X': /* Erase Characters. */
+ tty3270_erase_characters(tp, tty3270_getpar(tp, 0));
+ break;
+ case 'J': /* Erase display. */
+ tty3270_erase_display(tp, tp->esc_par[0]);
+ break;
+ case 'K': /* Erase line. */
+ tty3270_erase_line(tp, tp->esc_par[0]);
+ break;
+ case 'P': /* Delete characters. */
+ tty3270_delete_characters(tp, tty3270_getpar(tp, 0));
+ break;
+ case '@': /* Insert characters. */
+ tty3270_insert_characters(tp, tty3270_getpar(tp, 0));
+ break;
+ case 's': /* Save cursor position. */
+ tp->saved_cx = tp->cx;
+ tp->saved_cy = tp->cy;
+ tp->saved_attributes = tp->attributes;
+ break;
+ case 'u': /* Restore cursor position. */
+ tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
+ tp->attributes = tp->saved_attributes;
+ break;
+ }
+}
+
+/*
+ * String write routine for 3270 ttys
+ */
+static void tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ int i_msg, i;
+
+ spin_lock_irq(&tp->view.lock);
+ for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) {
+ if (tp->esc_state != 0) {
+ /* Continue escape sequence. */
+ tty3270_escape_sequence(tp, buf[i_msg]);
+ continue;
+ }
+
+ switch (buf[i_msg]) {
+ case 0x00:
+ break;
+ case 0x07: /* '\a' -- Alarm */
+ tp->wcc |= TW_PLUSALARM;
+ break;
+ case 0x08: /* Backspace. */
+ if (tp->cx > 0) {
+ tp->cx--;
+ tty3270_put_character(tp, ' ');
+ }
+ break;
+ case 0x09: /* '\t' -- Tabulate */
+ for (i = tp->cx % 8; i < 8; i++) {
+ if (tp->cx >= tp->view.cols) {
+ tty3270_cr(tp);
+ tty3270_lf(tp);
+ break;
+ }
+ tty3270_put_character(tp, ' ');
+ tp->cx++;
+ }
+ break;
+ case 0x0a: /* '\n' -- New Line */
+ tty3270_cr(tp);
+ tty3270_lf(tp);
+ break;
+ case 0x0c: /* '\f' -- Form Feed */
+ tty3270_erase_display(tp, 2);
+ tp->cx = 0;
+ tp->cy = 0;
+ break;
+ case 0x0d: /* '\r' -- Carriage Return */
+ tp->cx = 0;
+ break;
+ case 0x0e:
+ tp->attributes.alternate_charset = 1;
+ break;
+ case 0x0f: /* SuSE "exit alternate mode" */
+ tp->attributes.alternate_charset = 0;
+ break;
+ case 0x1b: /* Start escape sequence. */
+ tty3270_escape_sequence(tp, buf[i_msg]);
+ break;
+ default: /* Insert normal character. */
+ if (tp->cx >= tp->view.cols) {
+ tty3270_cr(tp);
+ tty3270_lf(tp);
+ }
+ tty3270_put_character(tp, buf[i_msg]);
+ tp->cx++;
+ break;
+ }
+ }
+ /* Setup timer to update display after 1/10 second */
+ tp->update_flags |= TTY_UPDATE_LINES;
+ if (!timer_pending(&tp->timer))
+ tty3270_set_timer(tp, msecs_to_jiffies(100));
+
+ spin_unlock_irq(&tp->view.lock);
+}
+
+/*
+ * String write routine for 3270 ttys
+ */
+static int tty3270_write(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return 0;
+ if (tp->char_count > 0) {
+ tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
+ tp->char_count = 0;
+ }
+ tty3270_do_write(tp, tty, buf, count);
+ return count;
+}
+
+/*
+ * Put single characters to the ttys character buffer
+ */
+static int tty3270_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE)
+ return 0;
+ tp->char_buf[tp->char_count++] = ch;
+ return 1;
+}
+
+/*
+ * Flush all characters from the ttys characeter buffer put there
+ * by tty3270_put_char.
+ */
+static void tty3270_flush_chars(struct tty_struct *tty)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return;
+ if (tp->char_count > 0) {
+ tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
+ tp->char_count = 0;
}
- /* Replace cline with allocated line s and reset cline. */
- list_add(&s->list, &cp->cline->list);
- list_del_init(&cp->cline->list);
- if (!list_empty(&cp->cline->update)) {
- list_add(&s->update, &cp->cline->update);
- list_del_init(&cp->cline->update);
+}
+
+/*
+ * Check for visible/invisible input switches
+ */
+static void tty3270_set_termios(struct tty_struct *tty, const struct ktermios *old)
+{
+ struct tty3270 *tp;
+ int new;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return;
+ spin_lock_irq(&tp->view.lock);
+ if (L_ICANON(tty)) {
+ new = L_ECHO(tty) ? TF_INPUT : TF_INPUTN;
+ if (new != tp->inattr) {
+ tp->inattr = new;
+ tty3270_update_prompt(tp, "");
+ tty3270_set_timer(tp, 1);
+ }
}
- cp->cline->len = 0;
+ spin_unlock_irq(&tp->view.lock);
}
/*
- * Write a string to the 3270 console
+ * Disable reading from a 3270 tty
*/
+static void tty3270_throttle(struct tty_struct *tty)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return;
+ tp->throttle = 1;
+}
+
+/*
+ * Enable reading from a 3270 tty
+ */
+static void tty3270_unthrottle(struct tty_struct *tty)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return;
+ tp->throttle = 0;
+ if (tp->attn)
+ tty3270_issue_read(tp, 1);
+}
+
+/*
+ * Hang up the tty device.
+ */
+static void tty3270_hangup(struct tty_struct *tty)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return;
+ spin_lock_irq(&tp->view.lock);
+ tp->cx = 0;
+ tp->cy = 0;
+ tp->saved_cx = 0;
+ tp->saved_cy = 0;
+ tty3270_reset_attributes(&tp->attributes);
+ tty3270_reset_attributes(&tp->saved_attributes);
+ tty3270_blank_screen(tp);
+ tp->update_flags = TTY_UPDATE_ALL;
+ spin_unlock_irq(&tp->view.lock);
+ tty3270_set_timer(tp, 1);
+}
+
+static void tty3270_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+}
+
+static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd,
+ unsigned long arg)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return -ENODEV;
+ if (tty_io_error(tty))
+ return -EIO;
+ return kbd_ioctl(tp->kbd, cmd, arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long tty3270_compat_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg)
+{
+ struct tty3270 *tp;
+
+ tp = tty->driver_data;
+ if (!tp)
+ return -ENODEV;
+ if (tty_io_error(tty))
+ return -EIO;
+ return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static const struct tty_operations tty3270_ops = {
+ .install = tty3270_install,
+ .cleanup = tty3270_cleanup,
+ .open = tty3270_open,
+ .close = tty3270_close,
+ .write = tty3270_write,
+ .put_char = tty3270_put_char,
+ .flush_chars = tty3270_flush_chars,
+ .write_room = tty3270_write_room,
+ .throttle = tty3270_throttle,
+ .unthrottle = tty3270_unthrottle,
+ .hangup = tty3270_hangup,
+ .wait_until_sent = tty3270_wait_until_sent,
+ .ioctl = tty3270_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = tty3270_compat_ioctl,
+#endif
+ .set_termios = tty3270_set_termios
+};
+
+static void tty3270_create_cb(int minor)
+{
+ tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
+}
+
+static void tty3270_destroy_cb(int minor)
+{
+ tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
+}
+
+static struct raw3270_notifier tty3270_notifier = {
+ .create = tty3270_create_cb,
+ .destroy = tty3270_destroy_cb,
+};
+
+/*
+ * 3270 tty registration code called from tty_init().
+ * Most kernel services (incl. kmalloc) are available at this poimt.
+ */
+static int __init tty3270_init(void)
+{
+ struct tty_driver *driver;
+ int ret;
+
+ driver = tty_alloc_driver(RAW3270_MAXDEVS,
+ TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV |
+ TTY_DRIVER_RESET_TERMIOS);
+ if (IS_ERR(driver))
+ return PTR_ERR(driver);
+
+ /*
+ * Initialize the tty_driver structure
+ * Entries in tty3270_driver that are NOT initialized:
+ * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
+ */
+ driver->driver_name = "tty3270";
+ driver->name = "3270/tty";
+ driver->major = IBM_TTY3270_MAJOR;
+ driver->minor_start = RAW3270_FIRSTMINOR;
+ driver->name_base = RAW3270_FIRSTMINOR;
+ driver->type = TTY_DRIVER_TYPE_SYSTEM;
+ driver->subtype = SYSTEM_TYPE_TTY;
+ driver->init_termios = tty_std_termios;
+ tty_set_operations(driver, &tty3270_ops);
+ ret = tty_register_driver(driver);
+ if (ret) {
+ tty_driver_kref_put(driver);
+ return ret;
+ }
+ tty3270_driver = driver;
+ raw3270_register_notifier(&tty3270_notifier);
+ return 0;
+}
+
+static void __exit tty3270_exit(void)
+{
+ struct tty_driver *driver;
+
+ raw3270_unregister_notifier(&tty3270_notifier);
+ driver = tty3270_driver;
+ tty3270_driver = NULL;
+ tty_unregister_driver(driver);
+ tty_driver_kref_put(driver);
+ tty3270_del_views();
+}
+
+#if IS_ENABLED(CONFIG_TN3270_CONSOLE)
+
+static struct tty3270 *condev;
+
static void
con3270_write(struct console *co, const char *str, unsigned int count)
{
- struct con3270 *cp;
+ struct tty3270 *tp = co->data;
unsigned long flags;
- unsigned char c;
+ char c;
- cp = condev;
- spin_lock_irqsave(&cp->view.lock, flags);
- while (count-- > 0) {
+ spin_lock_irqsave(&tp->view.lock, flags);
+ while (count--) {
c = *str++;
- if (cp->cline->len == 0)
- con3270_cline_add(cp);
- if (c != '\n')
- con3270_cline_insert(cp, c);
- if (c == '\n' || cp->cline->len >= cp->view.cols)
- con3270_cline_end(cp);
+ if (c == 0x0a) {
+ tty3270_cr(tp);
+ tty3270_lf(tp);
+ } else {
+ if (tp->cx >= tp->view.cols) {
+ tty3270_cr(tp);
+ tty3270_lf(tp);
+ }
+ tty3270_put_character(tp, c);
+ tp->cx++;
+ }
}
- /* Setup timer to output current console buffer after 1/10 second */
- cp->nr_up = 0;
- if (cp->view.dev && !timer_pending(&cp->timer))
- con3270_set_timer(cp, HZ/10);
- spin_unlock_irqrestore(&cp->view.lock,flags);
+ spin_unlock_irqrestore(&tp->view.lock, flags);
}
static struct tty_driver *
@@ -522,14 +2079,11 @@ con3270_device(struct console *c, int *index)
return tty3270_driver;
}
-/*
- * Wait for end of write request.
- */
static void
-con3270_wait_write(struct con3270 *cp)
+con3270_wait_write(struct tty3270 *tp)
{
- while (!cp->write) {
- raw3270_wait_cons_dev(cp->view.dev);
+ while (!tp->write) {
+ raw3270_wait_cons_dev(tp->view.dev);
barrier();
}
}
@@ -545,28 +2099,30 @@ con3270_wait_write(struct con3270 *cp)
static int con3270_notify(struct notifier_block *self,
unsigned long event, void *data)
{
- struct con3270 *cp;
+ struct tty3270 *tp;
unsigned long flags;
+ int rc;
- cp = condev;
- if (!cp->view.dev)
+ tp = condev;
+ if (!tp->view.dev)
return NOTIFY_DONE;
- if (!raw3270_view_lock_unavailable(&cp->view))
- raw3270_activate_view(&cp->view);
- if (!spin_trylock_irqsave(&cp->view.lock, flags))
+ if (!raw3270_view_lock_unavailable(&tp->view)) {
+ rc = raw3270_activate_view(&tp->view);
+ if (rc)
+ return NOTIFY_DONE;
+ }
+ if (!spin_trylock_irqsave(&tp->view.lock, flags))
return NOTIFY_DONE;
- con3270_wait_write(cp);
- cp->nr_up = 0;
- con3270_rebuild_update(cp);
- con3270_update_status(cp);
- while (cp->update_flags != 0) {
- spin_unlock_irqrestore(&cp->view.lock, flags);
- con3270_update(&cp->timer);
- spin_lock_irqsave(&cp->view.lock, flags);
- con3270_wait_write(cp);
- }
- spin_unlock_irqrestore(&cp->view.lock, flags);
-
+ con3270_wait_write(tp);
+ tp->nr_up = 0;
+ tp->update_flags = TTY_UPDATE_ALL;
+ while (tp->update_flags != 0) {
+ spin_unlock_irqrestore(&tp->view.lock, flags);
+ tty3270_update(&tp->timer);
+ spin_lock_irqsave(&tp->view.lock, flags);
+ con3270_wait_write(tp);
+ }
+ spin_unlock_irqrestore(&tp->view.lock, flags);
return NOTIFY_DONE;
}
@@ -580,9 +2136,6 @@ static struct notifier_block on_reboot_nb = {
.priority = INT_MIN + 1, /* run the callback late */
};
-/*
- * The console structure for the 3270 console
- */
static struct console con3270 = {
.name = "tty3270",
.write = con3270_write,
@@ -590,15 +2143,13 @@ static struct console con3270 = {
.flags = CON_PRINTBUFFER,
};
-/*
- * 3270 console initialization code called from console_init().
- */
static int __init
con3270_init(void)
{
+ struct raw3270_view *view;
struct raw3270 *rp;
- void *cbuf;
- int i;
+ struct tty3270 *tp;
+ int rc;
/* Check if 3270 is to be the console */
if (!CONSOLE_IS_3270)
@@ -614,38 +2165,28 @@ con3270_init(void)
if (IS_ERR(rp))
return PTR_ERR(rp);
- condev = kzalloc(sizeof(struct con3270), GFP_KERNEL | GFP_DMA);
- if (!condev)
- return -ENOMEM;
- condev->view.dev = rp;
-
- condev->read = raw3270_request_alloc(0);
- condev->read->callback = con3270_read_callback;
- condev->read->callback_data = condev;
- condev->write = raw3270_request_alloc(CON3270_OUTPUT_BUFFER_SIZE);
- condev->kreset = raw3270_request_alloc(1);
-
- INIT_LIST_HEAD(&condev->lines);
- INIT_LIST_HEAD(&condev->update);
- timer_setup(&condev->timer, con3270_update, 0);
- tasklet_init(&condev->readlet, con3270_read_tasklet,
- (unsigned long) condev->read);
-
- raw3270_add_view(&condev->view, &con3270_fn, 1, RAW3270_VIEW_LOCK_IRQ);
-
- INIT_LIST_HEAD(&condev->freemem);
- for (i = 0; i < CON3270_STRING_PAGES; i++) {
- cbuf = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
- add_string_memory(&condev->freemem, cbuf, PAGE_SIZE);
- }
- condev->cline = alloc_string(&condev->freemem, condev->view.cols);
- condev->cline->len = 0;
- con3270_create_status(condev);
- condev->input = alloc_string(&condev->freemem, 80);
+ /* Check if the tty3270 is already there. */
+ view = raw3270_find_view(&tty3270_fn, RAW3270_FIRSTMINOR);
+ if (IS_ERR(view)) {
+ rc = tty3270_create_view(0, &tp);
+ if (rc)
+ return rc;
+ } else {
+ tp = container_of(view, struct tty3270, view);
+ tp->inattr = TF_INPUT;
+ }
+ con3270.data = tp;
+ condev = tp;
atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
register_reboot_notifier(&on_reboot_nb);
register_console(&con3270);
return 0;
}
-
console_initcall(con3270_init);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR);
+
+module_init(tty3270_init);
+module_exit(tty3270_exit);
diff --git a/drivers/s390/char/diag_ftp.c b/drivers/s390/char/diag_ftp.c
index 36bbd6b6e210..65c7f2d565d8 100644
--- a/drivers/s390/char/diag_ftp.c
+++ b/drivers/s390/char/diag_ftp.c
@@ -159,8 +159,8 @@ ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
goto out;
}
- len = strlcpy(ldfpl->fident, ftp->fname, sizeof(ldfpl->fident));
- if (len >= HMCDRV_FTP_FIDENT_MAX) {
+ len = strscpy(ldfpl->fident, ftp->fname, sizeof(ldfpl->fident));
+ if (len < 0) {
len = -EINVAL;
goto out_free;
}
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 4c4683d8784a..4f26b0a55620 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include <linux/types.h>
+#include <uapi/asm/fs3270.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/ebcdic.h>
@@ -44,14 +45,12 @@ struct fs3270 {
static DEFINE_MUTEX(fs3270_mutex);
-static void
-fs3270_wake_up(struct raw3270_request *rq, void *data)
+static void fs3270_wake_up(struct raw3270_request *rq, void *data)
{
- wake_up((wait_queue_head_t *) data);
+ wake_up((wait_queue_head_t *)data);
}
-static inline int
-fs3270_working(struct fs3270 *fp)
+static inline int fs3270_working(struct fs3270 *fp)
{
/*
* The fullscreen view is in working order if the view
@@ -60,13 +59,12 @@ fs3270_working(struct fs3270 *fp)
return fp->active && raw3270_request_final(fp->init);
}
-static int
-fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
+static int fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
{
struct fs3270 *fp;
int rc;
- fp = (struct fs3270 *) view;
+ fp = (struct fs3270 *)view;
rq->callback = fs3270_wake_up;
rq->callback_data = &fp->wait;
@@ -90,22 +88,20 @@ fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
/*
* Switch to the fullscreen view.
*/
-static void
-fs3270_reset_callback(struct raw3270_request *rq, void *data)
+static void fs3270_reset_callback(struct raw3270_request *rq, void *data)
{
struct fs3270 *fp;
- fp = (struct fs3270 *) rq->view;
+ fp = (struct fs3270 *)rq->view;
raw3270_request_reset(rq);
wake_up(&fp->wait);
}
-static void
-fs3270_restore_callback(struct raw3270_request *rq, void *data)
+static void fs3270_restore_callback(struct raw3270_request *rq, void *data)
{
struct fs3270 *fp;
- fp = (struct fs3270 *) rq->view;
+ fp = (struct fs3270 *)rq->view;
if (rq->rc != 0 || rq->rescnt != 0) {
if (fp->fs_pid)
kill_pid(fp->fs_pid, SIGHUP, 1);
@@ -115,29 +111,31 @@ fs3270_restore_callback(struct raw3270_request *rq, void *data)
wake_up(&fp->wait);
}
-static int
-fs3270_activate(struct raw3270_view *view)
+static int fs3270_activate(struct raw3270_view *view)
{
struct fs3270 *fp;
char *cp;
int rc;
- fp = (struct fs3270 *) view;
+ fp = (struct fs3270 *)view;
/* If an old init command is still running just return. */
if (!raw3270_request_final(fp->init))
return 0;
+ raw3270_request_set_cmd(fp->init, TC_EWRITEA);
+ raw3270_request_set_idal(fp->init, fp->rdbuf);
+ fp->init->rescnt = 0;
+ cp = fp->rdbuf->data[0];
if (fp->rdbuf_size == 0) {
/* No saved buffer. Just clear the screen. */
- raw3270_request_set_cmd(fp->init, TC_EWRITEA);
+ fp->init->ccw.count = 1;
fp->init->callback = fs3270_reset_callback;
+ cp[0] = 0;
} else {
/* Restore fullscreen buffer saved by fs3270_deactivate. */
- raw3270_request_set_cmd(fp->init, TC_EWRITEA);
- raw3270_request_set_idal(fp->init, fp->rdbuf);
fp->init->ccw.count = fp->rdbuf_size;
- cp = fp->rdbuf->data[0];
+ fp->init->callback = fs3270_restore_callback;
cp[0] = TW_KR;
cp[1] = TO_SBA;
cp[2] = cp[6];
@@ -146,10 +144,9 @@ fs3270_activate(struct raw3270_view *view)
cp[5] = TO_SBA;
cp[6] = 0x40;
cp[7] = 0x40;
- fp->init->rescnt = 0;
- fp->init->callback = fs3270_restore_callback;
}
- rc = fp->init->rc = raw3270_start_locked(view, fp->init);
+ rc = raw3270_start_locked(view, fp->init);
+ fp->init->rc = rc;
if (rc)
fp->init->callback(fp->init, NULL);
else
@@ -160,12 +157,11 @@ fs3270_activate(struct raw3270_view *view)
/*
* Shutdown fullscreen view.
*/
-static void
-fs3270_save_callback(struct raw3270_request *rq, void *data)
+static void fs3270_save_callback(struct raw3270_request *rq, void *data)
{
struct fs3270 *fp;
- fp = (struct fs3270 *) rq->view;
+ fp = (struct fs3270 *)rq->view;
/* Correct idal buffer element 0 address. */
fp->rdbuf->data[0] -= 5;
@@ -181,18 +177,18 @@ fs3270_save_callback(struct raw3270_request *rq, void *data)
if (fp->fs_pid)
kill_pid(fp->fs_pid, SIGHUP, 1);
fp->rdbuf_size = 0;
- } else
+ } else {
fp->rdbuf_size = fp->rdbuf->size - rq->rescnt;
+ }
raw3270_request_reset(rq);
wake_up(&fp->wait);
}
-static void
-fs3270_deactivate(struct raw3270_view *view)
+static void fs3270_deactivate(struct raw3270_view *view)
{
struct fs3270 *fp;
- fp = (struct fs3270 *) view;
+ fp = (struct fs3270 *)view;
fp->active = 0;
/* If an old init command is still running just return. */
@@ -218,8 +214,8 @@ fs3270_deactivate(struct raw3270_view *view)
fp->init->callback(fp->init, NULL);
}
-static void
-fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
+static void fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq,
+ struct irb *irb)
{
/* Handle ATTN. Set indication and wake waiters for attention. */
if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
@@ -239,14 +235,14 @@ fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
/*
* Process reads from fullscreen 3270.
*/
-static ssize_t
-fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
+static ssize_t fs3270_read(struct file *filp, char __user *data,
+ size_t count, loff_t *off)
{
struct fs3270 *fp;
struct raw3270_request *rq;
struct idal_buffer *ib;
ssize_t rc;
-
+
if (count == 0 || count > 65535)
return -EINVAL;
fp = filp->private_data;
@@ -271,12 +267,12 @@ fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
rc = -EFAULT;
else
rc = count;
-
}
}
raw3270_request_free(rq);
- } else
+ } else {
rc = PTR_ERR(rq);
+ }
idal_buffer_free(ib);
return rc;
}
@@ -284,8 +280,8 @@ fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
/*
* Process writes to fullscreen 3270.
*/
-static ssize_t
-fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off)
+static ssize_t fs3270_write(struct file *filp, const char __user *data,
+ size_t count, loff_t *off)
{
struct fs3270 *fp;
struct raw3270_request *rq;
@@ -310,11 +306,13 @@ fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *o
rc = fs3270_do_io(&fp->view, rq);
if (rc == 0)
rc = count - rq->rescnt;
- } else
+ } else {
rc = -EFAULT;
+ }
raw3270_request_free(rq);
- } else
+ } else {
rc = PTR_ERR(rq);
+ }
idal_buffer_free(ib);
return rc;
}
@@ -322,8 +320,7 @@ fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *o
/*
* process ioctl commands for the tube driver
*/
-static long
-fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+static long fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
char __user *argp;
struct fs3270 *fp;
@@ -370,12 +367,11 @@ fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/*
* Allocate fs3270 structure.
*/
-static struct fs3270 *
-fs3270_alloc_view(void)
+static struct fs3270 *fs3270_alloc_view(void)
{
struct fs3270 *fp;
- fp = kzalloc(sizeof(struct fs3270),GFP_KERNEL);
+ fp = kzalloc(sizeof(*fp), GFP_KERNEL);
if (!fp)
return ERR_PTR(-ENOMEM);
fp->init = raw3270_request_alloc(0);
@@ -389,27 +385,25 @@ fs3270_alloc_view(void)
/*
* Free fs3270 structure.
*/
-static void
-fs3270_free_view(struct raw3270_view *view)
+static void fs3270_free_view(struct raw3270_view *view)
{
struct fs3270 *fp;
- fp = (struct fs3270 *) view;
+ fp = (struct fs3270 *)view;
if (fp->rdbuf)
idal_buffer_free(fp->rdbuf);
- raw3270_request_free(((struct fs3270 *) view)->init);
+ raw3270_request_free(((struct fs3270 *)view)->init);
kfree(view);
}
/*
* Unlink fs3270 data structure from filp.
*/
-static void
-fs3270_release(struct raw3270_view *view)
+static void fs3270_release(struct raw3270_view *view)
{
struct fs3270 *fp;
- fp = (struct fs3270 *) view;
+ fp = (struct fs3270 *)view;
if (fp->fs_pid)
kill_pid(fp->fs_pid, SIGHUP, 1);
}
@@ -418,7 +412,7 @@ fs3270_release(struct raw3270_view *view)
static struct raw3270_fn fs3270_fn = {
.activate = fs3270_activate,
.deactivate = fs3270_deactivate,
- .intv = (void *) fs3270_irq,
+ .intv = (void *)fs3270_irq,
.release = fs3270_release,
.free = fs3270_free_view
};
@@ -426,8 +420,7 @@ static struct raw3270_fn fs3270_fn = {
/*
* This routine is called whenever a 3270 fullscreen device is opened.
*/
-static int
-fs3270_open(struct inode *inode, struct file *filp)
+static int fs3270_open(struct inode *inode, struct file *filp)
{
struct fs3270 *fp;
struct idal_buffer *ib;
@@ -439,6 +432,7 @@ fs3270_open(struct inode *inode, struct file *filp)
/* Check for minor 0 multiplexer. */
if (minor == 0) {
struct tty_struct *tty = get_current_tty();
+
if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
tty_kref_put(tty);
return -ENODEV;
@@ -448,7 +442,7 @@ fs3270_open(struct inode *inode, struct file *filp)
}
mutex_lock(&fs3270_mutex);
/* Check if some other program is already using fullscreen mode. */
- fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
+ fp = (struct fs3270 *)raw3270_find_view(&fs3270_fn, minor);
if (!IS_ERR(fp)) {
raw3270_put_view(&fp->view);
rc = -EBUSY;
@@ -471,7 +465,7 @@ fs3270_open(struct inode *inode, struct file *filp)
}
/* Allocate idal-buffer. */
- ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0);
+ ib = idal_buffer_alloc(2 * fp->view.rows * fp->view.cols + 5, 0);
if (IS_ERR(ib)) {
raw3270_put_view(&fp->view);
raw3270_del_view(&fp->view);
@@ -497,8 +491,7 @@ out:
* This routine is called when the 3270 tty is closed. We wait
* for the remaining request to be completed. Then we clean up.
*/
-static int
-fs3270_close(struct inode *inode, struct file *filp)
+static int fs3270_close(struct inode *inode, struct file *filp)
{
struct fs3270 *fp;
@@ -538,8 +531,7 @@ static void fs3270_destroy_cb(int minor)
__unregister_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub");
}
-static struct raw3270_notifier fs3270_notifier =
-{
+static struct raw3270_notifier fs3270_notifier = {
.create = fs3270_create_cb,
.destroy = fs3270_destroy_cb,
};
@@ -547,8 +539,7 @@ static struct raw3270_notifier fs3270_notifier =
/*
* 3270 fullscreen driver initialization.
*/
-static int __init
-fs3270_init(void)
+static int __init fs3270_init(void)
{
int rc;
@@ -561,8 +552,7 @@ fs3270_init(void)
return 0;
}
-static void __exit
-fs3270_exit(void)
+static void __exit fs3270_exit(void)
{
raw3270_unregister_notifier(&fs3270_notifier);
device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, 0));
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index fb3f62ac8be4..09d7570d3b7d 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -30,6 +30,7 @@
#include <linux/mutex.h>
struct class *class3270;
+EXPORT_SYMBOL(class3270);
/* The main 3270 data structure. */
struct raw3270 {
@@ -37,7 +38,8 @@ struct raw3270 {
struct ccw_device *cdev;
int minor;
- short model, rows, cols;
+ int model, rows, cols;
+ int old_model, old_rows, old_cols;
unsigned int state;
unsigned long flags;
@@ -54,6 +56,7 @@ struct raw3270 {
struct raw3270_request init_readpart;
struct raw3270_request init_readmod;
unsigned char init_data[256];
+ struct work_struct resize_work;
};
/* raw3270->state */
@@ -89,6 +92,7 @@ module_param(tubxcorrect, bool, 0);
* Wait queue for device init/delete, view delete.
*/
DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
+EXPORT_SYMBOL(raw3270_wait_queue);
static void __raw3270_disconnect(struct raw3270 *rp);
@@ -111,9 +115,15 @@ static inline int raw3270_state_ready(struct raw3270 *rp)
return rp->state == RAW3270_STATE_READY;
}
-void
-raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
+void raw3270_buffer_address(struct raw3270 *rp, char *cp, int x, int y)
{
+ int addr;
+
+ if (x < 0)
+ x = max_t(int, 0, rp->view->cols + x);
+ if (y < 0)
+ y = max_t(int, 0, rp->view->rows + y);
+ addr = (y * rp->view->cols) + x;
if (test_bit(RAW3270_FLAGS_14BITADDR, &rp->flags)) {
cp[0] = (addr >> 8) & 0x3f;
cp[1] = addr & 0xff;
@@ -122,17 +132,17 @@ raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
cp[1] = raw3270_ebcgraf[addr & 0x3f];
}
}
+EXPORT_SYMBOL(raw3270_buffer_address);
/*
* Allocate a new 3270 ccw request
*/
-struct raw3270_request *
-raw3270_request_alloc(size_t size)
+struct raw3270_request *raw3270_request_alloc(size_t size)
{
struct raw3270_request *rq;
/* Allocate request structure */
- rq = kzalloc(sizeof(struct raw3270_request), GFP_KERNEL | GFP_DMA);
+ rq = kzalloc(sizeof(*rq), GFP_KERNEL | GFP_DMA);
if (!rq)
return ERR_PTR(-ENOMEM);
@@ -155,46 +165,48 @@ raw3270_request_alloc(size_t size)
return rq;
}
+EXPORT_SYMBOL(raw3270_request_alloc);
/*
* Free 3270 ccw request
*/
-void
-raw3270_request_free (struct raw3270_request *rq)
+void raw3270_request_free(struct raw3270_request *rq)
{
kfree(rq->buffer);
kfree(rq);
}
+EXPORT_SYMBOL(raw3270_request_free);
/*
* Reset request to initial state.
*/
-void
-raw3270_request_reset(struct raw3270_request *rq)
+int raw3270_request_reset(struct raw3270_request *rq)
{
- BUG_ON(!list_empty(&rq->list));
+ if (WARN_ON_ONCE(!list_empty(&rq->list)))
+ return -EBUSY;
rq->ccw.cmd_code = 0;
rq->ccw.count = 0;
rq->ccw.cda = __pa(rq->buffer);
rq->ccw.flags = CCW_FLAG_SLI;
rq->rescnt = 0;
rq->rc = 0;
+ return 0;
}
+EXPORT_SYMBOL(raw3270_request_reset);
/*
* Set command code to ccw of a request.
*/
-void
-raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd)
+void raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd)
{
rq->ccw.cmd_code = cmd;
}
+EXPORT_SYMBOL(raw3270_request_set_cmd);
/*
* Add data fragment to output buffer.
*/
-int
-raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
+int raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
{
if (size + rq->ccw.count > rq->size)
return -E2BIG;
@@ -202,35 +214,35 @@ raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
rq->ccw.count += size;
return 0;
}
+EXPORT_SYMBOL(raw3270_request_add_data);
/*
* Set address/length pair to ccw of a request.
*/
-void
-raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
+void raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
{
rq->ccw.cda = __pa(data);
rq->ccw.count = size;
}
+EXPORT_SYMBOL(raw3270_request_set_data);
/*
* Set idal buffer to ccw of a request.
*/
-void
-raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
+void raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
{
rq->ccw.cda = __pa(ib->data);
rq->ccw.count = ib->size;
rq->ccw.flags |= CCW_FLAG_IDA;
}
+EXPORT_SYMBOL(raw3270_request_set_idal);
/*
* Add the request to the request queue, try to start it if the
* 3270 device is idle. Return without waiting for end of i/o.
*/
-static int
-__raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
- struct raw3270_request *rq)
+static int __raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
+ struct raw3270_request *rq)
{
rq->view = view;
raw3270_get_view(view);
@@ -238,7 +250,7 @@ __raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
!test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
/* No other requests are on the queue. Start this one. */
rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
- (unsigned long) rq, 0, 0);
+ (unsigned long)rq, 0, 0);
if (rq->rc) {
raw3270_put_view(view);
return rq->rc;
@@ -248,16 +260,14 @@ __raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
return 0;
}
-int
-raw3270_view_active(struct raw3270_view *view)
+int raw3270_view_active(struct raw3270_view *view)
{
struct raw3270 *rp = view->dev;
return rp && rp->view == view;
}
-int
-raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
+int raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
{
unsigned long flags;
struct raw3270 *rp;
@@ -274,9 +284,25 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
return rc;
}
+EXPORT_SYMBOL(raw3270_start);
-int
-raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
+int raw3270_start_request(struct raw3270_view *view, struct raw3270_request *rq,
+ int cmd, void *data, size_t len)
+{
+ int rc;
+
+ rc = raw3270_request_reset(rq);
+ if (rc)
+ return rc;
+ raw3270_request_set_cmd(rq, cmd);
+ rc = raw3270_request_add_data(rq, data, len);
+ if (rc)
+ return rc;
+ return raw3270_start(view, rq);
+}
+EXPORT_SYMBOL(raw3270_start_request);
+
+int raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
{
struct raw3270 *rp;
int rc;
@@ -290,9 +316,9 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
rc = __raw3270_start(rp, view, rq);
return rc;
}
+EXPORT_SYMBOL(raw3270_start_locked);
-int
-raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
+int raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
{
struct raw3270 *rp;
@@ -302,12 +328,12 @@ raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
list_add_tail(&rq->list, &rp->req_queue);
return 0;
}
+EXPORT_SYMBOL(raw3270_start_irq);
/*
* 3270 interrupt routine, called from the ccw_device layer
*/
-static void
-raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
+static void raw3270_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
{
struct raw3270 *rp;
struct raw3270_view *view;
@@ -316,7 +342,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
rp = dev_get_drvdata(&cdev->dev);
if (!rp)
return;
- rq = (struct raw3270_request *) intparm;
+ rq = (struct raw3270_request *)intparm;
view = rq ? rq->view : rp->view;
if (!IS_ERR(irb)) {
@@ -357,9 +383,9 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
* started successful.
*/
while (!list_empty(&rp->req_queue)) {
- rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
+ rq = list_entry(rp->req_queue.next, struct raw3270_request, list);
rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
- (unsigned long) rq, 0, 0);
+ (unsigned long)rq, 0, 0);
if (rq->rc == 0)
break;
/* Start failed. Remove request and do callback. */
@@ -399,7 +425,7 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
char ymin;
char xmax;
char ymax;
- } __attribute__ ((packed)) uab;
+ } __packed uab;
struct { /* Alternate Usable Area Self-Defining Parameter */
char l; /* Length of this Self-Defining Parm */
char sdpid; /* 0x02 if Alternate Usable Area */
@@ -412,17 +438,27 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
int auayr;
char awauai;
char ahauai;
- } __attribute__ ((packed)) aua;
-} __attribute__ ((packed));
+ } __packed aua;
+} __packed;
-static void
-raw3270_size_device_vm(struct raw3270 *rp)
+static void raw3270_size_device_vm(struct raw3270 *rp)
{
int rc, model;
struct ccw_dev_id dev_id;
struct diag210 diag_data;
+ struct diag8c diag8c_data;
ccw_device_get_id(rp->cdev, &dev_id);
+ rc = diag8c(&diag8c_data, &dev_id);
+ if (!rc) {
+ rp->model = 2;
+ rp->rows = diag8c_data.height;
+ rp->cols = diag8c_data.width;
+ if (diag8c_data.flags & 1)
+ set_bit(RAW3270_FLAGS_14BITADDR, &rp->flags);
+ return;
+ }
+
diag_data.vrdcdvno = dev_id.devno;
diag_data.vrdclen = sizeof(struct diag210);
rc = diag210(&diag_data);
@@ -454,16 +490,14 @@ raw3270_size_device_vm(struct raw3270 *rp)
}
}
-static void
-raw3270_size_device(struct raw3270 *rp)
+static void raw3270_size_device(struct raw3270 *rp, char *init_data)
{
struct raw3270_ua *uap;
/* Got a Query Reply */
- uap = (struct raw3270_ua *) (rp->init_data + 1);
+ uap = (struct raw3270_ua *)(init_data + 1);
/* Paranoia check. */
- if (rp->init_readmod.rc || rp->init_data[0] != 0x88 ||
- uap->uab.qcode != 0x81) {
+ if (init_data[0] != 0x88 || uap->uab.qcode != 0x81) {
/* Couldn't detect size. Use default model 2. */
rp->model = 2;
rp->rows = 24;
@@ -494,17 +528,20 @@ raw3270_size_device(struct raw3270 *rp)
rp->model = 5;
}
-static void
-raw3270_size_device_done(struct raw3270 *rp)
+static void raw3270_resize_work(struct work_struct *work)
{
+ struct raw3270 *rp = container_of(work, struct raw3270, resize_work);
struct raw3270_view *view;
- rp->view = NULL;
- rp->state = RAW3270_STATE_READY;
/* Notify views about new size */
- list_for_each_entry(view, &rp->view_list, list)
+ list_for_each_entry(view, &rp->view_list, list) {
if (view->fn->resize)
- view->fn->resize(view, rp->model, rp->rows, rp->cols);
+ view->fn->resize(view, rp->model, rp->rows, rp->cols,
+ rp->old_model, rp->old_rows, rp->old_cols);
+ }
+ rp->old_cols = rp->cols;
+ rp->old_rows = rp->rows;
+ rp->old_model = rp->model;
/* Setup processing done, now activate a view */
list_for_each_entry(view, &rp->view_list, list) {
rp->view = view;
@@ -514,17 +551,23 @@ raw3270_size_device_done(struct raw3270 *rp)
}
}
-static void
-raw3270_read_modified_cb(struct raw3270_request *rq, void *data)
+static void raw3270_size_device_done(struct raw3270 *rp)
+{
+ rp->view = NULL;
+ rp->state = RAW3270_STATE_READY;
+ schedule_work(&rp->resize_work);
+}
+
+void raw3270_read_modified_cb(struct raw3270_request *rq, void *data)
{
struct raw3270 *rp = rq->view->dev;
- raw3270_size_device(rp);
+ raw3270_size_device(rp, data);
raw3270_size_device_done(rp);
}
+EXPORT_SYMBOL(raw3270_read_modified_cb);
-static void
-raw3270_read_modified(struct raw3270 *rp)
+static void raw3270_read_modified(struct raw3270 *rp)
{
if (rp->state != RAW3270_STATE_W4ATTN)
return;
@@ -534,17 +577,18 @@ raw3270_read_modified(struct raw3270 *rp)
rp->init_readmod.ccw.cmd_code = TC_READMOD;
rp->init_readmod.ccw.flags = CCW_FLAG_SLI;
rp->init_readmod.ccw.count = sizeof(rp->init_data);
- rp->init_readmod.ccw.cda = (__u32) __pa(rp->init_data);
+ rp->init_readmod.ccw.cda = (__u32)__pa(rp->init_data);
rp->init_readmod.callback = raw3270_read_modified_cb;
+ rp->init_readmod.callback_data = rp->init_data;
rp->state = RAW3270_STATE_READMOD;
raw3270_start_irq(&rp->init_view, &rp->init_readmod);
}
-static void
-raw3270_writesf_readpart(struct raw3270 *rp)
+static void raw3270_writesf_readpart(struct raw3270 *rp)
{
- static const unsigned char wbuf[] =
- { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
+ static const unsigned char wbuf[] = {
+ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81
+ };
/* Store 'read partition' data stream to init_data */
memset(&rp->init_readpart, 0, sizeof(rp->init_readpart));
@@ -553,7 +597,7 @@ raw3270_writesf_readpart(struct raw3270 *rp)
rp->init_readpart.ccw.cmd_code = TC_WRITESF;
rp->init_readpart.ccw.flags = CCW_FLAG_SLI;
rp->init_readpart.ccw.count = sizeof(wbuf);
- rp->init_readpart.ccw.cda = (__u32) __pa(&rp->init_data);
+ rp->init_readpart.ccw.cda = (__u32)__pa(&rp->init_data);
rp->state = RAW3270_STATE_W4ATTN;
raw3270_start_irq(&rp->init_view, &rp->init_readpart);
}
@@ -561,8 +605,7 @@ raw3270_writesf_readpart(struct raw3270 *rp)
/*
* Device reset
*/
-static void
-raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
+static void raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
{
struct raw3270 *rp = rq->view->dev;
@@ -574,13 +617,13 @@ raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
} else if (MACHINE_IS_VM) {
raw3270_size_device_vm(rp);
raw3270_size_device_done(rp);
- } else
+ } else {
raw3270_writesf_readpart(rp);
+ }
memset(&rp->init_reset, 0, sizeof(rp->init_reset));
}
-static int
-__raw3270_reset_device(struct raw3270 *rp)
+static int __raw3270_reset_device(struct raw3270 *rp)
{
int rc;
@@ -592,7 +635,7 @@ __raw3270_reset_device(struct raw3270 *rp)
rp->init_reset.ccw.cmd_code = TC_EWRITEA;
rp->init_reset.ccw.flags = CCW_FLAG_SLI;
rp->init_reset.ccw.count = 1;
- rp->init_reset.ccw.cda = (__u32) __pa(rp->init_data);
+ rp->init_reset.ccw.cda = (__u32)__pa(rp->init_data);
rp->init_reset.callback = raw3270_reset_device_cb;
rc = __raw3270_start(rp, &rp->init_view, &rp->init_reset);
if (rc == 0 && rp->state == RAW3270_STATE_INIT)
@@ -600,8 +643,7 @@ __raw3270_reset_device(struct raw3270 *rp)
return rc;
}
-static int
-raw3270_reset_device(struct raw3270 *rp)
+static int raw3270_reset_device(struct raw3270 *rp)
{
unsigned long flags;
int rc;
@@ -612,8 +654,7 @@ raw3270_reset_device(struct raw3270 *rp)
return rc;
}
-int
-raw3270_reset(struct raw3270_view *view)
+int raw3270_reset(struct raw3270_view *view)
{
struct raw3270 *rp;
int rc;
@@ -627,9 +668,9 @@ raw3270_reset(struct raw3270_view *view)
rc = raw3270_reset_device(view->dev);
return rc;
}
+EXPORT_SYMBOL(raw3270_reset);
-static void
-__raw3270_disconnect(struct raw3270 *rp)
+static void __raw3270_disconnect(struct raw3270 *rp)
{
struct raw3270_request *rq;
struct raw3270_view *view;
@@ -638,7 +679,7 @@ __raw3270_disconnect(struct raw3270 *rp)
rp->view = &rp->init_view;
/* Cancel all queued requests */
while (!list_empty(&rp->req_queue)) {
- rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
+ rq = list_entry(rp->req_queue.next, struct raw3270_request, list);
view = rq->view;
rq->rc = -EACCES;
list_del_init(&rq->list);
@@ -650,9 +691,8 @@ __raw3270_disconnect(struct raw3270 *rp)
__raw3270_reset_device(rp);
}
-static void
-raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
- struct irb *irb)
+static void raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
+ struct irb *irb)
{
struct raw3270 *rp;
@@ -678,8 +718,8 @@ static struct raw3270_fn raw3270_init_fn = {
/*
* Setup new 3270 device.
*/
-static int
-raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
+static int raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp,
+ char *ascebc)
{
struct list_head *l;
struct raw3270 *tmp;
@@ -699,6 +739,8 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
/* Set defaults. */
rp->rows = 24;
rp->cols = 80;
+ rp->old_rows = rp->rows;
+ rp->old_cols = rp->cols;
INIT_LIST_HEAD(&rp->req_queue);
INIT_LIST_HEAD(&rp->view_list);
@@ -706,6 +748,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
rp->init_view.dev = rp;
rp->init_view.fn = &raw3270_init_fn;
rp->view = &rp->init_view;
+ INIT_WORK(&rp->resize_work, raw3270_resize_work);
/*
* Add device to list and find the smallest unused minor
@@ -764,7 +807,7 @@ struct raw3270 __init *raw3270_setup_console(void)
if (IS_ERR(cdev))
return ERR_CAST(cdev);
- rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
+ rp = kzalloc(sizeof(*rp), GFP_KERNEL | GFP_DMA);
ascebc = kzalloc(256, GFP_KERNEL);
rc = raw3270_setup_device(cdev, rp, ascebc);
if (rc)
@@ -789,8 +832,7 @@ struct raw3270 __init *raw3270_setup_console(void)
return rp;
}
-void
-raw3270_wait_cons_dev(struct raw3270 *rp)
+void raw3270_wait_cons_dev(struct raw3270 *rp)
{
unsigned long flags;
@@ -804,14 +846,13 @@ raw3270_wait_cons_dev(struct raw3270 *rp)
/*
* Create a 3270 device structure.
*/
-static struct raw3270 *
-raw3270_create_device(struct ccw_device *cdev)
+static struct raw3270 *raw3270_create_device(struct ccw_device *cdev)
{
struct raw3270 *rp;
char *ascebc;
int rc;
- rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
+ rp = kzalloc(sizeof(*rp), GFP_KERNEL | GFP_DMA);
if (!rp)
return ERR_PTR(-ENOMEM);
ascebc = kmalloc(256, GFP_KERNEL);
@@ -845,14 +886,57 @@ int raw3270_view_lock_unavailable(struct raw3270_view *view)
return 0;
}
+static int raw3270_assign_activate_view(struct raw3270 *rp, struct raw3270_view *view)
+{
+ rp->view = view;
+ return view->fn->activate(view);
+}
+
+static int __raw3270_activate_view(struct raw3270 *rp, struct raw3270_view *view)
+{
+ struct raw3270_view *oldview = NULL, *nv;
+ int rc;
+
+ if (rp->view == view)
+ return 0;
+
+ if (!raw3270_state_ready(rp))
+ return -EBUSY;
+
+ if (rp->view && rp->view->fn->deactivate) {
+ oldview = rp->view;
+ oldview->fn->deactivate(oldview);
+ }
+
+ rc = raw3270_assign_activate_view(rp, view);
+ if (!rc)
+ return 0;
+
+ /* Didn't work. Try to reactivate the old view. */
+ if (oldview) {
+ rc = raw3270_assign_activate_view(rp, oldview);
+ if (!rc)
+ return 0;
+ }
+
+ /* Didn't work as well. Try any other view. */
+ list_for_each_entry(nv, &rp->view_list, list) {
+ if (nv == view || nv == oldview)
+ continue;
+ rc = raw3270_assign_activate_view(rp, nv);
+ if (!rc)
+ break;
+ rp->view = NULL;
+ }
+ return rc;
+}
+
/*
* Activate a view.
*/
-int
-raw3270_activate_view(struct raw3270_view *view)
+int raw3270_activate_view(struct raw3270_view *view)
{
struct raw3270 *rp;
- struct raw3270_view *oldview, *nv;
unsigned long flags;
int rc;
@@ -860,42 +944,16 @@ raw3270_activate_view(struct raw3270_view *view)
if (!rp)
return -ENODEV;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
- if (rp->view == view)
- rc = 0;
- else if (!raw3270_state_ready(rp))
- rc = -EBUSY;
- else {
- oldview = NULL;
- if (rp->view && rp->view->fn->deactivate) {
- oldview = rp->view;
- oldview->fn->deactivate(oldview);
- }
- rp->view = view;
- rc = view->fn->activate(view);
- if (rc) {
- /* Didn't work. Try to reactivate the old view. */
- rp->view = oldview;
- if (!oldview || oldview->fn->activate(oldview) != 0) {
- /* Didn't work as well. Try any other view. */
- list_for_each_entry(nv, &rp->view_list, list)
- if (nv != view && nv != oldview) {
- rp->view = nv;
- if (nv->fn->activate(nv) == 0)
- break;
- rp->view = NULL;
- }
- }
- }
- }
+ rc = __raw3270_activate_view(rp, view);
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
return rc;
}
+EXPORT_SYMBOL(raw3270_activate_view);
/*
* Deactivate current view.
*/
-void
-raw3270_deactivate_view(struct raw3270_view *view)
+void raw3270_deactivate_view(struct raw3270_view *view)
{
unsigned long flags;
struct raw3270 *rp;
@@ -922,12 +980,13 @@ raw3270_deactivate_view(struct raw3270_view *view)
}
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
}
+EXPORT_SYMBOL(raw3270_deactivate_view);
/*
* Add view to device with minor "minor".
*/
-int
-raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor, int subclass)
+int raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn,
+ int minor, int subclass)
{
unsigned long flags;
struct raw3270 *rp;
@@ -958,12 +1017,12 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor, in
mutex_unlock(&raw3270_mutex);
return rc;
}
+EXPORT_SYMBOL(raw3270_add_view);
/*
* Find specific view of device with minor "minor".
*/
-struct raw3270_view *
-raw3270_find_view(struct raw3270_fn *fn, int minor)
+struct raw3270_view *raw3270_find_view(struct raw3270_fn *fn, int minor)
{
struct raw3270 *rp;
struct raw3270_view *view, *tmp;
@@ -988,12 +1047,12 @@ raw3270_find_view(struct raw3270_fn *fn, int minor)
mutex_unlock(&raw3270_mutex);
return view;
}
+EXPORT_SYMBOL(raw3270_find_view);
/*
* Remove view from device and free view structure via call to view->fn->free.
*/
-void
-raw3270_del_view(struct raw3270_view *view)
+void raw3270_del_view(struct raw3270_view *view)
{
unsigned long flags;
struct raw3270 *rp;
@@ -1022,12 +1081,12 @@ raw3270_del_view(struct raw3270_view *view)
if (view->fn->free)
view->fn->free(view);
}
+EXPORT_SYMBOL(raw3270_del_view);
/*
* Remove a 3270 device structure.
*/
-static void
-raw3270_delete_device(struct raw3270 *rp)
+static void raw3270_delete_device(struct raw3270 *rp)
{
struct ccw_device *cdev;
@@ -1050,8 +1109,7 @@ raw3270_delete_device(struct raw3270 *rp)
kfree(rp);
}
-static int
-raw3270_probe (struct ccw_device *cdev)
+static int raw3270_probe(struct ccw_device *cdev)
{
return 0;
}
@@ -1059,31 +1117,32 @@ raw3270_probe (struct ccw_device *cdev)
/*
* Additional attributes for a 3270 device
*/
-static ssize_t
-raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t model_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
return sysfs_emit(buf, "%i\n",
((struct raw3270 *)dev_get_drvdata(dev))->model);
}
-static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
+static DEVICE_ATTR_RO(model);
-static ssize_t
-raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t rows_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
return sysfs_emit(buf, "%i\n",
((struct raw3270 *)dev_get_drvdata(dev))->rows);
}
-static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
+static DEVICE_ATTR_RO(rows);
static ssize_t
-raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
+columns_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
return sysfs_emit(buf, "%i\n",
((struct raw3270 *)dev_get_drvdata(dev))->cols);
}
-static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
+static DEVICE_ATTR_RO(columns);
-static struct attribute * raw3270_attrs[] = {
+static struct attribute *raw3270_attrs[] = {
&dev_attr_model.attr,
&dev_attr_rows.attr,
&dev_attr_columns.attr,
@@ -1115,6 +1174,7 @@ int raw3270_register_notifier(struct raw3270_notifier *notifier)
mutex_unlock(&raw3270_mutex);
return 0;
}
+EXPORT_SYMBOL(raw3270_register_notifier);
void raw3270_unregister_notifier(struct raw3270_notifier *notifier)
{
@@ -1126,12 +1186,12 @@ void raw3270_unregister_notifier(struct raw3270_notifier *notifier)
list_del(&notifier->list);
mutex_unlock(&raw3270_mutex);
}
+EXPORT_SYMBOL(raw3270_unregister_notifier);
/*
* Set 3270 device online.
*/
-static int
-raw3270_set_online (struct ccw_device *cdev)
+static int raw3270_set_online(struct ccw_device *cdev)
{
struct raw3270_notifier *np;
struct raw3270 *rp;
@@ -1158,8 +1218,7 @@ failure:
/*
* Remove 3270 device structure.
*/
-static void
-raw3270_remove (struct ccw_device *cdev)
+static void raw3270_remove(struct ccw_device *cdev)
{
unsigned long flags;
struct raw3270 *rp;
@@ -1173,7 +1232,7 @@ raw3270_remove (struct ccw_device *cdev)
* devices even if they haven't been varied online.
* Thus, rp may validly be NULL here.
*/
- if (rp == NULL)
+ if (!rp)
return;
sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
@@ -1209,8 +1268,7 @@ raw3270_remove (struct ccw_device *cdev)
/*
* Set 3270 device offline.
*/
-static int
-raw3270_set_offline (struct ccw_device *cdev)
+static int raw3270_set_offline(struct ccw_device *cdev)
{
struct raw3270 *rp;
@@ -1249,8 +1307,7 @@ static struct ccw_driver raw3270_ccw_driver = {
.int_class = IRQIO_C70,
};
-static int
-raw3270_init(void)
+static int raw3270_init(void)
{
struct raw3270 *rp;
int rc;
@@ -1272,8 +1329,7 @@ raw3270_init(void)
return rc;
}
-static void
-raw3270_exit(void)
+static void raw3270_exit(void)
{
ccw_driver_unregister(&raw3270_ccw_driver);
class_destroy(class3270);
@@ -1283,25 +1339,3 @@ MODULE_LICENSE("GPL");
module_init(raw3270_init);
module_exit(raw3270_exit);
-
-EXPORT_SYMBOL(class3270);
-EXPORT_SYMBOL(raw3270_request_alloc);
-EXPORT_SYMBOL(raw3270_request_free);
-EXPORT_SYMBOL(raw3270_request_reset);
-EXPORT_SYMBOL(raw3270_request_set_cmd);
-EXPORT_SYMBOL(raw3270_request_add_data);
-EXPORT_SYMBOL(raw3270_request_set_data);
-EXPORT_SYMBOL(raw3270_request_set_idal);
-EXPORT_SYMBOL(raw3270_buffer_address);
-EXPORT_SYMBOL(raw3270_add_view);
-EXPORT_SYMBOL(raw3270_del_view);
-EXPORT_SYMBOL(raw3270_find_view);
-EXPORT_SYMBOL(raw3270_activate_view);
-EXPORT_SYMBOL(raw3270_deactivate_view);
-EXPORT_SYMBOL(raw3270_start);
-EXPORT_SYMBOL(raw3270_start_locked);
-EXPORT_SYMBOL(raw3270_start_irq);
-EXPORT_SYMBOL(raw3270_reset);
-EXPORT_SYMBOL(raw3270_register_notifier);
-EXPORT_SYMBOL(raw3270_unregister_notifier);
-EXPORT_SYMBOL(raw3270_wait_queue);
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index 4cb6b5ee44ca..b1beecc7a0a9 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -8,88 +8,10 @@
* Copyright IBM Corp. 2003, 2009
*/
+#include <uapi/asm/raw3270.h>
#include <asm/idals.h>
#include <asm/ioctl.h>
-/* ioctls for fullscreen 3270 */
-#define TUBICMD _IO('3', 3) /* set ccw command for fs reads. */
-#define TUBOCMD _IO('3', 4) /* set ccw command for fs writes. */
-#define TUBGETI _IO('3', 7) /* get ccw command for fs reads. */
-#define TUBGETO _IO('3', 8) /* get ccw command for fs writes. */
-#define TUBSETMOD _IO('3',12) /* FIXME: what does it do ?*/
-#define TUBGETMOD _IO('3',13) /* FIXME: what does it do ?*/
-
-/* Local Channel Commands */
-#define TC_WRITE 0x01 /* Write */
-#define TC_RDBUF 0x02 /* Read Buffer */
-#define TC_EWRITE 0x05 /* Erase write */
-#define TC_READMOD 0x06 /* Read modified */
-#define TC_EWRITEA 0x0d /* Erase write alternate */
-#define TC_WRITESF 0x11 /* Write structured field */
-
-/* Buffer Control Orders */
-#define TO_SF 0x1d /* Start field */
-#define TO_SBA 0x11 /* Set buffer address */
-#define TO_IC 0x13 /* Insert cursor */
-#define TO_PT 0x05 /* Program tab */
-#define TO_RA 0x3c /* Repeat to address */
-#define TO_SFE 0x29 /* Start field extended */
-#define TO_EUA 0x12 /* Erase unprotected to address */
-#define TO_MF 0x2c /* Modify field */
-#define TO_SA 0x28 /* Set attribute */
-
-/* Field Attribute Bytes */
-#define TF_INPUT 0x40 /* Visible input */
-#define TF_INPUTN 0x4c /* Invisible input */
-#define TF_INMDT 0xc1 /* Visible, Set-MDT */
-#define TF_LOG 0x60
-
-/* Character Attribute Bytes */
-#define TAT_RESET 0x00
-#define TAT_FIELD 0xc0
-#define TAT_EXTHI 0x41
-#define TAT_COLOR 0x42
-#define TAT_CHARS 0x43
-#define TAT_TRANS 0x46
-
-/* Extended-Highlighting Bytes */
-#define TAX_RESET 0x00
-#define TAX_BLINK 0xf1
-#define TAX_REVER 0xf2
-#define TAX_UNDER 0xf4
-
-/* Reset value */
-#define TAR_RESET 0x00
-
-/* Color values */
-#define TAC_RESET 0x00
-#define TAC_BLUE 0xf1
-#define TAC_RED 0xf2
-#define TAC_PINK 0xf3
-#define TAC_GREEN 0xf4
-#define TAC_TURQ 0xf5
-#define TAC_YELLOW 0xf6
-#define TAC_WHITE 0xf7
-#define TAC_DEFAULT 0x00
-
-/* Write Control Characters */
-#define TW_NONE 0x40 /* No particular action */
-#define TW_KR 0xc2 /* Keyboard restore */
-#define TW_PLUSALARM 0x04 /* Add this bit for alarm */
-
-#define RAW3270_FIRSTMINOR 1 /* First minor number */
-#define RAW3270_MAXDEVS 255 /* Max number of 3270 devices */
-
-/* For TUBGETMOD and TUBSETMOD. Should include. */
-struct raw3270_iocb {
- short model;
- short line_cnt;
- short col_cnt;
- short pf_cnt;
- short re_cnt;
- short map;
-};
-
struct raw3270;
struct raw3270_view;
extern struct class *class3270;
@@ -105,17 +27,17 @@ struct raw3270_request {
int rc; /* return code for this request. */
/* Callback for delivering final status. */
- void (*callback)(struct raw3270_request *, void *);
+ void (*callback)(struct raw3270_request *rq, void *data);
void *callback_data;
};
struct raw3270_request *raw3270_request_alloc(size_t size);
-void raw3270_request_free(struct raw3270_request *);
-void raw3270_request_reset(struct raw3270_request *);
-void raw3270_request_set_cmd(struct raw3270_request *, u8 cmd);
-int raw3270_request_add_data(struct raw3270_request *, void *, size_t);
-void raw3270_request_set_data(struct raw3270_request *, void *, size_t);
-void raw3270_request_set_idal(struct raw3270_request *, struct idal_buffer *);
+void raw3270_request_free(struct raw3270_request *rq);
+int raw3270_request_reset(struct raw3270_request *rq);
+void raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd);
+int raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size);
+void raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size);
+void raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib);
static inline int
raw3270_request_final(struct raw3270_request *rq)
@@ -123,19 +45,21 @@ raw3270_request_final(struct raw3270_request *rq)
return list_empty(&rq->list);
}
-void raw3270_buffer_address(struct raw3270 *, char *, unsigned short);
+void raw3270_buffer_address(struct raw3270 *, char *, int, int);
/*
* Functions of a 3270 view.
*/
struct raw3270_fn {
- int (*activate)(struct raw3270_view *);
- void (*deactivate)(struct raw3270_view *);
- void (*intv)(struct raw3270_view *,
- struct raw3270_request *, struct irb *);
- void (*release)(struct raw3270_view *);
- void (*free)(struct raw3270_view *);
- void (*resize)(struct raw3270_view *, int, int, int);
+ int (*activate)(struct raw3270_view *rq);
+ void (*deactivate)(struct raw3270_view *rq);
+ void (*intv)(struct raw3270_view *view,
+ struct raw3270_request *rq, struct irb *ib);
+ void (*release)(struct raw3270_view *view);
+ void (*free)(struct raw3270_view *view);
+ void (*resize)(struct raw3270_view *view,
+ int new_model, int new_cols, int new_rows,
+ int old_model, int old_cols, int old_rows);
};
/*
@@ -148,7 +72,7 @@ struct raw3270_fn {
*/
struct raw3270_view {
struct list_head list;
- spinlock_t lock;
+ spinlock_t lock; /* protects members of view */
#define RAW3270_VIEW_LOCK_IRQ 0
#define RAW3270_VIEW_LOCK_BH 1
atomic_t ref_count;
@@ -159,18 +83,21 @@ struct raw3270_view {
unsigned char *ascebc; /* ascii -> ebcdic table */
};
-int raw3270_add_view(struct raw3270_view *, struct raw3270_fn *, int, int);
+int raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor, int subclass);
int raw3270_view_lock_unavailable(struct raw3270_view *view);
-int raw3270_activate_view(struct raw3270_view *);
-void raw3270_del_view(struct raw3270_view *);
-void raw3270_deactivate_view(struct raw3270_view *);
-struct raw3270_view *raw3270_find_view(struct raw3270_fn *, int);
-int raw3270_start(struct raw3270_view *, struct raw3270_request *);
-int raw3270_start_locked(struct raw3270_view *, struct raw3270_request *);
-int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *);
-int raw3270_reset(struct raw3270_view *);
-struct raw3270_view *raw3270_view(struct raw3270_view *);
-int raw3270_view_active(struct raw3270_view *);
+int raw3270_activate_view(struct raw3270_view *view);
+void raw3270_del_view(struct raw3270_view *view);
+void raw3270_deactivate_view(struct raw3270_view *view);
+struct raw3270_view *raw3270_find_view(struct raw3270_fn *fn, int minor);
+int raw3270_start(struct raw3270_view *view, struct raw3270_request *rq);
+int raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq);
+int raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq);
+int raw3270_reset(struct raw3270_view *view);
+struct raw3270_view *raw3270_view(struct raw3270_view *view);
+int raw3270_view_active(struct raw3270_view *view);
+int raw3270_start_request(struct raw3270_view *view, struct raw3270_request *rq,
+ int cmd, void *data, size_t len);
+void raw3270_read_modified_cb(struct raw3270_request *rq, void *data);
/* Reference count inliner for view structures. */
static inline void
@@ -189,7 +116,7 @@ raw3270_put_view(struct raw3270_view *view)
}
struct raw3270 *raw3270_setup_console(void);
-void raw3270_wait_cons_dev(struct raw3270 *);
+void raw3270_wait_cons_dev(struct raw3270 *rp);
/* Notifier for device addition/removal */
struct raw3270_notifier {
@@ -198,87 +125,5 @@ struct raw3270_notifier {
void (*destroy)(int minor);
};
-int raw3270_register_notifier(struct raw3270_notifier *);
-void raw3270_unregister_notifier(struct raw3270_notifier *);
-
-/*
- * Little memory allocator for string objects.
- */
-struct string
-{
- struct list_head list;
- struct list_head update;
- unsigned long size;
- unsigned long len;
- char string[];
-} __attribute__ ((aligned(8)));
-
-static inline struct string *
-alloc_string(struct list_head *free_list, unsigned long len)
-{
- struct string *cs, *tmp;
- unsigned long size;
-
- size = (len + 7L) & -8L;
- list_for_each_entry(cs, free_list, list) {
- if (cs->size < size)
- continue;
- if (cs->size > size + sizeof(struct string)) {
- char *endaddr = (char *) (cs + 1) + cs->size;
- tmp = (struct string *) (endaddr - size) - 1;
- tmp->size = size;
- cs->size -= size + sizeof(struct string);
- cs = tmp;
- } else
- list_del(&cs->list);
- cs->len = len;
- INIT_LIST_HEAD(&cs->list);
- INIT_LIST_HEAD(&cs->update);
- return cs;
- }
- return NULL;
-}
-
-static inline unsigned long
-free_string(struct list_head *free_list, struct string *cs)
-{
- struct string *tmp;
- struct list_head *p, *left;
-
- /* Find out the left neighbour in free memory list. */
- left = free_list;
- list_for_each(p, free_list) {
- if (list_entry(p, struct string, list) > cs)
- break;
- left = p;
- }
- /* Try to merge with right neighbour = next element from left. */
- if (left->next != free_list) {
- tmp = list_entry(left->next, struct string, list);
- if ((char *) (cs + 1) + cs->size == (char *) tmp) {
- list_del(&tmp->list);
- cs->size += tmp->size + sizeof(struct string);
- }
- }
- /* Try to merge with left neighbour. */
- if (left != free_list) {
- tmp = list_entry(left, struct string, list);
- if ((char *) (tmp + 1) + tmp->size == (char *) cs) {
- tmp->size += cs->size + sizeof(struct string);
- return tmp->size;
- }
- }
- __list_add(&cs->list, left, left->next);
- return cs->size;
-}
-
-static inline void
-add_string_memory(struct list_head *free_list, void *mem, unsigned long size)
-{
- struct string *cs;
-
- cs = (struct string *) mem;
- cs->size = size - sizeof(struct string);
- free_string(free_list, cs);
-}
-
+int raw3270_register_notifier(struct raw3270_notifier *notifier);
+void raw3270_unregister_notifier(struct raw3270_notifier *notifier);
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index c1c70a161c0e..f480d6c7fd39 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -163,7 +163,7 @@ static void __init sclp_early_console_detect(struct init_sccb *sccb)
sclp.has_linemode = 1;
}
-void __init sclp_early_adjust_va(void)
+void __init __no_sanitize_address sclp_early_adjust_va(void)
{
sclp_early_sccb = __va((unsigned long)sclp_early_sccb);
}
diff --git a/drivers/s390/char/sclp_ftp.c b/drivers/s390/char/sclp_ftp.c
index ec5a0e2b9255..d27e2cbfbccb 100644
--- a/drivers/s390/char/sclp_ftp.c
+++ b/drivers/s390/char/sclp_ftp.c
@@ -90,7 +90,7 @@ static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec *ftp)
struct completion completion;
struct sclp_diag_sccb *sccb;
struct sclp_req *req;
- size_t len;
+ ssize_t len;
int rc;
req = kzalloc(sizeof(*req), GFP_KERNEL);
@@ -117,9 +117,9 @@ static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec *ftp)
sccb->evbuf.mdd.ftp.length = ftp->len;
sccb->evbuf.mdd.ftp.bufaddr = virt_to_phys(ftp->buf);
- len = strlcpy(sccb->evbuf.mdd.ftp.fident, ftp->fname,
+ len = strscpy(sccb->evbuf.mdd.ftp.fident, ftp->fname,
HMCDRV_FTP_FIDENT_MAX);
- if (len >= HMCDRV_FTP_FIDENT_MAX) {
+ if (len < 0) {
rc = -EINVAL;
goto out_free;
}
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
deleted file mode 100644
index 26e3995ac062..000000000000
--- a/drivers/s390/char/tty3270.c
+++ /dev/null
@@ -1,1963 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * IBM/3270 Driver - tty functions.
- *
- * Author(s):
- * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- * -- Copyright IBM Corp. 2003
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kdev_t.h>
-#include <linux/tty.h>
-#include <linux/vt_kern.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-
-#include <linux/slab.h>
-#include <linux/memblock.h>
-#include <linux/compat.h>
-
-#include <asm/ccwdev.h>
-#include <asm/cio.h>
-#include <asm/ebcdic.h>
-#include <linux/uaccess.h>
-
-#include "raw3270.h"
-#include "tty3270.h"
-#include "keyboard.h"
-
-#define TTY3270_CHAR_BUF_SIZE 256
-#define TTY3270_OUTPUT_BUFFER_SIZE 1024
-#define TTY3270_STRING_PAGES 5
-
-struct tty_driver *tty3270_driver;
-static int tty3270_max_index;
-
-static struct raw3270_fn tty3270_fn;
-
-struct tty3270_cell {
- unsigned char character;
- unsigned char highlight;
- unsigned char f_color;
-};
-
-struct tty3270_line {
- struct tty3270_cell *cells;
- int len;
-};
-
-#define ESCAPE_NPAR 8
-
-/*
- * The main tty view data structure.
- * FIXME:
- * 1) describe line orientation & lines list concept against screen
- * 2) describe conversion of screen to lines
- * 3) describe line format.
- */
-struct tty3270 {
- struct raw3270_view view;
- struct tty_port port;
- void **freemem_pages; /* Array of pages used for freemem. */
- struct list_head freemem; /* List of free memory for strings. */
-
- /* Output stuff. */
- struct list_head lines; /* List of lines. */
- struct list_head update; /* List of lines to update. */
- unsigned char wcc; /* Write control character. */
- int nr_lines; /* # lines in list. */
- int nr_up; /* # lines up in history. */
- unsigned long update_flags; /* Update indication bits. */
- struct string *status; /* Lower right of display. */
- struct raw3270_request *write; /* Single write request. */
- struct timer_list timer; /* Output delay timer. */
-
- /* Current tty screen. */
- unsigned int cx, cy; /* Current output position. */
- unsigned int highlight; /* Blink/reverse/underscore */
- unsigned int f_color; /* Foreground color */
- struct tty3270_line *screen;
- unsigned int n_model, n_cols, n_rows; /* New model & size */
- struct work_struct resize_work;
-
- /* Input stuff. */
- struct string *prompt; /* Output string for input area. */
- struct string *input; /* Input string for read request. */
- struct raw3270_request *read; /* Single read request. */
- struct raw3270_request *kreset; /* Single keyboard reset request. */
- unsigned char inattr; /* Visible/invisible input. */
- int throttle, attn; /* tty throttle/unthrottle. */
- struct tasklet_struct readlet; /* Tasklet to issue read request. */
- struct tasklet_struct hanglet; /* Tasklet to hang up the tty. */
- struct kbd_data *kbd; /* key_maps stuff. */
-
- /* Escape sequence parsing. */
- int esc_state, esc_ques, esc_npar;
- int esc_par[ESCAPE_NPAR];
- unsigned int saved_cx, saved_cy;
- unsigned int saved_highlight, saved_f_color;
-
- /* Command recalling. */
- struct list_head rcl_lines; /* List of recallable lines. */
- struct list_head *rcl_walk; /* Point in rcl_lines list. */
- int rcl_nr, rcl_max; /* Number/max number of rcl_lines. */
-
- /* Character array for put_char/flush_chars. */
- unsigned int char_count;
- char char_buf[TTY3270_CHAR_BUF_SIZE];
-};
-
-/* tty3270->update_flags. See tty3270_update for details. */
-#define TTY_UPDATE_ERASE 1 /* Use EWRITEA instead of WRITE. */
-#define TTY_UPDATE_LIST 2 /* Update lines in tty3270->update. */
-#define TTY_UPDATE_INPUT 4 /* Update input line. */
-#define TTY_UPDATE_STATUS 8 /* Update status line. */
-#define TTY_UPDATE_ALL 16 /* Recreate screen. */
-
-static void tty3270_update(struct timer_list *);
-static void tty3270_resize_work(struct work_struct *work);
-
-/*
- * Setup timeout for a device. On timeout trigger an update.
- */
-static void tty3270_set_timer(struct tty3270 *tp, int expires)
-{
- mod_timer(&tp->timer, jiffies + expires);
-}
-
-/*
- * The input line are the two last lines of the screen.
- */
-static void
-tty3270_update_prompt(struct tty3270 *tp, char *input, int count)
-{
- struct string *line;
- unsigned int off;
-
- line = tp->prompt;
- if (count != 0)
- line->string[5] = TF_INMDT;
- else
- line->string[5] = tp->inattr;
- if (count > tp->view.cols * 2 - 11)
- count = tp->view.cols * 2 - 11;
- memcpy(line->string + 6, input, count);
- line->string[6 + count] = TO_IC;
- /* Clear to end of input line. */
- if (count < tp->view.cols * 2 - 11) {
- line->string[7 + count] = TO_RA;
- line->string[10 + count] = 0;
- off = tp->view.cols * tp->view.rows - 9;
- raw3270_buffer_address(tp->view.dev, line->string+count+8, off);
- line->len = 11 + count;
- } else
- line->len = 7 + count;
- tp->update_flags |= TTY_UPDATE_INPUT;
-}
-
-static void
-tty3270_create_prompt(struct tty3270 *tp)
-{
- static const unsigned char blueprint[] =
- { TO_SBA, 0, 0, 0x6e, TO_SF, TF_INPUT,
- /* empty input string */
- TO_IC, TO_RA, 0, 0, 0 };
- struct string *line;
- unsigned int offset;
-
- line = alloc_string(&tp->freemem,
- sizeof(blueprint) + tp->view.cols * 2 - 9);
- tp->prompt = line;
- tp->inattr = TF_INPUT;
- /* Copy blueprint to status line */
- memcpy(line->string, blueprint, sizeof(blueprint));
- line->len = sizeof(blueprint);
- /* Set output offsets. */
- offset = tp->view.cols * (tp->view.rows - 2);
- raw3270_buffer_address(tp->view.dev, line->string + 1, offset);
- offset = tp->view.cols * tp->view.rows - 9;
- raw3270_buffer_address(tp->view.dev, line->string + 8, offset);
-
- /* Allocate input string for reading. */
- tp->input = alloc_string(&tp->freemem, tp->view.cols * 2 - 9 + 6);
-}
-
-/*
- * The status line is the last line of the screen. It shows the string
- * "Running"/"Holding" in the lower right corner of the screen.
- */
-static void
-tty3270_update_status(struct tty3270 * tp)
-{
- char *str;
-
- str = (tp->nr_up != 0) ? "History" : "Running";
- memcpy(tp->status->string + 8, str, 7);
- codepage_convert(tp->view.ascebc, tp->status->string + 8, 7);
- tp->update_flags |= TTY_UPDATE_STATUS;
-}
-
-static void
-tty3270_create_status(struct tty3270 * tp)
-{
- static const unsigned char blueprint[] =
- { TO_SBA, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR, TAC_GREEN,
- 0, 0, 0, 0, 0, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR,
- TAC_RESET };
- struct string *line;
- unsigned int offset;
-
- line = alloc_string(&tp->freemem,sizeof(blueprint));
- tp->status = line;
- /* Copy blueprint to status line */
- memcpy(line->string, blueprint, sizeof(blueprint));
- /* Set address to start of status string (= last 9 characters). */
- offset = tp->view.cols * tp->view.rows - 9;
- raw3270_buffer_address(tp->view.dev, line->string + 1, offset);
-}
-
-/*
- * Set output offsets to 3270 datastream fragment of a tty string.
- * (TO_SBA offset at the start and TO_RA offset at the end of the string)
- */
-static void
-tty3270_update_string(struct tty3270 *tp, struct string *line, int nr)
-{
- unsigned char *cp;
-
- raw3270_buffer_address(tp->view.dev, line->string + 1,
- tp->view.cols * nr);
- cp = line->string + line->len - 4;
- if (*cp == TO_RA)
- raw3270_buffer_address(tp->view.dev, cp + 1,
- tp->view.cols * (nr + 1));
-}
-
-/*
- * Rebuild update list to print all lines.
- */
-static void
-tty3270_rebuild_update(struct tty3270 *tp)
-{
- struct string *s, *n;
- int line, nr_up;
-
- /*
- * Throw away update list and create a new one,
- * containing all lines that will fit on the screen.
- */
- list_for_each_entry_safe(s, n, &tp->update, update)
- list_del_init(&s->update);
- line = tp->view.rows - 3;
- nr_up = tp->nr_up;
- list_for_each_entry_reverse(s, &tp->lines, list) {
- if (nr_up > 0) {
- nr_up--;
- continue;
- }
- tty3270_update_string(tp, s, line);
- list_add(&s->update, &tp->update);
- if (--line < 0)
- break;
- }
- tp->update_flags |= TTY_UPDATE_LIST;
-}
-
-/*
- * Alloc string for size bytes. If there is not enough room in
- * freemem, free strings until there is room.
- */
-static struct string *
-tty3270_alloc_string(struct tty3270 *tp, size_t size)
-{
- struct string *s, *n;
-
- s = alloc_string(&tp->freemem, size);
- if (s)
- return s;
- list_for_each_entry_safe(s, n, &tp->lines, list) {
- BUG_ON(tp->nr_lines <= tp->view.rows - 2);
- list_del(&s->list);
- if (!list_empty(&s->update))
- list_del(&s->update);
- tp->nr_lines--;
- if (free_string(&tp->freemem, s) >= size)
- break;
- }
- s = alloc_string(&tp->freemem, size);
- BUG_ON(!s);
- if (tp->nr_up != 0 &&
- tp->nr_up + tp->view.rows - 2 >= tp->nr_lines) {
- tp->nr_up = tp->nr_lines - tp->view.rows + 2;
- tty3270_rebuild_update(tp);
- tty3270_update_status(tp);
- }
- return s;
-}
-
-/*
- * Add an empty line to the list.
- */
-static void
-tty3270_blank_line(struct tty3270 *tp)
-{
- static const unsigned char blueprint[] =
- { TO_SBA, 0, 0, TO_SA, TAT_EXTHI, TAX_RESET,
- TO_SA, TAT_COLOR, TAC_RESET, TO_RA, 0, 0, 0 };
- struct string *s;
-
- s = tty3270_alloc_string(tp, sizeof(blueprint));
- memcpy(s->string, blueprint, sizeof(blueprint));
- s->len = sizeof(blueprint);
- list_add_tail(&s->list, &tp->lines);
- tp->nr_lines++;
- if (tp->nr_up != 0)
- tp->nr_up++;
-}
-
-/*
- * Create a blank screen and remove all lines from the history.
- */
-static void
-tty3270_blank_screen(struct tty3270 *tp)
-{
- struct string *s, *n;
- int i;
-
- for (i = 0; i < tp->view.rows - 2; i++)
- tp->screen[i].len = 0;
- tp->nr_up = 0;
- list_for_each_entry_safe(s, n, &tp->lines, list) {
- list_del(&s->list);
- if (!list_empty(&s->update))
- list_del(&s->update);
- tp->nr_lines--;
- free_string(&tp->freemem, s);
- }
-}
-
-/*
- * Write request completion callback.
- */
-static void
-tty3270_write_callback(struct raw3270_request *rq, void *data)
-{
- struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
-
- if (rq->rc != 0) {
- /* Write wasn't successful. Refresh all. */
- tp->update_flags = TTY_UPDATE_ALL;
- tty3270_set_timer(tp, 1);
- }
- raw3270_request_reset(rq);
- xchg(&tp->write, rq);
-}
-
-/*
- * Update 3270 display.
- */
-static void
-tty3270_update(struct timer_list *t)
-{
- struct tty3270 *tp = from_timer(tp, t, timer);
- static char invalid_sba[2] = { 0xff, 0xff };
- struct raw3270_request *wrq;
- unsigned long updated;
- struct string *s, *n;
- char *sba, *str;
- int rc, len;
-
- wrq = xchg(&tp->write, 0);
- if (!wrq) {
- tty3270_set_timer(tp, 1);
- return;
- }
-
- spin_lock(&tp->view.lock);
- updated = 0;
- if (tp->update_flags & TTY_UPDATE_ALL) {
- tty3270_rebuild_update(tp);
- tty3270_update_status(tp);
- tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST |
- TTY_UPDATE_INPUT | TTY_UPDATE_STATUS;
- }
- if (tp->update_flags & TTY_UPDATE_ERASE) {
- /* Use erase write alternate to erase display. */
- raw3270_request_set_cmd(wrq, TC_EWRITEA);
- updated |= TTY_UPDATE_ERASE;
- } else
- raw3270_request_set_cmd(wrq, TC_WRITE);
-
- raw3270_request_add_data(wrq, &tp->wcc, 1);
- tp->wcc = TW_NONE;
-
- /*
- * Update status line.
- */
- if (tp->update_flags & TTY_UPDATE_STATUS)
- if (raw3270_request_add_data(wrq, tp->status->string,
- tp->status->len) == 0)
- updated |= TTY_UPDATE_STATUS;
-
- /*
- * Write input line.
- */
- if (tp->update_flags & TTY_UPDATE_INPUT)
- if (raw3270_request_add_data(wrq, tp->prompt->string,
- tp->prompt->len) == 0)
- updated |= TTY_UPDATE_INPUT;
-
- sba = invalid_sba;
-
- if (tp->update_flags & TTY_UPDATE_LIST) {
- /* Write strings in the update list to the screen. */
- list_for_each_entry_safe(s, n, &tp->update, update) {
- str = s->string;
- len = s->len;
- /*
- * Skip TO_SBA at the start of the string if the
- * last output position matches the start address
- * of this line.
- */
- if (s->string[1] == sba[0] && s->string[2] == sba[1]) {
- str += 3;
- len -= 3;
- }
- if (raw3270_request_add_data(wrq, str, len) != 0)
- break;
- list_del_init(&s->update);
- if (s->string[s->len - 4] == TO_RA)
- sba = s->string + s->len - 3;
- else
- sba = invalid_sba;
- }
- if (list_empty(&tp->update))
- updated |= TTY_UPDATE_LIST;
- }
- wrq->callback = tty3270_write_callback;
- rc = raw3270_start(&tp->view, wrq);
- if (rc == 0) {
- tp->update_flags &= ~updated;
- if (tp->update_flags)
- tty3270_set_timer(tp, 1);
- } else {
- raw3270_request_reset(wrq);
- xchg(&tp->write, wrq);
- }
- spin_unlock(&tp->view.lock);
-}
-
-/*
- * Command recalling.
- */
-static void
-tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
-{
- struct string *s;
-
- tp->rcl_walk = NULL;
- if (len <= 0)
- return;
- if (tp->rcl_nr >= tp->rcl_max) {
- s = list_entry(tp->rcl_lines.next, struct string, list);
- list_del(&s->list);
- free_string(&tp->freemem, s);
- tp->rcl_nr--;
- }
- s = tty3270_alloc_string(tp, len);
- memcpy(s->string, input, len);
- list_add_tail(&s->list, &tp->rcl_lines);
- tp->rcl_nr++;
-}
-
-static void
-tty3270_rcl_backward(struct kbd_data *kbd)
-{
- struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
- struct string *s;
-
- spin_lock_bh(&tp->view.lock);
- if (tp->inattr == TF_INPUT) {
- if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
- tp->rcl_walk = tp->rcl_walk->prev;
- else if (!list_empty(&tp->rcl_lines))
- tp->rcl_walk = tp->rcl_lines.prev;
- s = tp->rcl_walk ?
- list_entry(tp->rcl_walk, struct string, list) : NULL;
- if (tp->rcl_walk) {
- s = list_entry(tp->rcl_walk, struct string, list);
- tty3270_update_prompt(tp, s->string, s->len);
- } else
- tty3270_update_prompt(tp, NULL, 0);
- tty3270_set_timer(tp, 1);
- }
- spin_unlock_bh(&tp->view.lock);
-}
-
-/*
- * Deactivate tty view.
- */
-static void
-tty3270_exit_tty(struct kbd_data *kbd)
-{
- struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
-
- raw3270_deactivate_view(&tp->view);
-}
-
-/*
- * Scroll forward in history.
- */
-static void
-tty3270_scroll_forward(struct kbd_data *kbd)
-{
- struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
- int nr_up;
-
- spin_lock_bh(&tp->view.lock);
- nr_up = tp->nr_up - tp->view.rows + 2;
- if (nr_up < 0)
- nr_up = 0;
- if (nr_up != tp->nr_up) {
- tp->nr_up = nr_up;
- tty3270_rebuild_update(tp);
- tty3270_update_status(tp);
- tty3270_set_timer(tp, 1);
- }
- spin_unlock_bh(&tp->view.lock);
-}
-
-/*
- * Scroll backward in history.
- */
-static void
-tty3270_scroll_backward(struct kbd_data *kbd)
-{
- struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
- int nr_up;
-
- spin_lock_bh(&tp->view.lock);
- nr_up = tp->nr_up + tp->view.rows - 2;
- if (nr_up + tp->view.rows - 2 > tp->nr_lines)
- nr_up = tp->nr_lines - tp->view.rows + 2;
- if (nr_up != tp->nr_up) {
- tp->nr_up = nr_up;
- tty3270_rebuild_update(tp);
- tty3270_update_status(tp);
- tty3270_set_timer(tp, 1);
- }
- spin_unlock_bh(&tp->view.lock);
-}
-
-/*
- * Pass input line to tty.
- */
-static void
-tty3270_read_tasklet(unsigned long data)
-{
- struct raw3270_request *rrq = (struct raw3270_request *)data;
- static char kreset_data = TW_KR;
- struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
- char *input;
- int len;
-
- spin_lock_bh(&tp->view.lock);
- /*
- * Two AID keys are special: For 0x7d (enter) the input line
- * has to be emitted to the tty and for 0x6d the screen
- * needs to be redrawn.
- */
- input = NULL;
- len = 0;
- if (tp->input->string[0] == 0x7d) {
- /* Enter: write input to tty. */
- input = tp->input->string + 6;
- len = tp->input->len - 6 - rrq->rescnt;
- if (tp->inattr != TF_INPUTN)
- tty3270_rcl_add(tp, input, len);
- if (tp->nr_up > 0) {
- tp->nr_up = 0;
- tty3270_rebuild_update(tp);
- tty3270_update_status(tp);
- }
- /* Clear input area. */
- tty3270_update_prompt(tp, NULL, 0);
- tty3270_set_timer(tp, 1);
- } else if (tp->input->string[0] == 0x6d) {
- /* Display has been cleared. Redraw. */
- tp->update_flags = TTY_UPDATE_ALL;
- tty3270_set_timer(tp, 1);
- }
- spin_unlock_bh(&tp->view.lock);
-
- /* Start keyboard reset command. */
- raw3270_request_reset(tp->kreset);
- raw3270_request_set_cmd(tp->kreset, TC_WRITE);
- raw3270_request_add_data(tp->kreset, &kreset_data, 1);
- raw3270_start(&tp->view, tp->kreset);
-
- while (len-- > 0)
- kbd_keycode(tp->kbd, *input++);
- /* Emit keycode for AID byte. */
- kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
-
- raw3270_request_reset(rrq);
- xchg(&tp->read, rrq);
- raw3270_put_view(&tp->view);
-}
-
-/*
- * Read request completion callback.
- */
-static void
-tty3270_read_callback(struct raw3270_request *rq, void *data)
-{
- struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
- raw3270_get_view(rq->view);
- /* Schedule tasklet to pass input to tty. */
- tasklet_schedule(&tp->readlet);
-}
-
-/*
- * Issue a read request. Call with device lock.
- */
-static void
-tty3270_issue_read(struct tty3270 *tp, int lock)
-{
- struct raw3270_request *rrq;
- int rc;
-
- rrq = xchg(&tp->read, 0);
- if (!rrq)
- /* Read already scheduled. */
- return;
- rrq->callback = tty3270_read_callback;
- rrq->callback_data = tp;
- raw3270_request_set_cmd(rrq, TC_READMOD);
- raw3270_request_set_data(rrq, tp->input->string, tp->input->len);
- /* Issue the read modified request. */
- if (lock) {
- rc = raw3270_start(&tp->view, rrq);
- } else
- rc = raw3270_start_irq(&tp->view, rrq);
- if (rc) {
- raw3270_request_reset(rrq);
- xchg(&tp->read, rrq);
- }
-}
-
-/*
- * Hang up the tty
- */
-static void
-tty3270_hangup_tasklet(unsigned long data)
-{
- struct tty3270 *tp = (struct tty3270 *)data;
- tty_port_tty_hangup(&tp->port, true);
- raw3270_put_view(&tp->view);
-}
-
-/*
- * Switch to the tty view.
- */
-static int
-tty3270_activate(struct raw3270_view *view)
-{
- struct tty3270 *tp = container_of(view, struct tty3270, view);
-
- tp->update_flags = TTY_UPDATE_ALL;
- tty3270_set_timer(tp, 1);
- return 0;
-}
-
-static void
-tty3270_deactivate(struct raw3270_view *view)
-{
- struct tty3270 *tp = container_of(view, struct tty3270, view);
-
- del_timer(&tp->timer);
-}
-
-static void
-tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
-{
- /* Handle ATTN. Schedule tasklet to read aid. */
- if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
- if (!tp->throttle)
- tty3270_issue_read(tp, 0);
- else
- tp->attn = 1;
- }
-
- if (rq) {
- if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
- rq->rc = -EIO;
- raw3270_get_view(&tp->view);
- tasklet_schedule(&tp->hanglet);
- } else {
- /* Normal end. Copy residual count. */
- rq->rescnt = irb->scsw.cmd.count;
- }
- } else if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
- /* Interrupt without an outstanding request -> update all */
- tp->update_flags = TTY_UPDATE_ALL;
- tty3270_set_timer(tp, 1);
- }
-}
-
-/*
- * Allocate tty3270 structure.
- */
-static struct tty3270 *
-tty3270_alloc_view(void)
-{
- struct tty3270 *tp;
- int pages;
-
- tp = kzalloc(sizeof(struct tty3270), GFP_KERNEL);
- if (!tp)
- goto out_err;
- tp->freemem_pages =
- kmalloc_array(TTY3270_STRING_PAGES, sizeof(void *),
- GFP_KERNEL);
- if (!tp->freemem_pages)
- goto out_tp;
- INIT_LIST_HEAD(&tp->freemem);
- INIT_LIST_HEAD(&tp->lines);
- INIT_LIST_HEAD(&tp->update);
- INIT_LIST_HEAD(&tp->rcl_lines);
- tp->rcl_max = 20;
-
- for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
- tp->freemem_pages[pages] = (void *)
- __get_free_pages(GFP_KERNEL|GFP_DMA, 0);
- if (!tp->freemem_pages[pages])
- goto out_pages;
- add_string_memory(&tp->freemem,
- tp->freemem_pages[pages], PAGE_SIZE);
- }
- tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
- if (IS_ERR(tp->write))
- goto out_pages;
- tp->read = raw3270_request_alloc(0);
- if (IS_ERR(tp->read))
- goto out_write;
- tp->kreset = raw3270_request_alloc(1);
- if (IS_ERR(tp->kreset))
- goto out_read;
- tp->kbd = kbd_alloc();
- if (!tp->kbd)
- goto out_reset;
-
- tty_port_init(&tp->port);
- timer_setup(&tp->timer, tty3270_update, 0);
- tasklet_init(&tp->readlet, tty3270_read_tasklet,
- (unsigned long) tp->read);
- tasklet_init(&tp->hanglet, tty3270_hangup_tasklet,
- (unsigned long) tp);
- INIT_WORK(&tp->resize_work, tty3270_resize_work);
-
- return tp;
-
-out_reset:
- raw3270_request_free(tp->kreset);
-out_read:
- raw3270_request_free(tp->read);
-out_write:
- raw3270_request_free(tp->write);
-out_pages:
- while (pages--)
- free_pages((unsigned long) tp->freemem_pages[pages], 0);
- kfree(tp->freemem_pages);
- tty_port_destroy(&tp->port);
-out_tp:
- kfree(tp);
-out_err:
- return ERR_PTR(-ENOMEM);
-}
-
-/*
- * Free tty3270 structure.
- */
-static void
-tty3270_free_view(struct tty3270 *tp)
-{
- int pages;
-
- kbd_free(tp->kbd);
- raw3270_request_free(tp->kreset);
- raw3270_request_free(tp->read);
- raw3270_request_free(tp->write);
- for (pages = 0; pages < TTY3270_STRING_PAGES; pages++)
- free_pages((unsigned long) tp->freemem_pages[pages], 0);
- kfree(tp->freemem_pages);
- tty_port_destroy(&tp->port);
- kfree(tp);
-}
-
-/*
- * Allocate tty3270 screen.
- */
-static struct tty3270_line *
-tty3270_alloc_screen(unsigned int rows, unsigned int cols)
-{
- struct tty3270_line *screen;
- unsigned long size;
- int lines;
-
- size = sizeof(struct tty3270_line) * (rows - 2);
- screen = kzalloc(size, GFP_KERNEL);
- if (!screen)
- goto out_err;
- for (lines = 0; lines < rows - 2; lines++) {
- size = sizeof(struct tty3270_cell) * cols;
- screen[lines].cells = kzalloc(size, GFP_KERNEL);
- if (!screen[lines].cells)
- goto out_screen;
- }
- return screen;
-out_screen:
- while (lines--)
- kfree(screen[lines].cells);
- kfree(screen);
-out_err:
- return ERR_PTR(-ENOMEM);
-}
-
-/*
- * Free tty3270 screen.
- */
-static void
-tty3270_free_screen(struct tty3270_line *screen, unsigned int rows)
-{
- int lines;
-
- for (lines = 0; lines < rows - 2; lines++)
- kfree(screen[lines].cells);
- kfree(screen);
-}
-
-/*
- * Resize tty3270 screen
- */
-static void tty3270_resize_work(struct work_struct *work)
-{
- struct tty3270 *tp = container_of(work, struct tty3270, resize_work);
- struct tty3270_line *screen, *oscreen;
- struct tty_struct *tty;
- unsigned int orows;
- struct winsize ws;
-
- screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols);
- if (IS_ERR(screen))
- return;
- /* Switch to new output size */
- spin_lock_bh(&tp->view.lock);
- tty3270_blank_screen(tp);
- oscreen = tp->screen;
- orows = tp->view.rows;
- tp->view.model = tp->n_model;
- tp->view.rows = tp->n_rows;
- tp->view.cols = tp->n_cols;
- tp->screen = screen;
- free_string(&tp->freemem, tp->prompt);
- free_string(&tp->freemem, tp->status);
- tty3270_create_prompt(tp);
- tty3270_create_status(tp);
- while (tp->nr_lines < tp->view.rows - 2)
- tty3270_blank_line(tp);
- tp->update_flags = TTY_UPDATE_ALL;
- spin_unlock_bh(&tp->view.lock);
- tty3270_free_screen(oscreen, orows);
- tty3270_set_timer(tp, 1);
- /* Informat tty layer about new size */
- tty = tty_port_tty_get(&tp->port);
- if (!tty)
- return;
- ws.ws_row = tp->view.rows - 2;
- ws.ws_col = tp->view.cols;
- tty_do_resize(tty, &ws);
- tty_kref_put(tty);
-}
-
-static void
-tty3270_resize(struct raw3270_view *view, int model, int rows, int cols)
-{
- struct tty3270 *tp = container_of(view, struct tty3270, view);
-
- if (tp->n_model == model && tp->n_rows == rows && tp->n_cols == cols)
- return;
- tp->n_model = model;
- tp->n_rows = rows;
- tp->n_cols = cols;
- schedule_work(&tp->resize_work);
-}
-
-/*
- * Unlink tty3270 data structure from tty.
- */
-static void
-tty3270_release(struct raw3270_view *view)
-{
- struct tty3270 *tp = container_of(view, struct tty3270, view);
- struct tty_struct *tty = tty_port_tty_get(&tp->port);
-
- if (tty) {
- tty->driver_data = NULL;
- tty_port_tty_set(&tp->port, NULL);
- tty_hangup(tty);
- raw3270_put_view(&tp->view);
- tty_kref_put(tty);
- }
-}
-
-/*
- * Free tty3270 data structure
- */
-static void
-tty3270_free(struct raw3270_view *view)
-{
- struct tty3270 *tp = container_of(view, struct tty3270, view);
-
- del_timer_sync(&tp->timer);
- tty3270_free_screen(tp->screen, tp->view.rows);
- tty3270_free_view(tp);
-}
-
-/*
- * Delayed freeing of tty3270 views.
- */
-static void
-tty3270_del_views(void)
-{
- int i;
-
- for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) {
- struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i);
- if (!IS_ERR(view))
- raw3270_del_view(view);
- }
-}
-
-static struct raw3270_fn tty3270_fn = {
- .activate = tty3270_activate,
- .deactivate = tty3270_deactivate,
- .intv = (void *) tty3270_irq,
- .release = tty3270_release,
- .free = tty3270_free,
- .resize = tty3270_resize
-};
-
-/*
- * This routine is called whenever a 3270 tty is opened first time.
- */
-static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
-{
- struct raw3270_view *view;
- struct tty3270 *tp;
- int i, rc;
-
- /* Check if the tty3270 is already there. */
- view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR);
- if (!IS_ERR(view)) {
- tp = container_of(view, struct tty3270, view);
- tty->driver_data = tp;
- tty->winsize.ws_row = tp->view.rows - 2;
- tty->winsize.ws_col = tp->view.cols;
- tp->inattr = TF_INPUT;
- goto port_install;
- }
- if (tty3270_max_index < tty->index + 1)
- tty3270_max_index = tty->index + 1;
-
- /* Allocate tty3270 structure on first open. */
- tp = tty3270_alloc_view();
- if (IS_ERR(tp))
- return PTR_ERR(tp);
-
- rc = raw3270_add_view(&tp->view, &tty3270_fn,
- tty->index + RAW3270_FIRSTMINOR,
- RAW3270_VIEW_LOCK_BH);
- if (rc) {
- tty3270_free_view(tp);
- return rc;
- }
-
- tp->screen = tty3270_alloc_screen(tp->view.rows, tp->view.cols);
- if (IS_ERR(tp->screen)) {
- rc = PTR_ERR(tp->screen);
- raw3270_put_view(&tp->view);
- raw3270_del_view(&tp->view);
- tty3270_free_view(tp);
- return rc;
- }
-
- tty->winsize.ws_row = tp->view.rows - 2;
- tty->winsize.ws_col = tp->view.cols;
-
- tty3270_create_prompt(tp);
- tty3270_create_status(tp);
- tty3270_update_status(tp);
-
- /* Create blank line for every line in the tty output area. */
- for (i = 0; i < tp->view.rows - 2; i++)
- tty3270_blank_line(tp);
-
- tp->kbd->port = &tp->port;
- tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
- tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
- tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
- tp->kbd->fn_handler[KVAL(K_CONS)] = tty3270_rcl_backward;
- kbd_ascebc(tp->kbd, tp->view.ascebc);
-
- raw3270_activate_view(&tp->view);
-
-port_install:
- rc = tty_port_install(&tp->port, driver, tty);
- if (rc) {
- raw3270_put_view(&tp->view);
- return rc;
- }
-
- tty->driver_data = tp;
-
- return 0;
-}
-
-/*
- * This routine is called whenever a 3270 tty is opened.
- */
-static int
-tty3270_open(struct tty_struct *tty, struct file *filp)
-{
- struct tty3270 *tp = tty->driver_data;
- struct tty_port *port = &tp->port;
-
- port->count++;
- tty_port_tty_set(port, tty);
- return 0;
-}
-
-/*
- * This routine is called when the 3270 tty is closed. We wait
- * for the remaining request to be completed. Then we clean up.
- */
-static void
-tty3270_close(struct tty_struct *tty, struct file * filp)
-{
- struct tty3270 *tp = tty->driver_data;
-
- if (tty->count > 1)
- return;
- if (tp)
- tty_port_tty_set(&tp->port, NULL);
-}
-
-static void tty3270_cleanup(struct tty_struct *tty)
-{
- struct tty3270 *tp = tty->driver_data;
-
- if (tp) {
- tty->driver_data = NULL;
- raw3270_put_view(&tp->view);
- }
-}
-
-/*
- * We always have room.
- */
-static unsigned int
-tty3270_write_room(struct tty_struct *tty)
-{
- return INT_MAX;
-}
-
-/*
- * Insert character into the screen at the current position with the
- * current color and highlight. This function does NOT do cursor movement.
- */
-static void tty3270_put_character(struct tty3270 *tp, char ch)
-{
- struct tty3270_line *line;
- struct tty3270_cell *cell;
-
- line = tp->screen + tp->cy;
- if (line->len <= tp->cx) {
- while (line->len < tp->cx) {
- cell = line->cells + line->len;
- cell->character = tp->view.ascebc[' '];
- cell->highlight = tp->highlight;
- cell->f_color = tp->f_color;
- line->len++;
- }
- line->len++;
- }
- cell = line->cells + tp->cx;
- cell->character = tp->view.ascebc[(unsigned int) ch];
- cell->highlight = tp->highlight;
- cell->f_color = tp->f_color;
-}
-
-/*
- * Convert a tty3270_line to a 3270 data fragment usable for output.
- */
-static void
-tty3270_convert_line(struct tty3270 *tp, int line_nr)
-{
- struct tty3270_line *line;
- struct tty3270_cell *cell;
- struct string *s, *n;
- unsigned char highlight;
- unsigned char f_color;
- char *cp;
- int flen, i;
-
- /* Determine how long the fragment will be. */
- flen = 3; /* Prefix (TO_SBA). */
- line = tp->screen + line_nr;
- flen += line->len;
- highlight = TAX_RESET;
- f_color = TAC_RESET;
- for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
- if (cell->highlight != highlight) {
- flen += 3; /* TO_SA to switch highlight. */
- highlight = cell->highlight;
- }
- if (cell->f_color != f_color) {
- flen += 3; /* TO_SA to switch color. */
- f_color = cell->f_color;
- }
- }
- if (highlight != TAX_RESET)
- flen += 3; /* TO_SA to reset hightlight. */
- if (f_color != TAC_RESET)
- flen += 3; /* TO_SA to reset color. */
- if (line->len < tp->view.cols)
- flen += 4; /* Postfix (TO_RA). */
-
- /* Find the line in the list. */
- i = tp->view.rows - 2 - line_nr;
- list_for_each_entry_reverse(s, &tp->lines, list)
- if (--i <= 0)
- break;
- /*
- * Check if the line needs to get reallocated.
- */
- if (s->len != flen) {
- /* Reallocate string. */
- n = tty3270_alloc_string(tp, flen);
- list_add(&n->list, &s->list);
- list_del_init(&s->list);
- if (!list_empty(&s->update))
- list_del_init(&s->update);
- free_string(&tp->freemem, s);
- s = n;
- }
-
- /* Write 3270 data fragment. */
- cp = s->string;
- *cp++ = TO_SBA;
- *cp++ = 0;
- *cp++ = 0;
-
- highlight = TAX_RESET;
- f_color = TAC_RESET;
- for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
- if (cell->highlight != highlight) {
- *cp++ = TO_SA;
- *cp++ = TAT_EXTHI;
- *cp++ = cell->highlight;
- highlight = cell->highlight;
- }
- if (cell->f_color != f_color) {
- *cp++ = TO_SA;
- *cp++ = TAT_COLOR;
- *cp++ = cell->f_color;
- f_color = cell->f_color;
- }
- *cp++ = cell->character;
- }
- if (highlight != TAX_RESET) {
- *cp++ = TO_SA;
- *cp++ = TAT_EXTHI;
- *cp++ = TAX_RESET;
- }
- if (f_color != TAC_RESET) {
- *cp++ = TO_SA;
- *cp++ = TAT_COLOR;
- *cp++ = TAC_RESET;
- }
- if (line->len < tp->view.cols) {
- *cp++ = TO_RA;
- *cp++ = 0;
- *cp++ = 0;
- *cp++ = 0;
- }
-
- if (tp->nr_up + line_nr < tp->view.rows - 2) {
- /* Line is currently visible on screen. */
- tty3270_update_string(tp, s, line_nr);
- /* Add line to update list. */
- if (list_empty(&s->update)) {
- list_add_tail(&s->update, &tp->update);
- tp->update_flags |= TTY_UPDATE_LIST;
- }
- }
-}
-
-/*
- * Do carriage return.
- */
-static void
-tty3270_cr(struct tty3270 *tp)
-{
- tp->cx = 0;
-}
-
-/*
- * Do line feed.
- */
-static void
-tty3270_lf(struct tty3270 *tp)
-{
- struct tty3270_line temp;
- int i;
-
- tty3270_convert_line(tp, tp->cy);
- if (tp->cy < tp->view.rows - 3) {
- tp->cy++;
- return;
- }
- /* Last line just filled up. Add new, blank line. */
- tty3270_blank_line(tp);
- temp = tp->screen[0];
- temp.len = 0;
- for (i = 0; i < tp->view.rows - 3; i++)
- tp->screen[i] = tp->screen[i+1];
- tp->screen[tp->view.rows - 3] = temp;
- tty3270_rebuild_update(tp);
-}
-
-static void
-tty3270_ri(struct tty3270 *tp)
-{
- if (tp->cy > 0) {
- tty3270_convert_line(tp, tp->cy);
- tp->cy--;
- }
-}
-
-/*
- * Insert characters at current position.
- */
-static void
-tty3270_insert_characters(struct tty3270 *tp, int n)
-{
- struct tty3270_line *line;
- int k;
-
- line = tp->screen + tp->cy;
- while (line->len < tp->cx) {
- line->cells[line->len].character = tp->view.ascebc[' '];
- line->cells[line->len].highlight = TAX_RESET;
- line->cells[line->len].f_color = TAC_RESET;
- line->len++;
- }
- if (n > tp->view.cols - tp->cx)
- n = tp->view.cols - tp->cx;
- k = min_t(int, line->len - tp->cx, tp->view.cols - tp->cx - n);
- while (k--)
- line->cells[tp->cx + n + k] = line->cells[tp->cx + k];
- line->len += n;
- if (line->len > tp->view.cols)
- line->len = tp->view.cols;
- while (n-- > 0) {
- line->cells[tp->cx + n].character = tp->view.ascebc[' '];
- line->cells[tp->cx + n].highlight = tp->highlight;
- line->cells[tp->cx + n].f_color = tp->f_color;
- }
-}
-
-/*
- * Delete characters at current position.
- */
-static void
-tty3270_delete_characters(struct tty3270 *tp, int n)
-{
- struct tty3270_line *line;
- int i;
-
- line = tp->screen + tp->cy;
- if (line->len <= tp->cx)
- return;
- if (line->len - tp->cx <= n) {
- line->len = tp->cx;
- return;
- }
- for (i = tp->cx; i + n < line->len; i++)
- line->cells[i] = line->cells[i + n];
- line->len -= n;
-}
-
-/*
- * Erase characters at current position.
- */
-static void
-tty3270_erase_characters(struct tty3270 *tp, int n)
-{
- struct tty3270_line *line;
- struct tty3270_cell *cell;
-
- line = tp->screen + tp->cy;
- while (line->len > tp->cx && n-- > 0) {
- cell = line->cells + tp->cx++;
- cell->character = ' ';
- cell->highlight = TAX_RESET;
- cell->f_color = TAC_RESET;
- }
- tp->cx += n;
- tp->cx = min_t(int, tp->cx, tp->view.cols - 1);
-}
-
-/*
- * Erase line, 3 different cases:
- * Esc [ 0 K Erase from current position to end of line inclusive
- * Esc [ 1 K Erase from beginning of line to current position inclusive
- * Esc [ 2 K Erase entire line (without moving cursor)
- */
-static void
-tty3270_erase_line(struct tty3270 *tp, int mode)
-{
- struct tty3270_line *line;
- struct tty3270_cell *cell;
- int i;
-
- line = tp->screen + tp->cy;
- if (mode == 0)
- line->len = tp->cx;
- else if (mode == 1) {
- for (i = 0; i < tp->cx; i++) {
- cell = line->cells + i;
- cell->character = ' ';
- cell->highlight = TAX_RESET;
- cell->f_color = TAC_RESET;
- }
- if (line->len <= tp->cx)
- line->len = tp->cx + 1;
- } else if (mode == 2)
- line->len = 0;
- tty3270_convert_line(tp, tp->cy);
-}
-
-/*
- * Erase display, 3 different cases:
- * Esc [ 0 J Erase from current position to bottom of screen inclusive
- * Esc [ 1 J Erase from top of screen to current position inclusive
- * Esc [ 2 J Erase entire screen (without moving the cursor)
- */
-static void
-tty3270_erase_display(struct tty3270 *tp, int mode)
-{
- int i;
-
- if (mode == 0) {
- tty3270_erase_line(tp, 0);
- for (i = tp->cy + 1; i < tp->view.rows - 2; i++) {
- tp->screen[i].len = 0;
- tty3270_convert_line(tp, i);
- }
- } else if (mode == 1) {
- for (i = 0; i < tp->cy; i++) {
- tp->screen[i].len = 0;
- tty3270_convert_line(tp, i);
- }
- tty3270_erase_line(tp, 1);
- } else if (mode == 2) {
- for (i = 0; i < tp->view.rows - 2; i++) {
- tp->screen[i].len = 0;
- tty3270_convert_line(tp, i);
- }
- }
- tty3270_rebuild_update(tp);
-}
-
-/*
- * Set attributes found in an escape sequence.
- * Esc [ <attr> ; <attr> ; ... m
- */
-static void
-tty3270_set_attributes(struct tty3270 *tp)
-{
- static unsigned char f_colors[] = {
- TAC_DEFAULT, TAC_RED, TAC_GREEN, TAC_YELLOW, TAC_BLUE,
- TAC_PINK, TAC_TURQ, TAC_WHITE, 0, TAC_DEFAULT
- };
- int i, attr;
-
- for (i = 0; i <= tp->esc_npar; i++) {
- attr = tp->esc_par[i];
- switch (attr) {
- case 0: /* Reset */
- tp->highlight = TAX_RESET;
- tp->f_color = TAC_RESET;
- break;
- /* Highlight. */
- case 4: /* Start underlining. */
- tp->highlight = TAX_UNDER;
- break;
- case 5: /* Start blink. */
- tp->highlight = TAX_BLINK;
- break;
- case 7: /* Start reverse. */
- tp->highlight = TAX_REVER;
- break;
- case 24: /* End underlining */
- if (tp->highlight == TAX_UNDER)
- tp->highlight = TAX_RESET;
- break;
- case 25: /* End blink. */
- if (tp->highlight == TAX_BLINK)
- tp->highlight = TAX_RESET;
- break;
- case 27: /* End reverse. */
- if (tp->highlight == TAX_REVER)
- tp->highlight = TAX_RESET;
- break;
- /* Foreground color. */
- case 30: /* Black */
- case 31: /* Red */
- case 32: /* Green */
- case 33: /* Yellow */
- case 34: /* Blue */
- case 35: /* Magenta */
- case 36: /* Cyan */
- case 37: /* White */
- case 39: /* Black */
- tp->f_color = f_colors[attr - 30];
- break;
- }
- }
-}
-
-static inline int
-tty3270_getpar(struct tty3270 *tp, int ix)
-{
- return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1;
-}
-
-static void
-tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
-{
- int max_cx = max(0, cx);
- int max_cy = max(0, cy);
-
- tp->cx = min_t(int, tp->view.cols - 1, max_cx);
- cy = min_t(int, tp->view.rows - 3, max_cy);
- if (cy != tp->cy) {
- tty3270_convert_line(tp, tp->cy);
- tp->cy = cy;
- }
-}
-
-/*
- * Process escape sequences. Known sequences:
- * Esc 7 Save Cursor Position
- * Esc 8 Restore Cursor Position
- * Esc [ Pn ; Pn ; .. m Set attributes
- * Esc [ Pn ; Pn H Cursor Position
- * Esc [ Pn ; Pn f Cursor Position
- * Esc [ Pn A Cursor Up
- * Esc [ Pn B Cursor Down
- * Esc [ Pn C Cursor Forward
- * Esc [ Pn D Cursor Backward
- * Esc [ Pn G Cursor Horizontal Absolute
- * Esc [ Pn X Erase Characters
- * Esc [ Ps J Erase in Display
- * Esc [ Ps K Erase in Line
- * // FIXME: add all the new ones.
- *
- * Pn is a numeric parameter, a string of zero or more decimal digits.
- * Ps is a selective parameter.
- */
-static void
-tty3270_escape_sequence(struct tty3270 *tp, char ch)
-{
- enum { ESnormal, ESesc, ESsquare, ESgetpars };
-
- if (tp->esc_state == ESnormal) {
- if (ch == 0x1b)
- /* Starting new escape sequence. */
- tp->esc_state = ESesc;
- return;
- }
- if (tp->esc_state == ESesc) {
- tp->esc_state = ESnormal;
- switch (ch) {
- case '[':
- tp->esc_state = ESsquare;
- break;
- case 'E':
- tty3270_cr(tp);
- tty3270_lf(tp);
- break;
- case 'M':
- tty3270_ri(tp);
- break;
- case 'D':
- tty3270_lf(tp);
- break;
- case 'Z': /* Respond ID. */
- kbd_puts_queue(&tp->port, "\033[?6c");
- break;
- case '7': /* Save cursor position. */
- tp->saved_cx = tp->cx;
- tp->saved_cy = tp->cy;
- tp->saved_highlight = tp->highlight;
- tp->saved_f_color = tp->f_color;
- break;
- case '8': /* Restore cursor position. */
- tty3270_convert_line(tp, tp->cy);
- tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
- tp->highlight = tp->saved_highlight;
- tp->f_color = tp->saved_f_color;
- break;
- case 'c': /* Reset terminal. */
- tp->cx = tp->saved_cx = 0;
- tp->cy = tp->saved_cy = 0;
- tp->highlight = tp->saved_highlight = TAX_RESET;
- tp->f_color = tp->saved_f_color = TAC_RESET;
- tty3270_erase_display(tp, 2);
- break;
- }
- return;
- }
- if (tp->esc_state == ESsquare) {
- tp->esc_state = ESgetpars;
- memset(tp->esc_par, 0, sizeof(tp->esc_par));
- tp->esc_npar = 0;
- tp->esc_ques = (ch == '?');
- if (tp->esc_ques)
- return;
- }
- if (tp->esc_state == ESgetpars) {
- if (ch == ';' && tp->esc_npar < ESCAPE_NPAR - 1) {
- tp->esc_npar++;
- return;
- }
- if (ch >= '0' && ch <= '9') {
- tp->esc_par[tp->esc_npar] *= 10;
- tp->esc_par[tp->esc_npar] += ch - '0';
- return;
- }
- }
- tp->esc_state = ESnormal;
- if (ch == 'n' && !tp->esc_ques) {
- if (tp->esc_par[0] == 5) /* Status report. */
- kbd_puts_queue(&tp->port, "\033[0n");
- else if (tp->esc_par[0] == 6) { /* Cursor report. */
- char buf[40];
- sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
- kbd_puts_queue(&tp->port, buf);
- }
- return;
- }
- if (tp->esc_ques)
- return;
- switch (ch) {
- case 'm':
- tty3270_set_attributes(tp);
- break;
- case 'H': /* Set cursor position. */
- case 'f':
- tty3270_goto_xy(tp, tty3270_getpar(tp, 1) - 1,
- tty3270_getpar(tp, 0) - 1);
- break;
- case 'd': /* Set y position. */
- tty3270_goto_xy(tp, tp->cx, tty3270_getpar(tp, 0) - 1);
- break;
- case 'A': /* Cursor up. */
- case 'F':
- tty3270_goto_xy(tp, tp->cx, tp->cy - tty3270_getpar(tp, 0));
- break;
- case 'B': /* Cursor down. */
- case 'e':
- case 'E':
- tty3270_goto_xy(tp, tp->cx, tp->cy + tty3270_getpar(tp, 0));
- break;
- case 'C': /* Cursor forward. */
- case 'a':
- tty3270_goto_xy(tp, tp->cx + tty3270_getpar(tp, 0), tp->cy);
- break;
- case 'D': /* Cursor backward. */
- tty3270_goto_xy(tp, tp->cx - tty3270_getpar(tp, 0), tp->cy);
- break;
- case 'G': /* Set x position. */
- case '`':
- tty3270_goto_xy(tp, tty3270_getpar(tp, 0), tp->cy);
- break;
- case 'X': /* Erase Characters. */
- tty3270_erase_characters(tp, tty3270_getpar(tp, 0));
- break;
- case 'J': /* Erase display. */
- tty3270_erase_display(tp, tp->esc_par[0]);
- break;
- case 'K': /* Erase line. */
- tty3270_erase_line(tp, tp->esc_par[0]);
- break;
- case 'P': /* Delete characters. */
- tty3270_delete_characters(tp, tty3270_getpar(tp, 0));
- break;
- case '@': /* Insert characters. */
- tty3270_insert_characters(tp, tty3270_getpar(tp, 0));
- break;
- case 's': /* Save cursor position. */
- tp->saved_cx = tp->cx;
- tp->saved_cy = tp->cy;
- tp->saved_highlight = tp->highlight;
- tp->saved_f_color = tp->f_color;
- break;
- case 'u': /* Restore cursor position. */
- tty3270_convert_line(tp, tp->cy);
- tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
- tp->highlight = tp->saved_highlight;
- tp->f_color = tp->saved_f_color;
- break;
- }
-}
-
-/*
- * String write routine for 3270 ttys
- */
-static void
-tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
- const unsigned char *buf, int count)
-{
- int i_msg, i;
-
- spin_lock_bh(&tp->view.lock);
- for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) {
- if (tp->esc_state != 0) {
- /* Continue escape sequence. */
- tty3270_escape_sequence(tp, buf[i_msg]);
- continue;
- }
-
- switch (buf[i_msg]) {
- case 0x07: /* '\a' -- Alarm */
- tp->wcc |= TW_PLUSALARM;
- break;
- case 0x08: /* Backspace. */
- if (tp->cx > 0) {
- tp->cx--;
- tty3270_put_character(tp, ' ');
- }
- break;
- case 0x09: /* '\t' -- Tabulate */
- for (i = tp->cx % 8; i < 8; i++) {
- if (tp->cx >= tp->view.cols) {
- tty3270_cr(tp);
- tty3270_lf(tp);
- break;
- }
- tty3270_put_character(tp, ' ');
- tp->cx++;
- }
- break;
- case 0x0a: /* '\n' -- New Line */
- tty3270_cr(tp);
- tty3270_lf(tp);
- break;
- case 0x0c: /* '\f' -- Form Feed */
- tty3270_erase_display(tp, 2);
- tp->cx = tp->cy = 0;
- break;
- case 0x0d: /* '\r' -- Carriage Return */
- tp->cx = 0;
- break;
- case 0x0f: /* SuSE "exit alternate mode" */
- break;
- case 0x1b: /* Start escape sequence. */
- tty3270_escape_sequence(tp, buf[i_msg]);
- break;
- default: /* Insert normal character. */
- if (tp->cx >= tp->view.cols) {
- tty3270_cr(tp);
- tty3270_lf(tp);
- }
- tty3270_put_character(tp, buf[i_msg]);
- tp->cx++;
- break;
- }
- }
- /* Convert current line to 3270 data fragment. */
- tty3270_convert_line(tp, tp->cy);
-
- /* Setup timer to update display after 1/10 second */
- if (!timer_pending(&tp->timer))
- tty3270_set_timer(tp, HZ/10);
-
- spin_unlock_bh(&tp->view.lock);
-}
-
-/*
- * String write routine for 3270 ttys
- */
-static int
-tty3270_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- struct tty3270 *tp;
-
- tp = tty->driver_data;
- if (!tp)
- return 0;
- if (tp->char_count > 0) {
- tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
- tp->char_count = 0;
- }
- tty3270_do_write(tp, tty, buf, count);
- return count;
-}
-
-/*
- * Put single characters to the ttys character buffer
- */
-static int tty3270_put_char(struct tty_struct *tty, unsigned char ch)
-{
- struct tty3270 *tp;
-
- tp = tty->driver_data;
- if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE)
- return 0;
- tp->char_buf[tp->char_count++] = ch;
- return 1;
-}
-
-/*
- * Flush all characters from the ttys characeter buffer put there
- * by tty3270_put_char.
- */
-static void
-tty3270_flush_chars(struct tty_struct *tty)
-{
- struct tty3270 *tp;
-
- tp = tty->driver_data;
- if (!tp)
- return;
- if (tp->char_count > 0) {
- tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
- tp->char_count = 0;
- }
-}
-
-/*
- * Check for visible/invisible input switches
- */
-static void
-tty3270_set_termios(struct tty_struct *tty, const struct ktermios *old)
-{
- struct tty3270 *tp;
- int new;
-
- tp = tty->driver_data;
- if (!tp)
- return;
- spin_lock_bh(&tp->view.lock);
- if (L_ICANON(tty)) {
- new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN;
- if (new != tp->inattr) {
- tp->inattr = new;
- tty3270_update_prompt(tp, NULL, 0);
- tty3270_set_timer(tp, 1);
- }
- }
- spin_unlock_bh(&tp->view.lock);
-}
-
-/*
- * Disable reading from a 3270 tty
- */
-static void
-tty3270_throttle(struct tty_struct * tty)
-{
- struct tty3270 *tp;
-
- tp = tty->driver_data;
- if (!tp)
- return;
- tp->throttle = 1;
-}
-
-/*
- * Enable reading from a 3270 tty
- */
-static void
-tty3270_unthrottle(struct tty_struct * tty)
-{
- struct tty3270 *tp;
-
- tp = tty->driver_data;
- if (!tp)
- return;
- tp->throttle = 0;
- if (tp->attn)
- tty3270_issue_read(tp, 1);
-}
-
-/*
- * Hang up the tty device.
- */
-static void
-tty3270_hangup(struct tty_struct *tty)
-{
- struct tty3270 *tp;
-
- tp = tty->driver_data;
- if (!tp)
- return;
- spin_lock_bh(&tp->view.lock);
- tp->cx = tp->saved_cx = 0;
- tp->cy = tp->saved_cy = 0;
- tp->highlight = tp->saved_highlight = TAX_RESET;
- tp->f_color = tp->saved_f_color = TAC_RESET;
- tty3270_blank_screen(tp);
- while (tp->nr_lines < tp->view.rows - 2)
- tty3270_blank_line(tp);
- tp->update_flags = TTY_UPDATE_ALL;
- spin_unlock_bh(&tp->view.lock);
- tty3270_set_timer(tp, 1);
-}
-
-static void
-tty3270_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-}
-
-static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd,
- unsigned long arg)
-{
- struct tty3270 *tp;
-
- tp = tty->driver_data;
- if (!tp)
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
- return kbd_ioctl(tp->kbd, cmd, arg);
-}
-
-#ifdef CONFIG_COMPAT
-static long tty3270_compat_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct tty3270 *tp;
-
- tp = tty->driver_data;
- if (!tp)
- return -ENODEV;
- if (tty_io_error(tty))
- return -EIO;
- return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg));
-}
-#endif
-
-static const struct tty_operations tty3270_ops = {
- .install = tty3270_install,
- .cleanup = tty3270_cleanup,
- .open = tty3270_open,
- .close = tty3270_close,
- .write = tty3270_write,
- .put_char = tty3270_put_char,
- .flush_chars = tty3270_flush_chars,
- .write_room = tty3270_write_room,
- .throttle = tty3270_throttle,
- .unthrottle = tty3270_unthrottle,
- .hangup = tty3270_hangup,
- .wait_until_sent = tty3270_wait_until_sent,
- .ioctl = tty3270_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = tty3270_compat_ioctl,
-#endif
- .set_termios = tty3270_set_termios
-};
-
-static void tty3270_create_cb(int minor)
-{
- tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
-}
-
-static void tty3270_destroy_cb(int minor)
-{
- tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
-}
-
-static struct raw3270_notifier tty3270_notifier =
-{
- .create = tty3270_create_cb,
- .destroy = tty3270_destroy_cb,
-};
-
-/*
- * 3270 tty registration code called from tty_init().
- * Most kernel services (incl. kmalloc) are available at this poimt.
- */
-static int __init tty3270_init(void)
-{
- struct tty_driver *driver;
- int ret;
-
- driver = tty_alloc_driver(RAW3270_MAXDEVS,
- TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_DYNAMIC_DEV |
- TTY_DRIVER_RESET_TERMIOS);
- if (IS_ERR(driver))
- return PTR_ERR(driver);
-
- /*
- * Initialize the tty_driver structure
- * Entries in tty3270_driver that are NOT initialized:
- * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
- */
- driver->driver_name = "tty3270";
- driver->name = "3270/tty";
- driver->major = IBM_TTY3270_MAJOR;
- driver->minor_start = RAW3270_FIRSTMINOR;
- driver->name_base = RAW3270_FIRSTMINOR;
- driver->type = TTY_DRIVER_TYPE_SYSTEM;
- driver->subtype = SYSTEM_TYPE_TTY;
- driver->init_termios = tty_std_termios;
- tty_set_operations(driver, &tty3270_ops);
- ret = tty_register_driver(driver);
- if (ret) {
- tty_driver_kref_put(driver);
- return ret;
- }
- tty3270_driver = driver;
- raw3270_register_notifier(&tty3270_notifier);
- return 0;
-}
-
-static void __exit
-tty3270_exit(void)
-{
- struct tty_driver *driver;
-
- raw3270_unregister_notifier(&tty3270_notifier);
- driver = tty3270_driver;
- tty3270_driver = NULL;
- tty_unregister_driver(driver);
- tty_driver_kref_put(driver);
- tty3270_del_views();
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR);
-
-module_init(tty3270_init);
-module_exit(tty3270_exit);
diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h
deleted file mode 100644
index 52ceed6f8408..000000000000
--- a/drivers/s390/char/tty3270.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright IBM Corp. 2007
- *
- */
-
-#ifndef __DRIVERS_S390_CHAR_TTY3270_H
-#define __DRIVERS_S390_CHAR_TTY3270_H
-
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-
-extern struct tty_driver *tty3270_driver;
-
-#endif /* __DRIVERS_S390_CHAR_TTY3270_H */
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index c7db95398500..3ef636935a54 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -740,12 +740,21 @@ void css_schedule_eval_all(void)
spin_unlock_irqrestore(&slow_subchannel_lock, flags);
}
-static int __unset_registered(struct device *dev, void *data)
+static int __unset_validpath(struct device *dev, void *data)
{
struct idset *set = data;
struct subchannel *sch = to_subchannel(dev);
+ struct pmcw *pmcw = &sch->schib.pmcw;
+
+ /* Here we want to make sure that we are considering only those subchannels
+ * which do not have an operational device attached to it. This can be found
+ * with the help of PAM and POM values of pmcw. OPM provides the information
+ * about any path which is currently vary-off, so that we should not consider.
+ */
+ if (sch->st == SUBCHANNEL_TYPE_IO &&
+ (sch->opm & pmcw->pam & pmcw->pom))
+ idset_sch_del(set, sch->schid);
- idset_sch_del(set, sch->schid);
return 0;
}
@@ -774,8 +783,8 @@ void css_schedule_eval_cond(enum css_eval_cond cond, unsigned long delay)
}
idset_fill(set);
switch (cond) {
- case CSS_EVAL_UNREG:
- bus_for_each_dev(&css_bus_type, NULL, set, __unset_registered);
+ case CSS_EVAL_NO_PATH:
+ bus_for_each_dev(&css_bus_type, NULL, set, __unset_validpath);
break;
case CSS_EVAL_NOT_ONLINE:
bus_for_each_dev(&css_bus_type, NULL, set, __unset_online);
@@ -798,11 +807,11 @@ void css_wait_for_slow_path(void)
flush_workqueue(cio_work_q);
}
-/* Schedule reprobing of all unregistered subchannels. */
+/* Schedule reprobing of all subchannels with no valid operational path. */
void css_schedule_reprobe(void)
{
/* Schedule with a delay to allow merging of subsequent calls. */
- css_schedule_eval_cond(CSS_EVAL_UNREG, 1 * HZ);
+ css_schedule_eval_cond(CSS_EVAL_NO_PATH, 1 * HZ);
}
EXPORT_SYMBOL_GPL(css_schedule_reprobe);
@@ -1402,9 +1411,9 @@ static void css_shutdown(struct device *dev)
sch->driver->shutdown(sch);
}
-static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int css_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct subchannel *sch = to_subchannel(dev);
+ const struct subchannel *sch = to_subchannel(dev);
int ret;
ret = add_uevent_var(env, "ST=%01X", sch->st);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index ede0b905bc6f..ea5550554297 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -38,7 +38,7 @@
* Conditions used to specify which subchannels need evaluation
*/
enum css_eval_cond {
- CSS_EVAL_UNREG, /* unregistered subchannels */
+ CSS_EVAL_NO_PATH, /* Subchannels with no operational paths */
CSS_EVAL_NOT_ONLINE /* sch without an online-device */
};
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 9e0cf44ff9d4..8eb089b99cde 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -80,7 +80,7 @@ ccw_bus_match (struct device * dev, struct device_driver * drv)
* specified size. Return length of resulting string (excluding trailing '\0')
* even if string doesn't fit buffer (snprintf semantics). */
static int snprint_alias(char *buf, size_t size,
- struct ccw_device_id *id, const char *suffix)
+ const struct ccw_device_id *id, const char *suffix)
{
int len;
@@ -101,10 +101,10 @@ static int snprint_alias(char *buf, size_t size,
/* Set up environment variables for ccw device uevent. Return 0 on success,
* non-zero otherwise. */
-static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ccw_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct ccw_device *cdev = to_ccwdev(dev);
- struct ccw_device_id *id = &(cdev->id);
+ const struct ccw_device *cdev = to_ccwdev(dev);
+ const struct ccw_device_id *id = &(cdev->id);
int ret;
char modalias_buf[30];
@@ -244,10 +244,13 @@ int ccw_device_is_orphan(struct ccw_device *cdev)
static void ccw_device_unregister(struct ccw_device *cdev)
{
+ mutex_lock(&cdev->reg_mutex);
if (device_is_registered(&cdev->dev)) {
/* Undo device_add(). */
device_del(&cdev->dev);
}
+ mutex_unlock(&cdev->reg_mutex);
+
if (cdev->private->flags.initialized) {
cdev->private->flags.initialized = 0;
/* Release reference from device_initialize(). */
@@ -653,11 +656,13 @@ static void ccw_device_do_unbind_bind(struct ccw_device *cdev)
{
int ret;
+ mutex_lock(&cdev->reg_mutex);
if (device_is_registered(&cdev->dev)) {
device_release_driver(&cdev->dev);
ret = device_attach(&cdev->dev);
WARN_ON(ret == -ENODEV);
}
+ mutex_unlock(&cdev->reg_mutex);
}
static void
@@ -740,6 +745,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch,
INIT_LIST_HEAD(&priv->cmb_list);
init_waitqueue_head(&priv->wait_q);
timer_setup(&priv->timer, ccw_device_timeout, 0);
+ mutex_init(&cdev->reg_mutex);
atomic_set(&priv->onoff, 0);
cdev->ccwlock = sch->lock;
@@ -825,6 +831,7 @@ static void io_subchannel_register(struct ccw_device *cdev)
* be registered). We need to reprobe since we may now have sense id
* information.
*/
+ mutex_lock(&cdev->reg_mutex);
if (device_is_registered(&cdev->dev)) {
if (!cdev->drv) {
ret = device_reprobe(&cdev->dev);
@@ -847,12 +854,14 @@ static void io_subchannel_register(struct ccw_device *cdev)
spin_lock_irqsave(sch->lock, flags);
sch_set_cdev(sch, NULL);
spin_unlock_irqrestore(sch->lock, flags);
+ mutex_unlock(&cdev->reg_mutex);
/* Release initial device reference. */
put_device(&cdev->dev);
goto out_err;
}
out:
cdev->private->flags.recog_done = 1;
+ mutex_unlock(&cdev->reg_mutex);
wake_up(&cdev->private->wait_q);
out_err:
if (adjust_init_count && atomic_dec_and_test(&ccw_device_init_count))
diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c
index b6b4589c70bd..6b21ba68c1fe 100644
--- a/drivers/s390/cio/scm.c
+++ b/drivers/s390/cio/scm.c
@@ -37,7 +37,7 @@ static void scmdev_remove(struct device *dev)
scmdrv->remove(scmdev);
}
-static int scmdev_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int scmdev_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
return add_uevent_var(env, "MODALIAS=scm:scmdev");
}
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index c0a09fa8991a..1c31e81ca8de 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -42,8 +42,7 @@ struct ccwchain {
/*
* page_array_alloc() - alloc memory for page array
* @pa: page_array on which to perform the operation
- * @iova: target guest physical address
- * @len: number of bytes that should be pinned from @iova
+ * @len: number of pages that should be pinned from @iova
*
* Attempt to allocate memory for page array.
*
@@ -56,31 +55,24 @@ struct ccwchain {
* -EINVAL if pa->pa_nr is not initially zero, or pa->pa_iova is not NULL
* -ENOMEM if alloc failed
*/
-static int page_array_alloc(struct page_array *pa, u64 iova, unsigned int len)
+static int page_array_alloc(struct page_array *pa, unsigned int len)
{
- int i;
-
if (pa->pa_nr || pa->pa_iova)
return -EINVAL;
- pa->pa_nr = ((iova & ~PAGE_MASK) + len + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
- if (!pa->pa_nr)
+ if (len == 0)
return -EINVAL;
- pa->pa_iova = kcalloc(pa->pa_nr,
- sizeof(*pa->pa_iova) + sizeof(*pa->pa_page),
- GFP_KERNEL);
- if (unlikely(!pa->pa_iova)) {
- pa->pa_nr = 0;
+ pa->pa_nr = len;
+
+ pa->pa_iova = kcalloc(len, sizeof(*pa->pa_iova), GFP_KERNEL);
+ if (!pa->pa_iova)
return -ENOMEM;
- }
- pa->pa_page = (struct page **)&pa->pa_iova[pa->pa_nr];
- pa->pa_iova[0] = iova;
- pa->pa_page[0] = NULL;
- for (i = 1; i < pa->pa_nr; i++) {
- pa->pa_iova[i] = pa->pa_iova[i - 1] + PAGE_SIZE;
- pa->pa_page[i] = NULL;
+ pa->pa_page = kcalloc(len, sizeof(*pa->pa_page), GFP_KERNEL);
+ if (!pa->pa_page) {
+ kfree(pa->pa_iova);
+ return -ENOMEM;
}
return 0;
@@ -91,12 +83,13 @@ static int page_array_alloc(struct page_array *pa, u64 iova, unsigned int len)
* @pa: page_array on which to perform the operation
* @vdev: the vfio device to perform the operation
* @pa_nr: number of user pages to unpin
+ * @unaligned: were pages unaligned on the pin request
*
* Only unpin if any pages were pinned to begin with, i.e. pa_nr > 0,
* otherwise only clear pa->pa_nr
*/
static void page_array_unpin(struct page_array *pa,
- struct vfio_device *vdev, int pa_nr)
+ struct vfio_device *vdev, int pa_nr, bool unaligned)
{
int unpinned = 0, npage = 1;
@@ -105,7 +98,8 @@ static void page_array_unpin(struct page_array *pa,
dma_addr_t *last = &first[npage];
if (unpinned + npage < pa_nr &&
- *first + npage * PAGE_SIZE == *last) {
+ *first + npage * PAGE_SIZE == *last &&
+ !unaligned) {
npage++;
continue;
}
@@ -121,13 +115,20 @@ static void page_array_unpin(struct page_array *pa,
/*
* page_array_pin() - Pin user pages in memory
* @pa: page_array on which to perform the operation
- * @mdev: the mediated device to perform pin operations
+ * @vdev: the vfio device to perform pin operations
+ * @unaligned: are pages aligned to 4K boundary?
*
* Returns number of pages pinned upon success.
* If the pin request partially succeeds, or fails completely,
* all pages are left unpinned and a negative error value is returned.
+ *
+ * Requests to pin "aligned" pages can be coalesced into a single
+ * vfio_pin_pages request for the sake of efficiency, based on the
+ * expectation of 4K page requests. Unaligned requests are probably
+ * dealing with 2K "pages", and cannot be coalesced without
+ * reworking this logic to incorporate that math.
*/
-static int page_array_pin(struct page_array *pa, struct vfio_device *vdev)
+static int page_array_pin(struct page_array *pa, struct vfio_device *vdev, bool unaligned)
{
int pinned = 0, npage = 1;
int ret = 0;
@@ -137,7 +138,8 @@ static int page_array_pin(struct page_array *pa, struct vfio_device *vdev)
dma_addr_t *last = &first[npage];
if (pinned + npage < pa->pa_nr &&
- *first + npage * PAGE_SIZE == *last) {
+ *first + npage * PAGE_SIZE == *last &&
+ !unaligned) {
npage++;
continue;
}
@@ -159,14 +161,15 @@ static int page_array_pin(struct page_array *pa, struct vfio_device *vdev)
return ret;
err_out:
- page_array_unpin(pa, vdev, pinned);
+ page_array_unpin(pa, vdev, pinned, unaligned);
return ret;
}
/* Unpin the pages before releasing the memory. */
-static void page_array_unpin_free(struct page_array *pa, struct vfio_device *vdev)
+static void page_array_unpin_free(struct page_array *pa, struct vfio_device *vdev, bool unaligned)
{
- page_array_unpin(pa, vdev, pa->pa_nr);
+ page_array_unpin(pa, vdev, pa->pa_nr, unaligned);
+ kfree(pa->pa_page);
kfree(pa->pa_iova);
}
@@ -199,11 +202,12 @@ static inline void page_array_idal_create_words(struct page_array *pa,
* idaw.
*/
- for (i = 0; i < pa->pa_nr; i++)
+ for (i = 0; i < pa->pa_nr; i++) {
idaws[i] = page_to_phys(pa->pa_page[i]);
- /* Adjust the first IDAW, since it may not start on a page boundary */
- idaws[0] += pa->pa_iova[0] & (PAGE_SIZE - 1);
+ /* Incorporate any offset from each starting address */
+ idaws[i] += pa->pa_iova[i] & (PAGE_SIZE - 1);
+ }
}
static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
@@ -228,50 +232,7 @@ static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
}
}
-/*
- * Within the domain (@mdev), copy @n bytes from a guest physical
- * address (@iova) to a host physical address (@to).
- */
-static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova,
- unsigned long n)
-{
- struct page_array pa = {0};
- int i, ret;
- unsigned long l, m;
-
- ret = page_array_alloc(&pa, iova, n);
- if (ret < 0)
- return ret;
-
- ret = page_array_pin(&pa, vdev);
- if (ret < 0) {
- page_array_unpin_free(&pa, vdev);
- return ret;
- }
-
- l = n;
- for (i = 0; i < pa.pa_nr; i++) {
- void *from = kmap_local_page(pa.pa_page[i]);
-
- m = PAGE_SIZE;
- if (i == 0) {
- from += iova & (PAGE_SIZE - 1);
- m -= iova & (PAGE_SIZE - 1);
- }
-
- m = min(l, m);
- memcpy(to + (n - l), from, m);
- kunmap_local(from);
-
- l -= m;
- if (l == 0)
- break;
- }
-
- page_array_unpin_free(&pa, vdev);
-
- return l;
-}
+#define idal_is_2k(_cp) (!(_cp)->orb.cmd.c64 || (_cp)->orb.cmd.i2k)
/*
* Helpers to operate ccwchain.
@@ -356,40 +317,41 @@ static inline int is_tic_within_range(struct ccw1 *ccw, u32 head, int len)
static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len)
{
struct ccwchain *chain;
- void *data;
- size_t size;
-
- /* Make ccw address aligned to 8. */
- size = ((sizeof(*chain) + 7L) & -8L) +
- sizeof(*chain->ch_ccw) * len +
- sizeof(*chain->ch_pa) * len;
- chain = kzalloc(size, GFP_DMA | GFP_KERNEL);
+
+ chain = kzalloc(sizeof(*chain), GFP_KERNEL);
if (!chain)
return NULL;
- data = (u8 *)chain + ((sizeof(*chain) + 7L) & -8L);
- chain->ch_ccw = (struct ccw1 *)data;
+ chain->ch_ccw = kcalloc(len, sizeof(*chain->ch_ccw), GFP_DMA | GFP_KERNEL);
+ if (!chain->ch_ccw)
+ goto out_err;
- data = (u8 *)(chain->ch_ccw) + sizeof(*chain->ch_ccw) * len;
- chain->ch_pa = (struct page_array *)data;
-
- chain->ch_len = len;
+ chain->ch_pa = kcalloc(len, sizeof(*chain->ch_pa), GFP_KERNEL);
+ if (!chain->ch_pa)
+ goto out_err;
list_add_tail(&chain->next, &cp->ccwchain_list);
return chain;
+
+out_err:
+ kfree(chain->ch_ccw);
+ kfree(chain);
+ return NULL;
}
static void ccwchain_free(struct ccwchain *chain)
{
list_del(&chain->next);
+ kfree(chain->ch_pa);
+ kfree(chain->ch_ccw);
kfree(chain);
}
/* Free resource for a ccw that allocated memory for its cda. */
static void ccwchain_cda_free(struct ccwchain *chain, int idx)
{
- struct ccw1 *ccw = chain->ch_ccw + idx;
+ struct ccw1 *ccw = &chain->ch_ccw[idx];
if (ccw_is_tic(ccw))
return;
@@ -419,14 +381,6 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
cnt++;
/*
- * As we don't want to fail direct addressing even if the
- * orb specified one of the unsupported formats, we defer
- * checking for IDAWs in unsupported formats to here.
- */
- if ((!cp->orb.cmd.c64 || cp->orb.cmd.i2k) && ccw_is_idal(ccw))
- return -EOPNOTSUPP;
-
- /*
* We want to keep counting if the current CCW has the
* command-chaining flag enabled, or if it is a TIC CCW
* that loops back into the current chain. The latter
@@ -471,10 +425,9 @@ static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
int len, ret;
/* Copy 2K (the most we support today) of possible CCWs */
- len = copy_from_iova(vdev, cp->guest_cp, cda,
- CCWCHAIN_LEN_MAX * sizeof(struct ccw1));
- if (len)
- return len;
+ ret = vfio_dma_rw(vdev, cda, cp->guest_cp, CCWCHAIN_LEN_MAX * sizeof(struct ccw1), false);
+ if (ret)
+ return ret;
/* Convert any Format-0 CCWs to Format-1 */
if (!cp->orb.cmd.fmt)
@@ -489,6 +442,8 @@ static int ccwchain_handle_ccw(u32 cda, struct channel_program *cp)
chain = ccwchain_alloc(cp, len);
if (!chain)
return -ENOMEM;
+
+ chain->ch_len = len;
chain->ch_iova = cda;
/* Copy the actual CCWs into the new chain */
@@ -510,7 +465,7 @@ static int ccwchain_loop_tic(struct ccwchain *chain, struct channel_program *cp)
int i, ret;
for (i = 0; i < chain->ch_len; i++) {
- tic = chain->ch_ccw + i;
+ tic = &chain->ch_ccw[i];
if (!ccw_is_tic(tic))
continue;
@@ -528,11 +483,9 @@ static int ccwchain_loop_tic(struct ccwchain *chain, struct channel_program *cp)
return 0;
}
-static int ccwchain_fetch_tic(struct ccwchain *chain,
- int idx,
+static int ccwchain_fetch_tic(struct ccw1 *ccw,
struct channel_program *cp)
{
- struct ccw1 *ccw = chain->ch_ccw + idx;
struct ccwchain *iter;
u32 ccw_head;
@@ -548,43 +501,124 @@ static int ccwchain_fetch_tic(struct ccwchain *chain,
return -EFAULT;
}
-static int ccwchain_fetch_direct(struct ccwchain *chain,
- int idx,
- struct channel_program *cp)
+static unsigned long *get_guest_idal(struct ccw1 *ccw,
+ struct channel_program *cp,
+ int idaw_nr)
{
struct vfio_device *vdev =
&container_of(cp, struct vfio_ccw_private, cp)->vdev;
- struct ccw1 *ccw;
- struct page_array *pa;
- u64 iova;
unsigned long *idaws;
+ unsigned int *idaws_f1;
+ int idal_len = idaw_nr * sizeof(*idaws);
+ int idaw_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
+ int idaw_mask = ~(idaw_size - 1);
+ int i, ret;
+
+ idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
+ if (!idaws)
+ return ERR_PTR(-ENOMEM);
+
+ if (ccw_is_idal(ccw)) {
+ /* Copy IDAL from guest */
+ ret = vfio_dma_rw(vdev, ccw->cda, idaws, idal_len, false);
+ if (ret) {
+ kfree(idaws);
+ return ERR_PTR(ret);
+ }
+ } else {
+ /* Fabricate an IDAL based off CCW data address */
+ if (cp->orb.cmd.c64) {
+ idaws[0] = ccw->cda;
+ for (i = 1; i < idaw_nr; i++)
+ idaws[i] = (idaws[i - 1] + idaw_size) & idaw_mask;
+ } else {
+ idaws_f1 = (unsigned int *)idaws;
+ idaws_f1[0] = ccw->cda;
+ for (i = 1; i < idaw_nr; i++)
+ idaws_f1[i] = (idaws_f1[i - 1] + idaw_size) & idaw_mask;
+ }
+ }
+
+ return idaws;
+}
+
+/*
+ * ccw_count_idaws() - Calculate the number of IDAWs needed to transfer
+ * a specified amount of data
+ *
+ * @ccw: The Channel Command Word being translated
+ * @cp: Channel Program being processed
+ *
+ * The ORB is examined, since it specifies what IDAWs could actually be
+ * used by any CCW in the channel program, regardless of whether or not
+ * the CCW actually does. An ORB that does not specify Format-2-IDAW
+ * Control could still contain a CCW with an IDAL, which would be
+ * Format-1 and thus only move 2K with each IDAW. Thus all CCWs within
+ * the channel program must follow the same size requirements.
+ */
+static int ccw_count_idaws(struct ccw1 *ccw,
+ struct channel_program *cp)
+{
+ struct vfio_device *vdev =
+ &container_of(cp, struct vfio_ccw_private, cp)->vdev;
+ u64 iova;
+ int size = cp->orb.cmd.c64 ? sizeof(u64) : sizeof(u32);
int ret;
int bytes = 1;
- int idaw_nr, idal_len;
- int i;
-
- ccw = chain->ch_ccw + idx;
if (ccw->count)
bytes = ccw->count;
- /* Calculate size of IDAL */
if (ccw_is_idal(ccw)) {
- /* Read first IDAW to see if it's 4K-aligned or not. */
- /* All subsequent IDAws will be 4K-aligned. */
- ret = copy_from_iova(vdev, &iova, ccw->cda, sizeof(iova));
+ /* Read first IDAW to check its starting address. */
+ /* All subsequent IDAWs will be 2K- or 4K-aligned. */
+ ret = vfio_dma_rw(vdev, ccw->cda, &iova, size, false);
if (ret)
return ret;
+
+ /*
+ * Format-1 IDAWs only occupy the first 32 bits,
+ * and bit 0 is always off.
+ */
+ if (!cp->orb.cmd.c64)
+ iova = iova >> 32;
} else {
iova = ccw->cda;
}
- idaw_nr = idal_nr_words((void *)iova, bytes);
- idal_len = idaw_nr * sizeof(*idaws);
+
+ /* Format-1 IDAWs operate on 2K each */
+ if (!cp->orb.cmd.c64)
+ return idal_2k_nr_words((void *)iova, bytes);
+
+ /* Using the 2K variant of Format-2 IDAWs? */
+ if (cp->orb.cmd.i2k)
+ return idal_2k_nr_words((void *)iova, bytes);
+
+ /* The 'usual' case is 4K Format-2 IDAWs */
+ return idal_nr_words((void *)iova, bytes);
+}
+
+static int ccwchain_fetch_ccw(struct ccw1 *ccw,
+ struct page_array *pa,
+ struct channel_program *cp)
+{
+ struct vfio_device *vdev =
+ &container_of(cp, struct vfio_ccw_private, cp)->vdev;
+ unsigned long *idaws;
+ unsigned int *idaws_f1;
+ int ret;
+ int idaw_nr;
+ int i;
+
+ /* Calculate size of IDAL */
+ idaw_nr = ccw_count_idaws(ccw, cp);
+ if (idaw_nr < 0)
+ return idaw_nr;
/* Allocate an IDAL from host storage */
- idaws = kcalloc(idaw_nr, sizeof(*idaws), GFP_DMA | GFP_KERNEL);
- if (!idaws) {
- ret = -ENOMEM;
+ idaws = get_guest_idal(ccw, cp, idaw_nr);
+ if (IS_ERR(idaws)) {
+ ret = PTR_ERR(idaws);
goto out_init;
}
@@ -594,33 +628,24 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
* required for the data transfer, since we only only support
* 4K IDAWs today.
*/
- pa = chain->ch_pa + idx;
- ret = page_array_alloc(pa, iova, bytes);
+ ret = page_array_alloc(pa, idaw_nr);
if (ret < 0)
goto out_free_idaws;
- if (ccw_is_idal(ccw)) {
- /* Copy guest IDAL into host IDAL */
- ret = copy_from_iova(vdev, idaws, ccw->cda, idal_len);
- if (ret)
- goto out_unpin;
-
- /*
- * Copy guest IDAWs into page_array, in case the memory they
- * occupy is not contiguous.
- */
- for (i = 0; i < idaw_nr; i++)
+ /*
+ * Copy guest IDAWs into page_array, in case the memory they
+ * occupy is not contiguous.
+ */
+ idaws_f1 = (unsigned int *)idaws;
+ for (i = 0; i < idaw_nr; i++) {
+ if (cp->orb.cmd.c64)
pa->pa_iova[i] = idaws[i];
- } else {
- /*
- * No action is required here; the iova addresses in page_array
- * were initialized sequentially in page_array_alloc() beginning
- * with the contents of ccw->cda.
- */
+ else
+ pa->pa_iova[i] = idaws_f1[i];
}
if (ccw_does_data_transfer(ccw)) {
- ret = page_array_pin(pa, vdev);
+ ret = page_array_pin(pa, vdev, idal_is_2k(cp));
if (ret < 0)
goto out_unpin;
} else {
@@ -636,7 +661,7 @@ static int ccwchain_fetch_direct(struct ccwchain *chain,
return 0;
out_unpin:
- page_array_unpin_free(pa, vdev);
+ page_array_unpin_free(pa, vdev, idal_is_2k(cp));
out_free_idaws:
kfree(idaws);
out_init:
@@ -650,22 +675,20 @@ out_init:
* and to get rid of the cda 2G limitiaion of ccw1, we'll translate
* direct ccws to idal ccws.
*/
-static int ccwchain_fetch_one(struct ccwchain *chain,
- int idx,
+static int ccwchain_fetch_one(struct ccw1 *ccw,
+ struct page_array *pa,
struct channel_program *cp)
-{
- struct ccw1 *ccw = chain->ch_ccw + idx;
+{
if (ccw_is_tic(ccw))
- return ccwchain_fetch_tic(chain, idx, cp);
+ return ccwchain_fetch_tic(ccw, cp);
- return ccwchain_fetch_direct(chain, idx, cp);
+ return ccwchain_fetch_ccw(ccw, pa, cp);
}
/**
* cp_init() - allocate ccwchains for a channel program.
* @cp: channel_program on which to perform the operation
- * @mdev: the mediated device to perform pin/unpin operations
* @orb: control block for the channel program from the guest
*
* This creates one or more ccwchain(s), and copies the raw data of
@@ -708,15 +731,9 @@ int cp_init(struct channel_program *cp, union orb *orb)
/* Build a ccwchain for the first CCW segment */
ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
- if (!ret) {
+ if (!ret)
cp->initialized = true;
- /* It is safe to force: if it was not set but idals used
- * ccwchain_calc_length would have returned an error.
- */
- cp->orb.cmd.c64 = 1;
- }
-
return ret;
}
@@ -742,7 +759,7 @@ void cp_free(struct channel_program *cp)
cp->initialized = false;
list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) {
for (i = 0; i < chain->ch_len; i++) {
- page_array_unpin_free(chain->ch_pa + i, vdev);
+ page_array_unpin_free(&chain->ch_pa[i], vdev, idal_is_2k(cp));
ccwchain_cda_free(chain, i);
}
ccwchain_free(chain);
@@ -789,6 +806,8 @@ void cp_free(struct channel_program *cp)
int cp_prefetch(struct channel_program *cp)
{
struct ccwchain *chain;
+ struct ccw1 *ccw;
+ struct page_array *pa;
int len, idx, ret;
/* this is an error in the caller */
@@ -798,7 +817,10 @@ int cp_prefetch(struct channel_program *cp)
list_for_each_entry(chain, &cp->ccwchain_list, next) {
len = chain->ch_len;
for (idx = 0; idx < len; idx++) {
- ret = ccwchain_fetch_one(chain, idx, cp);
+ ccw = &chain->ch_ccw[idx];
+ pa = &chain->ch_pa[idx];
+
+ ret = ccwchain_fetch_one(ccw, pa, cp);
if (ret)
goto out_err;
}
@@ -817,14 +839,13 @@ out_err:
/**
* cp_get_orb() - get the orb of the channel program
* @cp: channel_program on which to perform the operation
- * @intparm: new intparm for the returned orb
- * @lpm: candidate value of the logical-path mask for the returned orb
+ * @sch: subchannel the operation will be performed against
*
* This function returns the address of the updated orb of the channel
* program. Channel I/O device drivers could use this orb to issue a
* ssch.
*/
-union orb *cp_get_orb(struct channel_program *cp, u32 intparm, u8 lpm)
+union orb *cp_get_orb(struct channel_program *cp, struct subchannel *sch)
{
union orb *orb;
struct ccwchain *chain;
@@ -836,12 +857,20 @@ union orb *cp_get_orb(struct channel_program *cp, u32 intparm, u8 lpm)
orb = &cp->orb;
- orb->cmd.intparm = intparm;
+ orb->cmd.intparm = (u32)virt_to_phys(sch);
orb->cmd.fmt = 1;
- orb->cmd.key = PAGE_DEFAULT_KEY >> 4;
+
+ /*
+ * Everything built by vfio-ccw is a Format-2 IDAL.
+ * If the input was a Format-1 IDAL, indicate that
+ * 2K Format-2 IDAWs were created here.
+ */
+ if (!orb->cmd.c64)
+ orb->cmd.i2k = 1;
+ orb->cmd.c64 = 1;
if (orb->cmd.lpm == 0)
- orb->cmd.lpm = lpm;
+ orb->cmd.lpm = sch->lpm;
chain = list_first_entry(&cp->ccwchain_list, struct ccwchain, next);
cpa = chain->ch_ccw;
@@ -919,7 +948,7 @@ bool cp_iova_pinned(struct channel_program *cp, u64 iova, u64 length)
list_for_each_entry(chain, &cp->ccwchain_list, next) {
for (i = 0; i < chain->ch_len; i++)
- if (page_array_iova_pinned(chain->ch_pa + i, iova, length))
+ if (page_array_iova_pinned(&chain->ch_pa[i], iova, length))
return true;
}
diff --git a/drivers/s390/cio/vfio_ccw_cp.h b/drivers/s390/cio/vfio_ccw_cp.h
index 54d26e242533..fc31eb699807 100644
--- a/drivers/s390/cio/vfio_ccw_cp.h
+++ b/drivers/s390/cio/vfio_ccw_cp.h
@@ -27,7 +27,6 @@
* struct channel_program - manage information for channel program
* @ccwchain_list: list head of ccwchains
* @orb: orb for the currently processed ssch request
- * @mdev: the mediated device to perform page pinning/unpinning
* @initialized: whether this instance is actually initialized
*
* @ccwchain_list is the head of a ccwchain list, that contents the
@@ -44,7 +43,7 @@ struct channel_program {
int cp_init(struct channel_program *cp, union orb *orb);
void cp_free(struct channel_program *cp);
int cp_prefetch(struct channel_program *cp);
-union orb *cp_get_orb(struct channel_program *cp, u32 intparm, u8 lpm);
+union orb *cp_get_orb(struct channel_program *cp, struct subchannel *sch);
void cp_update_scsw(struct channel_program *cp, union scsw *scsw);
bool cp_iova_pinned(struct channel_program *cp, u64 iova, u64 length);
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 54aba7cceb33..ff538a086fc7 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -225,7 +225,7 @@ static void vfio_ccw_sch_shutdown(struct subchannel *sch)
struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev);
struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
- if (WARN_ON(!private))
+ if (!private)
return;
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index 2784a4e4d2be..757b73141246 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -27,7 +27,7 @@ static int fsm_io_helper(struct vfio_ccw_private *private)
spin_lock_irqsave(sch->lock, flags);
- orb = cp_get_orb(&private->cp, (u32)virt_to_phys(sch), sch->lpm);
+ orb = cp_get_orb(&private->cp, sch);
if (!orb) {
ret = -EIO;
goto out;
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index b02c631f3b71..f4cc1720156f 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -613,10 +613,10 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
* It sets up a single environment variable DEV_TYPE which contains the
* hardware device type.
*/
-static int ap_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ap_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
int rc = 0;
- struct ap_device *ap_dev = to_ap_dev(dev);
+ const struct ap_device *ap_dev = to_ap_dev(dev);
/* Uevents from ap bus core don't need extensions to the env */
if (dev == ap_root_device)
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index 9c01957e56b3..28a36e016ea9 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -30,10 +30,13 @@
#define AP_QUEUE_UNASSIGNED "unassigned"
#define AP_QUEUE_IN_USE "in use"
+#define MAX_RESET_CHECK_WAIT 200 /* Sleep max 200ms for reset check */
+#define AP_RESET_INTERVAL 20 /* Reset sleep interval (20ms) */
+
static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable);
static struct vfio_ap_queue *vfio_ap_find_queue(int apqn);
static const struct vfio_device_ops vfio_ap_matrix_dev_ops;
-static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q, unsigned int retry);
+static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q);
/**
* get_update_locks_for_kvm: Acquire the locks required to dynamically update a
@@ -349,6 +352,8 @@ static int vfio_ap_validate_nib(struct kvm_vcpu *vcpu, dma_addr_t *nib)
{
*nib = vcpu->run->s.regs.gprs[2];
+ if (!*nib)
+ return -EINVAL;
if (kvm_is_error_hva(gfn_to_hva(vcpu->kvm, *nib >> PAGE_SHIFT)))
return -EINVAL;
@@ -1598,12 +1603,56 @@ static struct vfio_ap_queue *vfio_ap_find_queue(int apqn)
return q;
}
-static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q,
- unsigned int retry)
+static int apq_status_check(int apqn, struct ap_queue_status *status)
+{
+ switch (status->response_code) {
+ case AP_RESPONSE_NORMAL:
+ case AP_RESPONSE_RESET_IN_PROGRESS:
+ if (status->queue_empty && !status->irq_enabled)
+ return 0;
+ return -EBUSY;
+ case AP_RESPONSE_DECONFIGURED:
+ /*
+ * If the AP queue is deconfigured, any subsequent AP command
+ * targeting the queue will fail with the same response code. On the
+ * other hand, when an AP adapter is deconfigured, the associated
+ * queues are reset, so let's return a value indicating the reset
+ * for which we're waiting completed successfully.
+ */
+ return 0;
+ default:
+ WARN(true,
+ "failed to verify reset of queue %02x.%04x: TAPQ rc=%u\n",
+ AP_QID_CARD(apqn), AP_QID_QUEUE(apqn),
+ status->response_code);
+ return -EIO;
+ }
+}
+
+static int apq_reset_check(struct vfio_ap_queue *q)
+{
+ int ret;
+ int iters = MAX_RESET_CHECK_WAIT / AP_RESET_INTERVAL;
+ struct ap_queue_status status;
+
+ for (; iters > 0; iters--) {
+ msleep(AP_RESET_INTERVAL);
+ status = ap_tapq(q->apqn, NULL);
+ ret = apq_status_check(q->apqn, &status);
+ if (ret != -EBUSY)
+ return ret;
+ }
+ WARN_ONCE(iters <= 0,
+ "timeout verifying reset of queue %02x.%04x (%u, %u, %u)",
+ AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
+ status.queue_empty, status.irq_enabled, status.response_code);
+ return ret;
+}
+
+static int vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
{
struct ap_queue_status status;
int ret;
- int retry2 = 2;
if (!q)
return 0;
@@ -1613,25 +1662,29 @@ retry_zapq:
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
ret = 0;
+ /* if the reset has not completed, wait for it to take effect */
+ if (!status.queue_empty || status.irq_enabled)
+ ret = apq_reset_check(q);
break;
case AP_RESPONSE_RESET_IN_PROGRESS:
- if (retry--) {
- msleep(20);
- goto retry_zapq;
- }
- ret = -EBUSY;
- break;
- case AP_RESPONSE_Q_NOT_AVAIL:
+ /*
+ * There is a reset issued by another process in progress. Let's wait
+ * for that to complete. Since we have no idea whether it was a RAPQ or
+ * ZAPQ, then if it completes successfully, let's issue the ZAPQ.
+ */
+ ret = apq_reset_check(q);
+ if (ret)
+ break;
+ goto retry_zapq;
case AP_RESPONSE_DECONFIGURED:
- case AP_RESPONSE_CHECKSTOPPED:
- WARN_ONCE(status.irq_enabled,
- "PQAP/ZAPQ for %02x.%04x failed with rc=%u while IRQ enabled",
- AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
- status.response_code);
- ret = -EBUSY;
- goto free_resources;
+ /*
+ * When an AP adapter is deconfigured, the associated
+ * queues are reset, so let's return a value indicating the reset
+ * completed successfully.
+ */
+ ret = 0;
+ break;
default:
- /* things are really broken, give up */
WARN(true,
"PQAP/ZAPQ for %02x.%04x failed with invalid rc=%u\n",
AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn),
@@ -1639,17 +1692,6 @@ retry_zapq:
return -EIO;
}
- /* wait for the reset to take effect */
- while (retry2--) {
- if (status.queue_empty && !status.irq_enabled)
- break;
- msleep(20);
- status = ap_tapq(q->apqn, NULL);
- }
- WARN_ONCE(retry2 <= 0, "unable to verify reset of queue %02x.%04x",
- AP_QID_CARD(q->apqn), AP_QID_QUEUE(q->apqn));
-
-free_resources:
vfio_ap_free_aqic_resources(q);
return ret;
@@ -1661,7 +1703,7 @@ static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable)
struct vfio_ap_queue *q;
hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode) {
- ret = vfio_ap_mdev_reset_queue(q, 1);
+ ret = vfio_ap_mdev_reset_queue(q);
/*
* Regardless whether a queue turns out to be busy, or
* is not operational, we need to continue resetting
@@ -1857,8 +1899,10 @@ int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
return ret;
q = kzalloc(sizeof(*q), GFP_KERNEL);
- if (!q)
- return -ENOMEM;
+ if (!q) {
+ ret = -ENOMEM;
+ goto err_remove_group;
+ }
q->apqn = to_ap_queue(&apdev->device)->qid;
q->saved_isc = VFIO_AP_ISC_INVALID;
@@ -1876,6 +1920,10 @@ int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
release_update_locks_for_mdev(matrix_mdev);
return 0;
+
+err_remove_group:
+ sysfs_remove_group(&apdev->device.kobj, &vfio_queue_attr_group);
+ return ret;
}
void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
@@ -1906,7 +1954,7 @@ void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
}
}
- vfio_ap_mdev_reset_queue(q, 1);
+ vfio_ap_mdev_reset_queue(q);
dev_set_drvdata(&apdev->device, NULL);
kfree(q);
release_update_locks_for_mdev(matrix_mdev);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 4bf36e53fe3e..6fe05bb82c77 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -347,8 +347,7 @@ static ssize_t zcdn_create_store(struct class *class,
int rc;
char name[ZCDN_MAX_NAME];
- strncpy(name, skip_spaces(buf), sizeof(name));
- name[sizeof(name) - 1] = '\0';
+ strscpy(name, skip_spaces(buf), sizeof(name));
rc = zcdn_create(strim(name));
@@ -365,8 +364,7 @@ static ssize_t zcdn_destroy_store(struct class *class,
int rc;
char name[ZCDN_MAX_NAME];
- strncpy(name, skip_spaces(buf), sizeof(name));
- name[sizeof(name) - 1] = '\0';
+ strscpy(name, skip_spaces(buf), sizeof(name));
rc = zcdn_destroy(strim(name));
diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c
index dfb84bb03d32..90ec477386a8 100644
--- a/drivers/s390/net/ctcm_fsms.c
+++ b/drivers/s390/net/ctcm_fsms.c
@@ -370,7 +370,7 @@ static void chx_rx(fsm_instance *fi, int event, void *arg)
CTCM_FUNTAIL, dev->name, len);
priv->stats.rx_dropped++;
priv->stats.rx_length_errors++;
- goto again;
+ goto again;
}
if (len > ch->max_bufsize) {
CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
@@ -378,7 +378,7 @@ static void chx_rx(fsm_instance *fi, int event, void *arg)
CTCM_FUNTAIL, dev->name, len, ch->max_bufsize);
priv->stats.rx_dropped++;
priv->stats.rx_length_errors++;
- goto again;
+ goto again;
}
/*
@@ -403,7 +403,7 @@ static void chx_rx(fsm_instance *fi, int event, void *arg)
*((__u16 *)skb->data) = len;
priv->stats.rx_dropped++;
priv->stats.rx_length_errors++;
- goto again;
+ goto again;
}
if (block_len > 2) {
*((__u16 *)skb->data) = block_len - 2;
@@ -1006,7 +1006,7 @@ static void ctcm_chx_txretry(fsm_instance *fi, int event, void *arg)
use gptr as mpc indicator */
if (!(gptr && (fsm_getstate(gptr->fsm) != MPCG_STATE_READY)))
ctcm_chx_restart(fi, event, arg);
- goto done;
+ goto done;
}
CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG,
@@ -1024,7 +1024,7 @@ static void ctcm_chx_txretry(fsm_instance *fi, int event, void *arg)
CTCM_FUNTAIL, ch->id);
fsm_event(priv->fsm, DEV_EVENT_TXDOWN, dev);
ctcm_chx_restart(fi, event, arg);
- goto done;
+ goto done;
}
fsm_addtimer(&ch->timer, 1000, CTC_EVENT_TIMER, ch);
if (event == CTC_EVENT_TIMER) /* for TIMER not yet locked */
@@ -1251,12 +1251,12 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
if ((ch->collect_len <= 0) || (grp->in_sweep != 0)) {
spin_unlock(&ch->collect_lock);
fsm_newstate(fi, CTC_STATE_TXIDLE);
- goto done;
+ goto done;
}
if (ctcm_checkalloc_buffer(ch)) {
spin_unlock(&ch->collect_lock);
- goto done;
+ goto done;
}
ch->trans_skb->data = ch->trans_skb_data;
skb_reset_tail_pointer(ch->trans_skb);
@@ -1389,7 +1389,7 @@ static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg)
CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
"%s(%s): TRANS_SKB = NULL",
CTCM_FUNTAIL, dev->name);
- goto again;
+ goto again;
}
if (len < TH_HEADER_LENGTH) {
@@ -1409,7 +1409,7 @@ static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg)
"%s(%s): skb allocation failed",
CTCM_FUNTAIL, dev->name);
fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
- goto again;
+ goto again;
}
switch (fsm_getstate(grp->fsm)) {
case MPCG_STATE_RESET:
@@ -1441,9 +1441,9 @@ again:
skb_reset_tail_pointer(ch->trans_skb);
ch->trans_skb->len = 0;
ch->ccw[1].count = ch->max_bufsize;
- if (do_debug_ccw)
+ if (do_debug_ccw)
ctcmpc_dumpit((char *)&ch->ccw[0],
- sizeof(struct ccw1) * 3);
+ sizeof(struct ccw1) * 3);
dolock = !in_hardirq();
if (dolock)
spin_lock_irqsave(
@@ -1562,7 +1562,7 @@ void ctcmpc_chx_rxidle(fsm_instance *fi, int event, void *arg)
if (rc != 0) {
fsm_newstate(fi, CTC_STATE_RXINIT);
ctcm_ccw_check_rc(ch, rc, "initial RX");
- goto done;
+ goto done;
}
break;
default:
@@ -1677,10 +1677,10 @@ static void ctcmpc_chx_attnbusy(fsm_instance *fsm, int event, void *arg)
if (fsm_getstate(ch->fsm) == CH_XID0_INPROGRESS) {
fsm_newstate(ch->fsm, CH_XID0_PENDING) ;
fsm_deltimer(&grp->timer);
- goto done;
+ goto done;
}
fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- goto done;
+ goto done;
case MPCG_STATE_XID2INITX:
/* XID2 was received before ATTN Busy for second
channel.Send yside xid for second channel.
@@ -1768,7 +1768,7 @@ static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg)
/* give the previous IO time to complete */
fsm_addtimer(&wch->sweep_timer,
200, CTC_EVENT_RSWEEP_TIMER, wch);
- goto done;
+ goto done;
}
skb = skb_dequeue(&wch->sweep_queue);
@@ -1780,7 +1780,7 @@ static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg)
ctcm_clear_busy_do(dev);
dev_kfree_skb_any(skb);
fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- goto done;
+ goto done;
} else {
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 bdfab9ea0046..28db69d91f17 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -494,7 +494,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
ch->collect_len += l;
}
spin_unlock_irqrestore(&ch->collect_lock, saveflags);
- goto done;
+ goto done;
}
spin_unlock_irqrestore(&ch->collect_lock, saveflags);
/*
@@ -685,7 +685,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
ch->collect_len += skb->len;
spin_unlock_irqrestore(&ch->collect_lock, saveflags);
- goto done;
+ goto done;
}
/*
@@ -885,7 +885,7 @@ static netdev_tx_t ctcmpc_tx(struct sk_buff *skb, struct net_device *dev)
"%s(%s): NULL sk_buff passed",
CTCM_FUNTAIL, dev->name);
priv->stats.tx_dropped++;
- goto done;
+ goto done;
}
if (skb_headroom(skb) < (TH_HEADER_LENGTH + PDU_HEADER_LENGTH)) {
CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_ERROR,
@@ -908,7 +908,7 @@ static netdev_tx_t ctcmpc_tx(struct sk_buff *skb, struct net_device *dev)
priv->stats.tx_errors++;
priv->stats.tx_carrier_errors++;
fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- goto done;
+ goto done;
}
newskb->protocol = skb->protocol;
skb_reserve(newskb, TH_HEADER_LENGTH + PDU_HEADER_LENGTH);
@@ -931,7 +931,7 @@ static netdev_tx_t ctcmpc_tx(struct sk_buff *skb, struct net_device *dev)
priv->stats.tx_dropped++;
priv->stats.tx_errors++;
priv->stats.tx_carrier_errors++;
- goto done;
+ goto done;
}
if (ctcm_test_and_set_busy(dev)) {
@@ -943,7 +943,7 @@ static netdev_tx_t ctcmpc_tx(struct sk_buff *skb, struct net_device *dev)
priv->stats.tx_errors++;
priv->stats.tx_carrier_errors++;
fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- goto done;
+ goto done;
}
netif_trans_update(dev);
@@ -957,7 +957,7 @@ static netdev_tx_t ctcmpc_tx(struct sk_buff *skb, struct net_device *dev)
priv->stats.tx_carrier_errors++;
ctcm_clear_busy(dev);
fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- goto done;
+ goto done;
}
ctcm_clear_busy(dev);
done:
@@ -1421,7 +1421,7 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type,
"%s (%s) already in list, using old entry",
__func__, (*c)->id);
- goto free_return;
+ goto free_return;
}
spin_lock_init(&ch->collect_lock);
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c
index 8ac213a55141..b8a226c6e1a9 100644
--- a/drivers/s390/net/ctcm_mpc.c
+++ b/drivers/s390/net/ctcm_mpc.c
@@ -481,7 +481,7 @@ void ctc_mpc_establish_connectivity(int port_num,
grp->estconnfunc = NULL;
}
fsm_deltimer(&grp->timer);
- goto done;
+ goto done;
}
if ((wch->in_mpcgroup) &&
(fsm_getstate(wch->fsm) == CH_XID0_PENDING))
@@ -495,7 +495,7 @@ void ctc_mpc_establish_connectivity(int port_num,
grp->estconnfunc = NULL;
}
fsm_deltimer(&grp->timer);
- goto done;
+ goto done;
}
break;
case MPCG_STATE_XID0IOWAIT:
@@ -896,8 +896,9 @@ void mpc_group_ready(unsigned long adev)
grp->estconnfunc(grp->port_num, 0,
grp->group_max_buflen);
grp->estconnfunc = NULL;
- } else if (grp->allochanfunc)
+ } else if (grp->allochanfunc) {
grp->allochanfunc(grp->port_num, grp->group_max_buflen);
+ }
grp->send_qllc_disc = 1;
grp->changed_side = 0;
@@ -1109,7 +1110,7 @@ static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
priv->stats.rx_dropped++;
priv->stats.rx_length_errors++;
- goto done;
+ goto done;
}
skb_reset_mac_header(pskb);
new_len = curr_pdu->pdu_offset;
@@ -1132,7 +1133,7 @@ static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
CTCM_FUNTAIL, dev->name);
priv->stats.rx_dropped++;
fsm_event(grp->fsm, MPCG_EVENT_INOP, dev);
- goto done;
+ goto done;
}
skb_put_data(skb, pskb->data, new_len);
@@ -1543,7 +1544,7 @@ static int mpc_validate_xid(struct mpcg_info *mpcginfo)
CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
"%s(%s): xid = NULL",
CTCM_FUNTAIL, ch->id);
- goto done;
+ goto done;
}
CTCM_D3_DUMP((char *)xid, XID2_LENGTH);
@@ -1556,7 +1557,7 @@ static int mpc_validate_xid(struct mpcg_info *mpcginfo)
CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
"%s(%s): r/w channel pairing mismatch",
CTCM_FUNTAIL, ch->id);
- goto done;
+ goto done;
}
if (xid->xid2_dlc_type == XID2_READ_SIDE) {
diff --git a/drivers/s390/net/ism.h b/drivers/s390/net/ism.h
index 38fe90c2597d..70c5bbda0fea 100644
--- a/drivers/s390/net/ism.h
+++ b/drivers/s390/net/ism.h
@@ -5,6 +5,7 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/ism.h>
#include <net/smc.h>
#include <asm/pci_insn.h>
@@ -15,7 +16,6 @@
*/
#define ISM_DMB_WORD_OFFSET 1
#define ISM_DMB_BIT_OFFSET (ISM_DMB_WORD_OFFSET * 32)
-#define ISM_NR_DMBS 1920
#define ISM_IDENT_MASK 0x00FFFF
#define ISM_REG_SBA 0x1
@@ -177,7 +177,7 @@ struct ism_eq_header {
struct ism_eq {
struct ism_eq_header header;
- struct smcd_event entry[15];
+ struct ism_event entry[15];
};
struct ism_sba {
@@ -189,21 +189,6 @@ struct ism_sba {
u16 dmbe_mask[ISM_NR_DMBS];
};
-struct ism_dev {
- spinlock_t lock;
- struct pci_dev *pdev;
- struct smcd_dev *smcd;
-
- struct ism_sba *sba;
- dma_addr_t sba_dma_addr;
- DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
-
- struct ism_eq *ieq;
- dma_addr_t ieq_dma_addr;
-
- int ieq_idx;
-};
-
#define ISM_CREATE_REQ(dmb, idx, sf, offset) \
((dmb) | (idx) << 24 | (sf) << 23 | (offset))
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index dfd401d9e362..eb7e13486087 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -15,9 +15,6 @@
#include <linux/err.h>
#include <linux/ctype.h>
#include <linux/processor.h>
-#include <net/smc.h>
-
-#include <asm/debug.h>
#include "ism.h"
@@ -34,6 +31,84 @@ static const struct pci_device_id ism_device_table[] = {
MODULE_DEVICE_TABLE(pci, ism_device_table);
static debug_info_t *ism_debug_info;
+static const struct smcd_ops ism_ops;
+
+#define NO_CLIENT 0xff /* must be >= MAX_CLIENTS */
+static struct ism_client *clients[MAX_CLIENTS]; /* use an array rather than */
+ /* a list for fast mapping */
+static u8 max_client;
+static DEFINE_SPINLOCK(clients_lock);
+struct ism_dev_list {
+ struct list_head list;
+ struct mutex mutex; /* protects ism device list */
+};
+
+static struct ism_dev_list ism_dev_list = {
+ .list = LIST_HEAD_INIT(ism_dev_list.list),
+ .mutex = __MUTEX_INITIALIZER(ism_dev_list.mutex),
+};
+
+int ism_register_client(struct ism_client *client)
+{
+ struct ism_dev *ism;
+ unsigned long flags;
+ int i, rc = -ENOSPC;
+
+ mutex_lock(&ism_dev_list.mutex);
+ spin_lock_irqsave(&clients_lock, flags);
+ for (i = 0; i < MAX_CLIENTS; ++i) {
+ if (!clients[i]) {
+ clients[i] = client;
+ client->id = i;
+ if (i == max_client)
+ max_client++;
+ rc = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&clients_lock, flags);
+ if (i < MAX_CLIENTS) {
+ /* initialize with all devices that we got so far */
+ list_for_each_entry(ism, &ism_dev_list.list, list) {
+ ism->priv[i] = NULL;
+ client->add(ism);
+ }
+ }
+ mutex_unlock(&ism_dev_list.mutex);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ism_register_client);
+
+int ism_unregister_client(struct ism_client *client)
+{
+ struct ism_dev *ism;
+ unsigned long flags;
+ int rc = 0;
+
+ mutex_lock(&ism_dev_list.mutex);
+ spin_lock_irqsave(&clients_lock, flags);
+ clients[client->id] = NULL;
+ if (client->id + 1 == max_client)
+ max_client--;
+ spin_unlock_irqrestore(&clients_lock, flags);
+ list_for_each_entry(ism, &ism_dev_list.list, list) {
+ for (int i = 0; i < ISM_NR_DMBS; ++i) {
+ if (ism->sba_client_arr[i] == client->id) {
+ pr_err("%s: attempt to unregister client '%s'"
+ "with registered dmb(s)\n", __func__,
+ client->name);
+ rc = -EBUSY;
+ goto out;
+ }
+ }
+ }
+out:
+ mutex_unlock(&ism_dev_list.mutex);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ism_unregister_client);
static int ism_cmd(struct ism_dev *ism, void *cmd)
{
@@ -193,15 +268,14 @@ static int ism_read_local_gid(struct ism_dev *ism)
if (ret)
goto out;
- ism->smcd->local_gid = cmd.response.gid;
+ ism->local_gid = cmd.response.gid;
out:
return ret;
}
-static int ism_query_rgid(struct smcd_dev *smcd, u64 rgid, u32 vid_valid,
+static int ism_query_rgid(struct ism_dev *ism, u64 rgid, u32 vid_valid,
u32 vid)
{
- struct ism_dev *ism = smcd->priv;
union ism_query_rgid cmd;
memset(&cmd, 0, sizeof(cmd));
@@ -215,14 +289,14 @@ static int ism_query_rgid(struct smcd_dev *smcd, u64 rgid, u32 vid_valid,
return ism_cmd(ism, &cmd);
}
-static void ism_free_dmb(struct ism_dev *ism, struct smcd_dmb *dmb)
+static void ism_free_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
{
clear_bit(dmb->sba_idx, ism->sba_bitmap);
dma_free_coherent(&ism->pdev->dev, dmb->dmb_len,
dmb->cpu_addr, dmb->dma_addr);
}
-static int ism_alloc_dmb(struct ism_dev *ism, struct smcd_dmb *dmb)
+static int ism_alloc_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
{
unsigned long bit;
@@ -251,9 +325,9 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct smcd_dmb *dmb)
return dmb->cpu_addr ? 0 : -ENOMEM;
}
-static int ism_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
+int ism_register_dmb(struct ism_dev *ism, struct ism_dmb *dmb,
+ struct ism_client *client)
{
- struct ism_dev *ism = smcd->priv;
union ism_reg_dmb cmd;
int ret;
@@ -278,13 +352,14 @@ static int ism_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
goto out;
}
dmb->dmb_tok = cmd.response.dmb_tok;
+ ism->sba_client_arr[dmb->sba_idx - ISM_DMB_BIT_OFFSET] = client->id;
out:
return ret;
}
+EXPORT_SYMBOL_GPL(ism_register_dmb);
-static int ism_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
+int ism_unregister_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
{
- struct ism_dev *ism = smcd->priv;
union ism_unreg_dmb cmd;
int ret;
@@ -294,6 +369,8 @@ static int ism_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
cmd.request.dmb_tok = dmb->dmb_tok;
+ ism->sba_client_arr[dmb->sba_idx - ISM_DMB_BIT_OFFSET] = NO_CLIENT;
+
ret = ism_cmd(ism, &cmd);
if (ret && ret != ISM_ERROR)
goto out;
@@ -302,10 +379,10 @@ static int ism_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
out:
return ret;
}
+EXPORT_SYMBOL_GPL(ism_unregister_dmb);
-static int ism_add_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
+static int ism_add_vlan_id(struct ism_dev *ism, u64 vlan_id)
{
- struct ism_dev *ism = smcd->priv;
union ism_set_vlan_id cmd;
memset(&cmd, 0, sizeof(cmd));
@@ -317,9 +394,8 @@ static int ism_add_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
return ism_cmd(ism, &cmd);
}
-static int ism_del_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
+static int ism_del_vlan_id(struct ism_dev *ism, u64 vlan_id)
{
- struct ism_dev *ism = smcd->priv;
union ism_set_vlan_id cmd;
memset(&cmd, 0, sizeof(cmd));
@@ -331,20 +407,9 @@ static int ism_del_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
return ism_cmd(ism, &cmd);
}
-static int ism_set_vlan_required(struct smcd_dev *smcd)
-{
- return ism_cmd_simple(smcd->priv, ISM_SET_VLAN);
-}
-
-static int ism_reset_vlan_required(struct smcd_dev *smcd)
-{
- return ism_cmd_simple(smcd->priv, ISM_RESET_VLAN);
-}
-
-static int ism_signal_ieq(struct smcd_dev *smcd, u64 rgid, u32 trigger_irq,
+static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq,
u32 event_code, u64 info)
{
- struct ism_dev *ism = smcd->priv;
union ism_sig_ieq cmd;
memset(&cmd, 0, sizeof(cmd));
@@ -365,10 +430,9 @@ static unsigned int max_bytes(unsigned int start, unsigned int len,
return min(boundary - (start & (boundary - 1)), len);
}
-static int ism_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
- bool sf, unsigned int offset, void *data, unsigned int size)
+int ism_move(struct ism_dev *ism, u64 dmb_tok, unsigned int idx, bool sf,
+ unsigned int offset, void *data, unsigned int size)
{
- struct ism_dev *ism = smcd->priv;
unsigned int bytes;
u64 dmb_req;
int ret;
@@ -389,6 +453,7 @@ static int ism_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
return 0;
}
+EXPORT_SYMBOL_GPL(ism_move);
static struct ism_systemeid SYSTEM_EID = {
.seid_string = "IBM-SYSZ-ISMSEID00000000",
@@ -410,15 +475,14 @@ static void ism_create_system_eid(void)
memcpy(&SYSTEM_EID.type, tmp, 4);
}
-static u8 *ism_get_system_eid(void)
+u8 *ism_get_seid(void)
{
return SYSTEM_EID.seid_string;
}
+EXPORT_SYMBOL_GPL(ism_get_seid);
-static u16 ism_get_chid(struct smcd_dev *smcd)
+static u16 ism_get_chid(struct ism_dev *ism)
{
- struct ism_dev *ism = (struct ism_dev *)smcd->priv;
-
if (!ism || !ism->pdev)
return 0;
@@ -427,7 +491,8 @@ static u16 ism_get_chid(struct smcd_dev *smcd)
static void ism_handle_event(struct ism_dev *ism)
{
- struct smcd_event *entry;
+ struct ism_event *entry;
+ int i;
while ((ism->ieq_idx + 1) != READ_ONCE(ism->ieq->header.idx)) {
if (++(ism->ieq_idx) == ARRAY_SIZE(ism->ieq->entry))
@@ -435,13 +500,18 @@ static void ism_handle_event(struct ism_dev *ism)
entry = &ism->ieq->entry[ism->ieq_idx];
debug_event(ism_debug_info, 2, entry, sizeof(*entry));
- smcd_handle_event(ism->smcd, entry);
+ spin_lock(&clients_lock);
+ for (i = 0; i < max_client; ++i)
+ if (clients[i])
+ clients[i]->handle_event(ism, entry);
+ spin_unlock(&clients_lock);
}
}
static irqreturn_t ism_handle_irq(int irq, void *data)
{
struct ism_dev *ism = data;
+ struct ism_client *clt;
unsigned long bit, end;
unsigned long *bv;
u16 dmbemask;
@@ -461,7 +531,8 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
dmbemask = ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET];
ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET] = 0;
barrier();
- smcd_handle_irq(ism->smcd, bit + ISM_DMB_BIT_OFFSET, dmbemask);
+ clt = clients[ism->sba_client_arr[bit]];
+ clt->handle_irq(ism, bit + ISM_DMB_BIT_OFFSET, dmbemask);
}
if (ism->sba->e) {
@@ -473,33 +544,40 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static const struct smcd_ops ism_ops = {
- .query_remote_gid = ism_query_rgid,
- .register_dmb = ism_register_dmb,
- .unregister_dmb = ism_unregister_dmb,
- .add_vlan_id = ism_add_vlan_id,
- .del_vlan_id = ism_del_vlan_id,
- .set_vlan_required = ism_set_vlan_required,
- .reset_vlan_required = ism_reset_vlan_required,
- .signal_event = ism_signal_ieq,
- .move_data = ism_move,
- .get_system_eid = ism_get_system_eid,
- .get_chid = ism_get_chid,
-};
+static u64 ism_get_local_gid(struct ism_dev *ism)
+{
+ return ism->local_gid;
+}
+
+static void ism_dev_add_work_func(struct work_struct *work)
+{
+ struct ism_client *client = container_of(work, struct ism_client,
+ add_work);
+
+ client->add(client->tgt_ism);
+ atomic_dec(&client->tgt_ism->add_dev_cnt);
+ wake_up(&client->tgt_ism->waitq);
+}
static int ism_dev_init(struct ism_dev *ism)
{
struct pci_dev *pdev = ism->pdev;
- int ret;
+ unsigned long flags;
+ int i, ret;
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
if (ret <= 0)
goto out;
+ ism->sba_client_arr = kzalloc(ISM_NR_DMBS, GFP_KERNEL);
+ if (!ism->sba_client_arr)
+ goto free_vectors;
+ memset(ism->sba_client_arr, NO_CLIENT, ISM_NR_DMBS);
+
ret = request_irq(pci_irq_vector(pdev, 0), ism_handle_irq, 0,
pci_name(pdev), ism);
if (ret)
- goto free_vectors;
+ goto free_client_arr;
ret = register_sba(ism);
if (ret)
@@ -513,13 +591,31 @@ static int ism_dev_init(struct ism_dev *ism)
if (ret)
goto unreg_ieq;
- if (!ism_add_vlan_id(ism->smcd, ISM_RESERVED_VLANID))
+ if (!ism_add_vlan_id(ism, ISM_RESERVED_VLANID))
/* hardware is V2 capable */
ism_create_system_eid();
- ret = smcd_register_dev(ism->smcd);
- if (ret)
- goto unreg_ieq;
+ init_waitqueue_head(&ism->waitq);
+ atomic_set(&ism->free_clients_cnt, 0);
+ atomic_set(&ism->add_dev_cnt, 0);
+
+ wait_event(ism->waitq, !atomic_read(&ism->add_dev_cnt));
+ spin_lock_irqsave(&clients_lock, flags);
+ for (i = 0; i < max_client; ++i)
+ if (clients[i]) {
+ INIT_WORK(&clients[i]->add_work,
+ ism_dev_add_work_func);
+ clients[i]->tgt_ism = ism;
+ atomic_inc(&ism->add_dev_cnt);
+ schedule_work(&clients[i]->add_work);
+ }
+ spin_unlock_irqrestore(&clients_lock, flags);
+
+ wait_event(ism->waitq, !atomic_read(&ism->add_dev_cnt));
+
+ mutex_lock(&ism_dev_list.mutex);
+ list_add(&ism->list, &ism_dev_list.list);
+ mutex_unlock(&ism_dev_list.mutex);
query_info(ism);
return 0;
@@ -530,6 +626,8 @@ unreg_sba:
unregister_sba(ism);
free_irq:
free_irq(pci_irq_vector(pdev, 0), ism);
+free_client_arr:
+ kfree(ism->sba_client_arr);
free_vectors:
pci_free_irq_vectors(pdev);
out:
@@ -548,6 +646,12 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ism->lock);
dev_set_drvdata(&pdev->dev, ism);
ism->pdev = pdev;
+ ism->dev.parent = &pdev->dev;
+ device_initialize(&ism->dev);
+ dev_set_name(&ism->dev, dev_name(&pdev->dev));
+ ret = device_add(&ism->dev);
+ if (ret)
+ goto err_dev;
ret = pci_enable_device_mem(pdev);
if (ret)
@@ -565,55 +669,80 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dma_set_max_seg_size(&pdev->dev, SZ_1M);
pci_set_master(pdev);
- ism->smcd = smcd_alloc_dev(&pdev->dev, dev_name(&pdev->dev), &ism_ops,
- ISM_NR_DMBS);
- if (!ism->smcd) {
- ret = -ENOMEM;
- goto err_resource;
- }
-
- ism->smcd->priv = ism;
ret = ism_dev_init(ism);
if (ret)
- goto err_free;
+ goto err_resource;
return 0;
-err_free:
- smcd_free_dev(ism->smcd);
err_resource:
+ pci_clear_master(pdev);
pci_release_mem_regions(pdev);
err_disable:
pci_disable_device(pdev);
err:
- kfree(ism);
+ device_del(&ism->dev);
+err_dev:
dev_set_drvdata(&pdev->dev, NULL);
+ kfree(ism);
+
return ret;
}
+static void ism_dev_remove_work_func(struct work_struct *work)
+{
+ struct ism_client *client = container_of(work, struct ism_client,
+ remove_work);
+
+ client->remove(client->tgt_ism);
+ atomic_dec(&client->tgt_ism->free_clients_cnt);
+ wake_up(&client->tgt_ism->waitq);
+}
+
+/* Callers must hold ism_dev_list.mutex */
static void ism_dev_exit(struct ism_dev *ism)
{
struct pci_dev *pdev = ism->pdev;
+ unsigned long flags;
+ int i;
+
+ wait_event(ism->waitq, !atomic_read(&ism->free_clients_cnt));
+ spin_lock_irqsave(&clients_lock, flags);
+ for (i = 0; i < max_client; ++i)
+ if (clients[i]) {
+ INIT_WORK(&clients[i]->remove_work,
+ ism_dev_remove_work_func);
+ clients[i]->tgt_ism = ism;
+ atomic_inc(&ism->free_clients_cnt);
+ schedule_work(&clients[i]->remove_work);
+ }
+ spin_unlock_irqrestore(&clients_lock, flags);
+
+ wait_event(ism->waitq, !atomic_read(&ism->free_clients_cnt));
- smcd_unregister_dev(ism->smcd);
if (SYSTEM_EID.serial_number[0] != '0' ||
SYSTEM_EID.type[0] != '0')
- ism_del_vlan_id(ism->smcd, ISM_RESERVED_VLANID);
+ ism_del_vlan_id(ism, ISM_RESERVED_VLANID);
unregister_ieq(ism);
unregister_sba(ism);
free_irq(pci_irq_vector(pdev, 0), ism);
+ kfree(ism->sba_client_arr);
pci_free_irq_vectors(pdev);
+ list_del_init(&ism->list);
}
static void ism_remove(struct pci_dev *pdev)
{
struct ism_dev *ism = dev_get_drvdata(&pdev->dev);
+ mutex_lock(&ism_dev_list.mutex);
ism_dev_exit(ism);
+ mutex_unlock(&ism_dev_list.mutex);
- smcd_free_dev(ism->smcd);
+ pci_clear_master(pdev);
pci_release_mem_regions(pdev);
pci_disable_device(pdev);
+ device_del(&ism->dev);
dev_set_drvdata(&pdev->dev, NULL);
kfree(ism);
}
@@ -633,6 +762,8 @@ static int __init ism_init(void)
if (!ism_debug_info)
return -ENODEV;
+ memset(clients, 0, sizeof(clients));
+ max_client = 0;
debug_register_view(ism_debug_info, &debug_hex_ascii_view);
ret = pci_register_driver(&ism_driver);
if (ret)
@@ -643,9 +774,110 @@ static int __init ism_init(void)
static void __exit ism_exit(void)
{
+ struct ism_dev *ism;
+
+ mutex_lock(&ism_dev_list.mutex);
+ list_for_each_entry(ism, &ism_dev_list.list, list) {
+ ism_dev_exit(ism);
+ }
+ mutex_unlock(&ism_dev_list.mutex);
+
pci_unregister_driver(&ism_driver);
debug_unregister(ism_debug_info);
}
module_init(ism_init);
module_exit(ism_exit);
+
+/*************************** SMC-D Implementation *****************************/
+
+#if IS_ENABLED(CONFIG_SMC)
+static int smcd_query_rgid(struct smcd_dev *smcd, u64 rgid, u32 vid_valid,
+ u32 vid)
+{
+ return ism_query_rgid(smcd->priv, rgid, vid_valid, vid);
+}
+
+static int smcd_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
+ struct ism_client *client)
+{
+ return ism_register_dmb(smcd->priv, (struct ism_dmb *)dmb, client);
+}
+
+static int smcd_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
+{
+ return ism_unregister_dmb(smcd->priv, (struct ism_dmb *)dmb);
+}
+
+static int smcd_add_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
+{
+ return ism_add_vlan_id(smcd->priv, vlan_id);
+}
+
+static int smcd_del_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
+{
+ return ism_del_vlan_id(smcd->priv, vlan_id);
+}
+
+static int smcd_set_vlan_required(struct smcd_dev *smcd)
+{
+ return ism_cmd_simple(smcd->priv, ISM_SET_VLAN);
+}
+
+static int smcd_reset_vlan_required(struct smcd_dev *smcd)
+{
+ return ism_cmd_simple(smcd->priv, ISM_RESET_VLAN);
+}
+
+static int smcd_signal_ieq(struct smcd_dev *smcd, u64 rgid, u32 trigger_irq,
+ u32 event_code, u64 info)
+{
+ return ism_signal_ieq(smcd->priv, rgid, trigger_irq, event_code, info);
+}
+
+static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
+ bool sf, unsigned int offset, void *data,
+ unsigned int size)
+{
+ return ism_move(smcd->priv, dmb_tok, idx, sf, offset, data, size);
+}
+
+static u64 smcd_get_local_gid(struct smcd_dev *smcd)
+{
+ return ism_get_local_gid(smcd->priv);
+}
+
+static u16 smcd_get_chid(struct smcd_dev *smcd)
+{
+ return ism_get_chid(smcd->priv);
+}
+
+static inline struct device *smcd_get_dev(struct smcd_dev *dev)
+{
+ struct ism_dev *ism = dev->priv;
+
+ return &ism->dev;
+}
+
+static const struct smcd_ops ism_ops = {
+ .query_remote_gid = smcd_query_rgid,
+ .register_dmb = smcd_register_dmb,
+ .unregister_dmb = smcd_unregister_dmb,
+ .add_vlan_id = smcd_add_vlan_id,
+ .del_vlan_id = smcd_del_vlan_id,
+ .set_vlan_required = smcd_set_vlan_required,
+ .reset_vlan_required = smcd_reset_vlan_required,
+ .signal_event = smcd_signal_ieq,
+ .move_data = smcd_move,
+ .get_system_eid = ism_get_seid,
+ .get_local_gid = smcd_get_local_gid,
+ .get_chid = smcd_get_chid,
+ .get_dev = smcd_get_dev,
+};
+
+const struct smcd_ops *ism_get_smcd_ops(void)
+{
+ return &ism_ops;
+}
+EXPORT_SYMBOL_GPL(ism_get_smcd_ops);
+#endif
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 8bd9fd51208c..1d5b207c2b9e 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -2801,9 +2801,11 @@ static void qeth_print_status_message(struct qeth_card *card)
* of the level OSA sets the first character to zero
* */
if (!card->info.mcl_level[0]) {
- sprintf(card->info.mcl_level, "%02x%02x",
- card->info.mcl_level[2],
- card->info.mcl_level[3]);
+ scnprintf(card->info.mcl_level,
+ sizeof(card->info.mcl_level),
+ "%02x%02x",
+ card->info.mcl_level[2],
+ card->info.mcl_level[3]);
break;
}
fallthrough;
@@ -6090,7 +6092,7 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *fmt, ...)
if (!debug_level_enabled(id, level))
return;
va_start(args, fmt);
- vsnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args);
+ vscnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args);
va_end(args);
debug_text_event(id, level, dbf_txt_buf);
}
@@ -6330,8 +6332,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
goto err_dev;
}
- snprintf(dbf_name, sizeof(dbf_name), "qeth_card_%s",
- dev_name(&gdev->dev));
+ scnprintf(dbf_name, sizeof(dbf_name), "qeth_card_%s",
+ dev_name(&gdev->dev));
card->debug = qeth_get_dbf_entry(dbf_name);
if (!card->debug) {
rc = qeth_add_dbf_entry(card, dbf_name);
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 406be169173c..eea93f8f106f 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -23,15 +23,15 @@ static ssize_t qeth_dev_state_show(struct device *dev,
switch (card->state) {
case CARD_STATE_DOWN:
- return sprintf(buf, "DOWN\n");
+ return sysfs_emit(buf, "DOWN\n");
case CARD_STATE_SOFTSETUP:
if (card->dev->flags & IFF_UP)
- return sprintf(buf, "UP (LAN %s)\n",
- netif_carrier_ok(card->dev) ? "ONLINE" :
- "OFFLINE");
- return sprintf(buf, "SOFTSETUP\n");
+ return sysfs_emit(buf, "UP (LAN %s)\n",
+ netif_carrier_ok(card->dev) ?
+ "ONLINE" : "OFFLINE");
+ return sysfs_emit(buf, "SOFTSETUP\n");
default:
- return sprintf(buf, "UNKNOWN\n");
+ return sysfs_emit(buf, "UNKNOWN\n");
}
}
@@ -42,7 +42,7 @@ static ssize_t qeth_dev_chpid_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%02X\n", card->info.chpid);
+ return sysfs_emit(buf, "%02X\n", card->info.chpid);
}
static DEVICE_ATTR(chpid, 0444, qeth_dev_chpid_show, NULL);
@@ -52,7 +52,7 @@ static ssize_t qeth_dev_if_name_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", netdev_name(card->dev));
+ return sysfs_emit(buf, "%s\n", netdev_name(card->dev));
}
static DEVICE_ATTR(if_name, 0444, qeth_dev_if_name_show, NULL);
@@ -62,7 +62,7 @@ static ssize_t qeth_dev_card_type_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", qeth_get_cardname_short(card));
+ return sysfs_emit(buf, "%s\n", qeth_get_cardname_short(card));
}
static DEVICE_ATTR(card_type, 0444, qeth_dev_card_type_show, NULL);
@@ -86,7 +86,7 @@ static ssize_t qeth_dev_inbuf_size_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", qeth_get_bufsize_str(card));
+ return sysfs_emit(buf, "%s\n", qeth_get_bufsize_str(card));
}
static DEVICE_ATTR(inbuf_size, 0444, qeth_dev_inbuf_size_show, NULL);
@@ -96,7 +96,7 @@ static ssize_t qeth_dev_portno_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%i\n", card->dev->dev_port);
+ return sysfs_emit(buf, "%i\n", card->dev->dev_port);
}
static ssize_t qeth_dev_portno_store(struct device *dev,
@@ -134,7 +134,7 @@ static DEVICE_ATTR(portno, 0644, qeth_dev_portno_show, qeth_dev_portno_store);
static ssize_t qeth_dev_portname_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "no portname required\n");
+ return sysfs_emit(buf, "no portname required\n");
}
static ssize_t qeth_dev_portname_store(struct device *dev,
@@ -157,18 +157,18 @@ static ssize_t qeth_dev_prioqing_show(struct device *dev,
switch (card->qdio.do_prio_queueing) {
case QETH_PRIO_Q_ING_PREC:
- return sprintf(buf, "%s\n", "by precedence");
+ return sysfs_emit(buf, "%s\n", "by precedence");
case QETH_PRIO_Q_ING_TOS:
- return sprintf(buf, "%s\n", "by type of service");
+ return sysfs_emit(buf, "%s\n", "by type of service");
case QETH_PRIO_Q_ING_SKB:
- return sprintf(buf, "%s\n", "by skb-priority");
+ return sysfs_emit(buf, "%s\n", "by skb-priority");
case QETH_PRIO_Q_ING_VLAN:
- return sprintf(buf, "%s\n", "by VLAN headers");
+ return sysfs_emit(buf, "%s\n", "by VLAN headers");
case QETH_PRIO_Q_ING_FIXED:
- return sprintf(buf, "always queue %i\n",
+ return sysfs_emit(buf, "always queue %i\n",
card->qdio.default_out_queue);
default:
- return sprintf(buf, "disabled\n");
+ return sysfs_emit(buf, "disabled\n");
}
}
@@ -242,7 +242,7 @@ static ssize_t qeth_dev_bufcnt_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%i\n", card->qdio.in_buf_pool.buf_count);
+ return sysfs_emit(buf, "%i\n", card->qdio.in_buf_pool.buf_count);
}
static ssize_t qeth_dev_bufcnt_store(struct device *dev,
@@ -298,7 +298,7 @@ static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store);
static ssize_t qeth_dev_performance_stats_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "1\n");
+ return sysfs_emit(buf, "1\n");
}
static ssize_t qeth_dev_performance_stats_store(struct device *dev,
@@ -335,7 +335,7 @@ static ssize_t qeth_dev_layer2_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%i\n", card->options.layer);
+ return sysfs_emit(buf, "%i\n", card->options.layer);
}
static ssize_t qeth_dev_layer2_store(struct device *dev,
@@ -410,13 +410,13 @@ static ssize_t qeth_dev_isolation_show(struct device *dev,
switch (card->options.isolation) {
case ISOLATION_MODE_NONE:
- return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_NONE);
+ return sysfs_emit(buf, "%s\n", ATTR_QETH_ISOLATION_NONE);
case ISOLATION_MODE_FWD:
- return snprintf(buf, 9, "%s\n", ATTR_QETH_ISOLATION_FWD);
+ return sysfs_emit(buf, "%s\n", ATTR_QETH_ISOLATION_FWD);
case ISOLATION_MODE_DROP:
- return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_DROP);
+ return sysfs_emit(buf, "%s\n", ATTR_QETH_ISOLATION_DROP);
default:
- return snprintf(buf, 5, "%s\n", "N/A");
+ return sysfs_emit(buf, "%s\n", "N/A");
}
}
@@ -470,23 +470,25 @@ static ssize_t qeth_dev_switch_attrs_show(struct device *dev,
int rc = 0;
if (!qeth_card_hw_is_reachable(card))
- return sprintf(buf, "n/a\n");
+ return sysfs_emit(buf, "n/a\n");
rc = qeth_query_switch_attributes(card, &sw_info);
if (rc)
return rc;
if (!sw_info.capabilities)
- rc = sprintf(buf, "unknown");
+ rc = sysfs_emit(buf, "unknown");
if (sw_info.capabilities & QETH_SWITCH_FORW_802_1)
- rc = sprintf(buf, (sw_info.settings & QETH_SWITCH_FORW_802_1 ?
- "[802.1]" : "802.1"));
+ rc = sysfs_emit(buf,
+ (sw_info.settings & QETH_SWITCH_FORW_802_1 ?
+ "[802.1]" : "802.1"));
if (sw_info.capabilities & QETH_SWITCH_FORW_REFL_RELAY)
- rc += sprintf(buf + rc,
- (sw_info.settings & QETH_SWITCH_FORW_REFL_RELAY ?
- " [rr]" : " rr"));
- rc += sprintf(buf + rc, "\n");
+ rc += sysfs_emit_at(buf, rc,
+ (sw_info.settings &
+ QETH_SWITCH_FORW_REFL_RELAY ?
+ " [rr]" : " rr"));
+ rc += sysfs_emit_at(buf, rc, "\n");
return rc;
}
@@ -500,9 +502,9 @@ static ssize_t qeth_hw_trap_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
if (card->info.hwtrap)
- return snprintf(buf, 5, "arm\n");
+ return sysfs_emit(buf, "arm\n");
else
- return snprintf(buf, 8, "disarm\n");
+ return sysfs_emit(buf, "disarm\n");
}
static ssize_t qeth_hw_trap_store(struct device *dev,
@@ -573,7 +575,7 @@ static ssize_t qeth_dev_blkt_total_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%i\n", card->info.blkt.time_total);
+ return sysfs_emit(buf, "%i\n", card->info.blkt.time_total);
}
static ssize_t qeth_dev_blkt_total_store(struct device *dev,
@@ -593,7 +595,7 @@ static ssize_t qeth_dev_blkt_inter_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%i\n", card->info.blkt.inter_packet);
+ return sysfs_emit(buf, "%i\n", card->info.blkt.inter_packet);
}
static ssize_t qeth_dev_blkt_inter_store(struct device *dev,
@@ -613,7 +615,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%i\n", card->info.blkt.inter_packet_jumbo);
+ return sysfs_emit(buf, "%i\n", card->info.blkt.inter_packet_jumbo);
}
static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev,
diff --git a/drivers/s390/net/qeth_ethtool.c b/drivers/s390/net/qeth_ethtool.c
index e250f49535fa..c1caf7734c3e 100644
--- a/drivers/s390/net/qeth_ethtool.c
+++ b/drivers/s390/net/qeth_ethtool.c
@@ -172,7 +172,7 @@ static void qeth_get_strings(struct net_device *dev, u32 stringset, u8 *data)
qeth_add_stat_strings(&data, prefix, card_stats,
CARD_STATS_LEN);
for (i = 0; i < card->qdio.no_out_queues; i++) {
- snprintf(prefix, ETH_GSTRING_LEN, "tx%u ", i);
+ scnprintf(prefix, ETH_GSTRING_LEN, "tx%u ", i);
qeth_add_stat_strings(&data, prefix, txq_stats,
TXQ_STATS_LEN);
}
@@ -192,8 +192,8 @@ static void qeth_get_drvinfo(struct net_device *dev,
sizeof(info->driver));
strscpy(info->fw_version, card->info.mcl_level,
sizeof(info->fw_version));
- snprintf(info->bus_info, sizeof(info->bus_info), "%s/%s/%s",
- CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
+ scnprintf(info->bus_info, sizeof(info->bus_info), "%s/%s/%s",
+ CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
}
static void qeth_get_channels(struct net_device *dev,
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index c6ded3fdd715..9f13ed170a43 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -1255,37 +1255,38 @@ static void qeth_bridge_emit_host_event(struct qeth_card *card,
switch (evtype) {
case anev_reg_unreg:
- snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=%s",
- (code & IPA_ADDR_CHANGE_CODE_REMOVAL)
- ? "deregister" : "register");
+ scnprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=%s",
+ (code & IPA_ADDR_CHANGE_CODE_REMOVAL)
+ ? "deregister" : "register");
env[i] = str[i]; i++;
if (code & IPA_ADDR_CHANGE_CODE_VLANID) {
- snprintf(str[i], sizeof(str[i]), "VLAN=%d",
- addr_lnid->lnid);
+ scnprintf(str[i], sizeof(str[i]), "VLAN=%d",
+ addr_lnid->lnid);
env[i] = str[i]; i++;
}
if (code & IPA_ADDR_CHANGE_CODE_MACADDR) {
- snprintf(str[i], sizeof(str[i]), "MAC=%pM",
- addr_lnid->mac);
+ scnprintf(str[i], sizeof(str[i]), "MAC=%pM",
+ addr_lnid->mac);
env[i] = str[i]; i++;
}
- snprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x",
- token->cssid, token->ssid, token->devnum);
+ scnprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x",
+ token->cssid, token->ssid, token->devnum);
env[i] = str[i]; i++;
- snprintf(str[i], sizeof(str[i]), "NTOK_IID=%02x", token->iid);
+ scnprintf(str[i], sizeof(str[i]), "NTOK_IID=%02x", token->iid);
env[i] = str[i]; i++;
- snprintf(str[i], sizeof(str[i]), "NTOK_CHPID=%02x",
- token->chpid);
+ scnprintf(str[i], sizeof(str[i]), "NTOK_CHPID=%02x",
+ token->chpid);
env[i] = str[i]; i++;
- snprintf(str[i], sizeof(str[i]), "NTOK_CHID=%04x", token->chid);
+ scnprintf(str[i], sizeof(str[i]), "NTOK_CHID=%04x",
+ token->chid);
env[i] = str[i]; i++;
break;
case anev_abort:
- snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=abort");
+ scnprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=abort");
env[i] = str[i]; i++;
break;
case anev_reset:
- snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=reset");
+ scnprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=reset");
env[i] = str[i]; i++;
break;
}
@@ -1314,17 +1315,17 @@ static void qeth_bridge_state_change_worker(struct work_struct *work)
NULL
};
- snprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange");
- snprintf(env_role, sizeof(env_role), "ROLE=%s",
- (data->role == QETH_SBP_ROLE_NONE) ? "none" :
- (data->role == QETH_SBP_ROLE_PRIMARY) ? "primary" :
- (data->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" :
- "<INVALID>");
- snprintf(env_state, sizeof(env_state), "STATE=%s",
- (data->state == QETH_SBP_STATE_INACTIVE) ? "inactive" :
- (data->state == QETH_SBP_STATE_STANDBY) ? "standby" :
- (data->state == QETH_SBP_STATE_ACTIVE) ? "active" :
- "<INVALID>");
+ scnprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange");
+ scnprintf(env_role, sizeof(env_role), "ROLE=%s",
+ (data->role == QETH_SBP_ROLE_NONE) ? "none" :
+ (data->role == QETH_SBP_ROLE_PRIMARY) ? "primary" :
+ (data->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" :
+ "<INVALID>");
+ scnprintf(env_state, sizeof(env_state), "STATE=%s",
+ (data->state == QETH_SBP_STATE_INACTIVE) ? "inactive" :
+ (data->state == QETH_SBP_STATE_STANDBY) ? "standby" :
+ (data->state == QETH_SBP_STATE_ACTIVE) ? "active" :
+ "<INVALID>");
kobject_uevent_env(&data->card->gdev->dev.kobj,
KOBJ_CHANGE, env);
kfree(data);
diff --git a/drivers/s390/net/qeth_l2_sys.c b/drivers/s390/net/qeth_l2_sys.c
index a617351fff57..7f592f912517 100644
--- a/drivers/s390/net/qeth_l2_sys.c
+++ b/drivers/s390/net/qeth_l2_sys.c
@@ -19,7 +19,7 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
char *word;
if (!qeth_bridgeport_allowed(card))
- return sprintf(buf, "n/a (VNIC characteristics)\n");
+ return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
mutex_lock(&card->sbp_lock);
if (qeth_card_hw_is_reachable(card) &&
@@ -53,7 +53,7 @@ static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",
card->options.sbp.role, state);
else
- rc = sprintf(buf, "%s\n", word);
+ rc = sysfs_emit(buf, "%s\n", word);
}
mutex_unlock(&card->sbp_lock);
@@ -66,7 +66,7 @@ static ssize_t qeth_bridge_port_role_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
if (!qeth_bridgeport_allowed(card))
- return sprintf(buf, "n/a (VNIC characteristics)\n");
+ return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
return qeth_bridge_port_role_state_show(dev, attr, buf, 0);
}
@@ -117,7 +117,7 @@ static ssize_t qeth_bridge_port_state_show(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
if (!qeth_bridgeport_allowed(card))
- return sprintf(buf, "n/a (VNIC characteristics)\n");
+ return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
}
@@ -132,11 +132,11 @@ static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
int enabled;
if (!qeth_bridgeport_allowed(card))
- return sprintf(buf, "n/a (VNIC characteristics)\n");
+ return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
enabled = card->options.sbp.hostnotification;
- return sprintf(buf, "%d\n", enabled);
+ return sysfs_emit(buf, "%d\n", enabled);
}
static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
@@ -180,7 +180,7 @@ static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
char *state;
if (!qeth_bridgeport_allowed(card))
- return sprintf(buf, "n/a (VNIC characteristics)\n");
+ return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
if (card->options.sbp.reflect_promisc) {
if (card->options.sbp.reflect_promisc_primary)
@@ -190,7 +190,7 @@ static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
} else
state = "none";
- return sprintf(buf, "%s\n", state);
+ return sysfs_emit(buf, "%s\n", state);
}
static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
@@ -280,10 +280,10 @@ static ssize_t qeth_vnicc_timeout_show(struct device *dev,
rc = qeth_l2_vnicc_get_timeout(card, &timeout);
if (rc == -EBUSY)
- return sprintf(buf, "n/a (BridgePort)\n");
+ return sysfs_emit(buf, "n/a (BridgePort)\n");
if (rc == -EOPNOTSUPP)
- return sprintf(buf, "n/a\n");
- return rc ? rc : sprintf(buf, "%d\n", timeout);
+ return sysfs_emit(buf, "n/a\n");
+ return rc ? rc : sysfs_emit(buf, "%d\n", timeout);
}
/* change timeout setting */
@@ -318,10 +318,10 @@ static ssize_t qeth_vnicc_char_show(struct device *dev,
rc = qeth_l2_vnicc_get_state(card, vnicc, &state);
if (rc == -EBUSY)
- return sprintf(buf, "n/a (BridgePort)\n");
+ return sysfs_emit(buf, "n/a (BridgePort)\n");
if (rc == -EOPNOTSUPP)
- return sprintf(buf, "n/a\n");
- return rc ? rc : sprintf(buf, "%d\n", state);
+ return sysfs_emit(buf, "n/a\n");
+ return rc ? rc : sysfs_emit(buf, "%d\n", state);
}
/* change setting of characteristic */
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index d8487a10cd55..af4e60d2917e 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -19,6 +19,7 @@
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/in.h>
+#include <linux/inet.h>
#include <linux/ipv6.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
@@ -46,9 +47,9 @@ int qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const u8 *addr,
char *buf)
{
if (proto == QETH_PROT_IPV4)
- return sprintf(buf, "%pI4", addr);
+ return scnprintf(buf, INET_ADDRSTRLEN, "%pI4", addr);
else
- return sprintf(buf, "%pI6", addr);
+ return scnprintf(buf, INET6_ADDRSTRLEN, "%pI6", addr);
}
static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card,
@@ -158,7 +159,7 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
{
int rc = 0;
struct qeth_ipaddr *addr;
- char buf[40];
+ char buf[INET6_ADDRSTRLEN];
if (tmp_addr->type == QETH_IP_TYPE_RXIP)
QETH_CARD_TEXT(card, 2, "addrxip");
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index 1082380b21f8..9f90a860ca2c 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -32,26 +32,26 @@ static ssize_t qeth_l3_dev_route_show(struct qeth_card *card,
{
switch (route->type) {
case PRIMARY_ROUTER:
- return sprintf(buf, "%s\n", "primary router");
+ return sysfs_emit(buf, "%s\n", "primary router");
case SECONDARY_ROUTER:
- return sprintf(buf, "%s\n", "secondary router");
+ return sysfs_emit(buf, "%s\n", "secondary router");
case MULTICAST_ROUTER:
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
- return sprintf(buf, "%s\n", "multicast router+");
+ return sysfs_emit(buf, "%s\n", "multicast router+");
else
- return sprintf(buf, "%s\n", "multicast router");
+ return sysfs_emit(buf, "%s\n", "multicast router");
case PRIMARY_CONNECTOR:
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
- return sprintf(buf, "%s\n", "primary connector+");
+ return sysfs_emit(buf, "%s\n", "primary connector+");
else
- return sprintf(buf, "%s\n", "primary connector");
+ return sysfs_emit(buf, "%s\n", "primary connector");
case SECONDARY_CONNECTOR:
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
- return sprintf(buf, "%s\n", "secondary connector+");
+ return sysfs_emit(buf, "%s\n", "secondary connector+");
else
- return sprintf(buf, "%s\n", "secondary connector");
+ return sysfs_emit(buf, "%s\n", "secondary connector");
default:
- return sprintf(buf, "%s\n", "no");
+ return sysfs_emit(buf, "%s\n", "no");
}
}
@@ -138,7 +138,7 @@ static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0);
+ return sysfs_emit(buf, "%i\n", card->options.sniffer ? 1 : 0);
}
static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
@@ -200,7 +200,7 @@ static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid));
EBCASC(tmp_hsuid, 8);
- return sprintf(buf, "%s\n", tmp_hsuid);
+ return sysfs_emit(buf, "%s\n", tmp_hsuid);
}
static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
@@ -252,8 +252,8 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
goto out;
}
- snprintf(card->options.hsuid, sizeof(card->options.hsuid),
- "%-8s", tmp);
+ scnprintf(card->options.hsuid, sizeof(card->options.hsuid),
+ "%-8s", tmp);
ASCEBC(card->options.hsuid, 8);
memcpy(card->dev->perm_addr, card->options.hsuid, 9);
@@ -285,7 +285,7 @@ static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", card->ipato.enabled ? 1 : 0);
+ return sysfs_emit(buf, "%u\n", card->ipato.enabled ? 1 : 0);
}
static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
@@ -330,7 +330,7 @@ static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", card->ipato.invert4 ? 1 : 0);
+ return sysfs_emit(buf, "%u\n", card->ipato.invert4 ? 1 : 0);
}
static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
@@ -367,35 +367,21 @@ static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
struct qeth_ipato_entry *ipatoe;
- int str_len = 0;
+ char addr_str[INET6_ADDRSTRLEN];
+ int offset = 0;
mutex_lock(&card->ip_lock);
list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
- char addr_str[40];
- int entry_len;
-
if (ipatoe->proto != proto)
continue;
- entry_len = qeth_l3_ipaddr_to_string(proto, ipatoe->addr,
- addr_str);
- if (entry_len < 0)
- continue;
-
- /* Append /%mask to the entry: */
- entry_len += 1 + ((proto == QETH_PROT_IPV4) ? 2 : 3);
- /* Enough room to format %entry\n into null terminated page? */
- if (entry_len + 1 > PAGE_SIZE - str_len - 1)
- break;
-
- entry_len = scnprintf(buf, PAGE_SIZE - str_len,
- "%s/%i\n", addr_str, ipatoe->mask_bits);
- str_len += entry_len;
- buf += entry_len;
+ qeth_l3_ipaddr_to_string(proto, ipatoe->addr, addr_str);
+ offset += sysfs_emit_at(buf, offset, "%s/%i\n",
+ addr_str, ipatoe->mask_bits);
}
mutex_unlock(&card->ip_lock);
- return str_len ? str_len : scnprintf(buf, PAGE_SIZE, "\n");
+ return offset ? offset : sysfs_emit(buf, "\n");
}
static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev,
@@ -413,7 +399,7 @@ static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto,
int rc;
/* Expected input pattern: %addr/%mask */
- sep = strnchr(buf, 40, '/');
+ sep = strnchr(buf, INET6_ADDRSTRLEN, '/');
if (!sep)
return -EINVAL;
@@ -501,7 +487,7 @@ static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
- return sprintf(buf, "%u\n", card->ipato.invert6 ? 1 : 0);
+ return sysfs_emit(buf, "%u\n", card->ipato.invert6 ? 1 : 0);
}
static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
@@ -586,35 +572,22 @@ static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf,
enum qeth_ip_types type)
{
struct qeth_card *card = dev_get_drvdata(dev);
+ char addr_str[INET6_ADDRSTRLEN];
struct qeth_ipaddr *ipaddr;
- int str_len = 0;
+ int offset = 0;
int i;
mutex_lock(&card->ip_lock);
hash_for_each(card->ip_htable, i, ipaddr, hnode) {
- char addr_str[40];
- int entry_len;
-
if (ipaddr->proto != proto || ipaddr->type != type)
continue;
- entry_len = qeth_l3_ipaddr_to_string(proto, (u8 *)&ipaddr->u,
- addr_str);
- if (entry_len < 0)
- continue;
-
- /* Enough room to format %addr\n into null terminated page? */
- if (entry_len + 1 > PAGE_SIZE - str_len - 1)
- break;
-
- entry_len = scnprintf(buf, PAGE_SIZE - str_len, "%s\n",
- addr_str);
- str_len += entry_len;
- buf += entry_len;
+ qeth_l3_ipaddr_to_string(proto, (u8 *)&ipaddr->u, addr_str);
+ offset += sysfs_emit_at(buf, offset, "%s\n", addr_str);
}
mutex_unlock(&card->ip_lock);
- return str_len ? str_len : scnprintf(buf, PAGE_SIZE, "\n");
+ return offset ? offset : sysfs_emit(buf, "\n");
}
static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev,
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index a10dbe632ef9..954fc31b4bc7 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -363,7 +363,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
thinint_area->isc = VIRTIO_AIRQ_ISC;
ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
ccw->count = sizeof(*thinint_area);
- ccw->cda = (__u32)(unsigned long) thinint_area;
+ ccw->cda = (__u32)virt_to_phys(thinint_area);
} else {
/* payload is the address of the indicators */
indicatorp = ccw_device_dma_zalloc(vcdev->cdev,
@@ -373,7 +373,7 @@ static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev,
*indicatorp = 0;
ccw->cmd_code = CCW_CMD_SET_IND;
ccw->count = sizeof(indicators(vcdev));
- ccw->cda = (__u32)(unsigned long) indicatorp;
+ ccw->cda = (__u32)virt_to_phys(indicatorp);
}
/* Deregister indicators from host. */
*indicators(vcdev) = 0;
@@ -417,7 +417,7 @@ static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
ccw->cmd_code = CCW_CMD_READ_VQ_CONF;
ccw->flags = 0;
ccw->count = sizeof(struct vq_config_block);
- ccw->cda = (__u32)(unsigned long)(&vcdev->dma_area->config_block);
+ ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->config_block);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_VQ_CONF);
if (ret)
return ret;
@@ -454,7 +454,7 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
}
ccw->cmd_code = CCW_CMD_SET_VQ;
ccw->flags = 0;
- ccw->cda = (__u32)(unsigned long)(info->info_block);
+ ccw->cda = (__u32)virt_to_phys(info->info_block);
ret = ccw_io_helper(vcdev, ccw,
VIRTIO_CCW_DOING_SET_VQ | index);
/*
@@ -556,7 +556,7 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
}
ccw->cmd_code = CCW_CMD_SET_VQ;
ccw->flags = 0;
- ccw->cda = (__u32)(unsigned long)(info->info_block);
+ ccw->cda = (__u32)virt_to_phys(info->info_block);
err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
if (err) {
dev_warn(&vcdev->cdev->dev, "SET_VQ failed\n");
@@ -590,6 +590,7 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
{
int ret;
struct virtio_thinint_area *thinint_area = NULL;
+ unsigned long indicator_addr;
struct airq_info *info;
thinint_area = ccw_device_dma_zalloc(vcdev->cdev,
@@ -599,21 +600,22 @@ static int virtio_ccw_register_adapter_ind(struct virtio_ccw_device *vcdev,
goto out;
}
/* Try to get an indicator. */
- thinint_area->indicator = get_airq_indicator(vqs, nvqs,
- &thinint_area->bit_nr,
- &vcdev->airq_info);
- if (!thinint_area->indicator) {
+ indicator_addr = get_airq_indicator(vqs, nvqs,
+ &thinint_area->bit_nr,
+ &vcdev->airq_info);
+ if (!indicator_addr) {
ret = -ENOSPC;
goto out;
}
+ thinint_area->indicator = virt_to_phys((void *)indicator_addr);
info = vcdev->airq_info;
thinint_area->summary_indicator =
- (unsigned long) get_summary_indicator(info);
+ virt_to_phys(get_summary_indicator(info));
thinint_area->isc = VIRTIO_AIRQ_ISC;
ccw->cmd_code = CCW_CMD_SET_IND_ADAPTER;
ccw->flags = CCW_FLAG_SLI;
ccw->count = sizeof(*thinint_area);
- ccw->cda = (__u32)(unsigned long)thinint_area;
+ ccw->cda = (__u32)virt_to_phys(thinint_area);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND_ADAPTER);
if (ret) {
if (ret == -EOPNOTSUPP) {
@@ -686,7 +688,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
ccw->cmd_code = CCW_CMD_SET_IND;
ccw->flags = 0;
ccw->count = sizeof(indicators(vcdev));
- ccw->cda = (__u32)(unsigned long) indicatorp;
+ ccw->cda = (__u32)virt_to_phys(indicatorp);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_IND);
if (ret)
goto out;
@@ -697,7 +699,7 @@ static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs,
ccw->cmd_code = CCW_CMD_SET_CONF_IND;
ccw->flags = 0;
ccw->count = sizeof(indicators2(vcdev));
- ccw->cda = (__u32)(unsigned long) indicatorp;
+ ccw->cda = (__u32)virt_to_phys(indicatorp);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_CONF_IND);
if (ret)
goto out;
@@ -759,7 +761,7 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_READ_FEAT;
ccw->flags = 0;
ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
+ ccw->cda = (__u32)virt_to_phys(features);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
if (ret) {
rc = 0;
@@ -776,7 +778,7 @@ static u64 virtio_ccw_get_features(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_READ_FEAT;
ccw->flags = 0;
ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
+ ccw->cda = (__u32)virt_to_phys(features);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
if (ret == 0)
rc |= (u64)le32_to_cpu(features->features) << 32;
@@ -829,7 +831,7 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_WRITE_FEAT;
ccw->flags = 0;
ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
+ ccw->cda = (__u32)virt_to_phys(features);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
if (ret)
goto out_free;
@@ -843,7 +845,7 @@ static int virtio_ccw_finalize_features(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_WRITE_FEAT;
ccw->flags = 0;
ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
+ ccw->cda = (__u32)virt_to_phys(features);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
out_free:
@@ -875,7 +877,7 @@ static void virtio_ccw_get_config(struct virtio_device *vdev,
ccw->cmd_code = CCW_CMD_READ_CONF;
ccw->flags = 0;
ccw->count = offset + len;
- ccw->cda = (__u32)(unsigned long)config_area;
+ ccw->cda = (__u32)virt_to_phys(config_area);
ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_CONFIG);
if (ret)
goto out_free;
@@ -922,7 +924,7 @@ static void virtio_ccw_set_config(struct virtio_device *vdev,
ccw->cmd_code = CCW_CMD_WRITE_CONF;
ccw->flags = 0;
ccw->count = offset + len;
- ccw->cda = (__u32)(unsigned long)config_area;
+ ccw->cda = (__u32)virt_to_phys(config_area);
ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_CONFIG);
out_free:
@@ -946,7 +948,7 @@ static u8 virtio_ccw_get_status(struct virtio_device *vdev)
ccw->cmd_code = CCW_CMD_READ_STATUS;
ccw->flags = 0;
ccw->count = sizeof(vcdev->dma_area->status);
- ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status;
+ ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->status);
ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS);
/*
* If the channel program failed (should only happen if the device
@@ -975,7 +977,7 @@ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
ccw->cmd_code = CCW_CMD_WRITE_STATUS;
ccw->flags = 0;
ccw->count = sizeof(status);
- ccw->cda = (__u32)(unsigned long)&vcdev->dma_area->status;
+ ccw->cda = (__u32)virt_to_phys(&vcdev->dma_area->status);
/* We use ssch for setting the status which is a serializing
* instruction that guarantees the memory writes have
* completed before ssch.
@@ -1274,7 +1276,7 @@ static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
ccw->cmd_code = CCW_CMD_SET_VIRTIO_REV;
ccw->flags = 0;
ccw->count = sizeof(*rev);
- ccw->cda = (__u32)(unsigned long)rev;
+ ccw->cda = (__u32)virt_to_phys(rev);
vcdev->revision = VIRTIO_CCW_REV_MAX;
do {