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

📄 dasd.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		   struct dasd_device * device){	struct dasd_ccw_req *cqr;	/* Sanity checks */	if ( magic == NULL || datasize > PAGE_SIZE ||	     (cplength*sizeof(struct ccw1)) > PAGE_SIZE)		BUG();	debug_text_event ( dasd_debug_area, 1, "ALLC");	debug_text_event ( dasd_debug_area, 1, magic);	debug_int_event ( dasd_debug_area, 1, cplength);	debug_int_event ( dasd_debug_area, 1, datasize);	cqr = kmalloc(sizeof(struct dasd_ccw_req), GFP_ATOMIC);	if (cqr == NULL)		return ERR_PTR(-ENOMEM);	memset(cqr, 0, sizeof(struct dasd_ccw_req));	cqr->cpaddr = NULL;	if (cplength > 0) {		cqr->cpaddr = kmalloc(cplength*sizeof(struct ccw1),				      GFP_ATOMIC | GFP_DMA);		if (cqr->cpaddr == NULL) {			kfree(cqr);			return ERR_PTR(-ENOMEM);		}		memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));	}	cqr->data = NULL;	if (datasize > 0) {		cqr->data = kmalloc(datasize, GFP_ATOMIC | GFP_DMA);		if (cqr->data == NULL) {			if (cqr->cpaddr != NULL)				kfree(cqr->cpaddr);			kfree(cqr);			return ERR_PTR(-ENOMEM);		}		memset(cqr->data, 0, datasize);	}	strncpy((char *) &cqr->magic, magic, 4);	ASCEBC((char *) &cqr->magic, 4);	set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);	dasd_get_device(device);	return cqr;}struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength, int datasize,		   struct dasd_device * device){	unsigned long flags;	struct dasd_ccw_req *cqr;	char *data;	int size;	/* Sanity checks */	if ( magic == NULL || datasize > PAGE_SIZE ||	     (cplength*sizeof(struct ccw1)) > PAGE_SIZE)		BUG();	debug_text_event ( dasd_debug_area, 1, "ALLC");	debug_text_event ( dasd_debug_area, 1, magic);	debug_int_event ( dasd_debug_area, 1, cplength);	debug_int_event ( dasd_debug_area, 1, datasize);	size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;	if (cplength > 0)		size += cplength * sizeof(struct ccw1);	if (datasize > 0)		size += datasize;	spin_lock_irqsave(&device->mem_lock, flags);	cqr = (struct dasd_ccw_req *)		dasd_alloc_chunk(&device->ccw_chunks, size);	spin_unlock_irqrestore(&device->mem_lock, flags);	if (cqr == NULL)		return ERR_PTR(-ENOMEM);	memset(cqr, 0, sizeof(struct dasd_ccw_req));	data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);	cqr->cpaddr = NULL;	if (cplength > 0) {		cqr->cpaddr = (struct ccw1 *) data;		data += cplength*sizeof(struct ccw1);		memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));	}	cqr->data = NULL;	if (datasize > 0) {		cqr->data = data; 		memset(cqr->data, 0, datasize);	}	strncpy((char *) &cqr->magic, magic, 4);	ASCEBC((char *) &cqr->magic, 4);	set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);	dasd_get_device(device);	return cqr;}/* * Free memory of a channel program. This function needs to free all the * idal lists that might have been created by dasd_set_cda and the * struct dasd_ccw_req itself. */voiddasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device){#ifdef CONFIG_ARCH_S390X	struct ccw1 *ccw;	/* Clear any idals used for the request. */	ccw = cqr->cpaddr;	do {		clear_normalized_cda(ccw);	} while (ccw++->flags & (CCW_FLAG_CC | CCW_FLAG_DC));#endif	debug_text_event ( dasd_debug_area, 1, "FREE");	debug_int_event ( dasd_debug_area, 1, (long) cqr);	if (cqr->cpaddr != NULL)		kfree(cqr->cpaddr);	if (cqr->data != NULL)		kfree(cqr->data);	kfree(cqr);	dasd_put_device(device);}voiddasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device){	unsigned long flags;	debug_text_event(dasd_debug_area, 1, "FREE");	debug_int_event(dasd_debug_area, 1, (long) cqr);	spin_lock_irqsave(&device->mem_lock, flags);	dasd_free_chunk(&device->ccw_chunks, cqr);	spin_unlock_irqrestore(&device->mem_lock, flags);	dasd_put_device(device);}/* * Check discipline magic in cqr. */static inline intdasd_check_cqr(struct dasd_ccw_req *cqr){	struct dasd_device *device;	if (cqr == NULL)		return -EINVAL;	device = cqr->device;	if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {		DEV_MESSAGE(KERN_WARNING, device,			    " dasd_ccw_req 0x%08x magic doesn't match"			    " discipline 0x%08x",			    cqr->magic,			    *(unsigned int *) device->discipline->name);		return -EINVAL;	}	return 0;}/* * Terminate the current i/o and set the request to clear_pending. * Timer keeps device runnig. * ccw_device_clear can fail if the i/o subsystem * is in a bad mood. */intdasd_term_IO(struct dasd_ccw_req * cqr){	struct dasd_device *device;	int retries, rc;	/* Check the cqr */	rc = dasd_check_cqr(cqr);	if (rc)		return rc;	retries = 0;	device = (struct dasd_device *) cqr->device;	while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {		rc = ccw_device_clear(device->cdev, (long) cqr);		switch (rc) {		case 0:	/* termination successful */		        if (cqr->retries > 0) {				cqr->retries--;				cqr->status = DASD_CQR_CLEAR;			} else				cqr->status = DASD_CQR_FAILED;			cqr->stopclk = get_clock();			break;		case -ENODEV:			DBF_DEV_EVENT(DBF_ERR, device, "%s",				      "device gone, retry");			break;		case -EIO:			DBF_DEV_EVENT(DBF_ERR, device, "%s",				      "I/O error, retry");			break;		case -EINVAL:		case -EBUSY:			DBF_DEV_EVENT(DBF_ERR, device, "%s",				      "device busy, retry later");			break;		default:			DEV_MESSAGE(KERN_ERR, device,				    "line %d unknown RC=%d, please "				    "report to linux390@de.ibm.com",				    __LINE__, rc);			BUG();			break;		}		retries++;	}	dasd_schedule_bh(device);	return rc;}/* * Start the i/o. This start_IO can fail if the channel is really busy. * In that case set up a timer to start the request later. */intdasd_start_IO(struct dasd_ccw_req * cqr){	struct dasd_device *device;	int rc;	/* Check the cqr */	rc = dasd_check_cqr(cqr);	if (rc)		return rc;	device = (struct dasd_device *) cqr->device;	if (cqr->retries < 0) {		DEV_MESSAGE(KERN_DEBUG, device,			    "start_IO: request %p (%02x/%i) - no retry left.",			    cqr, cqr->status, cqr->retries);		cqr->status = DASD_CQR_FAILED;		return -EIO;	}	cqr->startclk = get_clock();	cqr->starttime = jiffies;	cqr->retries--;	rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr,			      cqr->lpm, 0);	switch (rc) {	case 0:		cqr->status = DASD_CQR_IN_IO;		break;	case -EBUSY:		DBF_DEV_EVENT(DBF_ERR, device, "%s",			      "start_IO: device busy, retry later");		break;	case -ETIMEDOUT:		DBF_DEV_EVENT(DBF_ERR, device, "%s",			      "start_IO: request timeout, retry later");		break;	case -ENODEV:	case -EIO:		DBF_DEV_EVENT(DBF_ERR, device, "%s",			      "start_IO: device gone, retry");		break;	default:		DEV_MESSAGE(KERN_ERR, device,			    "line %d unknown RC=%d, please report"			    " to linux390@de.ibm.com", __LINE__, rc);		BUG();		break;	}	return rc;}/* * Timeout function for dasd devices. This is used for different purposes *  1) missing interrupt handler for normal operation *  2) delayed start of request where start_IO failed with -EBUSY *  3) timeout for missing state change interrupts * The head of the ccw queue will have status DASD_CQR_IN_IO for 1), * DASD_CQR_QUEUED for 2) and 3). */static voiddasd_timeout_device(unsigned long ptr){	unsigned long flags;	struct dasd_device *device;	device = (struct dasd_device *) ptr;	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);	/* re-activate request queue */        device->stopped &= ~DASD_STOPPED_PENDING;	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);	dasd_schedule_bh(device);}/* * Setup timeout for a device in jiffies. */voiddasd_set_timer(struct dasd_device *device, int expires){	if (expires == 0) {		if (timer_pending(&device->timer))			del_timer(&device->timer);		return;	}	if (timer_pending(&device->timer)) {		if (mod_timer(&device->timer, jiffies + expires))			return;	}	device->timer.function = dasd_timeout_device;	device->timer.data = (unsigned long) device;	device->timer.expires = jiffies + expires;	add_timer(&device->timer);}/* * Clear timeout for a device. */voiddasd_clear_timer(struct dasd_device *device){	if (timer_pending(&device->timer))		del_timer(&device->timer);}static voiddasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm){	struct dasd_ccw_req *cqr;	struct dasd_device *device;	cqr = (struct dasd_ccw_req *) intparm;	if (cqr->status != DASD_CQR_IN_IO) {		MESSAGE(KERN_DEBUG,			"invalid status in handle_killed_request: "			"bus_id %s, status %02x",			cdev->dev.bus_id, cqr->status);		return;	}	device = (struct dasd_device *) cqr->device;	if (device == NULL ||	    device != dasd_device_from_cdev(cdev) ||	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",			cdev->dev.bus_id);		return;	}	/* Schedule request to be retried. */	cqr->status = DASD_CQR_QUEUED;	dasd_clear_timer(device);	dasd_schedule_bh(device);	dasd_put_device(device);}static voiddasd_handle_state_change_pending(struct dasd_device *device){	struct dasd_ccw_req *cqr;	struct list_head *l, *n;	device->stopped &= ~DASD_STOPPED_PENDING;        /* restart all 'running' IO on queue */	list_for_each_safe(l, n, &device->ccw_queue) {		cqr = list_entry(l, struct dasd_ccw_req, list);                if (cqr->status == DASD_CQR_IN_IO) {                        cqr->status = DASD_CQR_QUEUED;		}        }	dasd_clear_timer(device);	dasd_schedule_bh(device);}/* * Interrupt handler for "normal" ssch-io based dasd devices. */voiddasd_int_handler(struct ccw_device *cdev, unsigned long intparm,		 struct irb *irb){	struct dasd_ccw_req *cqr, *next;	struct dasd_device *device;	unsigned long long now;	int expires;	dasd_era_t era;	char mask;	if (IS_ERR(irb)) {		switch (PTR_ERR(irb)) {		case -EIO:			dasd_handle_killed_request(cdev, intparm);			break;		case -ETIMEDOUT:			printk(KERN_WARNING"%s(%s): request timed out\n",			       __FUNCTION__, cdev->dev.bus_id);			//FIXME - dasd uses own timeout interface...			break;		default:			printk(KERN_WARNING"%s(%s): unknown error %ld\n",			       __FUNCTION__, cdev->dev.bus_id, PTR_ERR(irb));		}		return;	}	now = get_clock();	DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x",		  cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat),		  (unsigned int) intparm);	/* first of all check for state change pending interrupt */	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;	if ((irb->scsw.dstat & mask) == mask) {		device = dasd_device_from_cdev(cdev);		if (!IS_ERR(device)) {			dasd_handle_state_change_pending(device);			dasd_put_device(device);		}		return;	}	cqr = (struct dasd_ccw_req *) intparm;	/* check for unsolicited interrupts */	if (cqr == NULL) {		MESSAGE(KERN_DEBUG,			"unsolicited interrupt received: bus_id %s",			cdev->dev.bus_id);		return;	}	device = (struct dasd_device *) cqr->device;	if (device == NULL ||	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",			cdev->dev.bus_id);		return;	}	/* Check for clear pending */	if (cqr->status == DASD_CQR_CLEAR &&	    irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {		cqr->status = DASD_CQR_QUEUED;		dasd_clear_timer(device);		dasd_schedule_bh(device);		return;	} 	/* check status - the request might have been killed by dyn detach */	if (cqr->status != DASD_CQR_IN_IO) {		MESSAGE(KERN_DEBUG,			"invalid status: bus_id %s, status %02x",			cdev->dev.bus_id, cqr->status);		return;	}	DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x",		      ((irb->scsw.cstat << 8) | irb->scsw.dstat)); 	/* Find out the appropriate era_action. */	if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) 		era = dasd_era_fatal;	else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&		 irb->scsw.cstat == 0 &&		 !irb->esw.esw0.erw.cons)		era = dasd_era_none;	else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) 	        era = dasd_era_fatal; /* don't recover this request */	else if (irb->esw.esw0.erw.cons)		era = device->discipline->examine_error(cqr, irb);	else 		era = dasd_era_recover;	DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);	expires = 0;	if (era == dasd_era_none) {		cqr->status = DASD_CQR_DONE;		cqr->stopclk = now;		/* Start first request on queue if possible -> fast_io. */		if (cqr->list.next != &device->ccw_queue) {			next = list_entry(cqr->list.next,					  struct dasd_ccw_req, list);			if ((next->status == DASD_CQR_QUEUED) &&			    (!device->stopped)) {				if (device->discipline->start_IO(next) == 0)					expires = next->expires;				else					DEV_MESSAGE(KERN_DEBUG, device, "%s",						    "Interrupt fastpath "						    "failed!");			}		}	} else {		/* error */		memcpy(&cqr->irb, irb, sizeof (struct irb));#ifdef ERP_DEBUG		/* dump sense data */		dasd_log_sense(cqr, irb);#endif		switch (era) {		case dasd_era_fatal:			cqr->status = DASD_CQR_FAILED;			cqr->stopclk = now;			break;		case dasd_era_recover:			cqr->status = DASD_CQR_ERROR;			break;		default:			BUG();		}	}	if (expires != 0)		dasd_set_timer(device, expires);	else		dasd_clear_timer(device);	dasd_schedule_bh(device);}/*

⌨️ 快捷键说明

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