⬢ DragonFlyBSD Kernel Audit
DF-5719 / passrep.c
← back to finding ↓ download raw
/*
 * 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);
}