Patch from Dotan Barak <dotanba@gmail.com>:
[mirror/scst/.git] / scst / src / dev_handlers / scst_disk.c
1 /*
2  *  scst_disk.c
3  *
4  *  Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
5  *                 and Leonid Stoljar
6  *
7  *  SCSI disk (type 0) dev handler
8  *  &
9  *  SCSI disk (type 0) "performance" device handler (skip all READ and WRITE
10  *   operations).
11  *
12  *  This program is free software; you can redistribute it and/or
13  *  modify it under the terms of the GNU General Public License
14  *  as published by the Free Software Foundation, version 2
15  *  of the License.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  *  GNU General Public License for more details.
21  */
22
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <scsi/scsi_host.h>
26
27 #define LOG_PREFIX           "dev_disk"
28
29 #include "scst.h"
30 #include "scst_dev_handler.h"
31
32 # define DISK_NAME           "dev_disk"
33 # define DISK_PERF_NAME      "dev_disk_perf"
34
35 #define DISK_TYPE {                                     \
36         .name =                 DISK_NAME,              \
37         .type =                 TYPE_DISK,              \
38         .parse_atomic =         1,                      \
39         .dev_done_atomic =      1,                      \
40         .exec_atomic =          1,                      \
41         .attach =               disk_attach,            \
42         .detach =               disk_detach,            \
43         .parse =                disk_parse,             \
44         .dev_done =             disk_done,              \
45 }
46
47 #define DISK_PERF_TYPE {                                \
48         .name =                 DISK_PERF_NAME,         \
49         .type =                 TYPE_DISK,              \
50         .parse_atomic =         1,                      \
51         .dev_done_atomic =      1,                      \
52         .exec_atomic =          1,                      \
53         .attach =               disk_attach,            \
54         .detach =               disk_detach,            \
55         .parse =                disk_parse,             \
56         .dev_done =             disk_done,              \
57         .exec =                 disk_exec,              \
58 }
59
60 #define DISK_DEF_BLOCK_SHIFT    9
61
62 struct disk_params {
63         int block_shift;
64 };
65
66 int disk_attach(struct scst_device *dev);
67 void disk_detach(struct scst_device *dev);
68 int disk_parse(struct scst_cmd *cmd);
69 int disk_done(struct scst_cmd *cmd);
70 int disk_exec(struct scst_cmd *cmd);
71
72 static struct scst_dev_type disk_devtype = DISK_TYPE;
73 static struct scst_dev_type disk_devtype_perf = DISK_PERF_TYPE;
74
75 static int __init init_scst_disk_driver(void)
76 {
77         int res = 0;
78
79         TRACE_ENTRY();
80
81         disk_devtype.module = THIS_MODULE;
82
83         res = scst_register_dev_driver(&disk_devtype);
84         if (res < 0)
85                 goto out;
86
87         res = scst_dev_handler_build_std_proc(&disk_devtype);
88         if (res != 0)
89                 goto out_unreg1;
90
91         disk_devtype_perf.module = THIS_MODULE;
92
93         res = scst_register_dev_driver(&disk_devtype_perf);
94         if (res < 0)
95                 goto out_unreg1_err1;
96
97         res = scst_dev_handler_build_std_proc(&disk_devtype_perf);
98         if (res != 0)
99                 goto out_unreg2;
100
101 out:
102         TRACE_EXIT_RES(res);
103         return res;
104
105 out_unreg2:
106         scst_dev_handler_destroy_std_proc(&disk_devtype_perf);
107
108 out_unreg1_err1:
109         scst_dev_handler_destroy_std_proc(&disk_devtype);
110
111 out_unreg1:
112         scst_unregister_dev_driver(&disk_devtype);
113         goto out;
114 }
115
116 static void __exit exit_scst_disk_driver(void)
117 {
118         TRACE_ENTRY();
119         scst_dev_handler_destroy_std_proc(&disk_devtype_perf);
120         scst_unregister_dev_driver(&disk_devtype_perf);
121         scst_dev_handler_destroy_std_proc(&disk_devtype);
122         scst_unregister_dev_driver(&disk_devtype);
123         TRACE_EXIT();
124         return;
125 }
126
127 module_init(init_scst_disk_driver);
128 module_exit(exit_scst_disk_driver);
129
130 /**************************************************************
131  *  Function:  disk_attach
132  *
133  *  Argument:
134  *
135  *  Returns :  1 if attached, error code otherwise
136  *
137  *  Description:
138  *************************************************************/
139 int disk_attach(struct scst_device *dev)
140 {
141         int res = 0;
142         uint8_t cmd[10];
143         const int buffer_size = 512;
144         uint8_t *buffer = NULL;
145         int retries;
146         unsigned char sense_buffer[SCST_SENSE_BUFFERSIZE];
147         enum dma_data_direction data_dir;
148         unsigned char *sbuff;
149         struct disk_params *params;
150
151         TRACE_ENTRY();
152
153         if (dev->scsi_dev == NULL ||
154             dev->scsi_dev->type != dev->handler->type) {
155                 PRINT_ERROR("%s", "SCSI device not define or illegal type");
156                 res = -ENODEV;
157                 goto out;
158         }
159
160         params = kzalloc(sizeof(*params), GFP_KERNEL);
161         if (params == NULL) {
162                 TRACE(TRACE_OUT_OF_MEM, "%s",
163                       "Unable to allocate struct disk_params");
164                 res = -ENOMEM;
165                 goto out;
166         }
167
168         buffer = kmalloc(buffer_size, GFP_KERNEL);
169         if (!buffer) {
170                 TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure");
171                 res = -ENOMEM;
172                 goto out_free_params;
173         }
174
175         /* Clear any existing UA's and get disk capacity (disk block size) */
176         memset(cmd, 0, sizeof(cmd));
177         cmd[0] = READ_CAPACITY;
178         cmd[1] = (dev->scsi_dev->scsi_level <= SCSI_2) ?
179             ((dev->scsi_dev->lun << 5) & 0xe0) : 0;
180         retries = SCST_DEV_UA_RETRIES;
181         while (1) {
182                 memset(buffer, 0, buffer_size);
183                 data_dir = SCST_DATA_READ;
184                 sbuff = sense_buffer;
185
186                 TRACE_DBG("%s", "Doing READ_CAPACITY");
187                 res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
188                                    buffer_size, sbuff,
189                                    SCST_GENERIC_DISK_REG_TIMEOUT, 3, 0);
190
191                 TRACE_DBG("READ_CAPACITY done: %x", res);
192
193                 if (!res || (sbuff[12] != 0x28 && sbuff[12] != 0x29))
194                         break;
195                 if (!--retries) {
196                         PRINT_ERROR("UA not clear after %d retries",
197                                 SCST_DEV_UA_RETRIES);
198                         res = -ENODEV;
199                         goto out_free_buf;
200                 }
201         }
202         if (res == 0) {
203                 int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) |
204                                      (buffer[6] << 8) | (buffer[7] << 0));
205                 if (sector_size == 0)
206                         params->block_shift = DISK_DEF_BLOCK_SHIFT;
207                 else
208                         params->block_shift = scst_calc_block_shift(sector_size);
209         } else {
210                 TRACE_BUFFER("Sense set", sbuff, SCST_SENSE_BUFFERSIZE);
211                 res = -ENODEV;
212                 goto out_free_buf;
213         }
214
215         res = scst_obtain_device_parameters(dev);
216         if (res != 0) {
217                 PRINT_ERROR("Failed to obtain control parameters for device "
218                         "%d:%d:%d:%d", dev->scsi_dev->host->host_no,
219                         dev->scsi_dev->channel, dev->scsi_dev->id,
220                         dev->scsi_dev->lun);
221                 goto out_free_buf;
222         }
223
224 out_free_buf:
225         kfree(buffer);
226
227 out_free_params:
228         if (res == 0)
229                 dev->dh_priv = params;
230         else
231                 kfree(params);
232
233 out:
234         TRACE_EXIT_RES(res);
235         return res;
236 }
237
238 /************************************************************
239  *  Function:  disk_detach
240  *
241  *  Argument:
242  *
243  *  Returns :  None
244  *
245  *  Description:  Called to detach this device type driver
246  ************************************************************/
247 void disk_detach(struct scst_device *dev)
248 {
249         struct disk_params *params =
250                 (struct disk_params *)dev->dh_priv;
251
252         TRACE_ENTRY();
253
254         kfree(params);
255         dev->dh_priv = NULL;
256
257         TRACE_EXIT();
258         return;
259 }
260
261 static int disk_get_block_shift(struct scst_cmd *cmd)
262 {
263         struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv;
264         /*
265          * No need for locks here, since *_detach() can not be
266          * called, when there are existing commands.
267          */
268         return params->block_shift;
269 }
270
271 /********************************************************************
272  *  Function:  disk_parse
273  *
274  *  Argument:
275  *
276  *  Returns :  The state of the command
277  *
278  *  Description:  This does the parsing of the command
279  *
280  *  Note:  Not all states are allowed on return
281  ********************************************************************/
282 int disk_parse(struct scst_cmd *cmd)
283 {
284         int res = SCST_CMD_STATE_DEFAULT;
285
286         scst_sbc_generic_parse(cmd, disk_get_block_shift);
287
288         cmd->retries = SCST_PASSTHROUGH_RETRIES;
289
290         return res;
291 }
292
293 static void disk_set_block_shift(struct scst_cmd *cmd, int block_shift)
294 {
295         struct disk_params *params = (struct disk_params *)cmd->dev->dh_priv;
296         /*
297          * No need for locks here, since *_detach() can not be
298          * called, when there are existing commands.
299          */
300         if (block_shift != 0)
301                 params->block_shift = block_shift;
302         else
303                 params->block_shift = DISK_DEF_BLOCK_SHIFT;
304         return;
305 }
306
307 /********************************************************************
308  *  Function:  disk_done
309  *
310  *  Argument:
311  *
312  *  Returns :
313  *
314  *  Description:  This is the completion routine for the command,
315  *                it is used to extract any necessary information
316  *                about a command.
317  ********************************************************************/
318 int disk_done(struct scst_cmd *cmd)
319 {
320         int res = SCST_CMD_STATE_DEFAULT;
321
322         TRACE_ENTRY();
323
324         res = scst_block_generic_dev_done(cmd, disk_set_block_shift);
325
326         TRACE_EXIT_RES(res);
327         return res;
328 }
329
330 /********************************************************************
331  *  Function:  disk_exec
332  *
333  *  Argument:
334  *
335  *  Returns :
336  *
337  *  Description:  Make SCST do nothing for data READs and WRITES.
338  *                Intended for raw line performance testing
339  ********************************************************************/
340 int disk_exec(struct scst_cmd *cmd)
341 {
342         int res = SCST_EXEC_NOT_COMPLETED, rc;
343         int opcode = cmd->cdb[0];
344
345         TRACE_ENTRY();
346
347         rc = scst_check_local_events(cmd);
348         if (unlikely(rc != 0))
349                 goto out_done;
350
351         cmd->status = 0;
352         cmd->msg_status = 0;
353         cmd->host_status = DID_OK;
354         cmd->driver_status = 0;
355
356         switch (opcode) {
357         case WRITE_6:
358         case WRITE_10:
359         case WRITE_12:
360         case WRITE_16:
361         case READ_6:
362         case READ_10:
363         case READ_12:
364         case READ_16:
365                 cmd->completed = 1;
366                 goto out_done;
367         }
368
369 out:
370         TRACE_EXIT_RES(res);
371         return res;
372
373 out_done:
374         res = SCST_EXEC_COMPLETED;
375         cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
376         goto out;
377 }
378
379 MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
380 MODULE_LICENSE("GPL");
381 MODULE_DESCRIPTION("SCSI disk (type 0) dev handler for SCST");
382 MODULE_VERSION(SCST_VERSION_STRING);