- scst_user docs updated
[mirror/scst/.git] / usr / fileio / common.c
1 /*
2  *  common.c
3  *
4  *  Copyright (C) 2007 - 2008 Vladislav Bolkhovitin <vst@vlnb.net>
5  *  Copyright (C) 2007 - 2008 CMS Distribution Limited
6  *
7  *  This program is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU General Public License
9  *  as published by the Free Software Foundation, version 2
10  *  of the License.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  *  GNU General Public License for more details.
16  */
17
18 #include <ctype.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <stdint.h>
26 #include <getopt.h>
27 #include <inttypes.h>
28
29 #include <sys/ioctl.h>
30 #include <sys/poll.h>
31
32 #include <arpa/inet.h>
33
34 #include <pthread.h>
35
36 #include "common.h"
37
38 static unsigned int random_values[256] = {
39             9862592UL,  3744545211UL,  2348289082UL,  4036111983UL,
40           435574201UL,  3110343764UL,  2383055570UL,  1826499182UL,
41          4076766377UL,  1549935812UL,  3696752161UL,  1200276050UL,
42          3878162706UL,  1783530428UL,  2291072214UL,   125807985UL,
43          3407668966UL,   547437109UL,  3961389597UL,   969093968UL,
44            56006179UL,  2591023451UL,     1849465UL,  1614540336UL,
45          3699757935UL,   479961779UL,  3768703953UL,  2529621525UL,
46          4157893312UL,  3673555386UL,  4091110867UL,  2193909423UL,
47          2800464448UL,  3052113233UL,   450394455UL,  3424338713UL,
48          2113709130UL,  4082064373UL,  3708640918UL,  3841182218UL,
49          3141803315UL,  1032476030UL,  1166423150UL,  1169646901UL,
50          2686611738UL,   575517645UL,  2829331065UL,  1351103339UL,
51          2856560215UL,  2402488288UL,   867847666UL,     8524618UL,
52           704790297UL,  2228765657UL,   231508411UL,  1425523814UL,
53          2146764591UL,  1287631730UL,  4142687914UL,  3879884598UL,
54           729945311UL,   310596427UL,  2263511876UL,  1983091134UL,
55          3500916580UL,  1642490324UL,  3858376049UL,   695342182UL,
56           780528366UL,  1372613640UL,  1100993200UL,  1314818946UL,
57           572029783UL,  3775573540UL,   776262915UL,  2684520905UL,
58          1007252738UL,  3505856396UL,  1974886670UL,  3115856627UL,
59          4194842288UL,  2135793908UL,  3566210707UL,     7929775UL,
60          1321130213UL,  2627281746UL,  3587067247UL,  2025159890UL,
61          2587032000UL,  3098513342UL,  3289360258UL,   130594898UL,
62          2258149812UL,  2275857755UL,  3966929942UL,  1521739999UL,
63          4191192765UL,   958953550UL,  4153558347UL,  1011030335UL,
64           524382185UL,  4099757640UL,   498828115UL,  2396978754UL,
65           328688935UL,   826399828UL,  3174103611UL,  3921966365UL,
66          2187456284UL,  2631406787UL,  3930669674UL,  4282803915UL,
67          1776755417UL,   374959755UL,  2483763076UL,   844956392UL,
68          2209187588UL,  3647277868UL,   291047860UL,  3485867047UL,
69          2223103546UL,  2526736133UL,  3153407604UL,  3828961796UL,
70          3355731910UL,  2322269798UL,  2752144379UL,   519897942UL,
71          3430536488UL,  1801511593UL,  1953975728UL,  3286944283UL,
72          1511612621UL,  1050133852UL,   409321604UL,  1037601109UL,
73          3352316843UL,  4198371381UL,   617863284UL,   994672213UL,
74          1540735436UL,  2337363549UL,  1242368492UL,   665473059UL,
75          2330728163UL,  3443103219UL,  2291025133UL,  3420108120UL,
76          2663305280UL,  1608969839UL,  2278959931UL,  1389747794UL,
77          2226946970UL,  2131266900UL,  3856979144UL,  1894169043UL,
78          2692697628UL,  3797290626UL,  3248126844UL,  3922786277UL,
79           343705271UL,  3739749888UL,  2191310783UL,  2962488787UL,
80          4119364141UL,  1403351302UL,  2984008923UL,  3822407178UL,
81          1932139782UL,  2323869332UL,  2793574182UL,  1852626483UL,
82          2722460269UL,  1136097522UL,  1005121083UL,  1805201184UL,
83          2212824936UL,  2979547931UL,  4133075915UL,  2585731003UL,
84          2431626071UL,   134370235UL,  3763236829UL,  1171434827UL,
85          2251806994UL,  1289341038UL,  3616320525UL,   392218563UL,
86          1544502546UL,  2993937212UL,  1957503701UL,  3579140080UL,
87          4270846116UL,  2030149142UL,  1792286022UL,   366604999UL,
88          2625579499UL,   790898158UL,   770833822UL,   815540197UL,
89          2747711781UL,  3570468835UL,  3976195842UL,  1257621341UL,
90          1198342980UL,  1860626190UL,  3247856686UL,   351473955UL,
91           993440563UL,   340807146UL,  1041994520UL,  3573925241UL,
92           480246395UL,  2104806831UL,  1020782793UL,  3362132583UL,
93          2272911358UL,  3440096248UL,  2356596804UL,   259492703UL,
94          3899500740UL,   252071876UL,  2177024041UL,  4284810959UL,
95          2775999888UL,  2653420445UL,  2876046047UL,  1025771859UL,
96          1994475651UL,  3564987377UL,  4112956647UL,  1821511719UL,
97          3113447247UL,   455315102UL,  1585273189UL,  2311494568UL,
98           774051541UL,  1898115372UL,  2637499516UL,   247231365UL,
99          1475014417UL,   803585727UL,  3911097303UL,  1714292230UL,
100           476579326UL,  2496900974UL,  3397613314UL,   341202244UL,
101           807790202UL,  4221326173UL,   499979741UL,  1301488547UL,
102          1056807896UL,  3525009458UL,  1174811641UL,  3049738746UL,
103 };
104
105 static void exec_inquiry(struct vdisk_cmd *vcmd);
106 static void exec_request_sense(struct vdisk_cmd *vcmd);
107 static void exec_mode_sense(struct vdisk_cmd *vcmd);
108 static void exec_mode_select(struct vdisk_cmd *vcmd);
109 static void exec_read_capacity(struct vdisk_cmd *vcmd);
110 static void exec_read_capacity16(struct vdisk_cmd *vcmd);
111 static void exec_read_toc(struct vdisk_cmd *vcmd);
112 static void exec_prevent_allow_medium_removal(struct vdisk_cmd *vcmd);
113 static int exec_fsync(struct vdisk_cmd *vcmd);
114 static void exec_read(struct vdisk_cmd *vcmd, loff_t loff);
115 static void exec_write(struct vdisk_cmd *vcmd, loff_t loff);
116 static void exec_verify(struct vdisk_cmd *vcmd, loff_t loff);
117
118 static inline void set_cmd_error_status(struct scst_user_scsi_cmd_reply_exec *reply,
119         int status)
120 {
121         reply->status = status;
122         reply->resp_data_len = 0;
123         return;
124 }
125
126 static int set_sense(uint8_t *buffer, int len, int key, int asc, int ascq)
127 {
128         int res = SCST_STANDARD_SENSE_LEN;
129
130         EXTRACHECKS_BUG_ON(len < res);
131
132         memset(buffer, 0, res);
133
134         buffer[0] = 0x70;       /* Error Code                   */
135         buffer[2] = key;        /* Sense Key                    */
136         buffer[7] = 0x0a;       /* Additional Sense Length      */
137         buffer[12] = asc;       /* ASC                          */
138         buffer[13] = ascq;      /* ASCQ                         */
139
140         TRACE_BUFFER("Sense set", buffer, res);
141         return res;
142 }
143
144 void set_cmd_error(struct vdisk_cmd *vcmd, int key, int asc, int ascq)
145 {
146         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
147
148         TRACE_ENTRY();
149
150         EXTRACHECKS_BUG_ON(vcmd->cmd->subcode != SCST_USER_EXEC);
151
152         set_cmd_error_status(reply, SAM_STAT_CHECK_CONDITION);
153         reply->sense_len = set_sense(vcmd->sense, sizeof(vcmd->sense), key,
154                 asc, ascq);
155         reply->psense_buffer = (unsigned long)vcmd->sense;
156
157         TRACE_EXIT();
158         return;
159 }
160
161 void set_busy(struct scst_user_scsi_cmd_reply_exec *reply)
162 {
163         TRACE_ENTRY();
164
165         set_cmd_error_status(reply, SAM_STAT_TASK_SET_FULL);
166         TRACE_MGMT_DBG("%s", "Sending QUEUE_FULL status");
167
168         TRACE_EXIT();
169         return;
170 }
171
172 static int do_parse(struct vdisk_cmd *vcmd)
173 {
174         int res = 0;
175         struct scst_user_scsi_cmd_parse *cmd = &vcmd->cmd->parse_cmd;
176         struct scst_user_scsi_cmd_reply_parse *reply = &vcmd->reply->parse_reply;
177
178         TRACE_ENTRY();
179
180         memset(reply, 0, sizeof(*reply));
181         vcmd->reply->cmd_h = vcmd->cmd->cmd_h;
182         vcmd->reply->subcode = vcmd->cmd->subcode;
183
184         if (cmd->expected_values_set == 0) {
185                 PRINT_ERROR("%s", "Oops, expected values are not set");
186                 reply->bufflen = -1; /* invalid value */
187                 goto out;
188         }
189
190         reply->queue_type = cmd->queue_type;
191         reply->data_direction = cmd->expected_data_direction;
192         reply->data_len = cmd->expected_transfer_len;
193         reply->bufflen = cmd->expected_transfer_len;
194
195 out:
196         TRACE_EXIT_RES(res);
197         return res;
198 }
199
200 struct vdisk_tgt_dev *find_tgt_dev(struct vdisk_dev *dev, uint64_t sess_h)
201 {
202         unsigned int i;
203         struct vdisk_tgt_dev *res = NULL;
204
205         for(i = 0; i < ARRAY_SIZE(dev->tgt_devs); i++) {
206                 if (dev->tgt_devs[i].sess_h == sess_h) {
207                         res = &dev->tgt_devs[i];
208                         break;
209                 }
210         }
211         return res;
212 }
213
214 struct vdisk_tgt_dev *find_empty_tgt_dev(struct vdisk_dev *dev)
215 {
216         unsigned int i;
217         struct vdisk_tgt_dev *res = NULL;
218
219         for(i = 0; i < ARRAY_SIZE(dev->tgt_devs); i++) {
220                 if (dev->tgt_devs[i].sess_h == 0) {
221                         res = &dev->tgt_devs[i];
222                         break;
223                 }
224         }
225         return res;
226 }
227
228 static inline int sync_queue_type(enum scst_cmd_queue_type qt)
229 {
230         switch(qt) {
231                 case SCST_CMD_QUEUE_ORDERED:
232                 case SCST_CMD_QUEUE_HEAD_OF_QUEUE:
233                         return 1;
234                 default:
235                         return 0;
236         }
237 }
238
239 static inline int need_pre_sync(enum scst_cmd_queue_type cur,
240         enum scst_cmd_queue_type last)
241 {
242         if (sync_queue_type(cur))
243                 if (!sync_queue_type(last))
244                         return 1;
245         return 0;
246 }
247
248 static int do_exec(struct vdisk_cmd *vcmd)
249 {
250         int res = 0;
251         struct vdisk_dev *dev = vcmd->dev;
252         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
253         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
254         uint64_t lba_start = 0;
255         loff_t data_len = 0;
256         uint8_t *cdb = cmd->cdb;
257         int opcode = cdb[0];
258         loff_t loff;
259         int fua = 0;
260
261         TRACE_ENTRY();
262
263         switch(cmd->queue_type) {
264         case SCST_CMD_QUEUE_ORDERED:
265                 TRACE(TRACE_ORDER, "ORDERED cmd_h %d", vcmd->cmd->cmd_h);
266                 break;
267         case SCST_CMD_QUEUE_HEAD_OF_QUEUE:
268                 TRACE(TRACE_ORDER, "HQ cmd_h %d", vcmd->cmd->cmd_h);
269                 break;
270         default:
271                 break;
272         }
273
274         memset(reply, 0, sizeof(*reply));
275         vcmd->reply->cmd_h = vcmd->cmd->cmd_h;
276         vcmd->reply->subcode = vcmd->cmd->subcode;
277         reply->reply_type = SCST_EXEC_REPLY_COMPLETED;
278
279 #ifdef DEBUG_SENSE
280         if ((random() % 100000) == 75) {
281                 set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
282                 goto out;
283         }
284 #endif
285
286 #ifdef DEBUG_TM_IGNORE
287         if (dev->debug_tm_ignore && (random() % 10000) == 75) {
288                 TRACE_MGMT_DBG("Ignore cmd op %x (h=%d)", cdb[0],
289                         vcmd->cmd->cmd_h);
290                 res = 150;
291                 goto out;
292         }
293 #endif
294
295         if ((cmd->pbuf == 0) && (cmd->alloc_len != 0)) {
296 #ifdef DEBUG_NOMEM
297                 if ((random() % 100) == 75)
298                         cmd->pbuf = 0;
299                 else
300 #endif
301                         cmd->pbuf = (unsigned long)dev->alloc_fn(cmd->alloc_len);
302                 TRACE_MEM("Buf %"PRIx64" alloced, len %d", cmd->pbuf,
303                         cmd->alloc_len);
304                 reply->pbuf = cmd->pbuf;
305                 if (cmd->pbuf == 0) {
306                         TRACE(TRACE_OUT_OF_MEM, "Unable to allocate buffer "
307                                 "(len %d)", cmd->alloc_len);
308 #ifndef DEBUG_NOMEM
309                         set_busy(reply);
310 #endif
311                         goto out;
312                 }
313         }
314
315         switch (opcode) {
316         case READ_6:
317         case WRITE_6:
318         case VERIFY_6:
319                 lba_start = (((cdb[1] & 0x1f) << (BYTE * 2)) +
320                              (cdb[2] << (BYTE * 1)) +
321                              (cdb[3] << (BYTE * 0)));
322                 data_len = cmd->bufflen;
323                 break;
324         case READ_10:
325         case READ_12:
326         case WRITE_10:
327         case WRITE_12:
328         case VERIFY:
329         case WRITE_VERIFY:
330         case WRITE_VERIFY_12:
331         case VERIFY_12:
332                 lba_start |= ((uint64_t)cdb[2]) << 24;
333                 lba_start |= ((uint64_t)cdb[3]) << 16;
334                 lba_start |= ((uint64_t)cdb[4]) << 8;
335                 lba_start |= ((uint64_t)cdb[5]);
336                 data_len = cmd->bufflen;
337                 break;
338         case SYNCHRONIZE_CACHE:
339                 lba_start |= ((uint64_t)cdb[2]) << 24;
340                 lba_start |= ((uint64_t)cdb[3]) << 16;
341                 lba_start |= ((uint64_t)cdb[4]) << 8;
342                 lba_start |= ((uint64_t)cdb[5]);
343                 data_len = ((cdb[7] << (BYTE * 1)) + (cdb[8] << (BYTE * 0)))
344                                 << dev->block_shift;
345                 if (data_len == 0)
346                         data_len = dev->file_size -
347                                 ((loff_t)lba_start << dev->block_shift);
348                 break;
349         case READ_16:
350         case WRITE_16:
351         case WRITE_VERIFY_16:
352         case VERIFY_16:
353                 lba_start |= ((uint64_t)cdb[2]) << 56;
354                 lba_start |= ((uint64_t)cdb[3]) << 48;
355                 lba_start |= ((uint64_t)cdb[4]) << 40;
356                 lba_start |= ((uint64_t)cdb[5]) << 32;
357                 lba_start |= ((uint64_t)cdb[6]) << 16;
358                 lba_start |= ((uint64_t)cdb[7]) << 8;
359                 lba_start |= ((uint64_t)cdb[8]);
360                 data_len = cmd->bufflen;
361                 break;
362         }
363
364         loff = (loff_t)lba_start << dev->block_shift;
365         TRACE_DBG("cmd %d, buf %"PRIx64", lba_start %"PRId64", loff %"PRId64
366                 ", data_len %"PRId64, vcmd->cmd->cmd_h, cmd->pbuf, lba_start,
367                 (uint64_t)loff, (uint64_t)data_len);
368         if ((loff < 0) || (data_len < 0) || ((loff + data_len) > dev->file_size)) {
369                 PRINT_INFO("Access beyond the end of the device "
370                         "(%"PRId64" of %"PRId64", len %"PRId64")", (uint64_t)loff,
371                         (uint64_t)dev->file_size, (uint64_t)data_len);
372                 set_cmd_error(vcmd, SCST_LOAD_SENSE(
373                                 scst_sense_block_out_range_error));
374                 goto out;
375         }
376
377         switch (opcode) {
378         case WRITE_10:
379         case WRITE_12:
380         case WRITE_16:
381                 fua = (cdb[1] & 0x8);
382                 if (cdb[1] & 0x8) {
383                         TRACE(TRACE_ORDER, "FUA(%d): loff=%"PRId64", "
384                                 "data_len=%"PRId64, fua, (uint64_t)loff,
385                                 (uint64_t)data_len);
386                 }
387                 break;
388         }
389
390         switch (opcode) {
391         case READ_6:
392         case READ_10:
393         case READ_12:
394         case READ_16:
395                 exec_read(vcmd, loff);
396                 break;
397         case WRITE_6:
398         case WRITE_10:
399         case WRITE_12:
400         case WRITE_16:
401                 if (!dev->rd_only_flag) {
402                         int do_fsync = sync_queue_type(cmd->queue_type);
403                         struct vdisk_tgt_dev *tgt_dev;
404                         enum scst_cmd_queue_type last_queue_type;
405
406                         tgt_dev = find_tgt_dev(dev, cmd->sess_h);
407                         if (tgt_dev == NULL) {
408                                 PRINT_ERROR("Session %"PRIx64" not found",
409                                         cmd->sess_h);
410                                 set_cmd_error(vcmd,
411                                     SCST_LOAD_SENSE(scst_sense_hardw_error));
412                                 goto out;
413                         }
414
415                         last_queue_type = tgt_dev->last_write_cmd_queue_type;
416                         tgt_dev->last_write_cmd_queue_type = cmd->queue_type;
417                         if (need_pre_sync(cmd->queue_type, last_queue_type)) {
418                                 TRACE(TRACE_ORDER, "ORDERED "
419                                         "WRITE(%d): loff=%"PRId64", data_len=%"
420                                         PRId64, cmd->queue_type, (uint64_t)loff,
421                                         (uint64_t)data_len);
422                                 do_fsync = 1;
423                                 if (exec_fsync(vcmd) != 0)
424                                         goto out;
425                         }
426                         exec_write(vcmd, loff);
427                         /* O_SYNC flag is used for WT devices */
428                         if (do_fsync || fua)
429                                 exec_fsync(vcmd);
430                 } else {
431                         TRACE(TRACE_MINOR, "Attempt to write to read-only "
432                                 "device %s", dev->name);
433                         set_cmd_error(vcmd,
434                                 SCST_LOAD_SENSE(scst_sense_data_protect));
435                 }
436                 break;
437         case WRITE_VERIFY:
438         case WRITE_VERIFY_12:
439         case WRITE_VERIFY_16:
440                 if (!dev->rd_only_flag) {
441                         int do_fsync = sync_queue_type(cmd->queue_type);
442                         struct vdisk_tgt_dev *tgt_dev;
443                         enum scst_cmd_queue_type last_queue_type;
444
445                         tgt_dev = find_tgt_dev(dev, cmd->sess_h);
446                         if (tgt_dev == NULL) {
447                                 PRINT_ERROR("Session %"PRIx64" not found",
448                                         cmd->sess_h);
449                                 set_cmd_error(vcmd,
450                                     SCST_LOAD_SENSE(scst_sense_hardw_error));
451                                 goto out;
452                         }
453
454                         last_queue_type = tgt_dev->last_write_cmd_queue_type;
455                         tgt_dev->last_write_cmd_queue_type = cmd->queue_type;
456                         if (need_pre_sync(cmd->queue_type, last_queue_type)) {
457                                 TRACE(TRACE_ORDER, "ORDERED "
458                                         "WRITE_VERIFY(%d): loff=%"PRId64", "
459                                         "data_len=%"PRId64, cmd->queue_type,
460                                         (uint64_t)loff, (uint64_t)data_len);
461                                 do_fsync = 1;
462                                 if (exec_fsync(vcmd) != 0)
463                                         goto out;
464                         }
465                         exec_write(vcmd, loff);
466                         /* O_SYNC flag is used for WT devices */
467                         if (reply->status == 0)
468                                 exec_verify(vcmd, loff);
469                         else if (do_fsync)
470                                 exec_fsync(vcmd);
471                 } else {
472                         TRACE(TRACE_MINOR, "Attempt to write to read-only "
473                                 "device %s", dev->name);
474                         set_cmd_error(vcmd,
475                                 SCST_LOAD_SENSE(scst_sense_data_protect));
476                 }
477                 break;
478         case SYNCHRONIZE_CACHE:
479         {
480                 int immed = cdb[1] & 0x2;
481                 TRACE(TRACE_ORDER, "SYNCHRONIZE_CACHE: "
482                         "loff=%"PRId64", data_len=%"PRId64", immed=%d",
483                         (uint64_t)loff, (uint64_t)data_len, immed);
484                 if (immed) {
485                         /* ToDo: backgroung exec */
486                         exec_fsync(vcmd);
487                         break;
488                 } else {
489                         exec_fsync(vcmd);
490                         break;
491                 }
492         }
493         case VERIFY_6:
494         case VERIFY:
495         case VERIFY_12:
496         case VERIFY_16:
497                 exec_verify(vcmd, loff);
498                 break;
499         case MODE_SENSE:
500         case MODE_SENSE_10:
501                 exec_mode_sense(vcmd);
502                 break;
503         case MODE_SELECT:
504         case MODE_SELECT_10:
505                 exec_mode_select(vcmd);
506                 break;
507         case ALLOW_MEDIUM_REMOVAL:
508                 exec_prevent_allow_medium_removal(vcmd);
509                 break;
510         case READ_TOC:
511                 exec_read_toc(vcmd);
512                 break;
513         case START_STOP:
514                 exec_fsync(vcmd/*, 0, dev->file_size*/);
515                 break;
516         case RESERVE:
517         case RESERVE_10:
518         case RELEASE:
519         case RELEASE_10:
520         case TEST_UNIT_READY:
521                 break;
522         case INQUIRY:
523                 exec_inquiry(vcmd);
524                 break;
525         case REQUEST_SENSE:
526                 exec_request_sense(vcmd);
527                 break;
528         case READ_CAPACITY:
529                 exec_read_capacity(vcmd);
530                 break;
531         case SERVICE_ACTION_IN:
532                 if ((cmd->cdb[1] & 0x1f) == SAI_READ_CAPACITY_16) {
533                         exec_read_capacity16(vcmd);
534                         break;
535                 }
536                 /* else go through */
537         case REPORT_LUNS:
538         default:
539                 TRACE_DBG("Invalid opcode %d", opcode);
540                 set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
541                 break;
542         }
543
544 out:
545         TRACE_EXIT();
546         return res;
547 }
548
549 static int do_alloc_mem(struct vdisk_cmd *vcmd)
550 {
551         struct scst_user_get_cmd *cmd = vcmd->cmd;
552         struct scst_user_reply_cmd *reply = vcmd->reply;
553         int res = 0;
554
555         TRACE_ENTRY();
556
557         TRACE_MEM("Alloc mem (cmd %d, sess_h %"PRIx64", cdb_len %d, "
558                 "alloc_len %d, queue_type %d, data_direction %d)", cmd->cmd_h,
559                 cmd->alloc_cmd.sess_h, cmd->alloc_cmd.cdb_len,
560                 cmd->alloc_cmd.alloc_len, cmd->alloc_cmd.queue_type,
561                 cmd->alloc_cmd.data_direction);
562
563         TRACE_BUFF_FLAG(TRACE_MEMORY, "CDB", cmd->alloc_cmd.cdb,
564                 cmd->alloc_cmd.cdb_len);
565
566         memset(reply, 0, sizeof(*reply));
567         reply->cmd_h = cmd->cmd_h;
568         reply->subcode = cmd->subcode;
569 #ifdef DEBUG_NOMEM
570         if ((random() % 100) == 75)
571                 reply->alloc_reply.pbuf = 0;
572         else
573 #endif
574                 reply->alloc_reply.pbuf = (unsigned long)vcmd->dev->alloc_fn(
575                                                 cmd->alloc_cmd.alloc_len);
576         TRACE_MEM("Buf %"PRIx64" alloced, len %d", reply->alloc_reply.pbuf,
577                 cmd->alloc_cmd.alloc_len);
578         if (reply->alloc_reply.pbuf == 0) {
579                 TRACE(TRACE_OUT_OF_MEM, "Unable to allocate buffer (len %d)",
580                         cmd->alloc_cmd.alloc_len);
581         }
582
583         TRACE_EXIT_RES(res);
584         return res;
585 }
586
587 static int do_cached_mem_free(struct vdisk_cmd *vcmd)
588 {
589         struct scst_user_get_cmd *cmd = vcmd->cmd;
590         struct scst_user_reply_cmd *reply = vcmd->reply;
591         int res = 0;
592
593         TRACE_ENTRY();
594
595         TRACE_MEM("Cached mem free (cmd %d, buf %"PRIx64")", cmd->cmd_h,
596                 cmd->on_cached_mem_free.pbuf);
597
598         free((void *)(unsigned long)cmd->on_cached_mem_free.pbuf);
599
600         memset(reply, 0, sizeof(*reply));
601         reply->cmd_h = cmd->cmd_h;
602         reply->subcode = cmd->subcode;
603
604         TRACE_EXIT_RES(res);
605         return res;
606 }
607
608 static int do_on_free_cmd(struct vdisk_cmd *vcmd)
609 {
610         struct scst_user_get_cmd *cmd = vcmd->cmd;
611         struct scst_user_reply_cmd *reply = vcmd->reply;
612         int res = 0;
613
614         TRACE_ENTRY();
615
616         TRACE_DBG("On free cmd (cmd %d, resp_data_len %d, aborted %d, "
617                 "status %d, delivery_status %d)", cmd->cmd_h,
618                 cmd->on_free_cmd.resp_data_len, cmd->on_free_cmd.aborted,
619                 cmd->on_free_cmd.status, cmd->on_free_cmd.delivery_status);
620
621         TRACE_MEM("On free cmd (cmd %d, buf %"PRIx64", buffer_cached %d)",
622                 cmd->cmd_h, cmd->on_free_cmd.pbuf,
623                 cmd->on_free_cmd.buffer_cached);
624
625         if (!cmd->on_free_cmd.buffer_cached && (cmd->on_free_cmd.pbuf != 0)) {
626                 TRACE_MEM("Freeing buf %"PRIx64, cmd->on_free_cmd.pbuf);
627                 free((void *)(unsigned long)cmd->on_free_cmd.pbuf);
628         }
629
630         memset(reply, 0, sizeof(*reply));
631         reply->cmd_h = cmd->cmd_h;
632         reply->subcode = cmd->subcode;
633
634         TRACE_EXIT_RES(res);
635         return res;
636 }
637
638 static int do_tm(struct vdisk_cmd *vcmd)
639 {
640         struct scst_user_get_cmd *cmd = vcmd->cmd;
641         struct scst_user_reply_cmd *reply = vcmd->reply;
642         int res = 0;
643
644         TRACE_ENTRY();
645
646         TRACE((cmd->tm_cmd.fn == SCST_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
647                 "TM fn %d (sess_h %"PRIx64", cmd_h_to_abort %d)", cmd->tm_cmd.fn,
648                 cmd->tm_cmd.sess_h, cmd->tm_cmd.cmd_h_to_abort);
649
650         memset(reply, 0, sizeof(*reply));
651         reply->cmd_h = cmd->cmd_h;
652         reply->subcode = cmd->subcode;
653         reply->result = 0;
654
655         TRACE_EXIT_RES(res);
656         return res;
657 }
658
659 static int do_sess(struct vdisk_cmd *vcmd)
660 {
661         struct scst_user_get_cmd *cmd = vcmd->cmd;
662         struct scst_user_reply_cmd *reply = vcmd->reply;
663         int res = 0;
664         struct vdisk_tgt_dev *tgt_dev;
665
666         TRACE_ENTRY();
667
668         /*
669          * We are guaranteed to have one and only one command at this point,
670          * which is ATTACH_SESS/DETACH_SESS, so no protection is needed
671          */
672
673         tgt_dev = find_tgt_dev(vcmd->dev, cmd->sess.sess_h);
674
675         if (cmd->subcode == SCST_USER_ATTACH_SESS) {
676                 if (tgt_dev != NULL) {
677                         PRINT_ERROR("Session %"PRIx64" already exists)",
678                                 cmd->sess.sess_h);
679                         res = EEXIST;
680                         goto reply;
681                 }
682
683                 tgt_dev = find_empty_tgt_dev(vcmd->dev);
684                 if (tgt_dev == NULL) {
685                         PRINT_ERROR("Too many initiators, session %"PRIx64
686                                 " refused)", cmd->sess.sess_h);
687                         res = ENOMEM;
688                         goto reply;
689                 }
690
691                 tgt_dev->sess_h = cmd->sess.sess_h;
692                 tgt_dev->last_write_cmd_queue_type = SCST_CMD_QUEUE_SIMPLE;
693
694                 PRINT_INFO("Session from initiator %s (target %s) attached "
695                         "(LUN %"PRIx64", threads_num %d, rd_only %d, sess_h "
696                         "%"PRIx64")", cmd->sess.initiator_name,
697                         cmd->sess.target_name, cmd->sess.lun,
698                         cmd->sess.threads_num, cmd->sess.rd_only,
699                         cmd->sess.sess_h);
700         } else {
701                 if (tgt_dev == NULL) {
702                         PRINT_ERROR("Session %"PRIx64" not found)",
703                                 cmd->sess.sess_h);
704                         res = ESRCH;
705                         goto reply;
706                 }
707                 tgt_dev->sess_h = 0;
708                 PRINT_INFO("Session detached (sess_h %"PRIx64")",
709                         cmd->sess.sess_h);
710         }
711
712 reply:
713         memset(reply, 0, sizeof(*reply));
714         reply->cmd_h = cmd->cmd_h;
715         reply->subcode = cmd->subcode;
716         reply->result = res;
717
718         TRACE_EXIT_RES(res);
719         return res;
720 }
721
722 static int open_dev_fd(struct vdisk_dev *dev)
723 {
724         int res;
725         int open_flags = O_LARGEFILE;
726
727         if (dev->rd_only_flag)
728                 open_flags |= O_RDONLY;
729         else
730                 open_flags |= O_RDWR;
731         if (dev->o_direct_flag)
732                 open_flags |= O_DIRECT;
733         if (dev->wt_flag)
734                 open_flags |= O_SYNC;
735
736         TRACE_DBG("Opening file %s, flags 0x%x", dev->file_name, open_flags);
737         res = open(dev->file_name, open_flags);
738
739         return res;
740 }
741
742 void *main_loop(void *arg)
743 {
744         int res = 0;
745         struct vdisk_dev *dev = (struct vdisk_dev *)arg;
746         struct scst_user_get_cmd cmd;
747         struct scst_user_reply_cmd reply;
748         struct vdisk_cmd vcmd = { -1, &cmd, dev, &reply, {0}};
749         int scst_usr_fd = dev->scst_usr_fd;
750         struct pollfd pl;
751
752         TRACE_ENTRY();
753
754         vcmd.fd = open_dev_fd(dev);
755         if (vcmd.fd < 0) {
756                 res = -errno;
757                 PRINT_ERROR("Unable to open file %s (%s)", dev->file_name,
758                         strerror(-res));
759                 goto out;
760         }
761
762         memset(&pl, 0, sizeof(pl));
763         pl.fd = scst_usr_fd;
764         pl.events = POLLIN;
765
766         cmd.preply = 0;
767
768         while(1) {
769 #ifdef DEBUG_TM_IGNORE_ALL
770                 if (dev->debug_tm_ignore && (random() % 50000) == 55) {
771                         TRACE_MGMT_DBG("%s", "Ignore ALL");
772                         dev->debug_tm_ignore_all = 1;
773                 }
774                 if (dev->debug_tm_ignore_all) {
775                         /* Go Astral */
776                         while(1) {
777                                 sleep(60);
778                         }
779                 }
780 #endif
781
782                 res = ioctl(scst_usr_fd, SCST_USER_REPLY_AND_GET_CMD, &cmd);
783                 if (res != 0) {
784                         res = errno;
785                         switch(res) {
786                         case ESRCH:
787                         case EBUSY:
788                                 TRACE_MGMT_DBG("SCST_USER_REPLY_AND_GET_CMD returned "
789                                         "%d (%s)", res, strerror(res));
790                                 cmd.preply = 0;
791                         case EINTR:
792                                 continue;
793                         case EAGAIN:
794                                 TRACE_DBG("SCST_USER_REPLY_AND_GET_CMD returned "
795                                         "EAGAIN (%d)", res);
796                                 cmd.preply = 0;
797                                 if (dev->non_blocking)
798                                         break;
799                                 else
800                                         continue;
801                         default:
802                                 PRINT_ERROR("SCST_USER_REPLY_AND_GET_CMD failed: "
803                                         "%s (%d)", strerror(res), res);
804 #if 1
805                                 continue;
806 #else
807                                 goto out_close;
808 #endif
809                         }
810 again_poll:
811                         res = poll(&pl, 1, 2000);
812                         if (res > 0)
813                                 continue;
814                         else if (res == 0)
815                                 goto again_poll;
816                         else {
817                                 res = errno;
818                                 switch(res) {
819                                 case ESRCH:
820                                 case EBUSY:
821                                 case EAGAIN:
822                                         TRACE_MGMT_DBG("poll() returned %d "
823                                                 "(%s)", res, strerror(res));
824                                 case EINTR:
825                                         goto again_poll;
826                                 default:
827                                         PRINT_ERROR("poll() failed: %s", strerror(res));
828 #if 1
829                                         goto again_poll;
830 #else
831                                         goto out_close;
832 #endif
833                                 }
834                         }
835                 }
836
837                 TRACE_BUFFER("Received cmd", &cmd, sizeof(cmd));
838
839                 switch(cmd.subcode) {
840                 case SCST_USER_EXEC:
841                         if (cmd.exec_cmd.data_direction == SCST_DATA_WRITE) {
842                                 TRACE_BUFFER("Received cmd data",
843                                         (void *)(unsigned long)cmd.exec_cmd.pbuf,
844                                         cmd.exec_cmd.bufflen);
845                         }
846                         res = do_exec(&vcmd);
847 #ifdef DEBUG_TM_IGNORE
848                         if (res == 150) {
849                                 cmd.preply = 0;
850                                 continue;
851                         }
852 #endif
853                         if (reply.exec_reply.resp_data_len != 0) {
854                                 TRACE_BUFFER("Reply data",
855                                         (void *)(unsigned long)reply.exec_reply.pbuf,
856                                         reply.exec_reply.resp_data_len);
857                         }
858                         break;
859
860                 case SCST_USER_ALLOC_MEM:
861                         res = do_alloc_mem(&vcmd);
862                         break;
863
864                 case SCST_USER_PARSE:
865                         res = do_parse(&vcmd);
866                         break;
867
868                 case SCST_USER_ON_CACHED_MEM_FREE:
869                         res = do_cached_mem_free(&vcmd);
870                         break;
871
872                 case SCST_USER_ON_FREE_CMD:
873                         res = do_on_free_cmd(&vcmd);
874                         break;
875
876                 case SCST_USER_TASK_MGMT:
877                         res = do_tm(&vcmd);
878 #if DEBUG_TM_FN_IGNORE
879                         if (dev->debug_tm_ignore) {
880                                 sleep(15);
881                         }
882 #endif
883                         break;
884
885                 case SCST_USER_ATTACH_SESS:
886                 case SCST_USER_DETACH_SESS:
887                         res = do_sess(&vcmd);
888                         break;
889
890                 default:
891                         PRINT_ERROR("Unknown or wrong cmd subcode %x",
892                                 cmd.subcode);
893                         goto out_close;
894                 }
895
896                 if (res != 0)
897                         goto out_close;
898
899                 cmd.preply = (unsigned long)&reply;
900                 TRACE_BUFFER("Sending reply", &reply, sizeof(reply));
901         }
902
903 out_close:
904         close(vcmd.fd);
905
906 out:
907         PRINT_INFO("Thread %d exiting (res=%d)", gettid(), res);
908
909         TRACE_EXIT_RES(res);
910         return (void *)(long)res;
911 }
912
913 uint64_t gen_dev_id_num(const struct vdisk_dev *dev)
914 {
915         unsigned int dev_id_num, i;
916
917         for (dev_id_num = 0, i = 0; i < strlen(dev->name); i++) {
918                 unsigned int rv = random_values[(int)(dev->name[i])];
919                 /* do some rotating of the bits */
920                 dev_id_num ^= ((rv << i) | (rv >> (32 - i)));
921         }
922
923         return ((uint64_t)vdisk_ID << 32) | dev_id_num;
924 }
925
926 static void exec_inquiry(struct vdisk_cmd *vcmd)
927 {
928         struct vdisk_dev *dev = vcmd->dev;
929         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
930         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
931         int resp_len = 0;
932         int length = cmd->bufflen;
933         unsigned int i;
934         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
935         uint8_t buf[INQ_BUF_SZ];
936
937         TRACE_ENTRY();
938
939         if (cmd->cdb[1] & CMDDT) {
940                 TRACE_DBG("%s", "INQUIRY: CMDDT is unsupported");
941                 set_cmd_error(vcmd,
942                     SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
943                 goto out;
944         }
945
946         memset(buf, 0, sizeof(buf));
947         buf[0] = dev->type;      /* type dev */
948         if (buf[0] == TYPE_ROM)
949                 buf[1] = 0x80;      /* removable */
950         /* Vital Product */
951         if (cmd->cdb[1] & EVPD) {
952                 uint64_t dev_id_num;
953                 int dev_id_len;
954                 char dev_id_str[17];
955
956                 dev_id_num  = gen_dev_id_num(dev);
957                 dev_id_len = snprintf(dev_id_str, sizeof(dev_id_str), "%llx",
958                                         dev_id_num);
959                 if (dev_id_len >= (signed)sizeof(dev_id_str))
960                         dev_id_len = sizeof(dev_id_str) - 1;
961                 TRACE_DBG("dev_id num %llx, str %s, len %d", dev_id_num,
962                         dev_id_str, dev_id_len);
963                 if (0 == cmd->cdb[2]) { /* supported vital product data pages */
964                         buf[3] = 3;
965                         buf[4] = 0x0; /* this page */
966                         buf[5] = 0x80; /* unit serial number */
967                         buf[6] = 0x83; /* device identification */
968                         resp_len = buf[3] + 4;
969                 } else if (0x80 == cmd->cdb[2]) { /* unit serial number */
970                         int usn_len = strlen(dev->usn);
971                         buf[1] = 0x80;
972                         buf[3] = usn_len;
973                         strncpy((char *)&buf[4], dev->usn, usn_len);
974                         resp_len = buf[3] + 4;
975                 } else if (0x83 == cmd->cdb[2]) { /* device identification */
976                         int num = 4;
977
978                         buf[1] = 0x83;
979                         /* Two identification descriptors: */
980                         /* T10 vendor identifier field format (faked) */
981                         buf[num + 0] = 0x2;     /* ASCII */
982                         buf[num + 1] = 0x1;     /* Vendor ID */
983                         memcpy(&buf[num + 4], VENDOR, 8);
984                         i = strlen(dev->name) + 1; /* for ' ' */
985                         memset(&buf[num + 12], ' ', i + dev_id_len);
986                         memcpy(&buf[num + 12], dev->name, i-1);
987                         memcpy(&buf[num + 12 + i], dev_id_str, dev_id_len);
988                         buf[num + 3] = 8 + i + dev_id_len;
989                         num += buf[num + 3];
990
991 #if 0 /* This isn't required and can be misleading, so let's disable it */
992                         num += 4;
993
994                         /* NAA IEEE registered identifier (faked) */
995                         buf[num] = 0x1; /* binary */
996                         buf[num + 1] = 0x3;
997                         buf[num + 2] = 0x0;
998                         buf[num + 3] = 0x8;
999                         buf[num + 4] = 0x51;    /* ieee company id=0x123456 (faked) */
1000                         buf[num + 5] = 0x23;
1001                         buf[num + 6] = 0x45;
1002                         buf[num + 7] = 0x60;
1003                         buf[num + 8] = (dev_id_num >> 24);
1004                         buf[num + 9] = (dev_id_num >> 16) & 0xff;
1005                         buf[num + 10] = (dev_id_num >> 8) & 0xff;
1006                         buf[num + 11] = dev_id_num & 0xff;
1007                         num = num + 12 - 4;
1008 #endif
1009
1010                         resp_len = num;
1011                         buf[2] = (resp_len >> 8) & 0xFF;
1012                         buf[3] = resp_len & 0xFF;
1013                         resp_len += 4;
1014                 } else {
1015                         TRACE_DBG("INQUIRY: Unsupported EVPD page %x",
1016                                 cmd->cdb[2]);
1017                         set_cmd_error(vcmd,
1018                             SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
1019                         goto out;
1020                 }
1021         } else {
1022                 int len;
1023
1024                 if (cmd->cdb[2] != 0) {
1025                         TRACE_DBG("INQUIRY: Unsupported page %x", cmd->cdb[2]);
1026                         set_cmd_error(vcmd,
1027                             SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
1028                         goto out;
1029                 }
1030
1031                 buf[2] = 4;     /* Device complies to this standard - SPC-2  */
1032                 buf[3] = 0x12;  /* HiSup + data in format specified in SPC-2 */
1033                 buf[4] = 31;/* n - 4 = 35 - 4 = 31 for full 36 byte data */
1034                 buf[6] = 1; /* MultiP 1 */
1035                 buf[7] = 2; /* CMDQUE 1, BQue 0 => commands queuing supported */
1036
1037                 /* 8 byte ASCII Vendor Identification of the target - left aligned */
1038                 memcpy(&buf[8], VENDOR, 8);
1039
1040                 /* 16 byte ASCII Product Identification of the target - left aligned */
1041                 memset(&buf[16], ' ', 16);
1042                 len = min(strlen(dev->name), (size_t)16);
1043                 memcpy(&buf[16], dev->name, len);
1044
1045                 /* 4 byte ASCII Product Revision Level of the target - left aligned */
1046                 memcpy(&buf[32], FIO_REV, 4);
1047                 resp_len = buf[4] + 5;
1048         }
1049
1050         sBUG_ON(resp_len >= (int)sizeof(buf));
1051         if (length > resp_len)
1052                 length = resp_len;
1053         memcpy(address, buf, length);
1054         reply->resp_data_len = length;
1055
1056 out:
1057         TRACE_EXIT();
1058         return;
1059 }
1060
1061 static void exec_request_sense(struct vdisk_cmd *vcmd)
1062 {
1063         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1064         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
1065         int length = cmd->bufflen;
1066         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1067
1068         TRACE_ENTRY();
1069
1070         if (length < SCST_STANDARD_SENSE_LEN) {
1071                 PRINT_ERROR("too small requested buffer for REQUEST SENSE "
1072                         "(len %d)", length);
1073                 set_cmd_error(vcmd,
1074                     SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
1075                 goto out;
1076         }
1077
1078         set_sense(address, length, SCST_LOAD_SENSE(scst_sense_no_sense));
1079         reply->resp_data_len = length;
1080
1081 out:
1082         TRACE_EXIT();
1083         return;
1084 }
1085
1086 /*
1087  * <<Following mode pages info copied from ST318451LW with some corrections>>
1088  *
1089  * ToDo: revise them
1090  */
1091
1092 static int err_recov_pg(unsigned char *p, int pcontrol)
1093 {       /* Read-Write Error Recovery page for mode_sense */
1094         const unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1095                                               5, 0, 0xff, 0xff};
1096
1097         memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1098         if (1 == pcontrol)
1099                 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1100         return sizeof(err_recov_pg);
1101 }
1102
1103 static int disconnect_pg(unsigned char *p, int pcontrol)
1104 {       /* Disconnect-Reconnect page for mode_sense */
1105         const unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1106                                                0, 0, 0, 0, 0, 0, 0, 0};
1107
1108         memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1109         if (1 == pcontrol)
1110                 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1111         return sizeof(disconnect_pg);
1112 }
1113
1114 static int rigid_geo_pg(unsigned char *p, int pcontrol,
1115         struct vdisk_dev *dev)
1116 {
1117         unsigned char geo_m_pg[] = {0x04, 0x16, 0, 0, 0, DEF_HEADS, 0, 0,
1118                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1119                                     0x3a, 0x98/* 15K RPM */, 0, 0};
1120         int32_t ncyl, n;
1121         
1122         memcpy(p, geo_m_pg, sizeof(geo_m_pg));
1123         ncyl = dev->nblocks / (DEF_HEADS * DEF_SECTORS);
1124         if ((dev->nblocks % (DEF_HEADS * DEF_SECTORS)) != 0)
1125                 ncyl++;
1126         memcpy(&n, p + 2, sizeof(uint32_t));
1127         n = n | (htonl(ncyl) >> 8);
1128         memcpy(p + 2, &n, sizeof(uint32_t));
1129         if (1 == pcontrol)
1130                 memset(p + 2, 0, sizeof(geo_m_pg) - 2);
1131         return sizeof(geo_m_pg);
1132 }
1133
1134 static int format_pg(unsigned char *p, int pcontrol,
1135                              struct vdisk_dev *dev)
1136 {       /* Format device page for mode_sense */
1137         const unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1138                                            0, 0, 0, 0, 0, 0, 0, 0,
1139                                            0, 0, 0, 0, 0x40, 0, 0, 0};
1140
1141         memcpy(p, format_pg, sizeof(format_pg));
1142         p[10] = (DEF_SECTORS >> 8) & 0xff;
1143         p[11] = DEF_SECTORS & 0xff;
1144         p[12] = (dev->block_size >> 8) & 0xff;
1145         p[13] = dev->block_size & 0xff;
1146         if (1 == pcontrol)
1147                 memset(p + 2, 0, sizeof(format_pg) - 2);
1148         return sizeof(format_pg);
1149 }
1150
1151 static int caching_pg(unsigned char *p, int pcontrol,
1152                              struct vdisk_dev *dev)
1153 {       /* Caching page for mode_sense */
1154         const unsigned char caching_pg[] = {0x8, 18, 0x10, 0, 0xff, 0xff, 0, 0,
1155                 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1156
1157         memcpy(p, caching_pg, sizeof(caching_pg));
1158         p[2] |= !(dev->wt_flag) ? WCE : 0;
1159         if (1 == pcontrol)
1160                 memset(p + 2, 0, sizeof(caching_pg) - 2);
1161         return sizeof(caching_pg);
1162 }
1163
1164 static int ctrl_m_pg(unsigned char *p, int pcontrol,
1165                             struct vdisk_dev *dev)
1166 {       /* Control mode page for mode_sense */
1167         const unsigned char ctrl_m_pg[] = {0xa, 0xa, 0x20, 0, 0, 0x40, 0, 0,
1168                                            0, 0, 0x2, 0x4b};
1169
1170         memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1171         if (!dev->wt_flag && !dev->nv_cache)
1172                 p[3] |= 0x10; /* Enable unrestricted reordering */
1173         if (1 == pcontrol)
1174                 memset(p + 2, 0, sizeof(ctrl_m_pg) - 2);
1175         return sizeof(ctrl_m_pg);
1176 }
1177
1178 static int iec_m_pg(unsigned char *p, int pcontrol)
1179 {       /* Informational Exceptions control mode page for mode_sense */
1180         const unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1181                                           0, 0, 0x0, 0x0};
1182         memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1183         if (1 == pcontrol)
1184                 memset(p + 2, 0, sizeof(iec_m_pg) - 2);
1185         return sizeof(iec_m_pg);
1186 }
1187
1188 static void exec_mode_sense(struct vdisk_cmd *vcmd)
1189 {
1190         struct vdisk_dev *dev = vcmd->dev;
1191         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1192         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
1193         int length = cmd->bufflen;
1194         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1195         uint8_t buf[MSENSE_BUF_SZ];
1196         int blocksize;
1197         uint64_t nblocks;
1198         unsigned char dbd, type;
1199         int pcontrol, pcode, subpcode;
1200         unsigned char dev_spec;
1201         int msense_6, offset = 0, len;
1202         unsigned char *bp;
1203
1204         TRACE_ENTRY();
1205
1206         blocksize = dev->block_size;
1207         nblocks = dev->nblocks;
1208
1209         type = dev->type;    /* type dev */
1210         dbd = cmd->cdb[1] & DBD;
1211         pcontrol = (cmd->cdb[2] & 0xc0) >> 6;
1212         pcode = cmd->cdb[2] & 0x3f;
1213         subpcode = cmd->cdb[3];
1214         msense_6 = (MODE_SENSE == cmd->cdb[0]);
1215         dev_spec = (dev->rd_only_flag ? WP : 0) | DPOFUA;
1216
1217         memset(buf, 0, sizeof(buf));
1218
1219         if (0x3 == pcontrol) {
1220                 TRACE_DBG("%s", "MODE SENSE: Saving values not supported");
1221                 set_cmd_error(vcmd,
1222                     SCST_LOAD_SENSE(scst_sense_saving_params_unsup));
1223                 goto out;
1224         }
1225
1226         if (msense_6) {
1227                 buf[1] = type;
1228                 buf[2] = dev_spec;
1229                 offset = 4;
1230         } else {
1231                 buf[2] = type;
1232                 buf[3] = dev_spec;
1233                 offset = 8;
1234         }
1235
1236         if (0 != subpcode) { /* TODO: Control Extension page */
1237                 TRACE_DBG("%s", "MODE SENSE: Only subpage 0 is supported");
1238                 set_cmd_error(vcmd,
1239                     SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
1240                 goto out;
1241         }
1242
1243         if (!dbd) {
1244                 /* Create block descriptor */
1245                 buf[offset - 1] = 0x08;         /* block descriptor length */
1246                 if (nblocks >> 32) {
1247                         buf[offset + 0] = 0xFF;
1248                         buf[offset + 1] = 0xFF;
1249                         buf[offset + 2] = 0xFF;
1250                         buf[offset + 3] = 0xFF;
1251                 } else {
1252                         buf[offset + 0] = (nblocks >> (BYTE * 3)) & 0xFF;/* num blks */
1253                         buf[offset + 1] = (nblocks >> (BYTE * 2)) & 0xFF;
1254                         buf[offset + 2] = (nblocks >> (BYTE * 1)) & 0xFF;
1255                         buf[offset + 3] = (nblocks >> (BYTE * 0)) & 0xFF;
1256                 }
1257                 buf[offset + 4] = 0;                    /* density code */
1258                 buf[offset + 5] = (blocksize >> (BYTE * 2)) & 0xFF;/* blklen */
1259                 buf[offset + 6] = (blocksize >> (BYTE * 1)) & 0xFF;
1260                 buf[offset + 7] = (blocksize >> (BYTE * 0)) & 0xFF;
1261
1262                 offset += 8;                    /* increment offset */
1263         }
1264
1265         bp = buf + offset;
1266
1267         switch (pcode) {
1268         case 0x1:       /* Read-Write error recovery page, direct access */
1269                 len = err_recov_pg(bp, pcontrol);
1270                 break;
1271         case 0x2:       /* Disconnect-Reconnect page, all devices */
1272                 len = disconnect_pg(bp, pcontrol);
1273                 break;
1274         case 0x3:       /* Format device page, direct access */
1275                 len = format_pg(bp, pcontrol, dev);
1276                 break;
1277         case 0x4:       /* Rigid disk geometry */
1278                 len = rigid_geo_pg(bp, pcontrol, dev);
1279                 break;
1280         case 0x8:       /* Caching page, direct access */
1281                 len = caching_pg(bp, pcontrol, dev);
1282                 break;
1283         case 0xa:       /* Control Mode page, all devices */
1284                 len = ctrl_m_pg(bp, pcontrol, dev);
1285                 break;
1286         case 0x1c:      /* Informational Exceptions Mode page, all devices */
1287                 len = iec_m_pg(bp, pcontrol);
1288                 break;
1289         case 0x3f:      /* Read all Mode pages */
1290                 len = err_recov_pg(bp, pcontrol);
1291                 len += disconnect_pg(bp + len, pcontrol);
1292                 len += format_pg(bp + len, pcontrol, dev);
1293                 len += caching_pg(bp + len, pcontrol, dev);
1294                 len += ctrl_m_pg(bp + len, pcontrol, dev);
1295                 len += iec_m_pg(bp + len, pcontrol);
1296                 len += rigid_geo_pg(bp + len, pcontrol, dev);
1297                 break;
1298         default:
1299                 TRACE_DBG("MODE SENSE: Unsupported page %x", pcode);
1300                 set_cmd_error(vcmd,
1301                     SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
1302                 goto out;
1303         }
1304
1305         offset += len;
1306
1307         if (msense_6)
1308                 buf[0] = offset - 1;
1309         else {
1310                 buf[0] = ((offset - 2) >> 8) & 0xff;
1311                 buf[1] = (offset - 2) & 0xff;
1312         }
1313
1314         sBUG_ON(offset >= (int)sizeof(buf));
1315         if (offset > length)
1316                 offset = length;
1317         memcpy(address, buf, offset);
1318         reply->resp_data_len = offset;
1319
1320 out:
1321         TRACE_EXIT();
1322         return;
1323 }
1324
1325 static int set_wt(struct vdisk_dev *dev, int wt)
1326 {
1327         int res = 0;
1328
1329         TRACE_ENTRY();
1330
1331         if ((dev->wt_flag == wt) || dev->nullio)
1332                 goto out;
1333
1334         pthread_mutex_lock(&dev->dev_mutex);
1335         dev->wt_flag = wt;
1336         pthread_mutex_unlock(&dev->dev_mutex);
1337
1338 out:
1339         TRACE_EXIT_RES(res);
1340         return res;
1341 }
1342
1343 static void exec_mode_select(struct vdisk_cmd *vcmd)
1344 {
1345         struct vdisk_dev *dev = vcmd->dev;
1346         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1347         int length = cmd->bufflen;
1348         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1349         int mselect_6, offset;
1350
1351         TRACE_ENTRY();
1352
1353         mselect_6 = (MODE_SELECT == cmd->cdb[0]);
1354
1355         if (!(cmd->cdb[1] & PF) || (cmd->cdb[1] & SP)) {
1356                 PRINT_ERROR("MODE SELECT: PF and/or SP are wrongly set "
1357                         "(cdb[1]=%x)", cmd->cdb[1]);
1358                 set_cmd_error(vcmd,
1359                     SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
1360                 goto out;
1361         }
1362
1363         if (mselect_6) {
1364                 offset = 4;
1365         } else {
1366                 offset = 8;
1367         }
1368
1369         if (address[offset - 1] == 8) {
1370                 offset += 8;
1371         } else if (address[offset - 1] != 0) {
1372                 PRINT_ERROR("%s", "MODE SELECT: Wrong parameters list "
1373                         "lenght");
1374                 set_cmd_error(vcmd,
1375                     SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
1376                 goto out;
1377         }
1378
1379         while (length > offset + 2) {
1380                 if (address[offset] & PS) {
1381                         PRINT_ERROR("%s", "MODE SELECT: Illegal PS bit");
1382                         set_cmd_error(vcmd, SCST_LOAD_SENSE(
1383                                 scst_sense_invalid_field_in_parm_list));
1384                         goto out;
1385                 }
1386                 if ((address[offset] & 0x3f) == 0x8) {  /* Caching page */
1387                         if (address[offset + 1] != 18) {
1388                                 PRINT_ERROR("%s", "MODE SELECT: Invalid "
1389                                         "caching page request");
1390                                 set_cmd_error(vcmd, SCST_LOAD_SENSE(
1391                                         scst_sense_invalid_field_in_parm_list));
1392                                 goto out;
1393                         }
1394                         if (set_wt(dev,
1395                               (address[offset + 2] & WCE) ? 0 : 1) != 0) {
1396                                 set_cmd_error(vcmd,
1397                                     SCST_LOAD_SENSE(scst_sense_hardw_error));
1398                                 goto out;
1399                         }
1400                         break;
1401                 }
1402                 offset += address[offset + 1];
1403         }
1404
1405 out:
1406         TRACE_EXIT();
1407         return;
1408 }
1409
1410 static void exec_read_capacity(struct vdisk_cmd *vcmd)
1411 {
1412         struct vdisk_dev *dev = vcmd->dev;
1413         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1414         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
1415         int length = cmd->bufflen;
1416         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1417         uint32_t blocksize;
1418         uint64_t nblocks;
1419         uint8_t buffer[READ_CAP_LEN];
1420
1421         TRACE_ENTRY();
1422
1423         blocksize = dev->block_size;
1424         nblocks = dev->nblocks;
1425
1426         /* last block on the dev is (nblocks-1) */
1427         memset(buffer, 0, sizeof(buffer));
1428         if (nblocks >> 32) {
1429                 buffer[0] = 0xFF;
1430                 buffer[1] = 0xFF;
1431                 buffer[2] = 0xFF;
1432                 buffer[3] = 0xFF;
1433         } else {
1434                 buffer[0] = ((nblocks - 1) >> (BYTE * 3)) & 0xFF;
1435                 buffer[1] = ((nblocks - 1) >> (BYTE * 2)) & 0xFF;
1436                 buffer[2] = ((nblocks - 1) >> (BYTE * 1)) & 0xFF;
1437                 buffer[3] = ((nblocks - 1) >> (BYTE * 0)) & 0xFF;
1438         }
1439         buffer[4] = (blocksize >> (BYTE * 3)) & 0xFF;
1440         buffer[5] = (blocksize >> (BYTE * 2)) & 0xFF;
1441         buffer[6] = (blocksize >> (BYTE * 1)) & 0xFF;
1442         buffer[7] = (blocksize >> (BYTE * 0)) & 0xFF;
1443
1444         if (length > READ_CAP_LEN)
1445                 length = READ_CAP_LEN;
1446         memcpy(address, buffer, length);
1447
1448         reply->resp_data_len = length;
1449
1450         TRACE_EXIT();
1451         return;
1452 }
1453
1454 static void exec_read_capacity16(struct vdisk_cmd *vcmd)
1455 {
1456         struct vdisk_dev *dev = vcmd->dev;
1457         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1458         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
1459         int length = cmd->bufflen;
1460         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1461         uint32_t blocksize;
1462         uint64_t nblocks;
1463         uint8_t buffer[READ_CAP16_LEN];
1464
1465         TRACE_ENTRY();
1466
1467         blocksize = dev->block_size;
1468         nblocks = dev->nblocks - 1;
1469
1470         memset(buffer, 0, sizeof(buffer));
1471         buffer[0] = nblocks >> 56;
1472         buffer[1] = (nblocks >> 48) & 0xFF;
1473         buffer[2] = (nblocks >> 40) & 0xFF;
1474         buffer[3] = (nblocks >> 32) & 0xFF;
1475         buffer[4] = (nblocks >> 24) & 0xFF;
1476         buffer[5] = (nblocks >> 16) & 0xFF;
1477         buffer[6] = (nblocks >> 8) & 0xFF;
1478         buffer[7] = nblocks& 0xFF;
1479
1480         buffer[8] = (blocksize >> (BYTE * 3)) & 0xFF;
1481         buffer[9] = (blocksize >> (BYTE * 2)) & 0xFF;
1482         buffer[10] = (blocksize >> (BYTE * 1)) & 0xFF;
1483         buffer[11] = (blocksize >> (BYTE * 0)) & 0xFF;
1484
1485         if (length > READ_CAP16_LEN)
1486                 length = READ_CAP16_LEN;
1487         memcpy(address, buffer, length);
1488
1489         reply->resp_data_len = length;
1490
1491         TRACE_EXIT();
1492         return;
1493 }
1494
1495 static void exec_read_toc(struct vdisk_cmd *vcmd)
1496 {
1497         struct vdisk_dev *dev = vcmd->dev;
1498         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1499         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
1500         int32_t off = 0;
1501         int length = cmd->bufflen;
1502         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1503         uint32_t nblocks;
1504         uint8_t buffer[4+8+8] = { 0x00, 0x0a, 0x01, 0x01, 0x00, 0x14,
1505                                   0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
1506
1507         TRACE_ENTRY();
1508
1509         if (dev->type != TYPE_ROM) {
1510                 PRINT_ERROR("%s", "READ TOC for non-CDROM device");
1511                 set_cmd_error(vcmd,
1512                         SCST_LOAD_SENSE(scst_sense_invalid_opcode));
1513                 goto out;
1514         }
1515
1516         if (cmd->cdb[2] & 0x0e/*Format*/) {
1517                 PRINT_ERROR("%s", "READ TOC: invalid requested data format");
1518                 set_cmd_error(vcmd,
1519                         SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
1520                 goto out;
1521         }
1522
1523         if ((cmd->cdb[6] != 0 && (cmd->cdb[2] & 0x01)) ||
1524             (cmd->cdb[6] > 1 && cmd->cdb[6] != 0xAA)) {
1525                 PRINT_ERROR("READ TOC: invalid requested track number %x",
1526                         cmd->cdb[6]);
1527                 set_cmd_error(vcmd,
1528                         SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
1529                 goto out;
1530         }
1531
1532         /* ToDo when you have > 8TB ROM device. */
1533         nblocks = (uint32_t)dev->nblocks;
1534
1535         /* Header */
1536         memset(buffer, 0, sizeof(buffer));
1537         buffer[2] = 0x01;    /* First Track/Session */
1538         buffer[3] = 0x01;    /* Last Track/Session */
1539         off = 4;
1540         if (cmd->cdb[6] <= 1)
1541         {
1542                 /* Fistr TOC Track Descriptor */
1543                 buffer[off+1] = 0x14; /* ADDR    0x10 - Q Sub-channel encodes current position data
1544                                          CONTROL 0x04 - Data track, recoreded uninterrupted */
1545                 buffer[off+2] = 0x01; /* Track Number */
1546                 off += 8;
1547         }
1548         if (!(cmd->cdb[2] & 0x01))
1549         {
1550                 /* Lead-out area TOC Track Descriptor */
1551                 buffer[off+1] = 0x14;
1552                 buffer[off+2] = 0xAA;     /* Track Number */
1553                 buffer[off+4] = (nblocks >> (BYTE * 3)) & 0xFF; /* Track Start Address */
1554                 buffer[off+5] = (nblocks >> (BYTE * 2)) & 0xFF;
1555                 buffer[off+6] = (nblocks >> (BYTE * 1)) & 0xFF;
1556                 buffer[off+7] = (nblocks >> (BYTE * 0)) & 0xFF;
1557                 off += 8;
1558         }
1559
1560         buffer[1] = off - 2;    /* Data  Length */
1561
1562         if (off > length)
1563                 off = length;
1564         memcpy(address, buffer, off);
1565         reply->resp_data_len = off;
1566
1567 out:
1568         TRACE_EXIT();
1569         return;
1570 }
1571
1572 static void exec_prevent_allow_medium_removal(struct vdisk_cmd *vcmd)
1573 {
1574         struct vdisk_dev *dev = vcmd->dev;
1575         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1576
1577         TRACE_DBG("PERSIST/PREVENT 0x%02x", cmd->cdb[4]);
1578
1579         pthread_mutex_lock(&dev->dev_mutex);
1580         if (dev->type == TYPE_ROM)
1581                 dev->prevent_allow_medium_removal =
1582                         cmd->cdb[4] & 0x01 ? 1 : 0;
1583         else {
1584                 PRINT_ERROR("%s", "Prevent allow medium removal for "
1585                         "non-CDROM device");
1586                 set_cmd_error(vcmd,
1587                         SCST_LOAD_SENSE(scst_sense_invalid_opcode));
1588         }
1589         pthread_mutex_unlock(&dev->dev_mutex);
1590
1591         return;
1592 }
1593
1594 static int exec_fsync(struct vdisk_cmd *vcmd)
1595 {
1596         int res = 0;
1597         struct vdisk_dev *dev = vcmd->dev;
1598
1599         /* Hopefully, the compiler will generate the single comparison */
1600         if (dev->nv_cache || dev->wt_flag || dev->rd_only_flag ||
1601             dev->o_direct_flag || dev->nullio)
1602                 goto out;
1603
1604         /* ToDo: use sync_file_range() instead */
1605         fsync(vcmd->fd);
1606
1607 out:
1608         TRACE_EXIT_RES(res);
1609         return res;
1610 }
1611
1612 static void exec_read(struct vdisk_cmd *vcmd, loff_t loff)
1613 {
1614         struct vdisk_dev *dev = vcmd->dev;
1615         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1616         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
1617         int length = cmd->bufflen;
1618         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1619         int fd = vcmd->fd;
1620         loff_t err;
1621
1622         TRACE_ENTRY();
1623
1624         TRACE_DBG("reading off %"PRId64", len %d", loff, length);
1625         if (dev->nullio)
1626                 err = length;
1627         else {
1628                 /* SEEK */
1629                 err = lseek64(fd, loff, 0/*SEEK_SET*/);
1630                 if (err != loff) {
1631                         PRINT_ERROR("lseek trouble %"PRId64" != %"PRId64
1632                                 " (errno %d)", (uint64_t)err, (uint64_t)loff,
1633                                 errno);
1634                         set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
1635                         goto out;
1636                 }
1637                 /* READ */
1638                 err = read(fd, address, length);
1639         }
1640
1641         if ((err < 0) || (err < length)) {
1642                 PRINT_ERROR("read() returned %"PRId64" from %d (errno %d)",
1643                         (uint64_t)err, length, errno);
1644                 if (err == -EAGAIN)
1645                         set_busy(reply);
1646                 else {
1647                         set_cmd_error(vcmd,
1648                             SCST_LOAD_SENSE(scst_sense_read_error));
1649                 }
1650                 goto out;
1651         }
1652
1653         reply->resp_data_len = cmd->bufflen;
1654
1655 out:
1656         TRACE_EXIT();
1657         return;
1658 }
1659
1660 static void exec_write(struct vdisk_cmd *vcmd, loff_t loff)
1661 {
1662         struct vdisk_dev *dev = vcmd->dev;
1663         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1664         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
1665         loff_t err;
1666         int length = cmd->bufflen;
1667         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1668         int fd = vcmd->fd;
1669
1670         TRACE_ENTRY();
1671
1672 restart:
1673         TRACE_DBG("writing off %"PRId64", len %d", loff, length);
1674
1675         if (dev->nullio)
1676                 err = length;
1677         else {
1678                 /* SEEK */
1679                 err = lseek64(fd, loff, 0/*SEEK_SET*/);
1680                 if (err != loff) {
1681                         PRINT_ERROR("lseek trouble %"PRId64" != %"PRId64
1682                                 " (errno %d)", (uint64_t)err, (uint64_t)loff,
1683                                 errno);
1684                         set_cmd_error(vcmd,
1685                             SCST_LOAD_SENSE(scst_sense_hardw_error));
1686                         goto out;
1687                 }
1688
1689                 /* WRITE */
1690                 err = write(fd, address, length);
1691         }
1692
1693         if (err < 0) {
1694                 PRINT_ERROR("write() returned %"PRId64" from %d (errno %d, "
1695                         "cmd_h %x)", err, length, errno, vcmd->cmd->cmd_h);
1696                 if (err == -EAGAIN)
1697                         set_busy(reply);
1698                 else {
1699                         set_cmd_error(vcmd,
1700                             SCST_LOAD_SENSE(scst_sense_write_error));
1701                 }
1702                 goto out;
1703         } else if (err < length) {
1704                 /*
1705                  * Probably that's wrong, but sometimes write() returns
1706                  * value less, than requested. Let's restart.
1707                  */
1708                 TRACE_MGMT_DBG("write() returned %d from %d", (int)err, length);
1709                 if (err == 0) {
1710                         PRINT_INFO("Suspicious: write() returned 0 from "
1711                                 "%d", length);
1712                 }
1713                 length -= err;
1714                 goto restart;
1715         }
1716
1717 out:
1718         TRACE_EXIT();
1719         return;
1720 }
1721
1722 static void exec_verify(struct vdisk_cmd *vcmd, loff_t loff)
1723 {
1724         struct vdisk_dev *dev = vcmd->dev;
1725         struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
1726         struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
1727         loff_t err;
1728         int length = cmd->bufflen;
1729         uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
1730         int compare;
1731         int fd = vcmd->fd;
1732         uint8_t mem_verify[128*1024];
1733
1734         TRACE_ENTRY();
1735
1736         if (exec_fsync(vcmd) != 0)
1737                 goto out;
1738
1739         /*
1740          * Until the cache is cleared prior the verifying, there is not
1741          * much point in this code. ToDo.
1742          *
1743          * Nevertherless, this code is valuable if the data have not read
1744          * from the file/disk yet.
1745          */
1746
1747         /* SEEK */
1748         if (!dev->nullio) {
1749                 err = lseek64(fd, loff, 0/*SEEK_SET*/);
1750                 if (err != loff) {
1751                         PRINT_ERROR("lseek trouble %"PRId64" != %"PRId64
1752                                 " (errno %d)", (uint64_t)err,
1753                                 (uint64_t)loff, errno);
1754                         set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
1755                         goto out;
1756                 }
1757         }
1758
1759         if ((length == 0) && (cmd->data_len != 0)) {
1760                 length = cmd->data_len;
1761                 compare = 0;
1762         } else
1763                 compare = 1;
1764
1765         while (length > 0) {
1766                 int len_mem = (length > (int)sizeof(mem_verify)) ?
1767                                         (int)sizeof(mem_verify) : length;
1768                 TRACE_DBG("Verify: length %d - len_mem %d", length, len_mem);
1769
1770                 if (!dev->nullio)
1771                         err = read(fd, (char *)mem_verify, len_mem);
1772                 else
1773                         err = len_mem;
1774                 if ((err < 0) || (err < len_mem)) {
1775                         PRINT_ERROR("read() returned %"PRId64" from %d "
1776                                 "(errno %d)", (uint64_t)err, len_mem, errno);
1777                         if (err == -EAGAIN)
1778                                 set_busy(reply);
1779                         else {
1780                                 set_cmd_error(vcmd,
1781                                     SCST_LOAD_SENSE(scst_sense_read_error));
1782                         }
1783                         goto out;
1784                 }
1785                 if (compare && memcmp(address, mem_verify, len_mem) != 0) {
1786                         TRACE_DBG("Verify: error memcmp length %d", length);
1787                         set_cmd_error(vcmd,
1788                             SCST_LOAD_SENSE(scst_sense_miscompare_error));
1789                         goto out;
1790                 }
1791                 length -= len_mem;
1792                 address += len_mem;
1793         }
1794
1795         if (length < 0) {
1796                 PRINT_ERROR("Failure: %d", length);
1797                 set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
1798         }
1799
1800 out:
1801         TRACE_EXIT();
1802         return;
1803 }