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 "scsi-lowlevel.h"
33 #include "dlinklist.h"
36 void scsi_free_scsi_task(struct scsi_task *task)
38 struct scsi_allocated_memory *mem;
40 while((mem = task->mem)) {
41 DLIST_REMOVE(task->mem, mem);
47 void *scsi_malloc(struct scsi_task *task, size_t size)
49 struct scsi_allocated_memory *mem;
51 mem = malloc(sizeof(struct scsi_allocated_memory));
53 printf("Failed to allocate memory to scsi task\n");
56 bzero(mem, sizeof(struct scsi_allocated_memory));
57 mem->ptr = malloc(size);
58 if (mem->ptr == NULL) {
59 printf("Failed to allocate memory buffer for scsi task\n");
63 bzero(mem->ptr, size);
64 DLIST_ADD(task->mem, mem);
71 struct scsi_task *scsi_cdb_testunitready(void)
73 struct scsi_task *task;
75 task = malloc(sizeof(struct scsi_task));
77 printf("Failed to allocate scsi task structure\n");
81 bzero(task, sizeof(struct scsi_task));
82 task->cdb[0] = SCSI_OPCODE_TESTUNITREADY;
85 task->xfer_dir = SCSI_XFER_NONE;
95 struct scsi_task *scsi_reportluns_cdb(int report_type, int alloc_len)
97 struct scsi_task *task;
99 task = malloc(sizeof(struct scsi_task));
101 printf("Failed to allocate scsi task structure\n");
105 bzero(task, sizeof(struct scsi_task));
106 task->cdb[0] = SCSI_OPCODE_REPORTLUNS;
107 task->cdb[2] = report_type;
108 *(uint32_t *)&task->cdb[6] = htonl(alloc_len);
111 task->xfer_dir = SCSI_XFER_READ;
112 task->expxferlen = alloc_len;
114 task->params.reportluns.report_type = report_type;
120 * parse the data in blob and calcualte the size of a full report luns datain structure
122 static int scsi_reportluns_datain_getfullsize(struct scsi_task *task)
126 list_size = htonl(*(uint32_t *)&(task->datain.data[0])) + 8;
132 * unmarshall the data in blob for reportluns into a structure
134 static struct scsi_reportluns_list *scsi_reportluns_datain_unmarshall(struct scsi_task *task)
136 struct scsi_reportluns_list *list;
140 if (task->datain.size < 4) {
141 printf("not enough data for reportluns list length\n");
145 list_size = htonl(*(uint32_t *)&(task->datain.data[0])) + 8;
146 if (list_size < task->datain.size) {
147 printf("not enough data to unmarshall reportluns data\n");
151 num_luns = list_size / 8 - 1;
152 list = scsi_malloc(task, offsetof(struct scsi_reportluns_list, luns) + sizeof(uint16_t) * num_luns);
154 printf("Failed to allocate reportluns structure\n");
158 list->num = num_luns;
159 for (i=0; i<num_luns; i++) {
160 list->luns[i] = htons(*(uint16_t *)&(task->datain.data[i*8+8]));
170 struct scsi_task *scsi_cdb_readcapacity10(int lba, int pmi)
172 struct scsi_task *task;
174 task = malloc(sizeof(struct scsi_task));
176 printf("Failed to allocate scsi task structure\n");
180 bzero(task, sizeof(struct scsi_task));
181 task->cdb[0] = SCSI_OPCODE_READCAPACITY10;
183 *(uint32_t *)&task->cdb[2] = htonl(lba);
186 task->cdb[8] |= 0x01;
190 task->xfer_dir = SCSI_XFER_READ;
191 task->expxferlen = 8;
193 task->params.readcapacity10.lba = lba;
194 task->params.readcapacity10.pmi = pmi;
200 * parse the data in blob and calcualte the size of a full readcapacity10 datain structure
202 static int scsi_readcapacity10_datain_getfullsize(struct scsi_task *task _U_)
208 * unmarshall the data in blob for readcapacity10 into a structure
210 static struct scsi_readcapacity10 *scsi_readcapacity10_datain_unmarshall(struct scsi_task *task)
212 struct scsi_readcapacity10 *rc10;
214 if (task->datain.size < 8) {
215 printf("Not enough data to unmarshall readcapacity10\n");
218 rc10 = malloc(sizeof(struct scsi_readcapacity10));
220 printf("Failed to allocate readcapacity10 structure\n");
224 rc10->lba = htonl(*(uint32_t *)&(task->datain.data[0]));
225 rc10->block_size = htonl(*(uint32_t *)&(task->datain.data[4]));
237 struct scsi_task *scsi_cdb_inquiry(int evpd, int page_code, int alloc_len)
239 struct scsi_task *task;
241 task = malloc(sizeof(struct scsi_task));
243 printf("Failed to allocate scsi task structure\n");
247 bzero(task, sizeof(struct scsi_task));
248 task->cdb[0] = SCSI_OPCODE_INQUIRY;
251 task->cdb[1] |= 0x01;
254 task->cdb[2] = page_code;
256 *(uint16_t *)&task->cdb[3] = htons(alloc_len);
259 task->xfer_dir = SCSI_XFER_READ;
260 task->expxferlen = alloc_len;
262 task->params.inquiry.evpd = evpd;
263 task->params.inquiry.page_code = page_code;
269 * parse the data in blob and calcualte the size of a full inquiry datain structure
271 static int scsi_inquiry_datain_getfullsize(struct scsi_task *task)
273 if (task->params.inquiry.evpd != 0) {
274 printf("Can not handle extended inquiry yet\n");
278 /* standard inquiry*/
279 return task->datain.data[4] + 3;
283 * unmarshall the data in blob for inquiry into a structure
285 void *scsi_inquiry_datain_unmarshall(struct scsi_task *task)
287 struct scsi_inquiry_standard *inq;
289 if (task->params.inquiry.evpd != 0) {
290 printf("Can not handle extended inquiry yet\n");
294 /* standard inquiry */
295 inq = scsi_malloc(task, sizeof(struct scsi_inquiry_standard));
297 printf("Failed to allocate standard inquiry structure\n");
301 inq->periperal_qualifier = (task->datain.data[0]>>5)&0x07;
302 inq->periperal_device_type = task->datain.data[0]&0x1f;
303 inq->rmb = task->datain.data[1]&0x80;
304 inq->version = task->datain.data[2];
305 inq->normaca = task->datain.data[3]&0x20;
306 inq->hisup = task->datain.data[3]&0x10;
307 inq->response_data_format = task->datain.data[3]&0x0f;
309 memcpy(&inq->vendor_identification[0], &task->datain.data[8], 8);
310 memcpy(&inq->product_identification[0], &task->datain.data[16], 16);
311 memcpy(&inq->product_revision_level[0], &task->datain.data[32], 4);
319 struct scsi_task *scsi_cdb_read10(int lba, int xferlen, int blocksize)
321 struct scsi_task *task;
323 task = malloc(sizeof(struct scsi_task));
325 printf("Failed to allocate scsi task structure\n");
329 bzero(task, sizeof(struct scsi_task));
330 task->cdb[0] = SCSI_OPCODE_READ10;
332 *(uint32_t *)&task->cdb[2] = htonl(lba);
333 *(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize);
336 task->xfer_dir = SCSI_XFER_READ;
337 task->expxferlen = xferlen;
345 struct scsi_task *scsi_cdb_write10(int lba, int xferlen, int fua, int fuanv, int blocksize)
347 struct scsi_task *task;
349 task = malloc(sizeof(struct scsi_task));
351 printf("Failed to allocate scsi task structure\n");
355 bzero(task, sizeof(struct scsi_task));
356 task->cdb[0] = SCSI_OPCODE_WRITE10;
359 task->cdb[1] |= 0x08;
362 task->cdb[1] |= 0x02;
365 *(uint32_t *)&task->cdb[2] = htonl(lba);
366 *(uint16_t *)&task->cdb[7] = htons(xferlen/blocksize);
369 task->xfer_dir = SCSI_XFER_WRITE;
370 task->expxferlen = xferlen;
380 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)
382 struct scsi_task *task;
384 task = malloc(sizeof(struct scsi_task));
386 printf("Failed to allocate scsi task structure\n");
390 bzero(task, sizeof(struct scsi_task));
391 task->cdb[0] = SCSI_OPCODE_MODESENSE6;
394 task->cdb[1] |= 0x08;
396 task->cdb[2] = pc<<6 | page_code;
397 task->cdb[3] = sub_page_code;
398 task->cdb[4] = alloc_len;
401 task->xfer_dir = SCSI_XFER_READ;
402 task->expxferlen = alloc_len;
404 task->params.modesense6.dbd = dbd;
405 task->params.modesense6.pc = pc;
406 task->params.modesense6.page_code = page_code;
407 task->params.modesense6.sub_page_code = sub_page_code;
413 * parse the data in blob and calcualte the size of a full report luns datain structure
415 static int scsi_modesense6_datain_getfullsize(struct scsi_task *task)
419 len = task->datain.data[0] + 1;
426 int scsi_datain_getfullsize(struct scsi_task *task)
428 switch (task->cdb[0]) {
429 case SCSI_OPCODE_TESTUNITREADY:
431 case SCSI_OPCODE_INQUIRY:
432 return scsi_inquiry_datain_getfullsize(task);
433 case SCSI_OPCODE_MODESENSE6:
434 return scsi_modesense6_datain_getfullsize(task);
435 case SCSI_OPCODE_READCAPACITY10:
436 return scsi_readcapacity10_datain_getfullsize(task);
437 // case SCSI_OPCODE_READ10:
438 // case SCSI_OPCODE_WRITE10:
439 case SCSI_OPCODE_REPORTLUNS:
440 return scsi_reportluns_datain_getfullsize(task);
442 printf("Unknown opcode:%d for datain get full size\n", task->cdb[0]);
446 void *scsi_datain_unmarshall(struct scsi_task *task)
448 switch (task->cdb[0]) {
449 case SCSI_OPCODE_TESTUNITREADY:
451 case SCSI_OPCODE_INQUIRY:
452 return scsi_inquiry_datain_unmarshall(task);
453 case SCSI_OPCODE_READCAPACITY10:
454 return scsi_readcapacity10_datain_unmarshall(task);
455 // case SCSI_OPCODE_READ10:
456 // case SCSI_OPCODE_WRITE10:
457 case SCSI_OPCODE_REPORTLUNS:
458 return scsi_reportluns_datain_unmarshall(task);
460 printf("Unknown opcode:%d for datain unmarshall\n", task->cdb[0]);