Edit

IABSD.fr/src/sys/scsi/scsi_ioctl.c

Branch :

  • Show log

    Commit

  • Author : krw
    Date : 2020-09-22 19:32:51
    Hash : 664c6166
    Message : Since dlg@'s 2009 scsi midlayer refactoring the 'struct scsi_generic *cmd' member of 'struct scsi_xfer' has always been pointed at the 'struct scsi_generic cmdstore' member of the same instance. So nuke 'cmdstore' and remove the '*' from cmd. Take the address of cmd as required by the various casts. No intentional functional change. luna88k test by aoyama@, sparc64 test by jmatthew@ Identification of 2009's last *cmd use and ok jmatthew@

  • sys/scsi/scsi_ioctl.c
  • /*	$OpenBSD: scsi_ioctl.c,v 1.67 2020/09/22 19:32:53 krw Exp $	*/
    /*	$NetBSD: scsi_ioctl.c,v 1.23 1996/10/12 23:23:17 christos Exp $	*/
    
    /*
     * Copyright (c) 1994 Charles Hannum.  All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     * 1. Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     * 2. Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     * 3. All advertising materials mentioning features or use of this software
     *    must display the following acknowledgement:
     *	This product includes software developed by Charles Hannum.
     * 4. The name of the author may not be used to endorse or promote products
     *    derived from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /*
     * Contributed by HD Associates (hd@world.std.com).
     * Copyright (c) 1992, 1993 HD Associates
     *
     * Berkeley style copyright.
     */
    
    #include <sys/param.h>
    #include <sys/errno.h>
    #include <sys/systm.h>
    #include <sys/pool.h>
    #include <sys/device.h>
    #include <sys/fcntl.h>
    
    #include <scsi/scsi_all.h>
    #include <scsi/scsi_debug.h>
    #include <scsi/scsiconf.h>
    
    #include <sys/scsiio.h>
    #include <sys/ataio.h>
    
    int			scsi_ioc_cmd(struct scsi_link *, scsireq_t *);
    int			scsi_ioc_ata_cmd(struct scsi_link *, atareq_t *);
    
    const unsigned char scsi_readsafe_cmd[256] = {
    	[0x00] = 1,	/* TEST UNIT READY */
    	[0x03] = 1,	/* REQUEST SENSE */
    	[0x08] = 1,	/* READ(6) */
    	[0x12] = 1,	/* INQUIRY */
    	[0x1a] = 1,	/* MODE SENSE */
    	[0x1b] = 1,	/* START STOP */
    	[0x23] = 1,	/* READ FORMAT CAPACITIES */
    	[0x25] = 1,	/* READ CDVD CAPACITY */
    	[0x28] = 1,	/* READ(10) */
    	[0x2b] = 1,	/* SEEK */
    	[0x2f] = 1,	/* VERIFY(10) */
    	[0x3c] = 1,	/* READ BUFFER */
    	[0x3e] = 1,	/* READ LONG */
    	[0x42] = 1,	/* READ SUBCHANNEL */
    	[0x43] = 1,	/* READ TOC PMA ATIP */
    	[0x44] = 1,	/* READ HEADER */
    	[0x45] = 1,	/* PLAY AUDIO(10) */
    	[0x46] = 1,	/* GET CONFIGURATION */
    	[0x47] = 1,	/* PLAY AUDIO MSF */
    	[0x48] = 1,	/* PLAY AUDIO TI */
    	[0x4a] = 1,	/* GET EVENT STATUS NOTIFICATION */
    	[0x4b] = 1,	/* PAUSE RESUME */
    	[0x4e] = 1,	/* STOP PLAY SCAN */
    	[0x51] = 1,	/* READ DISC INFO */
    	[0x52] = 1,	/* READ TRACK RZONE INFO */
    	[0x5a] = 1,	/* MODE SENSE(10) */
    	[0x88] = 1,	/* READ(16) */
    	[0x8f] = 1,	/* VERIFY(16) */
    	[0xa4] = 1,	/* REPORT KEY */
    	[0xa5] = 1,	/* PLAY AUDIO(12) */
    	[0xa8] = 1,	/* READ(12) */
    	[0xac] = 1,	/* GET PERFORMANCE */
    	[0xad] = 1,	/* READ DVD STRUCTURE */
    	[0xb9] = 1,	/* READ CD MSF */
    	[0xba] = 1,	/* SCAN */
    	[0xbc] = 1,	/* PLAY CD */
    	[0xbd] = 1,	/* MECHANISM STATUS */
    	[0xbe] = 1	/* READ CD */
    };
    
    int
    scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq)
    {
    	struct scsi_xfer		*xs;
    	int				 err = 0;
    
    	if (screq->cmdlen > sizeof(struct scsi_generic))
    		return EFAULT;
    	if (screq->datalen > MAXPHYS)
    		return EINVAL;
    
    	xs = scsi_xs_get(link, 0);
    	if (xs == NULL)
    		return ENOMEM;
    
    	memcpy(&xs->cmd, screq->cmd, screq->cmdlen);
    	xs->cmdlen = screq->cmdlen;
    
    	if (screq->datalen > 0) {
    		xs->data = dma_alloc(screq->datalen, PR_WAITOK | PR_ZERO);
    		if (xs->data == NULL) {
    			err = ENOMEM;
    			goto err;
    		}
    		xs->datalen = screq->datalen;
    	}
    
    	if (ISSET(screq->flags, SCCMD_READ))
    		SET(xs->flags, SCSI_DATA_IN);
    	if (ISSET(screq->flags, SCCMD_WRITE)) {
    		if (screq->datalen > 0) {
    			err = copyin(screq->databuf, xs->data, screq->datalen);
    			if (err != 0)
    				goto err;
    		}
    
    		SET(xs->flags, SCSI_DATA_OUT);
    	}
    
    	SET(xs->flags, SCSI_SILENT);	/* User is responsible for errors. */
    	xs->timeout = screq->timeout;
    	xs->retries = 0; /* user must do the retries *//* ignored */
    
    	scsi_xs_sync(xs);
    
    	screq->retsts = 0;
    	screq->status = xs->status;
    	switch (xs->error) {
    	case XS_NOERROR:
    		/* probably rubbish */
    		screq->datalen_used = xs->datalen - xs->resid;
    		screq->retsts = SCCMD_OK;
    		break;
    	case XS_SENSE:
    		SC_DEBUG_SENSE(xs);
    		screq->senselen_used = min(sizeof(xs->sense),
    		    sizeof(screq->sense));
    		memcpy(screq->sense, &xs->sense, screq->senselen_used);
    		screq->retsts = SCCMD_SENSE;
    		break;
    	case XS_SHORTSENSE:
    		SC_DEBUG_SENSE(xs);
    		printf("XS_SHORTSENSE\n");
    		screq->senselen_used = min(sizeof(xs->sense),
    		    sizeof(screq->sense));
    		memcpy(screq->sense, &xs->sense, screq->senselen_used);
    		screq->retsts = SCCMD_UNKNOWN;
    		break;
    	case XS_DRIVER_STUFFUP:
    		screq->retsts = SCCMD_UNKNOWN;
    		break;
    	case XS_TIMEOUT:
    		screq->retsts = SCCMD_TIMEOUT;
    		break;
    	case XS_BUSY:
    		screq->retsts = SCCMD_BUSY;
    		break;
    	default:
    		screq->retsts = SCCMD_UNKNOWN;
    		break;
    	}
    
    	if (screq->datalen > 0 && ISSET(screq->flags, SCCMD_READ)) {
    		err = copyout(xs->data, screq->databuf, screq->datalen);
    		if (err != 0)
    			goto err;
    	}
    
    err:
    	if (xs->data)
    		dma_free(xs->data, screq->datalen);
    	scsi_xs_put(xs);
    
    	return err;
    }
    
    int
    scsi_ioc_ata_cmd(struct scsi_link *link, atareq_t *atareq)
    {
    	struct scsi_xfer		*xs;
    	struct scsi_ata_passthru_12	*cdb;
    	int				 err = 0;
    
    	if (atareq->datalen > MAXPHYS)
    		return EINVAL;
    
    	xs = scsi_xs_get(link, 0);
    	if (xs == NULL)
    		return ENOMEM;
    
    	cdb = (struct scsi_ata_passthru_12 *)&xs->cmd;
    	cdb->opcode = ATA_PASSTHRU_12;
    
    	if (atareq->datalen > 0) {
    		if (ISSET(atareq->flags, ATACMD_READ)) {
    			cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAIN;
    			cdb->flags = ATA_PASSTHRU_T_DIR_READ;
    		} else {
    			cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAOUT;
    			cdb->flags = ATA_PASSTHRU_T_DIR_WRITE;
    		}
    		SET(cdb->flags, ATA_PASSTHRU_T_LEN_SECTOR_COUNT);
    	} else {
    		cdb->count_proto = ATA_PASSTHRU_PROTO_NON_DATA;
    		cdb->flags = ATA_PASSTHRU_T_LEN_NONE;
    	}
    	cdb->features = atareq->features;
    	cdb->sector_count = atareq->sec_count;
    	cdb->lba_low = atareq->sec_num;
    	cdb->lba_mid = atareq->cylinder;
    	cdb->lba_high = atareq->cylinder >> 8;
    	cdb->device = atareq->head & 0x0f;
    	cdb->command = atareq->command;
    
    	xs->cmdlen = sizeof(*cdb);
    
    	if (atareq->datalen > 0) {
    		xs->data = dma_alloc(atareq->datalen, PR_WAITOK | PR_ZERO);
    		if (xs->data == NULL) {
    			err = ENOMEM;
    			goto err;
    		}
    		xs->datalen = atareq->datalen;
    	}
    
    	if (ISSET(atareq->flags, ATACMD_READ))
    		SET(xs->flags, SCSI_DATA_IN);
    	if (ISSET(atareq->flags, ATACMD_WRITE)) {
    		if (atareq->datalen > 0) {
    			err = copyin(atareq->databuf, xs->data,
    			    atareq->datalen);
    			if (err != 0)
    				goto err;
    		}
    
    		SET(xs->flags, SCSI_DATA_OUT);
    	}
    
    	SET(xs->flags, SCSI_SILENT);	/* User is responsible for errors. */
    	xs->retries = 0; /* user must do the retries *//* ignored */
    
    	scsi_xs_sync(xs);
    
    	atareq->retsts = ATACMD_ERROR;
    	switch (xs->error) {
    	case XS_SENSE:
    	case XS_SHORTSENSE:
    		SC_DEBUG_SENSE(xs);
    		/* XXX this is not right */
    	case XS_NOERROR:
    		atareq->retsts = ATACMD_OK;
    		break;
    	default:
    		atareq->retsts = ATACMD_ERROR;
    		break;
    	}
    
    	if (atareq->datalen > 0 && ISSET(atareq->flags, ATACMD_READ)) {
    		err = copyout(xs->data, atareq->databuf, atareq->datalen);
    		if (err != 0)
    			goto err;
    	}
    
    err:
    	if (xs->data)
    		dma_free(xs->data, atareq->datalen);
    	scsi_xs_put(xs);
    
    	return err;
    }
    
    /*
     * Something (e.g. another driver) has called us
     * with a scsi_link for a target/lun/adapter, and a scsi
     * specific ioctl to perform, better try.
     */
    int
    scsi_do_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag)
    {
    	SC_DEBUG(link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd));
    
    	switch(cmd) {
    	case SCIOCIDENTIFY: {
    		struct scsi_addr *sca = (struct scsi_addr *)addr;
    
    		if (!ISSET(link->flags, (SDEV_ATAPI | SDEV_UMASS)))
    			/* A 'real' SCSI target. */
    			sca->type = TYPE_SCSI;
    		else
    			/* An 'emulated' SCSI target. */
    			sca->type = TYPE_ATAPI;
    		sca->scbus = link->bus->sc_dev.dv_unit;
    		sca->target = link->target;
    		sca->lun = link->lun;
    		return 0;
    	}
    	case SCIOCCOMMAND:
    		if (scsi_readsafe_cmd[((scsireq_t *)addr)->cmd[0]])
    			break;
    		/* FALLTHROUGH */
    	case ATAIOCCOMMAND:
    	case SCIOCDEBUG:
    		if (!ISSET(flag, FWRITE))
    			return EPERM;
    		break;
    	default:
    		if (link->bus->sb_adapter->ioctl)
    			return (link->bus->sb_adapter->ioctl)(link, cmd, addr, flag);
    		else
    			return ENOTTY;
    	}
    
    	switch(cmd) {
    	case SCIOCCOMMAND:
    		return scsi_ioc_cmd(link, (scsireq_t *)addr);
    	case ATAIOCCOMMAND:
    		return scsi_ioc_ata_cmd(link, (atareq_t *)addr);
    	case SCIOCDEBUG: {
    		int level = *((int *)addr);
    
    		SC_DEBUG(link, SDEV_DB3, ("debug set to %d\n", level));
    		CLR(link->flags, SDEV_DBX); /* clear debug bits */
    		if (level & 1)
    			SET(link->flags, SDEV_DB1);
    		if (level & 2)
    			SET(link->flags, SDEV_DB2);
    		if (level & 4)
    			SET(link->flags, SDEV_DB3);
    		if (level & 8)
    			SET(link->flags, SDEV_DB4);
    		return 0;
    	}
    	default:
    #ifdef DIAGNOSTIC
    		panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd);
    #endif /* DIAGNOSTIC */
    		return 0;
    	}
    }