Package org.jnode.driver.block.ide.disk

Source Code of org.jnode.driver.block.ide.disk.IDEDiskDriver$IDEDiskBus

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

package org.jnode.driver.block.ide.disk;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.jnode.bootlog.BootLogInstance;
import org.jnode.driver.Bus;
import org.jnode.driver.Device;
import org.jnode.driver.DeviceAlreadyRegisteredException;
import org.jnode.driver.DeviceManager;
import org.jnode.driver.Driver;
import org.jnode.driver.DriverException;
import org.jnode.driver.block.BlockDeviceAPI;
import org.jnode.driver.block.BlockDeviceAPIHelper;
import org.jnode.driver.bus.ide.IDEBus;
import org.jnode.driver.bus.ide.IDEConstants;
import org.jnode.driver.bus.ide.IDEDevice;
import org.jnode.driver.bus.ide.IDEDeviceAPI;
import org.jnode.driver.bus.ide.IDEDeviceFactory;
import org.jnode.driver.bus.ide.IDEDriveDescriptor;
import org.jnode.driver.bus.ide.IDEDriverUtils;
import org.jnode.driver.bus.ide.command.IDERWSectorsCommand;
import org.jnode.driver.bus.ide.command.IDEReadSectorsCommand;
import org.jnode.driver.bus.ide.command.IDEWriteSectorsCommand;
import org.jnode.naming.InitialNaming;
import org.jnode.partitions.ibm.IBMPartitionTable;
import org.jnode.partitions.ibm.IBMPartitionTableEntry;
import org.jnode.util.TimeoutException;

