void dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa) { struct dasd_device *device; struct dasd_ccw_req *lcqr; struct ccw1 *ccw; int cplength; device = cqr->device; /* log the channel program */ for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) { DEV_MESSAGE(KERN_ERR, device, "(%s) ERP chain report for req: %p", caller == 0 ? "EXAMINE" : "ACTION", lcqr); hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req)); cplength = 1; ccw = lcqr->cpaddr; while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) cplength++; if (cplength > 40) { /* log only parts of the CP */ DEV_MESSAGE(KERN_ERR, device, "%s", "Start of channel program:"); hex_dump_memory(device, lcqr->cpaddr, 40*sizeof(struct ccw1)); DEV_MESSAGE(KERN_ERR, device, "%s", "End of channel program:"); hex_dump_memory(device, lcqr->cpaddr + cplength - 10, 10*sizeof(struct ccw1)); } else { /* log the whole CP */ DEV_MESSAGE(KERN_ERR, device, "%s", "Channel program (complete):"); hex_dump_memory(device, lcqr->cpaddr, cplength*sizeof(struct ccw1)); } if (lcqr != cqr) continue; /* * Log bytes arround failed CCW but only if we did * not log the whole CP of the CCW is outside the * logged CP. */ if (cplength > 40 || ((addr_t) cpa < (addr_t) lcqr->cpaddr && (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) { DEV_MESSAGE(KERN_ERR, device, "Failed CCW (%p) (area):", (void *) (long) cpa); hex_dump_memory(device, cqr->cpaddr - 10, 20*sizeof(struct ccw1)); } } } /* end log_erp_chain */
/* * performs formatting of _device_ according to _fdata_ * Note: The discipline's format_function is assumed to deliver formatting * commands to format a single unit of the device. In terms of the ECKD * devices this means CCWs are generated to format a single track. */ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) { struct dasd_ccw_req *cqr; struct dasd_device *base; int rc; base = block->base; if (base->discipline->format_device == NULL) return -EPERM; if (base->state != DASD_STATE_BASIC) { DEV_MESSAGE(KERN_WARNING, base, "%s", "dasd_format: device is not disabled! "); return -EBUSY; } DBF_DEV_EVENT(DBF_NOTICE, base, "formatting units %d to %d (%d B blocks) flags %d", fdata->start_unit, fdata->stop_unit, fdata->blksize, fdata->intensity); /* Since dasdfmt keeps the device open after it was disabled, * there still exists an inode for this device. * We must update i_blkbits, otherwise we might get errors when * enabling the device later. */ if (fdata->start_unit == 0) { struct block_device *bdev = bdget_disk(block->gdp, 0); bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize); bdput(bdev); } while (fdata->start_unit <= fdata->stop_unit) { cqr = base->discipline->format_device(base, fdata); if (IS_ERR(cqr)) return PTR_ERR(cqr); rc = dasd_sleep_on_interruptible(cqr); dasd_sfree_request(cqr, cqr->memdev); if (rc) { if (rc != -ERESTARTSYS) DEV_MESSAGE(KERN_ERR, base, " Formatting of unit %d failed " "with rc = %d", fdata->start_unit, rc); return rc; } fdata->start_unit++; } return 0; }
/* * dasd_default_erp_action just retries the current cqr */ struct dasd_ccw_req * dasd_default_erp_action(struct dasd_ccw_req *cqr) { struct dasd_device *device; device = cqr->startdev; /* just retry - there is nothing to save ... I got no sense data.... */ if (cqr->retries > 0) { DEV_MESSAGE (KERN_DEBUG, device, "default ERP called (%i retries left)", cqr->retries); cqr->lpm = LPM_ANYPATH; cqr->status = DASD_CQR_FILLED; } else { DEV_MESSAGE (KERN_WARNING, device, "%s", "default ERP called (NO retry left)"); cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); } return cqr; } /* end dasd_default_erp_action */
/* * Print the hex dump of the memory used by a request. This includes * all error recovery ccws that have been chained in from of the * real request. */ static inline void hex_dump_memory(struct dasd_device *device, void *data, int len) { int *pint; pint = (int *) data; while (len > 0) { DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x", pint, pint[0], pint[1], pint[2], pint[3]); pint += 4; len -= 16; } }
/* * Quiesce device. */ static int dasd_ioctl_quiesce(struct dasd_block *block) { unsigned long flags; struct dasd_device *base; base = block->base; if (!capable (CAP_SYS_ADMIN)) return -EACCES; DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device"); spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); base->stopped |= DASD_STOPPED_QUIESCE; spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); return 0; }
/* * Quiesce device. */ static int dasd_ioctl_resume(struct dasd_device *device) { unsigned long flags; if (!capable (CAP_SYS_ADMIN)) return -EACCES; DEV_MESSAGE (KERN_DEBUG, device, "%s", "resume IO on device"); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); device->stopped &= ~DASD_STOPPED_QUIESCE; spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); dasd_schedule_bh (device); return 0; }
/* * Format device. */ static int dasd_ioctl_format(struct block_device *bdev, void __user *argp) { struct dasd_block *block = bdev->bd_disk->private_data; struct format_data_t fdata; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!argp) return -EINVAL; if (block->base->features & DASD_FEATURE_READONLY) return -EROFS; if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) return -EFAULT; if (bdev != bdev->bd_contains) { DEV_MESSAGE(KERN_WARNING, block->base, "%s", "Cannot low-level format a partition"); return -EINVAL; } return dasd_format(block, &fdata); }