ia64/linux-2.6.18-xen.hg

view drivers/xen/scsiback/emulate.c @ 562:66faefe721eb

pvSCSI backend driver

Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jun 02 09:58:27 2008 +0100 (2008-06-02)
parents
children 3b045d92c4c0
line source
1 /*
2 * Xen SCSI backend driver
3 *
4 * Copyright (c) 2008, FUJITSU Limited
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation; or, when distributed
9 * separately from the Linux kernel or incorporated into other
10 * software packages, subject to the following license:
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this source file (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use, copy, modify,
15 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16 * and to permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
31 #include <scsi/scsi.h>
32 #include <scsi/scsi_cmnd.h>
33 #include <scsi/scsi_device.h>
34 #include "comback.h"
36 /* Following SCSI commands are not defined in scsi/scsi.h */
37 #define EXTENDED_COPY 0x83 /* EXTENDED COPY command */
38 #define REPORT_ALIASES 0xa3 /* REPORT ALIASES command */
39 #define CHANGE_ALIASES 0xa4 /* CHANGE ALIASES command */
40 #define SET_PRIORITY 0xa4 /* SET PRIORITY command */
43 /*
44 The bitmap in order to control emulation.
45 (Bit 3 to 7 are reserved for future use.)
46 */
47 #define VSCSIIF_NEED_CMD_EXEC 0x01 /* If this bit is set, cmd exec */
48 /* is required. */
49 #define VSCSIIF_NEED_EMULATE_REQBUF 0x02 /* If this bit is set, need */
50 /* emulation reqest buff before */
51 /* cmd exec. */
52 #define VSCSIIF_NEED_EMULATE_RSPBUF 0x04 /* If this bit is set, need */
53 /* emulation resp buff after */
54 /* cmd exec. */
56 /* Additional Sense Code (ASC) used */
57 #define NO_ADDITIONAL_SENSE 0x0
58 #define LOGICAL_UNIT_NOT_READY 0x4
59 #define UNRECOVERED_READ_ERR 0x11
60 #define PARAMETER_LIST_LENGTH_ERR 0x1a
61 #define INVALID_OPCODE 0x20
62 #define ADDR_OUT_OF_RANGE 0x21
63 #define INVALID_FIELD_IN_CDB 0x24
64 #define INVALID_FIELD_IN_PARAM_LIST 0x26
65 #define POWERON_RESET 0x29
66 #define SAVING_PARAMS_UNSUP 0x39
67 #define THRESHOLD_EXCEEDED 0x5d
68 #define LOW_POWER_COND_ON 0x5e
72 /* Number os SCSI op_code */
73 #define VSCSI_MAX_SCSI_OP_CODE 256
74 static unsigned char bitmap[VSCSI_MAX_SCSI_OP_CODE];
76 /*
77 Emulation routines for each SCSI op_code.
78 */
79 static void (*pre_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *);
80 static void (*post_function[MAX_SCSI_OP_CODE])(pending_request_t *, void *);
83 static const int check_condition_result =
84 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
87 static int __copy_to_sg(struct scatterlist *sg, unsigned int nr_sg,
88 void *buf, unsigned int buflen)
89 {
90 void *from = buf;
91 void *to;
92 unsigned int from_rest = buflen;
93 unsigned int to_capa;
94 unsigned int copy_size;
95 unsigned int i;
97 for (i = 0; i < nr_sg; i++) {
98 if (sg->page == NULL) {
99 printk(KERN_WARN "%s: inconsistent length field in "
100 "scatterlist\n", __FUNCTION__);
101 return -1;
102 }
104 to_capa = sg->length;
105 copy_size = min_t(to_capa, from_rest);
107 to = page_to_virt(sg->page) + (sg->offset);
108 memcpy(to, from, copy_size);
110 from_rest -= copy_size;
111 if (from_rest == 0) {
112 return 0;
113 }
115 sg++;
116 from += copy_size;
117 }
119 printk(KERN_WARN "%s: no space in scatterlist\n",
120 __FUNCTION__);
121 return -1;
122 }
124 static int __copy_from_sg(struct scatterlist *sg, unsigned int nr_sg,
125 void *buf, unsigned int buflen)
126 {
127 void *from;
128 void *to = buf;
129 unsigned int from_rest;
130 unsigned int to_capa = buflen;
131 unsigned int copy_size;
132 unsigned int i;
134 for (i = 0; i < nr_sg; i++) {
135 if (sg->page == NULL) {
136 printk(KERN_WARN "%s: inconsistent length field in "
137 "scatterlist\n", __FUNCTION__);
138 return -1;
139 }
141 from_rest = sg->length;
142 if ((from_rest > 0) && (to_capa < from_rest)) {
143 printk(KERN_WARN
144 "%s: no space in destination buffer\n",
145 __FUNCTION__);
146 return -1;
147 }
148 copy_size = from_rest;
150 from = page_to_virt(sg->page) + (sg->offset);
151 memcpy(to, from, copy_size);
153 to_capa -= copy_size;
155 sg++;
156 to += copy_size;
157 }
159 return 0;
160 }
163 static void scsiback_mk_sense_buffer(uint8_t *date, uint8_t key, uint8_t asc,
164 utint_8 asq)
165 {
166 data[0] = 0x70; /* fixed, current */
167 data[2] = key;
168 data[7] = 0xa; /* implies 18 byte sense buffer */
169 data[12] = asc;
170 data[13] = asq;
171 }
175 /* tuning point*/
176 #define VSCSIIF_RLUN_ARR_SZ 2048
178 /* quoted scsi_debug.c/resp_report_luns() */
179 static void __report_luns(pending_request_t *pending_req, void *data)
180 {
181 struct vscsibk_info *info = pending_req->info;
182 unsigned int channel = pending_req->sdev->channel;
183 unsigned int target = pending_req->sdev->id;
184 unsigned char *cmd = (unsigned char *)pending_req->cmnd;
186 unsigned char rq_buff[VSCSIIF_RLUN_ARR_SZ];
187 unsigned char *sense_buf = pending_req->sense_buffer;
188 unsigned char alloc_len;
189 int select_report = (int)cmd[2];
190 int lun_cnt = 0;
192 struct v2p_entry *entry;
193 struct list_head *head = &(info->v2p_entry_lists);
194 unsigned long flags;
196 struct scsi_lun *one_lun;
198 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
199 if ((alloc_len < 4) || (select_report != 0)) {
200 scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
201 INVALID_FIELD_IN_CDB, 0);
202 pending_req->rslt = check_condition_result;
203 return;
204 }
206 memset(rq_buff, 0, VSCSIIF_RLUN_ARR_SZ);
207 __copy_from_sg(pending_req->sgl, pending_req->nr_segments,
208 rq_buff, VSCSIIF_RLUN_ARR_SZ);
211 rq_buff[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
212 rq_buff[3] = (sizeof(struct scsi_lun) * num) & 0xff;
215 one_lun = (struct scsi_lun *) &rq_buff[8];
216 spin_lock_irqsave(&info->v2p_lock, flags);
217 list_for_each_entry(entry, head, l) {
218 if ((entry->v.chn == channel) &&
219 (entry->v.tgt == target) {
220 lun = entry->v.lun;
221 upper = (lun >> 8) & 0x3f;
222 if (upper)
223 one_lun[lun_cnt].scsi_lun[0] = upper;
224 one_lun[lun_cnt].scsi_lun[1] = lun & 0xff;
225 lun_cnt++;
226 }
227 }
228 spin_unlock_irqrestore(&info->v2p_lock, flags);
231 lun_alloc = (unsigned char *)(one_lun + lun_cnt) - rq_buff;
233 return fill_from_dev_buffer(scp, rq_buff,
234 min((int)alloc_len, lun_alloc));
235 }
239 int __pre_do_emulation(pending_request_t *pending_req, void *data)
240 {
241 uint8_t op_code = pending_req->cmnd[0];
243 if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_REQBUF) &&
244 pre_function[op_code] != NULL) {
245 pre_function[op_code](pending_req, data);
246 }
248 /*
249 0: no need for native driver call, so should return immediately.
250 1: non emulation or should call native driver
251 after modifing the request buffer.
252 */
253 return (bitmap[op_code] & VSCSIIF_NEED_CMD_EXEC);
254 }
256 void scsiback_rsp_emulation(pending_request_t *pending_req)
257 {
258 uint8_t op_code = pending_req->cdb[0];
260 if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_RSPBUF) &&
261 post_function[op_code] != NULL) {
262 post_function[op_code](pending_req, NULL);
263 }
265 return;
266 }
269 void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req)
270 {
271 if (__pre_do_emulation(pending_req, NULL))
272 scsiback_cmd_exec(pending_req);
273 else
274 scsiback_do_resp_with_sense(pending_req);
275 }