Print this page
10567 lofi should support basic EFI ioctl()s

@@ -166,10 +166,12 @@
 #include <sys/rctl.h>
 #include <sys/vtoc.h>
 #include <sys/scsi/scsi.h>      /* for DTYPE_DIRECT */
 #include <sys/scsi/impl/uscsi.h>
 #include <sys/sysevent/dev.h>
+#include <sys/efi_partition.h>
+#include <sys/note.h>
 #include <LzmaDec.h>
 
 #define NBLOCKS_PROP_NAME       "Nblocks"
 #define SIZE_PROP_NAME          "Size"
 #define ZONE_PROP_NAME          "zone"

@@ -1739,30 +1741,62 @@
         bp->b_private = (void *)(uintptr_t)p_lba;       /* partition start */
         (void) taskq_dispatch(lsp->ls_taskq, lofi_strategy_task, bp, KM_SLEEP);
         return (0);
 }
 
-/*ARGSUSED2*/
 static int
 lofi_read(dev_t dev, struct uio *uio, struct cred *credp)
 {
+        _NOTE(ARGUNUSED(credp));
+
         if (getminor(dev) == 0)
                 return (EINVAL);
         UIO_CHECK(uio);
         return (physio(lofi_strategy, NULL, dev, B_READ, minphys, uio));
 }
 
-/*ARGSUSED2*/
 static int
 lofi_write(dev_t dev, struct uio *uio, struct cred *credp)
 {
+        _NOTE(ARGUNUSED(credp));
+
         if (getminor(dev) == 0)
                 return (EINVAL);
         UIO_CHECK(uio);
         return (physio(lofi_strategy, NULL, dev, B_WRITE, minphys, uio));
 }
 
+static int
+lofi_urw(struct lofi_state *lsp, uint16_t fmode, diskaddr_t off, size_t size,
+    intptr_t arg, int flag, cred_t *credp)
+{
+        struct uio uio;
+        iovec_t iov;
+
+        /*
+         * 1024 * 1024 apes cmlb_tg_max_efi_xfer as a reasonable max.
+         */
+        if (size == 0 || size > 1024 * 1024 ||
+            (size % (1 << lsp->ls_lbshift)) != 0)
+                return (EINVAL);
+
+        iov.iov_base = (void *)arg;
+        iov.iov_len = size;
+        uio.uio_iov = &iov;
+        uio.uio_iovcnt = 1;
+        uio.uio_loffset = off;
+        uio.uio_segflg = (flag & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
+        uio.uio_llimit = MAXOFFSET_T;
+        uio.uio_resid = size;
+        uio.uio_fmode = fmode;
+        uio.uio_extflg = 0;
+
+        return (fmode == FREAD ?
+            lofi_read(lsp->ls_dev, &uio, credp) :
+            lofi_write(lsp->ls_dev, &uio, credp));
+}
+
 /*ARGSUSED2*/
 static int
 lofi_aread(dev_t dev, struct aio_req *aio, struct cred *credp)
 {
         if (getminor(dev) == 0)

@@ -3186,10 +3220,11 @@
     int *rvalp)
 {
         int     error;
         enum dkio_state dkstate;
         struct lofi_state *lsp;
+        dk_efi_t user_efi;
         int     id;
 
         id = LOFI_MINOR2ID(getminor(dev));
 
         /* lofi ioctls only apply to the master device */

@@ -3436,10 +3471,39 @@
                 if (ddi_copyout(&uscmd, (void *)arg, sizeof (uscmd), flag) != 0)
                         return (EFAULT);
 #endif  /* _MULTI_DATAMODEL */
                 return (0);
         }
+
+        case DKIOCGMBOOT:
+                return (lofi_urw(lsp, FREAD, 0, 1 << lsp->ls_lbshift,
+                    arg, flag, credp));
+
+        case DKIOCSMBOOT:
+                return (lofi_urw(lsp, FWRITE, 0, 1 << lsp->ls_lbshift,
+                    arg, flag, credp));
+
+        case DKIOCGETEFI:
+                if (ddi_copyin((void *)arg, &user_efi,
+                    sizeof (dk_efi_t), flag) != 0)
+                        return (EFAULT);
+
+                return (lofi_urw(lsp, FREAD,
+                    user_efi.dki_lba * (1 << lsp->ls_lbshift),
+                    user_efi.dki_length, (intptr_t)user_efi.dki_data,
+                    flag, credp));
+
+        case DKIOCSETEFI:
+                if (ddi_copyin((void *)arg, &user_efi,
+                    sizeof (dk_efi_t), flag) != 0)
+                        return (EFAULT);
+
+                return (lofi_urw(lsp, FWRITE,
+                    user_efi.dki_lba * (1 << lsp->ls_lbshift),
+                    user_efi.dki_length, (intptr_t)user_efi.dki_data,
+                    flag, credp));
+
         default:
 #ifdef DEBUG
                 cmn_err(CE_WARN, "lofi_ioctl: %d is not implemented\n", cmd);
 #endif  /* DEBUG */
                 return (ENOTTY);