diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-21 12:10:17 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-21 12:10:17 -0700 |
commit | 267b50fe6fedb1ea9e25702129b95a1dfd19b31c (patch) | |
tree | 41a9335ec5d51f4fb9d1c915fbefaf381f977094 /drivers | |
parent | 8ca7de91640a9840a0d29021d17492be7fd8232b (diff) | |
parent | 03429f34c22cedc3300a81e13d5790450cc468af (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Martin Schwidefsky:
"Bug fixes for 3.6-rc7, including some important patches for large page
related memory management issues."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390/dasd: fix read unit address configuration loop
s390/dasd: fix pathgroup race
s390/mm: fix user access page-table walk code
s390/hwcaps: do not report high gprs for 31 bit kernel
s390/cio: invalidate cdev pointer before deregistration
s390/cio: fix IO subchannel event race
s390/dasd: move wake_up call
s390/hugetlb: use direct TLB flushing for hugetlbfs pages
s390/mm: fix deadlock in unmap_hugepage_range()
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/block/dasd.c | 17 | ||||
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 27 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 32 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 7 |
4 files changed, 71 insertions, 12 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 15370a2c5ff0..0595c763dafd 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -534,11 +534,11 @@ static void dasd_change_state(struct dasd_device *device) if (rc) device->target = device->state; - if (device->state == device->target) - wake_up(&dasd_init_waitq); - /* let user-space know that the device status changed */ kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE); + + if (device->state == device->target) + wake_up(&dasd_init_waitq); } /* @@ -2157,6 +2157,7 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible) test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && (!dasd_eer_enabled(device))) { cqr->status = DASD_CQR_FAILED; + cqr->intrc = -EAGAIN; continue; } /* Don't try to start requests if device is stopped */ @@ -3270,6 +3271,16 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event) dasd_schedule_device_bh(device); } if (path_event[chp] & PE_PATHGROUP_ESTABLISHED) { + if (!(device->path_data.opm & eventlpm) && + !(device->path_data.tbvpm & eventlpm)) { + /* + * we can not establish a pathgroup on an + * unavailable path, so trigger a path + * verification first + */ + device->path_data.tbvpm |= eventlpm; + dasd_schedule_device_bh(device); + } DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Pathgroup re-established\n"); if (device->discipline->kick_validate) diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 157defe5e069..6b556995bb33 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -384,6 +384,29 @@ static void _remove_device_from_lcu(struct alias_lcu *lcu, group->next = NULL; }; +static int +suborder_not_supported(struct dasd_ccw_req *cqr) +{ + char *sense; + char reason; + char msg_format; + char msg_no; + + sense = dasd_get_sense(&cqr->irb); + if (!sense) + return 0; + + reason = sense[0]; + msg_format = (sense[7] & 0xF0); + msg_no = (sense[7] & 0x0F); + + /* command reject, Format 0 MSG 4 - invalid parameter */ + if ((reason == 0x80) && (msg_format == 0x00) && (msg_no == 0x04)) + return 1; + + return 0; +} + static int read_unit_address_configuration(struct dasd_device *device, struct alias_lcu *lcu) { @@ -435,6 +458,8 @@ static int read_unit_address_configuration(struct dasd_device *device, do { rc = dasd_sleep_on(cqr); + if (rc && suborder_not_supported(cqr)) + return -EOPNOTSUPP; } while (rc && (cqr->retries > 0)); if (rc) { spin_lock_irqsave(&lcu->lock, flags); @@ -521,7 +546,7 @@ static void lcu_update_work(struct work_struct *work) * processing the data */ spin_lock_irqsave(&lcu->lock, flags); - if (rc || (lcu->flags & NEED_UAC_UPDATE)) { + if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) { DBF_DEV_EVENT(DBF_WARNING, device, "could not update" " alias data in lcu (rc = %d), retry later", rc); schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 2fb2b9ea97ec..c48c72abbefc 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1507,7 +1507,8 @@ static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device, * call might change behaviour of DASD devices. */ static int -dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) +dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav, + unsigned long flags) { struct dasd_ccw_req *cqr; int rc; @@ -1516,10 +1517,19 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) if (IS_ERR(cqr)) return PTR_ERR(cqr); + /* + * set flags e.g. turn on failfast, to prevent blocking + * the calling function should handle failed requests + */ + cqr->flags |= flags; + rc = dasd_sleep_on(cqr); if (!rc) /* trigger CIO to reprobe devices */ css_schedule_reprobe(); + else if (cqr->intrc == -EAGAIN) + rc = -EAGAIN; + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -1527,7 +1537,8 @@ dasd_eckd_psf_ssc(struct dasd_device *device, int enable_pav) /* * Valide storage server of current device. */ -static void dasd_eckd_validate_server(struct dasd_device *device) +static int dasd_eckd_validate_server(struct dasd_device *device, + unsigned long flags) { int rc; struct dasd_eckd_private *private; @@ -1536,17 +1547,18 @@ static void dasd_eckd_validate_server(struct dasd_device *device) private = (struct dasd_eckd_private *) device->private; if (private->uid.type == UA_BASE_PAV_ALIAS || private->uid.type == UA_HYPER_PAV_ALIAS) - return; + return 0; if (dasd_nopav || MACHINE_IS_VM) enable_pav = 0; else enable_pav = 1; - rc = dasd_eckd_psf_ssc(device, enable_pav); + rc = dasd_eckd_psf_ssc(device, enable_pav, flags); /* may be requested feature is not available on server, * therefore just report error and go ahead */ DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "PSF-SSC for SSID %04x " "returned rc=%d", private->uid.ssid, rc); + return rc; } /* @@ -1556,7 +1568,13 @@ static void dasd_eckd_do_validate_server(struct work_struct *work) { struct dasd_device *device = container_of(work, struct dasd_device, kick_validate); - dasd_eckd_validate_server(device); + if (dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST) + == -EAGAIN) { + /* schedule worker again if failed */ + schedule_work(&device->kick_validate); + return; + } + dasd_put_device(device); } @@ -1685,7 +1703,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) if (rc) goto out_err2; - dasd_eckd_validate_server(device); + dasd_eckd_validate_server(device, 0); /* device may report different configuration data after LCU setup */ rc = dasd_eckd_read_conf(device); @@ -4153,7 +4171,7 @@ static int dasd_eckd_restore_device(struct dasd_device *device) rc = dasd_alias_make_device_known_to_lcu(device); if (rc) return rc; - dasd_eckd_validate_server(device); + dasd_eckd_validate_server(device, DASD_CQR_FLAGS_FAILFAST); /* RE-Read Configuration Data */ rc = dasd_eckd_read_conf(device); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index ed25c8740a9c..fc916f5d7314 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1426,6 +1426,8 @@ static enum io_sch_action sch_get_action(struct subchannel *sch) return IO_SCH_REPROBE; if (cdev->online) return IO_SCH_VERIFY; + if (cdev->private->state == DEV_STATE_NOT_OPER) + return IO_SCH_UNREG_ATTACH; return IO_SCH_NOP; } @@ -1519,11 +1521,14 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) goto out; break; case IO_SCH_UNREG_ATTACH: + spin_lock_irqsave(sch->lock, flags); if (cdev->private->flags.resuming) { /* Device will be handled later. */ rc = 0; - goto out; + goto out_unlock; } + sch_set_cdev(sch, NULL); + spin_unlock_irqrestore(sch->lock, flags); /* Unregister ccw device. */ ccw_device_unregister(cdev); break; |