Пример #1
0
static rtems_status_code
rtems_bsd_scsi_read_capacity(union ccb *ccb, uint32_t *block_count, uint32_t *block_size)
{
	rtems_status_code sc = RTEMS_SUCCESSFUL;
	struct scsi_read_capacity_data rdcap;

	memset(&rdcap, 0, sizeof(rdcap));

	scsi_read_capacity(
		&ccb->csio,
		BSD_SCSI_RETRIES,
		rtems_bsd_ccb_callback,
		BSD_SCSI_TAG,
		&rdcap,
		SSD_FULL_SIZE,
		BSD_SCSI_TIMEOUT
	);

	sc = rtems_bsd_ccb_action(ccb);
	if (sc != RTEMS_SUCCESSFUL) {
		return RTEMS_IO_ERROR;
	}

	*block_size = scsi_4btoul(rdcap.length);
	*block_count = scsi_4btoul(rdcap.addr) + 1;

	return RTEMS_SUCCESSFUL;
}
Пример #2
0
int scsi_init(struct scsi_ifc *ifc) {
    int rc;
    scsi = kzalloc(sizeof(struct scsi_dev));
    if (scsi == NULL)
        return ERR_NO_MEM;

    /* Copy the driver interface */
    scsi->driver = ifc->driver;
    scsi->read = ifc->read;
    scsi->write = ifc->write;
    spinlock_init(&scsi->lock);

    rc = scsi_read_capacity();
    DEBUG("Reading device capacity parameters %s", DEBUG_STATUS(rc));

    if(rc < 0) {
        kfree(scsi);
        return -1;
    }

    DEBUG("Device block size %d, block count %d",
          scsi->block_size, scsi->total_block_count);

    scsi->op_status = OPERATING;

    return 0;
}
Пример #3
0
int
main(int argc, char * argv[])
{
    int64_t skip = 0;
    int64_t seek = 0;
    int ibs = 0;
    int obs = 0;
    int bpt = DEF_BLOCKS_PER_TRANSFER;
    int bpt_given = 0;
    char str[STR_SZ];
    char * key;
    char * buf;
    char inf[INOUTF_SZ];
    int in_type = FT_OTHER;
    char outf[INOUTF_SZ];
    int out_type = FT_OTHER;
    int res, k, t;
    int infd, outfd, blocks;
    unsigned char * wrkPos;
    unsigned char * wrkBuff = NULL;
    unsigned char * wrkMmap = NULL;
    int64_t in_num_sect = -1;
    int in_res_sz = 0;
    int64_t out_num_sect = -1;
    int out_res_sz = 0;
    int scsi_cdbsz_in = DEF_SCSI_CDBSZ;
    int scsi_cdbsz_out = DEF_SCSI_CDBSZ;
    int cdbsz_given = 0;
    int do_coe = 0;     /* dummy, just accept + ignore */
    int do_sync = 0;
    int num_dio_not_done = 0;
    int in_sect_sz, out_sect_sz;
    int n, flags;
    char ebuff[EBUFF_SZ];
    char b[80];
    int blocks_per;
    size_t psz;
    struct flags_t in_flags;
    struct flags_t out_flags;
    int ret = 0;

#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
    psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */
#else
    psz = 4096;     /* give up, pick likely figure */
#endif
    inf[0] = '\0';
    outf[0] = '\0';
    memset(&in_flags, 0, sizeof(in_flags));
    memset(&out_flags, 0, sizeof(out_flags));

    for (k = 1; k < argc; k++) {
        if (argv[k])
            strncpy(str, argv[k], STR_SZ);
        else
            continue;
        for (key = str, buf = key; *buf && *buf != '=';)
            buf++;
        if (*buf)
            *buf++ = '\0';
        if (0 == strcmp(key,"bpt")) {
            bpt = sg_get_num(buf);
            if (-1 == bpt) {
                pr2serr(ME "bad argument to 'bpt'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
            bpt_given = 1;
        } else if (0 == strcmp(key,"bs")) {
            blk_sz = sg_get_num(buf);
            if (-1 == blk_sz) {
                pr2serr(ME "bad argument to 'bs'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"cdbsz")) {
            scsi_cdbsz_in = sg_get_num(buf);
            scsi_cdbsz_out = scsi_cdbsz_in;
            cdbsz_given = 1;
        } else if (0 == strcmp(key,"coe")) {
            do_coe = sg_get_num(buf);   /* dummy, just accept + ignore */
            if (do_coe) {
                ;    /* unused, dummy to suppress warning */
            }
        } else if (0 == strcmp(key,"count")) {
            if (0 != strcmp("-1", buf)) {
                dd_count = sg_get_llnum(buf);
                if (-1LL == dd_count) {
                    pr2serr(ME "bad argument to 'count'\n");
                    return SG_LIB_SYNTAX_ERROR;
                }
            }   /* treat 'count=-1' as calculate count (same as not given) */
        } else if (0 == strcmp(key,"dio"))
            out_flags.dio = sg_get_num(buf);
        else if (0 == strcmp(key,"fua")) {
            n = sg_get_num(buf);
            if (n & 1)
                out_flags.fua = 1;
            if (n & 2)
                in_flags.fua = 1;
        } else if (0 == strcmp(key,"ibs")) {
            ibs = sg_get_num(buf);
            if (-1 == ibs) {
                pr2serr(ME "bad argument to 'ibs'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (strcmp(key,"if") == 0) {
            if ('\0' != inf[0]) {
                pr2serr("Second 'if=' argument??\n");
                return SG_LIB_SYNTAX_ERROR;
            } else
                strncpy(inf, buf, INOUTF_SZ);
        } else if (0 == strcmp(key, "iflag")) {
            if (process_flags(buf, &in_flags)) {
                pr2serr(ME "bad argument to 'iflag'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (strcmp(key,"of") == 0) {
            if ('\0' != outf[0]) {
                pr2serr("Second 'of=' argument??\n");
                return SG_LIB_SYNTAX_ERROR;
            } else
                strncpy(outf, buf, INOUTF_SZ);
        } else if (0 == strcmp(key, "oflag")) {
            if (process_flags(buf, &out_flags)) {
                pr2serr(ME "bad argument to 'oflag'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"obs")) {
            obs = sg_get_num(buf);
            if (-1 == obs) {
                pr2serr(ME "bad argument to 'obs'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"seek")) {
            seek = sg_get_llnum(buf);
            if (-1LL == seek) {
                pr2serr(ME "bad argument to 'seek'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"skip")) {
            skip = sg_get_llnum(buf);
            if (-1LL == skip) {
                pr2serr(ME "bad argument to 'skip'\n");
                return SG_LIB_SYNTAX_ERROR;
            }
        } else if (0 == strcmp(key,"sync"))
            do_sync = sg_get_num(buf);
        else if (0 == strcmp(key,"time"))
            do_time = sg_get_num(buf);
        else if (0 == strncmp(key, "verb", 4))
            verbose = sg_get_num(buf);
        else if ((0 == strncmp(key, "--help", 7)) ||
                 (0 == strcmp(key, "-h")) || (0 == strcmp(key, "-?"))) {
            usage();
            return 0;
        } else if ((0 == strncmp(key, "--vers", 6)) ||
                   (0 == strcmp(key, "-V"))) {
            pr2serr(ME ": %s\n", version_str);
            return 0;
        }
        else {
            pr2serr("Unrecognized option '%s'\n", key);
            pr2serr("For more information use '--help'\n");
            return SG_LIB_SYNTAX_ERROR;
        }
    }
    if (blk_sz <= 0) {
        blk_sz = DEF_BLOCK_SIZE;
        pr2serr("Assume default 'bs' (block size) of %d bytes\n", blk_sz);
    }
    if ((ibs && (ibs != blk_sz)) || (obs && (obs != blk_sz))) {
        pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n");
        usage();
        return SG_LIB_SYNTAX_ERROR;
    }
    if ((skip < 0) || (seek < 0)) {
        pr2serr("skip and seek cannot be negative\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    if ((out_flags.append > 0) && (seek > 0)) {
        pr2serr("Can't use both append and seek switches\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    if (bpt < 1) {
        pr2serr("bpt must be greater than 0\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    /* defaulting transfer size to 128*2048 for CD/DVDs is too large
       for the block layer in lk 2.6 and results in an EIO on the
       SG_IO ioctl. So reduce it in that case. */
    if ((blk_sz >= 2048) && (0 == bpt_given))
        bpt = DEF_BLOCKS_PER_2048TRANSFER;

#ifdef SG_DEBUG
    pr2serr(ME "if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64
            "\n", inf, skip, outf, seek, dd_count);
#endif
    install_handler (SIGINT, interrupt_handler);
    install_handler (SIGQUIT, interrupt_handler);
    install_handler (SIGPIPE, interrupt_handler);
    install_handler (SIGUSR1, siginfo_handler);

    infd = STDIN_FILENO;
    outfd = STDOUT_FILENO;
    if (inf[0] && ('-' != inf[0])) {
        in_type = dd_filetype(inf);
        if (verbose)
            pr2serr(" >> Input file type: %s\n",
                    dd_filetype_str(in_type, ebuff));

        if (FT_ERROR == in_type) {
            pr2serr(ME "unable to access %s\n", inf);
            return SG_LIB_FILE_ERROR;
        } else if (FT_ST == in_type) {
            pr2serr(ME "unable to use scsi tape device %s\n", inf);
            return SG_LIB_FILE_ERROR;
        } else if (FT_SG == in_type) {
            flags = O_RDWR | O_NONBLOCK;
            if (in_flags.direct)
                flags |= O_DIRECT;
            if (in_flags.excl)
                flags |= O_EXCL;
            if (in_flags.dsync)
                flags |= O_SYNC;
            if ((infd = open(inf, flags)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for sg reading", inf);
                perror(ebuff);
                return SG_LIB_FILE_ERROR;
            }
            res = ioctl(infd, SG_GET_VERSION_NUM, &t);
            if ((res < 0) || (t < 30122)) {
                pr2serr(ME "sg driver prior to 3.1.22\n");
                return SG_LIB_FILE_ERROR;
            }
            in_res_sz = blk_sz * bpt;
            if (0 != (in_res_sz % psz)) /* round up to next page */
                in_res_sz = ((in_res_sz / psz) + 1) * psz;
            if (ioctl(infd, SG_GET_RESERVED_SIZE, &t) < 0) {
                perror(ME "SG_GET_RESERVED_SIZE error");
                return SG_LIB_FILE_ERROR;
            }
            if (t < MIN_RESERVED_SIZE)
                t = MIN_RESERVED_SIZE;
            if (in_res_sz > t) {
                if (ioctl(infd, SG_SET_RESERVED_SIZE, &in_res_sz) < 0) {
                    perror(ME "SG_SET_RESERVED_SIZE error");
                    return SG_LIB_FILE_ERROR;
                }
            }
            wrkMmap = (unsigned char *)mmap(NULL, in_res_sz,
                                            PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0);
            if (MAP_FAILED == wrkMmap) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "error using mmap() on file: %s", inf);
                perror(ebuff);
                return SG_LIB_FILE_ERROR;
            }
        } else {
            flags = O_RDONLY;
            if (in_flags.direct)
                flags |= O_DIRECT;
            if (in_flags.excl)
                flags |= O_EXCL;
            if (in_flags.dsync)
                flags |= O_SYNC;
            if ((infd = open(inf, flags)) < 0) {
                snprintf(ebuff, EBUFF_SZ,
                         ME "could not open %s for reading", inf);
                perror(ebuff);
                return SG_LIB_FILE_ERROR;
            }
            else if (skip > 0) {
                off64_t offset = skip;

                offset *= blk_sz;       /* could exceed 32 bits here! */
                if (lseek64(infd, offset, SEEK_SET) < 0) {
                    snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to "
                             "required position on %s", inf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
                if (verbose)
                    pr2serr("  >> skip: lseek64 SEEK_SET, byte offset=0x%"
                            PRIx64 "\n", (uint64_t)offset);
            }
        }
    }

    if (outf[0] && ('-' != outf[0])) {
        out_type = dd_filetype(outf);
        if (verbose)
            pr2serr(" >> Output file type: %s\n",
                    dd_filetype_str(out_type, ebuff));

        if (FT_ST == out_type) {
            pr2serr(ME "unable to use scsi tape device %s\n", outf);
            return SG_LIB_FILE_ERROR;
        }
        else if (FT_SG == out_type) {
            flags = O_RDWR | O_NONBLOCK;
            if (out_flags.direct)
                flags |= O_DIRECT;
            if (out_flags.excl)
                flags |= O_EXCL;
            if (out_flags.dsync)
                flags |= O_SYNC;
            if ((outfd = open(outf, flags)) < 0) {
                snprintf(ebuff, EBUFF_SZ, ME "could not open %s for "
                         "sg writing", outf);
                perror(ebuff);
                return SG_LIB_FILE_ERROR;
            }
            res = ioctl(outfd, SG_GET_VERSION_NUM, &t);
            if ((res < 0) || (t < 30122)) {
                pr2serr(ME "sg driver prior to 3.1.22\n");
                return SG_LIB_FILE_ERROR;
            }
            if (ioctl(outfd, SG_GET_RESERVED_SIZE, &t) < 0) {
                perror(ME "SG_GET_RESERVED_SIZE error");
                return SG_LIB_FILE_ERROR;
            }
            if (t < MIN_RESERVED_SIZE)
                t = MIN_RESERVED_SIZE;
            out_res_sz = blk_sz * bpt;
            if (out_res_sz > t) {
                if (ioctl(outfd, SG_SET_RESERVED_SIZE, &out_res_sz) < 0) {
                    perror(ME "SG_SET_RESERVED_SIZE error");
                    return SG_LIB_FILE_ERROR;
                }
            }
            if (NULL == wrkMmap) {
                wrkMmap = (unsigned char *)mmap(NULL, out_res_sz,
                                                PROT_READ | PROT_WRITE, MAP_SHARED, outfd, 0);
                if (MAP_FAILED == wrkMmap) {
                    snprintf(ebuff, EBUFF_SZ,
                             ME "error using mmap() on file: %s", outf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
            }
        }
        else if (FT_DEV_NULL == out_type)
            outfd = -1; /* don't bother opening */
        else {
            if (FT_RAW != out_type) {
                flags = O_WRONLY | O_CREAT;
                if (out_flags.direct)
                    flags |= O_DIRECT;
                if (out_flags.excl)
                    flags |= O_EXCL;
                if (out_flags.dsync)
                    flags |= O_SYNC;
                if (out_flags.append)
                    flags |= O_APPEND;
                if ((outfd = open(outf, flags, 0666)) < 0) {
                    snprintf(ebuff, EBUFF_SZ,
                             ME "could not open %s for writing", outf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
            }
            else {
                if ((outfd = open(outf, O_WRONLY)) < 0) {
                    snprintf(ebuff, EBUFF_SZ, ME "could not open %s "
                             "for raw writing", outf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
            }
            if (seek > 0) {
                off64_t offset = seek;

                offset *= blk_sz;       /* could exceed 32 bits here! */
                if (lseek64(outfd, offset, SEEK_SET) < 0) {
                    snprintf(ebuff, EBUFF_SZ, ME "couldn't seek to "
                             "required position on %s", outf);
                    perror(ebuff);
                    return SG_LIB_FILE_ERROR;
                }
                if (verbose)
                    pr2serr("   >> seek: lseek64 SEEK_SET, byte offset=0x%"
                            PRIx64 "\n", (uint64_t)offset);
            }
        }
    }
    if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) {
        pr2serr("Won't default both IFILE to stdin _and_ OFILE to as "
                "stdout\n");
        pr2serr("For more information use '--help'\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    if (dd_count < 0) {
        in_num_sect = -1;
        if (FT_SG == in_type) {
            res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz);
            if (SG_LIB_CAT_UNIT_ATTENTION == res) {
                pr2serr("Unit attention(in), continuing\n");
                res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz);
            } else if (SG_LIB_CAT_ABORTED_COMMAND == res) {
                pr2serr("Aborted command(in), continuing\n");
                res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz);
            }
            if (0 != res) {
                sg_get_category_sense_str(res, sizeof(b), b, verbose);
                pr2serr("Read capacity (if=%s): %s\n", inf, b);
                in_num_sect = -1;
            }
        } else if (FT_BLOCK == in_type) {
            if (0 != read_blkdev_capacity(infd, &in_num_sect, &in_sect_sz)) {
                pr2serr("Unable to read block capacity on %s\n", inf);
                in_num_sect = -1;
            }
            if (blk_sz != in_sect_sz) {
                pr2serr("block size on %s confusion; bs=%d, from device=%d\n",
                        inf, blk_sz, in_sect_sz);
                in_num_sect = -1;
            }
        }
        if (in_num_sect > skip)
            in_num_sect -= skip;

        out_num_sect = -1;
        if (FT_SG == out_type) {
            res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz);
            if (SG_LIB_CAT_UNIT_ATTENTION == res) {
                pr2serr("Unit attention(out), continuing\n");
                res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz);
            } else if (SG_LIB_CAT_ABORTED_COMMAND == res) {
                pr2serr("Aborted command(out), continuing\n");
                res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz);
            }
            if (0 != res) {
                sg_get_category_sense_str(res, sizeof(b), b, verbose);
                pr2serr("Read capacity (of=%s): %s\n", inf, b);
                out_num_sect = -1;
            }
        } else if (FT_BLOCK == out_type) {
            if (0 != read_blkdev_capacity(outfd, &out_num_sect,
                                          &out_sect_sz)) {
                pr2serr("Unable to read block capacity on %s\n", outf);
                out_num_sect = -1;
            }
            if (blk_sz != out_sect_sz) {
                pr2serr("block size on %s confusion: bs=%d, from device=%d\n",
                        outf, blk_sz, out_sect_sz);
                out_num_sect = -1;
            }
        }
        if (out_num_sect > seek)
            out_num_sect -= seek;
#ifdef SG_DEBUG
        pr2serr("Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", "
                "out_num_sect=%" PRId64 "\n", dd_count, in_num_sect,
                out_num_sect);
#endif
        if (in_num_sect > 0) {
            if (out_num_sect > 0)
                dd_count = (in_num_sect > out_num_sect) ? out_num_sect :
                           in_num_sect;
            else
                dd_count = in_num_sect;
        }
        else
            dd_count = out_num_sect;
    }

    if (dd_count < 0) {
        pr2serr("Couldn't calculate count, please give one\n");
        return SG_LIB_SYNTAX_ERROR;
    }
    if (! cdbsz_given) {
        if ((FT_SG == in_type) && (MAX_SCSI_CDBSZ != scsi_cdbsz_in) &&
                (((dd_count + skip) > UINT_MAX) || (bpt > USHRT_MAX))) {
            pr2serr("Note: SCSI command size increased to 16 bytes (for "
                    "'if')\n");
            scsi_cdbsz_in = MAX_SCSI_CDBSZ;
        }
        if ((FT_SG == out_type) && (MAX_SCSI_CDBSZ != scsi_cdbsz_out) &&
                (((dd_count + seek) > UINT_MAX) || (bpt > USHRT_MAX))) {
            pr2serr("Note: SCSI command size increased to 16 bytes (for "
                    "'of')\n");
            scsi_cdbsz_out = MAX_SCSI_CDBSZ;
        }
    }

    if (out_flags.dio && (FT_SG != in_type)) {
        out_flags.dio = 0;
        pr2serr(">>> dio only performed on 'of' side when 'if' is an sg "
                "device\n");
    }
    if (out_flags.dio) {
        int fd;
        char c;

        if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) {
            if (1 == read(fd, &c, 1)) {
                if ('0' == c)
                    pr2serr(">>> %s set to '0' but should be set to '1' for "
                            "direct IO\n", proc_allow_dio);
            }
            close(fd);
        }
    }

    if (wrkMmap) {
        wrkPos = wrkMmap;
    } else {
        if ((FT_RAW == in_type) || (FT_RAW == out_type)) {
            wrkBuff = (unsigned char *)malloc(blk_sz * bpt + psz);
            if (0 == wrkBuff) {
                pr2serr("Not enough user memory for raw\n");
                return SG_LIB_FILE_ERROR;
            }
            /* perhaps use posix_memalign() instead */
            wrkPos = (unsigned char *)(((uintptr_t)wrkBuff + psz - 1) &
                                       (~(psz - 1)));
        }
        else {
            wrkBuff = (unsigned char *)malloc(blk_sz * bpt);
            if (0 == wrkBuff) {
                pr2serr("Not enough user memory\n");
                return SG_LIB_FILE_ERROR;
            }
            wrkPos = wrkBuff;
        }
    }

    blocks_per = bpt;
#ifdef SG_DEBUG
    pr2serr("Start of loop, count=%" PRId64 ", blocks_per=%d\n", dd_count,
            blocks_per);
#endif
    if (do_time) {
        start_tm.tv_sec = 0;
        start_tm.tv_usec = 0;
        gettimeofday(&start_tm, NULL);
        start_tm_valid = 1;
    }
    req_count = dd_count;

    if (verbose && (dd_count > 0) && (0 == out_flags.dio) &&
            (FT_SG == in_type) && (FT_SG == out_type))
        pr2serr("Since both 'if' and 'of' are sg devices, only do mmap-ed "
                "transfers on 'if'\n");

    while (dd_count > 0) {
        blocks = (dd_count > blocks_per) ? blocks_per : dd_count;
        if (FT_SG == in_type) {
            ret = sg_read(infd, wrkPos, blocks, skip, blk_sz, scsi_cdbsz_in,
                          in_flags.fua, in_flags.dpo, 1);
            if ((SG_LIB_CAT_UNIT_ATTENTION == ret) ||
                    (SG_LIB_CAT_ABORTED_COMMAND == ret)) {
                pr2serr("Unit attention or aborted command, continuing "
                        "(r)\n");
                ret = sg_read(infd, wrkPos, blocks, skip, blk_sz,
                              scsi_cdbsz_in, in_flags.fua, in_flags.dpo, 1);
            }
            if (0 != ret) {
                pr2serr("sg_read failed, skip=%" PRId64 "\n", skip);
                break;
            }
            else
                in_full += blocks;
        }
        else {
            while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) &&
                    ((EINTR == errno) || (EAGAIN == errno)))
                ;
            if (verbose > 2)
                pr2serr("read(unix): count=%d, res=%d\n", blocks * blk_sz,
                        res);
            if (ret < 0) {
                snprintf(ebuff, EBUFF_SZ, ME "reading, skip=%" PRId64 " ",
                         skip);
                perror(ebuff);
                ret = -1;
                break;
            }
            else if (res < blocks * blk_sz) {
                dd_count = 0;
                blocks = res / blk_sz;
                if ((res % blk_sz) > 0) {
                    blocks++;
                    in_partial++;
                }
            }
            in_full += blocks;
        }

        if (0 == blocks)
            break;      /* read nothing so leave loop */

        if (FT_SG == out_type) {
            int do_mmap = (FT_SG == in_type) ? 0 : 1;
            int dio_res = out_flags.dio;

            ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, scsi_cdbsz_out,
                           out_flags.fua, out_flags.dpo, do_mmap, &dio_res);
            if ((SG_LIB_CAT_UNIT_ATTENTION == ret) ||
                    (SG_LIB_CAT_ABORTED_COMMAND == ret)) {
                pr2serr("Unit attention or aborted command, continuing (w)\n");
                dio_res = out_flags.dio;
                ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz,
                               scsi_cdbsz_out, out_flags.fua, out_flags.dpo,
                               do_mmap, &dio_res);
            }
            if (0 != ret) {
                pr2serr("sg_write failed, seek=%" PRId64 "\n", seek);
                break;
            }
            else {
                out_full += blocks;
                if (out_flags.dio && (0 == dio_res))
                    num_dio_not_done++;
            }
        }
        else if (FT_DEV_NULL == out_type)
            out_full += blocks; /* act as if written out without error */
        else {
            while (((res = write(outfd, wrkPos, blocks * blk_sz)) < 0) &&
                    ((EINTR == errno) || (EAGAIN == errno)))
                ;
            if (verbose > 2)
                pr2serr("write(unix): count=%d, res=%d\n", blocks * blk_sz,
                        res);
            if (res < 0) {
                snprintf(ebuff, EBUFF_SZ, ME "writing, seek=%" PRId64 " ",
                         seek);
                perror(ebuff);
                break;
            }
            else if (res < blocks * blk_sz) {
                pr2serr("output file probably full, seek=%" PRId64 " ", seek);
                blocks = res / blk_sz;
                out_full += blocks;
                if ((res % blk_sz) > 0)
                    out_partial++;
                break;
            }
            else
                out_full += blocks;
        }
        if (dd_count > 0)
            dd_count -= blocks;
        skip += blocks;
        seek += blocks;
    }

    if (do_time)
        calc_duration_throughput(0);
    if (do_sync) {
        if (FT_SG == out_type) {
            pr2serr(">> Synchronizing cache on %s\n", outf);
            res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0);
            if (SG_LIB_CAT_UNIT_ATTENTION == res) {
                pr2serr("Unit attention(out), continuing\n");
                res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0);
            }
            if (0 != res) {
                sg_get_category_sense_str(res, sizeof(b), b, verbose);
                pr2serr("Synchronize cache(out): %s\n", b);
            }
        }
    }

    if (wrkBuff) free(wrkBuff);
    if (STDIN_FILENO != infd)
        close(infd);
    if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type))
        close(outfd);
    if (0 != dd_count) {
        pr2serr("Some error occurred,");
        if (0 == ret)
            ret = SG_LIB_CAT_OTHER;
    }
    print_stats();
    if (sum_of_resids)
        pr2serr(">> Non-zero sum of residual counts=%d\n", sum_of_resids);
    if (num_dio_not_done)
        pr2serr(">> dio requested but _not_ done %d times\n",
                num_dio_not_done);
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
}
Пример #4
0
/**
 * scsi_detect_dev - Detect scsi device
 *
 * @target: target id
 * @lun: target lun
 * @dev_desc: block device description
 *
 * The scsi_detect_dev detects and fills a dev_desc structure when the device is
 * detected.
 *
 * Return: 0 on success, error value otherwise
 */
static int scsi_detect_dev(struct udevice *dev, int target, int lun,
			   struct blk_desc *dev_desc)
{
	unsigned char perq, modi;
	lbaint_t capacity;
	unsigned long blksz;
	struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb;

	pccb->target = target;
	pccb->lun = lun;
	pccb->pdata = (unsigned char *)&tempbuff;
	pccb->datalen = 512;
	scsi_setup_inquiry(pccb);
	if (scsi_exec(dev, pccb)) {
		if (pccb->contr_stat == SCSI_SEL_TIME_OUT) {
			/*
			  * selection timeout => assuming no
			  * device present
			  */
			debug("Selection timeout ID %d\n",
			      pccb->target);
			return -ETIMEDOUT;
		}
		scsi_print_error(pccb);
		return -ENODEV;
	}
	perq = tempbuff[0];
	modi = tempbuff[1];
	if ((perq & 0x1f) == 0x1f)
		return -ENODEV; /* skip unknown devices */
	if ((modi & 0x80) == 0x80) /* drive is removable */
		dev_desc->removable = true;
	/* get info for this device */
	scsi_ident_cpy((unsigned char *)dev_desc->vendor,
		       &tempbuff[8], 8);
	scsi_ident_cpy((unsigned char *)dev_desc->product,
		       &tempbuff[16], 16);
	scsi_ident_cpy((unsigned char *)dev_desc->revision,
		       &tempbuff[32], 4);
	dev_desc->target = pccb->target;
	dev_desc->lun = pccb->lun;

	pccb->datalen = 0;
	scsi_setup_test_unit_ready(pccb);
	if (scsi_exec(dev, pccb)) {
		if (dev_desc->removable) {
			dev_desc->type = perq;
			goto removable;
		}
		scsi_print_error(pccb);
		return -EINVAL;
	}
	if (scsi_read_capacity(dev, pccb, &capacity, &blksz)) {
		scsi_print_error(pccb);
		return -EINVAL;
	}
	dev_desc->lba = capacity;
	dev_desc->blksz = blksz;
	dev_desc->log2blksz = LOG2(dev_desc->blksz);
	dev_desc->type = perq;
removable:
	return 0;
}
Пример #5
0
int scsi_get_info(struct scsi_info *info, unsigned int lun,
		  struct scsi_transport *tr, void *priv)
{
	int rc;
	u32 *cap;
	unsigned char __cacheline_aligned buf[64];
	struct scsi_request srb;

	if (!info || !tr || !tr->transport) {
		return VMM_EINVALID;
	}

	memset(info, 0, sizeof(*info));

	INIT_SCSI_REQUEST(&srb, lun, &buf, sizeof(buf));
	rc = scsi_inquiry(&srb, tr, priv);
	if (rc) {
		return rc;
	}

	info->lun = lun;
	info->perph_qualifier = (buf[0] & 0xE0) >> 5;
	info->perph_type = buf[0] & 0x1F;
	info->removable = (buf[1] & 0x80) ? TRUE : FALSE;

	memcpy(&info->vendor[0], (const void *)&buf[8], 8);
	memcpy(&info->product[0], (const void *)&buf[16], 16);
	memcpy(&info->revision[0], (const void *)&buf[32], 4);
	info->vendor[8] = 0;
	info->product[16] = 0;
	info->revision[4] = 0;

	INIT_SCSI_REQUEST(&srb, lun, NULL, 0);
	rc = scsi_test_unit_ready(&srb, tr, priv);
	if (rc) {
		return rc;
	}

	INIT_SCSI_REQUEST(&srb, lun, buf, sizeof(buf));
	rc = scsi_read_capacity(&srb, tr, priv);
	if (rc) {
		return rc;
	}
	cap = (u32 *)buf;
	cap[0] = vmm_cpu_to_be32(cap[0]);
	cap[1] = vmm_cpu_to_be32(cap[1]);

	info->capacity = cap[0] + 1;
	info->blksz = cap[1];

	info->readonly = TRUE;
	switch (info->perph_type) {
	case 0x00:
	case 0x0C:
	case 0x0E:
	case 0x0F:
		info->readonly = FALSE;
		break;
	default:
		break;
	};

	if (tr->info_fixup) {
		tr->info_fixup(info, tr, priv);
	}

	return VMM_OK;
}
Пример #6
0
/*********************************************************************************
 * (re)-scan the scsi bus and reports scsi device info
 * to the user if mode = 1
 */
void scsi_scan(int mode)
{
	unsigned char i,perq,modi,lun;
	lbaint_t capacity;
	unsigned long blksz;
	ccb* pccb=(ccb *)&tempccb;

	if(mode==1) {
		printf("scanning bus for devices...\n");
	}
	for(i=0;i<CONFIG_SYS_SCSI_MAX_DEVICE;i++) {
		scsi_dev_desc[i].target=0xff;
		scsi_dev_desc[i].lun=0xff;
		scsi_dev_desc[i].lba=0;
		scsi_dev_desc[i].blksz=0;
		scsi_dev_desc[i].type=DEV_TYPE_UNKNOWN;
		scsi_dev_desc[i].vendor[0]=0;
		scsi_dev_desc[i].product[0]=0;
		scsi_dev_desc[i].revision[0]=0;
		scsi_dev_desc[i].removable=FALSE;
		scsi_dev_desc[i].if_type=IF_TYPE_SCSI;
		scsi_dev_desc[i].dev=i;
		scsi_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
		scsi_dev_desc[i].block_read=scsi_read;
		scsi_dev_desc[i].block_write = scsi_write;
	}
	scsi_max_devs=0;
	for(i=0;i<CONFIG_SYS_SCSI_MAX_SCSI_ID;i++) {
		pccb->target=i;
		for(lun=0;lun<CONFIG_SYS_SCSI_MAX_LUN;lun++) {
			pccb->lun=lun;
			pccb->pdata=(unsigned char *)&tempbuff;
			pccb->datalen=512;
			scsi_setup_inquiry(pccb);
			if(scsi_exec(pccb)!=TRUE) {
				if(pccb->contr_stat==SCSI_SEL_TIME_OUT) {
					debug ("Selection timeout ID %d\n",pccb->target);
					continue; /* selection timeout => assuming no device present */
				}

				/* Device present at this target/lun
				 * but may not be ready yet.
				 */
				scsi_print_error(pccb);
				continue;
			}
			perq=tempbuff[0];
			modi=tempbuff[1];
			if((perq & 0x1f)==0x1f) {
				continue; /* skip unknown devices */
			}
			if((modi&0x80)==0x80) /* drive is removable */
				scsi_dev_desc[scsi_max_devs].removable=TRUE;
			/* get info for this device */
			scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].vendor[0],
				       &tempbuff[8], 8);
			scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].product[0],
				       &tempbuff[16], 16);
			scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].revision[0],
				       &tempbuff[32], 4);
			scsi_dev_desc[scsi_max_devs].target=pccb->target;
			scsi_dev_desc[scsi_max_devs].lun=pccb->lun;

			pccb->datalen=0;
			scsi_setup_test_unit_ready(pccb);
			if(scsi_exec(pccb)!=TRUE) {
				if(scsi_dev_desc[scsi_max_devs].removable==TRUE) {
					scsi_dev_desc[scsi_max_devs].type=perq;
					goto removable;
				}
				scsi_print_error(pccb);
				continue;
			}
			if (scsi_read_capacity(pccb, &capacity, &blksz)) {
				scsi_print_error(pccb);
				continue;
			}
			scsi_dev_desc[scsi_max_devs].lba=capacity;
			scsi_dev_desc[scsi_max_devs].blksz=blksz;
			scsi_dev_desc[scsi_max_devs].type=perq;
			init_part(&scsi_dev_desc[scsi_max_devs]);
removable:
			if(mode==1) {
				printf ("  Device %d: ", scsi_max_devs);
				dev_print(&scsi_dev_desc[scsi_max_devs]);
			} /* if mode */
			scsi_max_devs++;
		} /* next LUN */
	}
	if(scsi_max_devs>0)
		scsi_curr_dev=0;
	else
		scsi_curr_dev = -1;

	printf("Found %d device(s).\n", scsi_max_devs);
}
Пример #7
0
void DevOperate(DiscDCB *dcb, DiscReq *req)
{
	BYTE	  capacity_data[CAPACITY_LENGTH];
	WORD	  command_status,second_status;
	WORD	  block_addr, block_len;
	WORD	  done = 0;
	WORD	  size;
	BYTE	  *buf = req->Buf;
	INT	  res;
	BYTE sense_data[SENSE_LENGTH];

	FormatReq *freq;

	Wait(&dcb->Lock);

	/* Select the appropriate command */
	switch( req->DevReq.Request & FG_Mask)
	{
		case FG_Read:
#ifdef DEBUG
		IOdebug("read pos = %d size = %d",req->Pos / dcb->SectorSize,req->Size / dcb->SectorSize);
#endif
			size = req->Size;
			while( done < size )
			{
				WORD tfr = size - done;
				WORD position = (req->Pos / dcb->SectorSize) + (done/dcb->SectorSize);
				command_status = 8;/* make loop happen once*/
				if ( tfr > MAX_TFR )
				{
					tfr = MAX_TFR;
				}
				while (command_status == 8)
				  {
				  res = scsi_read(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
				  }

				if ( ( res < 0 ) || ( command_status ne 0 ))
					{
					 command_status = 8;
					 while (command_status == 8)
					   {
					   res = scsi_read(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
					   }
				}

				done += tfr;
				buf  += tfr;
			}

			req->DevReq.Result = command_status;
			if ( req->DevReq.Result eq 0 )
				req->Actual = req->Size;
			else
				req->Actual = 0;
			break;

		case FG_Write:
#ifdef DEBUG
			IOdebug("write pos = %d size = %d",req->Pos / dcb->SectorSize,req->Size / dcb->SectorSize);
#endif
			size = req->Size;
			while( done < size )
			{
				WORD tfr = size - done;
				WORD position = (req->Pos / dcb->SectorSize) + (done/dcb->SectorSize);
				command_status = 8; /* make loop happen once*/
				if ( tfr > MAX_TFR )
				{
					tfr = MAX_TFR;
				}
				while (command_status == 8)
				{
				  res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
				}
				if ( ( res < 0 ) || ( command_status ne 0 ))
				{
					command_status = 8;
					while (command_status == 8)
					{
					 res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status);
					}
				}
				done += tfr;
				buf  += tfr;
			}


			req->DevReq.Result = command_status;
			if ( req->DevReq.Result eq 0 )
				req->Actual = req->Size;
			else
				req->Actual = 0;
			break;

		case FG_GetSize:
#ifdef DEBUG
			IOdebug("read capacity request");
#endif
			command_status = 8;
			while (command_status == 8)
			{
			scsi_read_capacity(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,		/* lun		   */
				8,		/* capacity length */
				capacity_data,
				&command_status);
			}

			if ( command_status eq 0 )
			{
				block_addr = capacity_data[0] * 0x1000000 +
					     capacity_data[1] * 0x10000   +
					     capacity_data[2] * 0x100	  +
					     capacity_data[3];
				block_len  = capacity_data[4] * 0x1000000 +
					     capacity_data[5] * 0x10000   +
					     capacity_data[6] * 0x100	  +
					     capacity_data[7];
				req->DevReq.Result = block_addr * block_len;
			}
			break;
		case FG_Format:
			IOdebug("\rFormatting disk please wait ....");
			freq = (FormatReq *)req;


			command_status = 8;/* so the loop happens once*/
			while (command_status == 8)
			{
			scsi_mode_select(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				0,			/* format whole disk */
				dcb->SectorSize,
				&command_status);
			}
			command_status = 8;/* so the loop happens once*/
			while (command_status == 8)
			{
			scsi_format(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				freq->Interleave,
				&command_status);
			}
/* If the disk supports the busy status we need to wait until busy goes away
	before giving the message that we are verifying */

			command_status = 8;
			while (command_status == 8)
			{
			  scsi_test_unit_ready(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				&command_status);
			}
/* some disks will queue one command so we need to wait twice to cope with this
	*/
			command_status = 8;
			while (command_status != 0)
			{
			  IOdebug("status = %d",command_status);
			  scsi_test_unit_ready(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				&command_status);

			scsi_request_sense(
				dcb->Link,
				dcb->Table,
				dcb->DeviceId,
				0,
				SENSE_LENGTH,
				sense_data,
				&command_status);
			IOdebug("sense =%x",sense_data[2]);
			}


			{
			WORD	total_blocks;
			WORD	i,j;
			WORD	ten_cent,done = 0;
			BYTE	*data;

			IOdebug("\rVerifying disk please wait ....");
			data = Malloc(dcb->SectorSize);
			command_status = 8; /* do at least once*/
			while (command_status == 8 )
			{
				res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,1,dcb->SectorSize,dcb->SectorSize,data,&command_status);
			}
			total_blocks = (dcb->SectorsPerTrack * dcb->TracksPerCyl * dcb->Cylinders);
/*			IOdebug("\rdisk size is %d blocks",total_blocks);*/
			ten_cent =  total_blocks  / 10;
			for ( i = 1; i < total_blocks; i++)
			{
			 command_status = 8; /* you know by now*/
			 while (command_status == 8)
			 {
				 res = scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
			}
			second_status = 8;
			while (second_status == 8)
			{
			 res = scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
			}
					 if (( i % ten_cent )  eq 0)
				{
					done += 10;
					IOdebug("\rVerified %d percent of disk\v",done);
				}
				if ((command_status ne 0) || (second_status ne 0))
				{
					command_status = 8;
					while (command_status == 8 )
					{
					scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
					}
					second_status = 8;
					while (second_status == 8)
					{
					scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
					}
					if (( command_status  ne 0 ) || (second_status ne 0))
					{
						IOdebug("Verifier found bad block at %d",i);
						for( j = 0; j  < 10; j++)
						{
							command_status = 8;
							while (command_status == 8)
							{
							scsi_reassign_block(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
							}
							command_status = 8;
							while (command_status == 8)
							{
							scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status);
							}
							second_status = 8;
							while (second_status == 8)
							{
							scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status);
							}
							if ((command_status eq 0) && (second_status eq 0))break;
						}
						if  (( command_status eq 0 ) && (second_status eq 0))
							IOdebug("Block %d reassigned OK",i);
						else
							IOdebug("Failed to reassign block %d",i);
					}
				}
			}

			}
			IOdebug("Verification complete                         ");
			req->DevReq.Result = 0;
			break;
		default:
			break;
		}
		/* Unlock the driver */
		Signal(&dcb->Lock);
		/* Client action */
		(*req->DevReq.Action)(req);
		return;
}
Пример #8
0
/*********************************************************************************
 * (re)-scan the scsi bus and reports scsi device info
 * to the user if mode = 1
 */
void scsi_scan(int mode)
{
    unsigned char i,perq,modi,lun;
    lbaint_t capacity;
    unsigned long blksz;
    ccb* pccb=(ccb *)&tempccb;
    static int scsi_detected = 0;

    if (scsi_detected) {
        printf("** scsi detection can run only once - please");
        printf(" reset board before running detection again **\n");
        return;
    }
    scsi_detected = 1;

    if(mode==1) {
        printf("scanning bus for devices...\n");
    }

    if (tempbuff == NULL) {
        tempbuff = memalign(ARCH_DMA_MINALIGN, 512);
        if (tempbuff == NULL) {
            if (mode == 1)
                printf("error: cannot allocate buffer\n");
            return;
        }
    }

    for(i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) {
        scsi_dev_desc[i].target=0xff;
        scsi_dev_desc[i].lun=0xff;
        scsi_dev_desc[i].lba=0;
        scsi_dev_desc[i].blksz=0;
        scsi_dev_desc[i].log2blksz =
            LOG2_INVALID(typeof(scsi_dev_desc[i].log2blksz));
        scsi_dev_desc[i].type=DEV_TYPE_UNKNOWN;
        scsi_dev_desc[i].vendor[0]=0;
        scsi_dev_desc[i].product[0]=0;
        scsi_dev_desc[i].revision[0]=0;
        scsi_dev_desc[i].removable=FALSE;
        scsi_dev_desc[i].if_type=IF_TYPE_SCSI;
        scsi_dev_desc[i].dev=i;
        scsi_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
        scsi_dev_desc[i].block_read=scsi_read;
        scsi_dev_desc[i].block_write = scsi_write;
    }
    scsi_max_devs=0;
    for(i=0; i<CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
        pccb->target=i;
        for(lun=0; lun<CONFIG_SYS_SCSI_MAX_LUN; lun++) {
            pccb->lun=lun;
            pccb->pdata = (unsigned char *)tempbuff;
            pccb->datalen=512;
            scsi_setup_inquiry(pccb);
            if(scsi_exec(pccb)!=TRUE) {
                if(pccb->contr_stat==SCSI_SEL_TIME_OUT) {
                    debug ("Selection timeout ID %d\n",pccb->target);
                    continue; /* selection timeout => assuming no device present */
                }
                scsi_print_error(pccb);
                continue;
            }
            perq=tempbuff[0];
            modi=tempbuff[1];
            if((perq & 0x1f)==0x1f) {
                continue; /* skip unknown devices */
            }
            if((modi&0x80)==0x80) /* drive is removable */
                scsi_dev_desc[scsi_max_devs].removable=TRUE;
            /* get info for this device */
            scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].vendor[0],
                           &tempbuff[8], 8);
            scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].product[0],
                           &tempbuff[16], 16);
            scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].revision[0],
                           &tempbuff[32], 4);
            scsi_dev_desc[scsi_max_devs].target=pccb->target;
            scsi_dev_desc[scsi_max_devs].lun=pccb->lun;

            pccb->datalen=0;
            scsi_setup_test_unit_ready(pccb);
            if(scsi_exec(pccb)!=TRUE) {
                if(scsi_dev_desc[scsi_max_devs].removable==TRUE) {
                    scsi_dev_desc[scsi_max_devs].type=perq;
                    goto removable;
                }
                scsi_print_error(pccb);
                continue;
            }
            if (scsi_read_capacity(pccb, &capacity, &blksz)) {
                scsi_print_error(pccb);
                continue;
            }
            scsi_dev_desc[scsi_max_devs].lba=capacity;
            scsi_dev_desc[scsi_max_devs].blksz=blksz;
            scsi_dev_desc[scsi_max_devs].log2blksz =
                LOG2(scsi_dev_desc[scsi_max_devs].blksz);
            scsi_dev_desc[scsi_max_devs].type=perq;
            init_part(&scsi_dev_desc[scsi_max_devs]);
