123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- #include <sys/types.h>
- #include <sys/errno.h>
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/file.h>
- #include <sys/pool.h>
- #include <sys/device.h>
- #include <sys/fcntl.h>
- #include <scsi/scsi_all.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,
- [0x03] = 1,
- [0x08] = 1,
- [0x12] = 1,
- [0x1a] = 1,
- [0x1b] = 1,
- [0x23] = 1,
- [0x25] = 1,
- [0x28] = 1,
- [0x2b] = 1,
- [0x2f] = 1,
- [0x3c] = 1,
- [0x3e] = 1,
- [0x42] = 1,
- [0x43] = 1,
- [0x44] = 1,
- [0x45] = 1,
- [0x46] = 1,
- [0x47] = 1,
- [0x48] = 1,
- [0x4a] = 1,
- [0x4b] = 1,
- [0x4e] = 1,
- [0x51] = 1,
- [0x52] = 1,
- [0x5a] = 1,
- [0x88] = 1,
- [0x8f] = 1,
- [0xa4] = 1,
- [0xa5] = 1,
- [0xa8] = 1,
- [0xac] = 1,
- [0xad] = 1,
- [0xb9] = 1,
- [0xba] = 1,
- [0xbc] = 1,
- [0xbd] = 1,
- [0xbe] = 1
- };
- 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 (screq->flags & SCCMD_READ)
- xs->flags |= SCSI_DATA_IN;
- if (screq->flags & SCCMD_WRITE) {
- if (screq->datalen > 0) {
- err = copyin(screq->databuf, xs->data, screq->datalen);
- if (err != 0)
- goto err;
- }
- xs->flags |= SCSI_DATA_OUT;
- }
- xs->flags |= SCSI_SILENT;
- xs->timeout = screq->timeout;
- xs->retries = 0;
- scsi_xs_sync(xs);
- screq->retsts = 0;
- screq->status = xs->status;
- switch (xs->error) {
- case XS_NOERROR:
-
- screq->datalen_used = xs->datalen - xs->resid;
- screq->retsts = SCCMD_OK;
- break;
- case XS_SENSE:
- #ifdef SCSIDEBUG
- scsi_sense_print_debug(xs);
- #endif
- 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:
- #ifdef SCSIDEBUG
- scsi_sense_print_debug(xs);
- #endif
- 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 && 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 (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;
- }
- 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 (atareq->flags & ATACMD_READ)
- xs->flags |= SCSI_DATA_IN;
- if (atareq->flags & ATACMD_WRITE) {
- if (atareq->datalen > 0) {
- err = copyin(atareq->databuf, xs->data,
- atareq->datalen);
- if (err != 0)
- goto err;
- }
- xs->flags |= SCSI_DATA_OUT;
- }
- xs->flags |= SCSI_SILENT;
- xs->retries = 0;
- scsi_xs_sync(xs);
- atareq->retsts = ATACMD_ERROR;
- switch (xs->error) {
- case XS_SENSE:
- case XS_SHORTSENSE:
- #ifdef SCSIDEBUG
- scsi_sense_print_debug(xs);
- #endif
-
- case XS_NOERROR:
- atareq->retsts = ATACMD_OK;
- break;
- default:
- atareq->retsts = ATACMD_ERROR;
- break;
- }
- if (atareq->datalen > 0 && 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);
- }
- int
- scsi_do_ioctl(struct scsi_link *sc_link, u_long cmd, caddr_t addr, int flag)
- {
- SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd));
- switch(cmd) {
- case SCIOCIDENTIFY: {
- struct scsi_addr *sca = (struct scsi_addr *)addr;
- if ((sc_link->flags & (SDEV_ATAPI | SDEV_UMASS)) == 0)
-
- sca->type = TYPE_SCSI;
- else
-
- sca->type = TYPE_ATAPI;
- sca->scbus = sc_link->bus->sc_dev.dv_unit;
- sca->target = sc_link->target;
- sca->lun = sc_link->lun;
- return (0);
- }
- case SCIOCCOMMAND:
- if (scsi_readsafe_cmd[((scsireq_t *)addr)->cmd[0]])
- break;
-
- case ATAIOCCOMMAND:
- case SCIOCDEBUG:
- if ((flag & FWRITE) == 0)
- return (EPERM);
- break;
- default:
- if (sc_link->adapter->ioctl)
- return ((sc_link->adapter->ioctl)(sc_link, cmd, addr,
- flag));
- else
- return (ENOTTY);
- }
- switch(cmd) {
- case SCIOCCOMMAND:
- return (scsi_ioc_cmd(sc_link, (scsireq_t *)addr));
- case ATAIOCCOMMAND:
- return (scsi_ioc_ata_cmd(sc_link, (atareq_t *)addr));
- case SCIOCDEBUG: {
- int level = *((int *)addr);
- SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level));
- sc_link->flags &= ~SDEV_DBX;
- if (level & 1)
- sc_link->flags |= SDEV_DB1;
- if (level & 2)
- sc_link->flags |= SDEV_DB2;
- if (level & 4)
- sc_link->flags |= SDEV_DB3;
- if (level & 8)
- sc_link->flags |= SDEV_DB4;
- return (0);
- }
- default:
- #ifdef DIAGNOSTIC
- panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd);
- #endif
- return (0);
- }
- }
|