ia64/linux-2.6.18-xen.hg

view drivers/xen/scsiback/emulate.c @ 757:8761101c3ed5

[PVSCSI] Fix some issues

Signed-off-by: James Harper <james.harper@bendigoit.com.au>
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 Tue Dec 09 13:03:14 2008 +0000 (2008-12-09)
parents eccc622d03af
children
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 "common.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 #define NO_EMULATE(cmd) \
77 bitmap[cmd] = VSCSIIF_NEED_CMD_EXEC; \
78 pre_function[cmd] = NULL; \
79 post_function[cmd] = NULL
83 /*
84 Emulation routines for each SCSI op_code.
85 */
86 static void (*pre_function[VSCSI_MAX_SCSI_OP_CODE])(pending_req_t *, void *);
87 static void (*post_function[VSCSI_MAX_SCSI_OP_CODE])(pending_req_t *, void *);
90 static const int check_condition_result =
91 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
93 static void scsiback_mk_sense_buffer(uint8_t *data, uint8_t key,
94 uint8_t asc, uint8_t asq)
95 {
96 data[0] = 0x70; /* fixed, current */
97 data[2] = key;
98 data[7] = 0xa; /* implies 18 byte sense buffer */
99 data[12] = asc;
100 data[13] = asq;
101 }
103 static void resp_not_supported_cmd(pending_req_t *pending_req, void *data)
104 {
105 scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
106 INVALID_OPCODE, 0);
107 pending_req->resid = 0;
108 pending_req->rslt = check_condition_result;
109 }
112 static int __copy_to_sg(struct scatterlist *sg, unsigned int nr_sg,
113 void *buf, unsigned int buflen)
114 {
115 void *from = buf;
116 void *to;
117 unsigned int from_rest = buflen;
118 unsigned int to_capa;
119 unsigned int copy_size = 0;
120 unsigned int i;
121 unsigned long pfn;
123 for (i = 0; i < nr_sg; i++) {
124 if (sg->page == NULL) {
125 printk(KERN_WARNING "%s: inconsistent length field in "
126 "scatterlist\n", __FUNCTION__);
127 return -ENOMEM;
128 }
130 to_capa = sg->length;
131 copy_size = min_t(unsigned int, to_capa, from_rest);
133 pfn = page_to_pfn(sg->page);
134 to = pfn_to_kaddr(pfn) + (sg->offset);
135 memcpy(to, from, copy_size);
137 from_rest -= copy_size;
138 if (from_rest == 0) {
139 return 0;
140 }
142 sg++;
143 from += copy_size;
144 }
146 printk(KERN_WARNING "%s: no space in scatterlist\n",
147 __FUNCTION__);
148 return -ENOMEM;
149 }
151 static int __copy_from_sg(struct scatterlist *sg, unsigned int nr_sg,
152 void *buf, unsigned int buflen)
153 {
154 void *from;
155 void *to = buf;
156 unsigned int from_rest;
157 unsigned int to_capa = buflen;
158 unsigned int copy_size;
159 unsigned int i;
160 unsigned long pfn;
162 for (i = 0; i < nr_sg; i++) {
163 if (sg->page == NULL) {
164 printk(KERN_WARNING "%s: inconsistent length field in "
165 "scatterlist\n", __FUNCTION__);
166 return -ENOMEM;
167 }
169 from_rest = sg->length;
170 if ((from_rest > 0) && (to_capa < from_rest)) {
171 printk(KERN_WARNING
172 "%s: no space in destination buffer\n",
173 __FUNCTION__);
174 return -ENOMEM;
175 }
176 copy_size = from_rest;
178 pfn = page_to_pfn(sg->page);
179 from = pfn_to_kaddr(pfn) + (sg->offset);
180 memcpy(to, from, copy_size);
182 to_capa -= copy_size;
184 sg++;
185 to += copy_size;
186 }
188 return 0;
189 }
191 static int __nr_luns_under_host(struct vscsibk_info *info)
192 {
193 struct v2p_entry *entry;
194 struct list_head *head = &(info->v2p_entry_lists);
195 unsigned long flags;
196 int lun_cnt = 0;
198 spin_lock_irqsave(&info->v2p_lock, flags);
199 list_for_each_entry(entry, head, l) {
200 lun_cnt++;
201 }
202 spin_unlock_irqrestore(&info->v2p_lock, flags);
204 return (lun_cnt);
205 }
208 /* REPORT LUNS Define*/
209 #define VSCSI_REPORT_LUNS_HEADER 8
210 #define VSCSI_REPORT_LUNS_RETRY 3
212 /* quoted scsi_debug.c/resp_report_luns() */
213 static void __report_luns(pending_req_t *pending_req, void *data)
214 {
215 struct vscsibk_info *info = pending_req->info;
216 unsigned int channel = pending_req->v_chn;
217 unsigned int target = pending_req->v_tgt;
218 unsigned int nr_seg = pending_req->nr_segments;
219 unsigned char *cmd = (unsigned char *)pending_req->cmnd;
221 unsigned char *buff = NULL;
222 unsigned char alloc_len;
223 unsigned int alloc_luns = 0;
224 unsigned int req_bufflen = 0;
225 unsigned int actual_len = 0;
226 unsigned int retry_cnt = 0;
227 int select_report = (int)cmd[2];
228 int i, lun_cnt = 0, lun, upper, err = 0;
230 struct v2p_entry *entry;
231 struct list_head *head = &(info->v2p_entry_lists);
232 unsigned long flags;
234 struct scsi_lun *one_lun;
236 req_bufflen = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
237 if ((req_bufflen < 4) || (select_report != 0))
238 goto fail;
240 alloc_luns = __nr_luns_under_host(info);
241 alloc_len = sizeof(struct scsi_lun) * alloc_luns
242 + VSCSI_REPORT_LUNS_HEADER;
243 retry:
244 if ((buff = kmalloc(alloc_len, GFP_KERNEL)) == NULL) {
245 printk(KERN_ERR "scsiback:%s kmalloc err\n", __FUNCTION__);
246 goto fail;
247 }
249 memset(buff, 0, alloc_len);
251 one_lun = (struct scsi_lun *) &buff[8];
252 spin_lock_irqsave(&info->v2p_lock, flags);
253 list_for_each_entry(entry, head, l) {
254 if ((entry->v.chn == channel) &&
255 (entry->v.tgt == target)) {
257 /* check overflow */
258 if (lun_cnt >= alloc_luns) {
259 spin_unlock_irqrestore(&info->v2p_lock,
260 flags);
262 if (retry_cnt < VSCSI_REPORT_LUNS_RETRY) {
263 retry_cnt++;
264 if (buff)
265 kfree(buff);
266 goto retry;
267 }
269 goto fail;
270 }
272 lun = entry->v.lun;
273 upper = (lun >> 8) & 0x3f;
274 if (upper)
275 one_lun[lun_cnt].scsi_lun[0] = upper;
276 one_lun[lun_cnt].scsi_lun[1] = lun & 0xff;
277 lun_cnt++;
278 }
279 }
281 spin_unlock_irqrestore(&info->v2p_lock, flags);
283 buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
284 buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
286 actual_len = lun_cnt * sizeof(struct scsi_lun)
287 + VSCSI_REPORT_LUNS_HEADER;
288 req_bufflen = 0;
289 for (i = 0; i < nr_seg; i++)
290 req_bufflen += pending_req->sgl[i].length;
292 err = __copy_to_sg(pending_req->sgl, nr_seg, buff,
293 min(req_bufflen, actual_len));
294 if (err)
295 goto fail;
297 memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
298 pending_req->rslt = 0x00;
299 pending_req->resid = req_bufflen - min(req_bufflen, actual_len);
301 kfree(buff);
302 return;
304 fail:
305 scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
306 INVALID_FIELD_IN_CDB, 0);
307 pending_req->rslt = check_condition_result;
308 pending_req->resid = 0;
309 if (buff)
310 kfree(buff);
311 return;
312 }
316 int __pre_do_emulation(pending_req_t *pending_req, void *data)
317 {
318 uint8_t op_code = pending_req->cmnd[0];
320 if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_REQBUF) &&
321 pre_function[op_code] != NULL) {
322 pre_function[op_code](pending_req, data);
323 }
325 /*
326 0: no need for native driver call, so should return immediately.
327 1: non emulation or should call native driver
328 after modifing the request buffer.
329 */
330 return !!(bitmap[op_code] & VSCSIIF_NEED_CMD_EXEC);
331 }
333 void scsiback_rsp_emulation(pending_req_t *pending_req)
334 {
335 uint8_t op_code = pending_req->cmnd[0];
337 if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_RSPBUF) &&
338 post_function[op_code] != NULL) {
339 post_function[op_code](pending_req, NULL);
340 }
342 return;
343 }
346 void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req)
347 {
348 if (__pre_do_emulation(pending_req, NULL)) {
349 scsiback_cmd_exec(pending_req);
350 }
351 else {
352 scsiback_fast_flush_area(pending_req);
353 scsiback_do_resp_with_sense(pending_req->sense_buffer,
354 pending_req->rslt, pending_req->resid, pending_req);
355 }
356 }
359 /*
360 Following are not customizable functions.
361 */
362 void scsiback_emulation_init(void)
363 {
364 int i;
366 /* Initialize to default state */
367 for (i = 0; i < VSCSI_MAX_SCSI_OP_CODE; i++) {
368 bitmap[i] = (VSCSIIF_NEED_EMULATE_REQBUF |
369 VSCSIIF_NEED_EMULATE_RSPBUF);
370 pre_function[i] = resp_not_supported_cmd;
371 post_function[i] = NULL;
372 /* means,
373 - no need for pre-emulation
374 - no need for post-emulation
375 - call native driver
376 */
377 }
379 /*
380 Register appropriate functions below as you need.
381 (See scsi/scsi.h for definition of SCSI op_code.)
382 */
384 /*
385 Following commands do not require emulation.
386 */
387 NO_EMULATE(TEST_UNIT_READY); /*0x00*/
388 NO_EMULATE(REZERO_UNIT); /*0x01*/
389 NO_EMULATE(REQUEST_SENSE); /*0x03*/
390 NO_EMULATE(FORMAT_UNIT); /*0x04*/
391 NO_EMULATE(READ_BLOCK_LIMITS); /*0x05*/
392 /*NO_EMULATE(REASSIGN_BLOCKS); *//*0x07*/
393 /*NO_EMULATE(INITIALIZE_ELEMENT_STATUS); *//*0x07*/
394 NO_EMULATE(READ_6); /*0x08*/
395 NO_EMULATE(WRITE_6); /*0x0a*/
396 /*NO_EMULATE(SEEK_6); *//*0x0b*/
397 /*NO_EMULATE(READ_REVERSE); *//*0x0f*/
398 NO_EMULATE(WRITE_FILEMARKS); /*0x10*/
399 NO_EMULATE(SPACE); /*0x11*/
400 NO_EMULATE(INQUIRY); /*0x12*/
401 /*NO_EMULATE(RECOVER_BUFFERED_DATA); *//*0x14*/
402 /*NO_EMULATE(MODE_SELECT); *//*0x15*/
403 /*NO_EMULATE(RESERVE); *//*0x16*/
404 /*NO_EMULATE(RELEASE); *//*0x17*/
405 /*NO_EMULATE(COPY); *//*0x18*/
406 NO_EMULATE(ERASE); /*0x19*/
407 NO_EMULATE(MODE_SENSE); /*0x1a*/
408 /*NO_EMULATE(START_STOP); *//*0x1b*/
409 /*NO_EMULATE(RECEIVE_DIAGNOSTIC); *//*0x1c*/
410 NO_EMULATE(SEND_DIAGNOSTIC); /*0x1d*/
411 /*NO_EMULATE(ALLOW_MEDIUM_REMOVAL); *//*0x1e*/
413 /*NO_EMULATE(SET_WINDOW); *//*0x24*/
414 NO_EMULATE(READ_CAPACITY); /*0x25*/
415 NO_EMULATE(READ_10); /*0x28*/
416 NO_EMULATE(WRITE_10); /*0x2a*/
417 /*NO_EMULATE(SEEK_10); *//*0x2b*/
418 /*NO_EMULATE(POSITION_TO_ELEMENT); *//*0x2b*/
419 /*NO_EMULATE(WRITE_VERIFY); *//*0x2e*/
420 /*NO_EMULATE(VERIFY); *//*0x2f*/
421 /*NO_EMULATE(SEARCH_HIGH); *//*0x30*/
422 /*NO_EMULATE(SEARCH_EQUAL); *//*0x31*/
423 /*NO_EMULATE(SEARCH_LOW); *//*0x32*/
424 /*NO_EMULATE(SET_LIMITS); *//*0x33*/
425 /*NO_EMULATE(PRE_FETCH); *//*0x34*/
426 /*NO_EMULATE(READ_POSITION); *//*0x34*/
427 /*NO_EMULATE(SYNCHRONIZE_CACHE); *//*0x35*/
428 /*NO_EMULATE(LOCK_UNLOCK_CACHE); *//*0x36*/
429 /*NO_EMULATE(READ_DEFECT_DATA); *//*0x37*/
430 /*NO_EMULATE(MEDIUM_SCAN); *//*0x38*/
431 /*NO_EMULATE(COMPARE); *//*0x39*/
432 /*NO_EMULATE(COPY_VERIFY); *//*0x3a*/
433 /*NO_EMULATE(WRITE_BUFFER); *//*0x3b*/
434 /*NO_EMULATE(READ_BUFFER); *//*0x3c*/
435 /*NO_EMULATE(UPDATE_BLOCK); *//*0x3d*/
436 /*NO_EMULATE(READ_LONG); *//*0x3e*/
437 /*NO_EMULATE(WRITE_LONG); *//*0x3f*/
438 /*NO_EMULATE(CHANGE_DEFINITION); *//*0x40*/
439 /*NO_EMULATE(WRITE_SAME); *//*0x41*/
440 /*NO_EMULATE(READ_TOC); *//*0x43*/
441 /*NO_EMULATE(LOG_SELECT); *//*0x4c*/
442 /*NO_EMULATE(LOG_SENSE); *//*0x4d*/
443 /*NO_EMULATE(MODE_SELECT_10); *//*0x55*/
444 /*NO_EMULATE(RESERVE_10); *//*0x56*/
445 /*NO_EMULATE(RELEASE_10); *//*0x57*/
446 /*NO_EMULATE(MODE_SENSE_10); *//*0x5a*/
447 /*NO_EMULATE(PERSISTENT_RESERVE_IN); *//*0x5e*/
448 /*NO_EMULATE(PERSISTENT_RESERVE_OUT); *//*0x5f*/
449 /* REPORT_LUNS *//*0xa0*//*Full emulaiton*/
450 /*NO_EMULATE(MOVE_MEDIUM); *//*0xa5*/
451 /*NO_EMULATE(EXCHANGE_MEDIUM); *//*0xa6*/
452 /*NO_EMULATE(READ_12); *//*0xa8*/
453 /*NO_EMULATE(WRITE_12); *//*0xaa*/
454 /*NO_EMULATE(WRITE_VERIFY_12); *//*0xae*/
455 /*NO_EMULATE(SEARCH_HIGH_12); *//*0xb0*/
456 /*NO_EMULATE(SEARCH_EQUAL_12); *//*0xb1*/
457 /*NO_EMULATE(SEARCH_LOW_12); *//*0xb2*/
458 /*NO_EMULATE(READ_ELEMENT_STATUS); *//*0xb8*/
459 /*NO_EMULATE(SEND_VOLUME_TAG); *//*0xb6*/
460 /*NO_EMULATE(WRITE_LONG_2); *//*0xea*/
461 /*NO_EMULATE(READ_16); *//*0x88*/
462 /*NO_EMULATE(WRITE_16); *//*0x8a*/
463 /*NO_EMULATE(VERIFY_16); *//*0x8f*/
464 /*NO_EMULATE(SERVICE_ACTION_IN); *//*0x9e*/
466 /*
467 Following commands require emulation.
468 */
469 pre_function[REPORT_LUNS] = __report_luns;
470 bitmap[REPORT_LUNS] = (VSCSIIF_NEED_EMULATE_REQBUF |
471 VSCSIIF_NEED_EMULATE_RSPBUF);
473 return;
474 }