dasd_eckd.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 1,885 行 · 第 1/4 页

C
1,885
字号
		ct_data = (eckd_count_t *) last_data;		last_ccw = fcp->cpaddr;		switch (fdata->intensity & ~0x08) {		case 0x03:			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,                                           DASD_ECKD_CCW_WRITE_HOME_ADDRESS,                                           device, fcp)) {                                goto clear_fcp;                        }			last_ccw->flags |= CCW_FLAG_CC;			last_ccw++;			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,                                           DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,                                           device->sizes.bp_block, fcp)) {                                goto clear_fcp;                        }			last_ccw->flags |= CCW_FLAG_CC;			last_ccw++;			break;		case 0x01:			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,                                           DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, fcp)) {                                goto clear_fcp;                        }			last_ccw->flags |= CCW_FLAG_CC;			last_ccw++;			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,                                           DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,                                           device->sizes.bp_block, fcp)) {                                goto clear_fcp;                        }			last_ccw->flags |= CCW_FLAG_CC;			last_ccw++;			memset (r0_data, 0, sizeof (eckd_count_t));			break;		case 0x04:                        fdata->blksize = 8;		case 0x00:			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,                                           DASD_ECKD_CCW_WRITE_CKD, device, fcp)) {                                dasd_free_request (fcp, device);                                return NULL;                        }			last_ccw->flags |= CCW_FLAG_CC;			last_ccw++;			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,                                           DASD_ECKD_CCW_WRITE_CKD, device, fdata->blksize, fcp)) {                                goto clear_fcp;                        }			last_ccw->flags |= CCW_FLAG_CC;			last_ccw++;			break;		default:			MESSAGE (KERN_WARNING,                                 "Unknown format flags...%d",                                  fdata->intensity);			return NULL;		}		if (fdata->intensity & 0x02) {			MESSAGE (KERN_WARNING,                                 "Unsupported format flag...%d",                                  fdata->intensity);			return NULL;		}		if (fdata->intensity & 0x01) {	/* write record zero */			r0_data->cyl = cyl;			r0_data->head = head;			r0_data->record = 0;			r0_data->kl = 0;			r0_data->dl = 8;			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;			last_ccw->count = 8;			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;			if (dasd_set_normalized_cda (last_ccw, __pa (r0_data), fcp, device)) {                                goto clear_fcp;                        }			last_ccw++;		}		if ((fdata->intensity & ~0x08) & 0x04) {	/* erase track */			memset (ct_data, 0, sizeof (eckd_count_t));			ct_data->cyl = cyl;			ct_data->head = head;			ct_data->record = 1;			ct_data->kl = 0;			ct_data->dl = 0;			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;			last_ccw->count = 8;			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;			if (dasd_set_normalized_cda (last_ccw, __pa (ct_data), fcp, device)) {                                goto clear_fcp;                        }			last_ccw++;		} else {	/* write remaining records */			for (i = 0; i < rpt; i++) {				memset (ct_data + i, 0, sizeof (eckd_count_t));				(ct_data + i)->cyl = cyl;				(ct_data + i)->head = head;				(ct_data + i)->record = i + 1;				(ct_data + i)->kl = 0;				if (fdata->intensity & 0x08) {					// special handling when formatting CDL					switch (fdata->start_unit) {					case 0:						if (i < 3) {							(ct_data + i)->kl = 4;														    (ct_data + i)->dl =							    sizes_trk0[i] - 4;						} else							(ct_data + i)->dl = fdata->blksize;						break;					case 1:						(ct_data + i)->kl = 44;						(ct_data + i)->dl = LABEL_SIZE - 44;						break;					default:						(ct_data + i)->dl = fdata->blksize;						break;					}				} else					(ct_data + i)->dl = fdata->blksize;				last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;				last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;				last_ccw->count = 8;				if (dasd_set_normalized_cda (last_ccw,                                                             __pa (ct_data + i), fcp, device)) {                                goto clear_fcp;                                }				last_ccw++;			}		}		(last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);		fcp->device = device;                fcp->buildclk = get_clock ();		fcp->status = CQR_STATUS_FILLED;	}        goto out; clear_fcp:        dasd_free_request (fcp, device);        fcp=NULL; out:	return fcp;}static dasd_era_tdasd_eckd_examine_error (ccw_req_t * cqr, devstat_t * stat){	dasd_device_t *device = (dasd_device_t *) cqr->device;	if (stat->cstat == 0x00 &&	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))		    return dasd_era_none;	switch (device->devinfo.sid_data.cu_type) {	case 0x3990:	case 0x2105:		return dasd_3990_erp_examine (cqr, stat);	case 0x9343:		return dasd_9343_erp_examine (cqr, stat);	default:		MESSAGE (KERN_WARNING, "%s",                         "default (unknown CU type) - RECOVERABLE return");		return dasd_era_recover;	}}static dasd_erp_action_fn_tdasd_eckd_erp_action (ccw_req_t * cqr){	dasd_device_t *device = (dasd_device_t *) cqr->device;	switch (device->devinfo.sid_data.cu_type) {	case 0x3990:	case 0x2105:		return dasd_3990_erp_action;	case 0x9343:		/* Return dasd_9343_erp_action; */	default:		return dasd_default_erp_action;	}}static dasd_erp_postaction_fn_tdasd_eckd_erp_postaction (ccw_req_t * cqr){	return dasd_default_erp_postaction;}inline unsigned chardasd_eckd_cdl_cmd (dasd_device_t * device, int recid, int cmd){	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;	int byt_per_blk = device->sizes.bp_block;	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);	switch (cmd) {	case READ:		if (recid < 3)			return DASD_ECKD_CCW_READ_KD_MT;		if (recid < blk_per_trk)			return DASD_ECKD_CCW_READ_MT;		if (recid < 2 * blk_per_trk)			return DASD_ECKD_CCW_READ_KD_MT;		return DASD_ECKD_CCW_READ_MT;		break;	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);        unsigned long reloc_sector = req->sector +                 device->major_info->gendisk.part[MINOR(req->rq_dev)].start_sect;        int btrk = (reloc_sector >> shift) / blk_per_trk; 	int etrk = ((reloc_sector + req->nr_sectors - 1) >> shift) / blk_per_trk;	int recid = reloc_sector >> shift;	int locate4k_set = 0;	int nlocs = 0;	int errcode;	if (req->cmd == READ) {		rw_cmd = DASD_ECKD_CCW_READ_MT;	} else if (req->cmd == WRITE) {		rw_cmd = DASD_ECKD_CCW_WRITE_MT;	} else {		MESSAGE (KERN_ERR,                         "Unknown command %d",                          req->cmd);		return ERR_PTR(-EINVAL);	}	/* 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) {			MESSAGE(KERN_ERR, "ignoring bogus sized request: %d<%d",					  bh->b_size, byt_per_blk);                        return ERR_PTR(-EINVAL);		}                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 ERR_PTR(-ENOMEM);	}	DE_data = rw_cp->data;	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);	ccw = rw_cp->cpaddr;	if ((errcode = 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 ((errcode = 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 ((errcode = locate_record (ccw,                                                        LO_data++,                                                       recid /blk_per_trk,                                                       recid %blk_per_trk + 1,                                                       (((reloc_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 ((errcode = 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 = 256;	rw_cp->buildclk = get_clock ();	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=ERR_PTR(errcode); 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;        cqr = dasd_alloc_request (dasd_eckd_discipline.name,                                   1 + 1, 32, device);	if (cqr == NULL) {		MESSAGE (KERN_WARNING, "%s",                         "No memory to allocate initialization request");		return NULL;	}	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;        cqr->cpaddr->flags |= CCW_FLAG_SLI;        cqr->cpaddr->count = 32;	if (dasd_set_normalized_cda (cqr->cpaddr, __pa (cqr->data),                                      cqr, device)) {                dasd_free_request (cqr, device);                return NULL;        }        	cqr->device  = device;	cqr->retries = 0;	cqr->expires = 10 * TOD_SEC;	cqr->buildclk = get_clock ();	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;        cqr = dasd_alloc_request (dasd_eckd_discipline.name,                                   1 + 1, 32, device);	if (cqr == NULL) {		MESSAGE (KERN_WARNING, "%s",                         "No memory to allocate initialization request");		return NULL;

⌨️ 快捷键说明

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