diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 10:11:02 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 10:11:02 -0800 |
commit | 39ce941ec15032c0efc3632b9f00a6b2365e1870 (patch) | |
tree | 9ac548adf0444b8a74e31c984e5a49766fc2c385 /drivers | |
parent | 3d412f60b71e588544e7b75861084f12aa1d7acd (diff) | |
parent | c5411dba58c28736d25cffef65da1e01ed7d1423 (diff) | |
download | lwn-39ce941ec15032c0efc3632b9f00a6b2365e1870.tar.gz lwn-39ce941ec15032c0efc3632b9f00a6b2365e1870.zip |
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6:
[S390] dcss: Initialize workqueue before using it.
[S390] Remove BUILD_BUG_ON() in vmem code.
[S390] sclp_tty/sclp_vt220: Fix scheduling while atomic
[S390] dasd: fix panic caused by alias device offline
[S390] dasd: add ifcc handling
[S390] latencytop s390 support.
[S390] Implement ext2_find_next_bit.
[S390] Cleanup & optimize bitops.
[S390] Define GENERIC_LOCKBREAK.
[S390] console: allow vt220 console to be the only console
[S390] Fix couple of section mismatches.
[S390] Fix smp_call_function_mask semantics.
[S390] Fix linker script.
[S390] DEBUG_PAGEALLOC support for s390.
[S390] cio: Add shutdown callback for ccwgroup.
[S390] cio: Update documentation.
[S390] cio: Clean up chsc response code handling.
[S390] cio: make sense id procedure work with partial hardware response
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/block/dasd.c | 19 | ||||
-rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 62 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 5 | ||||
-rw-r--r-- | drivers/s390/char/sclp_tty.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp_vt220.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 147 | ||||
-rw-r--r-- | drivers/s390/cio/device_id.c | 107 |
8 files changed, 188 insertions, 168 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d640427c74c8..d984e0fae630 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1057,12 +1057,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, if (device->features & DASD_FEATURE_ERPLOG) { dasd_log_sense(cqr, irb); } - /* If we have no sense data, or we just don't want complex ERP - * for this request, but if we have retries left, then just - * reset this request and retry it in the fastpath + /* + * If we don't want complex ERP for this request, then just + * reset this and retry it in the fastpath */ - if (!(cqr->irb.esw.esw0.erw.cons && - test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) && + if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) && cqr->retries > 0) { DEV_MESSAGE(KERN_DEBUG, device, "default ERP in fastpath (%i retries left)", @@ -1707,7 +1706,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) req = (struct request *) cqr->callback_data; dasd_profile_end(cqr->block, cqr, req); - status = cqr->memdev->discipline->free_cp(cqr, req); + status = cqr->block->base->discipline->free_cp(cqr, req); if (status <= 0) error = status ? status : -EIO; dasd_end_request(req, error); @@ -1742,12 +1741,8 @@ restart: /* Process requests that may be recovered */ if (cqr->status == DASD_CQR_NEED_ERP) { - if (cqr->irb.esw.esw0.erw.cons && - test_bit(DASD_CQR_FLAGS_USE_ERP, - &cqr->flags)) { - erp_fn = base->discipline->erp_action(cqr); - erp_fn(cqr); - } + erp_fn = base->discipline->erp_action(cqr); + erp_fn(cqr); goto restart; } diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index c361ab69ec00..f69714a0e9e7 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -164,7 +164,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) /* reset status to submit the request again... */ erp->status = DASD_CQR_FILLED; - erp->retries = 1; + erp->retries = 10; } else { DEV_MESSAGE(KERN_ERR, device, "No alternate channel path left (lpum=%x / " @@ -301,8 +301,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) erp->function = dasd_3990_erp_action_4; } else { - - if (sense[25] == 0x1D) { /* state change pending */ + if (sense && (sense[25] == 0x1D)) { /* state change pending */ DEV_MESSAGE(KERN_INFO, device, "waiting for state change pending " @@ -311,7 +310,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) dasd_3990_erp_block_queue(erp, 30*HZ); - } else if (sense[25] == 0x1E) { /* busy */ + } else if (sense && (sense[25] == 0x1E)) { /* busy */ DEV_MESSAGE(KERN_INFO, device, "busy - redriving request later, " "%d retries left", @@ -2120,6 +2119,34 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) */ /* + * DASD_3990_ERP_CONTROL_CHECK + * + * DESCRIPTION + * Does a generic inspection if a control check occured and sets up + * the related error recovery procedure + * + * PARAMETER + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp_filled pointer to the erp + */ + +static struct dasd_ccw_req * +dasd_3990_erp_control_check(struct dasd_ccw_req *erp) +{ + struct dasd_device *device = erp->startdev; + + if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK + | SCHN_STAT_CHN_CTRL_CHK)) { + DEV_MESSAGE(KERN_DEBUG, device, "%s", + "channel or interface control check"); + erp = dasd_3990_erp_action_4(erp, NULL); + } + return erp; +} + +/* * DASD_3990_ERP_INSPECT * * DESCRIPTION @@ -2145,8 +2172,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp) if (erp_new) return erp_new; + /* check if no concurrent sens is available */ + if (!erp->refers->irb.esw.esw0.erw.cons) + erp_new = dasd_3990_erp_control_check(erp); /* distinguish between 24 and 32 byte sense data */ - if (sense[27] & DASD_SENSE_BIT_0) { + else if (sense[27] & DASD_SENSE_BIT_0) { /* inspect the 24 byte sense data */ erp_new = dasd_3990_erp_inspect_24(erp, sense); @@ -2285,6 +2315,17 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) // return 0; /* CCW doesn't match */ } + if (cqr1->irb.esw.esw0.erw.cons != cqr2->irb.esw.esw0.erw.cons) + return 0; + + if ((cqr1->irb.esw.esw0.erw.cons == 0) && + (cqr2->irb.esw.esw0.erw.cons == 0)) { + if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | + SCHN_STAT_CHN_CTRL_CHK)) == + (cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | + SCHN_STAT_CHN_CTRL_CHK))) + return 1; /* match with ifcc*/ + } /* check sense data; byte 0-2,25,27 */ if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && @@ -2560,17 +2601,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) return cqr; } - /* check if sense data are available */ - if (!cqr->irb.ecw) { - DEV_MESSAGE(KERN_DEBUG, device, - "ERP called witout sense data avail ..." - "request %p - NO ERP possible", cqr); - - cqr->status = DASD_CQR_FAILED; - - return cqr; - - } /* check if error happened before */ erp = dasd_3990_erp_in_erp(cqr); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 7779bfce1c31..3faf0538b328 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -415,6 +415,8 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char dev_info->gd->queue = dev_info->dcssblk_queue; dev_info->gd->private_data = dev_info; dev_info->gd->driverfs_dev = &dev_info->dev; + blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); + blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); /* * load the segment */ @@ -472,9 +474,6 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char if (rc) goto unregister_dev; - blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request); - blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096); - add_disk(dev_info->gd); switch (dev_info->segment_type) { diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index e3b3d390b4a3..2e616e33891d 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -332,7 +332,7 @@ sclp_tty_write_string(const unsigned char *str, int count) if (sclp_ttybuf == NULL) { while (list_empty(&sclp_tty_pages)) { spin_unlock_irqrestore(&sclp_tty_lock, flags); - if (in_interrupt()) + if (in_atomic()) sclp_sync_wait(); else wait_event(sclp_tty_waitq, diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 40cd21bc5cc4..68071622d4bb 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -400,7 +400,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, while (list_empty(&sclp_vt220_empty)) { spin_unlock_irqrestore(&sclp_vt220_lock, flags); - if (in_interrupt()) + if (in_atomic()) sclp_sync_wait(); else wait_event(sclp_vt220_waitq, diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 3964056a9a47..03914fa81174 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -391,12 +391,24 @@ ccwgroup_remove (struct device *dev) return 0; } +static void ccwgroup_shutdown(struct device *dev) +{ + struct ccwgroup_device *gdev; + struct ccwgroup_driver *gdrv; + + gdev = to_ccwgroupdev(dev); + gdrv = to_ccwgroupdrv(dev->driver); + if (gdrv && gdrv->shutdown) + gdrv->shutdown(gdev); +} + static struct bus_type ccwgroup_bus_type = { .name = "ccwgroup", .match = ccwgroup_bus_match, .uevent = ccwgroup_uevent, .probe = ccwgroup_probe, .remove = ccwgroup_remove, + .shutdown = ccwgroup_shutdown, }; /** diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index e7ba16a74ef7..007aaeb4f532 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -26,6 +26,25 @@ static void *sei_page; +static int chsc_error_from_response(int response) +{ + switch (response) { + case 0x0001: + return 0; + case 0x0002: + case 0x0003: + case 0x0006: + case 0x0007: + case 0x0008: + case 0x000a: + return -EINVAL; + case 0x0004: + return -EOPNOTSUPP; + default: + return -EIO; + } +} + struct chsc_ssd_area { struct chsc_header request; u16 :10; @@ -75,11 +94,11 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) ret = (ccode == 3) ? -ENODEV : -EBUSY; goto out_free; } - if (ssd_area->response.code != 0x0001) { + ret = chsc_error_from_response(ssd_area->response.code); + if (ret != 0) { CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n", schid.ssid, schid.sch_no, ssd_area->response.code); - ret = -EIO; goto out_free; } if (!ssd_area->sch_valid) { @@ -717,36 +736,15 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) return (ccode == 3) ? -ENODEV : -EBUSY; switch (secm_area->response.code) { - case 0x0001: /* Success. */ - ret = 0; - break; - case 0x0003: /* Invalid block. */ - case 0x0007: /* Invalid format. */ - case 0x0008: /* Other invalid block. */ - CIO_CRW_EVENT(2, "Error in chsc request block!\n"); - ret = -EINVAL; - break; - case 0x0004: /* Command not provided in model. */ - CIO_CRW_EVENT(2, "Model does not provide secm\n"); - ret = -EOPNOTSUPP; - break; - case 0x0102: /* cub adresses incorrect */ - CIO_CRW_EVENT(2, "Invalid addresses in chsc request block\n"); - ret = -EINVAL; - break; - case 0x0103: /* key error */ - CIO_CRW_EVENT(2, "Access key error in secm\n"); + case 0x0102: + case 0x0103: ret = -EINVAL; - break; - case 0x0105: /* error while starting */ - CIO_CRW_EVENT(2, "Error while starting channel measurement\n"); - ret = -EIO; - break; default: - CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", - secm_area->response.code); - ret = -EIO; + ret = chsc_error_from_response(secm_area->response.code); } + if (ret != 0) + CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n", + secm_area->response.code); return ret; } @@ -827,27 +825,14 @@ int chsc_determine_channel_path_description(struct chp_id chpid, goto out; } - switch (scpd_area->response.code) { - case 0x0001: /* Success. */ + ret = chsc_error_from_response(scpd_area->response.code); + if (ret == 0) + /* Success. */ memcpy(desc, &scpd_area->desc, sizeof(struct channel_path_desc)); - ret = 0; - break; - case 0x0003: /* Invalid block. */ - case 0x0007: /* Invalid format. */ - case 0x0008: /* Other invalid block. */ - CIO_CRW_EVENT(2, "Error in chsc request block!\n"); - ret = -EINVAL; - break; - case 0x0004: /* Command not provided in model. */ - CIO_CRW_EVENT(2, "Model does not provide scpd\n"); - ret = -EOPNOTSUPP; - break; - default: - CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", + else + CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", scpd_area->response.code); - ret = -EIO; - } out: free_page((unsigned long)scpd_area); return ret; @@ -923,8 +908,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) goto out; } - switch (scmc_area->response.code) { - case 0x0001: /* Success. */ + ret = chsc_error_from_response(scmc_area->response.code); + if (ret == 0) { + /* Success. */ if (!scmc_area->not_valid) { chp->cmg = scmc_area->cmg; chp->shared = scmc_area->shared; @@ -935,22 +921,9 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) chp->cmg = -1; chp->shared = -1; } - ret = 0; - break; - case 0x0003: /* Invalid block. */ - case 0x0007: /* Invalid format. */ - case 0x0008: /* Invalid bit combination. */ - CIO_CRW_EVENT(2, "Error in chsc request block!\n"); - ret = -EINVAL; - break; - case 0x0004: /* Command not provided. */ - CIO_CRW_EVENT(2, "Model does not provide scmc\n"); - ret = -EOPNOTSUPP; - break; - default: - CIO_CRW_EVENT(2, "Unknown CHSC response %d\n", + } else { + CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n", scmc_area->response.code); - ret = -EIO; } out: free_page((unsigned long)scmc_area); @@ -1002,21 +975,17 @@ chsc_enable_facility(int operation_code) ret = (ret == 3) ? -ENODEV : -EBUSY; goto out; } + switch (sda_area->response.code) { - case 0x0001: /* everything ok */ - ret = 0; - break; - case 0x0003: /* invalid request block */ - case 0x0007: - ret = -EINVAL; - break; - case 0x0004: /* command not provided */ - case 0x0101: /* facility not provided */ + case 0x0101: ret = -EOPNOTSUPP; break; - default: /* something went wrong */ - ret = -EIO; + default: + ret = chsc_error_from_response(sda_area->response.code); } + if (ret != 0) + CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n", + operation_code, sda_area->response.code); out: free_page((unsigned long)sda_area); return ret; @@ -1041,33 +1010,27 @@ chsc_determine_css_characteristics(void) } __attribute__ ((packed)) *scsc_area; scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!scsc_area) { - CIO_MSG_EVENT(0, "Was not able to determine available " - "CHSCs due to no memory.\n"); + if (!scsc_area) return -ENOMEM; - } scsc_area->request.length = 0x0010; scsc_area->request.code = 0x0010; result = chsc(scsc_area); if (result) { - CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, " - "cc=%i.\n", result); - result = -EIO; + result = (result == 3) ? -ENODEV : -EBUSY; goto exit; } - if (scsc_area->response.code != 1) { - CIO_MSG_EVENT(0, "Was not able to determine " - "available CHSCs.\n"); - result = -EIO; - goto exit; - } - memcpy(&css_general_characteristics, scsc_area->general_char, - sizeof(css_general_characteristics)); - memcpy(&css_chsc_characteristics, scsc_area->chsc_char, - sizeof(css_chsc_characteristics)); + result = chsc_error_from_response(scsc_area->response.code); + if (result == 0) { + memcpy(&css_general_characteristics, scsc_area->general_char, + sizeof(css_general_characteristics)); + memcpy(&css_chsc_characteristics, scsc_area->chsc_char, + sizeof(css_chsc_characteristics)); + } else + CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n", + scsc_area->response.code); exit: free_page ((unsigned long) scsc_area); return result; diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 918b8b89cf9a..dc4d87f77f6c 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -26,17 +26,18 @@ #include "ioasm.h" #include "io_sch.h" -/* - * Input : - * devno - device number - * ps - pointer to sense ID data area - * Output : none +/** + * vm_vdev_to_cu_type - Convert vm virtual device into control unit type + * for certain devices. + * @class: virtual device class + * @type: virtual device type + * + * Returns control unit type if a match was made or %0xffff otherwise. */ -static void -VM_virtual_device_info (__u16 devno, struct senseid *ps) +static int vm_vdev_to_cu_type(int class, int type) { static struct { - int vrdcvcla, vrdcvtyp, cu_type; + int class, type, cu_type; } vm_devices[] = { { 0x08, 0x01, 0x3480 }, { 0x08, 0x02, 0x3430 }, @@ -68,8 +69,26 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) { 0x40, 0xc0, 0x5080 }, { 0x80, 0x00, 0x3215 }, }; + int i; + + for (i = 0; i < ARRAY_SIZE(vm_devices); i++) + if (class == vm_devices[i].class && type == vm_devices[i].type) + return vm_devices[i].cu_type; + + return 0xffff; +} + +/** + * diag_get_dev_info - retrieve device information via DIAG X'210' + * @devno: device number + * @ps: pointer to sense ID data area + * + * Returns zero on success, non-zero otherwise. + */ +static int diag_get_dev_info(u16 devno, struct senseid *ps) +{ struct diag210 diag_data; - int ccode, i; + int ccode; CIO_TRACE_EVENT (4, "VMvdinf"); @@ -79,21 +98,21 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) }; ccode = diag210 (&diag_data); - ps->reserved = 0xff; + if ((ccode == 0) || (ccode == 2)) { + ps->reserved = 0xff; - /* Special case for bloody osa devices. */ - if (diag_data.vrdcvcla == 0x02 && - diag_data.vrdcvtyp == 0x20) { - ps->cu_type = 0x3088; - ps->cu_model = 0x60; - return; - } - for (i = 0; i < ARRAY_SIZE(vm_devices); i++) - if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla && - diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) { - ps->cu_type = vm_devices[i].cu_type; - return; + /* Special case for osa devices. */ + if (diag_data.vrdcvcla == 0x02 && diag_data.vrdcvtyp == 0x20) { + ps->cu_type = 0x3088; + ps->cu_model = 0x60; + return 0; } + ps->cu_type = vm_vdev_to_cu_type(diag_data.vrdcvcla, + diag_data.vrdcvtyp); + if (ps->cu_type != 0xffff) + return 0; + } + CIO_MSG_EVENT(0, "DIAG X'210' for device %04X returned (cc = %d):" "vdev class : %02X, vdev type : %04X \n ... " "rdev class : %02X, rdev type : %04X, " @@ -102,6 +121,8 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps) diag_data.vrdcvcla, diag_data.vrdcvtyp, diag_data.vrdcrccl, diag_data.vrdccrty, diag_data.vrdccrmd); + + return -ENODEV; } /* @@ -130,6 +151,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev) /* Try on every path. */ ret = -ENODEV; while (cdev->private->imask != 0) { + cdev->private->senseid.cu_type = 0xFFFF; if ((sch->opm & cdev->private->imask) != 0 && cdev->private->iretry > 0) { cdev->private->iretry--; @@ -153,7 +175,6 @@ ccw_device_sense_id_start(struct ccw_device *cdev) int ret; memset (&cdev->private->senseid, 0, sizeof (struct senseid)); - cdev->private->senseid.cu_type = 0xFFFF; cdev->private->imask = 0x80; cdev->private->iretry = 5; ret = __ccw_device_sense_id_start(cdev); @@ -173,13 +194,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - /* Did we get a proper answer ? */ - if (cdev->private->senseid.cu_type != 0xFFFF && - cdev->private->senseid.reserved == 0xFF) { - if (irb->scsw.count < sizeof (struct senseid) - 8) - cdev->private->flags.esid = 1; - return 0; /* Success */ - } + /* Check the error cases. */ if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Sense ID if requested. */ @@ -231,6 +246,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev) sch->schid.ssid, sch->schid.sch_no); return -EACCES; } + + /* Did we get a proper answer ? */ + if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF && + cdev->private->senseid.reserved == 0xFF) { + if (irb->scsw.count < sizeof(struct senseid) - 8) + cdev->private->flags.esid = 1; + return 0; /* Success */ + } + /* Hmm, whatever happened, try again. */ CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " "subchannel 0.%x.%04x returns status %02X%02X\n", @@ -283,20 +307,17 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) break; /* fall through. */ default: /* Sense ID failed. Try asking VM. */ - if (MACHINE_IS_VM) { - VM_virtual_device_info (cdev->private->dev_id.devno, + if (MACHINE_IS_VM) + ret = diag_get_dev_info(cdev->private->dev_id.devno, &cdev->private->senseid); - if (cdev->private->senseid.cu_type != 0xFFFF) { - /* Got the device information from VM. */ - ccw_device_sense_id_done(cdev, 0); - return; - } - } - /* - * If we can't couldn't identify the device type we - * consider the device "not operational". - */ - ccw_device_sense_id_done(cdev, -ENODEV); + else + /* + * If we can't couldn't identify the device type we + * consider the device "not operational". + */ + ret = -ENODEV; + + ccw_device_sense_id_done(cdev, ret); break; } } |