s390 2.6.25 patch queue.
Subsystems (15)
cover s390 2.6.25 patch queue.
This is my set of patches in the queue for the next upstream merge window. Most of them are bug fixes and small changes. The last three patches are big and introduce an interesting new feature: hyper PAV. Similar to the existing PAV support in the dasd driver the new hyper PAV support allows to start multiple channel programs on a single dasd device. The major difference is that the old style PAV support uses static alias devices while the hyper PAV code uses dynamic alias devices. The shortlog:
Christian Borntraeger (2):
[S390] Change vmalloc defintions
[S390] vmemmap: allocate struct pages before 1:1 mapping
Cornelia Huck (9):
[S390] cio: Use helpers instead of container_of(). [S390] cio: css_driver: Use consistent parameters. [S390] cio: Reset sch->driver.
[S390] cio: Add css_driver_{register,unregister}. [S390] cio: Cleanup debug feature usage.
[S390] cio: Introduce subchannel->private.
[S390] cio: I/O subchannel specific fields.
[S390] cio: Use dev_{g,s}et_drvdata().
[S390] cio: Set driver->owner on css, ccw and ccwgroup busses.
Denis Cheng (1):
[S390] use LIST_HEAD instead of LIST_HEAD_INIT
Heiko Carstens (10):
[S390] Standby cpu activation/deactivation.
[S390] sclp: convert channel path configure code to use sync interface. [S390] Print kernel version in dump_stack() and show_regs(). [S390] Get rid of HOLES_IN_ZONE requirement.
[S390] DEBUG_PAGEALLOC support for s390.
[S390] Remove owner_pc member from raw_spinlock_t.
[S390] Use new style spinlock initializer in __RWSEM_INITIALIZER. [S390] Get rid of additional_cpus kernel parameter.
[S390] Remove appldata include from sysctl_check.c
[S390] Allocate and free cpu lowcores and stacks when needed/possible.
Jan Glauber (1):
[S390] crypto: move s390 Kconfig options.
Joe Perches (5):
[S390] arch/s390: Add missing "space"
[S390] drivers/s390: Add missing "space"
[S390] arch/s390/: Spelling fixes
[S390] include/asm-s390/: Spelling fixes
[S390] drivers/s390/: Spelling fixesMartin Schwidefsky (3):
[S390] Optimize reference bit handling.
[S390] Fix tlb flushing with idte.
[S390] Move NOTES and BUG_TABLE.
Michael Ernst (1):
[S390] sclp: sysfs interface for SCLP cpi
Michael Holzheu (4):
[S390] kernel: Shutdown Actions Interface
[S390] Load disabled wait psw instead of stopping cpu on halt. [S390] Initialize sclp_ipl_info
[S390] Use diag308 subcodes 3 and 6 for reboot and dump when possible.
Peter Oberparleiter (2):
[S390] cio: Extend adapter interrupt interface. [S390] cio: reduce cpu utilization during device scan
Roland McGrath (1):
[S390] single-step cleanup
Sebastian Ott (3):
[S390] Cleanup in Documentation/kernel-parameters.txt. [S390] cio: Dump ccw device information in case of timeout. [S390] qdio: Remove double checked value.
Stefan Haberland (1):
[S390] dasd: fix return value of dasd_generic_probe()
Stefan Weinhuber (3):
[S390] dasd: add hyper PAV support to DASD device driver, part 1 [S390] dasd: add hyper PAV support to DASD device driver, part 2 [S390] dasd: add hyper PAV support to DASD device driver, part 3
Ursula Braun (1):
[S390] qdio: set QDIO_ACTIVATE_TIMEOUT to 5s
Have fun and merry xmas.
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 1/47 Cleanup in Documentation/kernel-parameters.txt.
From: Sebastian Ott <[email protected]>
---
Documentation/kernel-parameters.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
Documentation/kernel-parameters.txt +6 -2
@@ -369,8 +369,6 @@ and is between 256 and 4096 characters. configured. Potentially dangerous and should only be used if you are entirely sure of the consequences. - chandev= [HW,NET] Generic channel device initialisation - checkreqprot [SELINUX] Set initial checkreqprot flag value. Format: { "0" | "1" } See security/selinux/Kconfig help text.
@@ -381,6 +379,12 @@ and is between 256 and 4096 characters. Value can be changed at runtime via /selinux/checkreqprot. + cio_ignore= [S390] + See Documentation/s390/CommonIO for details. + + cio_msg= [S390] + See Documentation/s390/CommonIO for details. + clock= [BUGS=X86-32, HW] gettimeofday clocksource override. [Deprecated] Forces specified clocksource (if available) to be used
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 2/47 cio: Dump ccw device information in case of timeout.
In reply to Martin SchwidefskyFrom: Sebastian Ott <[email protected]>
Information about a ccw device will be dumped in case of a ccw timeout. This can be enabled with the kernel parameter ccw_timeout_log.
---
Documentation/kernel-parameters.txt | 3 ++ Documentation/s390/CommonIO | 5 +++ drivers/s390/cio/device_fsm.c | 50 ++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+)
Documentation/kernel-parameters.txt +3 -0
@@ -369,6 +369,9 @@ and is between 256 and 4096 characters. configured. Potentially dangerous and should only be used if you are entirely sure of the consequences. + ccw_timeout_log [S390] + See Documentation/s390/CommonIO for details. + checkreqprot [SELINUX] Set initial checkreqprot flag value. Format: { "0" | "1" } See security/selinux/Kconfig help text.
Documentation/s390/CommonIO +5 -0
@@ -4,6 +4,11 @@ S/390 common I/O-Layer - command line pa Command line parameters ----------------------- +* ccw_timeout_log + + Enable logging of debug information in case of ccw device timeouts. + + * cio_msg = yes | no Determines whether information on found devices and sensed device
drivers/s390/cio/device_fsm.c +50 -0
68 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 3/47 cio: Use helpers instead of container_of().
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
- Introduce to_cssdriver.
- Use to_xxx instead of container_of where possible.
---
drivers/s390/cio/ccwgroup.c | 4 ++-- drivers/s390/cio/css.c | 6 +++--- drivers/s390/cio/css.h | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-)
drivers/s390/cio/ccwgroup.c +2 -2
@@ -35,8 +35,8 @@ ccwgroup_bus_match (struct device * dev,struct ccwgroup_device *gdev;struct ccwgroup_driver *gdrv; - gdev = container_of(dev, struct ccwgroup_device, dev); - gdrv = container_of(drv, struct ccwgroup_driver, driver); + gdev =to_ccwgroupdev (dev); + gdrv =to_ccwgroupdrv (drv);if (gdev->creator_id == gdrv->driver_id)return 1 ;
drivers/s390/cio/css.c +3 -3
@@ -787,8 +787,8 @@ int sch_is_pseudo_sch(struct subchannelstatic int css_bus_match (struct device *dev,struct device_driver *drv) { - struct subchannel *sch = container_of (dev, struct subchannel, dev); - struct css_driver *driver = container_of (drv, struct css_driver, drv); +struct subchannel *sch =to_subchannel (dev); +struct css_driver *driver =to_cssdriver (drv);if (sch->st == driver->subchannel_type)return 1 ;
@@ -802,7 +802,7 @@ css_probe (struct device *dev)struct subchannel *sch; sch =to_subchannel (dev); - sch->driver = container_of (dev->driver, struct css_driver, drv); + sch->driver =to_cssdriver (dev->driver);return (sch->driver->probe ? sch->driver->probe (sch) :0 ); }
drivers/s390/cio/css.h +2 -0
@@ -134,6 +134,8 @@ struct css_driver {void (*shutdown)(struct subchannel *); }; +#define to_cssdriver (n) container_of(n, struct css_driver, drv) +/* * all css_drivers have the css_bus_type */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 4/47 cio: css_driver: Use consistent parameters.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Make all callbacks in css_driver take a struct subchannel (and not a struct device).
---
drivers/s390/cio/chsc.c | 16 ++++++++-------- drivers/s390/cio/cio.c | 4 ++-- drivers/s390/cio/css.c | 2 +- drivers/s390/cio/css.h | 8 ++++---- drivers/s390/cio/device.c | 38 ++++++++++++++++++++++++-------------- drivers/s390/cio/device.h | 1 - drivers/s390/cio/device_fsm.c | 19 +------------------ 7 files changed, 40 insertions(+), 48 deletions(-)
drivers/s390/cio/chsc.c +8 -8
@@ -132,7 +132,7 @@ static void terminate_internal_io(structdevice_set_intretry (sch);/* Call handler. */ if (sch->driver && sch->driver->termination) - sch->driver->termination (&sch->dev); + sch->driver->termination (sch); } static int
@@ -172,12 +172,12 @@ s390_subchannel_remove_chpid(struct deviterminate_internal_io (sch);/* Re-start path verification. */ if (sch->driver && sch->driver->verify) - sch->driver->verify (&sch->dev); + sch->driver->verify (sch); } }else {/* trigger path verification. */ if (sch->driver && sch->driver->verify) - sch->driver->verify (&sch->dev); + sch->driver->verify (sch);else if (sch->lpm == mask) goto out_unreg; }
@@ -279,7 +279,7 @@ __s390_process_res_acc(struct subchannelif (!old_lpm && sch->lpm)device_trigger_reprobe (sch);else if (sch->driver && sch->driver->verify) - sch->driver->verify (&sch->dev); + sch->driver->verify (sch); out:spin_unlock_irq (sch->lock);put_device (&sch->dev);
@@ -549,7 +549,7 @@ __chp_add(struct subchannel_id schid, vo | mask) & sch->opm;if (sch->driver && sch->driver->verify) - sch->driver->verify (&sch->dev); + sch->driver->verify (sch);spin_unlock_irq (sch->lock);put_device (&sch->dev);
@@ -589,7 +589,7 @@ static void __s390_subchannel_vary_chpidif (!old_lpm)device_trigger_reprobe (sch);else if (sch->driver && sch->driver->verify) - sch->driver->verify (&sch->dev); + sch->driver->verify (sch);break ; } sch->opm &= ~mask;
@@ -603,13 +603,13 @@ static void __s390_subchannel_vary_chpidterminate_internal_io (sch);/* Re-start path verification. */ if (sch->driver && sch->driver->verify) - sch->driver->verify (&sch->dev); + sch->driver->verify (sch); } }else if (!sch->lpm) {if (device_trigger_verify (sch) !=0 )css_schedule_eval (sch->schid); }else if (sch->driver && sch->driver->verify) - sch->driver->verify (&sch->dev); + sch->driver->verify (sch);break ; }spin_unlock_irqrestore (sch->lock, flags);
drivers/s390/cio/cio.c +2 -2
@@ -147,7 +147,7 @@ cio_tpi(void)spin_lock (sch->lock);memcpy (&sch->schib.scsw, &irb->scsw,sizeof (struct scsw ));if (sch->driver && sch->driver->irq) - sch->driver->irq (&sch->dev); + sch->driver->irq (sch);spin_unlock (sch->lock);irq_exit ();_local_bh_enable ();
@@ -680,7 +680,7 @@ do_IRQ (struct pt_regs *regs) sizeof (irb->scsw));/* Call interrupt handler if there is one. */ if (sch->driver && sch->driver->irq) - sch->driver->irq (&sch->dev); + sch->driver->irq (sch); }if (sch)spin_unlock (sch->lock);
drivers/s390/cio/css.c +1 -1
@@ -293,7 +293,7 @@ static int css_evaluate_known_subchannel action =UNREGISTER ;if (sch->driver && sch->driver->notify) {spin_unlock_irqrestore (sch->lock, flags); - ret = sch->driver->notify (&sch->dev, event); + ret = sch->driver->notify (sch, event);spin_lock_irqsave (sch->lock, flags);if (ret) action =NONE ;
drivers/s390/cio/css.h +4 -4
@@ -125,10 +125,10 @@ struct subchannel;struct css_driver {unsigned int subchannel_type;struct device_driver drv; -void (*irq)(struct device *); -int (*notify)(struct device *,int ); -void (*verify)(struct device *); -void (*termination)(struct device *); +void (*irq)(struct subchannel *); +int (*notify)(struct subchannel *,int ); +void (*verify)(struct subchannel *); +void (*termination)(struct subchannel *);int (*probe)(struct subchannel *);int (*remove)(struct subchannel *);void (*shutdown)(struct subchannel *);
drivers/s390/cio/device.c +24 -14
@@ -115,11 +115,12 @@ static int ccw_uevent(struct device *devstruct bus_type ccw_bus_type; -static int io_subchannel_probe (struct subchannel *); -static int io_subchannel_remove (struct subchannel *); -static int io_subchannel_notify (struct device *,int ); -static void io_subchannel_verify (struct device *); -static void io_subchannel_ioterm (struct device *); +static void io_subchannel_irq (struct subchannel *); +static int io_subchannel_probe (struct subchannel *); +static int io_subchannel_remove (struct subchannel *); +static int io_subchannel_notify (struct subchannel *,int ); +static void io_subchannel_verify (struct subchannel *); +static void io_subchannel_ioterm (struct subchannel *);static void io_subchannel_shutdown (struct subchannel *);static struct css_driver io_subchannel_driver = {
@@ -1096,6 +1097,18 @@ out:put_device (&cdev->dev); } +static void io_subchannel_irq (struct subchannel *sch) +{ +struct ccw_device *cdev; + + cdev = sch->dev.driver_data; + +CIO_TRACE_EVENT (3 ,"IRQ" ); +CIO_TRACE_EVENT (3 , sch->dev.bus_id); +if (cdev) +dev_fsm_event (cdev,DEV_EVENT_INTERRUPT ); +} +static int io_subchannel_probe (struct subchannel *sch) {
@@ -1183,12 +1196,11 @@ io_subchannel_remove (struct subchannelreturn 0 ; } -static int -io_subchannel_notify (struct device *dev,int event) +static int io_subchannel_notify (struct subchannel *sch,int event) {struct ccw_device *cdev; - cdev = dev->driver_data; + cdev = sch->dev.driver_data;if (!cdev)return 0 ;if (!cdev->drv)
@@ -1198,22 +1210,20 @@ io_subchannel_notify(struct device *dev,return cdev->drv->notify ? cdev->drv->notify (cdev, event) :0 ; } -static void -io_subchannel_verify (struct device *dev) +static void io_subchannel_verify (struct subchannel *sch) {struct ccw_device *cdev; - cdev = dev->driver_data; + cdev = sch->dev.driver_data;if (cdev)dev_fsm_event (cdev,DEV_EVENT_VERIFY ); } -static void -io_subchannel_ioterm (struct device *dev) +static void io_subchannel_ioterm (struct subchannel *sch) {struct ccw_device *cdev; - cdev = dev->driver_data; + cdev = sch->dev.driver_data;if (!cdev)return ;/* Internal I/O will be retried by the interrupt handler. */
drivers/s390/cio/device_fsm.c +1 -18
@@ -399,7 +399,7 @@ ccw_device_oper_notify(struct work_struc sch =to_subchannel (cdev->dev.parent);if (sch->driver && sch->driver->notify) {spin_unlock_irqrestore (cdev->ccwlock, flags); - ret = sch->driver->notify (&sch->dev,CIO_OPER ); + ret = sch->driver->notify (sch,CIO_OPER );spin_lock_irqsave (cdev->ccwlock, flags); }else ret =0 ;
@@ -1273,21 +1273,4 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES] }, }; -/* -* io_subchannel_irq is called for "real" interrupts or for status -* pending conditions on msch. -*/ -void -io_subchannel_irq (struct device *pdev) -{ -struct ccw_device *cdev; - - cdev =to_subchannel (pdev)->dev.driver_data; - -CIO_TRACE_EVENT (3 ,"IRQ" ); -CIO_TRACE_EVENT (3 , pdev->bus_id); -if (cdev) -dev_fsm_event (cdev,DEV_EVENT_INTERRUPT ); -} -EXPORT_SYMBOL_GPL (ccw_device_set_timeout);
drivers/s390/cio/device.h +0 -1
@@ -74,7 +74,6 @@ extern struct workqueue_struct *ccw_deviextern wait_queue_head_t ccw_device_init_wq;extern atomic_t ccw_device_init_count; -void io_subchannel_irq (struct device *pdev);void io_subchannel_recog_done (struct ccw_device *cdev);int ccw_device_cancel_halt_clear (struct ccw_device *);
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 5/47 cio: Reset sch->driver.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
sch->driver needs to be reset to NULL on failed probe and after remove. We also need to check for sch->driver on shutdown.
---
drivers/s390/cio/css.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
drivers/s390/cio/css.c +13 -9
@@ -796,32 +796,36 @@ css_bus_match (struct device *dev, strucreturn 0 ; } -static int -css_probe (struct device *dev) +static int css_probe (struct device *dev) {struct subchannel *sch; +int ret; sch =to_subchannel (dev); sch->driver =to_cssdriver (dev->driver); -return (sch->driver->probe ? sch->driver->probe (sch) :0 ); + ret = sch->driver->probe ? sch->driver->probe (sch) :0 ; +if (ret) + sch->driver =NULL ; +return ret; } -static int -css_remove (struct device *dev) +static int css_remove (struct device *dev) {struct subchannel *sch; +int ret; sch =to_subchannel (dev); -return (sch->driver->remove ? sch->driver->remove (sch) :0 ); + ret = sch->driver->remove ? sch->driver->remove (sch) :0 ; + sch->driver =NULL ; +return ret; } -static void -css_shutdown (struct device *dev) +static void css_shutdown (struct device *dev) {struct subchannel *sch; sch =to_subchannel (dev); -if (sch->driver->shutdown) +if (sch->driver && sch->driver->shutdown) sch->driver->shutdown (sch); }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 6/47 cio: Add css_driver_{register,unregister}.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Add wrapper functions for driver_register and driver_unregister so that css drivers don't need to muck with struct device_driver directly.
---
drivers/s390/cio/css.c | 27 +++++++++++++++++++++++++++ drivers/s390/cio/css.h | 4 ++++ drivers/s390/cio/device.c | 10 ++++------ 3 files changed, 35 insertions(+), 6 deletions(-)
drivers/s390/cio/css.c +27 -0
@@ -837,6 +837,33 @@ struct bus_type css_bus_type = { .shutdown = css_shutdown, }; +/** +* css_driver_register - register a css driver +* @cdrv: css driver to register +* +* This is mainly a wrapper around driver_register that sets name +* and bus_type in the embedded struct device_driver correctly. +*/ +int css_driver_register (struct css_driver *cdrv) +{ + cdrv->drv.name = cdrv->name; + cdrv->drv.bus = &css_bus_type; +return driver_register (&cdrv->drv); +} +EXPORT_SYMBOL_GPL (css_driver_register); + +/** +* css_driver_unregister - unregister a css driver +* @cdrv: css driver to unregister +* +* This is a wrapper around driver_unregister. +*/ +void css_driver_unregister (struct css_driver *cdrv) +{ +driver_unregister (&cdrv->drv); +} +EXPORT_SYMBOL_GPL (css_driver_unregister); +subsys_initcall (init_channel_subsystem);MODULE_LICENSE ("GPL" );
drivers/s390/cio/css.h +4 -0
@@ -132,6 +132,7 @@ struct css_driver {int (*probe)(struct subchannel *);int (*remove)(struct subchannel *);void (*shutdown)(struct subchannel *); +const char *name; };#define to_cssdriver (n) container_of(n, struct css_driver, drv)
@@ -141,6 +142,9 @@ struct css_driver {*/ extern struct bus_type css_bus_type; +extern int css_driver_register (struct css_driver *); +extern void css_driver_unregister (struct css_driver *); +extern void css_sch_device_unregister (struct subchannel *);extern struct subchannel *get_subchannel_by_schid (struct subchannel_id );extern int css_init_done;
drivers/s390/cio/device.c +4 -6
@@ -125,10 +125,7 @@ static void io_subchannel_shutdown(strucstatic struct css_driver io_subchannel_driver = { .subchannel_type =SUBCHANNEL_TYPE_IO , - .drv = { - .name ="io_subchannel" , - .bus = &css_bus_type, - }, + .name ="io_subchannel" , .irq = io_subchannel_irq, .notify = io_subchannel_notify, .verify = io_subchannel_verify,
@@ -167,7 +164,8 @@ init_ccw_bus_type (void)if ((ret =bus_register (&ccw_bus_type))) goto out_err; -if ((ret =driver_register (&io_subchannel_driver.drv))) + ret =css_driver_register (&io_subchannel_driver); +if (ret) goto out_err; wait_event(ccw_device_init_wq,
@@ -187,7 +185,7 @@ out_err: static void __exitcleanup_ccw_bus_type (void ) { -driver_unregister (&io_subchannel_driver.drv); +css_driver_unregister (&io_subchannel_driver);bus_unregister (&ccw_bus_type);destroy_workqueue (ccw_device_notify_work);destroy_workqueue (ccw_device_work);
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 7/47 cio: Cleanup debug feature usage.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Cleanup cio_debug.h.
Also make CIO_DEBUG add the "cio:" prefix to the printk string so that it isn't needed for the debug feature.
Fix outdated comments for cio_debug_init() and clean it up. Enlarge cio_crw to the same size as cio_msg so we may actually find some relevant information there.
---
drivers/s390/cio/cio.c | 38 ++++++++++++++++++-------------------- drivers/s390/cio/cio_debug.h | 22 +++++++++++----------- drivers/s390/cio/device_fsm.c | 8 ++++---- 3 files changed, 33 insertions(+), 35 deletions(-)
drivers/s390/cio/cio.c +18 -20
@@ -56,39 +56,37 @@ __setup ("cio_msg=", cio_setup);/* * Function: cio_debug_init -* Initializes three debug logs (under /proc/s390dbf) for common I/O: -* - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on +* Initializes three debug logs for common I/O: +* - cio_msg logs generic cio messages * - cio_trace logs the calling of different functions -* - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on -* debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW +* - cio_crw logs machine check related cio messages */ -static int __init -cio_debug_init (void ) +static int __init cio_debug_init (void ) { - cio_debug_msg_id =debug_register ("cio_msg" ,16 ,4 ,16 *sizeof (long )); + cio_debug_msg_id =debug_register ("cio_msg" ,16 ,4 ,16 *sizeof (long ));if (!cio_debug_msg_id) goto out_unregister; -debug_register_view (cio_debug_msg_id, &debug_sprintf_view); -debug_set_level (cio_debug_msg_id,2 ); - cio_debug_trace_id =debug_register ("cio_trace" ,16 ,4 ,16 ); +debug_register_view (cio_debug_msg_id, &debug_sprintf_view); +debug_set_level (cio_debug_msg_id,2 ); + cio_debug_trace_id =debug_register ("cio_trace" ,16 ,4 ,16 );if (!cio_debug_trace_id) goto out_unregister; -debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); -debug_set_level (cio_debug_trace_id,2 ); - cio_debug_crw_id =debug_register ("cio_crw" ,4 ,4 ,16 *sizeof (long )); +debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); +debug_set_level (cio_debug_trace_id,2 ); + cio_debug_crw_id =debug_register ("cio_crw" ,16 ,4 ,16 *sizeof (long ));if (!cio_debug_crw_id) goto out_unregister; -debug_register_view (cio_debug_crw_id, &debug_sprintf_view); -debug_set_level (cio_debug_crw_id,2 ); +debug_register_view (cio_debug_crw_id, &debug_sprintf_view); +debug_set_level (cio_debug_crw_id,4 );return 0 ; out_unregister:if (cio_debug_msg_id) -debug_unregister (cio_debug_msg_id); +debug_unregister (cio_debug_msg_id);if (cio_debug_trace_id) -debug_unregister (cio_debug_trace_id); +debug_unregister (cio_debug_trace_id);if (cio_debug_crw_id) -debug_unregister (cio_debug_crw_id); +debug_unregister (cio_debug_crw_id);printk (KERN_WARNING "cio: could not initialize debugging\n" );return -1 ; }
@@ -567,7 +565,7 @@ cio_validate_subchannel (struct subchann*/ if (sch->st !=0 ) {CIO_DEBUG (KERN_INFO ,0 , -"cio: Subchannel 0.%x.%04x reports " +"Subchannel 0.%x.%04x reports " "non-I/O subchannel type %04X\n" , sch->schid.ssid, sch->schid.sch_no, sch->st);/* We stop here for non-io subchannels. */
@@ -600,7 +598,7 @@ cio_validate_subchannel (struct subchann sch->lpm = sch->schib.pmcw.pam & sch->opm; CIO_DEBUG(KERN_INFO, 0, - "cio: Detected device %04x on subchannel 0.%x.%04X" + "Detected device %04x on subchannel 0.%x.%04X" " - PIM = %02X, PAM = %02X, POM = %02X\n", sch->schib.pmcw.dev, sch->schid.ssid, sch->schid.sch_no, sch->schib.pmcw.pim,
drivers/s390/cio/cio_debug.h +11 -11
@@ -8,20 +8,19 @@ extern debug_info_t *cio_debug_msg_id;extern debug_info_t *cio_debug_trace_id;extern debug_info_t *cio_debug_crw_id; -#define CIO_TRACE_EVENT (imp, txt) do { \ +#define CIO_TRACE_EVENT (imp, txt) do { \ debug_text_event(cio_debug_trace_id, imp, txt); \ } while (0) -#define CIO_MSG_EVENT(imp, args...) do { \ - debug_sprintf_event(cio_debug_msg_id, imp , ##args); \ +#define CIO_MSG_EVENT(imp, args...) do { \ + debug_sprintf_event(cio_debug_msg_id, imp , ##args); \ } while (0) -#define CIO_CRW_EVENT(imp, args...) do { \ - debug_sprintf_event(cio_debug_crw_id, imp , ##args); \ +#define CIO_CRW_EVENT(imp, args...) do { \ + debug_sprintf_event(cio_debug_crw_id, imp , ##args); \ } while (0) -static inline void -CIO_HEX_EVENT (int level,void *data,int length) +static inline void CIO_HEX_EVENT (int level,void *data,int length) {if (unlikely (!cio_debug_trace_id))return ;
@@ -32,9 +31,10 @@ CIO_HEX_EVENT(int level, void *data, int } } -#define CIO_DEBUG(printk_level,event_level,msg...) ({ \ - if (cio_show_msg) printk(printk_level msg); \ - CIO_MSG_EVENT (event_level, msg); \ -}) +#define CIO_DEBUG(printk_level, event_level, msg...) do { \ + if (cio_show_msg) \ + printk(printk_level "cio: " msg); \ + CIO_MSG_EVENT(event_level, msg); \ + } while (0)#endif
drivers/s390/cio/device_fsm.c +4 -4
@@ -318,7 +318,7 @@ ccw_device_recog_done(struct ccw_deviceswitch (state) {case DEV_STATE_NOT_OPER :CIO_DEBUG (KERN_WARNING ,2 , -"cio: SenseID : unknown device %04x on subchannel " +"SenseID : unknown device %04x on subchannel " "0.%x.%04x\n" , cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no);break ;
@@ -344,7 +344,7 @@ ccw_device_recog_done(struct ccw_device }/* Issue device info message. */ CIO_DEBUG(KERN_INFO, 2, - "cio: SenseID : device 0.%x.%04x reports: " + "SenseID : device 0.%x.%04x reports: " "CU Type/Mod = %04X/%02X, Dev Type/Mod = " "%04X/%02X\n", cdev->private->dev_id.ssid,
@@ -354,7 +354,7 @@ ccw_device_recog_done(struct ccw_devicebreak ;case DEV_STATE_BOXED :CIO_DEBUG (KERN_WARNING ,2 , -"cio: SenseID : boxed device %04x on subchannel " +"SenseID : boxed device %04x on subchannel " "0.%x.%04x\n" , cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no);break ;
@@ -439,7 +439,7 @@ ccw_device_done(struct ccw_device *cdev,if (state ==DEV_STATE_BOXED )CIO_DEBUG (KERN_WARNING ,2 , -"cio: Boxed device %04x on subchannel %04x\n" , +"Boxed device %04x on subchannel %04x\n" , cdev->private->dev_id.devno, sch->schid.sch_no);if (cdev->private->flags.donotify) {
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 8/47 cio: Introduce subchannel->private.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Introduce a private pointer in struct subchannel to store per-subchannel type data (cannot use dev->priv since this is already used for something else).
Create a new header io_sch.h for I/O subchannel specific structures and instructions.
---
drivers/s390/cio/cio.c | 43 ++++++---- drivers/s390/cio/cio.h | 84 +++++++------------- drivers/s390/cio/css.c | 2 drivers/s390/cio/css.h | 58 -------------- drivers/s390/cio/device.c | 16 +++ drivers/s390/cio/device.h | 2 drivers/s390/cio/device_fsm.c | 13 +-- drivers/s390/cio/device_id.c | 9 +- drivers/s390/cio/device_pgid.c | 6 + drivers/s390/cio/device_status.c | 13 +-- drivers/s390/cio/io_sch.h | 161 +++++++++++++++++++++++++++++++++++++++ drivers/s390/cio/ioasm.h | 66 --------------- 12 files changed, 261 insertions(+), 212 deletions(-)
drivers/s390/cio/cio.c +26 -17
@@ -28,6 +28,7 @@#include "css.h" #include "chsc.h" #include "ioasm.h" +#include "io_sch.h" #include "blacklist.h" #include "cio_debug.h" #include "chp.h"
@@ -182,33 +183,35 @@ cio_start_key (struct subchannel *sch, / {char dbf_txt[15 ];int ccode; +struct orb *orb; -CIO_TRACE_EVENT (4 ,"stIO" ); -CIO_TRACE_EVENT (4 , sch->dev.bus_id); +CIO_TRACE_EVENT (4 ,"stIO" ); +CIO_TRACE_EVENT (4 , sch->dev.bus_id); + orb = &to_io_private (sch)->orb;/* sch is always under 2G. */ - sch->orb.intparm = (__u32 )(unsigned long )sch; - sch->orb.fmt =1 ; + orb->intparm = (u32 )(addr_t )sch; + orb->fmt =1 ; - sch->orb.pfch = sch->options.prefetch ==0 ; - sch->orb.spnd = sch->options.suspend; - sch->orb.ssic = sch->options.suspend && sch->options.inter; - sch->orb.lpm = (lpm !=0 ) ? lpm : sch->lpm; + orb->pfch = sch->options.prefetch ==0 ; + orb->spnd = sch->options.suspend; + orb->ssic = sch->options.suspend && sch->options.inter; + orb->lpm = (lpm !=0 ) ? lpm : sch->lpm;#ifdef CONFIG_64BIT /* * for 64 bit we always support 64 bit IDAWs with 4k page size only */ - sch->orb.c64 =1 ; - sch->orb.i2k =0 ; + orb->c64 =1 ; + orb->i2k =0 ;#endif - sch->orb.key = key >>4 ; + orb->key = key >>4 ;/* issue "Start Subchannel" */ - sch->orb.cpa = (__u32 )__pa (cpa); - ccode =ssch (sch->schid, &sch->orb); + orb->cpa = (__u32 )__pa (cpa); + ccode =ssch (sch->schid, orb);/* process condition code */ -sprintf (dbf_txt,"ccode:%d" , ccode); -CIO_TRACE_EVENT (4 , dbf_txt); +sprintf (dbf_txt,"ccode:%d" , ccode); +CIO_TRACE_EVENT (4 , dbf_txt);switch (ccode) {case 0 :
@@ -423,7 +426,7 @@ cio_enable_subchannel (struct subchannelfor (retry =5 , ret =0 ; retry >0 ; retry--) { sch->schib.pmcw.ena =1 ; sch->schib.pmcw.isc = isc; - sch->schib.pmcw.intparm = (__u32 )(unsigned long )sch; + sch->schib.pmcw.intparm = (u32 )(addr_t )sch; ret =cio_modify (sch);if (ret == -ENODEV )break ;
@@ -696,8 +699,14 @@ do_IRQ (struct pt_regs *regs)#ifdef CONFIG_CCW_CONSOLE static struct subchannel console_subchannel; +static struct io_subchannel_private console_priv;static int console_subchannel_in_use; +void *cio_get_console_priv (void ) +{ +return &console_priv; +} +/* * busy wait for the next interrupt on the console */
@@ -802,7 +811,7 @@ cio_probe_console(void)ctl_set_bit (6 ,24 ); console_subchannel.schib.pmcw.isc =7 ; console_subchannel.schib.pmcw.intparm = - (__u32 )(unsigned long )&console_subchannel; + (u32)(addr_t)&console_subchannel; ret =cio_modify (&console_subchannel);if (ret) { console_subchannel_in_use =0 ;
drivers/s390/cio/cio.h +30 -54
114 lines not on this page · raw message
drivers/s390/cio/css.c +1 -1
@@ -77,7 +77,7 @@ css_alloc_subchannel(struct subchannel_i* This is fine even on 64bit since the subchannel is always located * under 2G. */ - sch->schib.pmcw.intparm = (__u32 )(unsigned long )sch; + sch->schib.pmcw.intparm = (u32 )(addr_t )sch; ret =cio_modify (sch);if (ret) {kfree (sch->lock);
drivers/s390/cio/css.h +0 -58
64 lines not on this page · raw message
drivers/s390/cio/device.c +14 -2
@@ -28,6 +28,7 @@#include "css.h" #include "device.h" #include "ioasm.h" +#include "io_sch.h" /******************* bus type handling ***********************/
@@ -1159,10 +1160,16 @@ io_subchannel_probe (struct subchannel *queue_work (slow_path_wq, &cdev->private->kick_work);return 0 ; } +/* Allocate I/O subchannel private data. */ + sch->private =kzalloc (sizeof (struct io_subchannel_private ), +GFP_KERNEL |GFP_DMA ); +if (!sch->private) +return -ENOMEM ; cdev =io_subchannel_create_ccwdev (sch); -if (IS_ERR (cdev)) +if (IS_ERR (cdev)) { +kfree (sch->private);return PTR_ERR (cdev); - + } rc =io_subchannel_recog (cdev, sch);if (rc) {spin_lock_irqsave (sch->lock, flags);
@@ -1170,6 +1177,7 @@ io_subchannel_probe (struct subchannel *spin_unlock_irqrestore (sch->lock, flags);if (cdev->dev.release) cdev->dev.release (&cdev->dev); +kfree (sch->private); }return rc;
@@ -1191,6 +1199,7 @@ io_subchannel_remove (struct subchannelspin_unlock_irqrestore (cdev->ccwlock, flags);ccw_device_unregister (cdev);put_device (&cdev->dev); +kfree (sch->private);return 0 ; }
@@ -1279,6 +1288,9 @@ ccw_device_console_enable (struct ccw_de {int rc; +/* Attach subchannel private data. */ + sch->private =cio_get_console_priv (); +memset (sch->private,0 ,sizeof (struct io_subchannel_private ));/* Initialize the ccw_device structure. */ cdev->dev.parent= &sch->dev; rc =io_subchannel_recog (cdev, sch);
drivers/s390/cio/device_fsm.c +8 -5
@@ -96,29 +96,32 @@ static void ccw_timeout_log(struct ccw_d {struct schib schib;struct subchannel *sch; +struct io_subchannel_private *private;int cc; sch =to_subchannel (cdev->dev.parent); + private =to_io_private (sch); cc =stsch (sch->schid, &schib);printk (KERN_WARNING "cio: ccw device timeout occurred at %llx, " "device information:\n" ,get_clock ());printk (KERN_WARNING "cio: orb:\n" );print_hex_dump (KERN_WARNING ,"cio: " ,DUMP_PREFIX_NONE ,16 ,1 , - &sch->orb,sizeof (sch->orb),0 ); + &private->orb,sizeof (private->orb),0 );printk (KERN_WARNING "cio: ccw device bus id: %s\n" , cdev->dev.bus_id);printk (KERN_WARNING "cio: subchannel bus id: %s\n" , sch->dev.bus_id);printk (KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " "vpm: %02x\n" , sch->lpm, sch->opm, sch->vpm); -if ((void *)(addr_t )sch->orb.cpa == &sch->sense_ccw || - (void *)(addr_t )sch->orb.cpa == cdev->private->iccws) +if ((void *)(addr_t )private->orb.cpa == &private->sense_ccw || + (void *)(addr_t )private->orb.cpa == cdev->private->iccws)printk (KERN_WARNING "cio: last channel program (intern):\n" );else printk (KERN_WARNING "cio: last channel program:\n" );print_hex_dump (KERN_WARNING ,"cio: " ,DUMP_PREFIX_NONE ,16 ,1 , - (void *)(addr_t )sch->orb.cpa,sizeof (struct ccw1 ),0 ); + (void *)(addr_t )private->orb.cpa, +sizeof (struct ccw1 ),0 );printk (KERN_WARNING "cio: ccw device state: %d\n" , cdev->private->state);printk (KERN_WARNING "cio: store subchannel returned: cc=%d\n" , cc);
@@ -1078,7 +1081,7 @@ device_trigger_reprobe(struct subchannel sch->schib.pmcw.ena =0 ;if ((sch->lpm & (sch->lpm -1 )) !=0 ) sch->schib.pmcw.mp =1 ; - sch->schib.pmcw.intparm = (__u32 )(unsigned long )sch; + sch->schib.pmcw.intparm = (u32 )(addr_t )sch;/* We should also udate ssd info, but this has to wait. */ /* Check if this is another device which appeared on the same sch. */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
drivers/s390/cio/device.h +2 -0
@@ -5,6 +5,8 @@#include <asm/atomic.h> #include <linux/wait.h> +#include "io_sch.h" +/* * states of the device statemachine */
drivers/s390/cio/device_id.c +6 -3
@@ -24,6 +24,7 @@#include "css.h" #include "device.h" #include "ioasm.h" +#include "io_sch.h" /* * Input :
@@ -219,11 +220,13 @@ ccw_device_check_sense_id(struct ccw_devreturn -EAGAIN ; }if (irb->scsw.cc ==3 ) { -if ((sch->orb.lpm & - sch->schib.pmcw.pim & sch->schib.pmcw.pam) !=0 ) +u8 lpm; + + lpm =to_io_private (sch)->orb.lpm; +if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) !=0 )CIO_MSG_EVENT (2 ,"SenseID : path %02X for device %04x " "on subchannel 0.%x.%04x is " -"'not operational'\n" , sch->orb.lpm, +"'not operational'\n" , lpm, cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no);return -EACCES ;
drivers/s390/cio/device_pgid.c +5 -1
@@ -22,6 +22,7 @@#include "css.h" #include "device.h" #include "ioasm.h" +#include "io_sch.h" /* * Helper function called from interrupt context to decide whether an
@@ -155,10 +156,13 @@ __ccw_device_check_sense_pgid(struct ccwreturn -EAGAIN ; }if (irb->scsw.cc ==3 ) { +u8 lpm; + + lpm =to_io_private (sch)->orb.lpm;CIO_MSG_EVENT (2 ,"SNID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n" , cdev->private->dev_id.devno, sch->schid.ssid, - sch->schid.sch_no, sch->orb.lpm); + sch->schid.sch_no, lpm);return -EACCES ; } i =8 -ffs (cdev->private->imask);
drivers/s390/cio/device_status.c +8 -5
@@ -20,6 +20,7 @@#include "css.h" #include "device.h" #include "ioasm.h" +#include "io_sch.h" /* * Check for any kind of channel or interface control check but don't
@@ -310,6 +311,7 @@ int ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) { struct subchannel *sch; +struct ccw1 *sense_ccw; sch =to_subchannel (cdev->dev.parent);
@@ -326,15 +328,16 @@ ccw_device_do_sense(struct ccw_device *c/* * We have ending status but no sense information. Do a basic sense. */ - sch->sense_ccw.cmd_code =CCW_CMD_BASIC_SENSE ; - sch->sense_ccw.cda = (__u32 )__pa (cdev->private->irb.ecw); - sch->sense_ccw.count =SENSE_MAX_COUNT ; - sch->sense_ccw.flags =CCW_FLAG_SLI ; + sense_ccw = &to_io_private (sch)->sense_ccw; + sense_ccw->cmd_code =CCW_CMD_BASIC_SENSE ; + sense_ccw->cda = (__u32 )__pa (cdev->private->irb.ecw); + sense_ccw->count =SENSE_MAX_COUNT ; + sense_ccw->flags =CCW_FLAG_SLI ;/* Reset internal retry indication. */ cdev->private->flags.intretry =0 ; -return cio_start (sch, &sch->sense_ccw,0xff ); +return cio_start (sch, sense_ccw,0xff ); }/*
drivers/s390/cio/ioasm.h +0 -66
72 lines not on this page · raw message
drivers/s390/cio/io_sch.h new file +161 -0
161 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 9/47 cio: Extend adapter interrupt interface.
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
From: Cornelia Huck <[email protected]>
Change the adapter interrupt interface in order to allow multiple adapter interrupt handlers to be registered. Indicators are now allocated by cio instead of the device driver.
The qdio parts have been
---
Documentation/DocBook/s390-drivers.tmpl | 1 drivers/s390/cio/airq.c | 177 +++++++++++++++++++++----------- drivers/s390/cio/airq.h | 10 - drivers/s390/cio/cio.c | 2 drivers/s390/cio/cio.h | 1 drivers/s390/cio/qdio.c | 35 +++--- include/asm-s390/airq.h | 19 +++ 7 files changed, 157 insertions(+), 88 deletions(-)
Documentation/DocBook/s390-drivers.tmpl +1 -0
@@ -116,6 +116,7 @@ !Iinclude/asm-s390/ccwdev.h !Edrivers/s390/cio/device.c !Edrivers/s390/cio/device_ops.c +!Edrivers/s390/cio/airq.c </sect1> <sect1 id="cmf"> <title>The channel-measurement facility</title>
drivers/s390/cio/airq.c +118 -59
202 lines not on this page · raw message
drivers/s390/cio/airq.h deleted +0 -10
@@ -1,10 +0,0 @@ -#ifndef S390_AINTERRUPT_H -#define S390_AINTERRUPT_H - -typedef int (*adapter_int_handler_t )(void ); - -extern int s390_register_adapter_interrupt (adapter_int_handler_t handler); -extern int s390_unregister_adapter_interrupt (adapter_int_handler_t handler); -extern void do_adapter_IO (void ); - -#endif
drivers/s390/cio/cio.c +1 -1
@@ -23,7 +23,7 @@#include <asm/reset.h> #include <asm/ipl.h> #include <asm/chpid.h> -#include "airq.h" +#include <asm/airq.h> #include "cio.h" #include "css.h" #include "chsc.h"
drivers/s390/cio/cio.h +1 -0
@@ -99,6 +99,7 @@ extern int cio_get_options (struct subchextern int cio_modify (struct subchannel *);int cio_create_sch_lock (struct subchannel *); +void do_adapter_IO (void );/* Use with care. */ #ifdef CONFIG_CCW_CONSOLE
drivers/s390/cio/qdio.c +17 -18
@@ -48,11 +48,11 @@#include <asm/debug.h> #include <asm/s390_rdev.h> #include <asm/qdio.h> +#include <asm/airq.h> #include "cio.h" #include "css.h" #include "device.h" -#include "airq.h" #include "qdio.h" #include "ioasm.h" #include "chsc.h"
@@ -96,7 +96,7 @@ static debug_info_t *qdio_dbf_slsb_in;static volatile struct qdio_q *tiq_list=NULL ;/* volatile as it could change during a while loop */ static DEFINE_SPINLOCK (ttiq_list_lock); -static int register_thinint_result; +static void *tiqdio_ind;static void tiqdio_tl (unsigned long ); static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0);
@@ -399,7 +399,7 @@ qdio_get_indicator(void) {int i; -for (i=1 ;i<INDICATORS_PER_CACHELINE ;i++) +for (i =0 ; i <INDICATORS_PER_CACHELINE ; i++)if (!indicator_used[i]) { indicator_used[i]=1 ;return indicators+i;
@@ -1911,8 +1911,7 @@ qdio_fill_thresholds(struct qdio_irq *ir } } -static int -tiqdio_thinint_handler (void ) +static void tiqdio_thinint_handler (void *ind,void *drv_data) {QDIO_DBF_TEXT4 (0 ,trace,"thin_int" );
@@ -1925,7 +1924,6 @@ tiqdio_thinint_handler(void)tiqdio_clear_global_summary ();tiqdio_inbound_checks (); -return 0 ; } static void
@@ -2445,7 +2443,7 @@ tiqdio_set_subchannel_ind(struct qdio_ir real_addr_dev_st_chg_ind=0 ; }else { real_addr_local_summary_bit= -virt_to_phys ((volatile void *)indicators); +virt_to_phys ((volatile void *)tiqdio_ind); real_addr_dev_st_chg_ind=virt_to_phys ((volatile void *)irq_ptr->dev_st_chg_ind); }
@@ -3740,23 +3738,25 @@ static voidtiqdio_register_thinints (void) {char dbf_text[20 ]; - register_thinint_result= -s390_register_adapter_interrupt (&tiqdio_thinint_handler); -if (register_thinint_result) { -sprintf (dbf_text,"regthn%x" ,(register_thinint_result&0xff )); + + tiqdio_ind = +s390_register_adapter_interrupt (&tiqdio_thinint_handler,NULL ); +if (IS_ERR (tiqdio_ind)) { +sprintf (dbf_text,"regthn%lx" ,PTR_ERR (tiqdio_ind));QDIO_DBF_TEXT0 (0 ,setup,dbf_text);QDIO_PRINT_ERR ("failed to register adapter handler " \ -"(rc=%i).\nAdapter interrupts might " \ +"(rc=%li).\nAdapter interrupts might " \"not work. Continuing.\n" , - register_thinint_result); +PTR_ERR (tiqdio_ind)); + tiqdio_ind =NULL ; } }static void tiqdio_unregister_thinints (void ) { -if (!register_thinint_result) -s390_unregister_adapter_interrupt (&tiqdio_thinint_handler); +if (tiqdio_ind) +s390_unregister_adapter_interrupt (tiqdio_ind); } static int
@@ -3768,8 +3768,8 @@ qdio_get_qdio_memory(void)for (i=1 ;i<INDICATORS_PER_CACHELINE ;i++) indicator_used[i]=0 ; indicators =kzalloc (sizeof (__u32)*(INDICATORS_PER_CACHELINE ), -GFP_KERNEL ); -if (!indicators) +GFP_KERNEL ); +if (!indicators)return -ENOMEM ;return 0 ; }
@@ -3780,7 +3780,6 @@ qdio_release_qdio_memory(void)kfree (indicators); } -static void qdio_unregister_dbf_views (void ) {
include/asm-s390/airq.h new file +19 -0
@@ -0,0 +1,19 @@ +/* +* include/asm-s390/airq.h +* +* Copyright IBM Corp. 2002,2007 +* Author(s): Ingo Adlung <[email protected]> +* Cornelia Huck <[email protected]> +* Arnd Bergmann <[email protected]> +* Peter Oberparleiter <[email protected]> +*/ + +#ifndef _ASM_S390_AIRQ_H +#define _ASM_S390_AIRQ_H + +typedef void (*adapter_int_handler_t )(void *,void *); + +void *s390_register_adapter_interrupt (adapter_int_handler_t ,void *); +void s390_unregister_adapter_interrupt (void *); + +#endif /* _ASM_S390_AIRQ_H */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 10/47 cio: I/O subchannel specific fields.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Some fields may be !0 only for I/O subchannels. Add some checks where required. Also adapt cio_enable_subchannel() to make the caller specify the intparm, which makes it more generic.
---
drivers/s390/cio/chsc.c | 5 +++-- drivers/s390/cio/cio.c | 24 ++++++++++++------------ drivers/s390/cio/cio.h | 4 ++-- drivers/s390/cio/css.c | 18 ++++++++++++++++-- drivers/s390/cio/css.h | 2 ++ drivers/s390/cio/device_fsm.c | 9 ++++++--- drivers/s390/cio/device_ops.c | 2 +- 7 files changed, 42 insertions(+), 22 deletions(-)
drivers/s390/cio/chsc.c +3 -2
@@ -89,7 +89,8 @@ int chsc_get_ssd_info(struct subchannel_/* Copy data */ ret =0 ;memset (ssd,0 ,sizeof (struct chsc_ssd_info )); -if ((ssd_area->st !=0 ) && (ssd_area->st !=2 )) +if ((ssd_area->st !=SUBCHANNEL_TYPE_IO ) && + (ssd_area->st !=SUBCHANNEL_TYPE_MSG )) goto out_free; ssd->path_mask = ssd_area->path_mask; ssd->fla_valid_mask = ssd_area->fla_valid_mask;
@@ -158,7 +159,7 @@ s390_subchannel_remove_chpid(struct devispin_lock_irq (sch->lock);stsch (sch->schid, &schib); -if (!schib.pmcw.dnv) +if (!css_sch_is_valid (&schib)) goto out_unreg;memcpy (&sch->schib, &schib,sizeof (struct schib ));/* Check for single path devices. */
drivers/s390/cio/cio.c +12 -12
@@ -406,8 +406,8 @@ cio_modify (struct subchannel *sch)/* * Enable subchannel. */ -int -cio_enable_subchannel (struct subchannel *sch,unsigned int isc) +int cio_enable_subchannel (struct subchannel *sch,unsigned int isc, +u32 intparm) {char dbf_txt[15 ];int ccode;
@@ -426,7 +426,7 @@ cio_enable_subchannel (struct subchannelfor (retry =5 , ret =0 ; retry >0 ; retry--) { sch->schib.pmcw.ena =1 ; sch->schib.pmcw.isc = isc; - sch->schib.pmcw.intparm = (u32 )(addr_t )sch; + sch->schib.pmcw.intparm = intparm; ret =cio_modify (sch);if (ret == -ENODEV )break ;
@@ -577,11 +577,8 @@ cio_validate_subchannel (struct subchann }/* Initialization for io subchannels. */ -if (!sch->schib.pmcw.dnv) { -/* io subchannel but device number is invalid. */ - err = -ENODEV ; - goto out; - } +if (!css_sch_is_valid (&sch->schib)) +return -ENODEV ;/* Devno is valid. */ if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {/*
@@ -745,9 +742,9 @@ cio_test_for_console(struct subchannel_i {if (stsch_err (schid, &console_subchannel.schib) !=0 )return -ENXIO ; -if (console_subchannel.schib.pmcw.dnv && - console_subchannel.schib.pmcw.dev == - console_devno) { +if ((console_subchannel.schib.pmcw.st ==SUBCHANNEL_TYPE_IO ) && + console_subchannel.schib.pmcw.dnv && + (console_subchannel.schib.pmcw.dev == console_devno)) { console_irq = schid.sch_no;return 1 ;/* found */ }
@@ -765,6 +762,7 @@ cio_get_console_sch_no(void)/* VM provided us with the irq number of the console. */ schid.sch_no = console_irq;if (stsch (schid, &console_subchannel.schib) !=0 || + (console_subchannel.schib.pmcw.st !=SUBCHANNEL_TYPE_IO ) || !console_subchannel.schib.pmcw.dnv)return -1 ; console_devno = console_subchannel.schib.pmcw.dev;
@@ -1029,7 +1027,7 @@ static int __reipl_subchannel_match(struif (stsch_reset (schid, &schib))return -ENXIO ; -if (schib.pmcw.dnv && +if ((schib.pmcw.st ==SUBCHANNEL_TYPE_IO ) && schib.pmcw.dnv && (schib.pmcw.dev == match_id->devid.devno) && (schid.ssid == match_id->devid.ssid)) { match_id->schid = schid;
@@ -1075,6 +1073,8 @@ int __init cio_get_iplinfo(struct cio_ipreturn -ENODEV ;if (stsch (schid, &schib))return -ENODEV ; +if (schib.pmcw.st !=SUBCHANNEL_TYPE_IO ) +return -ENODEV ;if (!schib.pmcw.dnv)return -ENODEV ; iplinfo->devno = schib.pmcw.dev;
drivers/s390/cio/cio.h +2 -2
@@ -60,7 +60,7 @@ struct subchannel {enum {SUBCHANNEL_TYPE_IO =0 ,SUBCHANNEL_TYPE_CHSC =1 , -SUBCHANNEL_TYPE_MESSAGE =2 , +SUBCHANNEL_TYPE_MSG =2 ,SUBCHANNEL_TYPE_ADM =3 , } st;/* subchannel type */
@@ -85,7 +85,7 @@ struct subchannel {#define to_subchannel (n) container_of(n, struct subchannel, dev)extern int cio_validate_subchannel (struct subchannel *,struct subchannel_id ); -extern int cio_enable_subchannel (struct subchannel *,unsigned int ); +extern int cio_enable_subchannel (struct subchannel *,unsigned int ,u32 );extern int cio_disable_subchannel (struct subchannel *);extern int cio_cancel (struct subchannel *);extern int cio_clear (struct subchannel *);
drivers/s390/cio/css.c +16 -2
@@ -237,11 +237,25 @@ get_subchannel_by_schid(struct subchannereturn dev ?to_subchannel (dev) :NULL ; } +/** +* css_sch_is_valid() - check if a subchannel is valid +* @schib: subchannel information block for the subchannel +*/ +int css_sch_is_valid (struct schib *schib) +{ +if ((schib->pmcw.st ==SUBCHANNEL_TYPE_IO ) && !schib->pmcw.dnv) +return 0 ; +return 1 ; +} +EXPORT_SYMBOL_GPL (css_sch_is_valid); +static int css_get_subchannel_status (struct subchannel *sch) {struct schib schib; -if (stsch (sch->schid, &schib) || !schib.pmcw.dnv) +if (stsch (sch->schid, &schib)) +return CIO_GONE ; +if (!css_sch_is_valid (&schib))return CIO_GONE ;if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))return CIO_REVALIDATE ;
@@ -349,7 +363,7 @@ static int css_evaluate_new_subchannel(s/* Will be done on the slow path. */ return -EAGAIN ; } -if (stsch_err (schid, &schib) || !schib.pmcw.dnv) { +if (stsch_err (schid, &schib) || !css_sch_is_valid (&schib)) {/* Unusable - ignore. */ return 0 ; }
drivers/s390/cio/css.h +2 -0
@@ -136,6 +136,8 @@ void css_schedule_eval(struct subchannelvoid css_schedule_eval_all (void );int sch_is_pseudo_sch (struct subchannel *); +struct schib ; +int css_sch_is_valid (struct schib *);extern struct workqueue_struct *slow_path_wq;
drivers/s390/cio/device_fsm.c +6 -3
@@ -553,7 +553,8 @@ ccw_device_recognition(struct ccw_device (cdev->private->state != DEV_STATE_BOXED))return -EINVAL ; sch =to_subchannel (cdev->dev.parent); - ret =cio_enable_subchannel (sch, sch->schib.pmcw.isc); + ret =cio_enable_subchannel (sch, sch->schib.pmcw.isc, + (u32 )(addr_t )sch);if (ret !=0 )/* Couldn't enable the subchannel for i/o. Sick device. */ return ret;
@@ -663,7 +664,8 @@ ccw_device_online(struct ccw_device *cde sch =to_subchannel (cdev->dev.parent);if (css_init_done && !get_device (&cdev->dev))return -ENODEV ; - ret =cio_enable_subchannel (sch, sch->schib.pmcw.isc); + ret =cio_enable_subchannel (sch, sch->schib.pmcw.isc, + (u32 )(addr_t )sch);if (ret !=0 ) {/* Couldn't enable the subchannel for i/o. Sick device. */ if (ret == -ENODEV )
@@ -1043,7 +1045,8 @@ ccw_device_start_id(struct ccw_device *cstruct subchannel *sch; sch =to_subchannel (cdev->dev.parent); -if (cio_enable_subchannel (sch, sch->schib.pmcw.isc) !=0 ) +if (cio_enable_subchannel (sch, sch->schib.pmcw.isc, + (u32 )(addr_t )sch) !=0 )/* Couldn't enable the subchannel for i/o. Sick device. */ return ;
drivers/s390/cio/device_ops.c +1 -1
@@ -501,7 +501,7 @@ ccw_device_stlck(struct ccw_device *cdevreturn -ENOMEM ; }spin_lock_irqsave (sch->lock, flags); - ret =cio_enable_subchannel (sch,3 ); + ret =cio_enable_subchannel (sch,3 , (u32 )(addr_t )sch);if (ret) goto out_unlock;/*
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 11/47 cio: Use dev_{g,s}et_drvdata().
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Also define helpers sch_{g,s}et_cdev() to make the intention more clear.
---
drivers/s390/cio/ccwgroup.c | 14 +++++++------- drivers/s390/cio/device.c | 36 ++++++++++++++++++------------------ drivers/s390/cio/device_fsm.c | 26 +++++++++++++------------- drivers/s390/cio/io_sch.h | 2 ++ 4 files changed, 40 insertions(+), 38 deletions(-)
drivers/s390/cio/ccwgroup.c +7 -7
@@ -111,7 +111,7 @@ ccwgroup_release (struct device *dev) gdev =to_ccwgroupdev (dev);for (i =0 ; i < gdev->count; i++) { - gdev->cdev[i]->dev.driver_data =NULL ; +dev_set_drvdata (&gdev->cdev[i]->dev,NULL );put_device (&gdev->cdev[i]->dev); }kfree (gdev);
@@ -196,11 +196,11 @@ int ccwgroup_create(struct device *root, goto error; }/* Don't allow a device to belong to more than one group. */ -if (gdev->cdev[i]->dev.driver_data) { +if (dev_get_drvdata (&gdev->cdev[i]->dev)) { rc = -EINVAL ; goto error; } - gdev->cdev[i]->dev.driver_data = gdev; +dev_set_drvdata (&gdev->cdev[i]->dev, gdev); } gdev->creator_id = creator_id;
@@ -234,8 +234,8 @@ int ccwgroup_create(struct device *root, error:for (i =0 ; i < argc; i++)if (gdev->cdev[i]) { -if (gdev->cdev[i]->dev.driver_data == gdev) - gdev->cdev[i]->dev.driver_data =NULL ; +if (dev_get_drvdata (&gdev->cdev[i]->dev) == gdev) +dev_set_drvdata (&gdev->cdev[i]->dev,NULL );put_device (&gdev->cdev[i]->dev); }mutex_unlock (&gdev->reg_mutex);
@@ -463,8 +463,8 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_d {struct ccwgroup_device *gdev; -if (cdev->dev.driver_data) { - gdev = (struct ccwgroup_device *)cdev->dev.driver_data; + gdev =dev_get_drvdata (&cdev->dev); +if (gdev) {if (get_device (&gdev->dev)) {mutex_lock (&gdev->reg_mutex);if (device_is_registered (&gdev->dev))
drivers/s390/cio/device.c +18 -18
@@ -773,7 +773,7 @@ static void sch_attach_device(struct sub {css_update_ssd_info (sch);spin_lock_irq (sch->lock); - sch->dev.driver_data = cdev; +sch_set_cdev (sch, cdev); cdev->private->schid = sch->schid; cdev->ccwlock = sch->lock;device_trigger_reprobe (sch);
@@ -795,7 +795,7 @@ static void sch_attach_disconnected_deviput_device (&other_sch->dev);return ; } - other_sch->dev.driver_data =NULL ; +sch_set_cdev (other_sch,NULL );/* No need to keep a subchannel without ccw device around. */ css_sch_device_unregister (other_sch);put_device (&other_sch->dev);
@@ -831,12 +831,12 @@ static void sch_create_and_recog_new_devreturn ; }spin_lock_irq (sch->lock); - sch->dev.driver_data = cdev; +sch_set_cdev (sch, cdev);spin_unlock_irq (sch->lock);/* Start recognition for the new ccw device. */ if (io_subchannel_recog (cdev, sch)) {spin_lock_irq (sch->lock); - sch->dev.driver_data =NULL ; +sch_set_cdev (sch,NULL );spin_unlock_irq (sch->lock);if (cdev->dev.release) cdev->dev.release (&cdev->dev);
@@ -940,7 +940,7 @@ io_subchannel_register(struct work_struc cdev->private->dev_id.devno, ret);put_device (&cdev->dev);spin_lock_irqsave (sch->lock, flags); - sch->dev.driver_data =NULL ; +sch_set_cdev (sch,NULL );spin_unlock_irqrestore (sch->lock, flags);kfree (cdev->private);kfree (cdev);
@@ -1022,7 +1022,7 @@ io_subchannel_recog(struct ccw_device *cint rc;struct ccw_device_private *priv; - sch->dev.driver_data = cdev; +sch_set_cdev (sch, cdev); sch->driver = &io_subchannel_driver; cdev->ccwlock = sch->lock;
@@ -1082,7 +1082,7 @@ static void ccw_device_move_to_sch(struc }if (former_parent) {spin_lock_irq (former_parent->lock); - former_parent->dev.driver_data =NULL ; +sch_set_cdev (former_parent,NULL );spin_unlock_irq (former_parent->lock);css_sch_device_unregister (former_parent);/* Reset intparm to zeroes. */
@@ -1100,7 +1100,7 @@ static void io_subchannel_irq(struct sub {struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev =sch_get_cdev (sch);CIO_TRACE_EVENT (3 ,"IRQ" );CIO_TRACE_EVENT (3 , sch->dev.bus_id);
@@ -1116,13 +1116,13 @@ io_subchannel_probe (struct subchannel *unsigned long flags;struct ccw_dev_id dev_id; -if (sch->dev.driver_data) { + cdev =sch_get_cdev (sch); +if (cdev) {/* * This subchannel already has an associated ccw_device. * Register it and exit. This happens for all early * device, e.g. the console. */ - cdev = sch->dev.driver_data; cdev->dev.groups = ccwdev_attr_groups;device_initialize (&cdev->dev);ccw_device_register (cdev);
@@ -1173,7 +1173,7 @@ io_subchannel_probe (struct subchannel * rc =io_subchannel_recog (cdev, sch);if (rc) {spin_lock_irqsave (sch->lock, flags); - sch->dev.driver_data =NULL ; +sch_set_cdev (sch,NULL );spin_unlock_irqrestore (sch->lock, flags);if (cdev->dev.release) cdev->dev.release (&cdev->dev);
@@ -1189,12 +1189,12 @@ io_subchannel_remove (struct subchannelstruct ccw_device *cdev;unsigned long flags; -if (!sch->dev.driver_data) + cdev =sch_get_cdev (sch); +if (!cdev)return 0 ; - cdev = sch->dev.driver_data;/* Set ccw device to not operational and drop reference. */ spin_lock_irqsave (cdev->ccwlock, flags); - sch->dev.driver_data =NULL ; +sch_set_cdev (sch,NULL ); cdev->private->state =DEV_STATE_NOT_OPER ;spin_unlock_irqrestore (cdev->ccwlock, flags);ccw_device_unregister (cdev);
@@ -1207,7 +1207,7 @@ static int io_subchannel_notify(struct s {struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev =sch_get_cdev (sch);if (!cdev)return 0 ;if (!cdev->drv)
@@ -1221,7 +1221,7 @@ static void io_subchannel_verify(struct {struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev =sch_get_cdev (sch);if (cdev)dev_fsm_event (cdev,DEV_EVENT_VERIFY ); }
@@ -1230,7 +1230,7 @@ static void io_subchannel_ioterm(struct {struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev =sch_get_cdev (sch);if (!cdev)return ;/* Internal I/O will be retried by the interrupt handler. */
@@ -1248,7 +1248,7 @@ io_subchannel_shutdown(struct subchannelstruct ccw_device *cdev;int ret; - cdev = sch->dev.driver_data; + cdev =sch_get_cdev (sch);if (cio_is_console (sch->schid))return ;
drivers/s390/cio/device_fsm.c +13 -13
@@ -32,9 +32,9 @@ device_is_online(struct subchannel *sch) {struct ccw_device *cdev; -if (!sch->dev.driver_data) + cdev =sch_get_cdev (sch); +if (!cdev)return 0 ; - cdev = sch->dev.driver_data;return (cdev->private->state ==DEV_STATE_ONLINE ); }
@@ -43,9 +43,9 @@ device_is_disconnected(struct subchannel {struct ccw_device *cdev; -if (!sch->dev.driver_data) + cdev =sch_get_cdev (sch); +if (!cdev)return 0 ; - cdev = sch->dev.driver_data;return (cdev->private->state ==DEV_STATE_DISCONNECTED || cdev->private->state ==DEV_STATE_DISCONNECTED_SENSE_ID ); }
@@ -55,9 +55,9 @@ device_set_disconnected(struct subchanne {struct ccw_device *cdev; -if (!sch->dev.driver_data) + cdev =sch_get_cdev (sch); +if (!cdev)return ; - cdev = sch->dev.driver_data;ccw_device_set_timeout (cdev,0 ); cdev->private->flags.fake_irb =0 ; cdev->private->state =DEV_STATE_DISCONNECTED ;
@@ -67,7 +67,7 @@ void device_set_intretry(struct subchann {struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev =sch_get_cdev (sch);if (!cdev)return ; cdev->private->flags.intretry =1 ;
@@ -77,7 +77,7 @@ int device_trigger_verify(struct subchan {struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev =sch_get_cdev (sch);if (!cdev || !cdev->online)return -EINVAL ;dev_fsm_event (cdev,DEV_EVENT_VERIFY );
@@ -175,9 +175,9 @@ device_kill_pending_timer(struct subchan {struct ccw_device *cdev; -if (!sch->dev.driver_data) + cdev =sch_get_cdev (sch); +if (!cdev)return ; - cdev = sch->dev.driver_data;ccw_device_set_timeout (cdev,0 ); }
@@ -992,7 +992,7 @@ void device_kill_io(struct subchannel *sint ret;struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev =sch_get_cdev (sch); ret =ccw_device_cancel_halt_clear (cdev);if (ret == -EBUSY ) {ccw_device_set_timeout (cdev,3 *HZ );
@@ -1062,9 +1062,9 @@ device_trigger_reprobe(struct subchannel {struct ccw_device *cdev; -if (!sch->dev.driver_data) + cdev =sch_get_cdev (sch); +if (!cdev)return ; - cdev = sch->dev.driver_data;if (cdev->private->state !=DEV_STATE_DISCONNECTED )return ;
drivers/s390/cio/io_sch.h +2 -0
@@ -34,6 +34,8 @@ struct io_subchannel_private { } __attribute__ ((aligned(8)));#define to_io_private (n) ((struct io_subchannel_private *)n->private) +#define sch_get_cdev (n) (dev_get_drvdata(&n->dev)) +#define sch_set_cdev (n, c) (dev_set_drvdata(&n->dev, c))#define MAX_CIWS 8
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 12/47 cio: Set driver->owner on css, ccw and ccwgroup busses.
In reply to Martin SchwidefskyFrom: Cornelia Huck <[email protected]>
Set the owner field in the embedded struct device_driver to the value provided in the {css,ccw,ccwgroup}_driver.
---
drivers/s390/cio/ccwgroup.c | 1 + drivers/s390/cio/css.c | 1 + drivers/s390/cio/css.h | 1 + drivers/s390/cio/device.c | 2 ++ 4 files changed, 5 insertions(+)
drivers/s390/cio/ccwgroup.c +1 -0
@@ -408,6 +408,7 @@ int ccwgroup_driver_register(struct ccwg/* register our new driver with the core */ cdriver->driver.bus = &ccwgroup_bus_type; cdriver->driver.name = cdriver->name; + cdriver->driver.owner = cdriver->owner;return driver_register (&cdriver->driver); }
drivers/s390/cio/css.c +1 -0
@@ -862,6 +862,7 @@ int css_driver_register(struct css_drive { cdrv->drv.name = cdrv->name; cdrv->drv.bus = &css_bus_type; + cdrv->drv.owner = cdrv->owner;return driver_register (&cdrv->drv); }EXPORT_SYMBOL_GPL (css_driver_register);
drivers/s390/cio/css.h +1 -0
@@ -65,6 +65,7 @@ struct pgid {*/ struct subchannel ;struct css_driver { +struct module *owner;unsigned int subchannel_type;struct device_driver drv;void (*irq)(struct subchannel *);
drivers/s390/cio/device.c +2 -0
@@ -125,6 +125,7 @@ static void io_subchannel_ioterm(structstatic void io_subchannel_shutdown (struct subchannel *);static struct css_driver io_subchannel_driver = { + .owner =THIS_MODULE , .subchannel_type =SUBCHANNEL_TYPE_IO , .name ="io_subchannel" , .irq = io_subchannel_irq,
@@ -1476,6 +1477,7 @@ int ccw_driver_register(struct ccw_drive drv->bus = &ccw_bus_type; drv->name = cdriver->name; + drv->owner = cdriver->owner;return driver_register (drv); }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 13/47 cio: reduce cpu utilization during device scan
In reply to Martin SchwidefskyFrom: Peter Oberparleiter <[email protected]>
Minimize calls to cpu intensive function get_subchannel_by_schid() by introducing function for_each_subchannel_staged() which temporarily caches the information about registered subchannels in a bitmap.
---
drivers/s390/cio/chsc.c | 96 ++++++++++++-------------------------- drivers/s390/cio/css.c | 120 ++++++++++++++++++++++++++++++++++++++++-------- drivers/s390/cio/css.h | 3 + 3 files changed, 136 insertions(+), 83 deletions(-)
drivers/s390/cio/chsc.c +31 -65
@@ -136,17 +136,13 @@ static void terminate_internal_io(struct sch->driver->termination (sch); } -static int -s390_subchannel_remove_chpid (struct device *dev,void *data) +static int s390_subchannel_remove_chpid (struct subchannel *sch,void *data) {int j;int mask; -struct subchannel *sch; -struct chp_id *chpid; +struct chp_id *chpid = data;struct schib schib; - sch =to_subchannel (dev); - chpid = data;for (j =0 ; j <8 ; j++) { mask =0x80 >> j; if ((sch->schib.pmcw.pim & mask) &&
@@ -202,12 +198,10 @@ void chsc_chp_offline(struct chp_id chpiif (chp_get_status (chpid) <=0 )return ; -bus_for_each_dev (&css_bus_type,NULL , &chpid, - s390_subchannel_remove_chpid); +for_each_subchannel_staged (s390_subchannel_remove_chpid,NULL , &chpid); } -static int -s390_process_res_acc_new_sch (struct subchannel_id schid) +static int s390_process_res_acc_new_sch (struct subchannel_id schid,void *data) {struct schib schib;/*
@@ -253,18 +247,10 @@ static int get_res_chpid_mask(struct chsreturn 0 ; } -static int -__s390_process_res_acc (struct subchannel_id schid,void *data) +static int __s390_process_res_acc (struct subchannel *sch,void *data) {int chp_mask, old_lpm; -struct res_acc_data *res_data; -struct subchannel *sch; - - res_data = data; - sch =get_subchannel_by_schid (schid); -if (!sch) -/* Check if a subchannel is newly available. */ -return s390_process_res_acc_new_sch (schid); +struct res_acc_data *res_data = data;spin_lock_irq (sch->lock); chp_mask =get_res_chpid_mask (&sch->ssd_info, res_data);
@@ -283,7 +269,7 @@ __s390_process_res_acc(struct subchannel sch->driver->verify (sch); out:spin_unlock_irq (sch->lock); -put_device (&sch->dev); +return 0 ; }
@@ -306,7 +292,8 @@ static void s390_process_res_acc (struct* The more information we have (info), the less scanning * will we have to do. */ -for_each_subchannel (__s390_process_res_acc, res_data); +for_each_subchannel_staged (__s390_process_res_acc, + s390_process_res_acc_new_sch, res_data); } static int
@@ -500,8 +487,7 @@ void chsc_process_crw(void) }while (sei_area->flags &0x80 ); } -static int -__chp_add_new_sch (struct subchannel_id schid) +static int __chp_add_new_sch (struct subchannel_id schid,void *data) {struct schib schib;
@@ -515,35 +501,27 @@ __chp_add_new_sch(struct subchannel_id s } -static int -__chp_add (struct subchannel_id schid,void *data) +static int __chp_add (struct subchannel *sch,void *data) {int i, mask; -struct chp_id *chpid; -struct subchannel *sch; +struct chp_id *chpid = data; - chpid = data; - sch =get_subchannel_by_schid (schid); -if (!sch) -/* Check if the subchannel is now available. */ -return __chp_add_new_sch (schid);spin_lock_irq (sch->lock);for (i=0 ; i<8 ; i++) { mask =0x80 >> i;if ((sch->schib.pmcw.pim & mask) && - (sch->schib.pmcw.chpid[i] == chpid->id)) { -if (stsch (sch->schid, &sch->schib) !=0 ) { -/* Endgame. */ -spin_unlock_irq (sch->lock); -return -ENXIO ; - } + (sch->schib.pmcw.chpid[i] == chpid->id))break ; - } }if (i==8 ) {spin_unlock_irq (sch->lock);return 0 ; } +if (stsch (sch->schid, &sch->schib)) { +spin_unlock_irq (sch->lock); +css_schedule_eval (sch->schid); +return 0 ; + } sch->lpm = ((sch->schib.pmcw.pim & sch->schib.pmcw.pam & sch->schib.pmcw.pom)
@@ -553,7 +531,7 @@ __chp_add(struct subchannel_id schid, vo sch->driver->verify (sch);spin_unlock_irq (sch->lock); -put_device (&sch->dev); +return 0 ; }
@@ -565,7 +543,8 @@ void chsc_chp_online(struct chp_id chpidCIO_TRACE_EVENT (2 , dbf_txt);if (chp_get_status (chpid) !=0 ) -for_each_subchannel (__chp_add, &chpid); +for_each_subchannel_staged (__chp_add, __chp_add_new_sch, + &chpid); } static void __s390_subchannel_vary_chpid(struct subchannel *sch,
@@ -616,25 +595,17 @@ static void __s390_subchannel_vary_chpidspin_unlock_irqrestore (sch->lock, flags); } -static int s390_subchannel_vary_chpid_off (struct device *dev,void *data) +static int s390_subchannel_vary_chpid_off (struct subchannel *sch,void *data) { -struct subchannel *sch; -struct chp_id *chpid; - - sch =to_subchannel (dev); - chpid = data; +struct chp_id *chpid = data;__s390_subchannel_vary_chpid (sch, *chpid,0 );return 0 ; } -static int s390_subchannel_vary_chpid_on (struct device *dev,void *data) +static int s390_subchannel_vary_chpid_on (struct subchannel *sch,void *data) { -struct subchannel *sch; -struct chp_id *chpid; - - sch =to_subchannel (dev); - chpid = data; +struct chp_id *chpid = data;__s390_subchannel_vary_chpid (sch, *chpid,1 );return 0 ;
@@ -644,13 +615,7 @@ static int __s390_vary_chpid_on(struct subchannel_id schid, void *data) { struct schib schib; -struct subchannel *sch; - sch =get_subchannel_by_schid (schid); -if (sch) { -put_device (&sch->dev); -return 0 ; - }if (stsch_err (schid, &schib))/* We're through */ return -ENXIO ;
@@ -670,12 +635,13 @@ int chsc_chp_vary(struct chp_id chpid, i* Redo PathVerification on the devices the chpid connects to */ -bus_for_each_dev (&css_bus_type,NULL , &chpid, on ? - s390_subchannel_vary_chpid_on : - s390_subchannel_vary_chpid_off);if (on) -/* Scan for new devices on varied on path. */ -for_each_subchannel (__s390_vary_chpid_on,NULL ); +for_each_subchannel_staged (s390_subchannel_vary_chpid_on, + __s390_vary_chpid_on, &chpid); +else +for_each_subchannel_staged (s390_subchannel_vary_chpid_off, +NULL , &chpid); +return 0 ; }
drivers/s390/cio/css.c +102 -18
155 lines not on this page · raw message
drivers/s390/cio/css.h +3 -0
@@ -91,6 +91,9 @@ extern void css_driver_unregister(structextern void css_sch_device_unregister (struct subchannel *);extern struct subchannel *get_subchannel_by_schid (struct subchannel_id );extern int css_init_done; +int for_each_subchannel_staged (int (*fn_known)(struct subchannel *,void *), +int (*fn_unknown)(struct subchannel_id , +void *),void *data);extern int for_each_subchannel (int (*fn)(struct subchannel_id ,void *),void *);extern void css_process_crw (int ,int );extern void css_reiterate_subchannels (void );
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 14/47 qdio: Remove double checked value.
In reply to Martin SchwidefskyFrom: Sebastian Ott <[email protected]>
---
drivers/s390/cio/qdio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/s390/cio/qdio.c +1 -2
@@ -1408,8 +1408,7 @@ __tiqdio_inbound_processing(struct qdio_if (q->hydra_gives_outbound_pcis) {if (!q->siga_sync_done_on_thinints) {SYNC_MEMORY_ALL ; - }else if ((!q->siga_sync_done_on_outb_tis)&& - (q->hydra_gives_outbound_pcis)) { + }else if (!q->siga_sync_done_on_outb_tis) {SYNC_MEMORY_ALL_OUTB ; } }else {
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 15/47 qdio: set QDIO_ACTIVATE_TIMEOUT to 5s
In reply to Martin SchwidefskyFrom: Ursula Braun <[email protected]>
Current definition of QDIO_ACTIVATE_TIMEOUT results in value 0. Thus it may cause endless wait in function qdio_activate().
---
drivers/s390/cio/qdio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/s390/cio/qdio.h +1 -1
@@ -57,7 +57,7 @@of the queue to 0 */ #define QDIO_ESTABLISH_TIMEOUT (1*HZ) -#define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10) +#define QDIO_ACTIVATE_TIMEOUT (5*HZ)#define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)#define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)#define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 16/47 sclp: sysfs interface for SCLP cpi
In reply to Martin SchwidefskyFrom: Michael Ernst <[email protected]>
---
drivers/s390/char/Makefile | 2 drivers/s390/char/sclp_cpi.c | 246 +----------------------- drivers/s390/char/sclp_cpi_sys.c | 390 +++++++++++++++++++++++++++++++++++++++ drivers/s390/char/sclp_cpi_sys.h | 15 + 4 files changed, 422 insertions(+), 231 deletions(-)
drivers/s390/char/Makefile +1 -1
@@ -3,7 +3,7 @@ # obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ - sclp_info.o sclp_config.o sclp_chp.o + sclp_info.o sclp_config.o sclp_chp.o sclp_cpi_sys.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
drivers/s390/char/sclp_cpi.c +16 -230
271 lines not on this page · raw message
drivers/s390/char/sclp_cpi_sys.c new file +390 -0
390 lines not on this page · raw message
drivers/s390/char/sclp_cpi_sys.h new file +15 -0
@@ -0,0 +1,15 @@ +/* +* drivers/s390/char/sclp_cpi_sys.h +* SCLP control program identification sysfs interface +* +* Copyright IBM Corp. 2007 +* Author(s): Michael Ernst <[email protected]> +*/ + +#ifndef __SCLP_CPI_SYS_H__ +#define __SCLP_CPI_SYS_H__ + +int sclp_cpi_set_data (const char *system,const char *sysplex, +const char *type,u64 level); + +#endif /* __SCLP_CPI_SYS_H__ */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 17/47 Standby cpu activation/deactivation.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
Add a new interface so that cpus can be put into standby state and configured state.
Only offline cpus can be put into standby state or configured state. For that the new percpu sysfs attribute "configure" must be used. To put a cpu in standby state a "0" must be written to the attribute. In order to switch it into configured state a "1" must be written to the attribute.
Only cpus in configured state can be brought online.
In addition this patch introduces a static mapping of physical to logical cpus. As a result only the sysfs directories of present cpus will be created. To scan for new cpus the new sysfs attribute "rescan" must be used.
Writing to /sys/devices/system/cpu/rescan will trigger a rescan of cpus and will create directories for new cpus.
On IPL only configured cpus will be used. And on reboot/shutdown all cpus will remain in their current state (configured/standby).
---
arch/s390/kernel/early.c | 3 arch/s390/kernel/setup.c | 2 arch/s390/kernel/smp.c | 401 ++++++++++++++++++++++++++++++++++-------- drivers/s390/char/Makefile | 2 drivers/s390/char/sclp.h | 4 drivers/s390/char/sclp_cmd.c | 319 +++++++++++++++++++++++++++++++++ drivers/s390/char/sclp_info.c | 116 ------------ include/asm-s390/sclp.h | 21 ++ 8 files changed, 675 insertions(+), 193 deletions(-)
arch/s390/kernel/early.c +2 -1
@@ -276,8 +276,9 @@ void __init startup_init(void)create_kernel_nss ();sort_main_extable ();setup_lowcore_early (); -sclp_readinfo_early (); +sclp_read_info_early ();sclp_facilities_detect (); +sclp_read_cpu_info_early (); memsize =sclp_memory_detect ();#ifndef CONFIG_64BIT /*
arch/s390/kernel/setup.c +1 -1
@@ -920,7 +920,7 @@ setup_arch(char **cmdline_p)void __cpuinit print_cpu_info (struct cpuinfo_S390 *cpuinfo) { - printk("cpu %d " + printk(KERN_INFO "cpu %d " #ifdef CONFIG_SMP "phys_idx=%d " #endif
arch/s390/kernel/smp.c +330 -71
529 lines not on this page · raw message
drivers/s390/char/Makefile +1 -1
@@ -3,7 +3,7 @@ # obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ - sclp_info.o sclp_config.o sclp_chp.o sclp_cpi_sys.o + sclp_cmd.o sclp_config.o sclp_chp.o sclp_cpi_sys.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
drivers/s390/char/sclp_cmd.c new file +319 -0
319 lines not on this page · raw message
drivers/s390/char/sclp.h +2 -2
@@ -56,8 +56,6 @@ typedef unsigned int sclp_cmdw_t;#define SCLP_CMDW_READ_EVENT_DATA 0x00770005#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005 -#define SCLP_CMDW_READ_SCP_INFO 0x00020001 -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001#define GDS_ID_MDSMU 0x1310#define GDS_ID_MDSROUTEINFO 0x1311
@@ -83,6 +81,8 @@ extern u64 sclp_facilities;#define SCLP_HAS_CHP_INFO (sclp_facilities & 0x8000000000000000ULL)#define SCLP_HAS_CHP_RECONFIG (sclp_facilities & 0x2000000000000000ULL) +#define SCLP_HAS_CPU_INFO (sclp_facilities & 0x0800000000000000ULL) +#define SCLP_HAS_CPU_RECONFIG (sclp_facilities & 0x0400000000000000ULL)struct gds_subvector {u8 length;
drivers/s390/char/sclp_info.c deleted +0 -116
116 lines not on this page · raw message
include/asm-s390/sclp.h +20 -1
@@ -27,7 +27,26 @@ struct sclp_ipl_info {char loadparm[LOADPARM_LEN ]; }; -void sclp_readinfo_early (void ); +struct sclp_cpu_entry { +u8 address; +u8 reserved0[13 ]; +u8 type; +u8 reserved1; +} __attribute__((packed)); + +struct sclp_cpu_info { +unsigned int configured; +unsigned int standby; +unsigned int combined; +int has_cpu_type; +struct sclp_cpu_entry cpu[255 ]; +}; + +int sclp_get_cpu_info (struct sclp_cpu_info *info); +int sclp_cpu_configure (u8 cpu); +int sclp_cpu_deconfigure (u8 cpu); +void sclp_read_info_early (void ); +void sclp_read_cpu_info_early (void );void sclp_facilities_detect (void );unsigned long long sclp_memory_detect (void );int sclp_sdias_blk_count (void );
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 18/47 sclp: convert channel path configure code to use sync interface.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
---
drivers/s390/char/Makefile | 2 drivers/s390/char/sclp_chp.c | 200 ------------------------------------------- drivers/s390/char/sclp_cmd.c | 123 ++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 202 deletions(-)
drivers/s390/char/Makefile +1 -1
@@ -3,7 +3,7 @@ # obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ - sclp_cmd.o sclp_config.o sclp_chp.o sclp_cpi_sys.o + sclp_cmd.o sclp_config.o sclp_cpi_sys.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
drivers/s390/char/sclp_chp.c deleted +0 -200
200 lines not on this page · raw message
drivers/s390/char/sclp_cmd.c +122 -1
138 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 19/47 Optimize reference bit handling.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
page_referenced always tests and clears the reference bit in the storage key, even if the page is not mapped. For a page that is only accessed with sys_read this has a negative side effect. A page that is only read once makes two trips over the inactive list before it is removed from the page cache. When the page is added to the page cache it is added to the start of the inactive list. After it went through the inactive list the reference bit is checked with a call to page_referenced which will find the referenced bit in the storage key set because the copy_to_user operation will set the bit. This causes the page to be added to the start of the inactive list again. This wastes cpu cycles in vmscan.
---
mm/rmap.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
mm/rmap.c +4 -3
@@ -391,9 +391,6 @@ int page_referenced(struct page *page, i {int referenced =0 ; -if (page_test_and_clear_young (page)) - referenced++; -if (TestClearPageReferenced (page)) referenced++;
@@ -409,6 +406,8 @@ int page_referenced(struct page *page, i referenced +=page_referenced_file (page);unlock_page (page); } +if (page_test_and_clear_young (page)) + referenced++; }return referenced; }
@@ -640,6 +639,8 @@ void page_remove_rmap(struct page *page,* Leaving it set also helps swapoff to reinstate ptes * faster for those pages still in swapcache. */ +if (page_test_and_clear_young (page)) +SetPageReferenced (page);if (page_test_dirty (page)) {page_clear_dirty (page);set_page_dirty (page);
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 20/47 Fix tlb flushing with idte.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
The clear-by-asce operation of the idte instruction gets an asce (address-space-control-element) as argument to specify which TLBs need to get flushed. The current code passes a plain pointer to the start of the pgd without the additional bits which would make the pointer an asce. The current machines don't mind the difference but a future model might want to use the designation type control bits in the asce as a filter for the TLBs to flush.
---
arch/s390/kernel/head64.S | 2 +- include/asm-s390/mmu_context.h | 27 ++++++++++++--------------- include/asm-s390/tlbflush.h | 12 ++++++------ 3 files changed, 19 insertions(+), 22 deletions(-)
arch/s390/kernel/head64.S +1 -1
@@ -157,7 +157,7 @@ startup_continue: .long 0xb2b10000 # store facility list tm 0xc8,0x08 # check bit for clearing-by-ASCE bno 0f-.LPG1(%r13) - lhi %r1,2094 + lhi %r1,2048 lhi %r2,0 .long 0xb98e2001 oi 7(%r12),0x80 # set IDTE flag
include/asm-s390/mmu_context.h +12 -15
@@ -12,10 +12,15 @@#include <asm/pgalloc.h> #include <asm-generic/mm_hooks.h> -/* -* get a new mmu context.. S390 don't know about contexts. -*/ -#define init_new_context (tsk,mm) 0 +static inline int init_new_context (struct task_struct *tsk, +struct mm_struct *mm) +{ + mm->context = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; +#ifdef CONFIG_64BIT + mm->context |= _ASCE_TYPE_REGION3; +#endif +return 0 ; +}#define destroy_context (mm) do { } while (0)
@@ -27,19 +32,11 @@static inline void update_mm (struct mm_struct *mm,struct task_struct *tsk) { -pgd_t *pgd = mm->pgd; -unsigned long asce_bits; - -/* Calculate asce bits from the first pgd table entry. */ - asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; -#ifdef CONFIG_64BIT - asce_bits |= _ASCE_TYPE_REGION3; -#endif - S390_lowcore.user_asce = asce_bits |__pa (pgd); + S390_lowcore.user_asce = mm->context |__pa (mm->pgd);if (switch_amode) {/* Load primary space page table origin. */ -pgd_t *shadow_pgd =get_shadow_table (pgd) ? : pgd; - S390_lowcore.user_exec_asce = asce_bits |__pa (shadow_pgd); +pgd_t *shadow_pgd =get_shadow_table (mm->pgd) ? : mm->pgd; + S390_lowcore.user_exec_asce = mm->context |__pa (shadow_pgd); asmvolatile (LCTL_OPCODE " 1,1,%0\n" : :"m" (S390_lowcore.user_exec_asce) ); }else
include/asm-s390/tlbflush.h +6 -6
@@ -42,11 +42,11 @@ static inline void __tlb_flush_global(vo/* * Flush all tlb entries of a page table on all cpus. */ -static inline void __tlb_flush_idte (pgd_t *pgd) +static inline void __tlb_flush_idte (unsigned long asce) { asmvolatile (" .insn rrf,0xb98e0000,0,%0,%1,0" - : :"a" (2048 ),"a" (__pa (pgd) &PAGE_MASK ) :"cc" ); + : :"a" (2048 ),"a" (asce) :"cc" ); }static inline void __tlb_flush_mm (struct mm_struct * mm)
@@ -61,11 +61,11 @@ static inline void __tlb_flush_mm(struct* only ran on the local cpu. */ if (MACHINE_HAS_IDTE ) { -pgd_t *shadow_pgd =get_shadow_table (mm->pgd); +pgd_t *shadow =get_shadow_table (mm->pgd); -if (shadow_pgd) -__tlb_flush_idte (shadow_pgd); -__tlb_flush_idte (mm->pgd); +if (shadow) +__tlb_flush_idte ((unsigned long ) shadow | mm->context); +__tlb_flush_idte ((unsigned long ) mm->pgd | mm->context);return ; }preempt_disable ();
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 21/47 Change vmalloc defintions
In reply to Martin SchwidefskyFrom: Christian Borntraeger <[email protected]>
Currently the vmalloc area starts at a dynamic address depending on the memory size. There was also an 8MB security hole after the physical memory to catch out-of-bounds accesses.
We can simplify the code by putting the vmalloc area explicitely at the top of the kernel mapping and setting the vmalloc size to a fixed value of 128MB/128GB for 31bit/64bit systems. Part of the vmalloc area will be used for the vmem_map. This leaves an area of 96MB/1GB for normal vmalloc allocations.
---
arch/s390/kernel/setup.c | 6 ++--- arch/s390/mm/vmem.c | 20 ++++++------------- include/asm-s390/pgtable.h | 46 +++++++++++++++------------------------------ 3 files changed, 26 insertions(+), 46 deletions(-)
arch/s390/kernel/setup.c +3 -3
@@ -617,7 +617,7 @@ EXPORT_SYMBOL_GPL(real_memory_size);static void __init setup_memory_end (void ) {unsigned long memory_size; -unsigned long max_mem, max_phys; +unsigned long max_mem;int i;#if defined(CONFIG_ZFCPDUMP ) || defined(CONFIG_ZFCPDUMP_MODULE )
@@ -625,10 +625,10 @@ static void __init setup_memory_end(void memory_end =ZFCPDUMP_HSA_SIZE ;#endif memory_size =0 ; - max_phys =VMALLOC_END_INIT -VMALLOC_MIN_SIZE ; memory_end &=PAGE_MASK ; - max_mem = memory_end ?min (max_phys, memory_end) : max_phys; + max_mem = memory_end ?min (VMALLOC_START , memory_end) :VMALLOC_START ; + memory_end =min (max_mem, memory_end);for (i =0 ; i <MEMORY_CHUNKS ; i++) {struct mem_chunk *chunk = &memory_chunk[i];
arch/s390/mm/vmem.c +7 -13
@@ -15,10 +15,6 @@#include <asm/setup.h> #include <asm/tlbflush.h> -unsigned long vmalloc_end; -EXPORT_SYMBOL (vmalloc_end); - -static struct page *vmem_map;static DEFINE_MUTEX (vmem_mutex);struct memory_segment {
@@ -188,8 +184,8 @@ static int vmem_add_mem_map(unsigned lonpte_t pte;int ret = -ENOMEM ; - map_start = vmem_map +PFN_DOWN (start); - map_end = vmem_map +PFN_DOWN (start + size); + map_start =VMEM_MAP +PFN_DOWN (start); + map_end =VMEM_MAP +PFN_DOWN (start + size); start_addr = (unsigned long ) map_start &PAGE_MASK ; end_addr =PFN_ALIGN ((unsigned long ) map_end);
@@ -254,7 +250,7 @@ static int insert_memory_segment(struct {struct memory_segment *tmp; -if (PFN_DOWN (seg->start + seg->size) > max_pfn || +if (seg->start + seg->size >=VMALLOC_START || seg->start + seg->size < seg->start)return -ERANGE ;
@@ -357,17 +353,15 @@ out:/* * map whole physical memory to virtual memory (identity mapping) +* we reserve enough space in the vmalloc area for vmemmap to hotplug +* additional memory segments. */ void __init vmem_map_init (void ) { -unsigned long map_size;int i; - map_size =ALIGN (max_low_pfn,MAX_ORDER_NR_PAGES ) *sizeof (struct page ); - vmalloc_end =PFN_ALIGN (VMALLOC_END_INIT ) -PFN_ALIGN (map_size); - vmem_map = (struct page *) vmalloc_end; -NODE_DATA (0 )->node_mem_map = vmem_map; - +BUILD_BUG_ON ((unsigned long )VMEM_MAP +VMEM_MAP_SIZE >VMEM_MAP_MAX ); +NODE_DATA (0 )->node_mem_map =VMEM_MAP ;for (i =0 ; i <MEMORY_CHUNKS && memory_chunk[i].size >0 ; i++)vmem_add_mem (memory_chunk[i].addr, memory_chunk[i].size); }
include/asm-s390/pgtable.h +16 -30
57 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 22/47 Print kernel version in dump_stack() and show_regs().
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
Also print PREEMPT and/or SMP if the kernel was configured that way. Makes s390 look a bit more like other architectures.
---
arch/s390/kernel/process.c | 18 ++++++++++-------- arch/s390/kernel/traps.c | 20 +++++++++++++++++--- 2 files changed, 27 insertions(+), 11 deletions(-)
arch/s390/kernel/process.c +10 -8
@@ -36,7 +36,7 @@#include <linux/init.h> #include <linux/module.h> #include <linux/notifier.h> - +#include <linux/utsname.h> #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/system.h>
@@ -182,13 +182,15 @@ void cpu_idle(void)void show_regs (struct pt_regs *regs) { -struct task_struct *tsk = current; - -printk ("CPU: %d %s\n" ,task_thread_info (tsk)->cpu,print_tainted ()); -printk ("Process %s (pid: %d, task: %p, ksp: %p)\n" , - current->comm,task_pid_nr (current), (void *) tsk, - (void *) tsk->thread.ksp); - +print_modules (); +printk ("CPU: %d %s %s %.*s\n" , +task_thread_info (current)->cpu,print_tainted (), +init_utsname ()->release, + (int )strcspn (init_utsname ()->version," " ), +init_utsname ()->version); +printk ("Process %s (pid: %d, task: %p, ksp: %p)\n" , + current->comm, current->pid, current, + (void *) current->thread.ksp);show_registers (regs);/* Show stack backtrace if pt_regs is from kernel mode */ if (!(regs->psw.mask &PSW_MASK_PSTATE ))
arch/s390/kernel/traps.c +17 -3
@@ -31,6 +31,7 @@#include <linux/reboot.h> #include <linux/kprobes.h> #include <linux/bug.h> +#include <linux/utsname.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h>
@@ -168,9 +169,16 @@ void show_stack(struct task_struct *task*/ void dump_stack (void ) { +printk ("CPU: %d %s %s %.*s\n" , +task_thread_info (current)->cpu,print_tainted (), +init_utsname ()->release, + (int )strcspn (init_utsname ()->version," " ), +init_utsname ()->version); +printk ("Process %s (pid: %d, task: %p, ksp: %p)\n" , + current->comm, current->pid, current, + (void *) current->thread.ksp);show_stack (NULL ,NULL ); } -EXPORT_SYMBOL (dump_stack);static inline int mask_bits (struct pt_regs *regs,unsigned long bits)
@@ -258,8 +266,14 @@ void die(const char * str, struct pt_regconsole_verbose ();spin_lock_irq (&die_lock);bust_spinlocks (1 ); -printk ("%s: %04lx [#%d]\n" , str, err &0xffff , ++die_counter); -print_modules (); +printk ("%s: %04lx [#%d] " , str, err &0xffff , ++die_counter); +#ifdef CONFIG_PREEMPT +printk ("PREEMPT " ); +#endif +#ifdef CONFIG_SMP +printk ("SMP" ); +#endif +printk ("\n" );notify_die (DIE_OOPS , str, regs, err, current->thread.trap_no,SIGSEGV );show_regs (regs);bust_spinlocks (0 );
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 23/47 Get rid of HOLES_IN_ZONE requirement.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
Align everything to MAX_ORDER so we can get rid of the extra checks.
---
arch/s390/Kconfig | 3 --- arch/s390/kernel/setup.c | 25 ++++++++++++++++++++++++- arch/s390/mm/vmem.c | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-)
arch/s390/Kconfig +0 -3
@@ -276,9 +276,6 @@ source "kernel/Kconfig.preempt" source "mm/Kconfig" -config HOLES_IN_ZONE - def_bool y - comment "I/O subsystem configuration" config MACHCHK_WARNING
arch/s390/kernel/setup.c +24 -1
@@ -559,7 +559,9 @@ setup_resources(void) data_resource.start = (unsigned long ) &_etext; data_resource.end = (unsigned long ) &_edata -1 ; -for (i =0 ; i <MEMORY_CHUNKS && memory_chunk[i].size >0 ; i++) { +for (i =0 ; i <MEMORY_CHUNKS ; i++) { +if (!memory_chunk[i].size) +continue ; res =alloc_bootmem_low (sizeof (struct resource )); res->flags =IORESOURCE_BUSY |IORESOURCE_MEM ;switch (memory_chunk[i].type) {
@@ -630,6 +632,27 @@ static void __init setup_memory_end(void max_mem = memory_end ?min (VMALLOC_START , memory_end) :VMALLOC_START ; memory_end =min (max_mem, memory_end); +/* +* Make sure all chunks are MAX_ORDER aligned so we don't need the +* extra checks that HOLES_IN_ZONE would require. +*/ +for (i =0 ; i <MEMORY_CHUNKS ; i++) { +unsigned long start, end; +struct mem_chunk *chunk; +unsigned long align; + + chunk = &memory_chunk[i]; + align =1UL << (MAX_ORDER +PAGE_SHIFT -1 ); + start = (chunk->addr + align -1 ) & ~(align -1 ); + end = (chunk->addr + chunk->size) & ~(align -1 ); +if (start >= end) +memset (chunk,0 ,sizeof (*chunk)); +else { + chunk->addr = start; + chunk->size = end - start; + } + } +for (i =0 ; i <MEMORY_CHUNKS ; i++) {struct mem_chunk *chunk = &memory_chunk[i];
arch/s390/mm/vmem.c +1 -1
@@ -376,7 +376,7 @@ static int __init vmem_convert_memory_chint i;mutex_lock (&vmem_mutex); -for (i =0 ; i <MEMORY_CHUNKS && memory_chunk[i].size >0 ; i++) { +for (i =0 ; i <MEMORY_CHUNKS ; i++) {if (!memory_chunk[i].size)continue ; seg =kzalloc (sizeof (*seg),GFP_KERNEL );
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 24/47 DEBUG_PAGEALLOC support for s390.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
---
arch/s390/Kconfig.debug | 8 ++++++++ arch/s390/defconfig | 1 + arch/s390/kernel/traps.c | 5 ++++- arch/s390/mm/init.c | 27 +++++++++++++++++++++++++++ include/asm-s390/cacheflush.h | 4 ++++ 5 files changed, 44 insertions(+), 1 deletion(-)
arch/s390/defconfig +1 -0
@@ -727,6 +727,7 @@ CONFIG_FORCED_INLINING=y # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set CONFIG_SAMPLES=y +# CONFIG_DEBUG_PAGEALLOC is not set # # Security options
arch/s390/Kconfig.debug +8 -0
@@ -6,4 +6,12 @@ config TRACE_IRQFLAGS_SUPPORT source "lib/Kconfig.debug" +config DEBUG_PAGEALLOC + bool "Debug page memory allocations" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a slowdown, but helps to find certain types of + memory corruptions. + endmenu
arch/s390/kernel/traps.c +4 -1
@@ -271,7 +271,10 @@ void die(const char * str, struct pt_regprintk ("PREEMPT " );#endif #ifdef CONFIG_SMP -printk ("SMP" ); +printk ("SMP " ); +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC +printk ("DEBUG_PAGEALLOC" );#endif printk ("\n" );notify_die (DIE_OOPS , str, regs, err, current->thread.trap_no,SIGSEGV );
arch/s390/mm/init.c +27 -0
@@ -167,6 +167,33 @@ void __init mem_init(void) PFN_ALIGN((unsigned long)&_eshared) - 1); } +#ifdef CONFIG_DEBUG_PAGEALLOC +void kernel_map_pages (struct page *page,int numpages,int enable) +{ +pgd_t *pgd; +pud_t *pud; +pmd_t *pmd; +pte_t *pte; +unsigned long address; +int i; + +for (i =0 ; i < numpages; i++) { + address =page_to_phys (page + i); + pgd =pgd_offset_k (address); + pud =pud_offset (pgd, address); + pmd =pmd_offset (pud, address); + pte =pte_offset_kernel (pmd, address); +if (!enable) { +ptep_invalidate (address, pte); +continue ; + } + *pte =mk_pte_phys (address,__pgprot (_PAGE_TYPE_RW)); +/* Flush cpu write queue. */ +mb (); + } +} +#endif +void free_initmem (void ) {unsigned long addr;
include/asm-s390/cacheflush.h +4 -0
@@ -24,4 +24,8 @@#define copy_from_user_page (vma, page, vaddr, dst, src, len) \ memcpy(dst, src, len) +#ifdef CONFIG_DEBUG_PAGEALLOC +void kernel_map_pages (struct page *page,int numpages,int enable); +#endif +#endif /* _S390_CACHEFLUSH_H */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 25/47 Remove owner_pc member from raw_spinlock_t.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
Used to contain the address of the holder of the lock. But since the spinlock code is not inlined anymore all locks contain the same address anyway. And since in addtition nobody complained about that for ages its obviously unused. So remove it.
---
arch/s390/lib/spinlock.c | 12 ++++-------- include/asm-s390/spinlock.h | 19 ++++++------------- include/asm-s390/spinlock_types.h | 1 - 3 files changed, 10 insertions(+), 22 deletions(-)
arch/s390/lib/spinlock.c +4 -8
@@ -39,7 +39,7 @@ static inline void _raw_yield_cpu(int cp_raw_yield (); } -void _raw_spin_lock_wait (raw_spinlock_t *lp,unsigned int pc) +void _raw_spin_lock_wait (raw_spinlock_t *lp) {int count = spin_retry;unsigned int cpu = ~smp_processor_id ();
@@ -53,15 +53,13 @@ void _raw_spin_lock_wait(raw_spinlock_t }if (__raw_spin_is_locked (lp))continue ; -if (_raw_compare_and_swap (&lp->owner_cpu,0 , cpu) ==0 ) { - lp->owner_pc = pc; +if (_raw_compare_and_swap (&lp->owner_cpu,0 , cpu) ==0 )return ; - } } }EXPORT_SYMBOL (_raw_spin_lock_wait); -int _raw_spin_trylock_retry (raw_spinlock_t *lp,unsigned int pc) +int _raw_spin_trylock_retry (raw_spinlock_t *lp) {unsigned int cpu = ~smp_processor_id ();int count;
@@ -69,10 +67,8 @@ int _raw_spin_trylock_retry(raw_spinlockfor (count = spin_retry; count >0 ; count--) {if (__raw_spin_is_locked (lp))continue ; -if (_raw_compare_and_swap (&lp->owner_cpu,0 , cpu) ==0 ) { - lp->owner_pc = pc; +if (_raw_compare_and_swap (&lp->owner_cpu,0 , cpu) ==0 )return 1 ; - } }return 0 ; }
include/asm-s390/spinlock.h +6 -13
@@ -58,39 +58,32 @@ _raw_compare_and_swap(volatile unsigneddo {while (__raw_spin_is_locked (lock)) \ _raw_spin_relax(lock); } while (0) -extern void _raw_spin_lock_wait (raw_spinlock_t *,unsigned int pc); -extern int _raw_spin_trylock_retry (raw_spinlock_t *,unsigned int pc); +extern void _raw_spin_lock_wait (raw_spinlock_t *); +extern int _raw_spin_trylock_retry (raw_spinlock_t *);extern void _raw_spin_relax (raw_spinlock_t *lock);static inline void __raw_spin_lock (raw_spinlock_t *lp) { -unsigned long pc =1 | (unsigned long )__builtin_return_address (0 );int old; old =_raw_compare_and_swap (&lp->owner_cpu,0 , ~smp_processor_id ()); -if (likely (old ==0 )) { - lp->owner_pc = pc; +if (likely (old ==0 ))return ; - } -_raw_spin_lock_wait (lp, pc); +_raw_spin_lock_wait (lp); }static inline int __raw_spin_trylock (raw_spinlock_t *lp) { -unsigned long pc =1 | (unsigned long )__builtin_return_address (0 );int old; old =_raw_compare_and_swap (&lp->owner_cpu,0 , ~smp_processor_id ()); -if (likely (old ==0 )) { - lp->owner_pc = pc; +if (likely (old ==0 ))return 1 ; - } -return _raw_spin_trylock_retry (lp, pc); +return _raw_spin_trylock_retry (lp); }static inline void __raw_spin_unlock (raw_spinlock_t *lp) { - lp->owner_pc =0 ;_raw_compare_and_swap (&lp->owner_cpu, lp->owner_cpu,0 ); }
include/asm-s390/spinlock_types.h +0 -1
@@ -7,7 +7,6 @@typedef struct {volatile unsigned int owner_cpu; -volatile unsigned int owner_pc; } __attribute__ ((aligned (4 )))raw_spinlock_t ;#define __RAW_SPIN_LOCK_UNLOCKED { 0 }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 26/47 Use new style spinlock initializer in __RWSEM_INITIALIZER.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
---
include/asm-s390/rwsem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
include/asm-s390/rwsem.h +2 -2
@@ -91,8 +91,8 @@ struct rw_semaphore {#endif #define __RWSEM_INITIALIZER (name) \ -{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \ - __RWSEM_DEP_MAP_INIT(name) } + { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait.lock), \ + LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }#define DECLARE_RWSEM (name) \ struct rw_semaphore name = __RWSEM_INITIALIZER(name)
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 27/47 Get rid of additional_cpus kernel parameter.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
It caused only a lot of confusion. From now on cpu hotplug of up to NR_CPUS will work by default. If somebody wants to limit that then the possible_cpus parameter can be used.
---
Documentation/cpu-hotplug.txt | 2 arch/s390/kernel/early.c | 1 arch/s390/kernel/setup.c | 1 arch/s390/kernel/smp.c | 178 +++++++++++++++++------------------------- drivers/s390/char/sclp_cmd.c | 46 ---------- include/asm-s390/sclp.h | 1 include/asm-s390/smp.h | 3 7 files changed, 78 insertions(+), 154 deletions(-)
arch/s390/kernel/early.c +0 -1
@@ -278,7 +278,6 @@ void __init startup_init(void)setup_lowcore_early ();sclp_read_info_early ();sclp_facilities_detect (); -sclp_read_cpu_info_early (); memsize =sclp_memory_detect ();#ifndef CONFIG_64BIT /*
arch/s390/kernel/setup.c +0 -1
@@ -922,7 +922,6 @@ setup_arch(char **cmdline_p)cpu_init (); __cpu_logical_map[0 ] = S390_lowcore.cpu_data.cpu_addr; -smp_setup_cpu_possible_map ();/* * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
arch/s390/kernel/smp.c +75 -103
251 lines not on this page · raw message
Documentation/cpu-hotplug.txt +1 -1
@@ -50,7 +50,7 @@ additional_cpus=n (*) Use this to limit cpu_possible_map = cpu_present_map + additional_cpus (*) Option valid only for following architectures -- x86_64, ia64, s390 +- x86_64, ia64 ia64 and x86_64 use the number of disabled local apics in ACPI tables MADT to determine the number of potentially hot-pluggable cpus. The implementation
drivers/s390/char/sclp_cmd.c +2 -44
72 lines not on this page · raw message
include/asm-s390/sclp.h +0 -1
@@ -46,7 +46,6 @@ int sclp_get_cpu_info(struct sclp_cpu_inint sclp_cpu_configure (u8 cpu);int sclp_cpu_deconfigure (u8 cpu);void sclp_read_info_early (void ); -void sclp_read_cpu_info_early (void );void sclp_facilities_detect (void );unsigned long long sclp_memory_detect (void );int sclp_sdias_blk_count (void );
include/asm-s390/smp.h +0 -3
@@ -35,8 +35,6 @@ extern void machine_restart_smp(char *);extern void machine_halt_smp (void );extern void machine_power_off_smp (void ); -extern void smp_setup_cpu_possible_map (void ); -#define NO_PROC_ID 0xFF/* No processor magic marker */ /*
@@ -103,7 +101,6 @@ static inline void smp_send_stop(void)#define hard_smp_processor_id () 0#define smp_cpu_not_running (cpu) 1 -#define smp_setup_cpu_possible_map () do { } while (0)#endif extern union save_area *zfcpdump_save_areas[NR_CPUS +1 ];
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 28/47 Remove appldata include from sysctl_check.c
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
Forgot to remove this when removing the appldata binary sysctls.
---
kernel/sysctl_check.c | 1 - 1 file changed, 1 deletion(-)
kernel/sysctl_check.c +0 -1
@@ -1,6 +1,5 @@#include <linux/stat.h> #include <linux/sysctl.h> -#include "../arch/s390/appldata/appldata.h" #include "../fs/xfs/linux-2.6/xfs_sysctl.h" #include <linux/sunrpc/debug.h> #include <linux/string.h>
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 29/47 crypto: move s390 Kconfig options.
In reply to Martin SchwidefskyFrom: Jan Glauber <[email protected]>
Move s390 crypto Kconfig options to drivers/crypto/Kconfig to have all hardware crypto devices in one place.
This also makes messing up the kernel source tree easier for some people.
---
arch/s390/crypto/Kconfig | 60 -------------------------------------------- drivers/crypto/Kconfig | 63 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 62 deletions(-)
arch/s390/crypto/Kconfig deleted +0 -60
@@ -1,60 +0,0 @@ -config CRYPTO_SHA1_S390 - tristate "SHA1 digest algorithm" - depends on S390 - select CRYPTO_ALGAPI - help - This is the s390 hardware accelerated implementation of the - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). - -config CRYPTO_SHA256_S390 - tristate "SHA256 digest algorithm" - depends on S390 - select CRYPTO_ALGAPI - help - This is the s390 hardware accelerated implementation of the - SHA256 secure hash standard (DFIPS 180-2). - - This version of SHA implements a 256 bit hash with 128 bits of - security against collision attacks. - -config CRYPTO_DES_S390 - tristate "DES and Triple DES cipher algorithms" - depends on S390 - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - help - This us the s390 hardware accelerated implementation of the - DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). - -config CRYPTO_AES_S390 - tristate "AES cipher algorithms" - depends on S390 - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - help - This is the s390 hardware accelerated implementation of the - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - On s390 the System z9-109 currently only supports the key size - of 128 bit. - -config S390_PRNG - tristate "Pseudo random number generator device driver" - depends on S390 - default "m" - help - Select this option if you want to use the s390 pseudo random number - generator. The PRNG is part of the cryptographic processor functions - and uses triple-DES to generate secure random numbers like the - ANSI X9.17 standard. The PRNG is usable via the char device - /dev/prandom.
drivers/crypto/Kconfig +61 -2
73 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 30/47 dasd: fix return value of dasd_generic_probe()
In reply to Martin SchwidefskyFrom: Stefan Haberland <[email protected]>
Using the return value of ccw_device_set_online as return value for dasd_generic_probe() causes the DASD to fail setting online
---
drivers/s390/block/dasd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/s390/block/dasd.c +4 -3
@@ -1969,9 +1969,10 @@ dasd_generic_probe (struct ccw_device *c ret =ccw_device_set_online (cdev);if (ret)printk (KERN_WARNING -"dasd_generic_probe: could not initially online " -"ccw-device %s\n" , cdev->dev.bus_id); -return ret; +"dasd_generic_probe: could not initially " +"online ccw-device %s; return code: %d\n" , + cdev->dev.bus_id, ret); +return 0 ; }/*
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 31/47 arch/s390: Add missing "space"
In reply to Martin SchwidefskyFrom: Joe Perches <[email protected]>
---
arch/s390/crypto/aes_s390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/crypto/aes_s390.c +1 -1
@@ -341,7 +341,7 @@ static int __init aes_init(void) ecb_aes_alg.cra_u.blkcipher.max_keysize =AES_MIN_KEY_SIZE ; cbc_aes_alg.cra_u.blkcipher.max_keysize =AES_MIN_KEY_SIZE ;printk (KERN_INFO -"aes_s390: hardware acceleration only available for" +"aes_s390: hardware acceleration only available for " "128 bit keys\n" ); }
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 32/47 drivers/s390: Add missing "space"
In reply to Martin SchwidefskyFrom: Joe Perches <[email protected]>
---
drivers/s390/char/monwriter.c | 2 +- drivers/s390/char/vmlogrdr.c | 2 +- drivers/s390/cio/chsc.c | 2 +- drivers/s390/net/claw.c | 2 +- drivers/s390/net/lcs.c | 2 +- drivers/s390/scsi/zfcp_fsf.c | 10 +++++----- 6 files changed, 10 insertions(+), 10 deletions(-)
drivers/s390/char/monwriter.c +1 -1
@@ -295,7 +295,7 @@ module_init(mon_init);module_exit (mon_exit);module_param_named (max_bufs, mon_max_bufs, int,0644 ); -MODULE_PARM_DESC (max_bufs,"Maximum number of sample monitor data buffers" +MODULE_PARM_DESC (max_bufs,"Maximum number of sample monitor data buffers " "that can be active at one time" );MODULE_AUTHOR ("Melissa Howland <[email protected]>" );
drivers/s390/char/vmlogrdr.c +1 -1
@@ -683,7 +683,7 @@ static int vmlogrdr_register_driver(void/* Register with iucv driver */ ret =iucv_register (&vmlogrdr_iucv_handler,1 );if (ret) { -printk (KERN_ERR "vmlogrdr: failed to register with" +printk (KERN_ERR "vmlogrdr: failed to register with " "iucv driver\n" ); goto out; }
drivers/s390/cio/chsc.c +1 -1
@@ -1042,7 +1042,7 @@ chsc_determine_css_characteristics(void) scsc_area = (void *)get_zeroed_page (GFP_KERNEL |GFP_DMA );if (!scsc_area) { -CIO_MSG_EVENT (0 ,"Was not able to determine available" +CIO_MSG_EVENT (0 ,"Was not able to determine available " "CHSCs due to no memory.\n" );return -ENOMEM ; }
drivers/s390/net/claw.c +1 -1
@@ -2416,7 +2416,7 @@ init_ccw_bk(struct net_device *dev) privptr->p_buff_pages_perwrite);#endif if (p_buff==NULL ) { - printk(KERN_INFO "%s:%s __get_free_pages" + printk(KERN_INFO "%s:%s __get_free_pages " "for writes buf failed : get is for %d pages\n", dev->name, __FUNCTION__,
drivers/s390/net/lcs.c +1 -1
@@ -1115,7 +1115,7 @@ list_modified: rc =lcs_send_setipm (card, ipm);spin_lock_irqsave (&card->ipm_lock, flags);if (rc) { -PRINT_INFO ("Adding multicast address failed." +PRINT_INFO ("Adding multicast address failed. " "Table possibly full!\n" );/* store ipm in failed list -> will be added * to ipm_list again, so a retry will be done
drivers/s390/scsi/zfcp_fsf.c +5 -5
@@ -502,7 +502,7 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp fsf_req->status |=ZFCP_STATUS_FSFREQ_ERROR ;break ;case FSF_SQ_NO_RECOM : -ZFCP_LOG_NORMAL ("bug: No recommendation could be given for a" +ZFCP_LOG_NORMAL ("bug: No recommendation could be given for a " "problem on the adapter %s " "Stopping all operations on this adapter. " ,zfcp_get_busid_by_adapter (fsf_req->adapter));
@@ -813,7 +813,7 @@ zfcp_fsf_status_read_port_closed(structread_unlock_irqrestore (&zfcp_data.config_lock, flags);if (!port || (port->d_id != (status_buffer->d_id &ZFCP_DID_MASK ))) { - ZFCP_LOG_NORMAL("bug: Reopen port indication received for" + ZFCP_LOG_NORMAL("bug: Reopen port indication received for " "nonexisting port with d_id 0x%06x on " "adapter %s. Ignored.\n", status_buffer->d_id & ZFCP_DID_MASK,
@@ -2280,7 +2280,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_ &lock_flags, &fsf_req);if (retval) {ZFCP_LOG_INFO ("error: Out of resources. Could not create an " -"exchange port data request for" +"exchange port data request for " "the adapter %s.\n" ,zfcp_get_busid_by_adapter (adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock,
@@ -2339,7 +2339,7 @@ zfcp_fsf_exchange_port_data_sync(struct 0, NULL, &lock_flags, &fsf_req);if (retval) {ZFCP_LOG_INFO ("error: Out of resources. Could not create an " -"exchange port data request for" +"exchange port data request for " "the adapter %s.\n" ,zfcp_get_busid_by_adapter (adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock,
@@ -4725,7 +4725,7 @@ zfcp_fsf_req_create(struct zfcp_adapter/* allocate new FSF request */ fsf_req =zfcp_fsf_req_alloc (pool, req_flags);if (unlikely (NULL == fsf_req)) { -ZFCP_LOG_DEBUG ("error: Could not put an FSF request into" +ZFCP_LOG_DEBUG ("error: Could not put an FSF request into " "the outbound (send) queue.\n" ); ret = -ENOMEM ; goto failed_fsf_req;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 33/47 kernel: Shutdown Actions Interface
In reply to Martin SchwidefskyFrom: Michael Holzheu <[email protected]>
In case of a kernel panic it is currently possible to specify that a dump should be created, the system should be rebooted or stopped. Virtual sysfs files under the directory /sys/firmware/ are used for that configuration. In addition to that, there are kernel parameters 'vmhalt', 'vmpoff' and 'vmpanic', which can be used to specify z/VM commands, which are automatically executed in case of halt, power off or a kernel panic. This patch combines both functionalities and allows to specify the z/VM CP commands also via sysfs attributes. In addition to that, it enhances the existing handling of shutdown triggers (e.g. halt or panic) and associated shutdown actions (e.g. dump or reipl) and makes it more flexible.
---
arch/s390/kernel/ipl.c | 923 ++++++++++++++++++++++++++++++----------------- arch/s390/kernel/setup.c | 103 ----- arch/s390/kernel/smp.c | 27 - include/asm-s390/ipl.h | 4 4 files changed, 595 insertions(+), 462 deletions(-)
arch/s390/kernel/ipl.c +591 -332
@@ -2,7 +2,7 @@* arch/s390/kernel/ipl.c * ipl/reipl/dump support for Linux on s390. * -* Copyright (C) IBM Corp. 2005,2006 +* Copyright IBM Corp. 2005,2007 * Author(s): Michael Holzheu <[email protected]> * Heiko Carstens <[email protected]> * Volker Sameske <[email protected]>
@@ -31,6 +31,43 @@#define IPL_FCP_DUMP_STR "fcp_dump"#define IPL_NSS_STR "nss" +#define DUMP_CCW_STR "ccw" +#define DUMP_FCP_STR "fcp" +#define DUMP_NONE_STR "none" + +/* +* Four shutdown trigger types are supported: +* - panic +* - halt +* - power off +* - reipl +*/ +#define ON_PANIC_STR "on_panic" +#define ON_HALT_STR "on_halt" +#define ON_POFF_STR "on_poff" +#define ON_REIPL_STR "on_reboot" + +struct shutdown_action ; +struct shutdown_trigger { +char *name; +struct shutdown_action *action; +}; + +/* +* Five shutdown action types are supported: +*/ +#define SHUTDOWN_ACTION_IPL_STR "ipl" +#define SHUTDOWN_ACTION_REIPL_STR "reipl" +#define SHUTDOWN_ACTION_DUMP_STR "dump" +#define SHUTDOWN_ACTION_VMCMD_STR "vmcmd" +#define SHUTDOWN_ACTION_STOP_STR "stop" + +struct shutdown_action { +char *name; +void (*fn) (struct shutdown_trigger *trigger); +int (*init) (void ); +}; +static char *ipl_type_str (enum ipl_type type) {switch (type) {
@@ -54,10 +91,6 @@ enum dump_type { DUMP_TYPE_FCP = 4, }; -#define DUMP_NONE_STR "none" -#define DUMP_CCW_STR "ccw" -#define DUMP_FCP_STR "fcp" -static char *dump_type_str (enum dump_type type) {switch (type) {
@@ -99,30 +132,6 @@ enum dump_method { DUMP_METHOD_FCP_DIAG, }; -enum shutdown_action { -SHUTDOWN_REIPL , -SHUTDOWN_DUMP , -SHUTDOWN_STOP , -}; - -#define SHUTDOWN_REIPL_STR "reipl" -#define SHUTDOWN_DUMP_STR "dump" -#define SHUTDOWN_STOP_STR "stop" - -static char *shutdown_action_str (enum shutdown_action action) -{ -switch (action) { -case SHUTDOWN_REIPL : -return SHUTDOWN_REIPL_STR ; -case SHUTDOWN_DUMP : -return SHUTDOWN_DUMP_STR ; -case SHUTDOWN_STOP : -return SHUTDOWN_STOP_STR ; -default : -return NULL ; - } -} -static int diag308_set_works =0 ;static int reipl_capabilities =IPL_TYPE_UNKNOWN ;
@@ -140,8 +149,6 @@ static enum dump_method dump_method = DUstatic struct ipl_parameter_block *dump_block_fcp;static struct ipl_parameter_block *dump_block_ccw; -static enum shutdown_action on_panic_action =SHUTDOWN_STOP ; -static struct sclp_ipl_info sclp_ipl_info;int diag308 (unsigned long subcode,void *addr)
@@ -200,8 +207,8 @@ static ssize_t sys_##_prefix##_##_name## static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \const char *buf,size_t len) \ { \ -if (sscanf (buf, _fmt_in, _value) !=1 ) \ -return -EINVAL ; \ +strncpy (_value, buf,sizeof (_value) -1 ); \ +strstrip (_value); \return len; \ } \ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
@@ -240,33 +247,6 @@ static __init enum ipl_type get_ipl_typereturn IPL_TYPE_FCP ; } -void __init setup_ipl_info (void ) -{ - ipl_info.type =get_ipl_type (); -switch (ipl_info.type) { -case IPL_TYPE_CCW : - ipl_info.data.ccw.dev_id.devno = ipl_devno; - ipl_info.data.ccw.dev_id.ssid =0 ; -break ; -case IPL_TYPE_FCP : -case IPL_TYPE_FCP_DUMP : - ipl_info.data.fcp.dev_id.devno = -IPL_PARMBLOCK_START ->ipl_info.fcp.devno; - ipl_info.data.fcp.dev_id.ssid =0 ; - ipl_info.data.fcp.wwpn =IPL_PARMBLOCK_START ->ipl_info.fcp.wwpn; - ipl_info.data.fcp.lun =IPL_PARMBLOCK_START ->ipl_info.fcp.lun; -break ; -case IPL_TYPE_NSS : -strncpy (ipl_info.data.nss.name, kernel_nss_name, -sizeof (ipl_info.data.nss.name)); -break ; -case IPL_TYPE_UNKNOWN : -default : -/* We have no info to copy */ -break ; - } -} -struct ipl_info ipl_info;EXPORT_SYMBOL_GPL (ipl_info);
@@ -420,8 +400,77 @@ static struct attribute_group ipl_unknow static decl_subsys(ipl, NULL, NULL); +static int __init ipl_register_fcp_files (void ) +{ +int rc; + + rc =sysfs_create_group (&ipl_subsys.kobj, + &ipl_fcp_attr_group); +if (rc) + goto out; + rc =sysfs_create_bin_file (&ipl_subsys.kobj, + &ipl_parameter_attr); +if (rc) + goto out_ipl_parm; + rc =sysfs_create_bin_file (&ipl_subsys.kobj, + &ipl_scp_data_attr); +if (!rc) + goto out; + +sysfs_remove_bin_file (&ipl_subsys.kobj, &ipl_parameter_attr); + +out_ipl_parm: +sysfs_remove_group (&ipl_subsys.kobj, &ipl_fcp_attr_group); +out: +return rc; +} + +static void ipl_run (struct shutdown_trigger *trigger) +{ +diag308 (DIAG308_IPL ,NULL ); +if (MACHINE_IS_VM ) +__cpcmd ("IPL" ,NULL ,0 ,NULL ); +else if (ipl_info.type ==IPL_TYPE_CCW ) +reipl_ccw_dev (&ipl_info.data.ccw.dev_id); +} + +static int ipl_init (void ) +{ +int rc; + + rc =firmware_register (&ipl_subsys); +if (rc) + goto out; +switch (ipl_info.type) { +case IPL_TYPE_CCW : + rc =sysfs_create_group (&ipl_subsys.kobj, + &ipl_ccw_attr_group); +break ; +case IPL_TYPE_FCP : +case IPL_TYPE_FCP_DUMP : + rc =ipl_register_fcp_files (); +break ; +case IPL_TYPE_NSS : + rc =sysfs_create_group (&ipl_subsys.kobj, + &ipl_nss_attr_group); +break ; +default : + rc =sysfs_create_group (&ipl_subsys.kobj, + &ipl_unknown_attr_group); +break ; + } +out: +if (rc) +panic ("ipl_init failed: rc = %i\n" , rc); + +return 0 ; +} + +static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR , ipl_run, + ipl_init}; +/* -* reipl section +* reipl shutdown action: Reboot Linux on shutdown. */ /* FCP reipl device attributes */
@@ -592,135 +641,7 @@ static struct subsys_attribute reipl_typ static decl_subsys(reipl, NULL, NULL); -/* -* dump section -*/ - -/* FCP dump device attributes */ - -DEFINE_IPL_ATTR_RW (dump_fcp, wwpn,"0x%016llx\n" ,"%016llx\n" , - dump_block_fcp->ipl_info.fcp.wwpn); -DEFINE_IPL_ATTR_RW (dump_fcp, lun,"0x%016llx\n" ,"%016llx\n" , - dump_block_fcp->ipl_info.fcp.lun); -DEFINE_IPL_ATTR_RW (dump_fcp, bootprog,"%lld\n" ,"%lld\n" , - dump_block_fcp->ipl_info.fcp.bootprog); -DEFINE_IPL_ATTR_RW (dump_fcp, br_lba,"%lld\n" ,"%lld\n" , - dump_block_fcp->ipl_info.fcp.br_lba); -DEFINE_IPL_ATTR_RW (dump_fcp, device,"0.0.%04llx\n" ,"0.0.%llx\n" , - dump_block_fcp->ipl_info.fcp.devno); - -static struct attribute *dump_fcp_attrs[] = { - &sys_dump_fcp_device_attr.attr, - &sys_dump_fcp_wwpn_attr.attr, - &sys_dump_fcp_lun_attr.attr, - &sys_dump_fcp_bootprog_attr.attr, - &sys_dump_fcp_br_lba_attr.attr, -NULL , -}; - -static struct attribute_group dump_fcp_attr_group = { - .name =IPL_FCP_STR , - .attrs = dump_fcp_attrs, -}; - -/* CCW dump device attributes */ - -DEFINE_IPL_ATTR_RW (dump_ccw, device,"0.0.%04llx\n" ,"0.0.%llx\n" , - dump_block_ccw->ipl_info.ccw.devno); - -static struct attribute *dump_ccw_attrs[] = { - &sys_dump_ccw_device_attr.attr, -NULL , -}; - -static struct attribute_group dump_ccw_attr_group = { - .name =IPL_CCW_STR , - .attrs = dump_ccw_attrs, -}; - -/* dump type */ - -static int dump_set_type (enum dump_type type) -{ -if (!(dump_capabilities & type)) -return -EINVAL ; -switch (type) { -case DUMP_TYPE_CCW : -if (MACHINE_IS_VM ) - dump_method =DUMP_METHOD_CCW_VM ; -else if (diag308_set_works) - dump_method =DUMP_METHOD_CCW_DIAG ; -else - dump_method =DUMP_METHOD_CCW_CIO ; -break ; -case DUMP_TYPE_FCP : - dump_method =DUMP_METHOD_FCP_DIAG ; -break ; -default : - dump_method =DUMP_METHOD_NONE ; - } - dump_type = type; -return 0 ; -} - -static ssize_t dump_type_show (struct kset *kset,char *page) -{ -return sprintf (page,"%s\n" ,dump_type_str (dump_type)); -} - -static ssize_t dump_type_store (struct kset *kset,const char *buf, -size_t len) -{ -int rc = -EINVAL ; - -if (strncmp (buf,DUMP_NONE_STR ,strlen (DUMP_NONE_STR )) ==0 ) - rc =dump_set_type (DUMP_TYPE_NONE ); -else if (strncmp (buf,DUMP_CCW_STR ,strlen (DUMP_CCW_STR )) ==0 ) - rc =dump_set_type (DUMP_TYPE_CCW ); -else if (strncmp (buf,DUMP_FCP_STR ,strlen (DUMP_FCP_STR )) ==0 ) - rc =dump_set_type (DUMP_TYPE_FCP ); -return (rc !=0 ) ? rc : len; -} - -static struct subsys_attribute dump_type_attr = -__ATTR (dump_type,0644 , dump_type_show, dump_type_store); - -static decl_subsys(dump, NULL, NULL); - -/* -* Shutdown actions section -*/ - -static decl_subsys(shutdown_actions, NULL, NULL); - -/* on panic */ - -static ssize_t on_panic_show (struct kset *kset,char *page) -{ -return sprintf (page,"%s\n" ,shutdown_action_str (on_panic_action)); -} - -static ssize_t on_panic_store (struct kset *kset,const char *buf, -size_t len) -{ -if (strncmp (buf,SHUTDOWN_REIPL_STR ,strlen (SHUTDOWN_REIPL_STR )) ==0 ) - on_panic_action =SHUTDOWN_REIPL ; -else if (strncmp (buf,SHUTDOWN_DUMP_STR , -strlen (SHUTDOWN_DUMP_STR )) ==0 ) - on_panic_action =SHUTDOWN_DUMP ; -else if (strncmp (buf,SHUTDOWN_STOP_STR , -strlen (SHUTDOWN_STOP_STR )) ==0 ) - on_panic_action =SHUTDOWN_STOP ; -else -return -EINVAL ; - -return len; -} - -static struct subsys_attribute on_panic_attr = -__ATTR (on_panic,0644 , on_panic_show, on_panic_store); - -void do_reipl (void ) +void reipl_run (struct shutdown_trigger *trigger) {struct ccw_dev_id devid;static char buf[100 ];
@@ -771,110 +692,18 @@ void do_reipl(void)default :break ; } -signal_processor (smp_processor_id (), sigp_stop_and_store_status); } -static void do_dump (void ) +static void __init reipl_probe (void ) { -struct ccw_dev_id devid; -static char buf[100 ]; +void *buffer; -switch (dump_method) { -case DUMP_METHOD_CCW_CIO : -smp_send_stop (); - devid.devno = dump_block_ccw->ipl_info.ccw.devno; - devid.ssid =0 ; -reipl_ccw_dev (&devid); -break ; -case DUMP_METHOD_CCW_VM : -smp_send_stop (); -sprintf (buf,"STORE STATUS" ); -__cpcmd (buf,NULL ,0 ,NULL ); -sprintf (buf,"IPL %X" , dump_block_ccw->ipl_info.ccw.devno); -__cpcmd (buf,NULL ,0 ,NULL ); -break ; -case DUMP_METHOD_CCW_DIAG : -diag308 (DIAG308_SET , dump_block_ccw); -diag308 (DIAG308_DUMP ,NULL ); -break ; -case DUMP_METHOD_FCP_DIAG : -diag308 (DIAG308_SET , dump_block_fcp); -diag308 (DIAG308_DUMP ,NULL ); -break ; -case DUMP_METHOD_NONE : -default : + buffer = (void *)get_zeroed_page (GFP_KERNEL ); +if (!buffer)return ; - } -printk (KERN_EMERG "Dump failed!\n" ); -} - -/* init functions */ - -static int __init ipl_register_fcp_files (void ) -{ -int rc; - - rc =sysfs_create_group (&ipl_subsys.kobj, - &ipl_fcp_attr_group); -if (rc) - goto out; - rc =sysfs_create_bin_file (&ipl_subsys.kobj, - &ipl_parameter_attr); -if (rc) - goto out_ipl_parm; - rc =sysfs_create_bin_file (&ipl_subsys.kobj, - &ipl_scp_data_attr); -if (!rc) - goto out; - -sysfs_remove_bin_file (&ipl_subsys.kobj, &ipl_parameter_attr); - -out_ipl_parm: -sysfs_remove_group (&ipl_subsys.kobj, &ipl_fcp_attr_group); -out: -return rc; -} - -static int __init ipl_init (void ) -{ -int rc; - - rc =firmware_register (&ipl_subsys); -if (rc) -return rc; -switch (ipl_info.type) { -case IPL_TYPE_CCW : - rc =sysfs_create_group (&ipl_subsys.kobj, - &ipl_ccw_attr_group); -break ; -case IPL_TYPE_FCP : -case IPL_TYPE_FCP_DUMP : - rc =ipl_register_fcp_files (); -break ; -case IPL_TYPE_NSS : - rc =sysfs_create_group (&ipl_subsys.kobj, - &ipl_nss_attr_group); -break ; -default : - rc =sysfs_create_group (&ipl_subsys.kobj, - &ipl_unknown_attr_group); -break ; - } -if (rc) -firmware_unregister (&ipl_subsys); -return rc; -} - -static void __init reipl_probe (void ) -{ -void *buffer; - - buffer = (void *)get_zeroed_page (GFP_KERNEL ); -if (!buffer) -return ; -if (diag308 (DIAG308_STORE , buffer) ==DIAG308_RC_OK ) - diag308_set_works =1 ; -free_page ((unsigned long )buffer); +if (diag308 (DIAG308_STORE , buffer) ==DIAG308_RC_OK ) + diag308_set_works =1 ; +free_page ((unsigned long )buffer); }static int __init reipl_nss_init (void )
@@ -954,7 +783,7 @@ static int __init reipl_fcp_init(void)return 0 ; } -static int __init reipl_init (void ) +static int reipl_init (void ) {int rc;
@@ -981,6 +810,136 @@ static int __init reipl_init(void)return 0 ; } +static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR , + reipl_run, reipl_init}; + +/* +* dump shutdown action: Dump Linux on shutdown. +*/ + +/* FCP dump device attributes */ + +DEFINE_IPL_ATTR_RW (dump_fcp, wwpn,"0x%016llx\n" ,"%016llx\n" , + dump_block_fcp->ipl_info.fcp.wwpn); +DEFINE_IPL_ATTR_RW (dump_fcp, lun,"0x%016llx\n" ,"%016llx\n" , + dump_block_fcp->ipl_info.fcp.lun); +DEFINE_IPL_ATTR_RW (dump_fcp, bootprog,"%lld\n" ,"%lld\n" , + dump_block_fcp->ipl_info.fcp.bootprog); +DEFINE_IPL_ATTR_RW (dump_fcp, br_lba,"%lld\n" ,"%lld\n" , + dump_block_fcp->ipl_info.fcp.br_lba); +DEFINE_IPL_ATTR_RW (dump_fcp, device,"0.0.%04llx\n" ,"0.0.%llx\n" , + dump_block_fcp->ipl_info.fcp.devno); + +static struct attribute *dump_fcp_attrs[] = { + &sys_dump_fcp_device_attr.attr, + &sys_dump_fcp_wwpn_attr.attr, + &sys_dump_fcp_lun_attr.attr, + &sys_dump_fcp_bootprog_attr.attr, + &sys_dump_fcp_br_lba_attr.attr, +NULL , +}; + +static struct attribute_group dump_fcp_attr_group = { + .name =IPL_FCP_STR , + .attrs = dump_fcp_attrs, +}; + +/* CCW dump device attributes */ + +DEFINE_IPL_ATTR_RW (dump_ccw, device,"0.0.%04llx\n" ,"0.0.%llx\n" , + dump_block_ccw->ipl_info.ccw.devno); + +static struct attribute *dump_ccw_attrs[] = { + &sys_dump_ccw_device_attr.attr, +NULL , +}; + +static struct attribute_group dump_ccw_attr_group = { + .name =IPL_CCW_STR , + .attrs = dump_ccw_attrs, +}; + +/* dump type */ + +static int dump_set_type (enum dump_type type) +{ +if (!(dump_capabilities & type)) +return -EINVAL ; +switch (type) { +case DUMP_TYPE_CCW : +if (MACHINE_IS_VM ) + dump_method =DUMP_METHOD_CCW_VM ; +else + dump_method =DUMP_METHOD_CCW_CIO ; +break ; +case DUMP_TYPE_FCP : + dump_method =DUMP_METHOD_FCP_DIAG ; +break ; +default : + dump_method =DUMP_METHOD_NONE ; + } + dump_type = type; +return 0 ; +} + +static ssize_t dump_type_show (struct kset *kset,char *page) +{ +return sprintf (page,"%s\n" ,dump_type_str (dump_type)); +} + +static ssize_t dump_type_store (struct kset *kset,const char *buf, +size_t len) +{ +int rc = -EINVAL ; + +if (strncmp (buf,DUMP_NONE_STR ,strlen (DUMP_NONE_STR )) ==0 ) + rc =dump_set_type (DUMP_TYPE_NONE ); +else if (strncmp (buf,DUMP_CCW_STR ,strlen (DUMP_CCW_STR )) ==0 ) + rc =dump_set_type (DUMP_TYPE_CCW ); +else if (strncmp (buf,DUMP_FCP_STR ,strlen (DUMP_FCP_STR )) ==0 ) + rc =dump_set_type (DUMP_TYPE_FCP ); +return (rc !=0 ) ? rc : len; +} + +static struct subsys_attribute dump_type_attr = +__ATTR (dump_type,0644 , dump_type_show, dump_type_store); + +static decl_subsys(dump, NULL, NULL); + +static void dump_run (struct shutdown_trigger *trigger) +{ +struct ccw_dev_id devid; +static char buf[100 ]; + +switch (dump_method) { +case DUMP_METHOD_CCW_CIO : +smp_send_stop (); + devid.devno = dump_block_ccw->ipl_info.ccw.devno; + devid.ssid =0 ; +reipl_ccw_dev (&devid); +break ; +case DUMP_METHOD_CCW_VM : +smp_send_stop (); +sprintf (buf,"STORE STATUS" ); +__cpcmd (buf,NULL ,0 ,NULL ); +sprintf (buf,"IPL %X" , dump_block_ccw->ipl_info.ccw.devno); +__cpcmd (buf,NULL ,0 ,NULL ); +break ; +case DUMP_METHOD_CCW_DIAG : +diag308 (DIAG308_SET , dump_block_ccw); +diag308 (DIAG308_DUMP ,NULL ); +break ; +case DUMP_METHOD_FCP_DIAG : +diag308 (DIAG308_SET , dump_block_fcp); +diag308 (DIAG308_DUMP ,NULL ); +break ; +case DUMP_METHOD_NONE : +default : +return ; + } +printk (KERN_EMERG "Dump failed!\n" ); +} +static int __init dump_ccw_init (void ) {int rc;
@@ -1026,24 +985,7 @@ static int __init dump_fcp_init(void)return 0 ; } -#define SHUTDOWN_ON_PANIC_PRIO 0 - -static int shutdown_on_panic_notify (struct notifier_block *self, -unsigned long event,void *data) -{ -if (on_panic_action ==SHUTDOWN_DUMP ) -do_dump (); -else if (on_panic_action ==SHUTDOWN_REIPL ) -do_reipl (); -return NOTIFY_OK ; -} - -static struct notifier_block shutdown_on_panic_nb = { - .notifier_call = shutdown_on_panic_notify, - .priority =SHUTDOWN_ON_PANIC_PRIO -}; - -static int __init dump_init (void ) +static int dump_init (void ) {int rc;
@@ -1065,46 +1007,362 @@ static int __init dump_init(void)return 0 ; } -static int __init shutdown_actions_init (void ) +static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR , + dump_run, dump_init}; + +/* +* vmcmd shutdown action: Trigger vm command on shutdown. +*/ + +static char vmcmd_on_reboot[128 ]; +static char vmcmd_on_panic[128 ]; +static char vmcmd_on_halt[128 ]; +static char vmcmd_on_poff[128 ]; + +DEFINE_IPL_ATTR_STR_RW (vmcmd, on_reboot,"%s\n" ,"%s\n" , vmcmd_on_reboot); +DEFINE_IPL_ATTR_STR_RW (vmcmd, on_panic,"%s\n" ,"%s\n" , vmcmd_on_panic); +DEFINE_IPL_ATTR_STR_RW (vmcmd, on_halt,"%s\n" ,"%s\n" , vmcmd_on_halt); +DEFINE_IPL_ATTR_STR_RW (vmcmd, on_poff,"%s\n" ,"%s\n" , vmcmd_on_poff); + +static struct attribute *vmcmd_attrs[] = { + &sys_vmcmd_on_reboot_attr.attr, + &sys_vmcmd_on_panic_attr.attr, + &sys_vmcmd_on_halt_attr.attr, + &sys_vmcmd_on_poff_attr.attr, +NULL , +}; + +static struct attribute_group vmcmd_attr_group = { + .attrs = vmcmd_attrs, +}; + +static decl_subsys(vmcmd, NULL, NULL); + +static void vmcmd_run (struct shutdown_trigger *trigger) +{ +char *cmd, *next_cmd; + +if (strcmp (trigger->name,ON_REIPL_STR ) ==0 ) + cmd = vmcmd_on_reboot; +else if (strcmp (trigger->name,ON_PANIC_STR ) ==0 ) + cmd = vmcmd_on_panic; +else if (strcmp (trigger->name,ON_HALT_STR ) ==0 ) + cmd = vmcmd_on_halt; +else if (strcmp (trigger->name,ON_POFF_STR ) ==0 ) + cmd = vmcmd_on_poff; +else +return ; + +if (strlen (cmd) ==0 ) +return ; +do { + next_cmd =strchr (cmd,'\n' ); +if (next_cmd) { + next_cmd[0 ] =0 ; + next_cmd +=1 ; + } +__cpcmd (cmd,NULL ,0 ,NULL ); + cmd = next_cmd; + }while (cmd !=NULL ); +} + +static int vmcmd_init (void ) {int rc; - rc =firmware_register (&shutdown_actions_subsys); +if (!MACHINE_IS_VM ) +return -ENOTSUPP ; + rc =firmware_register (&vmcmd_subsys);if (rc)return rc; - rc =subsys_create_file (&shutdown_actions_subsys, &on_panic_attr); -if (rc) { -firmware_unregister (&shutdown_actions_subsys); -return rc; +return sysfs_create_group (&vmcmd_subsys.kobj, &vmcmd_attr_group); +} + +static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR , + vmcmd_run, vmcmd_init}; + +/* +* stop shutdown action: Stop Linux on shutdown. +*/ + +static void stop_run (struct shutdown_trigger *trigger) +{ +signal_processor (smp_processor_id (), sigp_stop_and_store_status); +for (;;); +} + +static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR , + stop_run,NULL }; + +/* action list */ + +static struct shutdown_action *shutdown_actions_list[] = { + &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action}; +#define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *)) + +/* +* Trigger section +*/ + +static decl_subsys(shutdown_actions, NULL, NULL); + +static int set_trigger (const char *buf,struct shutdown_trigger *trigger, +size_t len) +{ +int i; + +for (i =0 ; i <SHUTDOWN_ACTIONS_COUNT ; i++) { +if (!shutdown_actions_list[i]) +continue ; +if (strncmp (buf, shutdown_actions_list[i]->name, +strlen (shutdown_actions_list[i]->name)) ==0 ) { + trigger->action = shutdown_actions_list[i]; +return len; + } } -atomic_notifier_chain_register (&panic_notifier_list, - &shutdown_on_panic_nb); -return 0 ; +return -EINVAL ; } -static int __init s390_ipl_init (void ) +/* on reipl */ + +static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR , + &reipl_action}; + +static ssize_t on_reboot_show (struct kset *kset,char *page) { -int rc; +return sprintf (page,"%s\n" , on_reboot_trigger.action->name); +} + +static ssize_t on_reboot_store (struct kset *kset,const char *buf,size_t len) +{ +return set_trigger (buf, &on_reboot_trigger, len); +} + +static struct subsys_attribute on_reboot_attr = +__ATTR (on_reboot,0644 , on_reboot_show, on_reboot_store); + +static void do_machine_restart (char *__unused) +{ +smp_send_stop (); + on_reboot_trigger.action->fn (&on_reboot_trigger); +reipl_run (NULL ); +} +void (*_machine_restart)(char *command) = do_machine_restart; + +/* on panic */ + +static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR , &stop_action}; + +static ssize_t on_panic_show (struct kset *kset,char *page) +{ +return sprintf (page,"%s\n" , on_panic_trigger.action->name); +} + +static ssize_t on_panic_store (struct kset *kset,const char *buf, +size_t len) +{ +return set_trigger (buf, &on_panic_trigger, len); +} + +static struct subsys_attribute on_panic_attr = +__ATTR (on_panic,0644 , on_panic_show, on_panic_store); + +static void do_panic (void ) +{ + on_panic_trigger.action->fn (&on_panic_trigger); +stop_run (&on_panic_trigger); +} + +/* on halt */ + +static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR , &stop_action}; + +static ssize_t on_halt_show (struct kset *kset,char *page) +{ +return sprintf (page,"%s\n" , on_halt_trigger.action->name); +} + +static ssize_t on_halt_store (struct kset *kset,const char *buf,size_t len) +{ +return set_trigger (buf, &on_halt_trigger, len); +} + +static struct subsys_attribute on_halt_attr = +__ATTR (on_halt,0644 , on_halt_show, on_halt_store); -sclp_get_ipl_info (&sclp_ipl_info); + +static void do_machine_halt (void ) +{ +smp_send_stop (); + on_halt_trigger.action->fn (&on_halt_trigger); +stop_run (&on_halt_trigger); +} +void (*_machine_halt)(void ) = do_machine_halt; + +/* on power off */ + +static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR , &stop_action}; + +static ssize_t on_poff_show (struct kset *kset,char *page) +{ +return sprintf (page,"%s\n" , on_poff_trigger.action->name); +} + +static ssize_t on_poff_store (struct kset *kset,const char *buf,size_t len) +{ +return set_trigger (buf, &on_poff_trigger, len); +} + +static struct subsys_attribute on_poff_attr = +__ATTR (on_poff,0644 , on_poff_show, on_poff_store); + + +static void do_machine_power_off (void ) +{ +smp_send_stop (); + on_poff_trigger.action->fn (&on_poff_trigger); +stop_run (&on_poff_trigger); +} +void (*_machine_power_off)(void ) = do_machine_power_off; + +static void __init shutdown_triggers_init (void ) +{ +if (firmware_register (&shutdown_actions_subsys)) + goto fail; +if (subsys_create_file (&shutdown_actions_subsys, &on_reboot_attr)) + goto fail; +if (subsys_create_file (&shutdown_actions_subsys, &on_panic_attr)) + goto fail; +if (subsys_create_file (&shutdown_actions_subsys, &on_halt_attr)) + goto fail; +if (subsys_create_file (&shutdown_actions_subsys, &on_poff_attr)) + goto fail; + +return ; +fail: +panic ("shutdown_triggers_init failed\n" ); +} + +static void __init shutdown_actions_init (void ) +{ +int i; + +for (i =0 ; i <SHUTDOWN_ACTIONS_COUNT ; i++) { +if (!shutdown_actions_list[i]->init) +continue ; +if (shutdown_actions_list[i]->init ()) + shutdown_actions_list[i] =NULL ; + } +} + +static int __init s390_ipl_init (void ) +{reipl_probe (); - rc =ipl_init (); -if (rc) -return rc; - rc =reipl_init (); -if (rc) -return rc; - rc =dump_init (); -if (rc) -return rc; - rc =shutdown_actions_init (); -if (rc) -return rc; +shutdown_actions_init (); +shutdown_triggers_init ();return 0 ; }__initcall (s390_ipl_init); +static void __init strncpy_skip_quote (char *dst,char *src,int n) +{ +int sx, dx; + + dx =0 ; +for (sx =0 ; src[sx] !=0 ; sx++) { +if (src[sx] =='"' ) +continue ; + dst[dx++] = src[sx]; +if (dx >= n) +break ; + } +} + +static int __init vmcmd_on_reboot_setup (char *str) +{ +if (!MACHINE_IS_VM ) +return 1 ; +strncpy_skip_quote (vmcmd_on_reboot, str,127 ); + vmcmd_on_reboot[127 ] =0 ; + on_panic_trigger.action = &vmcmd_action; +return 1 ; +} +__setup ("vmreboot=" , vmcmd_on_reboot_setup); + +static int __init vmcmd_on_panic_setup (char *str) +{ +if (!MACHINE_IS_VM ) +return 1 ; +strncpy_skip_quote (vmcmd_on_panic, str,127 ); + vmcmd_on_panic[127 ] =0 ; + on_panic_trigger.action = &vmcmd_action; +return 1 ; +} +__setup ("vmpanic=" , vmcmd_on_panic_setup); + +static int __init vmcmd_on_halt_setup (char *str) +{ +if (!MACHINE_IS_VM ) +return 1 ; +strncpy_skip_quote (vmcmd_on_halt, str,127 ); + vmcmd_on_halt[127 ] =0 ; + on_halt_trigger.action = &vmcmd_action; +return 1 ; +} +__setup ("vmhalt=" , vmcmd_on_halt_setup); + +static int __init vmcmd_on_poff_setup (char *str) +{ +if (!MACHINE_IS_VM ) +return 1 ; +strncpy_skip_quote (vmcmd_on_poff, str,127 ); + vmcmd_on_poff[127 ] =0 ; + on_poff_trigger.action = &vmcmd_action; +return 1 ; +} +__setup ("vmpoff=" , vmcmd_on_poff_setup); + +static int on_panic_notify (struct notifier_block *self, +unsigned long event,void *data) +{ +do_panic (); +return NOTIFY_OK ; +} + +static struct notifier_block on_panic_nb = { + .notifier_call = on_panic_notify, + .priority =0 , +}; + +void __init setup_ipl (void ) +{ + ipl_info.type =get_ipl_type (); +switch (ipl_info.type) { +case IPL_TYPE_CCW : + ipl_info.data.ccw.dev_id.devno = ipl_devno; + ipl_info.data.ccw.dev_id.ssid =0 ; +break ; +case IPL_TYPE_FCP : +case IPL_TYPE_FCP_DUMP : + ipl_info.data.fcp.dev_id.devno = +IPL_PARMBLOCK_START ->ipl_info.fcp.devno; + ipl_info.data.fcp.dev_id.ssid =0 ; + ipl_info.data.fcp.wwpn =IPL_PARMBLOCK_START ->ipl_info.fcp.wwpn; + ipl_info.data.fcp.lun =IPL_PARMBLOCK_START ->ipl_info.fcp.lun; +break ; +case IPL_TYPE_NSS : +strncpy (ipl_info.data.nss.name, kernel_nss_name, +sizeof (ipl_info.data.nss.name)); +break ; +case IPL_TYPE_UNKNOWN : +default : +/* We have no info to copy */ +break ; + } +atomic_notifier_chain_register (&panic_notifier_list, &on_panic_nb); +} +void __init ipl_save_parameters (void ) {struct cio_iplinfo iplinfo;
@@ -1185,3 +1443,4 @@ void s390_reset_system(void)do_reset_calls (); } +
arch/s390/kernel/setup.c +1 -102
121 lines not on this page · raw message
arch/s390/kernel/smp.c +0 -27
@@ -234,33 +234,6 @@ void smp_send_stop(void) }/* -* Reboot, halt and power_off routines for SMP. -*/ -void machine_restart_smp (char *__unused) -{ -smp_send_stop (); -do_reipl (); -} - -void machine_halt_smp (void ) -{ -smp_send_stop (); -if (MACHINE_IS_VM &&strlen (vmhalt_cmd) >0 ) -__cpcmd (vmhalt_cmd,NULL ,0 ,NULL ); -signal_processor (smp_processor_id (), sigp_stop_and_store_status); -for (;;); -} - -void machine_power_off_smp (void ) -{ -smp_send_stop (); -if (MACHINE_IS_VM &&strlen (vmpoff_cmd) >0 ) -__cpcmd (vmpoff_cmd,NULL ,0 ,NULL ); -signal_processor (smp_processor_id (), sigp_stop_and_store_status); -for (;;); -} - -/* * This is the main routine where commands issued by other * cpus are handled. */
include/asm-s390/ipl.h +3 -1
@@ -83,6 +83,8 @@ extern u32 dump_prefix_page;extern unsigned int zfcpdump_prefix_array[];extern void do_reipl (void ); +extern void do_halt (void ); +extern void do_poff (void );extern void ipl_save_parameters (void );enum {
@@ -118,7 +120,7 @@ struct ipl_info };extern struct ipl_info ipl_info; -extern void setup_ipl_info (void ); +extern void setup_ipl (void );/* * DIAG 308 support
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 34/47 Load disabled wait psw instead of stopping cpu on halt.
In reply to Martin SchwidefskyFrom: Michael Holzheu <[email protected]>
---
arch/s390/kernel/ipl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
arch/s390/kernel/ipl.c +6 -2
@@ -1087,8 +1087,12 @@ static struct shutdown_action vmcmd_actistatic void stop_run (struct shutdown_trigger *trigger) { -signal_processor (smp_processor_id (), sigp_stop_and_store_status); -for (;;); +if (strcmp (trigger->name,ON_PANIC_STR ) ==0 ) +disabled_wait ((unsigned long )__builtin_return_address (0 )); +else { +signal_processor (smp_processor_id (), sigp_stop); +for (;;); + } }static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR ,
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 35/47 use LIST_HEAD instead of LIST_HEAD_INIT
In reply to Martin SchwidefskyFrom: Denis Cheng <[email protected]>
single list_head variable initialized with LIST_HEAD_INIT could almost always can be replaced with LIST_HEAD declaration, this shrinks the code and looks better.
---
arch/s390/mm/extmem.c | 2 +- drivers/s390/block/dcssblk.c | 2 +- drivers/s390/char/raw3270.c | 4 ++-- drivers/s390/char/tape_core.c | 2 +- drivers/s390/net/netiucv.c | 3 +-- drivers/s390/net/smsgiucv.c | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-)
arch/s390/mm/extmem.c +1 -1
@@ -83,7 +83,7 @@ struct dcss_segment { };static DEFINE_MUTEX (dcss_lock); -static struct list_head dcss_list =LIST_HEAD_INIT (dcss_list); +static LIST_HEAD (dcss_list);static char *segtype_string[] = {"SW" ,"EW" ,"SR" ,"ER" ,"SN" ,"EN" ,"SC" ,"EW/EN-MIXED" };
drivers/s390/block/dcssblk.c +1 -1
@@ -82,7 +82,7 @@ struct dcssblk_dev_info {struct request_queue *dcssblk_queue; }; -static struct list_head dcssblk_devices =LIST_HEAD_INIT (dcssblk_devices); +static LIST_HEAD (dcssblk_devices);static struct rw_semaphore dcssblk_devices_sem;/*
drivers/s390/char/raw3270.c +2 -2
@@ -66,7 +66,7 @@ struct raw3270 {static DEFINE_MUTEX (raw3270_mutex);/* List of 3270 devices. */ -static struct list_head raw3270_devices =LIST_HEAD_INIT (raw3270_devices); +static LIST_HEAD (raw3270_devices);/* * Flag to indicate if the driver has been registered. Some operations
@@ -1210,7 +1210,7 @@ struct raw3270_notifier {void (*notifier)(int ,int ); }; -static struct list_head raw3270_notifier =LIST_HEAD_INIT (raw3270_notifier); +static LIST_HEAD (raw3270_notifier);int raw3270_register_notifier (void (*notifier)(int ,int )) {
drivers/s390/char/tape_core.c +1 -1
@@ -37,7 +37,7 @@ static void tape_long_busy_timeout(unsig* we can assign the devices to minor numbers of the same major * The list is protected by the rwlock */ -static struct list_head tape_device_list =LIST_HEAD_INIT (tape_device_list); +static LIST_HEAD (tape_device_list);static DEFINE_RWLOCK (tape_device_lock);/*
drivers/s390/net/netiucv.c +1 -2
@@ -198,8 +198,7 @@ struct iucv_connection {/** * Linked list of all connection structs. */ -static struct list_head iucv_connection_list = -LIST_HEAD_INIT (iucv_connection_list); +static LIST_HEAD (iucv_connection_list);static DEFINE_RWLOCK (iucv_connection_rwlock);/**
drivers/s390/net/smsgiucv.c +1 -1
@@ -42,7 +42,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCstatic struct iucv_path *smsg_path;static DEFINE_SPINLOCK (smsg_list_lock); -static struct list_head smsg_list =LIST_HEAD_INIT (smsg_list); +static LIST_HEAD (smsg_list);static int smsg_path_pending (struct iucv_path *,u8 ipvmid[8 ],u8 ipuser[16 ]);static void smsg_message_pending (struct iucv_path *,struct iucv_message *);
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 36/47 Allocate and free cpu lowcores and stacks when needed/possible.
In reply to Martin SchwidefskyFrom: Heiko Carstens <[email protected]>
No need to preallocate the per cpu lowcores and stacks. Savings are 28-32k per offline cpu.
---
arch/s390/kernel/smp.c | 106 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 34 deletions(-)
arch/s390/kernel/smp.c +72 -34
@@ -589,8 +589,72 @@ static void __init smp_create_idle(unsigspin_lock_init (&(&per_cpu (s390_idle, cpu))->lock); } +static int __cpuinit smp_alloc_lowcore (int cpu) +{ +unsigned long async_stack, panic_stack; +struct _lowcore *lowcore; +int lc_order; + + lc_order =sizeof (long ) ==8 ?1 :0 ; + lowcore = (void *)__get_free_pages (GFP_KERNEL |GFP_DMA , lc_order); +if (!lowcore) +return -ENOMEM ; + async_stack =__get_free_pages (GFP_KERNEL ,ASYNC_ORDER ); +if (!async_stack) + goto out_async_stack; + panic_stack =__get_free_page (GFP_KERNEL ); +if (!panic_stack) + goto out_panic_stack; + + *lowcore = S390_lowcore; + lowcore->async_stack = async_stack +ASYNC_SIZE ; + lowcore->panic_stack = panic_stack +PAGE_SIZE ; + +#ifndef CONFIG_64BIT +if (MACHINE_HAS_IEEE ) { +unsigned long save_area; + + save_area =get_zeroed_page (GFP_KERNEL ); +if (!save_area) + goto out_save_area; + lowcore->extended_save_area_addr = (u32 ) save_area; + } +#endif + lowcore_ptr[cpu] = lowcore; +return 0 ; + +#ifndef CONFIG_64BIT +out_save_area: +free_page (panic_stack); +#endif +out_panic_stack: +free_pages (async_stack,ASYNC_ORDER ); +out_async_stack: +free_pages ((unsigned long ) lowcore, lc_order); +return -ENOMEM ; +} + +#ifdef CONFIG_HOTPLUG_CPU +static void smp_free_lowcore (int cpu) +{ +struct _lowcore *lowcore; +int lc_order; + + lc_order =sizeof (long ) ==8 ?1 :0 ; + lowcore = lowcore_ptr[cpu]; +#ifndef CONFIG_64BIT +if (MACHINE_HAS_IEEE ) +free_page ((unsigned long ) lowcore->extended_save_area_addr); +#endif +free_page (lowcore->panic_stack -PAGE_SIZE ); +free_pages (lowcore->async_stack -ASYNC_SIZE ,ASYNC_ORDER ); +free_pages ((unsigned long ) lowcore, lc_order); + lowcore_ptr[cpu] =NULL ; +} +#endif /* CONFIG_HOTPLUG_CPU */ +/* Upping and downing of CPUs */ -int __cpu_up (unsigned int cpu) +int __cpuinit __cpu_up (unsigned int cpu) {struct task_struct *idle;struct _lowcore *cpu_lowcore;
@@ -599,6 +663,8 @@ int __cpu_up(unsigned int cpu)if (smp_cpu_state[cpu] !=CPU_STATE_CONFIGURED )return -EIO ; +if (smp_alloc_lowcore (cpu)) +return -ENOMEM ; ccode =signal_processor_p ((__u32 )(unsigned long )(lowcore_ptr[cpu]), cpu, sigp_set_prefix);
@@ -613,6 +679,7 @@ int __cpu_up(unsigned int cpu) cpu_lowcore = lowcore_ptr[cpu]; cpu_lowcore->kernel_stack = (unsigned long )task_stack_page (idle) +THREAD_SIZE ; + cpu_lowcore->thread_info = (unsigned long )task_thread_info (idle); sf = (struct stack_frame *) (cpu_lowcore->kernel_stack -sizeof (struct pt_regs ) -sizeof (struct stack_frame ));
@@ -626,6 +693,8 @@ int __cpu_up(unsigned int cpu) cpu_lowcore->percpu_offset = __per_cpu_offset[cpu]; cpu_lowcore->current_task = (unsigned long ) idle; cpu_lowcore->cpu_data.cpu_nr = cpu; + cpu_lowcore->softirq_pending =0 ; + cpu_lowcore->ext_call_fast =0 ;eieio ();while (signal_processor (cpu, sigp_restart) == sigp_busy)
@@ -686,6 +755,7 @@ void __cpu_die(unsigned int cpu)/* Wait until target cpu is down */ while (!smp_cpu_not_running (cpu))cpu_relax (); +smp_free_lowcore (cpu);printk (KERN_INFO "Processor %d spun down\n" , cpu); }
@@ -699,15 +769,9 @@ void cpu_die(void)#endif /* CONFIG_HOTPLUG_CPU */ -/* -* Cycle through the processors and setup structures. -*/ -void __init smp_prepare_cpus (unsigned int max_cpus) { -unsigned long stack;unsigned int cpu; -int i;smp_detect_cpus ();
@@ -715,35 +779,9 @@ void __init smp_prepare_cpus(unsigned inif (register_external_interrupt (0x1201 , do_ext_call_interrupt) !=0 )panic ("Couldn't request external interrupt 0x1201" );memset (lowcore_ptr,0 ,sizeof (lowcore_ptr)); -/* -* Initialize prefix pages and stacks for all possible cpus -*/ print_cpu_info (&S390_lowcore.cpu_data); +smp_alloc_lowcore (smp_processor_id ()); -for_each_possible_cpu (i) { - lowcore_ptr[i] = (struct _lowcore *) -__get_free_pages (GFP_KERNEL |GFP_DMA , -sizeof (void *) ==8 ?1 :0 ); - stack =__get_free_pages (GFP_KERNEL ,ASYNC_ORDER ); -if (!lowcore_ptr[i] || !stack) -panic ("smp_boot_cpus failed to allocate memory\n" ); - - *(lowcore_ptr[i]) = S390_lowcore; - lowcore_ptr[i]->async_stack = stack +ASYNC_SIZE ; - stack =__get_free_pages (GFP_KERNEL ,0 ); -if (!stack) -panic ("smp_boot_cpus failed to allocate memory\n" ); - lowcore_ptr[i]->panic_stack = stack +PAGE_SIZE ; -#ifndef CONFIG_64BIT -if (MACHINE_HAS_IEEE ) { - lowcore_ptr[i]->extended_save_area_addr = - (__u32 )__get_free_pages (GFP_KERNEL ,0 ); -if (!lowcore_ptr[i]->extended_save_area_addr) -panic ("smp_boot_cpus failed to " -"allocate memory\n" ); - } -#endif - }#ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE )ctl_set_bit (14 ,29 );/* enable extended save area */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 37/47 Initialize sclp_ipl_info
In reply to Martin SchwidefskyFrom: Michael Holzheu <[email protected]>
The sclp ipl information has not been initialized. Therefore the ipl loadparm and the "has_dump" flag have not been set correctly.
---
arch/s390/kernel/ipl.c | 1 + 1 file changed, 1 insertion(+)
arch/s390/kernel/ipl.c +1 -0
@@ -1262,6 +1262,7 @@ static void __init shutdown_actions_initstatic int __init s390_ipl_init (void ) {reipl_probe (); +sclp_get_ipl_info (&sclp_ipl_info);shutdown_actions_init ();shutdown_triggers_init ();return 0 ;
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 38/47 vmemmap: allocate struct pages before 1:1 mapping
In reply to Martin SchwidefskyFrom: Christian Borntraeger <[email protected]>
We have seen an oops in an OOM situation, where show_mem tried to access the struct page of a dcss segment. The vmemmap code has already created the 1:1 mapping but failed allocating the struct pages. In the OOM case, show_mem now walks the memory. It uses pfn_valid to detect if it may access the struct page. In the case described above, the mapping was established and pfn_valid returned true. As the struct pages were not allocated, the kernel oopsed.
We have to ensure that we have created the struct pages, before we add a mapping pointing to the pages.
---
arch/s390/mm/vmem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/s390/mm/vmem.c +2 -2
@@ -236,10 +236,10 @@ static int vmem_add_mem(unsigned long st {int ret; - ret =vmem_add_range (start, size); + ret =vmem_add_mem_map (start, size);if (ret)return ret; -return vmem_add_mem_map (start, size); +return vmem_add_range (start, size); }/*
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 39/47 Use diag308 subcodes 3 and 6 for reboot and dump when possible.
In reply to Martin SchwidefskyFrom: Michael Holzheu <[email protected]>
This patch fixes a problem with the following scenario:
1. Linux booted from DASD "A"
2. Reboot from DASD "B" using "/sys/firmware/reipl/ccw/device"
3. Reboot DASD "B"
Without this patch in step 3 on newer s390 systems under LPAR instead of DASD "B", DASD "A" will be booted. The reason is that in step 2 we use CCW reipl and in step 3 we use DIAG308 (subcode 3) reipl. DIAG308 does not notice the CCW reipl and still thinks that it has to reboot DASD "A". Before applying this fix, ensure to have MCF RJ9967101E or z9 GA3 base driver installed.
---
arch/s390/kernel/ipl.c | 14 ++++++++------ include/asm-s390/ipl.h | 4 ++++ 2 files changed, 12 insertions(+), 6 deletions(-)
arch/s390/kernel/ipl.c +8 -6
@@ -588,7 +588,9 @@ static int reipl_set_type(enum ipl_typeswitch (type) {case IPL_TYPE_CCW : -if (MACHINE_IS_VM ) +if (diag308_set_works) + reipl_method =REIPL_METHOD_CCW_DIAG ; +else if (MACHINE_IS_VM ) reipl_method =REIPL_METHOD_CCW_VM ;else reipl_method =REIPL_METHOD_CCW_CIO ;
@@ -650,8 +652,6 @@ void reipl_run(struct shutdown_trigger *switch (reipl_method) {case REIPL_METHOD_CCW_CIO : devid.devno = reipl_block_ccw->ipl_info.ccw.devno; -if (ipl_info.type ==IPL_TYPE_CCW && devid.devno == ipl_devno) -diag308 (DIAG308_IPL ,NULL ); devid.ssid =0 ;reipl_ccw_dev (&devid);break ;
@@ -736,6 +736,7 @@ static int __init reipl_ccw_init(void) reipl_block_ccw->hdr.version =IPL_PARM_BLOCK_VERSION ; reipl_block_ccw->hdr.blk0_len =IPL_PARM_BLK0_CCW_LEN ; reipl_block_ccw->hdr.pbt =DIAG308_IPL_TYPE_CCW ; + reipl_block_ccw->hdr.flags =DIAG308_FLAGS_LP_VALID ;/* check if read scp info worked and set loadparm */ if (sclp_ipl_info.is_valid) memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
@@ -744,8 +745,7 @@ static int __init reipl_ccw_init(void)/* read scp info failed: set empty loadparm (EBCDIC blanks) */ memset (reipl_block_ccw->ipl_info.ccw.load_param,0x40 ,LOADPARM_LEN ); -/* FIXME: check for diag308_set_works when enabling diag ccw reipl */ -if (!MACHINE_IS_VM ) +if (!MACHINE_IS_VM && !diag308_set_works) sys_reipl_ccw_loadparm_attr.attr.mode =S_IRUGO ;if (ipl_info.type ==IPL_TYPE_CCW ) reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
@@ -867,7 +867,9 @@ static int dump_set_type(enum dump_typereturn -EINVAL ;switch (type) {case DUMP_TYPE_CCW : -if (MACHINE_IS_VM ) +if (diag308_set_works) + dump_method =DUMP_METHOD_CCW_DIAG ; +else if (MACHINE_IS_VM ) dump_method =DUMP_METHOD_CCW_VM ;else dump_method =DUMP_METHOD_CCW_CIO ;
include/asm-s390/ipl.h +4 -0
@@ -143,6 +143,10 @@ enum diag308_opt { DIAG308_IPL_OPT_DUMP = 0x20, }; +enum diag308_flags { +DIAG308_FLAGS_LP_VALID =0x80 , +}; +enum diag308_rc {DIAG308_RC_OK =1 , };
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 40/47 arch/s390/: Spelling fixes
In reply to Martin SchwidefskyFrom: Joe Perches <[email protected]>
---
arch/s390/crypto/prng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/crypto/prng.c +1 -1
@@ -90,7 +90,7 @@ static ssize_t prng_read(struct file *fiint ret =0 ;int tmp; -/* nbytes can be arbitrary long, we spilt it into chunks */ +/* nbytes can be arbitrary length, we split it into chunks */ while (nbytes) {/* same as in extract_entropy_user in random.c */ if (need_resched ()) {
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 41/47 include/asm-s390/: Spelling fixes
In reply to Martin SchwidefskyFrom: Joe Perches <[email protected]>
---
include/asm-s390/cio.h | 4 ++-- include/asm-s390/dasd.h | 2 +- include/asm-s390/qdio.h | 2 +- include/asm-s390/zcrypt.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-)
include/asm-s390/cio.h +2 -2
@@ -24,8 +24,8 @@* @fmt: format * @pfch: prefetch * @isic: initial-status interruption control -* @alcc: adress-limit checking control -* @ssi: supress-suspended interruption +* @alcc: address-limit checking control +* @ssi: suppress-suspended interruption * @zcc: zero condition code * @ectl: extended control * @pno: path not operational
include/asm-s390/dasd.h +1 -1
@@ -105,7 +105,7 @@ typedef struct dasd_information_t { } dasd_information_t;/* -* Read Subsystem Data - Perfomance Statistics +* Read Subsystem Data - Performance Statistics */ typedef struct dasd_rssd_perf_stats_t { unsigned char invalid:1;
include/asm-s390/qdio.h +1 -1
@@ -184,7 +184,7 @@ struct qdr {#endif /* QDIO_32_BIT */ unsigned long qiba;/* queue-information-block address */ unsigned int res8;/* reserved */ - unsigned int qkey : 4; /* queue-informatio-block key */ + unsigned int qkey : 4; /* queue-information-block key */ unsigned int res9 : 28; /* reserved *//* union _qd {*/ /* why this? */ struct qdesfmt0 qdf0[126 ];
include/asm-s390/zcrypt.h +1 -1
@@ -117,7 +117,7 @@ struct CPRBX {unsigned char padx004[16 -sizeof (char *)];unsigned char * req_extb;/* request extension block 'addr'*/ unsigned char padx005[16 -sizeof (char *)]; -unsigned char * rpl_extb;/* reply extension block 'addres'*/ +unsigned char * rpl_extb;/* reply extension block 'address'*/ unsigned short ccp_rtcode;/* server return code */ unsigned short ccp_rscode;/* server reason code */ unsigned int mac_data_len;/* Mac Data Length */
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 42/47 drivers/s390/: Spelling fixes
In reply to Martin SchwidefskyFrom: Joe Perches <[email protected]>
---
drivers/s390/block/dasd_3990_erp.c | 2 +- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/char/sclp_rw.c | 2 +- drivers/s390/char/tape_3590.c | 2 +- drivers/s390/scsi/zfcp_erp.c | 2 +- drivers/s390/scsi/zfcp_qdio.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-)
drivers/s390/block/dasd_3990_erp.c +1 -1
@@ -2620,7 +2620,7 @@ dasd_3990_erp_handle_match_erp(struct da* DASD_3990_ERP_ACTION * * DESCRIPTION -* controll routine for 3990 erp actions. +* control routine for 3990 erp actions. * Has to be called with the queue lock (namely the s390_irq_lock) acquired. * * PARAMETER
drivers/s390/block/dasd_eckd.c +1 -1
@@ -1542,7 +1542,7 @@ dasd_eckd_performance(struct dasd_device prssdp = (struct dasd_psf_prssd_data *) cqr->data;memset (prssdp,0 ,sizeof (struct dasd_psf_prssd_data )); prssdp->order =PSF_ORDER_PRSSD ; - prssdp->suborder =0x01 ;/* Perfomance Statistics */ + prssdp->suborder =0x01 ;/* Performance Statistics */ prssdp->varies[1 ] =0x01 ;/* Perf Statistics for the Subsystem */ ccw = cqr->cpaddr;
drivers/s390/char/sclp_rw.c +1 -1
@@ -76,7 +76,7 @@ sclp_make_buffer(void *page, unsigned sh }/* -* Return a pointer to the orignal page that has been used to create +* Return a pointer to the original page that has been used to create * the buffer. */ void *
drivers/s390/char/tape_3590.c +1 -1
@@ -1495,7 +1495,7 @@ tape_3590_unit_check(struct tape_device device->cdev->dev.bus_id);return tape_3590_erp_basic (device, request, irb, -EPERM );case 0x8013 : -PRINT_WARN ("(%s): Another host has priviliged access to the " +PRINT_WARN ("(%s): Another host has privileged access to the " "tape device\n" , device->cdev->dev.bus_id);PRINT_WARN ("(%s): To solve the problem unload the current " "cartridge!\n" , device->cdev->dev.bus_id);
drivers/s390/scsi/zfcp_erp.c +1 -1
@@ -1285,7 +1285,7 @@ zfcp_erp_strategy_do_action(struct zfcp_* note: no lock in subsequent strategy routines * (this allows these routine to call schedule, e.g. * kmalloc with such flags or qdio_initialize & friends) -* Note: in case of timeout, the seperate strategies will fail +* Note: in case of timeout, the separate strategies will fail * anyhow. No need for a special action. Even worse, a nameserver * failure would not wake up waiting ports without the call. */
drivers/s390/scsi/zfcp_qdio.c +1 -1
@@ -529,7 +529,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req/** -* zfcp_qdio_sbale_fill - set address and lenght in current SBALE +* zfcp_qdio_sbale_fill - set address and length in current SBALE * on request_queue */ static void
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 43/47 Move NOTES and BUG_TABLE.
In reply to Martin SchwidefskyFrom: Martin Schwidefsky <[email protected]>
Move the NOTES and BUG_TABLE section in the linker script to the read-only sections right after the text section.
---
arch/s390/kernel/vmlinux.lds.S | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/s390/kernel/vmlinux.lds.S +9 -3
@@ -17,6 +17,12 @@ ENTRY(_start) jiffies = jiffies_64; #endif +PHDRS { + text PT_LOAD FLAGS(5); /* R_E */ + data PT_LOAD FLAGS(7); /* RWE */ + note PT_NOTE FLAGS(0); /* ___ */ +} + SECTIONS { . = 0x00000000;
@@ -33,6 +39,9 @@ SECTIONS _etext = .; /* End of text section */ + NOTES :text :note + BUG_TABLE :text + RODATA #ifdef CONFIG_SHARED_KERNEL
@@ -49,9 +58,6 @@ SECTIONS __stop___ex_table = .; } - NOTES - BUG_TABLE - .data : { /* Data */ DATA_DATA CONSTRUCTORS
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 44/47 single-step cleanup
In reply to Martin SchwidefskyFrom: Roland McGrath <[email protected]>
---
arch/s390/kernel/ptrace.c | 15 ++++++--------- arch/s390/kernel/signal.c | 20 +++++++++++++------- include/asm-s390/ptrace.h | 8 ++++++++ 3 files changed, 27 insertions(+), 16 deletions(-)
arch/s390/kernel/ptrace.c +6 -9
@@ -86,13 +86,13 @@ FixPerRegisters(struct task_struct *task per_info->control_regs.bits.storage_alt_space_ctl =0 ; } -static void set_single_step (struct task_struct *task) +void user_enable_single_step (struct task_struct *task) { task->thread.per_info.single_step =1 ;FixPerRegisters (task); } -static void clear_single_step (struct task_struct *task) +void user_disable_single_step (struct task_struct *task) { task->thread.per_info.single_step =0 ;FixPerRegisters (task);
@@ -107,7 +107,7 @@ void ptrace_disable(struct task_struct *child) {/* make sure the single step bit is not set. */ -clear_single_step (child); +user_disable_single_step (child); }#ifndef CONFIG_64BIT
@@ -651,7 +651,7 @@ do_ptrace(struct task_struct *child, lonclear_tsk_thread_flag (child,TIF_SYSCALL_TRACE ); child->exit_code = data;/* make sure the single step bit is not set. */ -clear_single_step (child); +user_disable_single_step (child);wake_up_process (child);return 0 ;
@@ -665,7 +665,7 @@ do_ptrace(struct task_struct *child, lonreturn 0 ; child->exit_code =SIGKILL ;/* make sure the single step bit is not set. */ -clear_single_step (child); +user_disable_single_step (child);wake_up_process (child);return 0 ;
@@ -675,10 +675,7 @@ do_ptrace(struct task_struct *child, lonreturn -EIO ;clear_tsk_thread_flag (child,TIF_SYSCALL_TRACE ); child->exit_code = data; -if (data) -set_tsk_thread_flag (child,TIF_SINGLE_STEP ); -else -set_single_step (child); +user_enable_single_step (child);/* give it a chance to run. */ wake_up_process (child);return 0 ;
arch/s390/kernel/signal.c +13 -7
@@ -471,6 +471,7 @@ void do_signal(struct pt_regs *regs) if (signr > 0) { /* Whee! Actually deliver the signal. */ + int ret; #ifdef CONFIG_COMPAT if (test_thread_flag(TIF_31BIT)) { extern int handle_signal32(unsigned long sig,
@@ -478,15 +479,12 @@ void do_signal(struct pt_regs *regs) siginfo_t *info, sigset_t *oldset, struct pt_regs *regs); -if (handle_signal32 ( - signr, &ka, &info, oldset, regs) ==0 ) { -if (test_thread_flag (TIF_RESTORE_SIGMASK )) -clear_thread_flag (TIF_RESTORE_SIGMASK ); - } - return; + ret = handle_signal32(signr, &ka, &info, oldset, regs); } + else#endif -if (handle_signal (signr, &ka, &info, oldset, regs) ==0 ) { + ret =handle_signal (signr, &ka, &info, oldset, regs); +if (!ret) {/* * A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame,
@@ -495,6 +493,14 @@ void do_signal(struct pt_regs *regs)*/ if (test_thread_flag (TIF_RESTORE_SIGMASK ))clear_thread_flag (TIF_RESTORE_SIGMASK ); + +/* +* If we would have taken a single-step trap +* for a normal instruction, act like we took +* one for the handler setup. +*/ +if (current->thread.per_info.single_step) +set_thread_flag (TIF_SINGLE_STEP ); }return ; }
include/asm-s390/ptrace.h +8 -0
@@ -465,6 +465,14 @@ struct user_regs_struct#ifdef __KERNEL__#define __ARCH_SYS_PTRACE 1 +/* +* These are defined as per linux/ptrace.h, which see. +*/ +#define arch_has_single_step () (1) +struct task_struct ; +extern void user_enable_single_step (struct task_struct *); +extern void user_disable_single_step (struct task_struct *); +#define user_mode (regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)#define instruction_pointer (regs) ((regs)->psw.addr & PSW_ADDR_INSN)#define regs_return_value (regs)((regs)->gprs[2])
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 45/47 dasd: add hyper PAV support to DASD device driver, part 1
In reply to Martin SchwidefskyFrom: Stefan Weinhuber <[email protected]>
Parallel access volumes (PAV) is a storage server feature, that allows to start multiple channel programs on the same DASD in parallel. It defines alias devices which can be used as alternative paths to the same disk. With the old base PAV support we only needed rudimentary functionality in the DASD device driver. As the mapping between base and alias devices was static, we just had to export an identifier (uid) and could leave the combining of devices to external layers like a device mapper multipath.
Now hyper PAV removes the requirement to dedicate alias devices to specific base devices. Instead each alias devices can be combined with multiple base device on a per request basis. This requires full support by the DASD device driver as now each channel program itself has to identify the target base device.
The changes to the dasd device driver and the ECKD discipline are:
- Separate subchannel device representation (dasd_device) from block device representation (dasd_block). Only base devices are block devices.
- Gather information about base and alias devices and possible combinations.
- For each request decide which dasd_device should be used (base or alias) and build specific channel program.
- Support summary unit checks, which allow the storage server to upgrade / downgrade between base and hyper PAV at runtime (support is mandatory).
---
drivers/s390/block/Makefile | 4 drivers/s390/block/dasd_3370_erp.c | 84 --- drivers/s390/block/dasd_3990_erp.c | 358 +++++--------- drivers/s390/block/dasd_9336_erp.c | 41 - drivers/s390/block/dasd_9343_erp.c | 21 drivers/s390/block/dasd_alias.c | 903 +++++++++++++++++++++++++++++++++++++ drivers/s390/block/dasd_int.h | 158 ++++-- drivers/s390/block/dasd_ioctl.c | 165 +++--- drivers/s390/block/dasd_proc.c | 21 9 files changed, 1231 insertions(+), 524 deletions(-)
drivers/s390/block/dasd_3370_erp.c deleted +0 -84
@@ -1,84 +0,0 @@ -/* -* File...........: linux/drivers/s390/block/dasd_3370_erp.c -* Author(s)......: Holger Smolinski <[email protected]> -* Bugreports.to..: <[email protected]> -* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 -* -*/ - -#define PRINTK_HEADER "dasd_erp(3370)" - -#include "dasd_int.h" - - -/* -* DASD_3370_ERP_EXAMINE -* -* DESCRIPTION -* Checks only for fatal/no/recover error. -* A detailed examination of the sense data is done later outside -* the interrupt handler. -* -* The logic is based on the 'IBM 3880 Storage Control Reference' manual -* 'Chapter 7. 3370 Sense Data'. -* -* RETURN VALUES -* dasd_era_none no error -* dasd_era_fatal for all fatal (unrecoverable errors) -* dasd_era_recover for all others. -*/ -dasd_era_t -dasd_3370_erp_examine (struct dasd_ccw_req * cqr,struct irb * irb) -{ -char *sense = irb->ecw; - -/* check for successful execution first */ -if (irb->scsw.cstat ==0x00 && - irb->scsw.dstat == (DEV_STAT_CHN_END |DEV_STAT_DEV_END )) -return dasd_era_none; -if (sense[0 ] &0x80 ) {/* CMD reject */ -return dasd_era_fatal; - } -if (sense[0 ] &0x40 ) {/* Drive offline */ -return dasd_era_recover; - } -if (sense[0 ] &0x20 ) {/* Bus out parity */ -return dasd_era_recover; - } -if (sense[0 ] &0x10 ) {/* equipment check */ -if (sense[1 ] &0x80 ) { -return dasd_era_fatal; - } -return dasd_era_recover; - } -if (sense[0 ] &0x08 ) {/* data check */ -if (sense[1 ] &0x80 ) { -return dasd_era_fatal; - } -return dasd_era_recover; - } -if (sense[0 ] &0x04 ) {/* overrun */ -if (sense[1 ] &0x80 ) { -return dasd_era_fatal; - } -return dasd_era_recover; - } -if (sense[1 ] &0x40 ) {/* invalid blocksize */ -return dasd_era_fatal; - } -if (sense[1 ] &0x04 ) {/* file protected */ -return dasd_era_recover; - } -if (sense[1 ] &0x01 ) {/* operation incomplete */ -return dasd_era_recover; - } -if (sense[2 ] &0x80 ) {/* check data erroor */ -return dasd_era_recover; - } -if (sense[2 ] &0x10 ) {/* Env. data present */ -return dasd_era_recover; - } -/* examine the 24 byte sense data */ -return dasd_era_recover; - -}/* END dasd_3370_erp_examine */
drivers/s390/block/dasd_3990_erp.c +126 -232
727 lines not on this page · raw message
drivers/s390/block/dasd_9336_erp.c deleted +0 -41
41 lines not on this page · raw message
drivers/s390/block/dasd_9343_erp.c deleted +0 -21
@@ -1,21 +0,0 @@ -/* -* File...........: linux/drivers/s390/block/dasd_9345_erp.c -* Author(s)......: Holger Smolinski <[email protected]> -* Bugreports.to..: <[email protected]> -* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 -* -*/ - -#define PRINTK_HEADER "dasd_erp(9343)" - -#include "dasd_int.h" - -dasd_era_t -dasd_9343_erp_examine (struct dasd_ccw_req * cqr,struct irb * irb) -{ -if (irb->scsw.cstat ==0x00 && - irb->scsw.dstat == (DEV_STAT_CHN_END |DEV_STAT_DEV_END )) -return dasd_era_none; - -return dasd_era_recover; -}
drivers/s390/block/dasd_alias.c new file +903 -0
903 lines not on this page · raw message
drivers/s390/block/dasd_int.h +101 -57
307 lines not on this page · raw message
drivers/s390/block/dasd_ioctl.c +86 -79
406 lines not on this page · raw message
drivers/s390/block/dasd_proc.c +13 -8
@@ -54,11 +54,16 @@ static int dasd_devices_show(struct seq_file *m, void *v) { struct dasd_device *device; +struct dasd_block *block;char *substr; device =dasd_device_from_devindex ((unsigned long ) v -1 );if (IS_ERR (device))return 0 ; +if (device->block) + block = device->block; +else +return 0 ;/* Print device number. */ seq_printf (m,"%s" , device->cdev->dev.bus_id);/* Print discipline string. */
@@ -67,14 +72,14 @@ dasd_devices_show(struct seq_file *m, voelse seq_printf (m,"(none)" );/* Print kdev. */ -if (device->gdp) +if (block->gdp)seq_printf (m," at (%3d:%6d)" , - device->gdp->major, device->gdp->first_minor); + block->gdp->major, block->gdp->first_minor);else seq_printf (m," at (???:??????)" );/* Print device name. */ -if (device->gdp) -seq_printf (m," is %-8s" , device->gdp->disk_name); +if (block->gdp) +seq_printf (m," is %-8s" , block->gdp->disk_name);else seq_printf (m," is ????????" );/* Print devices features. */
@@ -100,14 +105,14 @@ dasd_devices_show(struct seq_file *m, vocase DASD_STATE_READY :case DASD_STATE_ONLINE :seq_printf (m,"active " ); -if (dasd_check_blocksize (device->bp_block)) +if (dasd_check_blocksize (block->bp_block))seq_printf (m,"n/f " );else seq_printf (m,"at blocksize: %d, %ld blocks, %ld MB" , - device->bp_block, device->blocks, - ((device->bp_block >>9 ) * - device->blocks) >>11 ); + block->bp_block, block->blocks, + ((block->bp_block >>9 ) * + block->blocks) >>11 );break ;default :seq_printf (m,"no stat" );
drivers/s390/block/Makefile +2 -2
@@ -2,8 +2,8 @@ # S/390 block devices # -dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o -dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o +dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_alias.o +dasd_fba_mod-objs := dasd_fba.o dasd_diag_mod-objs := dasd_diag.o dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \ dasd_genhd.o dasd_erp.o
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 46/47 dasd: add hyper PAV support to DASD device driver, part 2
In reply to Martin SchwidefskyFrom: Stefan Weinhuber <[email protected]>
---
drivers/s390/block/dasd.c | 1661 +++++++++++++++++++++++++--------------------- 1 file changed, 938 insertions(+), 723 deletions(-)
drivers/s390/block/dasd.c +938 -723
@@ -48,13 +48,15 @@ MODULE_LICENSE("GPL");/* * SECTION: prototypes for static functions of dasd.c */ -static int dasd_alloc_queue (struct dasd_device * device); -static void dasd_setup_queue (struct dasd_device * device); -static void dasd_free_queue (struct dasd_device * device); -static void dasd_flush_request_queue (struct dasd_device *); -static int dasd_flush_ccw_queue (struct dasd_device *,int ); -static void dasd_tasklet (struct dasd_device *); +static int dasd_alloc_queue (struct dasd_block *); +static void dasd_setup_queue (struct dasd_block *); +static void dasd_free_queue (struct dasd_block *); +static void dasd_flush_request_queue (struct dasd_block *); +static int dasd_flush_block_queue (struct dasd_block *); +static void dasd_device_tasklet (struct dasd_device *); +static void dasd_block_tasklet (struct dasd_block *);static void do_kick_device (struct work_struct *); +static void dasd_return_cqr_cb (struct dasd_ccw_req *,void *);/* * SECTION: Operations on the device structure.
@@ -65,16 +67,13 @@ static wait_queue_head_t dasd_flush_wq;/* * Allocate memory for a new device structure. */ -struct dasd_device * -dasd_alloc_device (void ) +struct dasd_device *dasd_alloc_device (void ) {struct dasd_device *device; - device =kzalloc (sizeof (struct dasd_device ),GFP_ATOMIC ); + device =kzalloc (sizeof (struct dasd_device ),GFP_ATOMIC );if (device ==NULL )return ERR_PTR (-ENOMEM ); -/* open_count = 0 means device online but not in use */ -atomic_set (&device->open_count,-1 );/* Get two pages for normal block device operations. */ device->ccw_mem = (void *)__get_free_pages (GFP_ATOMIC |GFP_DMA ,1 );
@@ -93,10 +92,9 @@ dasd_alloc_device(void)dasd_init_chunklist (&device->ccw_chunks, device->ccw_mem,PAGE_SIZE *2 );dasd_init_chunklist (&device->erp_chunks, device->erp_mem,PAGE_SIZE );spin_lock_init (&device->mem_lock); -spin_lock_init (&device->request_queue_lock); -atomic_set (&device->tasklet_scheduled,0 ); +atomic_set (&device->tasklet_scheduled,0 );tasklet_init (&device->tasklet, - (void (*)(unsigned long )) dasd_tasklet, + (void (*)(unsigned long )) dasd_device_tasklet, (unsigned long ) device);INIT_LIST_HEAD (&device->ccw_queue);init_timer (&device->timer);
@@ -110,8 +108,7 @@ dasd_alloc_device(void)/* * Free memory of a device structure. */ -void -dasd_free_device (struct dasd_device *device) +void dasd_free_device (struct dasd_device *device) {kfree (device->private);free_page ((unsigned long ) device->erp_mem);
@@ -120,10 +117,42 @@ dasd_free_device(struct dasd_device *dev }/* +* Allocate memory for a new device structure. +*/ +struct dasd_block *dasd_alloc_block (void ) +{ +struct dasd_block *block; + + block =kzalloc (sizeof (*block),GFP_ATOMIC ); +if (block ==NULL ) +return ERR_PTR (-ENOMEM ); +/* open_count = 0 means device online but not in use */ +atomic_set (&block->open_count,-1 ); + +spin_lock_init (&block->request_queue_lock); +atomic_set (&block->tasklet_scheduled,0 ); +tasklet_init (&block->tasklet, + (void (*)(unsigned long )) dasd_block_tasklet, + (unsigned long ) block); +INIT_LIST_HEAD (&block->ccw_queue); +spin_lock_init (&block->queue_lock); +init_timer (&block->timer); + +return block; +} + +/* +* Free memory of a device structure. +*/ +void dasd_free_block (struct dasd_block *block) +{ +kfree (block); +} + +/* * Make a new device known to the system. */ -static int -dasd_state_new_to_known (struct dasd_device *device) +static int dasd_state_new_to_known (struct dasd_device *device) {int rc;
@@ -133,12 +162,13 @@ dasd_state_new_to_known(struct dasd_devi*/ dasd_get_device (device); - rc =dasd_alloc_queue (device); -if (rc) { -dasd_put_device (device); -return rc; +if (device->block) { + rc =dasd_alloc_queue (device->block); +if (rc) { +dasd_put_device (device); +return rc; + } } - device->state =DASD_STATE_KNOWN ;return 0 ; }
@@ -146,21 +176,24 @@ dasd_state_new_to_known(struct dasd_devi/* * Let the system forget about a device. */ -static int -dasd_state_known_to_new (struct dasd_device * device) +static int dasd_state_known_to_new (struct dasd_device *device) {/* Disable extended error reporting for this device. */ dasd_eer_disable (device);/* Forget the discipline information. */ -if (device->discipline) +if (device->discipline) { +if (device->discipline->uncheck_device) + device->discipline->uncheck_device (device);module_put (device->discipline->owner); + } device->discipline =NULL ;if (device->base_discipline)module_put (device->base_discipline->owner); device->base_discipline =NULL ; device->state =DASD_STATE_NEW ; -dasd_free_queue (device); +if (device->block) +dasd_free_queue (device->block);/* Give up reference we took in dasd_state_new_to_known. */ dasd_put_device (device);
@@ -170,19 +203,19 @@ dasd_state_known_to_new(struct dasd_devi/* * Request the irq line for the device. */ -static int -dasd_state_known_to_basic (struct dasd_device * device) +static int dasd_state_known_to_basic (struct dasd_device *device) {int rc;/* Allocate and register gendisk structure. */ - rc =dasd_gendisk_alloc (device); -if (rc) -return rc; - +if (device->block) { + rc =dasd_gendisk_alloc (device->block); +if (rc) +return rc; + }/* register 'device' debug area, used for all DBF_DEV_XXX calls */ device->debug_area =debug_register (device->cdev->dev.bus_id,1 ,2 , -8 *sizeof (long )); +8 *sizeof (long ));debug_register_view (device->debug_area, &debug_sprintf_view);debug_set_level (device->debug_area,DBF_WARNING );DBF_DEV_EVENT (DBF_EMERG , device,"%s" ,"debug area created" );
@@ -194,16 +227,17 @@ dasd_state_known_to_basic(struct dasd_de/* * Release the irq line for the device. Terminate any running i/o. */ -static int -dasd_state_basic_to_known (struct dasd_device * device) +static int dasd_state_basic_to_known (struct dasd_device *device) {int rc; - -dasd_gendisk_free (device); - rc =dasd_flush_ccw_queue (device,1 ); +if (device->block) { +dasd_gendisk_free (device->block); +dasd_block_clear_timer (device->block); + } + rc =dasd_flush_device_queue (device);if (rc)return rc; -dasd_clear_timer (device); +dasd_device_clear_timer (device);DBF_DEV_EVENT (DBF_EMERG , device,"%p debug area deleted" , device);if (device->debug_area !=NULL ) {
@@ -228,26 +262,32 @@ dasd_state_basic_to_known(struct dasd_de* In case the analysis returns an error, the device setup is stopped * (a fake disk was already added to allow formatting). */ -static int -dasd_state_basic_to_ready (struct dasd_device * device) +static int dasd_state_basic_to_ready (struct dasd_device *device) {int rc; +struct dasd_block *block; rc =0 ; -if (device->discipline->do_analysis !=NULL ) - rc = device->discipline->do_analysis (device); -if (rc) { -if (rc != -EAGAIN ) - device->state =DASD_STATE_UNFMT ; -return rc; - } + block = device->block;/* make disk known with correct capacity */ -dasd_setup_queue (device); -set_capacity (device->gdp, device->blocks << device->s2b_shift); - device->state =DASD_STATE_READY ; - rc =dasd_scan_partitions (device); -if (rc) - device->state =DASD_STATE_BASIC ; +if (block) { +if (block->base->discipline->do_analysis !=NULL ) + rc = block->base->discipline->do_analysis (block); +if (rc) { +if (rc != -EAGAIN ) + device->state =DASD_STATE_UNFMT ; +return rc; + } +dasd_setup_queue (block); +set_capacity (block->gdp, + block->blocks << block->s2b_shift); + device->state =DASD_STATE_READY ; + rc =dasd_scan_partitions (block); +if (rc) + device->state =DASD_STATE_BASIC ; + }else { + device->state =DASD_STATE_READY ; + }return rc; }
@@ -256,28 +296,31 @@ dasd_state_basic_to_ready(struct dasd_de* Forget format information. Check if the target level is basic * and if it is create fake disk for formatting. */ -static int -dasd_state_ready_to_basic (struct dasd_device * device) +static int dasd_state_ready_to_basic (struct dasd_device *device) {int rc; - rc =dasd_flush_ccw_queue (device,0 ); -if (rc) -return rc; -dasd_destroy_partitions (device); -dasd_flush_request_queue (device); - device->blocks =0 ; - device->bp_block =0 ; - device->s2b_shift =0 ; device->state =DASD_STATE_BASIC ; +if (device->block) { +struct dasd_block *block = device->block; + rc =dasd_flush_block_queue (block); +if (rc) { + device->state =DASD_STATE_READY ; +return rc; + } +dasd_destroy_partitions (block); +dasd_flush_request_queue (block); + block->blocks =0 ; + block->bp_block =0 ; + block->s2b_shift =0 ; + }return 0 ; }/* * Back to basic. */ -static int -dasd_state_unfmt_to_basic (struct dasd_device * device) +static int dasd_state_unfmt_to_basic (struct dasd_device *device) { device->state =DASD_STATE_BASIC ;return 0 ;
@@ -291,17 +334,31 @@ dasd_state_unfmt_to_basic(struct dasd_destatic int dasd_state_ready_to_online (struct dasd_device * device) { +int rc; + +if (device->discipline->ready_to_online) { + rc = device->discipline->ready_to_online (device); +if (rc) +return rc; + } device->state =DASD_STATE_ONLINE ; -dasd_schedule_bh (device); +if (device->block) +dasd_schedule_block_bh (device->block);return 0 ; }/* * Stop the requeueing of requests again. */ -static int -dasd_state_online_to_ready (struct dasd_device * device) +static int dasd_state_online_to_ready (struct dasd_device *device) { +int rc; + +if (device->discipline->online_to_ready) { + rc = device->discipline->online_to_ready (device); +if (rc) +return rc; + } device->state =DASD_STATE_READY ;return 0 ; }
@@ -309,8 +366,7 @@ dasd_state_online_to_ready(struct dasd_d/* * Device startup state changes. */ -static int -dasd_increase_state (struct dasd_device *device) +static int dasd_increase_state (struct dasd_device *device) {int rc;
@@ -345,8 +401,7 @@ dasd_increase_state(struct dasd_device */* * Device shutdown state changes. */ -static int -dasd_decrease_state (struct dasd_device *device) +static int dasd_decrease_state (struct dasd_device *device) {int rc;
@@ -381,8 +436,7 @@ dasd_decrease_state(struct dasd_device */* * This is the main startup/shutdown routine. */ -static void -dasd_change_state (struct dasd_device *device) +static void dasd_change_state (struct dasd_device *device) {int rc;
@@ -409,17 +463,15 @@ dasd_change_state(struct dasd_device *de* dasd_kick_device will schedule a call do do_kick_device to the kernel * event daemon. */ -static void -do_kick_device (struct work_struct *work) +static void do_kick_device (struct work_struct *work) { struct dasd_device *device = container_of(work, struct dasd_device, kick_work);dasd_change_state (device); -dasd_schedule_bh (device); +dasd_schedule_device_bh (device);dasd_put_device (device); } -void -dasd_kick_device (struct dasd_device *device) +void dasd_kick_device (struct dasd_device *device) {dasd_get_device (device);/* queue call to dasd_kick_device to the kernel event daemon. */
@@ -429,8 +481,7 @@ dasd_kick_device(struct dasd_device *dev/* * Set the target state for a device and starts the state change. */ -void -dasd_set_target_state (struct dasd_device *device,int target) +void dasd_set_target_state (struct dasd_device *device,int target) {/* If we are in probeonly mode stop at DASD_STATE_READY. */ if (dasd_probeonly && target >DASD_STATE_READY )
@@ -447,14 +498,12 @@ dasd_set_target_state(struct dasd_device/* * Enable devices with device numbers in [from..to]. */ -static inline int -_wait_for_device (struct dasd_device *device) +static inline int _wait_for_device (struct dasd_device *device) {return (device->state == device->target); } -void -dasd_enable_device (struct dasd_device *device) +void dasd_enable_device (struct dasd_device *device) {dasd_set_target_state (device,DASD_STATE_ONLINE );if (device->state <=DASD_STATE_KNOWN )
@@ -475,20 +524,20 @@ unsigned int dasd_profile_level = DASD_P/* * Increments counter in global and local profiling structures. */ -#define dasd_profile_counter (value, counter, device) \ +#define dasd_profile_counter (value, counter, block) \ { \ int index; \ for (index = 0; index < 31 && value >> (2+index); index++); \ dasd_global_profile.counter[index]++; \ - device->profile.counter[index]++; \ + block->profile.counter[index]++; \ }/* * Add profiling information for cqr before execution. */ -static void -dasd_profile_start (struct dasd_device *device,struct dasd_ccw_req * cqr, -struct request *req) +static void dasd_profile_start (struct dasd_block *block, +struct dasd_ccw_req *cqr, +struct request *req) {struct list_head *l;unsigned int counter;
@@ -498,19 +547,19 @@ dasd_profile_start(struct dasd_device *d/* count the length of the chanq for statistics */ counter =0 ; -list_for_each (l, &device->ccw_queue) +list_for_each (l, &block->ccw_queue)if (++counter >=31 )break ; dasd_global_profile.dasd_io_nr_req[counter]++; - device->profile.dasd_io_nr_req[counter]++; + block->profile.dasd_io_nr_req[counter]++; }/* * Add profiling information for cqr after execution. */ -static void -dasd_profile_end (struct dasd_device *device,struct dasd_ccw_req * cqr, -struct request *req) +static void dasd_profile_end (struct dasd_block *block, +struct dasd_ccw_req *cqr, +struct request *req) {long strtime, irqtime, endtime, tottime;/* in microseconds */ long tottimeps, sectors;
@@ -532,27 +581,27 @@ dasd_profile_end(struct dasd_device *devif (!dasd_global_profile.dasd_io_reqs)memset (&dasd_global_profile,0 , -sizeof (struct dasd_profile_info_t )); +sizeof (struct dasd_profile_info_t )); dasd_global_profile.dasd_io_reqs++; dasd_global_profile.dasd_io_sects += sectors; -if (!device->profile.dasd_io_reqs) -memset (&device->profile,0 , -sizeof (struct dasd_profile_info_t )); - device->profile.dasd_io_reqs++; - device->profile.dasd_io_sects += sectors; - -dasd_profile_counter (sectors, dasd_io_secs, device); -dasd_profile_counter (tottime, dasd_io_times, device); -dasd_profile_counter (tottimeps, dasd_io_timps, device); -dasd_profile_counter (strtime, dasd_io_time1, device); -dasd_profile_counter (irqtime, dasd_io_time2, device); -dasd_profile_counter (irqtime / sectors, dasd_io_time2ps, device); - dasd_profile_counter(endtime, dasd_io_time3, device); +if (!block->profile.dasd_io_reqs) +memset (&block->profile,0 , +sizeof (struct dasd_profile_info_t )); + block->profile.dasd_io_reqs++; + block->profile.dasd_io_sects += sectors; + +dasd_profile_counter (sectors, dasd_io_secs, block); +dasd_profile_counter (tottime, dasd_io_times, block); +dasd_profile_counter (tottimeps, dasd_io_timps, block); +dasd_profile_counter (strtime, dasd_io_time1, block); +dasd_profile_counter (irqtime, dasd_io_time2, block); +dasd_profile_counter (irqtime / sectors, dasd_io_time2ps, block); + dasd_profile_counter(endtime, dasd_io_time3, block); }#else -#define dasd_profile_start (device, cqr, req) do {} while (0) -#define dasd_profile_end (device, cqr, req) do {} while (0) +#define dasd_profile_start (block, cqr, req) do {} while (0) +#define dasd_profile_end (block, cqr, req) do {} while (0)#endif /* CONFIG_DASD_PROFILE */ /*
@@ -562,9 +611,9 @@ dasd_profile_end(struct dasd_device *dev* memory and 2) dasd_smalloc_request uses the static ccw memory * that gets allocated for each device. */ -struct dasd_ccw_req * -dasd_kmalloc_request (char *magic,int cplength,int datasize, -struct dasd_device * device) +struct dasd_ccw_req *dasd_kmalloc_request (char *magic,int cplength, +int datasize, +struct dasd_device *device) {struct dasd_ccw_req *cqr;
@@ -600,9 +649,9 @@ dasd_kmalloc_request(char *magic, int cpreturn cqr; } -struct dasd_ccw_req * -dasd_smalloc_request (char *magic,int cplength,int datasize, -struct dasd_device * device) +struct dasd_ccw_req *dasd_smalloc_request (char *magic,int cplength, +int datasize, +struct dasd_device *device) {unsigned long flags;struct dasd_ccw_req *cqr;
@@ -649,8 +698,7 @@ dasd_smalloc_request(char *magic, int cp* idal lists that might have been created by dasd_set_cda and the * struct dasd_ccw_req itself. */ -void -dasd_kfree_request (struct dasd_ccw_req * cqr,struct dasd_device * device) +void dasd_kfree_request (struct dasd_ccw_req *cqr,struct dasd_device *device) {#ifdef CONFIG_64BIT struct ccw1 *ccw;
@@ -667,8 +715,7 @@ dasd_kfree_request(struct dasd_ccw_req *dasd_put_device (device); } -void -dasd_sfree_request (struct dasd_ccw_req * cqr,struct dasd_device * device) +void dasd_sfree_request (struct dasd_ccw_req *cqr,struct dasd_device *device) {unsigned long flags;
@@ -681,14 +728,13 @@ dasd_sfree_request(struct dasd_ccw_req */* * Check discipline magic in cqr. */ -static inline int -dasd_check_cqr (struct dasd_ccw_req *cqr) +static inline int dasd_check_cqr (struct dasd_ccw_req *cqr) {struct dasd_device *device;if (cqr ==NULL )return -EINVAL ; - device = cqr->device; + device = cqr->startdev;if (strncmp ((char *) &cqr->magic, device->discipline->ebcname,4 )) {DEV_MESSAGE (KERN_WARNING , device, " dasd_ccw_req 0x%08x magic doesn't match"
@@ -706,8 +752,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr)* ccw_device_clear can fail if the i/o subsystem * is in a bad mood. */ -int -dasd_term_IO (struct dasd_ccw_req * cqr) +int dasd_term_IO (struct dasd_ccw_req *cqr) {struct dasd_device *device;int retries, rc;
@@ -717,13 +762,13 @@ dasd_term_IO(struct dasd_ccw_req * cqr)if (rc)return rc; retries =0 ; - device = (struct dasd_device *) cqr->device; + device = (struct dasd_device *) cqr->startdev;while ((retries <5 ) && (cqr->status ==DASD_CQR_IN_IO )) { rc =ccw_device_clear (device->cdev, (long ) cqr);switch (rc) {case 0 :/* termination successful */ cqr->retries--; - cqr->status =DASD_CQR_CLEAR ; + cqr->status =DASD_CQR_CLEAR_PENDING ; cqr->stopclk =get_clock (); cqr->starttime =0 ; DBF_DEV_EVENT(DBF_DEBUG, device,
@@ -753,7 +798,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr) } retries++; } -dasd_schedule_bh (device); +dasd_schedule_device_bh (device);return rc; }
@@ -761,8 +806,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)* Start the i/o. This start_IO can fail if the channel is really busy. * In that case set up a timer to start the request later. */ -int -dasd_start_IO (struct dasd_ccw_req * cqr) +int dasd_start_IO (struct dasd_ccw_req *cqr) {struct dasd_device *device;int rc;
@@ -771,12 +815,12 @@ dasd_start_IO(struct dasd_ccw_req * cqr) rc =dasd_check_cqr (cqr);if (rc)return rc; - device = (struct dasd_device *) cqr->device; + device = (struct dasd_device *) cqr->startdev;if (cqr->retries <0 ) {DEV_MESSAGE (KERN_DEBUG , device,"start_IO: request %p (%02x/%i) - no retry left." , cqr, cqr->status, cqr->retries); - cqr->status =DASD_CQR_FAILED ; + cqr->status =DASD_CQR_ERROR ;return -EIO ; } cqr->startclk =get_clock ();
@@ -833,8 +877,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr)* The head of the ccw queue will have status DASD_CQR_IN_IO for 1), * DASD_CQR_QUEUED for 2) and 3). */ -static void -dasd_timeout_device (unsigned long ptr) +static void dasd_device_timeout (unsigned long ptr) {unsigned long flags;struct dasd_device *device;
@@ -844,14 +887,13 @@ dasd_timeout_device(unsigned long ptr)/* re-activate request queue */ device->stopped &= ~DASD_STOPPED_PENDING ;spin_unlock_irqrestore (get_ccwdev_lock (device->cdev), flags); -dasd_schedule_bh (device); +dasd_schedule_device_bh (device); }/* * Setup timeout for a device in jiffies. */ -void -dasd_set_timer (struct dasd_device *device,int expires) +void dasd_device_set_timer (struct dasd_device *device,int expires) {if (expires ==0 ) {if (timer_pending (&device->timer))
@@ -862,7 +904,7 @@ dasd_set_timer(struct dasd_device *devicif (mod_timer (&device->timer, jiffies + expires))return ; } - device->timer.function = dasd_timeout_device; + device->timer.function = dasd_device_timeout; device->timer.data = (unsigned long ) device; device->timer.expires = jiffies + expires;add_timer (&device->timer);
@@ -871,15 +913,14 @@ dasd_set_timer(struct dasd_device *devic/* * Clear timeout for a device. */ -void -dasd_clear_timer (struct dasd_device *device) +void dasd_device_clear_timer (struct dasd_device *device) {if (timer_pending (&device->timer))del_timer (&device->timer); } -static void -dasd_handle_killed_request (struct ccw_device *cdev,unsigned long intparm) +static void dasd_handle_killed_request (struct ccw_device *cdev, +unsigned long intparm) {struct dasd_ccw_req *cqr;struct dasd_device *device;
@@ -893,7 +934,7 @@ dasd_handle_killed_request(struct ccw_dereturn ; } - device = (struct dasd_device *) cqr->device; + device = (struct dasd_device *) cqr->startdev;if (device ==NULL || device !=dasd_device_from_cdev_locked (cdev) ||strncmp (device->discipline->ebcname, (char *) &cqr->magic,4 )) {
@@ -905,13 +946,12 @@ dasd_handle_killed_request(struct ccw_de/* Schedule request to be retried. */ cqr->status =DASD_CQR_QUEUED ; -dasd_clear_timer (device); -dasd_schedule_bh (device); +dasd_device_clear_timer (device); +dasd_schedule_device_bh (device);dasd_put_device (device); } -static void -dasd_handle_state_change_pending (struct dasd_device *device) +void dasd_generic_handle_state_change (struct dasd_device *device) {struct dasd_ccw_req *cqr;struct list_head *l, *n;
@@ -923,28 +963,27 @@ dasd_handle_state_change_pending(struct/* restart all 'running' IO on queue */ list_for_each_safe (l, n, &device->ccw_queue) { - cqr = list_entry(l, struct dasd_ccw_req, list); + cqr = list_entry(l, struct dasd_ccw_req, devlist);if (cqr->status ==DASD_CQR_IN_IO ) { cqr->status =DASD_CQR_QUEUED ; } } -dasd_clear_timer (device); -dasd_schedule_bh (device); +dasd_device_clear_timer (device); +dasd_schedule_device_bh (device); +if (device->block) +dasd_schedule_block_bh (device->block); }/* * Interrupt handler for "normal" ssch-io based dasd devices. */ -void -dasd_int_handler (struct ccw_device *cdev,unsigned long intparm, -struct irb *irb) +void dasd_int_handler (struct ccw_device *cdev,unsigned long intparm, +struct irb *irb) {struct dasd_ccw_req *cqr, *next;struct dasd_device *device;unsigned long long now;int expires; -dasd_era_t era; -char mask;if (IS_ERR (irb)) {switch (PTR_ERR (irb)) {
@@ -969,28 +1008,19 @@ dasd_int_handler(struct ccw_device *cdev cdev->dev.bus_id, ((irb->scsw.cstat<<8 )|irb->scsw.dstat), (unsigned int) intparm); -/* first of all check for state change pending interrupt */ - mask =DEV_STAT_ATTENTION |DEV_STAT_DEV_END |DEV_STAT_UNIT_EXCEP ; -if ((irb->scsw.dstat & mask) == mask) { +/* check for unsolicited interrupts */ + cqr = (struct dasd_ccw_req *) intparm; +if (cqr ==NULL ) { device =dasd_device_from_cdev_locked (cdev);if (!IS_ERR (device)) { -dasd_handle_state_change_pending (device); + device->discipline->handle_unsolicited_interrupt (device, + irb);dasd_put_device (device); }return ; } - cqr = (struct dasd_ccw_req *) intparm; - -/* check for unsolicited interrupts */ -if (cqr ==NULL ) { -MESSAGE (KERN_DEBUG , -"unsolicited interrupt received: bus_id %s" , - cdev->dev.bus_id); -return ; - } - - device = (struct dasd_device *) cqr->device; + device = (struct dasd_device *) cqr->startdev;if (device ==NULL ||strncmp (device->discipline->ebcname, (char *) &cqr->magic,4 )) { MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
@@ -999,12 +1029,12 @@ dasd_int_handler(struct ccw_device *cdev }/* Check for clear pending */ -if (cqr->status ==DASD_CQR_CLEAR && +if (cqr->status ==DASD_CQR_CLEAR_PENDING && irb->scsw.fctl &SCSW_FCTL_CLEAR_FUNC ) { - cqr->status =DASD_CQR_QUEUED ; -dasd_clear_timer (device); + cqr->status =DASD_CQR_CLEARED ; +dasd_device_clear_timer (device);wake_up (&dasd_flush_wq); -dasd_schedule_bh (device); +dasd_schedule_device_bh (device);return ; }
@@ -1017,272 +1047,164 @@ dasd_int_handler(struct ccw_device *cdev }DBF_DEV_EVENT (DBF_DEBUG , device,"Int: CS/DS 0x%04x for cqr %p" , ((irb->scsw.cstat <<8 ) | irb->scsw.dstat), cqr); - -/* Find out the appropriate era_action. */ -if (irb->scsw.fctl &SCSW_FCTL_HALT_FUNC ) - era = dasd_era_fatal; -else if (irb->scsw.dstat == (DEV_STAT_CHN_END |DEV_STAT_DEV_END ) && - irb->scsw.cstat ==0 && - !irb->esw.esw0.erw.cons) - era = dasd_era_none; -else if (irb->esw.esw0.erw.cons) - era = device->discipline->examine_error (cqr, irb); -else - era = dasd_era_recover; - -DBF_DEV_EVENT (DBF_DEBUG , device,"era_code %d" , era); + next =NULL ; expires =0 ; -if (era == dasd_era_none) { - cqr->status =DASD_CQR_DONE ; +if (irb->scsw.dstat == (DEV_STAT_CHN_END |DEV_STAT_DEV_END ) && + irb->scsw.cstat ==0 && !irb->esw.esw0.erw.cons) { +/* request was completed successfully */ + cqr->status =DASD_CQR_SUCCESS ; cqr->stopclk = now;/* Start first request on queue if possible -> fast_io. */ -if (cqr->list.next != &device->ccw_queue) { - next =list_entry (cqr->list.next, - struct dasd_ccw_req, list); -if ((next->status ==DASD_CQR_QUEUED ) && - (!device->stopped)) { -if (device->discipline->start_IO (next) ==0 ) - expires = next->expires; -else -DEV_MESSAGE (KERN_DEBUG , device,"%s" , -"Interrupt fastpath " -"failed!" ); - } +if (cqr->devlist.next != &device->ccw_queue) { + next =list_entry (cqr->devlist.next, + struct dasd_ccw_req, devlist); } - }else {/* error */ -memcpy (&cqr->irb, irb,sizeof (struct irb )); + }else {/* error */ +memcpy (&cqr->irb, irb,sizeof (struct irb ));if (device->features &DASD_FEATURE_ERPLOG ) { -/* dump sense data */ dasd_log_sense (cqr, irb); } -switch (era) { -case dasd_era_fatal: - cqr->status =DASD_CQR_FAILED ; - cqr->stopclk = now; -break ; -case dasd_era_recover: +/* If we have no sense data, or we just don't want complex ERP +* for this request, but if we have retries left, then just +* reset this request and retry it in the fastpath +*/ +if (!(cqr->irb.esw.esw0.erw.cons && +test_bit (DASD_CQR_FLAGS_USE_ERP , &cqr->flags)) && + cqr->retries >0 ) { +DEV_MESSAGE (KERN_DEBUG , device, +"default ERP in fastpath (%i retries left)" , + cqr->retries); + cqr->lpm =LPM_ANYPATH ; + cqr->status =DASD_CQR_QUEUED ; + next = cqr; + }else cqr->status =DASD_CQR_ERROR ; -break ; -default : -BUG (); - } + } +if (next && (next->status ==DASD_CQR_QUEUED ) && + (!device->stopped)) { +if (device->discipline->start_IO (next) ==0 ) + expires = next->expires; +else +DEV_MESSAGE (KERN_DEBUG , device,"%s" , +"Interrupt fastpath " +"failed!" ); }if (expires !=0 ) -dasd_set_timer (device, expires); +dasd_device_set_timer (device, expires);else -dasd_clear_timer (device); -dasd_schedule_bh (device); +dasd_device_clear_timer (device); +dasd_schedule_device_bh (device); }/* -* posts the buffer_cache about a finalized request +* If we have an error on a dasd_block layer request then we cancel +* and return all further requests from the same dasd_block as well. */ -static inline void -dasd_end_request (struct request *req,int uptodate) +static void __dasd_device_recovery (struct dasd_device *device, +struct dasd_ccw_req *ref_cqr) { -if (end_that_request_first (req, uptodate, req->hard_nr_sectors)) -BUG (); -add_disk_randomness (req->rq_disk); -end_that_request_last (req, uptodate); -} +struct list_head *l, *n; +struct dasd_ccw_req *cqr; -/* -* Process finished error recovery ccw. -*/ -static inline void -__dasd_process_erp (struct dasd_device *device,struct dasd_ccw_req *cqr) -{ -dasd_erp_fn_t erp_fn; +/* +* only requeue request that came from the dasd_block layer +*/ +if (!ref_cqr->block) +return ; -if (cqr->status ==DASD_CQR_DONE ) -DBF_DEV_EVENT (DBF_NOTICE , device,"%s" ,"ERP successful" ); -else -DEV_MESSAGE (KERN_ERR , device,"%s" ,"ERP unsuccessful" ); - erp_fn = device->discipline->erp_postaction (cqr); -erp_fn (cqr); -} +list_for_each_safe (l, n, &device->ccw_queue) { + cqr = list_entry(l, struct dasd_ccw_req, devlist); +if (cqr->status ==DASD_CQR_QUEUED && + ref_cqr->block == cqr->block) { + cqr->status =DASD_CQR_CLEARED ; + } + } +};/* -* Process ccw request queue. +* Remove those ccw requests from the queue that need to be returned +* to the upper layer. */ -static void -__dasd_process_ccw_queue (struct dasd_device * device, -struct list_head *final_queue) +static void __dasd_device_process_ccw_queue (struct dasd_device *device, +struct list_head *final_queue) {struct list_head *l, *n;struct dasd_ccw_req *cqr; -dasd_erp_fn_t erp_fn; -restart:/* Process request with final status. */ list_for_each_safe (l, n, &device->ccw_queue) { - cqr = list_entry(l, struct dasd_ccw_req, list); + cqr = list_entry(l, struct dasd_ccw_req, devlist); +/* Stop list processing at the first non-final request. */ -if (cqr->status !=DASD_CQR_DONE && - cqr->status !=DASD_CQR_FAILED && - cqr->status !=DASD_CQR_ERROR ) +if (cqr->status ==DASD_CQR_QUEUED || + cqr->status ==DASD_CQR_IN_IO || + cqr->status ==DASD_CQR_CLEAR_PENDING )break ; -/* Process requests with DASD_CQR_ERROR */ if (cqr->status ==DASD_CQR_ERROR ) { -if (cqr->irb.scsw.fctl &SCSW_FCTL_HALT_FUNC ) { - cqr->status =DASD_CQR_FAILED ; - cqr->stopclk =get_clock (); - }else { -if (cqr->irb.esw.esw0.erw.cons && -test_bit (DASD_CQR_FLAGS_USE_ERP , - &cqr->flags)) { - erp_fn = device->discipline-> -erp_action (cqr); -erp_fn (cqr); - }else -dasd_default_erp_action (cqr); - } - goto restart; - } - -/* First of all call extended error reporting. */ -if (dasd_eer_enabled (device) && - cqr->status ==DASD_CQR_FAILED ) { -dasd_eer_write (device, cqr,DASD_EER_FATALERROR ); - -/* restart request */ - cqr->status =DASD_CQR_QUEUED ; - cqr->retries =255 ; - device->stopped |=DASD_STOPPED_QUIESCE ; - goto restart; - } - -/* Process finished ERP request. */ -if (cqr->refers) { -__dasd_process_erp (device, cqr); - goto restart; +__dasd_device_recovery (device, cqr); } -/* Rechain finished requests to final queue */ - cqr->endclk =get_clock (); -list_move_tail (&cqr->list, final_queue); +list_move_tail (&cqr->devlist, final_queue); } } -static void -dasd_end_request_cb (struct dasd_ccw_req * cqr,void *data) -{ -struct request *req; -struct dasd_device *device; -int status; - - req = (struct request *) data; - device = cqr->device; -dasd_profile_end (device, cqr, req); - status = cqr->device->discipline->free_cp (cqr,req); -spin_lock_irq (&device->request_queue_lock); -dasd_end_request (req, status); -spin_unlock_irq (&device->request_queue_lock); -} - -/* -* Fetch requests from the block device queue. +* the cqrs from the final queue are returned to the upper layer +* by setting a dasd_block state and calling the callback function */ -static void -__dasd_process_blk_queue (struct dasd_device * device) +static void __dasd_device_process_final_queue (struct dasd_device *device, +struct list_head *final_queue) { -struct request_queue *queue; -struct request *req; +struct list_head *l, *n;struct dasd_ccw_req *cqr; -int nr_queued; - - queue = device->request_queue; -/* No queue ? Then there is nothing to do. */ -if (queue ==NULL ) -return ; - -/* -* We requeue request from the block device queue to the ccw -* queue only in two states. In state DASD_STATE_READY the -* partition detection is done and we need to requeue requests -* for that. State DASD_STATE_ONLINE is normal block device -* operation. -*/ -if (device->state !=DASD_STATE_READY && - device->state !=DASD_STATE_ONLINE ) -return ; - nr_queued =0 ; -/* Now we try to fetch requests from the request queue */ -list_for_each_entry (cqr, &device->ccw_queue, list) -if (cqr->status ==DASD_CQR_QUEUED ) - nr_queued++; -while (!blk_queue_plugged (queue) && -elv_next_request (queue) && - nr_queued <DASD_CHANQ_MAX_SIZE ) { - req =elv_next_request (queue); -if (device->features &DASD_FEATURE_READONLY && -rq_data_dir (req) ==WRITE ) { -DBF_DEV_EVENT (DBF_ERR , device, -"Rejecting write request %p" , - req); -blkdev_dequeue_request (req); -dasd_end_request (req,0 ); -continue ; - } -if (device->stopped &DASD_STOPPED_DC_EIO ) { -blkdev_dequeue_request (req); -dasd_end_request (req,0 ); -continue ; - } - cqr = device->discipline->build_cp (device, req); -if (IS_ERR (cqr)) { -if (PTR_ERR (cqr) == -ENOMEM ) -break ;/* terminate request queue loop */ -if (PTR_ERR (cqr) == -EAGAIN ) { -/* -* The current request cannot be build right -* now, we have to try later. If this request -* is the head-of-queue we stop the device -* for 1/2 second. -*/ -if (!list_empty (&device->ccw_queue)) -break ; - device->stopped |=DASD_STOPPED_PENDING ; -dasd_set_timer (device,HZ /2 ); -break ; - } -DBF_DEV_EVENT (DBF_ERR , device, -"CCW creation failed (rc=%ld) " -"on request %p" , -PTR_ERR (cqr), req); -blkdev_dequeue_request (req); -dasd_end_request (req,0 ); -continue ; +list_for_each_safe (l, n, final_queue) { + cqr = list_entry(l, struct dasd_ccw_req, devlist); +list_del_init (&cqr->devlist); +if (cqr->block) +spin_lock_bh (&cqr->block->queue_lock); +switch (cqr->status) { +case DASD_CQR_SUCCESS : + cqr->status =DASD_CQR_DONE ; +break ; +case DASD_CQR_ERROR : + cqr->status =DASD_CQR_NEED_ERP ; +break ; +case DASD_CQR_CLEARED : + cqr->status =DASD_CQR_TERMINATED ; +break ; +default : +DEV_MESSAGE (KERN_ERR , device, +"wrong cqr status in __dasd_process_final_queue " +"for cqr %p, status %x" , + cqr, cqr->status); +BUG (); } - cqr->callback = dasd_end_request_cb; - cqr->callback_data = (void *) req; - cqr->status =DASD_CQR_QUEUED ; -blkdev_dequeue_request (req); -list_add_tail (&cqr->list, &device->ccw_queue); -dasd_profile_start (device, cqr, req); - nr_queued++; +if (cqr->block) +spin_unlock_bh (&cqr->block->queue_lock); +if (cqr->callback !=NULL ) + (cqr->callback)(cqr, cqr->callback_data); } } + +/* * Take a look at the first request on the ccw queue and check * if it reached its expire time. If so, terminate the IO. */ -static void -__dasd_check_expire (struct dasd_device * device) +static void __dasd_device_check_expire (struct dasd_device *device) {struct dasd_ccw_req *cqr;if (list_empty (&device->ccw_queue))return ; - cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); + cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);if ((cqr->status ==DASD_CQR_IN_IO && cqr->expires !=0 ) && (time_after_eq (jiffies, cqr->expires + cqr->starttime))) {if (device->discipline->term_IO (cqr) !=0 ) {/* Hmpf, try again in 5 sec */ -dasd_set_timer (device,5 *HZ ); +dasd_device_set_timer (device,5 *HZ );DEV_MESSAGE (KERN_ERR , device,"internal error - timeout (%is) expired " "for cqr %p, termination failed, "
@@ -1301,77 +1223,53 @@ __dasd_check_expire(struct dasd_device ** Take a look at the first request on the ccw queue and check * if it needs to be started. */ -static void -__dasd_start_head (struct dasd_device * device) +static void __dasd_device_start_head (struct dasd_device *device) {struct dasd_ccw_req *cqr;int rc;if (list_empty (&device->ccw_queue))return ; - cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); + cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);if (cqr->status !=DASD_CQR_QUEUED )return ; -/* Non-temporary stop condition will trigger fail fast */ -if (device->stopped & ~DASD_STOPPED_PENDING && -test_bit (DASD_CQR_FLAGS_FAILFAST , &cqr->flags) && - (!dasd_eer_enabled (device))) { - cqr->status =DASD_CQR_FAILED ; -dasd_schedule_bh (device); +/* when device is stopped, return request to previous layer */ +if (device->stopped) { + cqr->status =DASD_CQR_CLEARED ; +dasd_schedule_device_bh (device);return ; } -/* Don't try to start requests if device is stopped */ -if (device->stopped) -return ; rc = device->discipline->start_IO (cqr);if (rc ==0 ) -dasd_set_timer (device, cqr->expires); +dasd_device_set_timer (device, cqr->expires);else if (rc == -EACCES ) { -dasd_schedule_bh (device); +dasd_schedule_device_bh (device); }else /* Hmpf, try again in 1/2 sec */ -dasd_set_timer (device,50 ); -} - -static inline int -_wait_for_clear (struct dasd_ccw_req *cqr) -{ -return (cqr->status ==DASD_CQR_QUEUED ); +dasd_device_set_timer (device,50 ); }/* -* Remove all requests from the ccw queue (all = '1') or only block device -* requests in case all = '0'. -* Take care of the erp-chain (chained via cqr->refers) and remove either -* the whole erp-chain or none of the erp-requests. -* If a request is currently running, term_IO is called and the request -* is re-queued. Prior to removing the terminated request we need to wait -* for the clear-interrupt. -* In case termination is not possible we stop processing and just finishing -* the already moved requests. +* Go through all request on the dasd_device request queue, +* terminate them on the cdev if necessary, and return them to the +* submitting layer via callback. +* Note: +* Make sure that all 'submitting layers' still exist when +* this function is called!. In other words, when 'device' is a base +* device then all block layer requests must have been removed before +* via dasd_flush_block_queue. */ -static int -dasd_flush_ccw_queue (struct dasd_device * device,int all) +int dasd_flush_device_queue (struct dasd_device *device) { -struct dasd_ccw_req *cqr, *orig, *n; -int rc, i; - +struct dasd_ccw_req *cqr, *n; +int rc;struct list_head flush_queue;INIT_LIST_HEAD (&flush_queue);spin_lock_irq (get_ccwdev_lock (device->cdev)); rc =0 ; -restart: -list_for_each_entry_safe (cqr, n, &device->ccw_queue, list) { -/* get original request of erp request-chain */ -for (orig = cqr; orig->refers !=NULL ; orig = orig->refers); - -/* Flush all request or only block device requests? */ -if (all ==0 && cqr->callback != dasd_end_request_cb && - orig->callback != dasd_end_request_cb) { -continue ; - } +list_for_each_entry_safe (cqr, n, &device->ccw_queue, devlist) {/* Check status and move request to flush_queue */ switch (cqr->status) {case DASD_CQR_IN_IO :
@@ -1387,90 +1285,60 @@ restart: }break ;case DASD_CQR_QUEUED : -case DASD_CQR_ERROR : -/* set request to FAILED */ cqr->stopclk =get_clock (); - cqr->status =DASD_CQR_FAILED ; + cqr->status =DASD_CQR_CLEARED ;break ; -default :/* do not touch the others */ +default :/* no need to modify the others */ break ; } -/* Rechain request (including erp chain) */ -for (i =0 ; cqr !=NULL ; cqr = cqr->refers, i++) { - cqr->endclk =get_clock (); -list_move_tail (&cqr->list, &flush_queue); - } -if (i >1 ) -/* moved more than one request - need to restart */ - goto restart; +list_move_tail (&cqr->devlist, &flush_queue); } - finished:spin_unlock_irq (get_ccwdev_lock (device->cdev)); -/* Now call the callback function of flushed requests */ -restart_cb: -list_for_each_entry_safe (cqr, n, &flush_queue, list) { -if (cqr->status ==DASD_CQR_CLEAR ) { -/* wait for clear interrupt! */ -wait_event (dasd_flush_wq,_wait_for_clear (cqr)); - cqr->status =DASD_CQR_FAILED ; - } -/* Process finished ERP request. */ -if (cqr->refers) { -__dasd_process_erp (device, cqr); -/* restart list_for_xx loop since dasd_process_erp -* might remove multiple elements */ - goto restart_cb; - } -/* call the callback function */ - cqr->endclk =get_clock (); -if (cqr->callback !=NULL ) - (cqr->callback)(cqr, cqr->callback_data); - } +/* +* After this point all requests must be in state CLEAR_PENDING, +* CLEARED, SUCCESS or ERROR. Now wait for CLEAR_PENDING to become +* one of the others. +*/ +list_for_each_entry_safe (cqr, n, &flush_queue, devlist) +wait_event (dasd_flush_wq, + (cqr->status !=DASD_CQR_CLEAR_PENDING )); +/* +* Now set each request back to TERMINATED, DONE or NEED_ERP +* and call the callback function of flushed requests +*/ +__dasd_device_process_final_queue (device, &flush_queue);return rc; }/* * Acquire the device lock and process queues for the device. */ -static void -dasd_tasklet (struct dasd_device * device) +static void dasd_device_tasklet (struct dasd_device *device) {struct list_head final_queue; -struct list_head *l, *n; -struct dasd_ccw_req *cqr;atomic_set (&device->tasklet_scheduled,0 );INIT_LIST_HEAD (&final_queue);spin_lock_irq (get_ccwdev_lock (device->cdev));/* Check expire time of first request on the ccw queue. */ -__dasd_check_expire (device); -/* Finish off requests on ccw queue */ -__dasd_process_ccw_queue (device, &final_queue); +__dasd_device_check_expire (device); +/* find final requests on ccw queue */ +__dasd_device_process_ccw_queue (device, &final_queue);spin_unlock_irq (get_ccwdev_lock (device->cdev));/* Now call the callback function of requests with final status */ -list_for_each_safe (l, n, &final_queue) { - cqr = list_entry(l, struct dasd_ccw_req, list); -list_del_init (&cqr->list); -if (cqr->callback !=NULL ) - (cqr->callback)(cqr, cqr->callback_data); - } -spin_lock_irq (&device->request_queue_lock); -spin_lock (get_ccwdev_lock (device->cdev)); -/* Get new request from the block device request queue */ -__dasd_process_blk_queue (device); +__dasd_device_process_final_queue (device, &final_queue); +spin_lock_irq (get_ccwdev_lock (device->cdev));/* Now check if the head of the ccw queue needs to be started. */ -__dasd_start_head (device); -spin_unlock (get_ccwdev_lock (device->cdev)); -spin_unlock_irq (&device->request_queue_lock); +__dasd_device_start_head (device); +spin_unlock_irq (get_ccwdev_lock (device->cdev));dasd_put_device (device); }/* * Schedules a call to dasd_tasklet over the device tasklet. */ -void -dasd_schedule_bh (struct dasd_device * device) +void dasd_schedule_device_bh (struct dasd_device *device) {/* Protect against rescheduling. */ if (atomic_cmpxchg (&device->tasklet_scheduled,0 ,1 ) !=0 )
@@ -1480,160 +1348,109 @@ dasd_schedule_bh(struct dasd_device * de }/* -* Queue a request to the head of the ccw_queue. Start the I/O if -* possible. +* Queue a request to the head of the device ccw_queue. +* Start the I/O if possible. */ -void -dasd_add_request_head (struct dasd_ccw_req *req) +void dasd_add_request_head (struct dasd_ccw_req *cqr) {struct dasd_device *device;unsigned long flags; - device = req->device; + device = cqr->startdev;spin_lock_irqsave (get_ccwdev_lock (device->cdev), flags); - req->status =DASD_CQR_QUEUED ; - req->device = device; -list_add (&req->list, &device->ccw_queue); + cqr->status =DASD_CQR_QUEUED ; +list_add (&cqr->devlist, &device->ccw_queue);/* let the bh start the request to keep them in order */ -dasd_schedule_bh (device); +dasd_schedule_device_bh (device);spin_unlock_irqrestore (get_ccwdev_lock (device->cdev), flags); }/* -* Queue a request to the tail of the ccw_queue. Start the I/O if -* possible. +* Queue a request to the tail of the device ccw_queue. +* Start the I/O if possible. */ -void -dasd_add_request_tail (struct dasd_ccw_req *req) +void dasd_add_request_tail (struct dasd_ccw_req *cqr) {struct dasd_device *device;unsigned long flags; - device = req->device; + device = cqr->startdev;spin_lock_irqsave (get_ccwdev_lock (device->cdev), flags); - req->status =DASD_CQR_QUEUED ; - req->device = device; -list_add_tail (&req->list, &device->ccw_queue); + cqr->status =DASD_CQR_QUEUED ; +list_add_tail (&cqr->devlist, &device->ccw_queue);/* let the bh start the request to keep them in order */ -dasd_schedule_bh (device); +dasd_schedule_device_bh (device);spin_unlock_irqrestore (get_ccwdev_lock (device->cdev), flags); }/* -* Wakeup callback. +* Wakeup helper for the 'sleep_on' functions. */ -static void -dasd_wakeup_cb (struct dasd_ccw_req *cqr,void *data) +static void dasd_wakeup_cb (struct dasd_ccw_req *cqr,void *data) {wake_up ((wait_queue_head_t *) data); } -static inline int -_wait_for_wakeup (struct dasd_ccw_req *cqr) +static inline int _wait_for_wakeup (struct dasd_ccw_req *cqr) {struct dasd_device *device;int rc; - device = cqr->device; + device = cqr->startdev;spin_lock_irq (get_ccwdev_lock (device->cdev)); rc = ((cqr->status ==DASD_CQR_DONE || - cqr->status ==DASD_CQR_FAILED ) && -list_empty (&cqr->list)); + cqr->status ==DASD_CQR_NEED_ERP || + cqr->status ==DASD_CQR_TERMINATED ) && +list_empty (&cqr->devlist));spin_unlock_irq (get_ccwdev_lock (device->cdev));return rc; }/* -* Attempts to start a special ccw queue and waits for its completion. +* Queue a request to the tail of the device ccw_queue and wait for +* it's completion. */ -int -dasd_sleep_on (struct dasd_ccw_req * cqr) +int dasd_sleep_on (struct dasd_ccw_req *cqr) {wait_queue_head_t wait_q;struct dasd_device *device;int rc; - device = cqr->device; -spin_lock_irq (get_ccwdev_lock (device->cdev)); + device = cqr->startdev;init_waitqueue_head (&wait_q); cqr->callback = dasd_wakeup_cb; cqr->callback_data = (void *) &wait_q; - cqr->status =DASD_CQR_QUEUED ; -list_add_tail (&cqr->list, &device->ccw_queue); - -/* let the bh start the request to keep them in order */ -dasd_schedule_bh (device); - -spin_unlock_irq (get_ccwdev_lock (device->cdev)); - +dasd_add_request_tail (cqr);wait_event (wait_q,_wait_for_wakeup (cqr));/* Request status is either done or failed. */ - rc = (cqr->status ==DASD_CQR_FAILED ) ? -EIO :0 ; + rc = (cqr->status ==DASD_CQR_DONE ) ?0 : -EIO ;return rc; }/* -* Attempts to start a special ccw queue and wait interruptible -* for its completion. +* Queue a request to the tail of the device ccw_queue and wait +* interruptible for it's completion. */ -int -dasd_sleep_on_interruptible (struct dasd_ccw_req * cqr) +int dasd_sleep_on_interruptible (struct dasd_ccw_req *cqr) {wait_queue_head_t wait_q;struct dasd_device *device; -int rc, finished; - - device = cqr->device; -spin_lock_irq (get_ccwdev_lock (device->cdev)); +int rc; + device = cqr->startdev;init_waitqueue_head (&wait_q); cqr->callback = dasd_wakeup_cb; cqr->callback_data = (void *) &wait_q; - cqr->status =DASD_CQR_QUEUED ; -list_add_tail (&cqr->list, &device->ccw_queue); - -/* let the bh start the request to keep them in order */ -dasd_schedule_bh (device); -spin_unlock_irq (get_ccwdev_lock (device->cdev)); - - finished =0 ; -while (!finished) { - rc =wait_event_interruptible (wait_q,_wait_for_wakeup (cqr)); -if (rc != -ERESTARTSYS ) { -/* Request is final (done or failed) */ - rc = (cqr->status ==DASD_CQR_DONE ) ?0 : -EIO ; -break ; - } -spin_lock_irq (get_ccwdev_lock (device->cdev)); -switch (cqr->status) { -case DASD_CQR_IN_IO : -/* terminate runnig cqr */ -if (device->discipline->term_IO) { - cqr->retries =-1 ; - device->discipline->term_IO (cqr); -/* wait (non-interruptible) for final status -* because signal ist still pending */ -spin_unlock_irq (get_ccwdev_lock (device->cdev)); -wait_event (wait_q,_wait_for_wakeup (cqr)); -spin_lock_irq (get_ccwdev_lock (device->cdev)); - rc = (cqr->status ==DASD_CQR_DONE ) ?0 : -EIO ; - finished =1 ; - } -break ; -case DASD_CQR_QUEUED : -/* request */ -list_del_init (&cqr->list); - rc = -EIO ; - finished =1 ; -break ; -default : -/* cqr with 'non-interruptable' status - just wait */ -break ; - } -spin_unlock_irq (get_ccwdev_lock (device->cdev)); +dasd_add_request_tail (cqr); + rc =wait_event_interruptible (wait_q,_wait_for_wakeup (cqr)); +if (rc == -ERESTARTSYS ) { +dasd_cancel_req (cqr); +/* wait (non-interruptible) for final status */ +wait_event (wait_q,_wait_for_wakeup (cqr)); } + rc = (cqr->status ==DASD_CQR_DONE ) ?0 : -EIO ;return rc; }
@@ -1643,25 +1460,23 @@ dasd_sleep_on_interruptible(struct dasd_* and be put back to status queued, before the special request is added * to the head of the queue. Then the special request is waited on normally. */ -static inline int -_dasd_term_running_cqr (struct dasd_device *device) +static inline int _dasd_term_running_cqr (struct dasd_device *device) {struct dasd_ccw_req *cqr;if (list_empty (&device->ccw_queue))return 0 ; - cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); + cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);return device->discipline->term_IO (cqr); } -int -dasd_sleep_on_immediatly (struct dasd_ccw_req * cqr) +int dasd_sleep_on_immediatly (struct dasd_ccw_req *cqr) {wait_queue_head_t wait_q;struct dasd_device *device;int rc; - device = cqr->device; + device = cqr->startdev;spin_lock_irq (get_ccwdev_lock (device->cdev)); rc =_dasd_term_running_cqr (device);if (rc) {
@@ -1673,17 +1488,17 @@ dasd_sleep_on_immediatly(struct dasd_ccw cqr->callback = dasd_wakeup_cb; cqr->callback_data = (void *) &wait_q; cqr->status =DASD_CQR_QUEUED ; -list_add (&cqr->list, &device->ccw_queue); +list_add (&cqr->devlist, &device->ccw_queue);/* let the bh start the request to keep them in order */ -dasd_schedule_bh (device); +dasd_schedule_device_bh (device);spin_unlock_irq (get_ccwdev_lock (device->cdev));wait_event (wait_q,_wait_for_wakeup (cqr));/* Request status is either done or failed. */ - rc = (cqr->status ==DASD_CQR_FAILED ) ? -EIO :0 ; + rc = (cqr->status ==DASD_CQR_DONE ) ?0 : -EIO ;return rc; }
@@ -1692,11 +1507,14 @@ dasd_sleep_on_immediatly(struct dasd_ccw* This is useful to timeout requests. The request will be * terminated if it is currently in i/o. * Returns 1 if the request has been terminated. +* 0 if there was no need to terminate the request (not started yet) +* negative error code if termination failed +* Cancellation of a request is an asynchronous operation! The calling +* function has to wait until the request is properly returned via callback. */ -int -dasd_cancel_req (struct dasd_ccw_req *cqr) +int dasd_cancel_req (struct dasd_ccw_req *cqr) { -struct dasd_device *device = cqr->device; +struct dasd_device *device = cqr->startdev;unsigned long flags;int rc;
@@ -1704,74 +1522,453 @@ dasd_cancel_req(struct dasd_ccw_req *cqrspin_lock_irqsave (get_ccwdev_lock (device->cdev), flags);switch (cqr->status) {case DASD_CQR_QUEUED : -/* request was not started - just set to failed */ - cqr->status =DASD_CQR_FAILED ; +/* request was not started - just set to cleared */ + cqr->status =DASD_CQR_CLEARED ;break ;case DASD_CQR_IN_IO :/* request in IO - terminate IO and release again */ -if (device->discipline->term_IO (cqr) !=0 ) -/* what to do if unable to terminate ?????? -e.g. not _IN_IO */ - cqr->status =DASD_CQR_FAILED ; - cqr->stopclk =get_clock (); - rc =1 ; + rc = device->discipline->term_IO (cqr); +if (rc) { +DEV_MESSAGE (KERN_ERR , device, +"dasd_cancel_req is unable " +" to terminate request %p, rc = %d" , + cqr, rc); + }else { + cqr->stopclk =get_clock (); + rc =1 ; + }break ; -case DASD_CQR_DONE : -case DASD_CQR_FAILED : -/* already finished - do nothing */ +default :/* already finished or clear pending - do nothing */ break ; -default : -DEV_MESSAGE (KERN_ALERT , device, -"invalid status %02x in request" , - cqr->status); + } +spin_unlock_irqrestore (get_ccwdev_lock (device->cdev), flags); +dasd_schedule_device_bh (device); +return rc; +} + + +/* +* SECTION: Operations of the dasd_block layer. +*/ + +/* +* Timeout function for dasd_block. This is used when the block layer +* is waiting for something that may not come reliably, (e.g. a state +* change interrupt) +*/ +static void dasd_block_timeout (unsigned long ptr) +{ +unsigned long flags; +struct dasd_block *block; + + block = (struct dasd_block *) ptr; +spin_lock_irqsave (get_ccwdev_lock (block->base->cdev), flags); +/* re-activate request queue */ + block->base->stopped &= ~DASD_STOPPED_PENDING ; +spin_unlock_irqrestore (get_ccwdev_lock (block->base->cdev), flags); +dasd_schedule_block_bh (block); +} + +/* +* Setup timeout for a dasd_block in jiffies. +*/ +void dasd_block_set_timer (struct dasd_block *block,int expires) +{ +if (expires ==0 ) { +if (timer_pending (&block->timer)) +del_timer (&block->timer); +return ; + } +if (timer_pending (&block->timer)) { +if (mod_timer (&block->timer, jiffies + expires)) +return ; + } + block->timer.function = dasd_block_timeout; + block->timer.data = (unsigned long ) block; + block->timer.expires = jiffies + expires; +add_timer (&block->timer); +} + +/* +* Clear timeout for a dasd_block. +*/ +void dasd_block_clear_timer (struct dasd_block *block) +{ +if (timer_pending (&block->timer)) +del_timer (&block->timer); +} + +/* +* posts the buffer_cache about a finalized request +*/ +static inline void dasd_end_request (struct request *req,int uptodate) +{ +if (end_that_request_first (req, uptodate, req->hard_nr_sectors))BUG (); +add_disk_randomness (req->rq_disk); +end_that_request_last (req, uptodate); +} + +/* +* Process finished error recovery ccw. +*/ +static inline void __dasd_block_process_erp (struct dasd_block *block, +struct dasd_ccw_req *cqr) +{ +dasd_erp_fn_t erp_fn; +struct dasd_device *device = block->base; + +if (cqr->status ==DASD_CQR_DONE ) +DBF_DEV_EVENT (DBF_NOTICE , device,"%s" ,"ERP successful" ); +else +DEV_MESSAGE (KERN_ERR , device,"%s" ,"ERP unsuccessful" ); + erp_fn = device->discipline->erp_postaction (cqr); +erp_fn (cqr); +} + +/* +* Fetch requests from the block device queue. +*/ +static void __dasd_process_request_queue (struct dasd_block *block) +{ +struct request_queue *queue; +struct request *req; +struct dasd_ccw_req *cqr; +struct dasd_device *basedev; +unsigned long flags; + queue = block->request_queue; + basedev = block->base; +/* No queue ? Then there is nothing to do. */ +if (queue ==NULL ) +return ; + +/* +* We requeue request from the block device queue to the ccw +* queue only in two states. In state DASD_STATE_READY the +* partition detection is done and we need to requeue requests +* for that. State DASD_STATE_ONLINE is normal block device +* operation. +*/ +if (basedev->state <DASD_STATE_READY ) +return ; +/* Now we try to fetch requests from the request queue */ +while (!blk_queue_plugged (queue) && +elv_next_request (queue)) { + + req =elv_next_request (queue); + +if (basedev->features &DASD_FEATURE_READONLY && +rq_data_dir (req) ==WRITE ) { +DBF_DEV_EVENT (DBF_ERR , basedev, +"Rejecting write request %p" , + req); +blkdev_dequeue_request (req); +dasd_end_request (req,0 ); +continue ; + } + cqr = basedev->discipline->build_cp (basedev, block, req); +if (IS_ERR (cqr)) { +if (PTR_ERR (cqr) == -EBUSY ) +break ;/* normal end condition */ +if (PTR_ERR (cqr) == -ENOMEM ) +break ;/* terminate request queue loop */ +if (PTR_ERR (cqr) == -EAGAIN ) { +/* +* The current request cannot be build right +* now, we have to try later. If this request +* is the head-of-queue we stop the device +* for 1/2 second. +*/ +if (!list_empty (&block->ccw_queue)) +break ; +spin_lock_irqsave (get_ccwdev_lock (basedev->cdev), flags); + basedev->stopped |=DASD_STOPPED_PENDING ; +spin_unlock_irqrestore (get_ccwdev_lock (basedev->cdev), flags); +dasd_block_set_timer (block,HZ /2 ); +break ; + } +DBF_DEV_EVENT (DBF_ERR , basedev, +"CCW creation failed (rc=%ld) " +"on request %p" , +PTR_ERR (cqr), req); +blkdev_dequeue_request (req); +dasd_end_request (req,0 ); +continue ; + } +/* +* Note: callback is set to dasd_return_cqr_cb in +* __dasd_block_start_head to cover erp requests as well +*/ + cqr->callback_data = (void *) req; + cqr->status =DASD_CQR_FILLED ; +blkdev_dequeue_request (req); +list_add_tail (&cqr->blocklist, &block->ccw_queue); +dasd_profile_start (block, cqr, req); + } +} + +static void __dasd_cleanup_cqr (struct dasd_ccw_req *cqr) +{ +struct request *req; +int status; + + req = (struct request *) cqr->callback_data; +dasd_profile_end (cqr->block, cqr, req); + status = cqr->memdev->discipline->free_cp (cqr, req); +dasd_end_request (req, status); +} + +/* +* Process ccw request queue. +*/ +static void __dasd_process_block_ccw_queue (struct dasd_block *block, +struct list_head *final_queue) +{ +struct list_head *l, *n; +struct dasd_ccw_req *cqr; +dasd_erp_fn_t erp_fn; +unsigned long flags; +struct dasd_device *base = block->base; + +restart: +/* Process request with final status. */ +list_for_each_safe (l, n, &block->ccw_queue) { + cqr = list_entry(l, struct dasd_ccw_req, blocklist); +if (cqr->status !=DASD_CQR_DONE && + cqr->status !=DASD_CQR_FAILED && + cqr->status !=DASD_CQR_NEED_ERP && + cqr->status !=DASD_CQR_TERMINATED ) +continue ; + +if (cqr->status ==DASD_CQR_TERMINATED ) { + base->discipline->handle_terminated_request (cqr); + goto restart; + } + +/* Process requests that may be recovered */ +if (cqr->status ==DASD_CQR_NEED_ERP ) { +if (cqr->irb.esw.esw0.erw.cons && +test_bit (DASD_CQR_FLAGS_USE_ERP , + &cqr->flags)) { + erp_fn = base->discipline->erp_action (cqr); +erp_fn (cqr); + } + goto restart; + } + +/* First of all call extended error reporting. */ +if (dasd_eer_enabled (base) && + cqr->status ==DASD_CQR_FAILED ) { +dasd_eer_write (base, cqr,DASD_EER_FATALERROR ); + +/* restart request */ + cqr->status =DASD_CQR_FILLED ; + cqr->retries =255 ; +spin_lock_irqsave (get_ccwdev_lock (base->cdev), flags); + base->stopped |=DASD_STOPPED_QUIESCE ; +spin_unlock_irqrestore (get_ccwdev_lock (base->cdev), + flags); + goto restart; + } +/* Process finished ERP request. */ +if (cqr->refers) { +__dasd_block_process_erp (block, cqr); + goto restart; + } + +/* Rechain finished requests to final queue */ + cqr->endclk =get_clock (); +list_move_tail (&cqr->blocklist, final_queue); + } +} + +static void dasd_return_cqr_cb (struct dasd_ccw_req *cqr,void *data) +{ +dasd_schedule_block_bh (cqr->block); +} + +static void __dasd_block_start_head (struct dasd_block *block) +{ +struct dasd_ccw_req *cqr; + +if (list_empty (&block->ccw_queue)) +return ; +/* We allways begin with the first requests on the queue, as some +* of previously started requests have to be enqueued on a +* dasd_device again for error recovery. +*/ +list_for_each_entry (cqr, &block->ccw_queue, blocklist) { +if (cqr->status !=DASD_CQR_FILLED ) +continue ; +/* Non-temporary stop condition will trigger fail fast */ +if (block->base->stopped & ~DASD_STOPPED_PENDING && +test_bit (DASD_CQR_FLAGS_FAILFAST , &cqr->flags) && + (!dasd_eer_enabled (block->base))) { + cqr->status =DASD_CQR_FAILED ; +dasd_schedule_block_bh (block); +continue ; + } +/* Don't try to start requests if device is stopped */ +if (block->base->stopped) +return ; + +/* just a fail safe check, should not happen */ +if (!cqr->startdev) + cqr->startdev = block->base; + +/* make sure that the requests we submit find their way back */ + cqr->callback = dasd_return_cqr_cb; + +dasd_add_request_tail (cqr); + } +} + +/* +* Central dasd_block layer routine. Takes requests from the generic +* block layer request queue, creates ccw requests, enqueues them on +* a dasd_device and processes ccw requests that have been returned. +*/ +static void dasd_block_tasklet (struct dasd_block *block) +{ +struct list_head final_queue; +struct list_head *l, *n; +struct dasd_ccw_req *cqr; + +atomic_set (&block->tasklet_scheduled,0 ); +INIT_LIST_HEAD (&final_queue); +spin_lock (&block->queue_lock); +/* Finish off requests on ccw queue */ +__dasd_process_block_ccw_queue (block, &final_queue); +spin_unlock (&block->queue_lock); +/* Now call the callback function of requests with final status */ +spin_lock_irq (&block->request_queue_lock); +list_for_each_safe (l, n, &final_queue) { + cqr = list_entry(l, struct dasd_ccw_req, blocklist); +list_del_init (&cqr->blocklist); +__dasd_cleanup_cqr (cqr); + } +spin_lock (&block->queue_lock); +/* Get new request from the block device request queue */ +__dasd_process_request_queue (block); +/* Now check if the head of the ccw queue needs to be started. */ +__dasd_block_start_head (block); +spin_unlock (&block->queue_lock); +spin_unlock_irq (&block->request_queue_lock); +dasd_put_device (block->base); +} + +static void _dasd_wake_block_flush_cb (struct dasd_ccw_req *cqr,void *data) +{ +wake_up (&dasd_flush_wq); +} + +/* +* Go through all request on the dasd_block request queue, cancel them +* on the respective dasd_device, and return them to the generic +* block layer. +*/ +static int dasd_flush_block_queue (struct dasd_block *block) +{ +struct dasd_ccw_req *cqr, *n; +int rc, i; +struct list_head flush_queue; + +INIT_LIST_HEAD (&flush_queue); +spin_lock_bh (&block->queue_lock); + rc =0 ; +restart: +list_for_each_entry_safe (cqr, n, &block->ccw_queue, blocklist) { +/* if this request currently owned by a dasd_device cancel it */ +if (cqr->status >=DASD_CQR_QUEUED ) + rc =dasd_cancel_req (cqr); +if (rc <0 ) +break ; +/* Rechain request (including erp chain) so it won't be +* touched by the dasd_block_tasklet anymore. +* Replace the callback so we notice when the request +* is returned from the dasd_device layer. +*/ + cqr->callback = _dasd_wake_block_flush_cb; +for (i =0 ; cqr !=NULL ; cqr = cqr->refers, i++) +list_move_tail (&cqr->blocklist, &flush_queue); +if (i >1 ) +/* moved more than one request - need to restart */ + goto restart; + } +spin_unlock_bh (&block->queue_lock); +/* Now call the callback function of flushed requests */ +restart_cb: +list_for_each_entry_safe (cqr, n, &flush_queue, blocklist) { +wait_event (dasd_flush_wq, (cqr->status <DASD_CQR_QUEUED )); +/* Process finished ERP request. */ +if (cqr->refers) { +__dasd_block_process_erp (block, cqr); +/* restart list_for_xx loop since dasd_process_erp +* might remove multiple elements */ + goto restart_cb; + } +/* call the callback function */ + cqr->endclk =get_clock (); +list_del_init (&cqr->blocklist); +__dasd_cleanup_cqr (cqr); } -spin_unlock_irqrestore (get_ccwdev_lock (device->cdev), flags); -dasd_schedule_bh (device);return rc; }/* -* SECTION: Block device operations (request queue, partitions, open, release). +* Schedules a call to dasd_tasklet over the device tasklet. +*/ +void dasd_schedule_block_bh (struct dasd_block *block) +{ +/* Protect against rescheduling. */ +if (atomic_cmpxchg (&block->tasklet_scheduled,0 ,1 ) !=0 ) +return ; +/* life cycle of block is bound to it's base device */ +dasd_get_device (block->base); +tasklet_hi_schedule (&block->tasklet); +} + + +/* +* SECTION: external block device operations +* (request queue handling, open, release, etc.) */ /* * Dasd request queue function. Called from ll_rw_blk.c */ -static void -do_dasd_request (struct request_queue * queue) +static void do_dasd_request (struct request_queue *queue) { -struct dasd_device *device; +struct dasd_block *block; - device = (struct dasd_device *) queue->queuedata; -spin_lock (get_ccwdev_lock (device->cdev)); + block = queue->queuedata; +spin_lock (&block->queue_lock);/* Get new request from the block device request queue */ -__dasd_process_blk_queue (device); +__dasd_process_request_queue (block);/* Now check if the head of the ccw queue needs to be started. */ -__dasd_start_head (device); -spin_unlock (get_ccwdev_lock (device->cdev)); +__dasd_block_start_head (block); +spin_unlock (&block->queue_lock); }/* * Allocate and initialize request queue and default I/O scheduler. */ -static int -dasd_alloc_queue (struct dasd_device * device) +static int dasd_alloc_queue (struct dasd_block *block) {int rc; - device->request_queue =blk_init_queue (do_dasd_request, - &device->request_queue_lock); -if (device->request_queue ==NULL ) + block->request_queue =blk_init_queue (do_dasd_request, + &block->request_queue_lock); +if (block->request_queue ==NULL )return -ENOMEM ; - device->request_queue->queuedata = device; + block->request_queue->queuedata = block; -elevator_exit (device->request_queue->elevator); - rc =elevator_init (device->request_queue,"deadline" ); +elevator_exit (block->request_queue->elevator); + rc =elevator_init (block->request_queue,"deadline" );if (rc) { -blk_cleanup_queue (device->request_queue); +blk_cleanup_queue (block->request_queue);return rc; }return 0 ;
@@ -1780,79 +1977,76 @@ dasd_alloc_queue(struct dasd_device * de/* * Allocate and initialize request queue. */ -static void -dasd_setup_queue (struct dasd_device * device) +static void dasd_setup_queue (struct dasd_block *block) {int max; -blk_queue_hardsect_size (device->request_queue, device->bp_block); - max = device->discipline->max_blocks << device->s2b_shift; -blk_queue_max_sectors (device->request_queue, max); -blk_queue_max_phys_segments (device->request_queue,-1L ); -blk_queue_max_hw_segments (device->request_queue,-1L ); -blk_queue_max_segment_size (device->request_queue,-1L ); -blk_queue_segment_boundary (device->request_queue,-1L ); -blk_queue_ordered (device->request_queue,QUEUE_ORDERED_TAG ,NULL ); +blk_queue_hardsect_size (block->request_queue, block->bp_block); + max = block->base->discipline->max_blocks << block->s2b_shift; +blk_queue_max_sectors (block->request_queue, max); +blk_queue_max_phys_segments (block->request_queue,-1L ); +blk_queue_max_hw_segments (block->request_queue,-1L ); +blk_queue_max_segment_size (block->request_queue,-1L ); +blk_queue_segment_boundary (block->request_queue,-1L ); +blk_queue_ordered (block->request_queue,QUEUE_ORDERED_DRAIN ,NULL ); }/* * Deactivate and free request queue. */ -static void -dasd_free_queue (struct dasd_device * device) +static void dasd_free_queue (struct dasd_block *block) { -if (device->request_queue) { -blk_cleanup_queue (device->request_queue); - device->request_queue =NULL ; +if (block->request_queue) { +blk_cleanup_queue (block->request_queue); + block->request_queue =NULL ; } }/* * Flush request on the request queue. */ -static void -dasd_flush_request_queue (struct dasd_device * device) +static void dasd_flush_request_queue (struct dasd_block *block) {struct request *req; -if (!device->request_queue) +if (!block->request_queue)return ; -spin_lock_irq (&device->request_queue_lock); -while ((req =elv_next_request (device->request_queue))) { +spin_lock_irq (&block->request_queue_lock); +while ((req =elv_next_request (block->request_queue))) {blkdev_dequeue_request (req);dasd_end_request (req,0 ); } -spin_unlock_irq (&device->request_queue_lock); +spin_unlock_irq (&block->request_queue_lock); } -static int -dasd_open (struct inode *inp,struct file *filp) +static int dasd_open (struct inode *inp,struct file *filp) {struct gendisk *disk = inp->i_bdev->bd_disk; -struct dasd_device *device = disk->private_data; +struct dasd_block *block = disk->private_data; +struct dasd_device *base = block->base;int rc; -atomic_inc (&device->open_count); -if (test_bit (DASD_FLAG_OFFLINE , &device->flags)) { +atomic_inc (&block->open_count); +if (test_bit (DASD_FLAG_OFFLINE , &base->flags)) { rc = -ENODEV ; goto unlock; } -if (!try_module_get (device->discipline->owner)) { +if (!try_module_get (base->discipline->owner)) { rc = -EINVAL ; goto unlock; }if (dasd_probeonly) { -DEV_MESSAGE (KERN_INFO , device,"%s" , +DEV_MESSAGE (KERN_INFO , base,"%s" ,"No access to device due to probeonly mode" ); rc = -EPERM ; goto out; } -if (device->state <=DASD_STATE_BASIC ) { -DBF_DEV_EVENT (DBF_ERR , device," %s" , +if (base->state <=DASD_STATE_BASIC ) { +DBF_DEV_EVENT (DBF_ERR , base," %s" ," Cannot open unrecognized device" ); rc = -ENODEV ; goto out;
@@ -1861,41 +2055,41 @@ dasd_open(struct inode *inp, struct filereturn 0 ; out: -module_put (device->discipline->owner); +module_put (base->discipline->owner); unlock: -atomic_dec (&device->open_count); +atomic_dec (&block->open_count);return rc; } -static int -dasd_release (struct inode *inp,struct file *filp) +static int dasd_release (struct inode *inp,struct file *filp) {struct gendisk *disk = inp->i_bdev->bd_disk; -struct dasd_device *device = disk->private_data; +struct dasd_block *block = disk->private_data; -atomic_dec (&device->open_count); -module_put (device->discipline->owner); +atomic_dec (&block->open_count); +module_put (block->base->discipline->owner);return 0 ; }/* * Return disk geometry. */ -static int -dasd_getgeo (struct block_device *bdev,struct hd_geometry *geo) +static int dasd_getgeo (struct block_device *bdev,struct hd_geometry *geo) { -struct dasd_device *device; +struct dasd_block *block; +struct dasd_device *base; - device = bdev->bd_disk->private_data; -if (!device) + block = bdev->bd_disk->private_data; + base = block->base; +if (!block)return -ENODEV ; -if (!device->discipline || - !device->discipline->fill_geometry) +if (!base->discipline || + !base->discipline->fill_geometry)return -EINVAL ; - device->discipline->fill_geometry (device, geo); - geo->start =get_start_sect (bdev) >> device->s2b_shift; + base->discipline->fill_geometry (block, geo); + geo->start =get_start_sect (bdev) >> block->s2b_shift;return 0 ; }
@@ -1909,6 +2103,9 @@ dasd_device_operations = { .getgeo = dasd_getgeo, }; +/******************************************************************************* +* end of block device operations +*/ static void dasd_exit (void )
@@ -1937,9 +2134,8 @@ dasd_exit(void)* Initial attempt at a probe function. this can be simplified once * the other detection code is gone. */ -int -dasd_generic_probe (struct ccw_device *cdev, -struct dasd_discipline *discipline) +int dasd_generic_probe (struct ccw_device *cdev, +struct dasd_discipline *discipline) {int ret;
@@ -1979,10 +2175,10 @@ dasd_generic_probe (struct ccw_device *c* This will one day be called from a global not_oper handler. * It is also used by driver_unregister during module unload. */ -void -dasd_generic_remove (struct ccw_device *cdev) +void dasd_generic_remove (struct ccw_device *cdev) {struct dasd_device *device; +struct dasd_block *block; cdev->handler =NULL ;
@@ -2002,7 +2198,15 @@ dasd_generic_remove (struct ccw_device **/ dasd_set_target_state (device,DASD_STATE_NEW );/* dasd_delete_device destroys the device reference. */ + block = device->block; + device->block =NULL ;dasd_delete_device (device); +/* +* life cycle of block is bound to device, so delete it after +* device was safely removed +*/ +if (block) +dasd_free_block (block); }/*
@@ -2010,10 +2214,8 @@ dasd_generic_remove (struct ccw_device ** the device is detected for the first time and is supposed to be used * or the user has started activation through sysfs. */ -int -dasd_generic_set_online (struct ccw_device *cdev, -struct dasd_discipline *base_discipline) - +int dasd_generic_set_online (struct ccw_device *cdev, +struct dasd_discipline *base_discipline) {struct dasd_discipline *discipline;struct dasd_device *device;
@@ -2049,6 +2251,7 @@ dasd_generic_set_online (struct ccw_devi device->base_discipline = base_discipline; device->discipline = discipline; +/* check_device will allocate block device if necessary */ rc = discipline->check_device (device);if (rc) { printk (KERN_WARNING
@@ -2068,6 +2271,8 @@ dasd_generic_set_online (struct ccw_devi cdev->dev.bus_id); rc = -ENODEV ;dasd_set_target_state (device,DASD_STATE_NEW ); +if (device->block) +dasd_free_block (device->block);dasd_delete_device (device); }else pr_debug("dasd_generic device %s found\n",
@@ -2082,10 +2287,10 @@ dasd_generic_set_online (struct ccw_devireturn rc; } -int -dasd_generic_set_offline (struct ccw_device *cdev) +int dasd_generic_set_offline (struct ccw_device *cdev) {struct dasd_device *device; +struct dasd_block *block;int max_count, open_count; device =dasd_device_from_cdev (cdev);
@@ -2102,30 +2307,39 @@ dasd_generic_set_offline (struct ccw_dev* the blkdev_get in dasd_scan_partitions. We are only interested * in the other openers. */ - max_count = device->bdev ?0 :-1 ; - open_count = (int )atomic_read (&device->open_count); -if (open_count > max_count) { -if (open_count >0 ) -printk (KERN_WARNING "Can't offline dasd device with " -"open count = %i.\n" , - open_count); -else -printk (KERN_WARNING "%s" , -"Can't offline dasd device due to internal " -"use\n" ); -clear_bit (DASD_FLAG_OFFLINE , &device->flags); -dasd_put_device (device); -return -EBUSY ; +if (device->block) { +struct dasd_block *block = device->block; + max_count = block->bdev ?0 :-1 ; + open_count = (int )atomic_read (&block->open_count); +if (open_count > max_count) { +if (open_count >0 ) +printk (KERN_WARNING "Can't offline dasd " +"device with open count = %i.\n" , + open_count); +else +printk (KERN_WARNING "%s" , +"Can't offline dasd device due " +"to internal use\n" ); +clear_bit (DASD_FLAG_OFFLINE , &device->flags); +dasd_put_device (device); +return -EBUSY ; + } }dasd_set_target_state (device,DASD_STATE_NEW );/* dasd_delete_device destroys the device reference. */ + block = device->block; + device->block =NULL ;dasd_delete_device (device); - +/* +* life cycle of block is bound to device, so delete it after +* device was safely removed +*/ +if (block) +dasd_free_block (block);return 0 ; } -int -dasd_generic_notify (struct ccw_device *cdev,int event) +int dasd_generic_notify (struct ccw_device *cdev,int event) {struct dasd_device *device;struct dasd_ccw_req *cqr;
@@ -2146,27 +2360,22 @@ dasd_generic_notify(struct ccw_device *cif (device->state <DASD_STATE_BASIC )break ;/* Device is active. We want to keep it. */ -if (test_bit (DASD_FLAG_DSC_ERROR , &device->flags)) { -list_for_each_entry (cqr, &device->ccw_queue, list) -if (cqr->status ==DASD_CQR_IN_IO ) - cqr->status =DASD_CQR_FAILED ; - device->stopped |=DASD_STOPPED_DC_EIO ; - }else { -list_for_each_entry (cqr, &device->ccw_queue, list) -if (cqr->status ==DASD_CQR_IN_IO ) { - cqr->status =DASD_CQR_QUEUED ; - cqr->retries++; - } - device->stopped |=DASD_STOPPED_DC_WAIT ; -dasd_set_timer (device,0 ); - } -dasd_schedule_bh (device); +list_for_each_entry (cqr, &device->ccw_queue, devlist) +if (cqr->status ==DASD_CQR_IN_IO ) { + cqr->status =DASD_CQR_QUEUED ; + cqr->retries++; + } + device->stopped |=DASD_STOPPED_DC_WAIT ; +dasd_device_clear_timer (device); +dasd_schedule_device_bh (device); ret =1 ;break ;case CIO_OPER :/* FIXME: add a sanity check. */ - device->stopped &= ~(DASD_STOPPED_DC_WAIT |DASD_STOPPED_DC_EIO ); -dasd_schedule_bh (device); + device->stopped &= ~DASD_STOPPED_DC_WAIT ; +dasd_schedule_device_bh (device); +if (device->block) +dasd_schedule_block_bh (device->block); ret =1 ;break ; }
@@ -2196,7 +2405,8 @@ static struct dasd_ccw_req *dasd_generic ccw->cda = (__u32 )(addr_t )rdc_buffer; ccw->count = rdc_buffer_size; - cqr->device = device; + cqr->startdev = device; + cqr->memdev = device; cqr->expires =10 *HZ ;clear_bit (DASD_CQR_FLAGS_USE_ERP , &cqr->flags); cqr->retries =2 ;
@@ -2218,13 +2428,12 @@ int dasd_generic_read_dev_chars(struct dreturn PTR_ERR (cqr); ret =dasd_sleep_on (cqr); -dasd_sfree_request (cqr, cqr->device); +dasd_sfree_request (cqr, cqr->memdev);return ret; }EXPORT_SYMBOL_GPL (dasd_generic_read_dev_chars); -static int __init -dasd_init (void ) +static int __init dasd_init (void ) {int rc;
@@ -2232,7 +2441,7 @@ dasd_init(void)init_waitqueue_head (&dasd_flush_wq);/* register 'common' DASD debug area, used for all DBF_XXX calls */ - dasd_debug_area =debug_register ("dasd" ,1 ,2 ,8 *sizeof (long )); + dasd_debug_area =debug_register ("dasd" ,1 ,2 ,8 *sizeof (long ));if (dasd_debug_area ==NULL ) { rc = -ENOMEM ; goto failed;
@@ -2278,15 +2487,18 @@ EXPORT_SYMBOL(dasd_diag_discipline_pointEXPORT_SYMBOL (dasd_add_request_head);EXPORT_SYMBOL (dasd_add_request_tail);EXPORT_SYMBOL (dasd_cancel_req); -EXPORT_SYMBOL (dasd_clear_timer); +EXPORT_SYMBOL (dasd_device_clear_timer); +EXPORT_SYMBOL (dasd_block_clear_timer);EXPORT_SYMBOL (dasd_enable_device);EXPORT_SYMBOL (dasd_int_handler);EXPORT_SYMBOL (dasd_kfree_request);EXPORT_SYMBOL (dasd_kick_device);EXPORT_SYMBOL (dasd_kmalloc_request); -EXPORT_SYMBOL (dasd_schedule_bh); +EXPORT_SYMBOL (dasd_schedule_device_bh); +EXPORT_SYMBOL (dasd_schedule_block_bh);EXPORT_SYMBOL (dasd_set_target_state); -EXPORT_SYMBOL (dasd_set_timer); +EXPORT_SYMBOL (dasd_device_set_timer); +EXPORT_SYMBOL (dasd_block_set_timer);EXPORT_SYMBOL (dasd_sfree_request);EXPORT_SYMBOL (dasd_sleep_on);EXPORT_SYMBOL (dasd_sleep_on_immediatly);
@@ -2300,4 +2512,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);EXPORT_SYMBOL_GPL (dasd_generic_notify);EXPORT_SYMBOL_GPL (dasd_generic_set_online);EXPORT_SYMBOL_GPL (dasd_generic_set_offline); - +EXPORT_SYMBOL_GPL (dasd_generic_handle_state_change); +EXPORT_SYMBOL_GPL (dasd_flush_device_queue); +EXPORT_SYMBOL_GPL (dasd_alloc_block); +EXPORT_SYMBOL_GPL (dasd_free_block);
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 47/47 dasd: add hyper PAV support to DASD device driver, part 3
In reply to Martin SchwidefskyFrom: Stefan Weinhuber <[email protected]>
---
drivers/s390/block/dasd_devmap.c | 94 +--- drivers/s390/block/dasd_diag.c | 107 +++-- drivers/s390/block/dasd_eckd.c | 780 ++++++++++++++++++++++++++++----------- drivers/s390/block/dasd_eckd.h | 125 ++++++ drivers/s390/block/dasd_eer.c | 11 drivers/s390/block/dasd_erp.c | 25 - drivers/s390/block/dasd_fba.c | 114 +++-- drivers/s390/block/dasd_genhd.c | 76 +-- 8 files changed, 912 insertions(+), 420 deletions(-)
drivers/s390/block/dasd_devmap.c +37 -57
@@ -49,22 +49,6 @@ struct dasd_devmap { };/* -* dasd_server_ssid_map contains a globally unique storage server subsystem ID. -* dasd_server_ssid_list contains the list of all subsystem IDs accessed by -* the DASD device driver. -*/ -struct dasd_server_ssid_map { -struct list_head list; -struct system_id { -char vendor[4 ]; -char serial[15 ]; -__u16 ssid; - } sid; -}; - -static struct list_head dasd_server_ssid_list; - -/* * Parameter parsing functions for dasd= parameter. The syntax is: * <devno> : (0x)?[0-9a-fA-F]+ * <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
@@ -721,8 +705,9 @@ dasd_ro_store(struct device *dev, struct devmap->features &= ~DASD_FEATURE_READONLY ;if (devmap->device) devmap->device->features = devmap->features; -if (devmap->device && devmap->device->gdp) -set_disk_ro (devmap->device->gdp, val); +if (devmap->device && devmap->device->block + && devmap->device->block->gdp) +set_disk_ro (devmap->device->block->gdp, val);spin_unlock (&dasd_devmap_lock);return count; }
@@ -893,12 +878,16 @@ dasd_alias_show(struct device *dev, stru devmap =dasd_find_busid (dev->bus_id);spin_lock (&dasd_devmap_lock); -if (!IS_ERR (devmap)) - alias = devmap->uid.alias; +if (IS_ERR (devmap) ||strlen (devmap->uid.vendor) ==0 ) { +spin_unlock (&dasd_devmap_lock); +return sprintf (buf,"0\n" ); + } +if (devmap->uid.type ==UA_BASE_PAV_ALIAS || + devmap->uid.type ==UA_HYPER_PAV_ALIAS ) + alias =1 ;else alias =0 ;spin_unlock (&dasd_devmap_lock); -return sprintf (buf, alias ?"1\n" :"0\n" ); }
@@ -930,19 +919,36 @@ static ssize_t dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dasd_devmap *devmap; -char uid[UID_STRLEN ]; +char uid_string[UID_STRLEN ]; +char ua_string[3 ]; +struct dasd_uid *uid; devmap =dasd_find_busid (dev->bus_id);spin_lock (&dasd_devmap_lock); -if (!IS_ERR (devmap) &&strlen (devmap->uid.vendor) >0 ) -snprintf (uid,sizeof (uid),"%s.%s.%04x.%02x" , - devmap->uid.vendor, devmap->uid.serial, - devmap->uid.ssid, devmap->uid.unit_addr); -else - uid[0 ] =0 ; +if (IS_ERR (devmap) ||strlen (devmap->uid.vendor) ==0 ) { +spin_unlock (&dasd_devmap_lock); +return sprintf (buf,"\n" ); + } + uid = &devmap->uid; +switch (uid->type) { +case UA_BASE_DEVICE : +sprintf (ua_string,"%02x" , uid->real_unit_addr); +break ; +case UA_BASE_PAV_ALIAS : +sprintf (ua_string,"%02x" , uid->base_unit_addr); +break ; +case UA_HYPER_PAV_ALIAS : +sprintf (ua_string,"xx" ); +break ; +default : +/* should not happen, treat like base device */ +sprintf (ua_string,"%02x" , uid->real_unit_addr); +break ; + } +snprintf (uid_string,sizeof (uid_string),"%s.%s.%04x.%s" , + uid->vendor, uid->serial, uid->ssid, ua_string);spin_unlock (&dasd_devmap_lock); - -return snprintf (buf,PAGE_SIZE ,"%s\n" , uid); +return snprintf (buf,PAGE_SIZE ,"%s\n" , uid_string); } static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
@@ -1040,39 +1046,16 @@ int dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) { struct dasd_devmap *devmap; -struct dasd_server_ssid_map *srv, *tmp; devmap =dasd_find_busid (cdev->dev.bus_id);if (IS_ERR (devmap))return PTR_ERR (devmap); -/* generate entry for server_ssid_map */ - srv = (struct dasd_server_ssid_map *) -kzalloc (sizeof (struct dasd_server_ssid_map ),GFP_KERNEL ); -if (!srv) -return -ENOMEM ; -strncpy (srv->sid.vendor, uid->vendor,sizeof (srv->sid.vendor) -1 ); -strncpy (srv->sid.serial, uid->serial,sizeof (srv->sid.serial) -1 ); - srv->sid.ssid = uid->ssid; - -/* server is already contained ? */ spin_lock (&dasd_devmap_lock); devmap->uid = *uid; -list_for_each_entry (tmp, &dasd_server_ssid_list, list) { -if (!memcmp (&srv->sid, &tmp->sid, -sizeof (struct system_id ))) { -kfree (srv); - srv =NULL ; -break ; - } - } - -/* add servermap to serverlist */ -if (srv) -list_add (&srv->list, &dasd_server_ssid_list);spin_unlock (&dasd_devmap_lock); -return (srv ?1 :0 ); +return 0 ; }EXPORT_SYMBOL_GPL (dasd_set_uid);
@@ -1138,9 +1121,6 @@ dasd_devmap_init(void) dasd_max_devindex =0 ;for (i =0 ; i <256 ; i++)INIT_LIST_HEAD (&dasd_hashlists[i]); - -/* Initialize servermap structure. */ -INIT_LIST_HEAD (&dasd_server_ssid_list);return 0 ; }
drivers/s390/block/dasd_diag.c +60 -47
248 lines not on this page · raw message
drivers/s390/block/dasd_eckd.c +572 -208
1,229 lines not on this page · raw message
drivers/s390/block/dasd_eckd.h +124 -1
153 lines not on this page · raw message
drivers/s390/block/dasd_eer.c +6 -5
@@ -336,7 +336,7 @@ static void dasd_eer_write_snss_trigger(unsigned long flags;struct eerbuffer *eerb; - snss_rc = (cqr->status ==DASD_CQR_FAILED ) ? -EIO :0 ; + snss_rc = (cqr->status ==DASD_CQR_DONE ) ?0 : -EIO ;if (snss_rc) data_size =0 ;else
@@ -404,10 +404,11 @@ void dasd_eer_snss(struct dasd_device *dset_bit (DASD_FLAG_EER_SNSS , &device->flags);return ; } +/* cdev is already locked, can't use dasd_add_request_head */ clear_bit (DASD_FLAG_EER_SNSS , &device->flags); cqr->status =DASD_CQR_QUEUED ; -list_add (&cqr->list, &device->ccw_queue); -dasd_schedule_bh (device); +list_add (&cqr->devlist, &device->ccw_queue); +dasd_schedule_device_bh (device); }/*
@@ -415,7 +416,7 @@ void dasd_eer_snss(struct dasd_device *d*/ static void dasd_eer_snss_cb (struct dasd_ccw_req *cqr,void *data) { -struct dasd_device *device = cqr->device; +struct dasd_device *device = cqr->startdev;unsigned long flags;dasd_eer_write (device, cqr,DASD_EER_STATECHANGE );
@@ -458,7 +459,7 @@ int dasd_eer_enable(struct dasd_device *if (!cqr)return -ENOMEM ; - cqr->device = device; + cqr->startdev = device; cqr->retries =255 ; cqr->expires =10 *HZ ;clear_bit (DASD_CQR_FLAGS_USE_ERP , &cqr->flags);
drivers/s390/block/dasd_erp.c +12 -13
@@ -46,6 +46,8 @@ dasd_alloc_erp_request(char *magic, intif (cqr ==NULL )return ERR_PTR (-ENOMEM );memset (cqr,0 ,sizeof (struct dasd_ccw_req )); +INIT_LIST_HEAD (&cqr->devlist); +INIT_LIST_HEAD (&cqr->blocklist); data = (char *) cqr + ((sizeof (struct dasd_ccw_req ) +7L ) &-8L ); cqr->cpaddr =NULL ;if (cplength >0 ) {
@@ -66,7 +68,7 @@ dasd_alloc_erp_request(char *magic, int }void -dasd_free_erp_request (struct dasd_ccw_req * cqr,struct dasd_device * device) +dasd_free_erp_request (struct dasd_ccw_req *cqr,struct dasd_device * device) {unsigned long flags;
@@ -81,11 +83,11 @@ dasd_free_erp_request(struct dasd_ccw_re* dasd_default_erp_action just retries the current cqr */ struct dasd_ccw_req * -dasd_default_erp_action (struct dasd_ccw_req * cqr) +dasd_default_erp_action (struct dasd_ccw_req *cqr) {struct dasd_device *device; - device = cqr->device; + device = cqr->startdev;/* just retry - there is nothing to save ... I got no sense data.... */ if (cqr->retries >0 ) {
@@ -93,12 +95,12 @@ dasd_default_erp_action(struct dasd_ccw_"default ERP called (%i retries left)" , cqr->retries); cqr->lpm =LPM_ANYPATH ; - cqr->status =DASD_CQR_QUEUED ; + cqr->status =DASD_CQR_FILLED ; }else {DEV_MESSAGE (KERN_WARNING , device,"%s" ,"default ERP called (NO retry left)" ); cqr->status =DASD_CQR_FAILED ; - cqr->stopclk =get_clock (); + cqr->stopclk =get_clock (); }return cqr; }/* end dasd_default_erp_action */
@@ -117,15 +119,12 @@ dasd_default_erp_action(struct dasd_ccw_* RETURN VALUES * cqr pointer to the original CQR */ -struct dasd_ccw_req * -dasd_default_erp_postaction (struct dasd_ccw_req * cqr) +struct dasd_ccw_req *dasd_default_erp_postaction (struct dasd_ccw_req *cqr) { -struct dasd_device *device;int success;BUG_ON (cqr->refers ==NULL || cqr->function ==NULL ); - device = cqr->device; success = cqr->status ==DASD_CQR_DONE ;/* free all ERPs - but NOT the original cqr */
@@ -133,10 +132,10 @@ dasd_default_erp_postaction(struct dasd_struct dasd_ccw_req *refers; refers = cqr->refers; -/* remove the request from the device queue */ -list_del (&cqr->list); +/* remove the request from the block queue */ +list_del (&cqr->blocklist);/* free the finished erp request */ -dasd_free_erp_request (cqr, device); +dasd_free_erp_request (cqr, cqr->memdev); cqr = refers; }
@@ -157,7 +156,7 @@ dasd_log_sense(struct dasd_ccw_req *cqr, {struct dasd_device *device; - device = cqr->device; + device = cqr->startdev;/* dump sense data */ if (device->discipline && device->discipline->dump_sense) device->discipline->dump_sense (device, cqr, irb);
drivers/s390/block/dasd_fba.c +65 -49
227 lines not on this page · raw message
drivers/s390/block/dasd_genhd.c +36 -40
160 lines not on this page · raw message
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.