📄 dasd_eckd.c
字号:
case WRITE: if (recid < 3) return DASD_ECKD_CCW_WRITE_KD_MT; if (recid < blk_per_trk) return DASD_ECKD_CCW_WRITE_MT; if (recid < 2 * blk_per_trk) return DASD_ECKD_CCW_WRITE_KD_MT; return DASD_ECKD_CCW_WRITE_MT; break; default: BUG (); } return 0; // never executed}static ccw_req_t *dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req){ ccw_req_t *rw_cp = NULL; int rw_cmd; int bhct; long size; ccw1_t *ccw; DE_eckd_data_t *DE_data; LO_eckd_data_t *LO_data; struct buffer_head *bh; dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private; int byt_per_blk = device->sizes.bp_block; int shift = device->sizes.s2b_shift; int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk); int btrk = (req->sector >> shift) / blk_per_trk; int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk; int recid = req->sector >> shift; int locate4k_set = 0; int nlocs = 0; if (req->cmd == READ) { rw_cmd = DASD_ECKD_CCW_READ_MT; } else if (req->cmd == WRITE) { rw_cmd = DASD_ECKD_CCW_WRITE_MT; } else { PRINT_ERR ("Unknown command %d\n", req->cmd); return NULL; } /* Build the request */ /* count bhs to prevent errors, when bh smaller than block */ bhct = 0; for (bh = req->bh; bh; bh = bh->b_reqnext) { if (bh->b_size < byt_per_blk) BUG(); bhct+= bh->b_size >> (device->sizes.s2b_shift+9); } if (btrk < 2 && private->uses_cdl) { if (etrk < 2) nlocs = bhct; else nlocs = 2 * blk_per_trk - recid; } rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 2 + nlocs + bhct + 1, sizeof (DE_eckd_data_t) + (1 + nlocs) * sizeof (LO_eckd_data_t), device); if (!rw_cp) { return NULL; } DE_data = rw_cp->data; LO_data = rw_cp->data + sizeof (DE_eckd_data_t); ccw = rw_cp->cpaddr; if (define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device, rw_cp)) { goto clear_rw_cp; } ccw->flags |= CCW_FLAG_CC; for (bh = req->bh; bh != NULL;) { for (size = 0; size < bh->b_size; size += byt_per_blk) { if (!locate4k_set) { // we need to chain a locate record before our rw-ccw ccw++; if ((recid / blk_per_trk) < 2 && private->uses_cdl) { /* Do a locate record for our special blocks */ int cmd = dasd_eckd_cdl_cmd (device,recid, req->cmd); if (locate_record (ccw, LO_data++, recid / blk_per_trk, recid % blk_per_trk + 1, 1, cmd, device, dasd_eckd_cdl_reclen(device, recid), rw_cp)) { goto clear_rw_cp; } } else { // Do a locate record for standard blocks */ if (locate_record (ccw, LO_data++, recid /blk_per_trk, recid %blk_per_trk + 1, (((req->sector + req->nr_sectors) >> shift) - recid), rw_cmd, device, device->sizes.bp_block, rw_cp)) { goto clear_rw_cp; } locate4k_set = 1; } ccw->flags |= CCW_FLAG_CC; } ccw++; ccw->flags |= CCW_FLAG_CC; ccw->cmd_code = locate4k_set ? rw_cmd : dasd_eckd_cdl_cmd (device, recid, req->cmd); ccw->count = byt_per_blk; if (!locate4k_set) { ccw->count = dasd_eckd_cdl_reclen (device,recid); if (ccw->count < byt_per_blk) { memset (bh->b_data + size + ccw->count, 0xE5, byt_per_blk - ccw->count); } } if (dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), rw_cp, device)) { goto clear_rw_cp; } recid++; } bh = bh->b_reqnext; } ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC); rw_cp->device = device; rw_cp->expires = 5 * TOD_MIN; /* 5 minutes */ rw_cp->req = req; rw_cp->lpm = LPM_ANYPATH; rw_cp->retries = 2; asm volatile ("STCK %0":"=m" (rw_cp->buildclk)); check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED); goto out; clear_rw_cp: dasd_free_request (rw_cp, device); rw_cp=NULL; out: return rw_cp;}#if 0intdasd_eckd_cleanup_request (ccw_req_t * cqr){ int ret = 0; struct request *req = cqr->req; dasd_device_t *device = cqr->device; int byt_per_blk = device->sizes.bp_block; for (bh = req->bh; bh != NULL;) { if (bh->b_size > byt_per_blk) { for (size = 0; size < bh->b_size; size += byt_per_blk) { ccw++; ccw->flags |= CCW_FLAG_CC; ccw->cmd_code = rw_cmd; ccw->count = byt_per_blk; set_normalized_cda (ccw, __pa (bh->b_data + size)); } bh = bh->b_reqnext; } else { /* group N bhs to fit into byt_per_blk */ for (size = 0; bh != NULL && size < byt_per_blk;) { ccw++; ccw->flags |= CCW_FLAG_DC; ccw->cmd_code = rw_cmd; ccw->count = bh->b_size; set_normalized_cda (ccw, __pa (bh->b_data)); size += bh->b_size; bh = bh->b_reqnext; } } } return ret;}#endif/* * DASD_ECKD_RESERVE * * DESCRIPTION * Buils a channel programm to reserve a device. * Options are set to 'synchronous wait for interrupt' and * 'timeout the request'. This leads to an terminate IO if * the interrupt is outstanding for a certain time. */ccw_req_t *dasd_eckd_reserve (struct dasd_device_t * device){ ccw_req_t *cqr = dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device); if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); return NULL; } cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE; cqr->device = device; cqr->retries = 0; cqr->expires = 10 * TOD_SEC; cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */ cqr->status = CQR_STATUS_FILLED; return cqr; }/* * DASD_ECKD_RELEASE * * DESCRIPTION * Buils a channel programm to releases a prior reserved * (see dasd_eckd_reserve) device. */ccw_req_t *dasd_eckd_release (struct dasd_device_t * device){ ccw_req_t *cqr = dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device); if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); return NULL; } cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE; cqr->device = device; cqr->retries = 0; cqr->expires = 10 * TOD_SEC; cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */ cqr->status = CQR_STATUS_FILLED; return cqr;}/* * DASD_ECKD_STEAL_LOCK * * DESCRIPTION * Buils a channel programm to break a device's reservation. * (unconditional reserve) */ccw_req_t *dasd_eckd_steal_lock (struct dasd_device_t * device){ ccw_req_t *cqr = dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device); if (cqr == NULL) { printk (KERN_WARNING PRINTK_HEADER "No memory to allocate initialization request\n"); return NULL; } cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK; cqr->device = device; cqr->retries = 0; cqr->expires = 10 * TOD_SEC; cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */ cqr->status = CQR_STATUS_FILLED; return cqr;}static inline ccw1_t *dasd_eckd_find_cmd (ccw_req_t * cqr, int cmd){ ccw1_t *cp; cp = cqr->cpaddr; do { if (cp->cmd_code == cmd) return cp; if (cp->cmd_code == CCW_CMD_TIC) { cp = (ccw1_t *) (long) cp->cda; continue; } if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) { cp++; continue; } break; } while (1); return NULL;}static ccw_req_t *dasd_eckd_merge_cp (dasd_device_t * device){ return NULL;}static intdasd_eckd_fill_info (dasd_device_t * device, dasd_information_t * info){ int rc = 0; info->label_block = 2; if (((dasd_eckd_private_t *) device->private)->uses_cdl) info->FBA_layout = 0; else info->FBA_layout = 1; info->characteristics_size = sizeof (dasd_eckd_characteristics_t); memcpy (info->characteristics, &((dasd_eckd_private_t *) device->private)->rdc_data, sizeof (dasd_eckd_characteristics_t)); info->confdata_size = sizeof (dasd_eckd_confdata_t); memcpy (info->configuration_data, &((dasd_eckd_private_t *) device->private)->conf_data, sizeof (dasd_eckd_confdata_t)); return rc;}static char*dasd_eckd_dump_sense (struct dasd_device_t *device, ccw_req_t *req){ char *page = (char *) get_free_page (GFP_ATOMIC); devstat_t *stat = &device->dev_status; char *sense = stat->ii.sense.data; int len, sl, sct; if (page == NULL) { printk (KERN_ERR PRINTK_HEADER "No memory to dump sense data\n"); return NULL; } len = sprintf (page, KERN_ERR PRINTK_HEADER "device %04X on irq %d: I/O status report:\n", device->devinfo.devno, device->devinfo.irq); len += sprintf (page + len, KERN_ERR PRINTK_HEADER "in req: %p CS: 0x%02X DS: 0x%02X\n", req, stat->cstat, stat->dstat); len += sprintf (page + len, KERN_ERR PRINTK_HEADER "Failing CCW: %p\n", (void *) (long) stat->cpa); { ccw1_t *act = req->cpaddr; int i = req->cplength; do {#ifdef ERP_DEBUG printk (KERN_ERR "CCW %p: %08X %08X\n", act, ((int *) act)[0], ((int *) act)[1]); printk (KERN_ERR "DAT: %08X %08X %08X %08X\n", ((int *) act->cda)[0], ((int *) act->cda)[1], ((int *) act->cda)[2], ((int *) act->cda)[3]);#endif /* ERP_DEBUG */ act++; } while (--i); } if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) { for (sl = 0; sl < 4; sl++) { len += sprintf (page + len, KERN_ERR PRINTK_HEADER "Sense(hex) %2d-%2d:", (8 * sl), ((8 * sl) + 7)); for (sct = 0; sct < 8; sct++) { len += sprintf (page + len, " %02x", sense[8 * sl + sct]); } len += sprintf (page + len, "\n"); } if (sense[27] & DASD_SENSE_BIT_0) { /* 24 Byte Sense Data */ len += sprintf (page + len, KERN_ERR PRINTK_HEADER "24 Byte: %x MSG %x, %s MSGb to SYSOP\n", sense[7] >> 4, sense[7] & 0x0f, sense[1] & 0x10 ? "" : "no"); } else { /* 32 Byte Sense Data */ len += sprintf (page + len, KERN_ERR PRINTK_HEADER "32 Byte: Format: %x Exception class %x\n", sense[6] & 0x0f, sense[22] >> 4); } } printk ("Sense data:\n%s", page); free_page ((unsigned long) page); return NULL;}dasd_discipline_t dasd_eckd_discipline = { owner: THIS_MODULE, name:"ECKD", ebcname:"ECKD", max_blocks:255, id_check:dasd_eckd_id_check, check_characteristics:dasd_eckd_check_characteristics, init_analysis:dasd_eckd_init_analysis, do_analysis:dasd_eckd_do_analysis, fill_geometry:dasd_eckd_fill_geometry, start_IO:dasd_start_IO, term_IO:dasd_term_IO, format_device:dasd_eckd_format_device, examine_error:dasd_eckd_examine_error, erp_action:dasd_eckd_erp_action, erp_postaction:dasd_eckd_erp_postaction, build_cp_from_req:dasd_eckd_build_cp_from_req, dump_sense:dasd_eckd_dump_sense, int_handler:dasd_int_handler, reserve:dasd_eckd_reserve, release:dasd_eckd_release, steal_lock:dasd_eckd_steal_lock, merge_cp:dasd_eckd_merge_cp, fill_info:dasd_eckd_fill_info,};intdasd_eckd_init (void){ int rc = 0; printk (KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_eckd_discipline.name); ASCEBC (dasd_eckd_discipline.ebcname, 4); dasd_discipline_add (&dasd_eckd_discipline);#ifdef CONFIG_DASD_DYNAMIC { int i; for (i = 0; i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); i++) { printk (KERN_INFO PRINTK_HEADER "We are interested in: CU %04X/%02x\n", dasd_eckd_known_devices[i].ci.hc.ctype, dasd_eckd_known_devices[i].ci.hc.cmode); s390_device_register (&dasd_eckd_known_devices[i]); } }#endif /* CONFIG_DASD_DYNAMIC */ return rc;}voiddasd_eckd_cleanup (void){ printk (KERN_INFO PRINTK_HEADER "%s discipline cleaning up\n", dasd_eckd_discipline.name);#ifdef CONFIG_DASD_DYNAMIC { int i; for (i = 0; i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); i++) { printk (KERN_INFO PRINTK_HEADER "We were interested in: CU %04X/%02x\n", dasd_eckd_known_devices[i].ci.hc.ctype, dasd_eckd_known_devices[i].ci.hc.cmode); s390_device_unregister (&dasd_eckd_known_devices[i]); } }#endif /* CONFIG_DASD_DYNAMIC */ dasd_discipline_del (&dasd_eckd_discipline);}#ifdef MODULEintinit_module (void){ int rc = 0; rc = dasd_eckd_init (); return rc;}voidcleanup_module (void){ dasd_eckd_cleanup (); return;}#endif/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -