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

📄 dm-mpath-rdac.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Acquires h->ctlr->lock */static void submit_mode_select(struct rdac_handler *h){	struct request *rq;	struct request_queue *q = bdev_get_queue(h->path->dev->bdev);	spin_lock(&h->ctlr->lock);	if (h->ctlr->submitted) {		list_add(&h->entry, &h->ctlr->cmd_list);		goto drop_lock;	}	if (!q) {		DMINFO("submit_mode_select: no queue");		goto fail_path;	}	rq = rdac_failover_get(h);	if (!rq) {		DMERR("submit_mode_select: no rq");		goto fail_path;	}	DMINFO("queueing MODE_SELECT command on %s", h->path->dev->name);	blk_execute_rq_nowait(q, NULL, rq, 1, mode_select_endio);	h->ctlr->submitted = 1;	goto drop_lock;fail_path:	dm_pg_init_complete(h->path, MP_FAIL_PATH);drop_lock:	spin_unlock(&h->ctlr->lock);}static void release_ctlr(struct kref *kref){	struct rdac_controller *ctlr;	ctlr = container_of(kref, struct rdac_controller, kref);	spin_lock(&list_lock);	list_del(&ctlr->node);	spin_unlock(&list_lock);	kfree(ctlr);}static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id){	struct rdac_controller *ctlr, *tmp;	spin_lock(&list_lock);	list_for_each_entry(tmp, &ctlr_list, node) {		if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) &&			  (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) {			kref_get(&tmp->kref);			spin_unlock(&list_lock);			return tmp;		}	}	ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC);	if (!ctlr)		goto done;	/* initialize fields of controller */	memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN);	memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN);	kref_init(&ctlr->kref);	spin_lock_init(&ctlr->lock);	ctlr->submitted = 0;	ctlr->use_10_ms = -1;	INIT_LIST_HEAD(&ctlr->cmd_list);	list_add(&ctlr->node, &ctlr_list);done:	spin_unlock(&list_lock);	return ctlr;}static void c4_endio(struct request *req, int error){	struct rdac_handler *h = req->end_io_data;	struct c4_inquiry *sp;	if (had_failures(req, error)) {		dm_pg_init_complete(h->path, MP_FAIL_PATH);		goto done;	}	sp = &h->inq.c4;	h->ctlr = get_controller(sp->subsys_id, sp->slot_id);	if (h->ctlr) {		h->cmd_to_send = SEND_C9_INQUIRY;		queue_work(rdac_wkqd, &h->work);	} else		dm_pg_init_complete(h->path, MP_FAIL_PATH);done:	__blk_put_request(req->q, req);}static void c2_endio(struct request *req, int error){	struct rdac_handler *h = req->end_io_data;	struct c2_inquiry *sp;	if (had_failures(req, error)) {		dm_pg_init_complete(h->path, MP_FAIL_PATH);		goto done;	}	sp = &h->inq.c2;	/* If more than MODE6_MAX_LUN luns are supported, use mode select 10 */	if (sp->max_lun_supported >= MODE6_MAX_LUN)		h->ctlr->use_10_ms = 1;	else		h->ctlr->use_10_ms = 0;	h->cmd_to_send = SEND_MODE_SELECT;	queue_work(rdac_wkqd, &h->work);done:	__blk_put_request(req->q, req);}static void c9_endio(struct request *req, int error){	struct rdac_handler *h = req->end_io_data;	struct c9_inquiry *sp;	if (had_failures(req, error)) {		dm_pg_init_complete(h->path, MP_FAIL_PATH);		goto done;	}	/* We need to look at the sense keys here to take clear action.	 * For now simple logic: If the host is in AVT mode or if controller	 * owns the lun, return dm_pg_init_complete(), otherwise submit	 * MODE SELECT.	 */	sp = &h->inq.c9;	/* If in AVT mode, return success */	if ((sp->avte_cvp >> 7) == 0x1) {		dm_pg_init_complete(h->path, 0);		goto done;	}	/* If the controller on this path owns the LUN, return success */	if (sp->avte_cvp & 0x1) {		dm_pg_init_complete(h->path, 0);		goto done;	}	if (h->ctlr) {		if (h->ctlr->use_10_ms == -1)			h->cmd_to_send = SEND_C2_INQUIRY;		else			h->cmd_to_send = SEND_MODE_SELECT;	} else		h->cmd_to_send = SEND_C4_INQUIRY;	queue_work(rdac_wkqd, &h->work);done:	__blk_put_request(req->q, req);}static void c8_endio(struct request *req, int error){	struct rdac_handler *h = req->end_io_data;	struct c8_inquiry *sp;	if (had_failures(req, error)) {		dm_pg_init_complete(h->path, MP_FAIL_PATH);		goto done;	}	/* We need to look at the sense keys here to take clear action.	 * For now simple logic: Get the lun from the inquiry page.	 */	sp = &h->inq.c8;	h->lun = sp->lun[7]; /* currently it uses only one byte */	h->cmd_to_send = SEND_C9_INQUIRY;	queue_work(rdac_wkqd, &h->work);done:	__blk_put_request(req->q, req);}static void submit_inquiry(struct rdac_handler *h, int page_code,		unsigned int len, rq_end_io_fn endio){	struct request *rq;	struct request_queue *q = bdev_get_queue(h->path->dev->bdev);	if (!q)		goto fail_path;	rq = get_rdac_req(h, &h->inq, len, READ);	if (!rq)		goto fail_path;	/* Prepare the command. */	rq->cmd[0] = INQUIRY;	rq->cmd[1] = 1;	rq->cmd[2] = page_code;	rq->cmd[4] = len;	rq->cmd_len = COMMAND_SIZE(INQUIRY);	blk_execute_rq_nowait(q, NULL, rq, 1, endio);	return;fail_path:	dm_pg_init_complete(h->path, MP_FAIL_PATH);}static void service_wkq(struct work_struct *work){	struct rdac_handler *h = container_of(work, struct rdac_handler, work);	switch (h->cmd_to_send) {	case SEND_C2_INQUIRY:		submit_inquiry(h, 0xC2, sizeof(struct c2_inquiry), c2_endio);		break;	case SEND_C4_INQUIRY:		submit_inquiry(h, 0xC4, sizeof(struct c4_inquiry), c4_endio);		break;	case SEND_C8_INQUIRY:		submit_inquiry(h, 0xC8, sizeof(struct c8_inquiry), c8_endio);		break;	case SEND_C9_INQUIRY:		submit_inquiry(h, 0xC9, sizeof(struct c9_inquiry), c9_endio);		break;	case SEND_MODE_SELECT:		submit_mode_select(h);		break;	default:		BUG();	}}/* * only support subpage2c until we confirm that this is just a matter of * of updating firmware or not, and RDAC (basic AVT works already) for now * but we can add these in in when we get time and testers */static int rdac_create(struct hw_handler *hwh, unsigned argc, char **argv){	struct rdac_handler *h;	unsigned timeout;	if (argc == 0) {		/* No arguments: use defaults */		timeout = RDAC_FAILOVER_TIMEOUT;	} else if (argc != 1) {		DMWARN("incorrect number of arguments");		return -EINVAL;	} else {		if (sscanf(argv[1], "%u", &timeout) != 1) {			DMWARN("invalid timeout value");			return -EINVAL;		}	}	h = kzalloc(sizeof(*h), GFP_KERNEL);	if (!h)		return -ENOMEM;	hwh->context = h;	h->timeout = timeout;	h->lun = UNINITIALIZED_LUN;	INIT_WORK(&h->work, service_wkq);	DMWARN("using RDAC command with timeout %u", h->timeout);	return 0;}static void rdac_destroy(struct hw_handler *hwh){	struct rdac_handler *h = hwh->context;	if (h->ctlr)		kref_put(&h->ctlr->kref, release_ctlr);	kfree(h);	hwh->context = NULL;}static unsigned rdac_error(struct hw_handler *hwh, struct bio *bio){	/* Try default handler */	return dm_scsi_err_handler(hwh, bio);}static void rdac_pg_init(struct hw_handler *hwh, unsigned bypassed,			struct dm_path *path){	struct rdac_handler *h = hwh->context;	h->path = path;	switch (h->lun) {	case UNINITIALIZED_LUN:		submit_inquiry(h, 0xC8, sizeof(struct c8_inquiry), c8_endio);		break;	default:		submit_inquiry(h, 0xC9, sizeof(struct c9_inquiry), c9_endio);	}}static struct hw_handler_type rdac_handler = {	.name = RDAC_DM_HWH_NAME,	.module = THIS_MODULE,	.create = rdac_create,	.destroy = rdac_destroy,	.pg_init = rdac_pg_init,	.error = rdac_error,};static int __init rdac_init(void){	int r;	rdac_wkqd = create_singlethread_workqueue("rdac_wkqd");	if (!rdac_wkqd) {		DMERR("Failed to create workqueue rdac_wkqd.");		return -ENOMEM;	}	r = dm_register_hw_handler(&rdac_handler);	if (r < 0) {		DMERR("%s: register failed %d", RDAC_DM_HWH_NAME, r);		destroy_workqueue(rdac_wkqd);		return r;	}	DMINFO("%s: version %s loaded", RDAC_DM_HWH_NAME, RDAC_DM_HWH_VER);	return 0;}static void __exit rdac_exit(void){	int r = dm_unregister_hw_handler(&rdac_handler);	destroy_workqueue(rdac_wkqd);	if (r < 0)		DMERR("%s: unregister failed %d", RDAC_DM_HWH_NAME, r);}module_init(rdac_init);module_exit(rdac_exit);MODULE_DESCRIPTION("DM Multipath LSI/Engenio RDAC support");MODULE_AUTHOR("Mike Christie, Chandra Seetharaman");MODULE_LICENSE("GPL");MODULE_VERSION(RDAC_DM_HWH_VER);

⌨️ 快捷键说明

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