DF-5719 / passrep.c
/* * passrep.c -- replicate the kernel's cdreadsubchannel() CCB byte-for-byte * through the pass(4) driver and dump the full completion state, to find * why CDIOCREADSUBCHANNEL returns EIO while the same CDB via camcontrol * succeeds. Kernel reference: sys/bus/cam/scsi/scsi_cd.c:3324-3369. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <camlib.h> #include <bus/cam/cam_ccb.h> #include <bus/cam/scsi/scsi_message.h> #include <sys/ioctl.h> int main(int argc, char **argv) { struct cam_device *dev; union ccb *ccb; unsigned char data[64]; int retries = argc > 2 ? atoi(argv[2]) : 1; int timeout = argc > 3 ? atoi(argv[3]) : 50000; int track = argc > 4 ? atoi(argv[4]) : 0; int dxfer = argc > 5 ? atoi(argv[5]) : 16; int i; dev = cam_open_device(argv[1], O_RDWR); if (dev == NULL) { printf("cam_open: %s\n", cam_errbuf); return (2); } ccb = cam_getccb(dev); if (ccb == NULL) { printf("getccb fail\n"); return (2); } memset(data, 0, sizeof(data)); /* clear the csio body but PRESERVE the header cam_getccb set up * (path_id/target_id/target_lun) -- mirrors CCB_CLEAR_ALL_EXCEPT_HDR */ { char *base = (char *)ccb; char *hdr = (char *)&ccb->ccb_h; size_t hdrlen = sizeof(struct ccb_hdr); memset(base + hdrlen, 0, sizeof(union ccb) - hdrlen); } cam_fill_csio(&ccb->csio, /*retries*/ retries, /*cbfcnp*/ NULL, /*flags*/ CAM_DIR_IN | CAM_DEV_QFRZDIS, /*tag_action*/ MSG_SIMPLE_Q_TAG, /*data_ptr*/ data, /*dxfer_len*/ dxfer, /*sense_len*/ SSD_FULL_SIZE, /*cdb_len*/ 10, /*timeout*/ timeout); /* VERBATIM CDB construction from scsi_cd.c:3351-3361 */ { struct scsi_read_subchannel_cdb { u_int8_t op_code; u_int8_t byte1; u_int8_t byte2; u_int8_t subchan_format; u_int8_t unused[2]; u_int8_t track; u_int8_t data_len[2]; u_int8_t control; } *c = (void *)&ccb->csio.cdb_io.cdb_bytes; memset(c, 0, sizeof(*c)); c->op_code = 0x42; c->byte1 = argc > 8 ? strtoul(argv[8], NULL, 0) : 0x02; c->byte2 = argc > 6 ? strtoul(argv[6], NULL, 0) : 0x40; c->subchan_format = argc > 7 ? strtoul(argv[7], NULL, 0) : 1; c->track = (u_int8_t)track; c->data_len[0] = (dxfer >> 8) & 0xff; /* scsi_ulto2b BE */ c->data_len[1] = dxfer & 0xff; c->control = 0; } if (cam_send_ccb(dev, ccb) < 0 || (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { printf("FAILED: cam_status=0x%x scsi_status=0x%x resid=%u\n", ccb->ccb_h.status, ccb->csio.scsi_status, ccb->csio.resid); printf("sense:"); for (i = 0; i < 32 && i < ccb->csio.sense_len; i++) printf(" %02x", ((u_int8_t *)&ccb->csio.sense_data)[i]); printf("\n"); cam_freeccb(ccb); return (1); } printf("OK: resid=%u data:", ccb->csio.resid); for (i = 0; i < dxfer - ccb->csio.resid; i++) printf(" %02x", data[i]); printf("\n"); cam_freeccb(ccb); return (0); } |