diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-25 08:36:50 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-25 08:36:50 -0700 |
commit | c4a6eb3b7d5b483de331313e7ea38a6891a3447a (patch) | |
tree | de415b67626308b1fa414e47f17959939c017c92 /drivers | |
parent | 33081adf8b89d5a716d7e1c60171768d39795b39 (diff) | |
parent | 96f4a70d8eb4d746b19d5b5510407c8ff0d00340 (diff) |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (48 commits)
[S390] topology: export cpu topology via proc/sysinfo
[S390] topology: move topology sysinfo code
[S390] topology: clean up facility detection
[S390] cleanup facility list handling
[S390] enable ARCH_DMA_ADDR_T_64BIT with 64BIT
[S390] dasd: ignore unsolicited interrupts for DIAG
[S390] kvm: Enable z196 instruction facilities
[S390] dasd: fix unsolicited interrupt recognition
[S390] dasd: fix use after free in dbf
[S390] kvm: Fix badness at include/asm/mmu_context.h:83
[S390] cio: fix I/O cancel function
[S390] topology: change default
[S390] smp: use correct cpu address in print_cpu_info()
[S390] remove ieee_instruction_pointer from thread_struct
[S390] cleanup system call parameter setup
[S390] correct alignment of cpuid structure
[S390] cleanup lowcore access from external interrupts
[S390] cleanup lowcore access from program checks
[S390] pgtable: move pte_mkhuge() from hugetlb.h to pgtable.h
[S390] fix SIGBUS handling
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/hvc_iucv.c | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd.c | 24 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 3 | ||||
-rw-r--r-- | drivers/s390/block/dasd_diag.c | 19 | ||||
-rw-r--r-- | drivers/s390/block/dasd_diag.h | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 68 | ||||
-rw-r--r-- | drivers/s390/block/dasd_proc.c | 1 | ||||
-rw-r--r-- | drivers/s390/char/sclp.c | 14 | ||||
-rw-r--r-- | drivers/s390/char/vmlogrdr.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/blacklist.c | 10 | ||||
-rw-r--r-- | drivers/s390/cio/chp.c | 41 | ||||
-rw-r--r-- | drivers/s390/cio/chp.h | 12 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 291 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 28 | ||||
-rw-r--r-- | drivers/s390/cio/chsc_sch.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 50 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 18 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 41 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 23 | ||||
-rw-r--r-- | drivers/s390/cio/io_sch.h | 7 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 9 | ||||
-rw-r--r-- | drivers/s390/kvm/kvm_virtio.c | 9 |
22 files changed, 378 insertions, 314 deletions
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 7b01bc609de..c3425bb3a1f 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -1303,13 +1303,11 @@ static int __init hvc_iucv_init(void) if (rc) { pr_err("Registering IUCV handlers failed with error code=%d\n", rc); - goto out_error_iucv; + goto out_error_hvc; } return 0; -out_error_iucv: - iucv_unregister(&hvc_iucv_handler, 0); out_error_hvc: for (i = 0; i < hvc_iucv_devices; i++) if (hvc_iucv_table[i]) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index aa95f100176..fb613d70c2c 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1099,16 +1099,30 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, cqr = (struct dasd_ccw_req *) intparm; if (!cqr || ((scsw_cc(&irb->scsw) == 1) && (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && - (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) { + ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) || + (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND | + SCSW_STCTL_ALERT_STATUS))))) { if (cqr && cqr->status == DASD_CQR_IN_IO) cqr->status = DASD_CQR_QUEUED; + if (cqr) + memcpy(&cqr->irb, irb, sizeof(*irb)); device = dasd_device_from_cdev_locked(cdev); - if (!IS_ERR(device)) { - dasd_device_clear_timer(device); - device->discipline->handle_unsolicited_interrupt(device, - irb); + if (IS_ERR(device)) + return; + /* ignore unsolicited interrupts for DIAG discipline */ + if (device->discipline == dasd_diag_discipline_pointer) { dasd_put_device(device); + return; } + device->discipline->dump_sense_dbf(device, irb, + "unsolicited"); + if ((device->features & DASD_FEATURE_ERPLOG)) + device->discipline->dump_sense(device, cqr, + irb); + dasd_device_clear_timer(device); + device->discipline->handle_unsolicited_interrupt(device, + irb); + dasd_put_device(device); return; } diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index e82d427ff5e..968c76cf712 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -221,6 +221,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier) ccw->cmd_code = CCW_CMD_DCTL; ccw->count = 4; ccw->cda = (__u32)(addr_t) DCTL_data; + dctl_cqr->flags = erp->flags; dctl_cqr->function = dasd_3990_erp_DCTL; dctl_cqr->refers = erp; dctl_cqr->startdev = device; @@ -1710,6 +1711,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) ccw->cda = cpa; /* fill erp related fields */ + erp->flags = default_erp->flags; erp->function = dasd_3990_erp_action_1B_32; erp->refers = default_erp->refers; erp->startdev = device; @@ -2354,6 +2356,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) ccw->cda = (long)(cqr->cpaddr); } + erp->flags = cqr->flags; erp->function = dasd_3990_erp_add_erp; erp->refers = cqr; erp->startdev = device; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 2b3bc3ec054..266b34b5540 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -228,25 +228,22 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr) } /* Handle external interruption. */ -static void -dasd_ext_handler(__u16 code) +static void dasd_ext_handler(unsigned int ext_int_code, + unsigned int param32, unsigned long param64) { struct dasd_ccw_req *cqr, *next; struct dasd_device *device; unsigned long long expires; unsigned long flags; - u8 int_code, status; addr_t ip; int rc; - int_code = *((u8 *) DASD_DIAG_LC_INT_CODE); - status = *((u8 *) DASD_DIAG_LC_INT_STATUS); - switch (int_code) { + switch (ext_int_code >> 24) { case DASD_DIAG_CODE_31BIT: - ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT); + ip = (addr_t) param32; break; case DASD_DIAG_CODE_64BIT: - ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT); + ip = (addr_t) param64; break; default: return; @@ -281,7 +278,7 @@ dasd_ext_handler(__u16 code) cqr->stopclk = get_clock(); expires = 0; - if (status == 0) { + if ((ext_int_code & 0xff0000) == 0) { cqr->status = DASD_CQR_SUCCESS; /* Start first request on queue if possible -> fast_io. */ if (!list_empty(&device->ccw_queue)) { @@ -296,8 +293,8 @@ dasd_ext_handler(__u16 code) } else { cqr->status = DASD_CQR_QUEUED; DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for " - "request %p was %d (%d retries left)", cqr, status, - cqr->retries); + "request %p was %d (%d retries left)", cqr, + (ext_int_code >> 16) & 0xff, cqr->retries); dasd_diag_erp(device); } diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h index b8c78267ff3..4f71fbe60c8 100644 --- a/drivers/s390/block/dasd_diag.h +++ b/drivers/s390/block/dasd_diag.h @@ -18,10 +18,6 @@ #define DEV_CLASS_FBA 0x01 #define DEV_CLASS_ECKD 0x04 -#define DASD_DIAG_LC_INT_CODE 132 -#define DASD_DIAG_LC_INT_STATUS 133 -#define DASD_DIAG_LC_INT_PARM_31BIT 128 -#define DASD_DIAG_LC_INT_PARM_64BIT 4536 #define DASD_DIAG_CODE_31BIT 0x03 #define DASD_DIAG_CODE_64BIT 0x07 diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 59b4ecfb967..50cf96389d2 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1776,13 +1776,13 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, } /* summary unit check */ - if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && - (irb->ecw[7] == 0x0D)) { + sense = dasd_get_sense(irb); + if (sense && (sense[7] == 0x0D) && + (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { dasd_alias_handle_summary_unit_check(device, irb); return; } - sense = dasd_get_sense(irb); /* service information message SIM */ if (sense && !(sense[27] & DASD_SENSE_BIT_0) && ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) { @@ -1791,26 +1791,15 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, return; } - if ((scsw_cc(&irb->scsw) == 1) && - (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) && - (scsw_actl(&irb->scsw) & SCSW_ACTL_START_PEND) && - (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) { + if ((scsw_cc(&irb->scsw) == 1) && !sense && + (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) && + (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) && + (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) { /* fake irb do nothing, they are handled elsewhere */ dasd_schedule_device_bh(device); return; } - if (!sense) { - /* just report other unsolicited interrupts */ - DBF_DEV_EVENT(DBF_ERR, device, "%s", - "unsolicited interrupt received"); - } else { - DBF_DEV_EVENT(DBF_ERR, device, "%s", - "unsolicited interrupt received " - "(sense available)"); - device->discipline->dump_sense_dbf(device, irb, "unsolicited"); - } - dasd_schedule_device_bh(device); return; }; @@ -3093,19 +3082,19 @@ dasd_eckd_dump_sense_dbf(struct dasd_device *device, struct irb *irb, char *reason) { u64 *sense; + u64 *stat; sense = (u64 *) dasd_get_sense(irb); + stat = (u64 *) &irb->scsw; if (sense) { - DBF_DEV_EVENT(DBF_EMERG, device, - "%s: %s %02x%02x%02x %016llx %016llx %016llx " - "%016llx", reason, - scsw_is_tm(&irb->scsw) ? "t" : "c", - scsw_cc(&irb->scsw), scsw_cstat(&irb->scsw), - scsw_dstat(&irb->scsw), sense[0], sense[1], - sense[2], sense[3]); + DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : " + "%016llx %016llx %016llx %016llx", + reason, *stat, *((u32 *) (stat + 1)), + sense[0], sense[1], sense[2], sense[3]); } else { - DBF_DEV_EVENT(DBF_EMERG, device, "%s", - "SORRY - NO VALID SENSE AVAILABLE\n"); + DBF_DEV_EVENT(DBF_EMERG, device, "%s: %016llx %08x : %s", + reason, *stat, *((u32 *) (stat + 1)), + "NO VALID SENSE"); } } @@ -3131,9 +3120,12 @@ static void dasd_eckd_dump_sense_ccw(struct dasd_device *device, " I/O status report for device %s:\n", dev_name(&device->cdev->dev)); len += sprintf(page + len, KERN_ERR PRINTK_HEADER - " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d\n", - req, scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), - scsw_cc(&irb->scsw), req ? req->intrc : 0); + " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X " + "CS:%02X RC:%d\n", + req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw), + scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw), + scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw), + req ? req->intrc : 0); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", dev_name(&device->cdev->dev), @@ -3234,11 +3226,13 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, " I/O status report for device %s:\n", dev_name(&device->cdev->dev)); len += sprintf(page + len, KERN_ERR PRINTK_HEADER - " in req: %p CS: 0x%02X DS: 0x%02X CC: 0x%02X RC: %d " - "fcxs: 0x%02X schxs: 0x%02X\n", req, - scsw_cstat(&irb->scsw), scsw_dstat(&irb->scsw), - scsw_cc(&irb->scsw), req->intrc, - irb->scsw.tm.fcxs, irb->scsw.tm.schxs); + " in req: %p CC:%02X FC:%02X AC:%02X SC:%02X DS:%02X " + "CS:%02X fcxs:%02X schxs:%02X RC:%d\n", + req, scsw_cc(&irb->scsw), scsw_fctl(&irb->scsw), + scsw_actl(&irb->scsw), scsw_stctl(&irb->scsw), + scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw), + irb->scsw.tm.fcxs, irb->scsw.tm.schxs, + req ? req->intrc : 0); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing TCW: %p\n", dev_name(&device->cdev->dev), @@ -3246,7 +3240,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, tsb = NULL; sense = NULL; - if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs == 0x01)) + if (irb->scsw.tm.tcw && (irb->scsw.tm.fcxs & 0x01)) tsb = tcw_get_tsb( (struct tcw *)(unsigned long)irb->scsw.tm.tcw); @@ -3344,7 +3338,7 @@ static void dasd_eckd_dump_sense_tcw(struct dasd_device *device, static void dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req *req, struct irb *irb) { - if (req && scsw_is_tm(&req->irb.scsw)) + if (scsw_is_tm(&irb->scsw)) dasd_eckd_dump_sense_tcw(device, req, irb); else dasd_eckd_dump_sense_ccw(device, req, irb); diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 2eb02559280..c4a6a31bd9c 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -251,7 +251,6 @@ static ssize_t dasd_stats_proc_write(struct file *file, buffer = dasd_get_user_string(user_buf, user_len); if (IS_ERR(buffer)) return PTR_ERR(buffer); - DBF_EVENT(DBF_DEBUG, "/proc/dasd/statictics: '%s'\n", buffer); /* check for valid verbs */ str = skip_spaces(buffer); diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 5707a80b96b..35cc4686b99 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -395,16 +395,16 @@ __sclp_find_req(u32 sccb) /* Handler for external interruption. Perform request post-processing. * Prepare read event data request if necessary. Start processing of next * request on queue. */ -static void -sclp_interrupt_handler(__u16 code) +static void sclp_interrupt_handler(unsigned int ext_int_code, + unsigned int param32, unsigned long param64) { struct sclp_req *req; u32 finished_sccb; u32 evbuf_pending; spin_lock(&sclp_lock); - finished_sccb = S390_lowcore.ext_params & 0xfffffff8; - evbuf_pending = S390_lowcore.ext_params & 0x3; + finished_sccb = param32 & 0xfffffff8; + evbuf_pending = param32 & 0x3; if (finished_sccb) { del_timer(&sclp_request_timer); sclp_running_state = sclp_running_state_reset_pending; @@ -819,12 +819,12 @@ EXPORT_SYMBOL(sclp_reactivate); /* Handler for external interruption used during initialization. Modify * request state to done. */ -static void -sclp_check_handler(__u16 code) +static void sclp_check_handler(unsigned int ext_int_code, + unsigned int param32, unsigned long param64) { u32 finished_sccb; - finished_sccb = S390_lowcore.ext_params & 0xfffffff8; + finished_sccb = param32 & 0xfffffff8; /* Is this the interrupt we are waiting for? */ if (finished_sccb == 0) return; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 0d6dc4b92cc..9f661426e4a 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -215,7 +215,7 @@ static void vmlogrdr_iucv_message_pending(struct iucv_path *path, static int vmlogrdr_get_recording_class_AB(void) { - char cp_command[]="QUERY COMMAND RECORDING "; + static const char cp_command[] = "QUERY COMMAND RECORDING "; char cp_response[80]; char *tail; int len,i; @@ -638,7 +638,7 @@ static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { - char cp_command[] = "QUERY RECORDING "; + static const char cp_command[] = "QUERY RECORDING "; int len; cpcmd(cp_command, buf, 4096, NULL); diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 13cb60162e4..76058a5166e 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -79,17 +79,15 @@ static int pure_hex(char **cp, unsigned int *val, int min_digit, int max_digit, int max_val) { int diff; - unsigned int value; diff = 0; *val = 0; - while (isxdigit(**cp) && (diff <= max_digit)) { + while (diff <= max_digit) { + int value = hex_to_bin(**cp); - if (isdigit(**cp)) - value = **cp - '0'; - else - value = tolower(**cp) - 'a' + 10; + if (value < 0) + break; *val = *val * 16 + value; (*cp)++; diff++; diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 6c9fa15aac7..2d32233943a 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/chp.c * - * Copyright IBM Corp. 1999,2007 + * Copyright IBM Corp. 1999,2010 * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> @@ -54,12 +54,6 @@ static struct work_struct cfg_work; /* Wait queue for configure completion events. */ static wait_queue_head_t cfg_wait_queue; -/* Return channel_path struct for given chpid. */ -static inline struct channel_path *chpid_to_chp(struct chp_id chpid) -{ - return channel_subsystems[chpid.cssid]->chps[chpid.id]; -} - /* Set vary state for given chpid. */ static void set_chp_logically_online(struct chp_id chpid, int onoff) { @@ -241,11 +235,13 @@ static ssize_t chp_status_show(struct device *dev, struct device_attribute *attr, char *buf) { struct channel_path *chp = to_channelpath(dev); + int status; - if (!chp) - return 0; - return (chp_get_status(chp->chpid) ? sprintf(buf, "online\n") : - sprintf(buf, "offline\n")); + mutex_lock(&chp->lock); + status = chp->state; + mutex_unlock(&chp->lock); + + return status ? sprintf(buf, "online\n") : sprintf(buf, "offline\n"); } static ssize_t chp_status_write(struct device *dev, @@ -261,15 +257,18 @@ static ssize_t chp_status_write(struct device *dev, if (!num_args) return count; - if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1")) + if (!strnicmp(cmd, "on", 2) || !strcmp(cmd, "1")) { + mutex_lock(&cp->lock); error = s390_vary_chpid(cp->chpid, 1); - else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0")) + mutex_unlock(&cp->lock); + } else if (!strnicmp(cmd, "off", 3) || !strcmp(cmd, "0")) { + mutex_lock(&cp->lock); error = s390_vary_chpid(cp->chpid, 0); - else + mutex_unlock(&cp->lock); + } else error = -EINVAL; return error < 0 ? error : count; - } static DEVICE_ATTR(status, 0644, chp_status_show, chp_status_write); @@ -315,10 +314,12 @@ static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct channel_path *chp = to_channelpath(dev); + u8 type; - if (!chp) - return 0; - return sprintf(buf, "%x\n", chp->desc.desc); + mutex_lock(&chp->lock); + type = chp->desc.desc; + mutex_unlock(&chp->lock); + return sprintf(buf, "%x\n", type); } static DEVICE_ATTR(type, 0444, chp_type_show, NULL); @@ -395,6 +396,7 @@ int chp_new(struct chp_id chpid) chp->state = 1; chp->dev.parent = &channel_subsystems[chpid.cssid]->device; chp->dev.release = chp_release; + mutex_init(&chp->lock); /* Obtain channel path description and fill it in. */ ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc); @@ -464,7 +466,10 @@ void *chp_get_chp_desc(struct chp_id chpid) desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); if (!desc) return NULL; + + mutex_lock(&chp->lock); memcpy(desc, &chp->desc, sizeof(struct channel_path_desc)); + mutex_unlock(&chp->lock); return desc; } diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index 26c3d224617..12b4903d6fe 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h @@ -1,7 +1,7 @@ /* * drivers/s390/cio/chp.h * - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2007,2010 * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> */ @@ -10,6 +10,7 @@ #include <linux/types.h> #include <linux/device.h> +#include <linux/mutex.h> #include <asm/chpid.h> #include "chsc.h" #include "css.h" @@ -40,16 +41,23 @@ static inline int chp_test_bit(u8 *bitmap, int num) struct channel_path { + struct device dev; struct chp_id chpid; + struct mutex lock; /* Serialize access to below members. */ int state; struct channel_path_desc desc; /* Channel-measurement related stuff: */ int cmg; int shared; void *cmg_chars; - struct device dev; }; +/* Return channel_path struct for given chpid. */ +static inline struct channel_path *chpid_to_chp(struct chp_id chpid) +{ + return channel_subsystems[chpid.cssid]->chps[chpid.id]; +} + int chp_get_status(struct chp_id chpid); u8 chp_get_sch_opm(struct subchannel *sch); int chp_is_registered(struct chp_id chpid); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 4cbb1a6ca33..1aaddea673e 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -2,7 +2,7 @@ * drivers/s390/cio/chsc.c * S/390 common I/O routines -- channel subsystem call * - * Copyright IBM Corp. 1999,2008 + * Copyright IBM Corp. 1999,2010 * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) @@ -29,8 +29,8 @@ #include "chsc.h" static void *sei_page; -static DEFINE_SPINLOCK(siosl_lock); -static DEFINE_SPINLOCK(sda_lock); +static void *chsc_page; +static DEFINE_SPINLOCK(chsc_page_lock); /** * chsc_error_from_response() - convert a chsc response to an error @@ -85,17 +85,15 @@ struct chsc_ssd_area { int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) { - unsigned long page; struct chsc_ssd_area *ssd_area; int ccode; int ret; int i; int mask; - page = get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!page) - return -ENOMEM; - ssd_area = (struct chsc_ssd_area *) page; + spin_lock_irq(&chsc_page_lock); + memset(chsc_page, 0, PAGE_SIZE); + ssd_area = chsc_page; ssd_area->request.length = 0x0010; ssd_area->request.code = 0x0004; ssd_area->ssid = schid.ssid; @@ -106,25 +104,25 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) /* Check response. */ if (ccode > 0) { ret = (ccode == 3) ? -ENODEV : -EBUSY; - goto out_free; + goto out; } ret = chsc_error_from_response(ssd_area->response.code); if (ret != 0) { CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", schid.ssid, schid.sch_no, ssd_area->response.code); - goto out_free; + goto out; } if (!ssd_area->sch_valid) { ret = -ENODEV; - goto out_free; + goto out; } /* Copy data */ ret = 0; memset(ssd, 0, sizeof(struct chsc_ssd_info)); if ((ssd_area->st != SUBCHANNEL_TYPE_IO) && (ssd_area->st != SUBCHANNEL_TYPE_MSG)) - goto out_free; + goto out; ssd->path_mask = ssd_area->path_mask; ssd->fla_valid_mask = ssd_area->fla_valid_mask; for (i = 0; i < 8; i++) { @@ -136,8 +134,8 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) if (ssd_area->fla_valid_mask & mask) ssd->fla[i] = ssd_area->fla[i]; } -out_free: - free_page(page); +out: + spin_unlock_irq(&chsc_page_lock); return ret; } @@ -497,6 +495,7 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) */ int chsc_chp_vary(struct chp_id chpid, int on) { + struct channel_path *chp = chpid_to_chp(chpid); struct chp_link link; memset(&link, 0, sizeof(struct chp_link)); @@ -506,11 +505,12 @@ int chsc_chp_vary(struct chp_id chpid, int on) /* * Redo PathVerification on the devices the chpid connects to */ - - if (on) + if (on) { + /* Try to update the channel path descritor. */ + chsc_determine_base_channel_path_desc(chpid, &chp->desc); for_each_subchannel_staged(s390_subchannel_vary_chpid_on, __s390_vary_chpid_on, &link); - else + } else for_each_subchannel_staged(s390_subchannel_vary_chpid_off, NULL, &link); @@ -552,7 +552,7 @@ cleanup: return ret; } -int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) +int __chsc_do_secm(struct channel_subsystem *css, int enable) { struct { struct chsc_header request; @@ -573,7 +573,9 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) } __attribute__ ((packed)) *secm_area; int ret, ccode; - secm_area = page; + spin_lock_irq(&chsc_page_lock); + memset(chsc_page, 0, PAGE_SIZE); + secm_area = chsc_page; secm_area->request.length = 0x0050; secm_area->request.code = 0x0016; @@ -584,8 +586,10 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) secm_area->operation_code = enable ? 0 : 1; ccode = chsc(secm_area); - if (ccode > 0) - return (ccode == 3) ? -ENODEV : -EBUSY; + if (ccode > 0) { + ret = (ccode == 3) ? -ENODEV : -EBUSY; + goto out; + } switch (secm_area->response.code) { case 0x0102: @@ -598,37 +602,32 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) if (ret != 0) CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n", secm_area->response.code); +out: + spin_unlock_irq(&chsc_page_lock); return ret; } int chsc_secm(struct channel_subsystem *css, int enable) { - void *secm_area; int ret; - secm_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!secm_area) - return -ENOMEM; - if (enable && !css->cm_enabled) { css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!css->cub_addr1 || !css->cub_addr2) { free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); - free_page((unsigned long)secm_area); return -ENOMEM; } } - ret = __chsc_do_secm(css, enable, secm_area); + ret = __chsc_do_secm(css, enable); if (!ret) { css->cm_enabled = enable; if (css->cm_enabled) { ret = chsc_add_cmg_attr(css); if (ret) { - memset(secm_area, 0, PAGE_SIZE); - __chsc_do_secm(css, 0, secm_area); + __chsc_do_secm(css, 0); css->cm_enabled = 0; } } else @@ -638,44 +637,24 @@ chsc_secm(struct channel_subsystem *css, int enable) free_page((unsigned long)css->cub_addr1); free_page((unsigned long)css->cub_addr2); } - free_page((unsigned long)secm_area); return ret; } int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, - int c, int m, - struct chsc_response_struct *resp) + int c, int m, void *page) { + struct chsc_scpd *scpd_area; int ccode, ret; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 c : 1; - u32 fmt : 4; - u32 cssid : 8; - u32 : 4; - u32 rfmt : 4; - u32 first_chpid : 8; - u32 : 24; - u32 last_chpid : 8; - u32 zeroes1; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *scpd_area; - if ((rfmt == 1) && !css_general_characteristics.fcs) return -EINVAL; if ((rfmt == 2) && !css_general_characteristics.cib) return -EINVAL; - scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!scpd_area) - return -ENOMEM; + memset(page, 0, PAGE_SIZE); + scpd_area = page; scpd_area->request.length = 0x0010; scpd_area->request.code = 0x0002; - scpd_area->cssid = chpid.cssid; scpd_area->first_chpid = chpid.id; scpd_area->last_chpid = chpid.id; @@ -685,20 +664,13 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, scpd_area->rfmt = rfmt; ccode = chsc(scpd_area); - if (ccode > 0) { - ret = (ccode == 3) ? -ENODEV : -EBUSY; - goto out; - } + if (ccode > 0) + return (ccode == 3) ? -ENODEV : -EBUSY; ret = chsc_error_from_response(scpd_area->response.code); - if (ret == 0) - /* Success. */ - memcpy(resp, &scpd_area->response, scpd_area->response.length); - else + if (ret) CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", scpd_area->response.code); -out: - free_page((unsigned long)scpd_area); return ret; } EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); @@ -707,17 +679,19 @@ int chsc_determine_base_channel_path_desc(struct chp_id chpid, struct channel_path_desc *desc) { struct chsc_response_struct *chsc_resp; + struct chsc_scpd *scpd_area; + unsigned long flags; int ret; - chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL); - if (!chsc_resp) - return -ENOMEM; - ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp); + spin_lock_irqsave(&chsc_page_lock, flags); + scpd_area = chsc_page; + ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, scpd_area); if (ret) - goto out_free; + goto out; + chsc_resp = (void *)&scpd_area->response; memcpy(desc, &chsc_resp->data, sizeof(*desc)); -out_free: - kfree(chsc_resp); +out: + spin_unlock_irqrestore(&chsc_page_lock, flags); return ret; } @@ -725,33 +699,22 @@ static void chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, struct cmg_chars *chars) { - switch (chp->cmg) { - case 2: - case 3: - chp->cmg_chars = kmalloc(sizeof(struct cmg_chars), - GFP_KERNEL); - if (chp->cmg_chars) { - int i, mask; - struct cmg_chars *cmg_chars; - - cmg_chars = chp->cmg_chars; - for (i = 0; i < NR_MEASUREMENT_CHARS; i++) { - mask = 0x80 >> (i + 3); - if (cmcv & mask) - cmg_chars->values[i] = chars->values[i]; - else - cmg_chars- |