1224106Snwhitehorn/*- 2224106Snwhitehorn * Copyright (C) 2008 Semihalf, Rafal Jaworowski 3224106Snwhitehorn * Copyright (C) 2009 Semihalf, Piotr Ziecik 4224106Snwhitehorn * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) 5224106Snwhitehorn * All rights reserved. 6224106Snwhitehorn * 7224106Snwhitehorn * Redistribution and use in source and binary forms, with or without 8224106Snwhitehorn * modification, are permitted provided that the following conditions 9224106Snwhitehorn * are met: 10224106Snwhitehorn * 1. Redistributions of source code must retain the above copyright 11224106Snwhitehorn * notice, this list of conditions and the following disclaimer. 12224106Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 13224106Snwhitehorn * notice, this list of conditions and the following disclaimer in the 14224106Snwhitehorn * documentation and/or other materials provided with the distribution. 15224106Snwhitehorn * 16224106Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17224106Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18224106Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19224106Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20224106Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21224106Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22224106Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23224106Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24224106Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25224106Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26224106Snwhitehorn * 27224106Snwhitehorn * $FreeBSD$ 28224106Snwhitehorn */ 29224106Snwhitehorn 30224106Snwhitehorn#include <sys/endian.h> 31224106Snwhitehorn#include <machine/stdarg.h> 32224106Snwhitehorn#include <stand.h> 33224106Snwhitehorn#include <uuid.h> 34224106Snwhitehorn 35224106Snwhitehorn#define FSTYPENAMES 36224106Snwhitehorn#include <sys/disklabel.h> 37224106Snwhitehorn#include <sys/diskmbr.h> 38224106Snwhitehorn#include <sys/gpt.h> 39224106Snwhitehorn 40224106Snwhitehorn#include "bootstrap.h" 41224106Snwhitehorn#include "ps3bus.h" 42224106Snwhitehorn#include "ps3devdesc.h" 43224106Snwhitehorn#include "ps3stor.h" 44224106Snwhitehorn 45224106Snwhitehorn#define dev_printf(dev, fmt, args...) \ 46224106Snwhitehorn printf("%s%d: " fmt "\n" , dev->d_dev->dv_name, dev->d_unit, ##args) 47224106Snwhitehorn 48224106Snwhitehorn#ifdef DISK_DEBUG 49224106Snwhitehorn#define DEBUG(fmt, args...) printf("%s:%d: " fmt "\n" , __func__ , __LINE__, ##args) 50224106Snwhitehorn#else 51224106Snwhitehorn#define DEBUG(fmt, args...) 52224106Snwhitehorn#endif 53224106Snwhitehorn 54224106Snwhitehornstruct open_dev; 55224106Snwhitehorn 56224106Snwhitehornstatic int ps3disk_open_gpt(struct ps3_devdesc *dev, struct open_dev *od); 57224106Snwhitehornstatic void ps3disk_uuid_letoh(uuid_t *uuid); 58224106Snwhitehorn 59224106Snwhitehornstatic int ps3disk_init(void); 60224106Snwhitehornstatic int ps3disk_strategy(void *devdata, int flag, daddr_t dblk, 61224106Snwhitehorn size_t size, char *buf, size_t *rsize); 62224106Snwhitehornstatic int ps3disk_open(struct open_file *f, ...); 63224106Snwhitehornstatic int ps3disk_close(struct open_file *f); 64224106Snwhitehornstatic void ps3disk_print(int verbose); 65224106Snwhitehorn 66224106Snwhitehornstruct devsw ps3disk = { 67224106Snwhitehorn "disk", 68224106Snwhitehorn DEVT_DISK, 69224106Snwhitehorn ps3disk_init, 70224106Snwhitehorn ps3disk_strategy, 71224106Snwhitehorn ps3disk_open, 72224106Snwhitehorn ps3disk_close, 73224106Snwhitehorn noioctl, 74224106Snwhitehorn ps3disk_print, 75224106Snwhitehorn}; 76224106Snwhitehorn 77224106Snwhitehornstruct gpt_part { 78224106Snwhitehorn int gp_index; 79224106Snwhitehorn uuid_t gp_type; 80224106Snwhitehorn uint64_t gp_start; 81224106Snwhitehorn uint64_t gp_end; 82224106Snwhitehorn}; 83224106Snwhitehorn 84224106Snwhitehornstruct open_dev { 85224106Snwhitehorn uint64_t od_start; 86224106Snwhitehorn 87224106Snwhitehorn union { 88224106Snwhitehorn struct { 89224106Snwhitehorn int nparts; 90224106Snwhitehorn struct gpt_part *parts; 91224106Snwhitehorn } gpt; 92224106Snwhitehorn } od_kind; 93224106Snwhitehorn}; 94224106Snwhitehorn 95224106Snwhitehorn#define od_gpt_nparts od_kind.gpt.nparts 96224106Snwhitehorn#define od_gpt_parts od_kind.gpt.parts 97224106Snwhitehorn 98224106Snwhitehornstatic struct ps3_stordev stor_dev; 99224106Snwhitehorn 100224106Snwhitehornstatic int ps3disk_init(void) 101224106Snwhitehorn{ 102224106Snwhitehorn int err; 103224106Snwhitehorn 104224106Snwhitehorn err = ps3stor_setup(&stor_dev, PS3_DEV_TYPE_STOR_DISK); 105224106Snwhitehorn if (err) 106224106Snwhitehorn return err; 107224106Snwhitehorn 108224106Snwhitehorn return 0; 109224106Snwhitehorn} 110224106Snwhitehorn 111224106Snwhitehornstatic int ps3disk_strategy(void *devdata, int flag, daddr_t dblk, 112224106Snwhitehorn size_t size, char *buf, size_t *rsize) 113224106Snwhitehorn{ 114224106Snwhitehorn struct ps3_devdesc *dev = (struct ps3_devdesc *) devdata; 115224106Snwhitehorn struct open_dev *od = (struct open_dev *) dev->d_disk.data; 116224106Snwhitehorn int err; 117224106Snwhitehorn 118224106Snwhitehorn if (flag != F_READ) { 119224106Snwhitehorn dev_printf(dev, "write operation is not supported!\n"); 120224106Snwhitehorn return EROFS; 121224106Snwhitehorn } 122224106Snwhitehorn 123224106Snwhitehorn if (size % stor_dev.sd_blksize) { 124224106Snwhitehorn dev_printf(dev, "size=%u is not multiple of device block size=%llu\n", 125224106Snwhitehorn size, stor_dev.sd_blksize); 126224106Snwhitehorn return EIO; 127224106Snwhitehorn } 128224106Snwhitehorn 129224106Snwhitehorn if (rsize) 130224106Snwhitehorn *rsize = 0; 131224106Snwhitehorn 132224106Snwhitehorn err = ps3stor_read_sectors(&stor_dev, dev->d_unit, od->od_start + dblk, 133224106Snwhitehorn size / stor_dev.sd_blksize, 0, buf); 134224106Snwhitehorn 135224106Snwhitehorn if (!err && rsize) 136224106Snwhitehorn *rsize = size; 137224106Snwhitehorn 138224106Snwhitehorn if (err) 139224106Snwhitehorn dev_printf(dev, "read operation failed dblk=%llu size=%d err=%d\n", 140224106Snwhitehorn dblk, size, err); 141224106Snwhitehorn 142224106Snwhitehorn return err; 143224106Snwhitehorn} 144224106Snwhitehorn 145224106Snwhitehornstatic int ps3disk_open(struct open_file *f, ...) 146224106Snwhitehorn{ 147224106Snwhitehorn va_list ap; 148224106Snwhitehorn struct ps3_devdesc *dev; 149224106Snwhitehorn struct open_dev *od; 150224106Snwhitehorn int err; 151224106Snwhitehorn 152224106Snwhitehorn va_start(ap, f); 153224106Snwhitehorn dev = va_arg(ap, struct ps3_devdesc *); 154224106Snwhitehorn va_end(ap); 155224106Snwhitehorn 156224106Snwhitehorn od = malloc(sizeof(struct open_dev)); 157224106Snwhitehorn if (!od) { 158224106Snwhitehorn dev_printf(dev, "couldn't allocate memory for new open_dev\n"); 159224106Snwhitehorn return ENOMEM; 160224106Snwhitehorn } 161224106Snwhitehorn 162224106Snwhitehorn err = ps3disk_open_gpt(dev, od); 163224106Snwhitehorn 164224106Snwhitehorn if (err) { 165224106Snwhitehorn dev_printf(dev, "couldn't open GPT disk error=%d\n", err); 166224106Snwhitehorn free(od); 167224106Snwhitehorn } else { 168224106Snwhitehorn ((struct ps3_devdesc *) (f->f_devdata))->d_disk.data = od; 169224106Snwhitehorn } 170224106Snwhitehorn 171224106Snwhitehorn return err; 172224106Snwhitehorn} 173224106Snwhitehorn 174224106Snwhitehornstatic int ps3disk_close(struct open_file *f) 175224106Snwhitehorn{ 176224106Snwhitehorn struct ps3_devdesc *dev = f->f_devdata; 177224106Snwhitehorn struct open_dev *od = dev->d_disk.data; 178224106Snwhitehorn 179224106Snwhitehorn if (dev->d_disk.ptype == PTYPE_GPT && od->od_gpt_nparts) 180224106Snwhitehorn free(od->od_gpt_parts); 181224106Snwhitehorn 182224106Snwhitehorn free(od); 183224106Snwhitehorn 184224106Snwhitehorn dev->d_disk.data = NULL; 185224106Snwhitehorn 186224106Snwhitehorn return 0; 187224106Snwhitehorn} 188224106Snwhitehorn 189224106Snwhitehornstatic void ps3disk_print(int verbose) 190224106Snwhitehorn{ 191224106Snwhitehorn} 192224106Snwhitehorn 193224106Snwhitehornstatic int ps3disk_open_gpt(struct ps3_devdesc *dev, struct open_dev *od) 194224106Snwhitehorn{ 195224106Snwhitehorn char buf[512]; 196224106Snwhitehorn struct gpt_hdr *hdr; 197224106Snwhitehorn struct gpt_ent *ent; 198224106Snwhitehorn daddr_t slba, elba, lba; 199224106Snwhitehorn int nparts, eps, i, part, err; 200224106Snwhitehorn 201224106Snwhitehorn od->od_gpt_nparts = 0; 202224106Snwhitehorn od->od_gpt_parts = NULL; 203224106Snwhitehorn 204224106Snwhitehorn err = ps3stor_read_sectors(&stor_dev, dev->d_unit, 0, 1, 0, buf); 205224106Snwhitehorn if (err) { 206224106Snwhitehorn err = EIO; 207224106Snwhitehorn goto out; 208224106Snwhitehorn } 209224106Snwhitehorn 210224106Snwhitehorn if (le16toh(*((uint16_t *) (buf + DOSMAGICOFFSET))) != DOSMAGIC) { 211224106Snwhitehorn err = ENXIO; 212224106Snwhitehorn goto out; 213224106Snwhitehorn } 214224106Snwhitehorn 215224106Snwhitehorn err = ps3stor_read_sectors(&stor_dev, dev->d_unit, 1, 1, 0, buf); 216224106Snwhitehorn if (err) { 217224106Snwhitehorn err = EIO; 218224106Snwhitehorn goto out; 219224106Snwhitehorn } 220224106Snwhitehorn 221224106Snwhitehorn hdr = (struct gpt_hdr *) buf; 222224106Snwhitehorn 223224106Snwhitehorn if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) || 224224106Snwhitehorn le64toh(hdr->hdr_lba_self) != 1 || le32toh(hdr->hdr_revision) < 0x00010000 || 225224106Snwhitehorn le32toh(hdr->hdr_entsz) < sizeof(struct gpt_ent) || 226224106Snwhitehorn stor_dev.sd_blksize % le32toh(hdr->hdr_entsz) != 0) { 227224106Snwhitehorn err = ENXIO; 228224106Snwhitehorn goto out; 229224106Snwhitehorn } 230224106Snwhitehorn 231224106Snwhitehorn nparts = 0; 232224106Snwhitehorn eps = stor_dev.sd_blksize / le32toh(hdr->hdr_entsz); 233224106Snwhitehorn slba = le64toh(hdr->hdr_lba_table); 234224106Snwhitehorn elba = slba + le32toh(hdr->hdr_entries) / eps; 235224106Snwhitehorn 236224106Snwhitehorn for (lba = slba; lba < elba; lba++) { 237224106Snwhitehorn err = ps3stor_read_sectors(&stor_dev, dev->d_unit, lba, 1, 0, buf); 238224106Snwhitehorn if (err) { 239224106Snwhitehorn err = EIO; 240224106Snwhitehorn goto out; 241224106Snwhitehorn } 242224106Snwhitehorn 243224106Snwhitehorn ent = (struct gpt_ent *) buf; 244224106Snwhitehorn 245224106Snwhitehorn for (i = 0; i < eps; i++) { 246224106Snwhitehorn if (uuid_is_nil(&ent[i].ent_type, NULL) || 247224106Snwhitehorn le64toh(ent[i].ent_lba_start) == 0 || 248224106Snwhitehorn le64toh(ent[i].ent_lba_end) < le64toh(ent[i].ent_lba_start)) 249224106Snwhitehorn continue; 250224106Snwhitehorn 251224106Snwhitehorn nparts++; 252224106Snwhitehorn } 253224106Snwhitehorn } 254224106Snwhitehorn 255224106Snwhitehorn if (nparts) { 256224106Snwhitehorn od->od_gpt_nparts = nparts; 257224106Snwhitehorn 258224106Snwhitehorn od->od_gpt_parts = malloc(nparts * sizeof(struct gpt_part)); 259224106Snwhitehorn if (!od->od_gpt_parts) { 260224106Snwhitehorn err = ENOMEM; 261224106Snwhitehorn goto out; 262224106Snwhitehorn } 263224106Snwhitehorn 264224106Snwhitehorn for (lba = slba, part = 0; lba < elba; lba++) { 265224106Snwhitehorn err = ps3stor_read_sectors(&stor_dev, dev->d_unit, lba, 1, 0, buf); 266224106Snwhitehorn if (err) { 267224106Snwhitehorn err = EIO; 268224106Snwhitehorn goto out; 269224106Snwhitehorn } 270224106Snwhitehorn 271224106Snwhitehorn ent = (struct gpt_ent *) buf; 272224106Snwhitehorn 273224106Snwhitehorn for (i = 0; i < eps; i++) { 274224106Snwhitehorn if (uuid_is_nil(&ent[i].ent_type, NULL) || 275224106Snwhitehorn le64toh(ent[i].ent_lba_start) == 0 || 276224106Snwhitehorn le64toh(ent[i].ent_lba_end) < le64toh(ent[i].ent_lba_start)) 277224106Snwhitehorn continue; 278224106Snwhitehorn 279224106Snwhitehorn od->od_gpt_parts[part].gp_index = (lba - slba) * eps + i + 1; 280224106Snwhitehorn od->od_gpt_parts[part].gp_type = ent[i].ent_type; 281224106Snwhitehorn od->od_gpt_parts[part].gp_start = le64toh(ent[i].ent_lba_start); 282224106Snwhitehorn od->od_gpt_parts[part].gp_end = le64toh(ent[i].ent_lba_end); 283224106Snwhitehorn ps3disk_uuid_letoh(&od->od_gpt_parts[part].gp_type); 284224106Snwhitehorn part++; 285224106Snwhitehorn } 286224106Snwhitehorn } 287224106Snwhitehorn } 288224106Snwhitehorn 289224106Snwhitehorn dev->d_disk.ptype = PTYPE_GPT; 290224106Snwhitehorn 291224106Snwhitehorn if (od->od_gpt_nparts && !dev->d_disk.pnum) 292224106Snwhitehorn dev->d_disk.pnum = od->od_gpt_parts[0].gp_index; 293224106Snwhitehorn 294224106Snwhitehorn for (i = 0; i < od->od_gpt_nparts; i++) 295224106Snwhitehorn if (od->od_gpt_parts[i].gp_index == dev->d_disk.pnum) 296224106Snwhitehorn od->od_start = od->od_gpt_parts[i].gp_start; 297224106Snwhitehorn 298224106Snwhitehorn err = 0; 299224106Snwhitehorn 300224106Snwhitehornout: 301224106Snwhitehorn 302224106Snwhitehorn if (err && od->od_gpt_parts) 303224106Snwhitehorn free(od->od_gpt_parts); 304224106Snwhitehorn 305224106Snwhitehorn return err; 306224106Snwhitehorn} 307224106Snwhitehorn 308224106Snwhitehornstatic void ps3disk_uuid_letoh(uuid_t *uuid) 309224106Snwhitehorn{ 310224106Snwhitehorn uuid->time_low = le32toh(uuid->time_low); 311224106Snwhitehorn uuid->time_mid = le16toh(uuid->time_mid); 312224106Snwhitehorn uuid->time_hi_and_version = le16toh(uuid->time_hi_and_version); 313224106Snwhitehorn} 314