dasd_devmap.c revision a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6e
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * File...........: linux/drivers/s390/block/dasd_devmap.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		    Horst Hummel <Horst.Hummel@de.ibm.com>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		    Carsten Otte <Cotte@de.ibm.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bugreports.to..: <Linux390@de.ibm.com>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device mapping and dasd= parameter parsing functions. All devmap
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * functions may not be called from interrupt context. In particular
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dasd_get_device is a no-no from interrupt context.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ctype.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
188d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russell#include <linux/module.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/debug.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is ugly... */
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PRINTK_HEADER "dasd_devmap:"
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "dasd_int.h"
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskmem_cache_t *dasd_page_cache;
29405455734e1cdec09c37233216f9240cb1a058e5Horst HummelEXPORT_SYMBOL_GPL(dasd_page_cache);
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dasd_devmap_t is used to store the features and the relation
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * between device number and device index. To find a dasd_devmap_t
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that corresponds to a device number of a device index each
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dasd_devmap_t is added to two linked lists, one to search by
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the device number and one to search by the device index. As
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * soon as big minor numbers are available the device index list
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can be removed since the device number will then be identical
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the device index.
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dasd_devmap {
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head list;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char bus_id[BUS_ID_SIZE];
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        unsigned int devindex;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        unsigned short features;
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_device *device;
473d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	struct dasd_uid uid;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
51b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter * dasd_server_ssid_map contains a globally unique storage server subsystem ID.
52b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter * dasd_server_ssid_list contains the list of all subsystem IDs accessed by
53b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter * the DASD device driver.
54405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel */
55b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiterstruct dasd_server_ssid_map {
56405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	struct list_head list;
578e79a441a4d8a34d64efe93add49b3eefca5cd1cHorst Hummel	struct system_id {
58405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel		char vendor[4];
59405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel		char serial[15];
608e79a441a4d8a34d64efe93add49b3eefca5cd1cHorst Hummel		__u16 ssid;
61405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	} sid;
62405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel};
63405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel
64b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiterstatic struct list_head dasd_server_ssid_list;
65405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel
66405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel/*
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parameter parsing functions for dasd= parameter. The syntax is:
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <devno>		: (0x)?[0-9a-fA-F]+
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <busid>		: [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <feature>		: ro
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <feature_list>	: \(<feature>(:<feature>)*\)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <devno-range>	: <devno>(-<devno>)?<feature_list>?
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <busid-range>	: <busid>(-<busid>)?<feature_list>?
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <devices>		: <devno-range>|<busid-range>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <dasd_module>	: dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   <dasd>		: autodetect|probeonly|<devices>(,<devices>)*
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dasd_probeonly =  0;	/* is true, when probeonly mode is active */
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dasd_autodetect = 0;	/* is true, when autodetection is active */
82405455734e1cdec09c37233216f9240cb1a058e5Horst Hummelint dasd_nopav = 0;		/* is true, when PAV is disabled */
83405455734e1cdec09c37233216f9240cb1a058e5Horst HummelEXPORT_SYMBOL_GPL(dasd_nopav);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is named 'dasd' to directly be filled by insmod with the comma separated
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * strings when running as a module.
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *dasd[256];
918d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param_array(dasd, charp, NULL, 0);
928d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russell
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
94d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel * Single spinlock to protect devmap and servermap structures and lists.
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(dasd_devmap_lock);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hash lists for devmap structures.
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct list_head dasd_hashlists[256];
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint dasd_max_devindex;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dasd_devmap *dasd_add_busid(char *, int);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_hash_busid(char *bus_id)
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int hash, i;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash = 0;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; (i < BUS_ID_SIZE) && *bus_id; i++, bus_id++)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hash += *bus_id;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return hash & 0xff;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The parameter parsing functions for builtin-drivers are called
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * before kmalloc works. Store the pointers to the parameters strings
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into dasd[] for later processing.
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_call_setup(char *str)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int count = 0;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (count < 256)
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dasd[count++] = str;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup ("dasd=", dasd_call_setup);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif	/* #ifndef MODULE */
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read a device busid/devno from a string.
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_busid(char **str, int *id0, int *id1, int *devno)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int val, old_style;
143138c014dcba74211dc4e835658f34a787c40cf17Horst Hummel
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check for leading '0x' */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	old_style = 0;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((*str)[0] == '0' && (*str)[1] == 'x') {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*str += 2;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		old_style = 1;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!isxdigit((*str)[0]))	/* We require at least one hex digit */
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(*str, str, 16);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (old_style || (*str)[0] != '.') {
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*id0 = *id1 = 0;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (val < 0 || val > 0xffff)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*devno = val;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* New style x.y.z busid */
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val < 0 || val > 0xff)
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*id0 = val;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(*str)++;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!isxdigit((*str)[0]))	/* We require at least one hex digit */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(*str, str, 16);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val < 0 || val > 0xff || (*str)++[0] != '.')
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*id1 = val;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!isxdigit((*str)[0]))	/* We require at least one hex digit */
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val = simple_strtoul(*str, str, 16);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (val < 0 || val > 0xffff)
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*devno = val;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read colon separated list of dasd features. Currently there is
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only one: "ro" for read-only devices. The default feature set
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is empty (value 0).
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_feature_list(char *str, char **endp)
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int features, len, rc;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 0;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*str != '(') {
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*endp = str;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return DASD_FEATURE_DEFAULT;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	str++;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	features = 0;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (1) {
199138c014dcba74211dc4e835658f34a787c40cf17Horst Hummel		for (len = 0;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     str[len] && str[len] != ':' && str[len] != ')'; len++);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len == 2 && !strncmp(str, "ro", 2))
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			features |= DASD_FEATURE_READONLY;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (len == 4 && !strncmp(str, "diag", 4))
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			features |= DASD_FEATURE_USEDIAG;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			MESSAGE(KERN_WARNING,
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"unsupported feature: %*s, "
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"ignoring setting", len, str);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = -EINVAL;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		str += len;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*str != ':')
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		str++;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*str != ')') {
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MESSAGE(KERN_WARNING, "%s",
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"missing ')' in dasd parameter string\n");
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EINVAL;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		str++;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*endp = str;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc != 0)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return features;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to match the first element on the comma separated parse string
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with one of the known keywords. If a keyword is found, take the approprate
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * action and return a pointer to the residual string. If the first element
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * could not be matched to any keyword then return an error code.
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_parse_keyword( char *parsestring ) {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *nextcomma, *residual_str;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int length;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	nextcomma = strchr(parsestring,',');
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (nextcomma) {
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		length = nextcomma - parsestring;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		residual_str = nextcomma + 1;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		length = strlen(parsestring);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		residual_str = parsestring + length;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
248405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	if (strncmp("autodetect", parsestring, length) == 0) {
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dasd_autodetect = 1;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MESSAGE (KERN_INFO, "%s",
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 "turning to autodetection mode");
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return residual_str;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
254405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	if (strncmp("probeonly", parsestring, length) == 0) {
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dasd_probeonly = 1;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MESSAGE(KERN_INFO, "%s",
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"turning to probeonly mode");
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return residual_str;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
260405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	if (strncmp("nopav", parsestring, length) == 0) {
261405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel		dasd_nopav = 1;
262405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel		MESSAGE(KERN_INFO, "%s", "disable PAV mode");
263405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel		return residual_str;
264405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	}
265405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	if (strncmp("fixedbuffers", parsestring, length) == 0) {
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dasd_page_cache)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return residual_str;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dasd_page_cache =
2692f6c55fc3109bcfa1bb1a112c825e07212c20f37Heiko Carstens			kmem_cache_create("dasd_page_cache", PAGE_SIZE,
2702f6c55fc3109bcfa1bb1a112c825e07212c20f37Heiko Carstens					  PAGE_SIZE, SLAB_CACHE_DMA,
2712f6c55fc3109bcfa1bb1a112c825e07212c20f37Heiko Carstens					  NULL, NULL );
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!dasd_page_cache)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"fixed buffer mode disabled.");
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			MESSAGE (KERN_INFO, "%s",
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "turning on fixed buffer mode");
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return residual_str;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(-EINVAL);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to interprete the first element on the comma separated parse string
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as a device number or a range of devices. If the interpretation is
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * successfull, create the matching dasd_devmap entries and return a pointer
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the residual string.
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If interpretation fails or in case of an error, return an error code.
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_parse_range( char *parsestring ) {
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int from, from_id0, from_id1;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int to, to_id0, to_id1;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int features, rc;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char bus_id[BUS_ID_SIZE+1], *str;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	str = parsestring;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = dasd_busid(&str, &from_id0, &from_id1, &from);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc == 0) {
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to = from;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_id0 = from_id0;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to_id1 = from_id1;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (*str == '-') {
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			str++;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = dasd_busid(&str, &to_id0, &to_id1, &to);
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc == 0 &&
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (from_id0 != to_id0 || from_id1 != to_id1 || from > to))
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EINVAL;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		MESSAGE(KERN_ERR, "Invalid device range %s", parsestring);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(rc);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	features = dasd_feature_list(str, &str);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (features < 0)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-EINVAL);
320405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	/* each device in dasd= parameter should be set initially online */
321405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	features |= DASD_FEATURE_INITIAL_ONLINE;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (from <= to) {
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sprintf(bus_id, "%01x.%01x.%04x",
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			from_id0, from_id1, from++);
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devmap = dasd_add_busid(bus_id, features);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (IS_ERR(devmap))
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return (char *)devmap;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*str == ',')
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return str + 1;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (*str == '\0')
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return str;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MESSAGE(KERN_WARNING,
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"junk at end of dasd parameter string: %s\n", str);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(-EINVAL);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline char *
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_parse_next_element( char *parsestring ) {
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char * residual_str;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	residual_str = dasd_parse_keyword(parsestring);
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!IS_ERR(residual_str))
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return residual_str;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	residual_str = dasd_parse_range(parsestring);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return residual_str;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parse parameters stored in dasd[]
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The 'dasd=...' parameter allows to specify a comma separated list of
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * keywords and device ranges. When the dasd driver is build into the kernel,
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the complete list will be stored as one element of the dasd[] array.
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When the dasd driver is build as a module, then the list is broken into
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it's elements and each dasd[] entry contains one element.
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_parse(void)
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc, i;
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *parsestring;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 0;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 256; i++) {
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dasd[i] == NULL)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		parsestring = dasd[i];
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* loop over the comma separated list in the parsestring */
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (*parsestring) {
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			parsestring = dasd_parse_next_element(parsestring);
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(IS_ERR(parsestring)) {
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rc = PTR_ERR(parsestring);
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rc) {
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add a devmap for the device specified by busid. It is possible that
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the devmap already exists (dasd= parameter). The order of the devices
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * added through this function will define the kdevs for the individual
387138c014dcba74211dc4e835658f34a787c40cf17Horst Hummel * devices.
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dasd_devmap *
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_add_busid(char *bus_id, int features)
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap, *new, *tmp;
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int hash;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	new = (struct dasd_devmap *)
396138c014dcba74211dc4e835658f34a787c40cf17Horst Hummel		kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!new)
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(-ENOMEM);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&dasd_devmap_lock);
400d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens	devmap = NULL;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash = dasd_hash_busid(bus_id);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(tmp, &dasd_hashlists[hash], list)
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			devmap = tmp;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!devmap) {
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This bus_id is new. */
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new->devindex = dasd_max_devindex++;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new->features = features;
412d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens		new->device = NULL;
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_add(&new->list, &dasd_hashlists[hash]);
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devmap = new;
415d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens		new = NULL;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&dasd_devmap_lock);
41817fd682e544556a2a829e94383239c029bb21c5eJesper Juhl	kfree(new);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return devmap;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find devmap for device with given bus_id.
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dasd_devmap *
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_find_busid(char *bus_id)
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap, *tmp;
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int hash;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&dasd_devmap_lock);
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap = ERR_PTR(-ENODEV);
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hash = dasd_hash_busid(bus_id);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(tmp, &dasd_hashlists[hash], list) {
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			devmap = tmp;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&dasd_devmap_lock);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return devmap;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check if busid has been added to the list of dasd ranges.
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_busid_known(char *bus_id)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Forget all about the device numbers added so far.
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This may only be called at module unload or system shutdown.
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_forget_ranges(void)
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap, *n;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&dasd_devmap_lock);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 256; i++) {
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) {
466606f44228e257ea1e35557c2fec7133cca634096Eric Sesterhenn			BUG_ON(devmap->device != NULL);
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			list_del(&devmap->list);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(devmap);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&dasd_devmap_lock);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Find the device struct by its device index.
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dasd_device *
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_device_from_devindex(int devindex)
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap, *tmp;
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_device *device;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&dasd_devmap_lock);
485d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens	devmap = NULL;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; (i < 256) && !devmap; i++)
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		list_for_each_entry(tmp, &dasd_hashlists[i], list)
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (tmp->devindex == devindex) {
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Found the devmap for the device. */
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				devmap = tmp;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (devmap && devmap->device) {
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device = devmap->device;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dasd_get_device(device);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device = ERR_PTR(-ENODEV);
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&dasd_devmap_lock);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return device;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return devmap for cdev. If no devmap exists yet, create one and
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * connect it to the cdev.
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct dasd_devmap *
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_devmap_from_cdev(struct ccw_device *cdev)
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap = dasd_find_busid(cdev->dev.bus_id);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(devmap))
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devmap = dasd_add_busid(cdev->dev.bus_id,
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					DASD_FEATURE_DEFAULT);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return devmap;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Create a dasd device structure for cdev.
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dasd_device *
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_create_device(struct ccw_device *cdev)
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_device *device;
526a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	unsigned long flags;
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap = dasd_devmap_from_cdev(cdev);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(devmap))
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (void *) devmap;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device = dasd_alloc_device();
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(device))
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return device;
536a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	atomic_set(&device->ref_count, 3);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&dasd_devmap_lock);
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!devmap->device) {
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devmap->device = device;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device->devindex = devmap->devindex;
542c6eb7b7703ac4b3401b74f411c8c51ded214bf19Horst Hummel		device->features = devmap->features;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		get_device(&cdev->dev);
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		device->cdev = cdev;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = 0;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Someone else was faster. */
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EBUSY;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&dasd_devmap_lock);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc) {
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dasd_free_device(device);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ERR_PTR(rc);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
555a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky
556a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
557a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	cdev->dev.driver_data = device;
558a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
559a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return device;
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait queue for dasd_delete_device waits.
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq);
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove a dasd device structure. The passed referenced
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is destroyed.
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_delete_device(struct dasd_device *device)
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ccw_device *cdev;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap;
577a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	unsigned long flags;
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* First remove device pointer from devmap. */
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap = dasd_find_busid(device->cdev->dev.bus_id);
581606f44228e257ea1e35557c2fec7133cca634096Eric Sesterhenn	BUG_ON(IS_ERR(devmap));
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&dasd_devmap_lock);
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (devmap->device != device) {
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&dasd_devmap_lock);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dasd_put_device(device);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap->device = NULL;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&dasd_devmap_lock);
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	/* Disconnect dasd_device structure from ccw_device structure. */
592a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
593a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	device->cdev->dev.driver_data = NULL;
594a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
595a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky
596a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	/*
597a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	 * Drop ref_count by 3, one for the devmap reference, one for
598a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	 * the cdev reference and one for the passed reference.
599a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	 */
600a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	atomic_sub(3, &device->ref_count);
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait for reference counter to drop to zero. */
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Disconnect dasd_device structure from ccw_device structure. */
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cdev = device->cdev;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	device->cdev = NULL;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Put ccw_device structure. */
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	put_device(&cdev->dev);
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Now the device structure can be freed. */
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dasd_free_device(device);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reference counter dropped to zero. Wake up waiter
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in dasd_delete_device.
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_put_device_wake(struct dasd_device *device)
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wake_up(&dasd_delete_wq);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return dasd_device structure associated with cdev.
628a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky * This function needs to be called with the ccw device
629a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky * lock held. It can be used from interrupt context.
630a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky */
631a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefskystruct dasd_device *
632a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefskydasd_device_from_cdev_locked(struct ccw_device *cdev)
633a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky{
634a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	struct dasd_device *device = cdev->dev.driver_data;
635a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky
636a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	if (!device)
637a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky		return ERR_PTR(-ENODEV);
638a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	dasd_get_device(device);
639a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	return device;
640a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky}
641a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky
642a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky/*
643a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky * Return dasd_device structure associated with cdev.
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct dasd_device *
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_device_from_cdev(struct ccw_device *cdev)
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_device *device;
649a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	unsigned long flags;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
652a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	device = dasd_device_from_cdev_locked(cdev);
653a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return device;
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SECTION: files in sysfs
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * readonly controls the readonly status of a dasd
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
665e404e274f62665f3333d6a539d0d3701f678a598Yani Ioannoudasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap;
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ro_flag;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap = dasd_find_busid(dev->bus_id);
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!IS_ERR(devmap))
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0;
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf(buf, PAGE_SIZE, ro_flag ? "1\n" : "0\n");
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
679138c014dcba74211dc4e835658f34a787c40cf17Horst Hummeldasd_ro_store(struct device *dev, struct device_attribute *attr,
680138c014dcba74211dc4e835658f34a787c40cf17Horst Hummel	      const char *buf, size_t count)
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ro_flag;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(devmap))
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(devmap);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ro_flag = buf[0] == '1';
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&dasd_devmap_lock);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ro_flag)
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devmap->features |= DASD_FEATURE_READONLY;
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		devmap->features &= ~DASD_FEATURE_READONLY;
694c6eb7b7703ac4b3401b74f411c8c51ded214bf19Horst Hummel	if (devmap->device)
695c6eb7b7703ac4b3401b74f411c8c51ded214bf19Horst Hummel		devmap->device->features = devmap->features;
696f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	if (devmap->device && devmap->device->gdp)
697f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel		set_disk_ro(devmap->device->gdp, ro_flag);
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&dasd_devmap_lock);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * use_diag controls whether the driver should use diag rather than ssch
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to talk to the device
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
708138c014dcba74211dc4e835658f34a787c40cf17Horst Hummelstatic ssize_t
709e404e274f62665f3333d6a539d0d3701f678a598Yani Ioannoudasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int use_diag;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap = dasd_find_busid(dev->bus_id);
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!IS_ERR(devmap))
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sprintf(buf, use_diag ? "1\n" : "0\n");
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
723138c014dcba74211dc4e835658f34a787c40cf17Horst Hummeldasd_use_diag_store(struct device *dev, struct device_attribute *attr,
724138c014dcba74211dc4e835658f34a787c40cf17Horst Hummel		    const char *buf, size_t count)
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct dasd_devmap *devmap;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ssize_t rc;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int use_diag;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(devmap))
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(devmap);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	use_diag = buf[0] == '1';
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&dasd_devmap_lock);
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Changing diag discipline flag is only allowed in offline state. */
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = count;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!devmap->device) {
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (use_diag)
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			devmap->features |= DASD_FEATURE_USEDIAG;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			devmap->features &= ~DASD_FEATURE_USEDIAG;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = -EPERM;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&dasd_devmap_lock);
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
748138c014dcba74211dc4e835658f34a787c40cf17Horst Hummelstatic DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
751138c014dcba74211dc4e835658f34a787c40cf17Horst Hummeldasd_discipline_show(struct device *dev, struct device_attribute *attr,
752138c014dcba74211dc4e835658f34a787c40cf17Horst Hummel		     char *buf)
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
754a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	struct dasd_device *device;
755a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	ssize_t len;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
757a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	device = dasd_device_from_cdev(to_ccwdev(dev));
758a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	if (!IS_ERR(device) && device->discipline) {
759a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky		len = snprintf(buf, PAGE_SIZE, "%s\n",
760a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky			       device->discipline->name);
761a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky		dasd_put_device(device);
762a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	} else
763a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky		len = snprintf(buf, PAGE_SIZE, "none\n");
764a00bfd7147c0c5c04a59f7adcb0e6d8948b90a6eMartin Schwidefsky	return len;
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7693d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummelstatic ssize_t
7703d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummeldasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
7713d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel{
7723d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	struct dasd_devmap *devmap;
7733d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	int alias;
7743d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
7753d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	devmap = dasd_find_busid(dev->bus_id);
7763d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_lock(&dasd_devmap_lock);
7773d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	if (!IS_ERR(devmap))
7783d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		alias = devmap->uid.alias;
7793d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	else
7803d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		alias = 0;
7813d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_unlock(&dasd_devmap_lock);
7823d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
7833d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	return sprintf(buf, alias ? "1\n" : "0\n");
7843d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel}
7853d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
7863d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummelstatic DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL);
7873d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
7883d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummelstatic ssize_t
7893d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummeldasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
7903d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel{
7913d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	struct dasd_devmap *devmap;
7923d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	char *vendor;
7933d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
7943d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	devmap = dasd_find_busid(dev->bus_id);
7953d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_lock(&dasd_devmap_lock);
7963d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
7973d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		vendor = devmap->uid.vendor;
7983d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	else
7993d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		vendor = "";
8003d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_unlock(&dasd_devmap_lock);
8013d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
8023d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	return snprintf(buf, PAGE_SIZE, "%s\n", vendor);
8033d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel}
8043d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
8053d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummelstatic DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);
8063d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
8073d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial    */ 14 + 1 +\
8083d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		     /* SSID   */ 4 + 1 + /* unit addr */ 2 + 1)
8093d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
8103d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummelstatic ssize_t
8113d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummeldasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
8123d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel{
8133d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	struct dasd_devmap *devmap;
8143d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	char uid[UID_STRLEN];
8153d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
8163d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	devmap = dasd_find_busid(dev->bus_id);
8173d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_lock(&dasd_devmap_lock);
8183d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
8193d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
8203d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel			 devmap->uid.vendor, devmap->uid.serial,
8213d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel			 devmap->uid.ssid, devmap->uid.unit_addr);
8223d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	else
8233d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		uid[0] = 0;
8243d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_unlock(&dasd_devmap_lock);
8253d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
8263d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	return snprintf(buf, PAGE_SIZE, "%s\n", uid);
8273d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel}
8283d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
8293d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummelstatic DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
8303d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
83120c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber/*
83220c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber * extended error-reporting
83320c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber */
83420c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuberstatic ssize_t
83520c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuberdasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf)
83620c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber{
83720c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	struct dasd_devmap *devmap;
83820c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	int eer_flag;
83920c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber
84020c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	devmap = dasd_find_busid(dev->bus_id);
84120c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	if (!IS_ERR(devmap) && devmap->device)
84220c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber		eer_flag = dasd_eer_enabled(devmap->device);
84320c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	else
84420c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber		eer_flag = 0;
84520c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	return snprintf(buf, PAGE_SIZE, eer_flag ? "1\n" : "0\n");
84620c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber}
84720c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber
84820c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuberstatic ssize_t
84920c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuberdasd_eer_store(struct device *dev, struct device_attribute *attr,
85020c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	       const char *buf, size_t count)
85120c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber{
85220c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	struct dasd_devmap *devmap;
85320c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	int rc;
85420c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber
85520c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
85620c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	if (IS_ERR(devmap))
85720c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber		return PTR_ERR(devmap);
85820c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	if (!devmap->device)
85920c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber		return count;
86020c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	if (buf[0] == '1') {
86120c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber		rc = dasd_eer_enable(devmap->device);
86220c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber		if (rc)
86320c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber			return rc;
86420c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	} else
86520c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber		dasd_eer_disable(devmap->device);
86620c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	return count;
86720c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber}
86820c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber
86920c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuberstatic DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);
87020c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct attribute * dasd_attrs[] = {
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&dev_attr_readonly.attr,
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&dev_attr_discipline.attr,
8743d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	&dev_attr_alias.attr,
8753d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	&dev_attr_vendor.attr,
8763d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	&dev_attr_uid.attr,
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&dev_attr_use_diag.attr,
87820c644680af1ef9a6b36c0873f59498c98b07ab1Stefan Weinhuber	&dev_attr_eer_enabled.attr,
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	NULL,
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct attribute_group dasd_attr_group = {
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.attrs = dasd_attrs,
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
886405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel/*
8873d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel * Return copy of the device unique identifier.
8883d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel */
8893d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummelint
8903d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummeldasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
8913d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel{
8923d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	struct dasd_devmap *devmap;
8933d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
8943d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	devmap = dasd_find_busid(cdev->dev.bus_id);
8953d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	if (IS_ERR(devmap))
8963d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		return PTR_ERR(devmap);
8973d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_lock(&dasd_devmap_lock);
8983d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	*uid = devmap->uid;
8993d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_unlock(&dasd_devmap_lock);
9003d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	return 0;
9013d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel}
9023d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
9033d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel/*
9043d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel * Register the given device unique identifier into devmap struct.
905b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter * In addition check if the related storage server subsystem ID is already
906b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter * contained in the dasd_server_ssid_list. If subsystem ID is not contained,
907b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter * create new entry.
908405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel * Return 0 if server was already in serverlist,
909405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel *	  1 if the server was added successful
910405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel *	 <0 in case of error.
9113d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel */
9123d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummelint
9133d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummeldasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
9143d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel{
9153d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	struct dasd_devmap *devmap;
916b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter	struct dasd_server_ssid_map *srv, *tmp;
9173d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
9183d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	devmap = dasd_find_busid(cdev->dev.bus_id);
9193d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	if (IS_ERR(devmap))
9203d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel		return PTR_ERR(devmap);
921d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel
922b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter	/* generate entry for server_ssid_map */
923b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter	srv = (struct dasd_server_ssid_map *)
924b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter		kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
925d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel	if (!srv)
926d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel		return -ENOMEM;
927d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel	strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
928d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel	strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
9298e79a441a4d8a34d64efe93add49b3eefca5cd1cHorst Hummel	srv->sid.ssid = uid->ssid;
930d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel
931d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel	/* server is already contained ? */
9323d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_lock(&dasd_devmap_lock);
9333d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	devmap->uid = *uid;
934b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter	list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
935d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel		if (!memcmp(&srv->sid, &tmp->sid,
9368e79a441a4d8a34d64efe93add49b3eefca5cd1cHorst Hummel			    sizeof(struct system_id))) {
937d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel			kfree(srv);
938d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel			srv = NULL;
939d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel			break;
940d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel		}
941d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel	}
942d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel
943d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel	/* add servermap to serverlist */
944d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel	if (srv)
945b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter		list_add(&srv->list, &dasd_server_ssid_list);
9463d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel	spin_unlock(&dasd_devmap_lock);
947d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel
948d0710c7c9eea2145a0614f39dbe9dc8cb4ae14daHorst Hummel	return (srv ? 1 : 0);
9493d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel}
950405455734e1cdec09c37233216f9240cb1a058e5Horst HummelEXPORT_SYMBOL_GPL(dasd_set_uid);
9513d052595423b4432f4d599c1aeb1949ac0da7314Horst Hummel
952f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel/*
953f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel * Return value of the specified feature.
954f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel */
955f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummelint
956f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummeldasd_get_feature(struct ccw_device *cdev, int feature)
957f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel{
958f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	struct dasd_devmap *devmap;
959f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel
960f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	devmap = dasd_find_busid(cdev->dev.bus_id);
961f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	if (IS_ERR(devmap))
962405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel		return PTR_ERR(devmap);
963f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel
964f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	return ((devmap->features & feature) != 0);
965f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel}
966f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel
967f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel/*
968f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel * Set / reset given feature.
969f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel * Flag indicates wether to set (!=0) or the reset (=0) the feature.
970f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel */
971f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummelint
972f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummeldasd_set_feature(struct ccw_device *cdev, int feature, int flag)
973f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel{
974f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	struct dasd_devmap *devmap;
975f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel
976f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	devmap = dasd_find_busid(cdev->dev.bus_id);
977f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	if (IS_ERR(devmap))
978405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel		return PTR_ERR(devmap);
979f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel
980f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	spin_lock(&dasd_devmap_lock);
981f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	if (flag)
982f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel		devmap->features |= feature;
983f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	else
984f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel		devmap->features &= ~feature;
985c6eb7b7703ac4b3401b74f411c8c51ded214bf19Horst Hummel	if (devmap->device)
986c6eb7b7703ac4b3401b74f411c8c51ded214bf19Horst Hummel		devmap->device->features = devmap->features;
987f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	spin_unlock(&dasd_devmap_lock);
988f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel	return 0;
989f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel}
990f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel
991f24acd4503270ed4c842c8fef0b71105285e0a06Horst Hummel
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_add_sysfs_files(struct ccw_device *cdev)
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_remove_sysfs_files(struct ccw_device *cdev)
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_devmap_init(void)
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Initialize devmap structures. */
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dasd_max_devindex = 0;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 256; i++)
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		INIT_LIST_HEAD(&dasd_hashlists[i]);
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1015405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	/* Initialize servermap structure. */
1016b18a60e7c2a7f2a17dbd57885621a42d546e2f7dPeter Oberparleiter	INIT_LIST_HEAD(&dasd_server_ssid_list);
1017405455734e1cdec09c37233216f9240cb1a058e5Horst Hummel	return 0;
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdasd_devmap_exit(void)
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dasd_forget_ranges();
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1025