]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/nvme/host/core.c
2 * NVM Express device driver
3 * Copyright (c) 2011-2014, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 #include <linux/blkdev.h>
16 #include <linux/blk-mq.h>
17 #include <linux/errno.h>
18 #include <linux/kernel.h>
19 #include <linux/slab.h>
20 #include <linux/types.h>
25 * Returns 0 on success. If the result is negative, it's a Linux error code;
26 * if the result is positive, it's an NVM Express status code
28 int __nvme_submit_sync_cmd(struct request_queue
*q
, struct nvme_command
*cmd
,
29 void *buffer
, void __user
*ubuffer
, unsigned bufflen
,
30 u32
*result
, unsigned timeout
)
32 bool write
= cmd
->common
.opcode
& 1;
33 struct bio
*bio
= NULL
;
37 req
= blk_mq_alloc_request(q
, write
, 0);
41 req
->cmd_type
= REQ_TYPE_DRV_PRIV
;
42 req
->cmd_flags
|= REQ_FAILFAST_DRIVER
;
44 req
->__sector
= (sector_t
) -1;
45 req
->bio
= req
->biotail
= NULL
;
47 req
->timeout
= timeout
? timeout
: ADMIN_TIMEOUT
;
49 req
->cmd
= (unsigned char *)cmd
;
50 req
->cmd_len
= sizeof(struct nvme_command
);
51 req
->special
= (void *)0;
53 if (buffer
&& bufflen
) {
54 ret
= blk_rq_map_kern(q
, req
, buffer
, bufflen
, GFP_KERNEL
);
57 } else if (ubuffer
&& bufflen
) {
58 ret
= blk_rq_map_user(q
, req
, NULL
, ubuffer
, bufflen
,
65 blk_execute_rq(req
->q
, NULL
, req
, 0);
67 blk_rq_unmap_user(bio
);
69 *result
= (u32
)(uintptr_t)req
->special
;
72 blk_mq_free_request(req
);
76 int nvme_submit_sync_cmd(struct request_queue
*q
, struct nvme_command
*cmd
,
77 void *buffer
, unsigned bufflen
)
79 return __nvme_submit_sync_cmd(q
, cmd
, buffer
, NULL
, bufflen
, NULL
, 0);
82 int nvme_identify_ctrl(struct nvme_ctrl
*dev
, struct nvme_id_ctrl
**id
)
84 struct nvme_command c
= { };
87 /* gcc-4.4.4 (at least) has issues with initializers and anon unions */
88 c
.identify
.opcode
= nvme_admin_identify
;
89 c
.identify
.cns
= cpu_to_le32(1);
91 *id
= kmalloc(sizeof(struct nvme_id_ctrl
), GFP_KERNEL
);
95 error
= nvme_submit_sync_cmd(dev
->admin_q
, &c
, *id
,
96 sizeof(struct nvme_id_ctrl
));
102 int nvme_identify_ns(struct nvme_ctrl
*dev
, unsigned nsid
,
103 struct nvme_id_ns
**id
)
105 struct nvme_command c
= { };
108 /* gcc-4.4.4 (at least) has issues with initializers and anon unions */
109 c
.identify
.opcode
= nvme_admin_identify
,
110 c
.identify
.nsid
= cpu_to_le32(nsid
),
112 *id
= kmalloc(sizeof(struct nvme_id_ns
), GFP_KERNEL
);
116 error
= nvme_submit_sync_cmd(dev
->admin_q
, &c
, *id
,
117 sizeof(struct nvme_id_ns
));
123 int nvme_get_features(struct nvme_ctrl
*dev
, unsigned fid
, unsigned nsid
,
124 dma_addr_t dma_addr
, u32
*result
)
126 struct nvme_command c
;
128 memset(&c
, 0, sizeof(c
));
129 c
.features
.opcode
= nvme_admin_get_features
;
130 c
.features
.nsid
= cpu_to_le32(nsid
);
131 c
.features
.prp1
= cpu_to_le64(dma_addr
);
132 c
.features
.fid
= cpu_to_le32(fid
);
134 return __nvme_submit_sync_cmd(dev
->admin_q
, &c
, NULL
, NULL
, 0,
138 int nvme_set_features(struct nvme_ctrl
*dev
, unsigned fid
, unsigned dword11
,
139 dma_addr_t dma_addr
, u32
*result
)
141 struct nvme_command c
;
143 memset(&c
, 0, sizeof(c
));
144 c
.features
.opcode
= nvme_admin_set_features
;
145 c
.features
.prp1
= cpu_to_le64(dma_addr
);
146 c
.features
.fid
= cpu_to_le32(fid
);
147 c
.features
.dword11
= cpu_to_le32(dword11
);
149 return __nvme_submit_sync_cmd(dev
->admin_q
, &c
, NULL
, NULL
, 0,
153 int nvme_get_log_page(struct nvme_ctrl
*dev
, struct nvme_smart_log
**log
)
155 struct nvme_command c
= { };
158 c
.common
.opcode
= nvme_admin_get_log_page
,
159 c
.common
.nsid
= cpu_to_le32(0xFFFFFFFF),
160 c
.common
.cdw10
[0] = cpu_to_le32(
161 (((sizeof(struct nvme_smart_log
) / 4) - 1) << 16) |
164 *log
= kmalloc(sizeof(struct nvme_smart_log
), GFP_KERNEL
);
168 error
= nvme_submit_sync_cmd(dev
->admin_q
, &c
, *log
,
169 sizeof(struct nvme_smart_log
));