removable:
            if(mode==1) {
                printf ("  Device %d: ", scsi_max_devs);
                dev_print(&scsi_dev_desc[scsi_max_devs]);
            } /* if mode */
            scsi_max_devs++;
        } /* next LUN */
    }
    if (scsi_max_devs > 0)
        scsi_curr_dev = 0;
    else
        scsi_curr_dev = -1;

    printf("Found %d device(s).\n", scsi_max_devs);
    setenv_ulong("scsidevs", scsi_max_devs);
}
Пример #9
0
/*ARGSUSED*/
scsi_ret_t
scdisk_open(
	target_info_t		*tgt,
	io_req_t	        req)
{
	register int 	i;
	register scsi_ret_t	ret = SCSI_RET_SUCCESS;
	unsigned int		disk_size, secs_per_cyl, sector_size;
	unsigned int		nsectors, ntracks, ncylinders;
	scsi_rcap_data_t	*cap;
	struct disklabel	*label = 0;
	io_req_t		ior;
	void			(*readfun)(
					target_info_t	*tgt,
					unsigned int	secno,
					io_req_t	ior) = scdisk_read;
	char			*data, *rdata = 0;
	boolean_t		look_for_label;

	if (tgt->flags & TGT_ONLINE)
		return SCSI_RET_SUCCESS;

	tgt->lun = rzlun(req->io_unit);

	/*
	 * Dummy ior for proper sync purposes
	 */
	io_req_alloc(ior);
	bzero((char *)ior, sizeof(*ior));
	simple_lock_init(&(ior)->io_req_lock, ETAP_IO_REQ);

#if 0
	/*
	 * Set the LBN to tgt->block_size with a MODE SELECT.
	 * xxx do a MODE SENSE instead ?
	 */
	/*
	 * Ugh.  Can't use tgt->block_size here -- not set up
	 * yet.  Also can't use DEV_BSIZE.  So...since MK6
	 * dispenses with this command entirely, let's do
	 * so as well.
	 */
	for (i = 0; i < 5; i++) {
		ior->io_op = IO_INTERNAL;
		ior->io_error = 0;
		ret = scdisk_mode_select(tgt, tgt->block_size, ior,0,0,FALSE);
		if (ret == SCSI_RET_SUCCESS)
			break;
		if (ret == SCSI_RET_RETRY) {
			timeout((timeout_fcn_t)wakeup, tgt, 2*hz);
			await(tgt);
		}
		if (ret == SCSI_RET_DEVICE_DOWN)
			goto done;
	}
	if (ret != SCSI_RET_SUCCESS) {
		scsi_error( tgt, SCSI_ERR_MSEL, ret, 0);
		ret = D_INVALID_SIZE;
		goto done;
	}
#endif

#ifdef hp_pa
	if (tgt->flags & TGT_REMOVABLE_MEDIA) {
		scsi_mode_sense_page5_t	*page5;
		unsigned char           mode_save[0xff];
		scsi_mode_select_param_t *parm;
		int length;

		if((ret = scsi_mode_sense(tgt, 0x05, 0xff, 0))
		   != SCSI_RET_SUCCESS) 
			goto done;

		length = *tgt->cmd_ptr + 1;
		bcopy(tgt->cmd_ptr, mode_save, length);

		page5 = (scsi_mode_sense_page5_t *)(mode_save + 4 + mode_save[3]);
#if 1 
		/* force sector size to 512 */
		parm = (scsi_mode_select_param_t *)mode_save;

		parm->reserved1 = 0;
		parm->medium_type = 2;
		parm->device_spec &= ~0x90;
			
		parm->descs[0].density_code = 2; 
		parm->descs[0].nblocks1 = 0;
		parm->descs[0].nblocks2 = 0;
		parm->descs[0].nblocks3 = 0;
		parm->descs[0].reclen1 = 0x2;
		parm->descs[0].reclen2 = 0;
		parm->descs[0].reclen3 = 0;

		page5->ps = 0;
		page5->page_code &= ~0x80;
		
		page5->sectors_per_track = page5->sectors_per_track * 
			(page5->bytes_per_sector_msb << 8 |
			 page5->bytes_per_sector_lsb) /
				 512;
		
		page5->bytes_per_sector_msb = 2;
		page5->bytes_per_sector_lsb = 0;
			
		length -= parm->desc_len;
		parm->desc_len = 0;
		bcopy((const char*)page5, mode_save+4, sizeof(*page5));
		
		if((ret = scdisk_mode_select(tgt, 0, 0, mode_save, length, 0)) 
		   != SCSI_RET_SUCCESS) 
			goto done;

		if((ret = scsi_mode_sense(tgt, 0x05, 0xff, 0))
		   != SCSI_RET_SUCCESS) 
			goto done;

		length = *tgt->cmd_ptr + 1;
		bcopy(tgt->cmd_ptr, mode_save, length);
#endif

		ntracks      = page5->number_of_heads;
		nsectors     = page5->sectors_per_track;
		sector_size  = page5->bytes_per_sector_msb << 8 |
			page5->bytes_per_sector_lsb;
		ncylinders   = page5->number_of_cylinders_msb << 8 |
			page5->number_of_cylinders_lsb;
		secs_per_cyl = nsectors * ntracks;

		look_for_label = FALSE;
		geom_done = TRUE;
	}
#endif

	/*
	 * Do a READ CAPACITY to get max size. Check LBN too.
	 */
	for (i = 0; i < 5; i++) {
		ior->io_op = IO_INTERNAL;
		ior->io_error = 0;
		ret = scsi_read_capacity(tgt, 0, ior);
		if (ret == SCSI_RET_SUCCESS)
			break;
		if (ret == SCSI_RET_RETRY) {
			timeout((timeout_fcn_t)wakeup, tgt, 2*hz);
			await(tgt);
		}
		if (ret == SCSI_RET_DEVICE_DOWN)
			goto done;
	}
	if (ret != SCSI_RET_SUCCESS) {
		scsi_error( tgt, SCSI_ERR_MSEL, ret, 0);
		ret = D_INVALID_SIZE;
		goto done;
	}

	cap = (scsi_rcap_data_t*) tgt->cmd_ptr;
	disk_size = (cap->lba1<<24) |
	  	    (cap->lba2<<16) |
		    (cap->lba3<< 8) |
		     cap->lba4 + 1;
	if (scsi_debug)
		printf("rz%d holds %d blocks\n", tgt->unit_no, disk_size);

	tgt->block_size = (cap->blen1<<24) |
	  		  (cap->blen2<<16) |
	    		  (cap->blen3<<8 ) |
			   cap->blen4;

	if (scsi_debug) {
		printf("rz%d block size is %d bytes/block\n",
			       tgt->unit_no, tgt->block_size);
	}

	if (tgt->block_size > RZDISK_MAX_SECTOR || tgt->block_size <= 0) {
	 	 ret = D_INVALID_SIZE;
	  	goto done;
       	}

        rdata = (char *) kalloc(2*tgt->block_size);
	if (round_page(rdata) == round_page(rdata + tgt->block_size))
	    data = rdata;
	else
	    data = (char *)round_page(rdata);
#ifdef POWERMAC
	/* XXX TODO NMGS remove! must be cache aligned for now */
	if ((unsigned long)data & 0x1f)
		data = (char*)((unsigned long)(data + 0x1f) & ~0x1f);
	if (round_page(data) != round_page(data + tgt->block_size))
		data = (char *)round_page(data);
#endif /* POWERMAC */

	if (disk_size > SCSI_CMD_READ_MAX_LBA)
		tgt->flags |= TGT_BIG;

	/*
	 * Mandatory long-form commands ?
	 */
	if (BGET(scsi_use_long_form,(unsigned char)tgt->masterno,tgt->target_id))
		tgt->flags |= TGT_BIG;
	if (tgt->flags & TGT_BIG)
		readfun = scsi_long_read;

	ior->io_op = IO_INTERNAL;
	ior->io_error = 0;

#ifdef hp_pa
	if(geom_done)
		goto setup_label;
#endif

	/*
	 * Find out about the phys disk geometry
	 */

#if	PARAGON860

	/*
	 * The NCR RAID controller does not support a read capacity command
	 * with the Partial Medium Indicator (PMI) bit set.  Therefore we
	 * have to calculate the number of sectors per cylinder from data
	 * in the mode select pages.  This method should work for standalone
	 * disks as well.
	 */

	/*
	 * Read page 3 to find the number of sectors/track and bytes/sector
	 */
	ret = scsi_mode_sense(tgt, 0x03, 0xff, ior);
	/* scsi_error(...) */
	{
		scsi_mode_sense_page3_t	*page3;

		page3 = (scsi_mode_sense_page3_t *)
			(((scsi_mode_sense_data_t *)tgt->cmd_ptr) + 1);

		nsectors    = (page3->sectors_per_track_msb << 8) |
			       page3->sectors_per_track_lsb;

		sector_size = (page3->bytes_per_sector_msb  << 8) |
			       page3->bytes_per_sector_lsb;
	}

	ior->io_op = IO_INTERNAL;
	ior->io_error = 0;

	/*
	 * Read page 4 to find the number of cylinders and tracks/cylinder
	 */
	ret = scsi_mode_sense(tgt, 0x04, 0xff, ior);
	/* scsi_error(...) */
	{
		scsi_mode_sense_page4_t	*page4;

		page4 = (scsi_mode_sense_page4_t *)
			(((scsi_mode_sense_data_t *)tgt->cmd_ptr) + 1);

		ncylinders = (page4->number_of_cylinders_msb << 16) |
			     (page4->number_of_cylinders     <<  8) |
			      page4->number_of_cylinders_lsb;

		ntracks    = page4->number_of_heads;
	}

	/*
	 * Calculate the sectors per cylinder (sec/track * tracks/cyl)
	 */
	secs_per_cyl = nsectors * ntracks;

	if (scsi_debug) {
		printf("rz%d: %d bytes/sec %d sec/track\n", tgt->unit_no,
			sector_size, nsectors);
		printf("     %d tracks/cyl %d cyl/unit\n",
			ntracks, ncylinders);
	}

#else	/* PARAGON860 */
       /* Read page one to get read / write error recovery info */
       ret = scsi_mode_sense(tgt, 0x01, 0xff, ior);
       if(ret == SCSI_RET_SUCCESS) {
               scsi_mode_sense_page1_t *page1;
               unsigned char           mode_save[0xff];
               int length;

               length = *tgt->cmd_ptr + 1;
               bcopy(tgt->cmd_ptr, mode_save, length);

               page1 = (scsi_mode_sense_page1_t *)(mode_save + 4 + mode_save[3]);

               *mode_save = 0;         /* mode data length */
               page1->ps       = 0;
               page1->flags    = PAGE1_AWRE | PAGE1_ARRE | PAGE1_TB | PAGE1_PER;

               /*
                * Enable automatic reallocation of bad blocks,
                * Report any recovered errors.
                */
               ior->io_op = IO_INTERNAL;
               ior->io_error = 0;
               ret = scdisk_mode_select(tgt, 0, ior, mode_save, length, 0);
               if(ret != SCSI_RET_SUCCESS) {
		       if (scsi_debug)
                       printf("rz%d: Can't change error recovery parameters\n",
                                tgt->unit_no);
	       }
       }

       ior->io_op = IO_INTERNAL;
       ior->io_error = 0;

#ifdef	POWERMAC
	tgt->flags |= TGT_OPTIONAL_CMD;
#endif
		
	ret = scsi_read_capacity( tgt, 1, ior);
#ifdef POWERMAC
	tgt->flags &= ~TGT_OPTIONAL_CMD;
#endif
	/* scsi_error(...) */
	if (ret) {
		secs_per_cyl = 16;
		sector_size = tgt->block_size;
	} else {
		cap = (scsi_rcap_data_t*) tgt->cmd_ptr;
		secs_per_cyl =	(cap->lba1<<24) | (cap->lba2<<16) |
				(cap->lba3<< 8) |  cap->lba4;
		secs_per_cyl += 1;
		sector_size =	(cap->blen1<<24) | (cap->blen2<<16) |
			(cap->blen3<<8 ) |  cap->blen4;
	}
	if (scsi_debug)
	printf("rz%d: %d sect/cyl %d bytes/sec\n", tgt->unit_no,
		secs_per_cyl, sector_size);
#endif	/* PARAGON860 */

#if	NSCSI2 > 0
	/*
	 * ... and a bunch of other things for scsi2
	 */
#endif	/* NSCSI2 > 0 */

	/*
	 * Get partition table off pack
	 */

	if (tgt->dev_ops == &scsi_devsw[SCSI_CDROM]) {
		/* no label on a CD-ROM */
		look_for_label = FALSE;
	} else {
		look_for_label = TRUE;
	}

 setup_label:


	if (look_for_label) {
		/* first look for a BSD label */	
		ior->io_data = data;
		ior->io_count = tgt->block_size;
		ior->io_op = IO_READ;
		ior->io_error = 0;
		tgt->ior = ior;
		(*readfun)( tgt, LABELOFFSET/tgt->block_size, ior);
		iowait(ior);

		if (!ior->io_error) {
			/* Search for BSD label, might be a bit further along */
			register int	j;

			for (i = LABELOFFSET % tgt->block_size;
			     i < (tgt->block_size-sizeof(struct disklabel));
			     i += sizeof(int)) {
				label = (struct disklabel *) &data[i];
				if (label->d_magic  == DISKMAGIC &&
				    label->d_magic2 == DISKMAGIC) {
					break;
				} else
					label = (struct disklabel *) 0;
			}
		}
	} else {
		label = (struct disklabel *) 0;
	}

	if (label) {
		if (scsi_debug)
			printf("{Using BSD label}");
		tgt->dev_info.disk.l = *label;
	} else {
		/* then look for a vendor's label, but first
		   fill in defaults and what we found */

		label = &tgt->dev_info.disk.l;
		*label = scsi_default_label;
		label->d_secsize    = sector_size;
		label->d_nsectors   = nsectors;
		label->d_ntracks    = ntracks;
		label->d_ncylinders = ncylinders;
		label->d_secpercyl  = secs_per_cyl;
		label->d_secperunit = disk_size;

		ior->io_data = data;
		if (!look_for_label || !rz_vendor_label(tgt, label, ior)) {

			if (look_for_label) {
				printf("%s rz%d, %s\n",
				       "WARNING: No valid disk label on",
				       tgt->unit_no,
				       "using defaults");
			}

			/* Validate partitions a and c for initialization */
			tgt->dev_info.disk.l.d_partitions[0].p_offset = 0;
			tgt->dev_info.disk.l.d_partitions[0].p_size   = disk_size;
			tgt->dev_info.disk.l.d_partitions[2].p_offset = 0;
			tgt->dev_info.disk.l.d_partitions[2].p_size   = disk_size;
			tgt->dev_info.disk.l.d_partitions[MAXPARTITIONS].p_offset = 0;
			tgt->dev_info.disk.l.d_partitions[MAXPARTITIONS].p_size   = -1;
		}
		label->d_checksum = 0;
		label->d_checksum = dkcksum(label);
	}

	ret = SCSI_RET_SUCCESS;
done:
        if (rdata)
                kfree((vm_offset_t) rdata, 2 * tgt->block_size);
	io_req_free(ior);
	return ret;
}
Пример #10
0
void scsi_proc(void)
{
    if (USBD_ep_buffer_full(BOMS_EP_DATA_OUT)) {
        if (sizeof(BOMSCmd) == USBD_transfer(BOMS_EP_DATA_OUT, (uint8_t *)&BOMSCmd, sizeof(BOMSCmd))) {
            if (BOMSCmd.dCBWSignature == BOMS_USBC) {
                if (BOMSCmd.CBWCB.unit_ready.op_code == BOMS_SCSI_TEST_UNIT_READY) // SCSI Test Unit Ready
                {
                    scsi_test_unit_ready(&BOMSCmd);
                } 
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_READ) // SCSI Read
                {
                    scsi_read(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_WRITE) // SCSI Write
                {
                    scsi_write(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.inquiry.op_code == BOMS_SCSI_INQUIRY) // SCSI Inquiry
                {
                    scsi_inquiry(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_REQUEST_SENSE) // SCSI Request Sense
                {
                    scsi_request_sense(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.read_capacity.op_code == BOMS_SCSI_READ_CAPACITY) // SCSI Read Capacity (10)
                {
                    scsi_read_capacity(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.read_capacity.op_code == BOMS_SCSI_READ_FORMAT_CAPACITY) // SCSI Read Format Capacity (10)
                {
                    scsi_read_format_capacity(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.mode_sense.op_code == BOMS_SCSI_MODE_SENSE) // SCSI Mode Sense
                {
                    scsi_mode_sense(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_READ_CAPACITY_16) // SCSI Read Capacity (16)
                {
                    scsi_read_capacity(&BOMSCmd);
                }
                else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_PREVENT_ALLOW_REMOVAL) // SCSI Prevent Allow Removal
                {
                    scsi_prevent_allow_removal(&BOMSCmd);
                }
                else
                {
                    // Send IN a zero length packet.
                    if (BOMSCmd.dCBWDataTransferLength)
                    {
                        USBD_stall_endpoint(BOMS_EP_DATA_IN);
                    }
                    boms_send_status(BOMS_STATUS_COMMAND_FAILED, &BOMSCmd);
                    scsi_sense_illegal_request_command();
                }
            }
            else
            {
                // Was not a USBC signature.
                boms_send_status(BOMS_STATUS_PHASE_ERROR, &BOMSCmd);
                scsi_sense_illegal_request_cdb();
            }
        }else{
            // Wrong command size.
            boms_send_status(BOMS_STATUS_COMMAND_FAILED, &BOMSCmd);
            scsi_sense_illegal_request_parm();
        }
    }
}