/**
* Device driver for IDE disks.
*
* @author epr
*/
public class IDEDiskDriver extends Driver
    implements IDEDeviceAPI<IBMPartitionTableEntry>, IDEConstants {

    /**
     * My logger
     */
    private static final Logger log = Logger.getLogger(IDEDiskDriver.class);

    /**
     * Number of addressable sectors
     */
    private long maxSector;

    /** Has LBA support? */
    //private boolean lba;

    /** Has DMA support? */
    //private boolean dma;

    /**
     * Support 48-bit addressing?
     */
    private boolean is48bit;
    private IDEDiskBus diskBus;
    private IBMPartitionTable pt;

    protected void startDevice() throws DriverException {
        final IDEDevice dev = (IDEDevice) getDevice();
        diskBus = new IDEDiskBus(dev);
        /* Register the IDEDevice API */
        dev.registerAPI(IDEDeviceAPI.class,
            new IDEDeviceBlockAlignmentSupport<IBMPartitionTableEntry>(this, SECTOR_SIZE));

        /* Get basic configuration */
        final IDEDriveDescriptor descr = dev.getDescriptor();
        //lba = descr.supportsLBA();
        //dma = descr.supportsDMA();
        is48bit = descr.supports48bitAddressing();
        maxSector = descr.getSectorsAddressable();

        // Look for partitions
        try {
            // Find the devicemanager
            DeviceManager devMan = InitialNaming.lookup(DeviceManager.NAME);
            // Read the bootsector
            final byte[] bs1 = new byte[SECTOR_SIZE];
            read(0, ByteBuffer.wrap(bs1));

            // Read the bootsector twice, since the first read seems to fail.
            // todo: THIS IS A WORKAROUND
            final byte[] bs = new byte[SECTOR_SIZE];
            read(0, ByteBuffer.wrap(bs));

            IDEDeviceFactory factory;
            try {
                factory = IDEDriverUtils.getIDEDeviceFactory();
            } catch (NamingException ex) {
                throw new DriverException(ex);
            }
            log.debug("Creating partition table object on " + dev.getId());
            this.pt = factory.createIBMPartitionTable(bs, dev);
            log.debug("Created partition table object");

            int partIndex = 0;
            int i = 0;
            for (IBMPartitionTableEntry pte : pt) {
                log.debug("Processing partition " + i);
                if (pte == null) {
                    BootLogInstance.get().warn("PartitionTableEntry #" + i + " is null");
                } else if (pte.isValid()) {
                    log.debug("Partition " + i + " is valid");
                    registerPartition(devMan, dev, pte, partIndex);
                }
                partIndex++;
                i++;
            }
            if (!pt.getExtendedPartitions().isEmpty()) {
                // Create partition devices for the extended partition
                log.debug("Extended");
                partIndex = registerExtendedPartition(devMan, dev, partIndex);
            }
        } catch (DeviceAlreadyRegisteredException ex) {
            log.error("Partition device is already known");
            throw new DriverException("Partition device is already known???? Probably a bug", ex);
        } catch (IOException ex) {
            log.error("Cannot read partition table", ex);
            throw new DriverException("Cannot read partition table", ex);
        } catch (NameNotFoundException ex) {
            log.error("Cannot find DeviceManager", ex);
            throw new DriverException("Cannot find DeviceManager", ex);
        } catch (Throwable ex) {
            log.error("Unknown error", ex);
            throw new DriverException("Unknown error", ex);
        }
    }

    protected void stopDevice() throws DriverException {
        final IDEDevice dev = (IDEDevice) getDevice();
        // find mounted partitions on this device and unregister them !
        try {
            DeviceManager devMan = InitialNaming.lookup(DeviceManager.NAME);
            Collection<Device> devices = devMan.getDevices();
            final ArrayList<IDEDiskPartitionDevice> toStop = new ArrayList<IDEDiskPartitionDevice>();

            for (Device device : devices) {
                if (device instanceof IDEDiskPartitionDevice) {
                    IDEDiskPartitionDevice partition = (IDEDiskPartitionDevice) device;
                    if (partition.getParent() == dev) {
                        toStop.add(partition);
                    }
                }

            }

            for (IDEDiskPartitionDevice partition : toStop) {
                devMan.unregister(partition);
            }
        } catch (NameNotFoundException e) {
            throw new DriverException("Problem while stopping this IDE device", e);
        }

        dev.unregisterAPI(BlockDeviceAPI.class);
        this.pt = null;
    }

    public void flush() {
        // Nothing to do yet
    }

    public long getLength() {
        return maxSector * SECTOR_SIZE;
    }

    public void read(long devOffset, ByteBuffer destBuf) throws IOException {
        transfer(devOffset, destBuf, false);
    }

    public void write(long devOffset, ByteBuffer srcBuf) throws IOException {
        transfer(devOffset, srcBuf, true);
    }

    protected void transfer(long devOffset, ByteBuffer buf, boolean isWrite) throws IOException {
//        int bufOffset = 0;
        int length = buf.remaining();
        if (length < SECTOR_SIZE) {
            log.debug("Transfer length=" + length + (isWrite ? " Wr " : " Rd "));
        }

        BlockDeviceAPIHelper.checkBounds(this, devOffset, length);
        BlockDeviceAPIHelper.checkAlignment(SECTOR_SIZE, this, devOffset, length);

        final long lbaStart = devOffset / SECTOR_SIZE;
        final int sectors = length / SECTOR_SIZE;

        final String errorSource = isWrite ? "write" : "read";
        if (lbaStart + sectors > this.maxSector) {
            throw new IOException(errorSource + " beyond device sectors");
        }

        final IDEDevice dev = (IDEDevice) getDevice();
        final IDEBus bus = (IDEBus) dev.getBus();
        final int maxSectorCount = is48bit ? MAX_SECTOR_COUNT_48 : MAX_SECTOR_COUNT_28;
        final boolean primary = dev.isPrimary();
        final boolean master = dev.isMaster();

        while (length > 0) {
            final long partLbaStart = devOffset / SECTOR_SIZE;
            final int partSectorCount = Math.min(length / SECTOR_SIZE, maxSectorCount);
            final int partLength = partSectorCount * SECTOR_SIZE;

            final IDERWSectorsCommand cmd = isWrite ?
                new IDEWriteSectorsCommand(primary, master, is48bit, partLbaStart, partSectorCount, buf) :
                new IDEReadSectorsCommand(primary, master, is48bit, partLbaStart, partSectorCount, buf);
            try {
                log.debug("bus.exAndWt" + (isWrite ? "W" : "R") + " dev=" + dev.getId() + " start=" + partLbaStart +
                    " sectors=" + partSectorCount + " len=" + partLength);
                bus.executeAndWait(cmd, IDE_DATA_XFER_TIMEOUT);
            } catch (InterruptedException ex) {
                throw new IOException("IDE " + errorSource + " interrupted", ex);
            } catch (TimeoutException ex) {
                throw new InterruptedIOException("IDE timeout: " + ex.getMessage());
            }
            if (cmd.hasError()) {
                throw new IOException("IDE " + errorSource + " error:" + cmd.getError());
            }

            length -= partLength;
            devOffset += partLength;
        }
    }

    static class IDEDiskBus extends Bus {

        public IDEDiskBus(IDEDevice parent) {
            super(parent);
        }
    }

    /*
     * Register the given partition entry (maybe an extended partition entry)
     */
    private void registerPartition(DeviceManager devMan, IDEDevice dev,
                                   IBMPartitionTableEntry pte, int partIndex)
        throws DeviceAlreadyRegisteredException, DriverException {
        final String id = dev.getId() + partIndex;
        final IDEDiskPartitionDevice pdev =
            new IDEDiskPartitionDevice(
                diskBus,
                id,
                dev,
                pte,
                pte.getStartLba(),
                pte.getNrSectors());
        pdev.setDriver(new IDEDiskPartitionDriver());
        devMan.register(pdev);
    }

    /**
     * register all the partitions included in the extended partition
     *
     * @param devMan
     * @param dev
     * @param partIndex the first partition index to use
     * @return the next partition index
     * @throws DeviceAlreadyRegisteredException
     *
     * @throws DriverException
     */
    private int registerExtendedPartition(DeviceManager devMan, IDEDevice dev, int partIndex)
        throws DeviceAlreadyRegisteredException, DriverException {
        //now we should have an filled vector in the pt
        final List<IBMPartitionTableEntry> extendedPartitions = pt.getExtendedPartitions();
        log.info("Have " + extendedPartitions.size() + " Extended partitions found");

        for (int iPart = 0; iPart < extendedPartitions.size(); iPart++) {
            IBMPartitionTableEntry pteExt = extendedPartitions.get(iPart);
            registerPartition(devMan, dev, pteExt, partIndex);

            if (iPart < (extendedPartitions.size() - 1)) {
                partIndex++;
            }
        }
        return partIndex;
    }

    public int getSectorSize() throws IOException {
        return SECTOR_SIZE;
    }

    /**
     * Gets the partition table that this block device contains.
     *
     * @return {@code null} if no partition table is found.
     * @throws IOException
     */
    public IBMPartitionTable getPartitionTable() throws IOException {
        return pt;
    }
}
TOP

Related Classes of org.jnode.driver.block.ide.disk.IDEDiskDriver$IDEDiskBus

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.