Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F110658790
D7373.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D7373.diff
View Options
Index: usr.sbin/camdd/camdd.c
===================================================================
--- usr.sbin/camdd/camdd.c
+++ usr.sbin/camdd/camdd.c
@@ -84,6 +84,8 @@
#include <camlib.h>
#include <mtlib.h>
#include <zlib.h>
+#include <cam/ata/ata_all.h>
+#include <cam/cam_ccb.h>
typedef enum {
CAMDD_CMD_NONE = 0x00000000,
@@ -105,6 +107,25 @@
CAMDD_ARG_RETRIES = 0x00000100
} camdd_argmask;
+
+typedef enum {
+ ADA_FLAG_CAN_48BIT = 0x0002,
+ ADA_FLAG_CAN_FLUSHCACHE = 0x0004,
+ ADA_FLAG_CAN_NCQ = 0x0008,
+ ADA_FLAG_CAN_DMA = 0x0010,
+ ADA_FLAG_NEED_OTAG = 0x0020,
+ ADA_FLAG_WAS_OTAG = 0x0040,
+ ADA_FLAG_CAN_TRIM = 0x0080,
+ ADA_FLAG_OPEN = 0x0100,
+ ADA_FLAG_SCTX_INIT = 0x0200,
+ ADA_FLAG_CAN_CFA = 0x0400,
+ ADA_FLAG_CAN_POWERMGT = 0x0800,
+ ADA_FLAG_CAN_DMA48 = 0x1000,
+ ADA_FLAG_DIRTY = 0x2000,
+ ADA_FLAG_CAN_NCQ_TRIM = 0x4000, /* CAN_TRIM also set */
+ ADA_FLAG_PIM_CAN_NCQ_TRIM = 0x8000
+} ada_flags;
+
typedef enum {
CAMDD_DEV_NONE = 0x00,
CAMDD_DEV_PASS = 0x01,
@@ -259,7 +280,9 @@
#define NUM_DEV_TYPES 2
struct camdd_dev_pass {
- int scsi_dev_type;
+ int scsi_dev_type;
+ int protocol;
+ ada_flags ada_flags;
struct cam_device *dev;
uint64_t max_sector;
uint32_t block_len;
@@ -467,7 +490,7 @@
struct kevent *new_ke, int num_ke,
int retry_count, int timeout);
static struct camdd_buf *camdd_alloc_buf(struct camdd_dev *dev,
- camdd_buf_type buf_type);
+ camdd_buf_type buf_type);
void camdd_release_buf(struct camdd_buf *buf);
struct camdd_buf *camdd_get_buf(struct camdd_dev *dev, camdd_buf_type buf_type);
int camdd_buf_sg_create(struct camdd_buf *buf, int iovec,
@@ -477,6 +500,20 @@
void camdd_buf_add_child(struct camdd_buf *buf, struct camdd_buf *child_buf);
int camdd_probe_tape(int fd, char *filename, uint64_t *max_iosize,
uint64_t *max_blk, uint64_t *min_blk, uint64_t *blk_gran);
+uint64_t max_sector(int is48bit, struct ata_params *parm);
+int camdd_probe_pass_scsi(struct cam_device *cam_dev, union ccb *ccb,
+ int probe_retry_count, camdd_argmask arglist,
+ int probe_timeout, uint64_t *maxsector, uint32_t *block_len);
+int camdd_probe_pass_ata(struct cam_device *cam_dev, union ccb *ccb,
+ camdd_argmask arglist, int probe_retry_count,
+ int probe_timeout, uint8_t command, ada_flags ada_flags,
+ uint64_t *maxsector, uint32_t *block_len);
+void set_flags(ada_flags *flags, struct ccb_getdev *cgd);
+int ata_do_cmd(union ccb *ccb, int retries,
+ u_int32_t flags, u_int8_t tag_action,
+ u_int8_t command, u_int8_t features, u_int32_t lba,
+ u_int16_t sector_count, u_int8_t *data_ptr, size_t dxfer_len,
+ int timeout, ada_flags ada_flags);
struct camdd_dev *camdd_probe_file(int fd, struct camdd_io_opts *io_opts,
int retry_count, int timeout);
struct camdd_dev *camdd_probe_pass(struct cam_device *cam_dev,
@@ -485,7 +522,8 @@
int probe_timeout, int io_retry_count,
int io_timeout);
void *camdd_file_worker(void *arg);
-camdd_buf_status camdd_ccb_status(union ccb *ccb);
+camdd_buf_status camdd_ccb_status(union ccb *ccb, int protocol);
+int get_cgd(struct cam_device *device, struct ccb_getdev *cgd);
int camdd_queue_peer_buf(struct camdd_dev *dev, struct camdd_buf *buf);
int camdd_complete_peer_buf(struct camdd_dev *dev, struct camdd_buf *peer_buf);
void camdd_peer_done(struct camdd_buf *buf);
@@ -1252,59 +1290,125 @@
return (NULL);
}
+
/*
- * Need to implement this. Do a basic probe:
- * - Check the inquiry data, make sure we're talking to a device that we
- * can reasonably expect to talk to -- direct, RBC, CD, WORM.
- * - Send a test unit ready, make sure the device is available.
- * - Get the capacity and block size.
- */
-struct camdd_dev *
-camdd_probe_pass(struct cam_device *cam_dev, struct camdd_io_opts *io_opts,
- camdd_argmask arglist, int probe_retry_count,
- int probe_timeout, int io_retry_count, int io_timeout)
+ * * Get a get device CCB for the specified device.
+ * */
+int
+get_cgd(struct cam_device *device, struct ccb_getdev *cgd)
{
union ccb *ccb;
- uint64_t maxsector;
- uint32_t cpi_maxio, max_iosize, pass_numblocks;
- uint32_t block_len;
- struct scsi_read_capacity_data rcap;
- struct scsi_read_capacity_data_long rcaplong;
- struct camdd_dev *dev;
- struct camdd_dev_pass *pass_dev;
- struct kevent ke;
- int scsi_dev_type;
+ int retval = 0;
- dev = NULL;
+ ccb = cam_getccb(device);
- scsi_dev_type = SID_TYPE(&cam_dev->inq_data);
- maxsector = 0;
- block_len = 0;
+ if (ccb == NULL) {
+ warnx("get_cgd: couldn't allocate CCB");
+ return 1;
+ }
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_pathinq) - sizeof(struct ccb_hdr));
+ ccb->ccb_h.func_code = XPT_GDEV_TYPE;
- /*
- * For devices that support READ CAPACITY, we'll attempt to get the
- * capacity. Otherwise, we really don't support tape or other
- * devices via SCSI passthrough, so just return an error in that case.
- */
- switch (scsi_dev_type) {
- case T_DIRECT:
- case T_WORM:
- case T_CDROM:
- case T_OPTICAL:
- case T_RBC:
- case T_ZBC_HM:
- break;
- default:
- errx(1, "Unsupported SCSI device type %d", scsi_dev_type);
- break; /*NOTREACHED*/
+ if (cam_send_ccb(device, ccb) < 0) {
+ warn("get_cgd: error sending Path Inquiry CCB");
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ retval = 1;
+ goto get_cgd_bailout;
}
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ retval = 1;
+ goto get_cgd_bailout;
+ }
+ bcopy(&ccb->cgd, cgd, sizeof(struct ccb_getdev));
+get_cgd_bailout:
- ccb = cam_getccb(cam_dev);
+ cam_freeccb(ccb);
- if (ccb == NULL) {
- warnx("%s: error allocating ccb", __func__);
- goto bailout;
+ return retval;
+}
+
+void
+set_flags(ada_flags *flags, struct ccb_getdev *cgd)
+{
+ if ((cgd->ident_data.capabilities1 & ATA_SUPPORT_DMA) &&
+ (cgd->inq_flags & SID_DMA))
+ *flags |= ADA_FLAG_CAN_DMA;
+ else
+ *flags &= ~ADA_FLAG_CAN_DMA;
+
+ if (cgd->ident_data.support.command2 & ATA_SUPPORT_ADDRESS48) {
+ *flags |= ADA_FLAG_CAN_48BIT;
+ if (cgd->inq_flags & SID_DMA48)
+ *flags |= ADA_FLAG_CAN_DMA48;
+ else
+ *flags &= ~ADA_FLAG_CAN_DMA48;
+ } else
+ *flags &= ~(ADA_FLAG_CAN_48BIT | ADA_FLAG_CAN_DMA48);
+
+ if ((cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ) &&
+ (cgd->inq_flags & SID_DMA) && (cgd->inq_flags & SID_CmdQue))
+ *flags |= ADA_FLAG_CAN_NCQ;
+ else
+ *flags &= ~ADA_FLAG_CAN_NCQ;
+}
+
+int
+ata_do_cmd(union ccb *ccb, int retries,
+ u_int32_t flags, u_int8_t tag_action,
+ u_int8_t command, u_int8_t features, u_int32_t lba,
+ u_int16_t sector_count, u_int8_t *data_ptr, size_t dxfer_len,
+ int timeout, ada_flags ada_flags)
+{
+
+ cam_fill_ataio(&ccb->ataio,
+ /*retries*/ retries,
+ /*cbfcnp*/ NULL,
+ /*flags*/ flags,
+ /*tag_action*/ tag_action,
+ /*data_ptr*/ data_ptr,
+ /*dxfer_len*/ dxfer_len,
+ /*timeout*/ timeout);
+
+ if (ada_flags & ADA_FLAG_CAN_48BIT && lba + sector_count >= ATA_MAX_28BIT_LBA) {
+ ata_48bit_cmd(&ccb->ataio, command, features, lba,
+ sector_count);
+
+ }
+ else if (ada_flags & ATA_SUPPORT_NCQ) {
+ ata_ncq_cmd(&ccb->ataio, command, lba,
+ sector_count);
}
+ else {
+ ata_28bit_cmd(&ccb->ataio, command, features, lba,
+ sector_count);
+ }
+ return 0;
+}
+
+uint64_t
+max_sector(int is48bit, struct ata_params *parm)
+{
+ if (is48bit)
+ return ((u_int64_t)parm->lba_size48_1 |
+ ((u_int64_t)parm->lba_size48_2 << 16) |
+ ((u_int64_t)parm->lba_size48_3 << 32) |
+ ((u_int64_t)parm->lba_size48_4 << 48));
+ else
+ return ((u_int32_t)parm->lba_size_1 |
+ ((u_int32_t)parm->lba_size_2 << 16));
+}
+
+int
+camdd_probe_pass_scsi(struct cam_device *cam_dev, union ccb *ccb, int probe_retry_count,
+ camdd_argmask arglist, int probe_timeout,
+ uint64_t *maxsector, uint32_t *block_len)
+{
+ struct scsi_read_capacity_data rcap;
+ struct scsi_read_capacity_data_long rcaplong;
CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
@@ -1327,7 +1431,6 @@
cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
-
goto bailout;
}
@@ -1336,28 +1439,28 @@
goto bailout;
}
- maxsector = scsi_4btoul(rcap.addr);
- block_len = scsi_4btoul(rcap.length);
+ *maxsector = scsi_4btoul(rcap.addr);
+ *block_len = scsi_4btoul(rcap.length);
/*
* A last block of 2^32-1 means that the true capacity is over 2TB,
* and we need to issue the long READ CAPACITY to get the real
* capacity. Otherwise, we're all set.
*/
- if (maxsector != 0xffffffff)
- goto rcap_done;
+ if (*maxsector != 0xffffffff)
+ return 0;
scsi_read_capacity_16(&ccb->csio,
- /*retries*/ probe_retry_count,
- /*cbfcnp*/ NULL,
- /*tag_action*/ MSG_SIMPLE_Q_TAG,
- /*lba*/ 0,
- /*reladdr*/ 0,
- /*pmi*/ 0,
- (uint8_t *)&rcaplong,
- sizeof(rcaplong),
- /*sense_len*/ SSD_FULL_SIZE,
- /*timeout*/ probe_timeout ? probe_timeout : 5000);
+ /*retries*/ probe_retry_count,
+ /*cbfcnp*/ NULL,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*lba*/ 0,
+ /*reladdr*/ 0,
+ /*pmi*/ 0,
+ (uint8_t *)&rcaplong,
+ sizeof(rcaplong),
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ probe_timeout ? probe_timeout : 5000);
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
@@ -1377,14 +1480,156 @@
goto bailout;
}
- maxsector = scsi_8btou64(rcaplong.addr);
- block_len = scsi_4btoul(rcaplong.length);
+ *maxsector = scsi_8btou64(rcaplong.addr);
+ *block_len = scsi_4btoul(rcaplong.length);
+ return 0;
+bailout:
+ return -1;
+}
+
+int
+camdd_probe_pass_ata(struct cam_device *cam_dev, union ccb *ccb,
+ camdd_argmask arglist, int probe_retry_count,
+ int probe_timeout, uint8_t command, ada_flags ada_flags,
+ uint64_t *maxsector, uint32_t *block_len)
+{
+ int16_t *ptr = NULL;
+ size_t dxfer_len = 0;
+ int retval;
+ struct ata_params *parm;
+
+ dxfer_len = sizeof(struct ata_params);
+ ptr = (uint16_t *)malloc(dxfer_len);
+ if (ptr == NULL) {
+ warnx("can't malloc memory for identify");
+ retval = -1;
+ goto bailout;
+ }
+ bzero(ptr, dxfer_len);
+
+ /* Use the ATA CMDS directly instead of ATA_SCSI Passthrough.*/
+ bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) -
+ sizeof(struct ccb_hdr));
+ ata_do_cmd(ccb,
+ /*retries*/probe_retry_count,
+ /*flags*/CAM_DIR_IN,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/command,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/sizeof(struct ata_params),
+ /*data_ptr*/(u_int8_t *)ptr,
+ /*dxfer_len*/dxfer_len,
+ /*timeout*/probe_timeout ? probe_timeout : 5000,
+ /*ada_flags*/ada_flags);
+
+ if (arglist & CAMDD_ARG_ERR_RECOVER)
+ ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+ retval = cam_send_ccb(cam_dev, ccb);
+
+ if (retval != 0) {
+ warn("error sending ATA_IDENTIFY CCB");
+ retval = -1;
+ goto bailout;
+ }
+
+ parm = (struct ata_params *)(ptr);
+ *block_len = (unsigned long)ata_physical_sector_size(parm);
+ *maxsector = max_sector(ada_flags & ADA_FLAG_CAN_48BIT, parm);
+ retval = 0;
+bailout:
+ return retval;
+}
+
+
+/*
+ * Need to implement this. Do a basic probe:
+ * - Check the inquiry data, make sure we're talking to a device that we
+ * can reasonably expect to talk to -- direct, RBC, CD, WORM.
+ * - Send a test unit ready, make sure the device is available.
+ * - Get the capacity and block size.
+ */
+struct camdd_dev *
+camdd_probe_pass(struct cam_device *cam_dev, struct camdd_io_opts *io_opts,
+ camdd_argmask arglist, int probe_retry_count,
+ int probe_timeout, int io_retry_count, int io_timeout)
+{
+ union ccb *ccb;
+ uint64_t maxsector = 0;
+ uint32_t cpi_maxio, max_iosize, pass_numblocks;
+ uint32_t block_len = 0;
+ struct camdd_dev *dev = NULL;
+ struct camdd_dev_pass *pass_dev;
+ struct kevent ke;
+ struct ccb_getdev cgd;
+ int retval;
+ ada_flags ada_flags = 0;
+ uint8_t command;
+ int scsi_dev_type;
+
+ if ((retval = get_cgd(cam_dev, &cgd)) != 0) {
+ warnx("couldn't get CGD");
+ return (NULL);
+ }
+
+ if ((ccb = cam_getccb(cam_dev)) == NULL) {
+ warnx("Could not allocate CCB");
+ retval = -1;
+ goto bailout_error;
+ }
+
+ switch(cgd.protocol) {
+ case PROTO_SCSI:
+ scsi_dev_type = SID_TYPE(&cam_dev->inq_data);
+
+ /*
+ * For devices that support READ CAPACITY, we'll attempt to get the
+ * capacity. Otherwise, we really don't support tape or other
+ * devices via SCSI passthrough, so just return an error in that case.
+ */
+ switch (scsi_dev_type) {
+ case T_DIRECT:
+ case T_WORM:
+ case T_CDROM:
+ case T_OPTICAL:
+ case T_RBC:
+ break;
+
+ default:
+ errx(1, "Unsupported SCSI device type %d", scsi_dev_type);
+ break; /*NOTREACHED*/
+ } /*SWitch scsi_dev_type*/
+
+
+ if ((retval = camdd_probe_pass_scsi(cam_dev, ccb, probe_retry_count,
+ arglist, probe_timeout, &maxsector, &block_len))) {
+ goto bailout;
+ }
+ break;
+ case PROTO_ATA:
+ case PROTO_ATAPI:
+
+ command = (cgd.protocol == PROTO_ATA) ?
+ ATA_ATA_IDENTIFY : ATA_ATAPI_IDENTIFY;
+
+ set_flags(&ada_flags, &cgd);
+
+ if ((retval = camdd_probe_pass_ata(cam_dev, ccb, arglist, probe_retry_count,
+ probe_timeout, command, ada_flags, &maxsector, &block_len))) {
+ goto bailout;
+ }
+ break; /* switch ATA */
+ default:
+ errx(1, "Unsupported PROTO type %d", cgd.protocol);
+ break; /*NOTREACHED*/
+ } /*switch cgd.protocol */
-rcap_done:
if (block_len == 0) {
warnx("Sector size for %s%u is 0, cannot continue",
- cam_dev->device_name, cam_dev->dev_unit_num);
- goto bailout_error;
+ cam_dev->device_name, cam_dev->dev_unit_num);
+ goto bailout;
}
CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cpi);
@@ -1392,7 +1637,7 @@
ccb->ccb_h.func_code = XPT_PATH_INQ;
ccb->ccb_h.flags = CAM_DIR_NONE;
ccb->ccb_h.retry_count = 1;
-
+
if (cam_send_ccb(cam_dev, ccb) < 0) {
warn("error sending XPT_PATH_INQ CCB");
@@ -1410,12 +1655,14 @@
pass_dev = &dev->dev_spec.pass;
pass_dev->scsi_dev_type = scsi_dev_type;
+ pass_dev->protocol = cgd.protocol;
+ pass_dev->ada_flags = ada_flags;
pass_dev->dev = cam_dev;
pass_dev->max_sector = maxsector;
pass_dev->block_len = block_len;
pass_dev->cpi_maxio = ccb->cpi.maxio;
snprintf(dev->device_name, sizeof(dev->device_name), "%s%u",
- pass_dev->dev->device_name, pass_dev->dev->dev_unit_num);
+ pass_dev->dev->device_name, pass_dev->dev->dev_unit_num);
dev->sector_size = block_len;
dev->max_sector = maxsector;
@@ -1720,46 +1967,68 @@
* Simplistic translation of CCB status to our local status.
*/
camdd_buf_status
-camdd_ccb_status(union ccb *ccb)
+camdd_ccb_status(union ccb *ccb, int protocol)
{
camdd_buf_status status = CAMDD_STATUS_NONE;
cam_status ccb_status;
ccb_status = ccb->ccb_h.status & CAM_STATUS_MASK;
- switch (ccb_status) {
- case CAM_REQ_CMP: {
- if (ccb->csio.resid == 0) {
- status = CAMDD_STATUS_OK;
- } else if (ccb->csio.dxfer_len > ccb->csio.resid) {
- status = CAMDD_STATUS_SHORT_IO;
- } else {
- status = CAMDD_STATUS_EOF;
+ if (protocol == PROTO_SCSI) {
+ switch (ccb_status) {
+ case CAM_REQ_CMP: {
+
+ if (ccb->csio.resid == 0) {
+ status = CAMDD_STATUS_OK;
+ } else if (ccb->csio.dxfer_len > ccb->csio.resid) {
+ status = CAMDD_STATUS_SHORT_IO;
+ } else {
+ status = CAMDD_STATUS_EOF;
+ }
+ break;
+ }
+ case CAM_SCSI_STATUS_ERROR: {
+ switch (ccb->csio.scsi_status) {
+ case SCSI_STATUS_OK:
+ case SCSI_STATUS_COND_MET:
+ case SCSI_STATUS_INTERMED:
+ case SCSI_STATUS_INTERMED_COND_MET:
+ status = CAMDD_STATUS_OK;
+ break;
+ case SCSI_STATUS_CMD_TERMINATED:
+ case SCSI_STATUS_CHECK_COND:
+ case SCSI_STATUS_QUEUE_FULL:
+ case SCSI_STATUS_BUSY:
+ case SCSI_STATUS_RESERV_CONFLICT:
+ default:
+ status = CAMDD_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ default:
+ status = CAMDD_STATUS_ERROR;
+ break;
}
- break;
}
- case CAM_SCSI_STATUS_ERROR: {
- switch (ccb->csio.scsi_status) {
- case SCSI_STATUS_OK:
- case SCSI_STATUS_COND_MET:
- case SCSI_STATUS_INTERMED:
- case SCSI_STATUS_INTERMED_COND_MET:
- status = CAMDD_STATUS_OK;
- break;
- case SCSI_STATUS_CMD_TERMINATED:
- case SCSI_STATUS_CHECK_COND:
- case SCSI_STATUS_QUEUE_FULL:
- case SCSI_STATUS_BUSY:
- case SCSI_STATUS_RESERV_CONFLICT:
- default:
- status = CAMDD_STATUS_ERROR;
- break;
+ else {
+
+ switch(ccb_status) {
+ case CAM_REQ_CMP: {
+
+ if (ccb->ataio.resid == 0) {
+ status = CAMDD_STATUS_OK;
+ } else if (ccb->ataio.dxfer_len > ccb->ataio.resid) {
+ status = CAMDD_STATUS_SHORT_IO;
+ } else {
+ status = CAMDD_STATUS_EOF;
+ }
+ break;
+ }
+ default:
+ status = CAMDD_STATUS_ERROR;
+ break;
}
- break;
- }
- default:
- status = CAMDD_STATUS_ERROR;
- break;
}
return (status);
@@ -2154,11 +2423,17 @@
CAM_EPF_ALL, stderr);
}
- data->resid = ccb.csio.resid;
- dev->bytes_transferred += (ccb.csio.dxfer_len - ccb.csio.resid);
+ if (pass_dev->protocol == PROTO_SCSI) {
+ data->resid = ccb.csio.resid;
+ dev->bytes_transferred += (ccb.csio.dxfer_len - ccb.csio.resid);
+ }
+ else {
+ data->resid = ccb.ataio.resid;
+ dev->bytes_transferred += (ccb.ataio.dxfer_len - ccb.ataio.resid);
+ }
if (buf->status == CAMDD_STATUS_NONE)
- buf->status = camdd_ccb_status(&ccb);
+ buf->status = camdd_ccb_status(&ccb, pass_dev->protocol);
if (buf->status == CAMDD_STATUS_ERROR)
error_count++;
else if (buf->status == CAMDD_STATUS_EOF) {
@@ -2220,7 +2495,7 @@
*/
if (write_dev != 0) {
retval = camdd_buf_sg_create(buf, /*iovec*/ 1,
- dev->sector_size, &num_sectors, &double_buf_needed);
+ dev->sector_size, &num_sectors, &double_buf_needed);
if (retval != 0) {
no_resources = 1;
goto bailout;
@@ -2412,6 +2687,7 @@
union ccb *ccb;
int retval = 0, is_write = dev->write_dev;
int double_buf_needed = 0;
+ uint8_t command;
buf = STAILQ_FIRST(&dev->run_queue);
if (buf == NULL) {
@@ -2438,7 +2714,6 @@
data = &buf->buf_type_spec.data;
ccb = &data->ccb;
- CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
/*
* In almost every case the number of blocks should be the device
@@ -2450,33 +2725,100 @@
else
num_blocks = data->fill_len / pass_dev->block_len;
- scsi_read_write(&ccb->csio,
+ if(data->fill_len == 0 ) {
+ retval = -1;
+ goto bailout;
+ }
+
+ if (pass_dev->protocol == PROTO_SCSI) {
+ CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio);
+
+ scsi_read_write(&ccb->csio,
/*retries*/ dev->retry_count,
/*cbfcnp*/ NULL,
/*tag_action*/ MSG_SIMPLE_Q_TAG,
/*readop*/ (dev->write_dev == 0) ? SCSI_RW_READ :
- SCSI_RW_WRITE,
+ SCSI_RW_WRITE,
/*byte2*/ 0,
/*minimum_cmd_size*/ dev->min_cmd_size,
/*lba*/ buf->lba,
/*block_count*/ num_blocks,
/*data_ptr*/ (data->sg_count != 0) ?
- (uint8_t *)data->segs : data->buf,
+ (uint8_t *)data->segs : data->buf,
/*dxfer_len*/ (num_blocks * pass_dev->block_len),
/*sense_len*/ SSD_FULL_SIZE,
/*timeout*/ dev->io_timeout);
+ if (data->sg_count != 0) {
+ ccb->ccb_h.flags |= CAM_DATA_SG;
+ ccb->csio.sglist_cnt = data->sg_count;
+ }
+ }
+ else {
+
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
+
+ if (pass_dev->ada_flags & ATA_SUPPORT_NCQ) {
+ if (is_write == 0) {
+ command = ATA_READ_FPDMA_QUEUED;
+ } else {
+ command = ATA_WRITE_FPDMA_QUEUED;
+ }
+ } else if ((pass_dev->ada_flags & ADA_FLAG_CAN_48BIT) &&
+ (buf->lba + num_blocks >= ATA_MAX_28BIT_LBA ||
+ num_blocks > 256)) {
+ if (pass_dev->ada_flags & ADA_FLAG_CAN_DMA48) {
+ if (is_write == 0) {
+ command = ATA_READ_DMA48;
+ } else {
+ command = ATA_WRITE_DMA48;
+ }
+ } else {
+ if (is_write == 0) {
+ command = ATA_READ_MUL48;
+ } else {
+ command = ATA_WRITE_MUL48;
+ }
+ }
+ }
+ else {
+ if (pass_dev->ada_flags & ADA_FLAG_CAN_DMA) {
+ if (is_write == 0) {
+ command = ATA_READ_DMA;
+ } else {
+ command = ATA_WRITE_DMA;
+ }
+ } else {
+ if (is_write == 0) {
+ command = ATA_READ_MUL;
+ } else {
+ command = ATA_WRITE_MUL;
+ }
+ }
+ }
+
+ ata_do_cmd(ccb,
+ /*retries*/dev->retry_count,
+ /*flags*/(is_write == 0) ? CAM_DIR_IN : CAM_DIR_OUT,
+ /*tag_action*/CAM_TAG_ACTION_NONE,
+ /*command*/command,
+ /*features*/0,
+ /*lba*/buf->lba,
+ /*sector_count*/num_blocks,
+ /*data_ptr*/(data->sg_count != 0) ?
+ (uint8_t *)data->segs : data->buf,
+ /*dxfer_len*/num_blocks * pass_dev->block_len,
+ /*timeout*/dev->io_timeout,
+ /*adaflags*/pass_dev->ada_flags);
+ }
+
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
if (dev->retry_count != 0)
ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
- if (data->sg_count != 0) {
- ccb->csio.sglist_cnt = data->sg_count;
- ccb->ccb_h.flags |= CAM_DATA_SG;
- }
-
/*
* Store a pointer to the buffer in the CCB. The kernel will
* restore this when we get it back, and we'll use it to identify
@@ -2495,7 +2837,7 @@
pthread_mutex_lock(&dev->mutex);
warn("%s: error sending CAMIOQUEUE ioctl to %s%u", __func__,
- pass_dev->dev->device_name, pass_dev->dev->dev_unit_num);
+ pass_dev->dev->device_name, pass_dev->dev->dev_unit_num);
warn("%s: CCB address is %p", __func__, ccb);
retval = -1;
@@ -3049,12 +3391,12 @@
}
devs[i] = camdd_probe_pass(new_cam_dev,
- /*io_opts*/ &io_opts[i],
- CAMDD_ARG_ERR_RECOVER,
- /*probe_retry_count*/ 3,
- /*probe_timeout*/ 5000,
- /*io_retry_count*/ retry_count,
- /*io_timeout*/ timeout);
+ /*io_opts*/ &io_opts[i],
+ CAMDD_ARG_ERR_RECOVER,
+ /*probe_retry_count*/ 3,
+ /*probe_timeout*/ 5000,
+ /*io_retry_count*/ retry_count,
+ /*io_timeout*/ timeout);
if (devs[i] == NULL) {
warn("Unable to probe device %s%u",
new_cam_dev->device_name,
@@ -3089,7 +3431,7 @@
}
devs[i] = camdd_probe_file(fd, &io_opts[i],
- retry_count, timeout);
+ retry_count, timeout);
if (devs[i] == NULL) {
error = 1;
goto bailout;
@@ -3114,10 +3456,6 @@
(devs[i]->start_offset_bytes /
devs[i]->sector_size) +
(max_io / devs[i]->sector_size) - 1;
- devs[i]->sector_io_limit =
- (devs[i]->start_offset_bytes /
- devs[i]->sector_size) +
- (max_io / devs[i]->sector_size) - 1;
}
devs[i]->next_io_pos_bytes = devs[i]->start_offset_bytes;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Feb 22, 1:49 PM (1 h, 30 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16772622
Default Alt Text
D7373.diff (28 KB)
Attached To
Mode
D7373: Extending camdd utility to handle ATA devices.
Attached
Detach File
Event Timeline
Log In to Comment