📄 dasd_3990_erp.c
字号:
/* * File...........: linux/drivers/s390/block/dasd_3990_erp.c * Author(s)......: Horst Hummel <Horst.Hummel@de.ibm.com> * Holger Smolinski <Holger.Smolinski@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 * * $Revision: 1.36 $ */#include <linux/timer.h>#include <linux/slab.h>#include <asm/idals.h>#include <asm/todclk.h>#define PRINTK_HEADER "dasd_erp(3990): "#include "dasd_int.h"#include "dasd_eckd.h"struct DCTL_data { unsigned char subcommand; /* e.g Inhibit Write, Enable Write,... */ unsigned char modifier; /* Subcommand modifier */ unsigned short res; /* reserved */} __attribute__ ((packed));/* ***************************************************************************** * SECTION ERP EXAMINATION ***************************************************************************** *//* * DASD_3990_ERP_EXAMINE_24 * * DESCRIPTION * Checks only for fatal (unrecoverable) error. * A detailed examination of the sense data is done later outside * the interrupt handler. * * Each bit configuration leading to an action code 2 (Exit with * programming error or unusual condition indication) * are handled as fatal error磗. * * All other configurations are handled as recoverable errors. * * RETURN VALUES * dasd_era_fatal for all fatal (unrecoverable errors) * dasd_era_recover for all others. */static dasd_era_tdasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense){ struct dasd_device *device = cqr->device; /* check for 'Command Reject' */ if ((sense[0] & SNS0_CMD_REJECT) && (!(sense[2] & SNS2_ENV_DATA_PRESENT))) { DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 24: Command Reject detected - " "fatal error"); return dasd_era_fatal; } /* check for 'Invalid Track Format' */ if ((sense[1] & SNS1_INV_TRACK_FORMAT) && (!(sense[2] & SNS2_ENV_DATA_PRESENT))) { DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 24: Invalid Track Format detected " "- fatal error"); return dasd_era_fatal; } /* check for 'No Record Found' */ if (sense[1] & SNS1_NO_REC_FOUND) { /* FIXME: fatal error ?!? */ DEV_MESSAGE(KERN_ERR, device, "EXAMINE 24: No Record Found detected %s", device->state <= DASD_STATE_BASIC ? " " : "- fatal error"); return dasd_era_fatal; } /* return recoverable for all others */ return dasd_era_recover;} /* END dasd_3990_erp_examine_24 *//* * DASD_3990_ERP_EXAMINE_32 * * DESCRIPTION * Checks only for fatal/no/recoverable error. * A detailed examination of the sense data is done later outside * the interrupt handler. * * RETURN VALUES * dasd_era_none no error * dasd_era_fatal for all fatal (unrecoverable errors) * dasd_era_recover for recoverable others. */static dasd_era_tdasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense){ struct dasd_device *device = cqr->device; switch (sense[25]) { case 0x00: return dasd_era_none; case 0x01: DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error"); return dasd_era_fatal; default: return dasd_era_recover; }} /* end dasd_3990_erp_examine_32 *//* * DASD_3990_ERP_EXAMINE * * DESCRIPTION * Checks only for fatal/no/recover error. * A detailed examination of the sense data is done later outside * the interrupt handler. * * The logic is based on the 'IBM 3990 Storage Control Reference' manual * 'Chapter 7. Error Recovery Procedures'. * * RETURN VALUES * dasd_era_none no error * dasd_era_fatal for all fatal (unrecoverable errors) * dasd_era_recover for all others. */dasd_era_tdasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb){ char *sense = irb->ecw; dasd_era_t era = dasd_era_recover; struct dasd_device *device = cqr->device; /* check for successful execution first */ if (irb->scsw.cstat == 0x00 && irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) return dasd_era_none; /* distinguish between 24 and 32 byte sense data */ if (sense[27] & DASD_SENSE_BIT_0) { era = dasd_3990_erp_examine_24(cqr, sense); } else { era = dasd_3990_erp_examine_32(cqr, sense); } /* log the erp chain if fatal error occurred */ if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) { dasd_log_sense(cqr, irb); dasd_log_ccw(cqr, 0, irb->scsw.cpa); } return era;} /* END dasd_3990_erp_examine *//* ***************************************************************************** * SECTION ERP HANDLING ***************************************************************************** *//* ***************************************************************************** * 24 and 32 byte sense ERP functions ***************************************************************************** *//* * DASD_3990_ERP_CLEANUP * * DESCRIPTION * Removes the already build but not necessary ERP request and sets * the status of the original cqr / erp to the given (final) status * * PARAMETER * erp request to be blocked * final_status either DASD_CQR_DONE or DASD_CQR_FAILED * * RETURN VALUES * cqr original cqr */static struct dasd_ccw_req *dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status){ struct dasd_ccw_req *cqr = erp->refers; dasd_free_erp_request(erp, erp->device); cqr->status = final_status; return cqr;} /* end dasd_3990_erp_cleanup *//* * DASD_3990_ERP_BLOCK_QUEUE * * DESCRIPTION * Block the given device request queue to prevent from further * processing until the started timer has expired or an related * interrupt was received. */static voiddasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires){ struct dasd_device *device = erp->device; DEV_MESSAGE(KERN_INFO, device, "blocking request queue for %is", expires/HZ); device->stopped |= DASD_STOPPED_PENDING; erp->status = DASD_CQR_QUEUED; dasd_set_timer(device, expires);}/* * DASD_3990_ERP_INT_REQ * * DESCRIPTION * Handles 'Intervention Required' error. * This means either device offline or not installed. * * PARAMETER * erp current erp * RETURN VALUES * erp modified erp */static struct dasd_ccw_req *dasd_3990_erp_int_req(struct dasd_ccw_req * erp){ struct dasd_device *device = erp->device; /* first time set initial retry counter and erp_function */ /* and retry once without blocking queue */ /* (this enables easier enqueing of the cqr) */ if (erp->function != dasd_3990_erp_int_req) { erp->retries = 256; erp->function = dasd_3990_erp_int_req; } else { /* issue a message and wait for 'device ready' interrupt */ DEV_MESSAGE(KERN_ERR, device, "%s", "is offline or not installed - " "INTERVENTION REQUIRED!!"); dasd_3990_erp_block_queue(erp, 60*HZ); } return erp;} /* end dasd_3990_erp_int_req *//* * DASD_3990_ERP_ALTERNATE_PATH * * DESCRIPTION * Repeat the operation on a different channel path. * If all alternate paths have been tried, the request is posted with a * permanent error. * * PARAMETER * erp pointer to the current ERP * * RETURN VALUES * erp modified pointer to the ERP */static voiddasd_3990_erp_alternate_path(struct dasd_ccw_req * erp){ struct dasd_device *device = erp->device; __u8 opm; /* try alternate valid path */ opm = ccw_device_get_path_mask(device->cdev); //FIXME: start with get_opm ? if (erp->lpm == 0) erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum); else erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); if ((erp->lpm & opm) != 0x00) { DEV_MESSAGE(KERN_DEBUG, device, "try alternate lpm=%x (lpum=%x / opm=%x)", erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm); /* reset status to queued to handle the request again... */ if (erp->status > DASD_CQR_QUEUED) erp->status = DASD_CQR_QUEUED; erp->retries = 1; } else { DEV_MESSAGE(KERN_ERR, device, "No alternate channel path left (lpum=%x / " "opm=%x) -> permanent error", erp->irb.esw.esw0.sublog.lpum, opm); /* post request with permanent error */ if (erp->status > DASD_CQR_QUEUED) erp->status = DASD_CQR_FAILED; }} /* end dasd_3990_erp_alternate_path *//* * DASD_3990_ERP_DCTL * * DESCRIPTION * Setup cqr to do the Diagnostic Control (DCTL) command with an * Inhibit Write subcommand (0x20) and the given modifier. * * PARAMETER * erp pointer to the current (failed) ERP * modifier subcommand modifier * * RETURN VALUES * dctl_cqr pointer to NEW dctl_cqr * */static struct dasd_ccw_req *dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier){ struct dasd_device *device = erp->device; struct DCTL_data *DCTL_data; struct ccw1 *ccw; struct dasd_ccw_req *dctl_cqr; dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1, sizeof (struct DCTL_data), erp->device); if (IS_ERR(dctl_cqr)) { DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate DCTL-CQR"); erp->status = DASD_CQR_FAILED; return erp; } DCTL_data = dctl_cqr->data; DCTL_data->subcommand = 0x02; /* Inhibit Write */ DCTL_data->modifier = modifier; ccw = dctl_cqr->cpaddr; memset(ccw, 0, sizeof (struct ccw1)); ccw->cmd_code = CCW_CMD_DCTL; ccw->count = 4; ccw->cda = (__u32)(addr_t) DCTL_data; dctl_cqr->function = dasd_3990_erp_DCTL; dctl_cqr->refers = erp; dctl_cqr->device = erp->device; dctl_cqr->magic = erp->magic; dctl_cqr->expires = 5 * 60 * HZ; dctl_cqr->retries = 2; dctl_cqr->buildclk = get_clock(); dctl_cqr->status = DASD_CQR_FILLED; return dctl_cqr;} /* end dasd_3990_erp_DCTL *//* * DASD_3990_ERP_ACTION_1 * * DESCRIPTION * Setup ERP to do the ERP action 1 (see Reference manual). * Repeat the operation on a different channel path. * If all alternate paths have been tried, the request is posted with a * permanent error. * Note: duplex handling is not implemented (yet). * * PARAMETER * erp pointer to the current ERP * * RETURN VALUES * erp pointer to the ERP * */static struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req * erp){ erp->function = dasd_3990_erp_action_1; dasd_3990_erp_alternate_path(erp); return erp;} /* end dasd_3990_erp_action_1 *//* * DASD_3990_ERP_ACTION_4 * * DESCRIPTION * Setup ERP to do the ERP action 4 (see Reference manual). * Set the current request to PENDING to block the CQR queue for that device * until the state change interrupt appears. * Use a timer (20 seconds) to retry the cqr if the interrupt is still * missing. * * PARAMETER * sense sense data of the actual error * erp pointer to the current ERP * * RETURN VALUES * erp pointer to the ERP * */static struct dasd_ccw_req *dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense){ struct dasd_device *device = erp->device; /* first time set initial retry counter and erp_function */ /* and retry once without waiting for state change pending */ /* interrupt (this enables easier enqueing of the cqr) */ if (erp->function != dasd_3990_erp_action_4) { DEV_MESSAGE(KERN_INFO, device, "%s", "dasd_3990_erp_action_4: first time retry"); erp->retries = 256; erp->function = dasd_3990_erp_action_4; } else { if (sense[25] == 0x1D) { /* state change pending */ DEV_MESSAGE(KERN_INFO, device, "waiting for state change pending " "interrupt, %d retries left", erp->retries); dasd_3990_erp_block_queue(erp, 30*HZ); } else if (sense[25] == 0x1E) { /* busy */ DEV_MESSAGE(KERN_INFO, device, "busy - redriving request later, " "%d retries left", erp->retries); dasd_3990_erp_block_queue(erp, HZ); } else { /* no state change pending - retry */ DEV_MESSAGE (KERN_INFO, device, "redriving request immediately, " "%d retries left", erp->retries); erp->status = DASD_CQR_QUEUED; } } return erp;} /* end dasd_3990_erp_action_4 *//* ***************************************************************************** * 24 byte sense ERP functions (only) ***************************************************************************** *//* * DASD_3990_ERP_ACTION_5 * * DESCRIPTION * Setup ERP to do the ERP action 5 (see Reference manual). * NOTE: Further handling is done in xxx_further_erp after the retries. * * PARAMETER * erp pointer to the current ERP * * RETURN VALUES * erp pointer to the ERP * */static struct dasd_ccw_req *dasd_3990_erp_action_5(struct dasd_ccw_req * erp){ /* first of all retry */ erp->retries = 10; erp->function = dasd_3990_erp_action_5; return erp;} /* end dasd_3990_erp_action_5 *//* * DASD_3990_HANDLE_ENV_DATA * * DESCRIPTION * Handles 24 byte 'Environmental data present'.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -