⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dasd_eckd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
			      device);		data += sizeof(struct DE_eckd_data);		ccw[-1].flags |= CCW_FLAG_CC;		locate_record(ccw++, (struct LO_eckd_data *) data,			      fdata->start_unit, 0, rpt + 1,			      DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,			      device->bp_block);		data += sizeof(struct LO_eckd_data);		break;	case 0x04: /* Invalidate track. */		define_extent(ccw++, (struct DE_eckd_data *) data,			      fdata->start_unit, fdata->start_unit,			      DASD_ECKD_CCW_WRITE_CKD, device);		data += sizeof(struct DE_eckd_data);		ccw[-1].flags |= CCW_FLAG_CC;		locate_record(ccw++, (struct LO_eckd_data *) data,			      fdata->start_unit, 0, 1,			      DASD_ECKD_CCW_WRITE_CKD, device, 8);		data += sizeof(struct LO_eckd_data);		break;	}	if (fdata->intensity & 0x01) {	/* write record zero */		ect = (struct eckd_count *) data;		data += sizeof(struct eckd_count);		ect->cyl = cyl;		ect->head = head;		ect->record = 0;		ect->kl = 0;		ect->dl = 8;		ccw[-1].flags |= CCW_FLAG_CC;		ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;		ccw->flags = CCW_FLAG_SLI;		ccw->count = 8;		ccw->cda = (__u32)(addr_t) ect;		ccw++;	}	if ((fdata->intensity & ~0x08) & 0x04) {	/* erase track */		ect = (struct eckd_count *) data;		data += sizeof(struct eckd_count);		ect->cyl = cyl;		ect->head = head;		ect->record = 1;		ect->kl = 0;		ect->dl = 0;		ccw[-1].flags |= CCW_FLAG_CC;		ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;		ccw->flags = CCW_FLAG_SLI;		ccw->count = 8;		ccw->cda = (__u32)(addr_t) ect;	} else {		/* write remaining records */		for (i = 0; i < rpt; i++) {			ect = (struct eckd_count *) data;			data += sizeof(struct eckd_count);			ect->cyl = cyl;			ect->head = head;			ect->record = i + 1;			ect->kl = 0;			ect->dl = fdata->blksize;			/* Check for special tracks 0-1 when formatting CDL */			if ((fdata->intensity & 0x08) &&			    fdata->start_unit == 0) {				if (i < 3) {					ect->kl = 4;					ect->dl = sizes_trk0[i] - 4;				} 			}			if ((fdata->intensity & 0x08) &&			    fdata->start_unit == 1) {				ect->kl = 44;				ect->dl = LABEL_SIZE - 44;			}			ccw[-1].flags |= CCW_FLAG_CC;			ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;			ccw->flags = CCW_FLAG_SLI;			ccw->count = 8;			ccw->cda = (__u32)(addr_t) ect;			ccw++;		}	}	fcp->device = device;	fcp->retries = 2;	/* set retry counter to enable ERP */	fcp->buildclk = get_clock();	fcp->status = DASD_CQR_FILLED;	return fcp;}static dasd_era_tdasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb){	struct dasd_device *device = (struct dasd_device *) cqr->device;	struct ccw_device *cdev = device->cdev;	if (irb->scsw.cstat == 0x00 &&	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))		return dasd_era_none;	switch (cdev->id.cu_type) {	case 0x3990:	case 0x2105:	case 0x2107:	case 0x1750:		return dasd_3990_erp_examine(cqr, irb);	case 0x9343:		return dasd_9343_erp_examine(cqr, irb);	case 0x3880:	default:		DEV_MESSAGE(KERN_WARNING, device, "%s",			    "default (unknown CU type) - RECOVERABLE return");		return dasd_era_recover;	}}static dasd_erp_fn_tdasd_eckd_erp_action(struct dasd_ccw_req * cqr){	struct dasd_device *device = (struct dasd_device *) cqr->device;	struct ccw_device *cdev = device->cdev;	switch (cdev->id.cu_type) {	case 0x3990:	case 0x2105:	case 0x2107:	case 0x1750:		return dasd_3990_erp_action;	case 0x9343:	case 0x3880:	default:		return dasd_default_erp_action;	}}static dasd_erp_fn_tdasd_eckd_erp_postaction(struct dasd_ccw_req * cqr){	return dasd_default_erp_postaction;}static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device * device, struct request *req){	struct dasd_eckd_private *private;	unsigned long *idaws;	struct LO_eckd_data *LO_data;	struct dasd_ccw_req *cqr;	struct ccw1 *ccw;	struct bio *bio;	struct bio_vec *bv;	char *dst;	unsigned int blksize, blk_per_trk, off;	int count, cidaw, cplength, datasize;	sector_t recid, first_rec, last_rec;	sector_t first_trk, last_trk;	unsigned int first_offs, last_offs;	unsigned char cmd, rcmd;	int i;	private = (struct dasd_eckd_private *) device->private;	if (rq_data_dir(req) == READ)		cmd = DASD_ECKD_CCW_READ_MT;	else if (rq_data_dir(req) == WRITE)		cmd = DASD_ECKD_CCW_WRITE_MT;	else		return ERR_PTR(-EINVAL);	/* Calculate number of blocks/records per track. */	blksize = device->bp_block;	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);	/* Calculate record id of first and last block. */	first_rec = first_trk = req->sector >> device->s2b_shift;	first_offs = sector_div(first_trk, blk_per_trk);	last_rec = last_trk =		(req->sector + req->nr_sectors - 1) >> device->s2b_shift;	last_offs = sector_div(last_trk, blk_per_trk);	/* Check struct bio and count the number of blocks for the request. */	count = 0;	cidaw = 0;	rq_for_each_bio(bio, req) {		bio_for_each_segment(bv, bio, i) {			if (bv->bv_len & (blksize - 1))				/* Eckd can only do full blocks. */				return ERR_PTR(-EINVAL);			count += bv->bv_len >> (device->s2b_shift + 9);#if defined(CONFIG_ARCH_S390X)			if (idal_is_needed (page_address(bv->bv_page),					    bv->bv_len))				cidaw += bv->bv_len >> (device->s2b_shift + 9);#endif		}	}	/* Paranoia. */	if (count != last_rec - first_rec + 1)		return ERR_PTR(-EINVAL);	/* 1x define extent + 1x locate record + number of blocks */	cplength = 2 + count;	/* 1x define extent + 1x locate record + cidaws*sizeof(long) */	datasize = sizeof(struct DE_eckd_data) + sizeof(struct LO_eckd_data) +		cidaw * sizeof(unsigned long);	/* Find out the number of additional locate record ccws for cdl. */	if (private->uses_cdl && first_rec < 2*blk_per_trk) {		if (last_rec >= 2*blk_per_trk)			count = 2*blk_per_trk - first_rec;		cplength += count;		datasize += count*sizeof(struct LO_eckd_data);	}	/* Allocate the ccw request. */	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,				   cplength, datasize, device);	if (IS_ERR(cqr))		return cqr;	ccw = cqr->cpaddr;	/* First ccw is define extent. */	define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);	/* Build locate_record+read/write/ccws. */	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));	LO_data = (struct LO_eckd_data *) (idaws + cidaw);	recid = first_rec;	if (private->uses_cdl == 0 || recid > 2*blk_per_trk) {		/* Only standard blocks so there is just one locate record. */		ccw[-1].flags |= CCW_FLAG_CC;		locate_record(ccw++, LO_data++, first_trk, first_offs + 1,			      last_rec - recid + 1, cmd, device, blksize);	}	rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {		dst = page_address(bv->bv_page) + bv->bv_offset;		if (dasd_page_cache) {			char *copy = kmem_cache_alloc(dasd_page_cache,						      SLAB_DMA | __GFP_NOWARN);			if (copy && rq_data_dir(req) == WRITE)				memcpy(copy + bv->bv_offset, dst, bv->bv_len);			if (copy)				dst = copy + bv->bv_offset;		}		for (off = 0; off < bv->bv_len; off += blksize) {			sector_t trkid = recid;			unsigned int recoffs = sector_div(trkid, blk_per_trk);			rcmd = cmd;			count = blksize;			/* Locate record for cdl special block ? */			if (private->uses_cdl && recid < 2*blk_per_trk) {				if (dasd_eckd_cdl_special(blk_per_trk, recid)){					rcmd |= 0x8;					count = dasd_eckd_cdl_reclen(recid);					if (count < blksize &&					    rq_data_dir(req) == READ)						memset(dst + count, 0xe5,						       blksize - count);				}				ccw[-1].flags |= CCW_FLAG_CC;				locate_record(ccw++, LO_data++,					      trkid, recoffs + 1,					      1, rcmd, device, count);			}			/* Locate record for standard blocks ? */			if (private->uses_cdl && recid == 2*blk_per_trk) {				ccw[-1].flags |= CCW_FLAG_CC;				locate_record(ccw++, LO_data++,					      trkid, recoffs + 1,					      last_rec - recid + 1,					      cmd, device, count);			}			/* Read/write ccw. */			ccw[-1].flags |= CCW_FLAG_CC;			ccw->cmd_code = rcmd;			ccw->count = count;			if (idal_is_needed(dst, blksize)) {				ccw->cda = (__u32)(addr_t) idaws;				ccw->flags = CCW_FLAG_IDA;				idaws = idal_create_words(idaws, dst, blksize);			} else {				ccw->cda = (__u32)(addr_t) dst;				ccw->flags = 0;			}			ccw++;			dst += blksize;			recid++;		}	}	cqr->device = device;	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */	cqr->lpm = private->path_data.ppm;	cqr->retries = 256;	cqr->buildclk = get_clock();	cqr->status = DASD_CQR_FILLED;	return cqr;}static intdasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req){	struct dasd_eckd_private *private;	struct ccw1 *ccw;	struct bio *bio;	struct bio_vec *bv;	char *dst, *cda;	unsigned int blksize, blk_per_trk, off;	sector_t recid;	int i, status;	if (!dasd_page_cache)		goto out;	private = (struct dasd_eckd_private *) cqr->device->private;	blksize = cqr->device->bp_block;	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);	recid = req->sector >> cqr->device->s2b_shift;	ccw = cqr->cpaddr;	/* Skip over define extent & locate record. */	ccw++;	if (private->uses_cdl == 0 || recid > 2*blk_per_trk)		ccw++;	rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {		dst = page_address(bv->bv_page) + bv->bv_offset;		for (off = 0; off < bv->bv_len; off += blksize) {			/* Skip locate record. */			if (private->uses_cdl && recid <= 2*blk_per_trk)				ccw++;			if (dst) {				if (ccw->flags & CCW_FLAG_IDA)					cda = *((char **)((addr_t) ccw->cda));				else					cda = (char *)((addr_t) ccw->cda);				if (dst != cda) {					if (rq_data_dir(req) == READ)						memcpy(dst, cda, bv->bv_len);					kmem_cache_free(dasd_page_cache,					    (void *)((addr_t)cda & PAGE_MASK));				}				dst = NULL;			}			ccw++;			recid++;		}	}out:	status = cqr->status == DASD_CQR_DONE;	dasd_sfree_request(cqr, cqr->device);	return status;}static intdasd_eckd_fill_info(struct dasd_device * device,		    struct dasd_information2_t * info){	struct dasd_eckd_private *private;	private = (struct dasd_eckd_private *) device->private;	info->label_block = 2;	info->FBA_layout = private->uses_cdl ? 0 : 1;	info->format = private->uses_cdl ? DASD_FORMAT_CDL : DASD_FORMAT_LDL;	info->characteristics_size = sizeof(struct dasd_eckd_characteristics);	memcpy(info->characteristics, &private->rdc_data,	       sizeof(struct dasd_eckd_characteristics));	info->confdata_size = sizeof (struct dasd_eckd_confdata);	memcpy(info->configuration_data, &private->conf_data,	       sizeof (struct dasd_eckd_confdata));	return 0;}/* * SECTION: ioctl functions for eckd devices. *//* * Release device ioctl. * Buils a channel programm to releases a prior reserved  * (see dasd_eckd_reserve) device. */static intdasd_eckd_release(struct block_device *bdev, int no, long args){	struct dasd_device *device;	struct dasd_ccw_req *cqr;	int rc;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	device = bdev->bd_disk->private_data;	if (device == NULL)		return -ENODEV;	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,				   1, 32, device);	if (IS_ERR(cqr)) {		DEV_MESSAGE(KERN_WARNING, device, "%s",			    "Could not allocate initialization request");		return PTR_ERR(cqr);	}	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;        cqr->cpaddr->flags |= CCW_FLAG_SLI;        cqr->cpaddr->count = 32;	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;	cqr->device = device;	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);	cqr->retries = 0;	cqr->expires = 2 * HZ;	cqr->buildclk = get_clock();	cqr->status = DASD_CQR_FILLED;	rc = dasd_sleep_on_immediatly(cqr);	dasd_sfree_request(cqr, cqr->device);	return rc;}/* * Reserve device ioctl. * Options are set to 'synchronous wait for interrupt' and * 'timeout the request'. This leads to a terminate IO if  * the interrupt is outstanding for a certain time.  */static intdasd_eckd_reserve(struct block_device *bdev, int no, long args){	struct dasd_device *device;	struct dasd_ccw_req *cqr;	int rc;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	device = bdev->bd_disk->private_data;	if (device == NULL)		return -ENODEV;	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,				   1, 32, device);	if (IS_ERR(cqr)) {		DEV_MESSAGE(KERN_WARNING, device, "%s",			    "Could not allocate initialization request");		return PTR_ERR(cqr);	}	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -