2 Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * would be nice if this could grow into a full blown library for scsi to
20 * 2, check how big a complete data-in structure needs to be
21 * 3, unmarshall data-in into a real structure
22 * 4, marshall a real structure into a data-out blob
31 #include <arpa/inet.h>
32 #include <ccan/compiler/compiler.h>
33 #include "scsi-lowlevel.h"
34 #include "dlinklist.h"
37 void scsi_free_scsi_task(struct scsi_task *task)
39 struct scsi_allocated_memory *mem;
41 while((mem = task->mem)) {
42 DLIST_REMOVE(task->mem, mem);
48 static void *scsi_malloc(struct scsi_task *task, size_t size)
50 struct scsi_allocated_memory *mem;
52 mem = malloc(sizeof(struct scsi_allocated_memory));
54 printf("Failed to allocate memory to scsi task\n");
57 bzero(mem, sizeof(struct scsi_allocated_memory));
58 mem->ptr = malloc(size);
59 if (mem->ptr == NULL) {
60 printf("Failed to allocate memory buffer for scsi task\n");
64 bzero(mem->ptr, size);
65 DLIST_ADD(task->mem, mem);
72 struct scsi_task *scsi_cdb_testunitready(void)
74 struct scsi_task *task;
76 task = malloc(sizeof(struct scsi_task));
78 printf("Failed to allocate scsi task structure\n");
82 bzero(task, sizeof(struct scsi_task));
83 task->cdb[0] = SCSI_OPCODE_TESTUNITREADY;
86 task->xfer_dir = SCSI_XFER_NONE;
96 struct scsi_task *scsi_reportluns_cdb(int report_type, int alloc_len)
98 struct scsi_task *task;
100 task = malloc(sizeof(struct scsi_task));
102 printf("Failed to allocate scsi task structure\n");
106 bzero(task, sizeof(struct scsi_task));
107 task->cdb[0] = SCSI_OPCODE_REPORTLUNS;
108 task->cdb[2] = report_type;
109 *(uint32_t *)&task->cdb[6] = htonl(alloc_len);
112 task->xfer_dir = SCSI_XFER_READ;
113 task->expxferlen = alloc_len;
115 task->params.reportluns.report_type = report_type;
121 * parse the data in blob and calcualte the size of a full report luns datain structure
123 static int scsi_reportluns_datain_getfullsize(struct scsi_task *task)
127 list_size = htonl(*(uint32_t *)&(task->datain.data[0])) + 8;
133 * unmarshall the data in blob for reportluns into a structure
135 static struct scsi_reportluns_list *scsi_reportluns_datain_unmarshall(struct scsi_task *task)
137 struct scsi_reportluns_list *list;
141 if (task->datain.size < 4) {
142 printf("not enough data for reportluns list length\n");
146 list_size = htonl(*(uint32_t *)&(task->datain.data[0])) + 8;
147 if (list_size < task->datain.size) {
148 printf("not enough data to unmarshall reportluns data\n");
152 num_luns = list_size / 8 - 1;
153 list = scsi_malloc(task, offsetof(struct scsi_reportluns_list, luns) + sizeof(uint16_t) * num_luns);
155 printf("Failed to allocate reportluns structure\n");
159 list->num = num_luns;
160 for (i=0; i<num_luns; i++) {
161 list->luns[i] = htons(*(uint16_t *)&(task->datain.data[i*8+8]));
171 struct scsi_task *scsi_cdb_readcapacity10(int lba, int pmi)
173 struct scsi_task *task;
175 task = malloc(sizeof(struct scsi_task));
177 printf("Failed to allocate scsi task structure\n");
181 bzero(task, sizeof(struct scsi_task));
182 task->cdb[0] = SCSI_OPCODE_READCAPACITY10;
184 *(uint32_t *)&task->cdb[2] = htonl(lba);
187 task->cdb[8] |= 0x01;
191 task->xfer_dir = SCSI_XFER_READ;
192 task->expxferlen = 8;
194 task->params.readcapacity10.lba = lba;
195 task->params.readcapacity10.pmi = pmi;
201 * parse the data in blob and calcualte the size of a full readcapacity10 datain structure
203 static int scsi_readcapacity10_datain_getfullsize(struct scsi_task *task
210 * unmarshall the data in blob for readcapacity10 into a structure
212 static struct scsi_readcapacity10 *scsi_readcapacity10_datain_unmarshall(struct scsi_task *task)
214 struct scsi_readcapacity10 *rc10;
216 if (task->datain.size < 8) {
217 printf("Not enough data to unmarshall readcapacity10\n");
220 rc10 = malloc(sizeof(struct scsi_readcapacity10));
222 printf("Failed to allocate readcapacity10 structure\n");
226 rc10->lba = htonl(*(uint32_t *)&(task->datain.data[0]));
227 rc10->block_size = htonl(*(uint32_t *)&(task->datain.data[4]));
239 struct scsi_task *scsi_cdb_inquiry(int evpd, int page_code, int alloc_len)
241 struct scsi_task *task;
243 task = malloc(sizeof(struct scsi_task));
245 printf("Failed to allocate scsi task structure\n");
249 bzero(task, sizeof(struct scsi_task));
250 task->cdb[0] = SCSI_OPCODE_INQUIRY;
253 task->cdb[1] |= 0x01;
256 task->cdb[2] = page_code;
258 *(uint16_t *)&task->cdb[3] = htons(alloc_len);
261 task->xfer_dir = SCSI_XFER_READ;
262 task->expxferlen = alloc_len;
264 task->params.inquiry.evpd = evpd;
265 task->params.inquiry.page_code = page_code;
271 * parse the data in blob and calcualte the size of a full inquiry datain structure
273 static int scsi_inquiry_datain_getfullsize(struct scsi_task *task)
275 if (task->params.inquiry.evpd != 0) {
276 printf("Can not handle extended inquiry yet\n");
280 /* standard inquiry*/
281 return task->datain.data[4] + 3;
285 * unmarshall the data in blob for inquiry into a structure
287 static void *scsi_inquiry_datain_unmarshall(struct scsi_task *task)
289 struct scsi_inquiry_standard *inq;
291 if (task->params.inquiry.evpd != 0) {
292 printf("Can not handle extended inquiry yet\n");
296 /* standard inquiry */
297 inq = scsi_malloc(task, sizeof(struct scsi_inquiry_standard));
299 printf("Failed to allocate standard inquiry structure\n");
303 inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07;
304 inq->periperal_device_type = task->datain.data[0]&0x1f;
305 inq->rmb = task->datain.data[1]&0x80;
306 inq->version = task->datain.data[2];
307 inq->normaca = task->datain.data[3]&0x20;
308 inq->hisup = task->datain.data[3]&0x10;
309 inq->response_data_format = task->datain.data[3]&0x0f;
311 memcpy(&inq->vendor_identification[0], &task->datain.data[8], 8);
312 memcpy(&inq->product_identification[0], &task->datain.data[16], 16);
313 memcpy(&inq->product_revision_level[0], &task->datain.data[32], 4);
321 struct scsi_task *scsi_cdb_read10(int lba, int xferlen, int blocksize)
323 struct scsi_task *task;
325 task = malloc(sizeof(struct scsi_task));
327 printf("Failed to allocate scsi task structure\n");
331 bzero(task, sizeof(struct scsi_task));
332 task->cdb[0] = SCSI_OPCODE_READ10;
334 *(uint32_t *)&task->cdb[2] = htonl(lba);
335 *(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize);
338 task->xfer_dir = SCSI_XFER_READ;
339 task->expxferlen = xferlen;
347 struct scsi_task *scsi_cdb_write10(int lba, int xferlen, int fua, int fuanv, int blocksize)
349 struct scsi_task *task;
351 task = malloc(sizeof(struct scsi_task));
353 printf("Failed to allocate scsi task structure\n");
357 bzero(task, sizeof(struct scsi_task));
358 task->cdb[0] = SCSI_OPCODE_WRITE10;
361 task->cdb[1] |= 0x08;
364 task->cdb[1] |= 0x02;
367 *(uint32_t *)&task->cdb[2] = htonl(lba);
368 *(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize);
371 task->xfer_dir = SCSI_XFER_WRITE;
372 task->expxferlen = xferlen;
382 struct scsi_task *scsi_cdb_modesense6(int dbd, enum scsi_modesense_page_control pc, enum scsi_modesense_page_code page_code, int sub_page_code, unsigned char alloc_len)
384 struct scsi_task *task;
386 task = malloc(sizeof(struct scsi_task));
388 printf("Failed to allocate scsi task structure\n");
392 bzero(task, sizeof(struct scsi_task));
393 task->cdb[0] = SCSI_OPCODE_MODESENSE6;
396 task->cdb[1] |= 0x08;
398 task->cdb[2] = pc<<6 | page_code;
399 task->cdb[3] = sub_page_code;
400 task->cdb[4] = alloc_len;
403 task->xfer_dir = SCSI_XFER_READ;
404 task->expxferlen = alloc_len;
406 task->params.modesense6.dbd = dbd;
407 task->params.modesense6.pc = pc;
408 task->params.modesense6.page_code = page_code;
409 task->params.modesense6.sub_page_code = sub_page_code;
415 * parse the data in blob and calcualte the size of a full report luns datain structure
417 static int scsi_modesense6_datain_getfullsize(struct scsi_task *task)
421 len = task->datain.data[0] + 1;
428 int scsi_datain_getfullsize(struct scsi_task *task)
430 switch (task->cdb[0]) {
431 case SCSI_OPCODE_TESTUNITREADY:
433 case SCSI_OPCODE_INQUIRY:
434 return scsi_inquiry_datain_getfullsize(task);
435 case SCSI_OPCODE_MODESENSE6:
436 return scsi_modesense6_datain_getfullsize(task);
437 case SCSI_OPCODE_READCAPACITY10:
438 return scsi_readcapacity10_datain_getfullsize(task);
439 // case SCSI_OPCODE_READ10:
440 // case SCSI_OPCODE_WRITE10:
441 case SCSI_OPCODE_REPORTLUNS:
442 return scsi_reportluns_datain_getfullsize(task);
444 printf("Unknown opcode:%d for datain get full size\n", task->cdb[0]);
448 void *scsi_datain_unmarshall(struct scsi_task *task)
450 switch (task->cdb[0]) {
451 case SCSI_OPCODE_TESTUNITREADY:
453 case SCSI_OPCODE_INQUIRY:
454 return scsi_inquiry_datain_unmarshall(task);
455 case SCSI_OPCODE_READCAPACITY10:
456 return scsi_readcapacity10_datain_unmarshall(task);
457 // case SCSI_OPCODE_READ10:
458 // case SCSI_OPCODE_WRITE10:
459 case SCSI_OPCODE_REPORTLUNS:
460 return scsi_reportluns_datain_unmarshall(task);
462 printf("Unknown opcode:%d for datain unmarshall\n", task->cdb[0]);