diff options
author | Stefan Haberland <stefan.haberland@de.ibm.com> | 2010-05-17 04:00:11 -0400 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-05-17 04:00:16 -0400 |
commit | 2dedf0d9eadf39660f2e1686b5d36e4a7515803f (patch) | |
tree | 39fefcb959ee6e7c9c15b07b58eb9ef6a9e6304d | |
parent | 501183f2ed74434e30a1b039b2f3af30f1f3f461 (diff) |
[S390] dasd: remove uid from devmap
Remove the duplicate of the DASD uid from the devmap structure.
Use the uid from the device private structure instead.
This also removes a lockdep warning complaining about a possible
SOFTIRQ-safe -> SOFTIRQ-unsafe lock order.
Signed-off-by: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | drivers/s390/block/dasd_alias.c | 117 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 174 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 78 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 44 |
4 files changed, 218 insertions, 195 deletions
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index a564b9941114..4155805dcdff 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
@@ -190,20 +190,21 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
190 | struct alias_server *server, *newserver; | 190 | struct alias_server *server, *newserver; |
191 | struct alias_lcu *lcu, *newlcu; | 191 | struct alias_lcu *lcu, *newlcu; |
192 | int is_lcu_known; | 192 | int is_lcu_known; |
193 | struct dasd_uid *uid; | 193 | struct dasd_uid uid; |
194 | 194 | ||
195 | private = (struct dasd_eckd_private *) device->private; | 195 | private = (struct dasd_eckd_private *) device->private; |
196 | uid = &private->uid; | 196 | |
197 | device->discipline->get_uid(device, &uid); | ||
197 | spin_lock_irqsave(&aliastree.lock, flags); | 198 | spin_lock_irqsave(&aliastree.lock, flags); |
198 | is_lcu_known = 1; | 199 | is_lcu_known = 1; |
199 | server = _find_server(uid); | 200 | server = _find_server(&uid); |
200 | if (!server) { | 201 | if (!server) { |
201 | spin_unlock_irqrestore(&aliastree.lock, flags); | 202 | spin_unlock_irqrestore(&aliastree.lock, flags); |
202 | newserver = _allocate_server(uid); | 203 | newserver = _allocate_server(&uid); |
203 | if (IS_ERR(newserver)) | 204 | if (IS_ERR(newserver)) |
204 | return PTR_ERR(newserver); | 205 | return PTR_ERR(newserver); |
205 | spin_lock_irqsave(&aliastree.lock, flags); | 206 | spin_lock_irqsave(&aliastree.lock, flags); |
206 | server = _find_server(uid); | 207 | server = _find_server(&uid); |
207 | if (!server) { | 208 | if (!server) { |
208 | list_add(&newserver->server, &aliastree.serverlist); | 209 | list_add(&newserver->server, &aliastree.serverlist); |
209 | server = newserver; | 210 | server = newserver; |
@@ -214,14 +215,14 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
214 | } | 215 | } |
215 | } | 216 | } |
216 | 217 | ||
217 | lcu = _find_lcu(server, uid); | 218 | lcu = _find_lcu(server, &uid); |
218 | if (!lcu) { | 219 | if (!lcu) { |
219 | spin_unlock_irqrestore(&aliastree.lock, flags); | 220 | spin_unlock_irqrestore(&aliastree.lock, flags); |
220 | newlcu = _allocate_lcu(uid); | 221 | newlcu = _allocate_lcu(&uid); |
221 | if (IS_ERR(newlcu)) | 222 | if (IS_ERR(newlcu)) |
222 | return PTR_ERR(newlcu); | 223 | return PTR_ERR(newlcu); |
223 | spin_lock_irqsave(&aliastree.lock, flags); | 224 | spin_lock_irqsave(&aliastree.lock, flags); |
224 | lcu = _find_lcu(server, uid); | 225 | lcu = _find_lcu(server, &uid); |
225 | if (!lcu) { | 226 | if (!lcu) { |
226 | list_add(&newlcu->lcu, &server->lculist); | 227 | list_add(&newlcu->lcu, &server->lculist); |
227 | lcu = newlcu; | 228 | lcu = newlcu; |
@@ -256,20 +257,20 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device) | |||
256 | unsigned long flags; | 257 | unsigned long flags; |
257 | struct alias_server *server; | 258 | struct alias_server *server; |
258 | struct alias_lcu *lcu; | 259 | struct alias_lcu *lcu; |
259 | struct dasd_uid *uid; | 260 | struct dasd_uid uid; |
260 | 261 | ||
261 | private = (struct dasd_eckd_private *) device->private; | 262 | private = (struct dasd_eckd_private *) device->private; |
262 | uid = &private->uid; | 263 | device->discipline->get_uid(device, &uid); |
263 | lcu = NULL; | 264 | lcu = NULL; |
264 | spin_lock_irqsave(&aliastree.lock, flags); | 265 | spin_lock_irqsave(&aliastree.lock, flags); |
265 | server = _find_server(uid); | 266 | server = _find_server(&uid); |
266 | if (server) | 267 | if (server) |
267 | lcu = _find_lcu(server, uid); | 268 | lcu = _find_lcu(server, &uid); |
268 | spin_unlock_irqrestore(&aliastree.lock, flags); | 269 | spin_unlock_irqrestore(&aliastree.lock, flags); |
269 | if (!lcu) { | 270 | if (!lcu) { |
270 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, | 271 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, |
271 | "could not find lcu for %04x %02x", | 272 | "could not find lcu for %04x %02x", |
272 | uid->ssid, uid->real_unit_addr); | 273 | uid.ssid, uid.real_unit_addr); |
273 | WARN_ON(1); | 274 | WARN_ON(1); |
274 | return; | 275 | return; |
275 | } | 276 | } |
@@ -282,20 +283,20 @@ void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) | |||
282 | unsigned long flags; | 283 | unsigned long flags; |
283 | struct alias_server *server; | 284 | struct alias_server *server; |
284 | struct alias_lcu *lcu; | 285 | struct alias_lcu *lcu; |
285 | struct dasd_uid *uid; | 286 | struct dasd_uid uid; |
286 | 287 | ||
287 | private = (struct dasd_eckd_private *) device->private; | 288 | private = (struct dasd_eckd_private *) device->private; |
288 | uid = &private->uid; | 289 | device->discipline->get_uid(device, &uid); |
289 | lcu = NULL; | 290 | lcu = NULL; |
290 | spin_lock_irqsave(&aliastree.lock, flags); | 291 | spin_lock_irqsave(&aliastree.lock, flags); |
291 | server = _find_server(uid); | 292 | server = _find_server(&uid); |
292 | if (server) | 293 | if (server) |
293 | lcu = _find_lcu(server, uid); | 294 | lcu = _find_lcu(server, &uid); |
294 | spin_unlock_irqrestore(&aliastree.lock, flags); | 295 | spin_unlock_irqrestore(&aliastree.lock, flags); |
295 | if (!lcu) { | 296 | if (!lcu) { |
296 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, | 297 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, |
297 | "could not find lcu for %04x %02x", | 298 | "could not find lcu for %04x %02x", |
298 | uid->ssid, uid->real_unit_addr); | 299 | uid.ssid, uid.real_unit_addr); |
299 | WARN_ON(1); | 300 | WARN_ON(1); |
300 | return; | 301 | return; |
301 | } | 302 | } |
@@ -314,9 +315,11 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
314 | struct alias_lcu *lcu; | 315 | struct alias_lcu *lcu; |
315 | struct alias_server *server; | 316 | struct alias_server *server; |
316 | int was_pending; | 317 | int was_pending; |
318 | struct dasd_uid uid; | ||
317 | 319 | ||
318 | private = (struct dasd_eckd_private *) device->private; | 320 | private = (struct dasd_eckd_private *) device->private; |
319 | lcu = private->lcu; | 321 | lcu = private->lcu; |
322 | device->discipline->get_uid(device, &uid); | ||
320 | spin_lock_irqsave(&lcu->lock, flags); | 323 | spin_lock_irqsave(&lcu->lock, flags); |
321 | list_del_init(&device->alias_list); | 324 | list_del_init(&device->alias_list); |
322 | /* make sure that the workers don't use this device */ | 325 | /* make sure that the workers don't use this device */ |
@@ -353,7 +356,7 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
353 | _schedule_lcu_update(lcu, NULL); | 356 | _schedule_lcu_update(lcu, NULL); |
354 | spin_unlock(&lcu->lock); | 357 | spin_unlock(&lcu->lock); |
355 | } | 358 | } |
356 | server = _find_server(&private->uid); | 359 | server = _find_server(&uid); |
357 | if (server && list_empty(&server->lculist)) { | 360 | if (server && list_empty(&server->lculist)) { |
358 | list_del(&server->server); | 361 | list_del(&server->server); |
359 | _free_server(server); | 362 | _free_server(server); |
@@ -366,19 +369,30 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
366 | * in the lcu is up to date and will update the device uid before | 369 | * in the lcu is up to date and will update the device uid before |
367 | * adding it to a pav group. | 370 | * adding it to a pav group. |
368 | */ | 371 | */ |
372 | |||
369 | static int _add_device_to_lcu(struct alias_lcu *lcu, | 373 | static int _add_device_to_lcu(struct alias_lcu *lcu, |
370 | struct dasd_device *device) | 374 | struct dasd_device *device, |
375 | struct dasd_device *pos) | ||
371 | { | 376 | { |
372 | 377 | ||
373 | struct dasd_eckd_private *private; | 378 | struct dasd_eckd_private *private; |
374 | struct alias_pav_group *group; | 379 | struct alias_pav_group *group; |
375 | struct dasd_uid *uid; | 380 | struct dasd_uid uid; |
381 | unsigned long flags; | ||
376 | 382 | ||
377 | private = (struct dasd_eckd_private *) device->private; | 383 | private = (struct dasd_eckd_private *) device->private; |
378 | uid = &private->uid; | 384 | |
379 | uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type; | 385 | /* only lock if not already locked */ |
380 | uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua; | 386 | if (device != pos) |
381 | dasd_set_uid(device->cdev, &private->uid); | 387 | spin_lock_irqsave_nested(get_ccwdev_lock(device->cdev), flags, |
388 | CDEV_NESTED_SECOND); | ||
389 | private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type; | ||
390 | private->uid.base_unit_addr = | ||
391 | lcu->uac->unit[private->uid.real_unit_addr].base_ua; | ||
392 | uid = private->uid; | ||
393 | |||
394 | if (device != pos) | ||
395 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
382 | 396 | ||
383 | /* if we have no PAV anyway, we don't need to bother with PAV groups */ | 397 | /* if we have no PAV anyway, we don't need to bother with PAV groups */ |
384 | if (lcu->pav == NO_PAV) { | 398 | if (lcu->pav == NO_PAV) { |
@@ -386,25 +400,25 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, | |||
386 | return 0; | 400 | return 0; |
387 | } | 401 | } |
388 | 402 | ||
389 | group = _find_group(lcu, uid); | 403 | group = _find_group(lcu, &uid); |
390 | if (!group) { | 404 | if (!group) { |
391 | group = kzalloc(sizeof(*group), GFP_ATOMIC); | 405 | group = kzalloc(sizeof(*group), GFP_ATOMIC); |
392 | if (!group) | 406 | if (!group) |
393 | return -ENOMEM; | 407 | return -ENOMEM; |
394 | memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor)); | 408 | memcpy(group->uid.vendor, uid.vendor, sizeof(uid.vendor)); |
395 | memcpy(group->uid.serial, uid->serial, sizeof(uid->serial)); | 409 | memcpy(group->uid.serial, uid.serial, sizeof(uid.serial)); |
396 | group->uid.ssid = uid->ssid; | 410 | group->uid.ssid = uid.ssid; |
397 | if (uid->type == UA_BASE_DEVICE) | 411 | if (uid.type == UA_BASE_DEVICE) |
398 | group->uid.base_unit_addr = uid->real_unit_addr; | 412 | group->uid.base_unit_addr = uid.real_unit_addr; |
399 | else | 413 | else |
400 | group->uid.base_unit_addr = uid->base_unit_addr; | 414 | group->uid.base_unit_addr = uid.base_unit_addr; |
401 | memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit)); | 415 | memcpy(group->uid.vduit, uid.vduit, sizeof(uid.vduit)); |
402 | INIT_LIST_HEAD(&group->group); | 416 | INIT_LIST_HEAD(&group->group); |
403 | INIT_LIST_HEAD(&group->baselist); | 417 | INIT_LIST_HEAD(&group->baselist); |
404 | INIT_LIST_HEAD(&group->aliaslist); | 418 | INIT_LIST_HEAD(&group->aliaslist); |
405 | list_add(&group->group, &lcu->grouplist); | 419 | list_add(&group->group, &lcu->grouplist); |
406 | } | 420 | } |
407 | if (uid->type == UA_BASE_DEVICE) | 421 | if (uid.type == UA_BASE_DEVICE) |
408 | list_move(&device->alias_list, &group->baselist); | 422 | list_move(&device->alias_list, &group->baselist); |
409 | else | 423 | else |
410 | list_move(&device->alias_list, &group->aliaslist); | 424 | list_move(&device->alias_list, &group->aliaslist); |
@@ -525,7 +539,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
525 | if (rc) | 539 | if (rc) |
526 | return rc; | 540 | return rc; |
527 | 541 | ||
528 | spin_lock_irqsave(&lcu->lock, flags); | 542 | /* need to take cdev lock before lcu lock */ |
543 | spin_lock_irqsave_nested(get_ccwdev_lock(refdev->cdev), flags, | ||
544 | CDEV_NESTED_FIRST); | ||
545 | spin_lock(&lcu->lock); | ||
529 | lcu->pav = NO_PAV; | 546 | lcu->pav = NO_PAV; |
530 | for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { | 547 | for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { |
531 | switch (lcu->uac->unit[i].ua_type) { | 548 | switch (lcu->uac->unit[i].ua_type) { |
@@ -542,9 +559,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
542 | 559 | ||
543 | list_for_each_entry_safe(device, tempdev, &lcu->active_devices, | 560 | list_for_each_entry_safe(device, tempdev, &lcu->active_devices, |
544 | alias_list) { | 561 | alias_list) { |
545 | _add_device_to_lcu(lcu, device); | 562 | _add_device_to_lcu(lcu, device, refdev); |
546 | } | 563 | } |
547 | spin_unlock_irqrestore(&lcu->lock, flags); | 564 | spin_unlock(&lcu->lock); |
565 | spin_unlock_irqrestore(get_ccwdev_lock(refdev->cdev), flags); | ||
548 | return 0; | 566 | return 0; |
549 | } | 567 | } |
550 | 568 | ||
@@ -628,9 +646,12 @@ int dasd_alias_add_device(struct dasd_device *device) | |||
628 | private = (struct dasd_eckd_private *) device->private; | 646 | private = (struct dasd_eckd_private *) device->private; |
629 | lcu = private->lcu; | 647 | lcu = private->lcu; |
630 | rc = 0; | 648 | rc = 0; |
631 | spin_lock_irqsave(&lcu->lock, flags); | 649 | |
650 | /* need to take cdev lock before lcu lock */ | ||
651 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
652 | spin_lock(&lcu->lock); | ||
632 | if (!(lcu->flags & UPDATE_PENDING)) { | 653 | if (!(lcu->flags & UPDATE_PENDING)) { |
633 | rc = _add_device_to_lcu(lcu, device); | 654 | rc = _add_device_to_lcu(lcu, device, device); |
634 | if (rc) | 655 | if (rc) |
635 | lcu->flags |= UPDATE_PENDING; | 656 | lcu->flags |= UPDATE_PENDING; |
636 | } | 657 | } |
@@ -638,7 +659,8 @@ int dasd_alias_add_device(struct dasd_device *device) | |||
638 | list_move(&device->alias_list, &lcu->active_devices); | 659 | list_move(&device->alias_list, &lcu->active_devices); |
639 | _schedule_lcu_update(lcu, device); | 660 | _schedule_lcu_update(lcu, device); |
640 | } | 661 | } |
641 | spin_unlock_irqrestore(&lcu->lock, flags); | 662 | spin_unlock(&lcu->lock); |
663 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
642 | return rc; | 664 | return rc; |
643 | } | 665 | } |
644 | 666 | ||
@@ -748,19 +770,30 @@ static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu) | |||
748 | struct alias_pav_group *pavgroup; | 770 | struct alias_pav_group *pavgroup; |
749 | struct dasd_device *device; | 771 | struct dasd_device *device; |
750 | struct dasd_eckd_private *private; | 772 | struct dasd_eckd_private *private; |
773 | unsigned long flags; | ||
751 | 774 | ||
752 | /* active and inactive list can contain alias as well as base devices */ | 775 | /* active and inactive list can contain alias as well as base devices */ |
753 | list_for_each_entry(device, &lcu->active_devices, alias_list) { | 776 | list_for_each_entry(device, &lcu->active_devices, alias_list) { |
754 | private = (struct dasd_eckd_private *) device->private; | 777 | private = (struct dasd_eckd_private *) device->private; |
755 | if (private->uid.type != UA_BASE_DEVICE) | 778 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
779 | if (private->uid.type != UA_BASE_DEVICE) { | ||
780 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
781 | flags); | ||
756 | continue; | 782 | continue; |
783 | } | ||
784 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
757 | dasd_schedule_block_bh(device->block); | 785 | dasd_schedule_block_bh(device->block); |
758 | dasd_schedule_device_bh(device); | 786 | dasd_schedule_device_bh(device); |
759 | } | 787 | } |
760 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { | 788 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { |
761 | private = (struct dasd_eckd_private *) device->private; | 789 | private = (struct dasd_eckd_private *) device->private; |
762 | if (private->uid.type != UA_BASE_DEVICE) | 790 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
791 | if (private->uid.type != UA_BASE_DEVICE) { | ||
792 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
793 | flags); | ||
763 | continue; | 794 | continue; |
795 | } | ||
796 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
764 | dasd_schedule_block_bh(device->block); | 797 | dasd_schedule_block_bh(device->block); |
765 | dasd_schedule_device_bh(device); | 798 | dasd_schedule_device_bh(device); |
766 | } | 799 | } |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index eff9c812c5c2..34d51dd4c539 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -49,7 +49,6 @@ struct dasd_devmap { | |||
49 | unsigned int devindex; | 49 | unsigned int devindex; |
50 | unsigned short features; | 50 | unsigned short features; |
51 | struct dasd_device *device; | 51 | struct dasd_device *device; |
52 | struct dasd_uid uid; | ||
53 | }; | 52 | }; |
54 | 53 | ||
55 | /* | 54 | /* |
@@ -936,42 +935,46 @@ dasd_device_status_show(struct device *dev, struct device_attribute *attr, | |||
936 | 935 | ||
937 | static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); | 936 | static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); |
938 | 937 | ||
939 | static ssize_t | 938 | static ssize_t dasd_alias_show(struct device *dev, |
940 | dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) | 939 | struct device_attribute *attr, char *buf) |
941 | { | 940 | { |
942 | struct dasd_devmap *devmap; | 941 | struct dasd_device *device; |
943 | int alias; | 942 | struct dasd_uid uid; |
944 | 943 | ||
945 | devmap = dasd_find_busid(dev_name(dev)); | 944 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
946 | spin_lock(&dasd_devmap_lock); | 945 | if (IS_ERR(device)) |
947 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { | ||
948 | spin_unlock(&dasd_devmap_lock); | ||
949 | return sprintf(buf, "0\n"); | 946 | return sprintf(buf, "0\n"); |
947 | |||
948 | if (device->discipline && device->discipline->get_uid && | ||
949 | !device->discipline->get_uid(device, &uid)) { | ||
950 | if (uid.type == UA_BASE_PAV_ALIAS || | ||
951 | uid.type == UA_HYPER_PAV_ALIAS) | ||
952 | return sprintf(buf, "1\n"); | ||
950 | } | 953 | } |
951 | if (devmap->uid.type == UA_BASE_PAV_ALIAS || | 954 | dasd_put_device(device); |
952 | devmap->uid.type == UA_HYPER_PAV_ALIAS) | 955 | |
953 | alias = 1; | 956 | return sprintf(buf, "0\n"); |
954 | else | ||
955 | alias = 0; | ||
956 | spin_unlock(&dasd_devmap_lock); | ||
957 | return sprintf(buf, alias ? "1\n" : "0\n"); | ||
958 | } | 957 | } |
959 | 958 | ||
960 | static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); | 959 | static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); |
961 | 960 | ||
962 | static ssize_t | 961 | static ssize_t dasd_vendor_show(struct device *dev, |
963 | dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) | 962 | struct device_attribute *attr, char *buf) |
964 | { | 963 | { |
965 | struct dasd_devmap *devmap; | 964 | struct dasd_device *device; |
965 | struct dasd_uid uid; | ||
966 | char *vendor; | 966 | char *vendor; |
967 | 967 | ||
968 | devmap = dasd_find_busid(dev_name(dev)); | 968 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
969 | spin_lock(&dasd_devmap_lock); | 969 | vendor = ""; |
970 | if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) | 970 | if (IS_ERR(device)) |
971 | vendor = devmap->uid.vendor; | 971 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); |
972 | else | 972 | |
973 | vendor = ""; | 973 | if (device->discipline && device->discipline->get_uid && |
974 | spin_unlock(&dasd_devmap_lock); | 974 | !device->discipline->get_uid(device, &uid)) |
975 | vendor = uid.vendor; | ||
976 | |||
977 | dasd_put_device(device); | ||
975 | 978 | ||
976 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); | 979 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); |
977 | } | 980 | } |
@@ -985,48 +988,51 @@ static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); | |||
985 | static ssize_t | 988 | static ssize_t |
986 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) | 989 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) |
987 | { | 990 | { |
988 | struct dasd_devmap *devmap; | 991 | struct dasd_device *device; |
992 | struct dasd_uid uid; | ||
989 | char uid_string[UID_STRLEN]; | 993 | char uid_string[UID_STRLEN]; |
990 | char ua_string[3]; | 994 | char ua_string[3]; |
991 | struct dasd_uid *uid; | ||
992 | 995 | ||
993 | devmap = dasd_find_busid(dev_name(dev)); | 996 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
994 | spin_lock(&dasd_devmap_lock); | 997 | uid_string[0] = 0; |
995 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { | 998 | if (IS_ERR(device)) |
996 | spin_unlock(&dasd_devmap_lock); | 999 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); |
997 | return sprintf(buf, "\n"); | 1000 | |
998 | } | 1001 | if (device->discipline && device->discipline->get_uid && |
999 | uid = &devmap->uid; | 1002 | !device->discipline->get_uid(device, &uid)) { |
1000 | switch (uid->type) { | 1003 | switch (uid.type) { |
1001 | case UA_BASE_DEVICE: | 1004 | case UA_BASE_DEVICE: |
1002 | sprintf(ua_string, "%02x", uid->real_unit_addr); | 1005 | snprintf(ua_string, sizeof(ua_string), "%02x", |
1003 | break; | 1006 | uid.real_unit_addr); |
1004 | case UA_BASE_PAV_ALIAS: | 1007 | break; |
1005 | sprintf(ua_string, "%02x", uid->base_unit_addr); | 1008 | case UA_BASE_PAV_ALIAS: |
1006 | break; | 1009 | snprintf(ua_string, sizeof(ua_string), "%02x", |
1007 | case UA_HYPER_PAV_ALIAS: | 1010 | uid.base_unit_addr); |
1008 | sprintf(ua_string, "xx"); | 1011 | break; |
1009 | break; | 1012 | case UA_HYPER_PAV_ALIAS: |
1010 | default: | 1013 | snprintf(ua_string, sizeof(ua_string), "xx"); |
1011 | /* should not happen, treat like base device */ | 1014 | break; |
1012 | sprintf(ua_string, "%02x", uid->real_unit_addr); | 1015 | default: |
1013 | break; | 1016 | /* should not happen, treat like base device */ |
1017 | snprintf(ua_string, sizeof(ua_string), "%02x", | ||
1018 | uid.real_unit_addr); | ||
1019 | break; | ||
1020 | } | ||
1021 | |||
1022 | if (strlen(uid.vduit) > 0) | ||
1023 | snprintf(uid_string, sizeof(uid_string), | ||
1024 | "%s.%s.%04x.%s.%s", | ||
1025 | uid.vendor, uid.serial, uid.ssid, ua_string, | ||
1026 | uid.vduit); | ||
1027 | else | ||
1028 | snprintf(uid_string, sizeof(uid_string), | ||
1029 | "%s.%s.%04x.%s", | ||
1030 | uid.vendor, uid.serial, uid.ssid, ua_string); | ||
1014 | } | 1031 | } |
1015 | if (strlen(uid->vduit) > 0) | 1032 | dasd_put_device(device); |
1016 | snprintf(uid_string, sizeof(uid_string), | 1033 | |
1017 | "%s.%s.%04x.%s.%s", | ||
1018 | uid->vendor, uid->serial, | ||
1019 | uid->ssid, ua_string, | ||
1020 | uid->vduit); | ||
1021 | else | ||
1022 | snprintf(uid_string, sizeof(uid_string), | ||
1023 | "%s.%s.%04x.%s", | ||
1024 | uid->vendor, uid->serial, | ||
1025 | uid->ssid, ua_string); | ||
1026 | spin_unlock(&dasd_devmap_lock); | ||
1027 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); | 1034 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); |
1028 | } | 1035 | } |
1029 | |||
1030 | static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); | 1036 | static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); |
1031 | 1037 | ||
1032 | /* | 1038 | /* |
@@ -1094,50 +1100,6 @@ static struct attribute_group dasd_attr_group = { | |||
1094 | }; | 1100 | }; |
1095 | 1101 | ||
1096 | /* | 1102 | /* |
1097 | * Return copy of the device unique identifier. | ||
1098 | */ | ||
1099 | int | ||
1100 | dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | ||
1101 | { | ||
1102 | struct dasd_devmap *devmap; | ||
1103 | |||
1104 | devmap = dasd_find_busid(dev_name(&cdev->dev)); | ||
1105 | if (IS_ERR(devmap)) | ||
1106 | return PTR_ERR(devmap); | ||
1107 | spin_lock(&dasd_devmap_lock); | ||
1108 | *uid = devmap->uid; | ||
1109 | spin_unlock(&dasd_devmap_lock); | ||
1110 | return 0; | ||
1111 | } | ||
1112 | EXPORT_SYMBOL_GPL(dasd_get_uid); | ||
1113 | |||
1114 | /* | ||
1115 | * Register the given device unique identifier into devmap struct. | ||
1116 | * In addition check if the related storage server subsystem ID is already | ||
1117 | * contained in the dasd_server_ssid_list. If subsystem ID is not contained, | ||
1118 | * create new entry. | ||
1119 | * Return 0 if server was already in serverlist, | ||
1120 | * 1 if the server was added successful | ||
1121 | * <0 in case of error. | ||
1122 | */ | ||
1123 | int | ||
1124 | dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) | ||
1125 | { | ||
1126 | struct dasd_devmap *devmap; | ||
1127 | |||
1128 | devmap = dasd_find_busid(dev_name(&cdev->dev)); | ||
1129 | if (IS_ERR(devmap)) | ||
1130 | return PTR_ERR(devmap); | ||
1131 | |||
1132 | spin_lock(&dasd_devmap_lock); | ||
1133 | devmap->uid = *uid; | ||
1134 | spin_unlock(&dasd_devmap_lock); | ||
1135 | |||
1136 | return 0; | ||
1137 | } | ||
1138 | EXPORT_SYMBOL_GPL(dasd_set_uid); | ||
1139 | |||
1140 | /* | ||
1141 | * Return value of the specified feature. | 1103 | * Return value of the specified feature. |
1142 | */ | 1104 | */ |
1143 | int | 1105 | int |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 4305c23c57a4..5b1cd8d6e971 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -692,18 +692,20 @@ dasd_eckd_cdl_reclen(int recid) | |||
692 | /* | 692 | /* |
693 | * Generate device unique id that specifies the physical device. | 693 | * Generate device unique id that specifies the physical device. |
694 | */ | 694 | */ |
695 | static int dasd_eckd_generate_uid(struct dasd_device *device, | 695 | static int dasd_eckd_generate_uid(struct dasd_device *device) |
696 | struct dasd_uid *uid) | ||
697 | { | 696 | { |
698 | struct dasd_eckd_private *private; | 697 | struct dasd_eckd_private *private; |
698 | struct dasd_uid *uid; | ||
699 | int count; | 699 | int count; |
700 | unsigned long flags; | ||
700 | 701 | ||
701 | private = (struct dasd_eckd_private *) device->private; | 702 | private = (struct dasd_eckd_private *) device->private; |
702 | if (!private) | 703 | if (!private) |
703 | return -ENODEV; | 704 | return -ENODEV; |
704 | if (!private->ned || !private->gneq) | 705 | if (!private->ned || !private->gneq) |
705 | return -ENODEV; | 706 | return -ENODEV; |
706 | 707 | uid = &private->uid; | |
708 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
707 | memset(uid, 0, sizeof(struct dasd_uid)); | 709 | memset(uid, 0, sizeof(struct dasd_uid)); |
708 | memcpy(uid->vendor, private->ned->HDA_manufacturer, | 710 | memcpy(uid->vendor, private->ned->HDA_manufacturer, |
709 | sizeof(uid->vendor) - 1); | 711 | sizeof(uid->vendor) - 1); |
@@ -726,9 +728,25 @@ static int dasd_eckd_generate_uid(struct dasd_device *device, | |||
726 | private->vdsneq->uit[count]); | 728 | private->vdsneq->uit[count]); |
727 | } | 729 | } |
728 | } | 730 | } |
731 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
729 | return 0; | 732 | return 0; |
730 | } | 733 | } |
731 | 734 | ||
735 | static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid) | ||
736 | { | ||
737 | struct dasd_eckd_private *private; | ||
738 | unsigned long flags; | ||
739 | |||
740 | if (device->private) { | ||
741 | private = (struct dasd_eckd_private *)device->private; | ||
742 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
743 | *uid = private->uid; | ||
744 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
745 | return 0; | ||
746 | } | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | |||
732 | static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, | 750 | static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, |
733 | void *rcd_buffer, | 751 | void *rcd_buffer, |
734 | struct ciw *ciw, __u8 lpm) | 752 | struct ciw *ciw, __u8 lpm) |
@@ -1088,6 +1106,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1088 | { | 1106 | { |
1089 | struct dasd_eckd_private *private; | 1107 | struct dasd_eckd_private *private; |
1090 | struct dasd_block *block; | 1108 | struct dasd_block *block; |
1109 | struct dasd_uid temp_uid; | ||
1091 | int is_known, rc; | 1110 | int is_known, rc; |
1092 | int readonly; | 1111 | int readonly; |
1093 | 1112 | ||
@@ -1124,13 +1143,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
1124 | if (rc) | 1143 | if (rc) |
1125 | goto out_err1; | 1144 | goto out_err1; |
1126 | 1145 | ||
1127 | /* Generate device unique id and register in devmap */ | 1146 | /* Generate device unique id */ |
1128 | rc = dasd_eckd_generate_uid(device, &private->uid); | 1147 | rc = dasd_eckd_generate_uid(device); |
1129 | if (rc) | 1148 | if (rc) |
1130 | goto out_err1; | 1149 | goto out_err1; |
1131 | dasd_set_uid(device->cdev, &private->uid); | ||
1132 | 1150 | ||
1133 | if (private->uid.type == UA_BASE_DEVICE) { | 1151 | dasd_eckd_get_uid(device, &temp_uid); |
1152 | if (temp_uid.type == UA_BASE_DEVICE) { | ||
1134 | block = dasd_alloc_block(); | 1153 | block = dasd_alloc_block(); |
1135 | if (IS_ERR(block)) { | 1154 | if (IS_ERR(block)) { |
1136 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", | 1155 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", |
@@ -3305,15 +3324,16 @@ static int dasd_eckd_restore_device(struct dasd_device *device) | |||
3305 | if (rc) | 3324 | if (rc) |
3306 | goto out_err; | 3325 | goto out_err; |
3307 | 3326 | ||
3308 | /* Generate device unique id and register in devmap */ | 3327 | dasd_eckd_get_uid(device, &temp_uid); |
3309 | rc = dasd_eckd_generate_uid(device, &private->uid); | 3328 | /* Generate device unique id */ |
3310 | dasd_get_uid(device->cdev, &temp_uid); | 3329 | rc = dasd_eckd_generate_uid(device); |
3330 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
3311 | if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) | 3331 | if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) |
3312 | dev_err(&device->cdev->dev, "The UID of the DASD has " | 3332 | dev_err(&device->cdev->dev, "The UID of the DASD has " |
3313 | "changed\n"); | 3333 | "changed\n"); |
3334 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
3314 | if (rc) | 3335 | if (rc) |
3315 | goto out_err; | 3336 | goto out_err; |
3316 | dasd_set_uid(device->cdev, &private->uid); | ||
3317 | 3337 | ||
3318 | /* register lcu with alias handling, enable PAV if this is a new lcu */ | 3338 | /* register lcu with alias handling, enable PAV if this is a new lcu */ |
3319 | is_known = dasd_alias_make_device_known_to_lcu(device); | 3339 | is_known = dasd_alias_make_device_known_to_lcu(device); |
@@ -3358,42 +3378,45 @@ static int dasd_eckd_reload_device(struct dasd_device *device) | |||
3358 | { | 3378 | { |
3359 | struct dasd_eckd_private *private; | 3379 | struct dasd_eckd_private *private; |
3360 | int rc, old_base; | 3380 | int rc, old_base; |
3361 | char uid[60]; | 3381 | char print_uid[60]; |
3382 | struct dasd_uid uid; | ||
3383 | unsigned long flags; | ||
3362 | 3384 | ||
3363 | private = (struct dasd_eckd_private *) device->private; | 3385 | private = (struct dasd_eckd_private *) device->private; |
3386 | |||
3387 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
3364 | old_base = private->uid.base_unit_addr; | 3388 | old_base = private->uid.base_unit_addr; |
3389 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
3390 | |||
3365 | /* Read Configuration Data */ | 3391 | /* Read Configuration Data */ |
3366 | rc = dasd_eckd_read_conf(device); | 3392 | rc = dasd_eckd_read_conf(device); |
3367 | if (rc) | 3393 | if (rc) |
3368 | goto out_err; | 3394 | goto out_err; |
3369 | 3395 | ||
3370 | rc = dasd_eckd_generate_uid(device, &private->uid); | 3396 | rc = dasd_eckd_generate_uid(device); |
3371 | if (rc) | 3397 | if (rc) |
3372 | goto out_err; | 3398 | goto out_err; |
3373 | |||
3374 | dasd_set_uid(device->cdev, &private->uid); | ||
3375 | |||
3376 | /* | 3399 | /* |
3377 | * update unit address configuration and | 3400 | * update unit address configuration and |
3378 | * add device to alias management | 3401 | * add device to alias management |
3379 | */ | 3402 | */ |
3380 | dasd_alias_update_add_device(device); | 3403 | dasd_alias_update_add_device(device); |
3381 | 3404 | ||
3382 | if (old_base != private->uid.base_unit_addr) { | 3405 | dasd_eckd_get_uid(device, &uid); |
3383 | if (strlen(private->uid.vduit) > 0) | 3406 | |
3384 | snprintf(uid, 60, "%s.%s.%04x.%02x.%s", | 3407 | if (old_base != uid.base_unit_addr) { |
3385 | private->uid.vendor, private->uid.serial, | 3408 | if (strlen(uid.vduit) > 0) |
3386 | private->uid.ssid, private->uid.base_unit_addr, | 3409 | snprintf(print_uid, sizeof(print_uid), |
3387 | private->uid.vduit); | 3410 | "%s.%s.%04x.%02x.%s", uid.vendor, uid.serial, |
3411 | uid.ssid, uid.base_unit_addr, uid.vduit); | ||
3388 | else | 3412 | else |
3389 | snprintf(uid, 60, "%s.%s.%04x.%02x", | 3413 | snprintf(print_uid, sizeof(print_uid), |
3390 | private->uid.vendor, private->uid.serial, | 3414 | "%s.%s.%04x.%02x", uid.vendor, uid.serial, |
3391 | private->uid.ssid, | 3415 | uid.ssid, uid.base_unit_addr); |
3392 | private->uid.base_unit_addr); | ||
3393 | 3416 | ||
3394 | dev_info(&device->cdev->dev, | 3417 | dev_info(&device->cdev->dev, |
3395 | "An Alias device was reassigned to a new base device " | 3418 | "An Alias device was reassigned to a new base device " |
3396 | "with UID: %s\n", uid); | 3419 | "with UID: %s\n", print_uid); |
3397 | } | 3420 | } |
3398 | return 0; | 3421 | return 0; |
3399 | 3422 | ||
@@ -3455,6 +3478,7 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
3455 | .freeze = dasd_eckd_pm_freeze, | 3478 | .freeze = dasd_eckd_pm_freeze, |
3456 | .restore = dasd_eckd_restore_device, | 3479 | .restore = dasd_eckd_restore_device, |
3457 | .reload = dasd_eckd_reload_device, | 3480 | .reload = dasd_eckd_reload_device, |
3481 | .get_uid = dasd_eckd_get_uid, | ||
3458 | }; | 3482 | }; |
3459 | 3483 | ||
3460 | static int __init | 3484 | static int __init |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 1ae7b121628e..32fac186ba3f 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -81,6 +81,10 @@ struct dasd_block; | |||
81 | #define DASD_SIM_MSG_TO_OP 0x03 | 81 | #define DASD_SIM_MSG_TO_OP 0x03 |
82 | #define DASD_SIM_LOG 0x0C | 82 | #define DASD_SIM_LOG 0x0C |
83 | 83 | ||
84 | /* lock class for nested cdev lock */ | ||
85 | #define CDEV_NESTED_FIRST 1 | ||
86 | #define CDEV_NESTED_SECOND 2 | ||
87 | |||
84 | /* | 88 | /* |
85 | * SECTION: MACROs for klogd and s390 debug feature (dbf) | 89 | * SECTION: MACROs for klogd and s390 debug feature (dbf) |
86 | */ | 90 | */ |
@@ -229,6 +233,24 @@ struct dasd_ccw_req { | |||
229 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); | 233 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); |
230 | 234 | ||
231 | /* | 235 | /* |
236 | * Unique identifier for dasd device. | ||
237 | */ | ||
238 | #define UA_NOT_CONFIGURED 0x00 | ||
239 | #define UA_BASE_DEVICE 0x01 | ||
240 | #define UA_BASE_PAV_ALIAS 0x02 | ||
241 | #define UA_HYPER_PAV_ALIAS 0x03 | ||
242 | |||
243 | struct dasd_uid { | ||
244 | __u8 type; | ||
245 | char vendor[4]; | ||
246 | char serial[15]; | ||
247 | __u16 ssid; | ||
248 | __u8 real_unit_addr; | ||
249 | __u8 base_unit_addr; | ||
250 | char vduit[33]; | ||
251 | }; | ||
252 | |||
253 | /* | ||
232 | * the struct dasd_discipline is | 254 | * the struct dasd_discipline is |
233 | * sth like a table of virtual functions, if you think of dasd_eckd | 255 | * sth like a table of virtual functions, if you think of dasd_eckd |
234 | * inheriting dasd... | 256 | * inheriting dasd... |
@@ -315,29 +337,13 @@ struct dasd_discipline { | |||
315 | 337 | ||
316 | /* reload device after state change */ | 338 | /* reload device after state change */ |
317 | int (*reload) (struct dasd_device *); | 339 | int (*reload) (struct dasd_device *); |
340 | |||
341 | int (*get_uid) (struct dasd_device *, struct dasd_uid *); | ||
318 | }; | 342 | }; |
319 | 343 | ||
320 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | 344 | extern struct dasd_discipline *dasd_diag_discipline_pointer; |
321 | 345 | ||
322 | /* | 346 | /* |
323 | * Unique identifier for dasd device. | ||
324 | */ | ||
325 | #define UA_NOT_CONFIGURED 0x00 | ||
326 | #define UA_BASE_DEVICE 0x01 | ||
327 | #define UA_BASE_PAV_ALIAS 0x02 | ||
328 | #define UA_HYPER_PAV_ALIAS 0x03 | ||
329 | |||
330 | struct dasd_uid { | ||
331 | __u8 type; | ||
332 | char vendor[4]; | ||
333 | char serial[15]; | ||
334 | __u16 ssid; | ||
335 | __u8 real_unit_addr; | ||
336 | __u8 base_unit_addr; | ||
337 | char vduit[33]; | ||
338 | }; | ||
339 | |||
340 | /* | ||
341 | * Notification numbers for extended error reporting notifications: | 347 | * Notification numbers for extended error reporting notifications: |
342 | * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's | 348 | * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's |
343 | * eer pointer) is freed. The error reporting module needs to do all necessary | 349 | * eer pointer) is freed. The error reporting module needs to do all necessary |
@@ -634,8 +640,6 @@ void dasd_devmap_exit(void); | |||
634 | struct dasd_device *dasd_create_device(struct ccw_device *); | 640 | struct dasd_device *dasd_create_device(struct ccw_device *); |
635 | void dasd_delete_device(struct dasd_device *); | 641 | void dasd_delete_device(struct dasd_device *); |
636 | 642 | ||
637 | int dasd_get_uid(struct ccw_device *, struct dasd_uid *); | ||
638 | int dasd_set_uid(struct ccw_device *, struct dasd_uid *); | ||
639 | int dasd_get_feature(struct ccw_device *, int); | 643 | int dasd_get_feature(struct ccw_device *, int); |
640 | int dasd_set_feature(struct ccw_device *, int, int); | 644 | int dasd_set_feature(struct ccw_device *, int, int); |
641 | 645 | ||