📄 dm-mpath-rdac.c
字号:
/* 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 + -