ofdisk.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. /* ofdisk.c - Open Firmware disk access. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2004,2006,2007,2008,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/misc.h>
  20. #include <grub/disk.h>
  21. #include <grub/mm.h>
  22. #include <grub/ieee1275/ieee1275.h>
  23. #include <grub/ieee1275/ofdisk.h>
  24. #include <grub/i18n.h>
  25. #include <grub/time.h>
  26. #include <grub/safemath.h>
  27. static char *last_devpath;
  28. static grub_ieee1275_ihandle_t last_ihandle;
  29. struct ofdisk_hash_ent
  30. {
  31. char *devpath;
  32. char *open_path;
  33. char *grub_devpath;
  34. int is_boot;
  35. int is_removable;
  36. int block_size_fails;
  37. /* Pointer to shortest available name on nodes representing canonical names,
  38. otherwise NULL. */
  39. const char *shortest;
  40. const char *grub_shortest;
  41. struct ofdisk_hash_ent *next;
  42. };
  43. static grub_err_t
  44. grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
  45. struct ofdisk_hash_ent *op);
  46. #define OFDISK_HASH_SZ 8
  47. static struct ofdisk_hash_ent *ofdisk_hash[OFDISK_HASH_SZ];
  48. static int
  49. ofdisk_hash_fn (const char *devpath)
  50. {
  51. int hash = 0;
  52. while (*devpath)
  53. hash ^= *devpath++;
  54. return (hash & (OFDISK_HASH_SZ - 1));
  55. }
  56. static struct ofdisk_hash_ent *
  57. ofdisk_hash_find (const char *devpath)
  58. {
  59. struct ofdisk_hash_ent *p = ofdisk_hash[ofdisk_hash_fn(devpath)];
  60. while (p)
  61. {
  62. if (!grub_strcmp (p->devpath, devpath))
  63. break;
  64. p = p->next;
  65. }
  66. return p;
  67. }
  68. static struct ofdisk_hash_ent *
  69. ofdisk_hash_add_real (char *devpath)
  70. {
  71. struct ofdisk_hash_ent *p;
  72. struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)];
  73. const char *iptr;
  74. char *optr;
  75. grub_size_t sz;
  76. p = grub_zalloc (sizeof (*p));
  77. if (!p)
  78. return NULL;
  79. p->devpath = devpath;
  80. if (grub_mul (grub_strlen (p->devpath), 2, &sz) ||
  81. grub_add (sz, sizeof ("ieee1275/"), &sz))
  82. {
  83. grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path"));
  84. return NULL;
  85. }
  86. p->grub_devpath = grub_malloc (sz);
  87. if (!p->grub_devpath)
  88. {
  89. grub_free (p);
  90. return NULL;
  91. }
  92. if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0))
  93. {
  94. if (grub_add (grub_strlen (p->devpath), 3, &sz))
  95. {
  96. grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of an open path"));
  97. return NULL;
  98. }
  99. p->open_path = grub_malloc (sz);
  100. if (!p->open_path)
  101. {
  102. grub_free (p->grub_devpath);
  103. grub_free (p);
  104. return NULL;
  105. }
  106. optr = grub_stpcpy (p->open_path, p->devpath);
  107. *optr++ = ':';
  108. *optr++ = '0';
  109. *optr = '\0';
  110. }
  111. else
  112. p->open_path = p->devpath;
  113. optr = grub_stpcpy (p->grub_devpath, "ieee1275/");
  114. for (iptr = p->devpath; *iptr; )
  115. {
  116. if (*iptr == ',')
  117. *optr++ = '\\';
  118. *optr++ = *iptr++;
  119. }
  120. *optr = 0;
  121. p->next = *head;
  122. *head = p;
  123. return p;
  124. }
  125. static int
  126. check_string_removable (const char *str)
  127. {
  128. const char *ptr = grub_strrchr (str, '/');
  129. if (ptr)
  130. ptr++;
  131. else
  132. ptr = str;
  133. return (grub_strncmp (ptr, "cdrom", 5) == 0 || grub_strncmp (ptr, "fd", 2) == 0);
  134. }
  135. static struct ofdisk_hash_ent *
  136. ofdisk_hash_add (char *devpath, char *curcan)
  137. {
  138. struct ofdisk_hash_ent *p, *pcan;
  139. p = ofdisk_hash_add_real (devpath);
  140. grub_dprintf ("disk", "devpath = %s, canonical = %s\n", devpath, curcan);
  141. if (!curcan)
  142. {
  143. p->shortest = p->devpath;
  144. p->grub_shortest = p->grub_devpath;
  145. if (check_string_removable (devpath))
  146. p->is_removable = 1;
  147. return p;
  148. }
  149. pcan = ofdisk_hash_find (curcan);
  150. if (!pcan)
  151. pcan = ofdisk_hash_add_real (curcan);
  152. else
  153. grub_free (curcan);
  154. if (check_string_removable (devpath) || check_string_removable (curcan))
  155. pcan->is_removable = 1;
  156. if (!pcan)
  157. grub_errno = GRUB_ERR_NONE;
  158. else
  159. {
  160. if (!pcan->shortest
  161. || grub_strlen (pcan->shortest) > grub_strlen (devpath))
  162. {
  163. pcan->shortest = p->devpath;
  164. pcan->grub_shortest = p->grub_devpath;
  165. }
  166. }
  167. return p;
  168. }
  169. static void
  170. dev_iterate_real (const char *name, const char *path)
  171. {
  172. struct ofdisk_hash_ent *op;
  173. grub_dprintf ("disk", "disk name = %s, path = %s\n", name,
  174. path);
  175. op = ofdisk_hash_find (path);
  176. if (!op)
  177. {
  178. char *name_dup = grub_strdup (name);
  179. char *can = grub_strdup (path);
  180. if (!name_dup || !can)
  181. {
  182. grub_errno = GRUB_ERR_NONE;
  183. grub_free (name_dup);
  184. grub_free (can);
  185. return;
  186. }
  187. op = ofdisk_hash_add (name_dup, can);
  188. }
  189. return;
  190. }
  191. static void
  192. dev_iterate (const struct grub_ieee1275_devalias *alias)
  193. {
  194. if (grub_strcmp (alias->type, "vscsi") == 0)
  195. {
  196. static grub_ieee1275_ihandle_t ihandle;
  197. struct set_color_args
  198. {
  199. struct grub_ieee1275_common_hdr common;
  200. grub_ieee1275_cell_t method;
  201. grub_ieee1275_cell_t ihandle;
  202. grub_ieee1275_cell_t catch_result;
  203. grub_ieee1275_cell_t nentries;
  204. grub_ieee1275_cell_t table;
  205. }
  206. args;
  207. char *buf, *bufptr;
  208. unsigned i;
  209. grub_size_t sz;
  210. if (grub_ieee1275_open (alias->path, &ihandle))
  211. return;
  212. /* This method doesn't need memory allocation for the table. Open
  213. firmware takes care of all memory management and the result table
  214. stays in memory and is never freed. */
  215. INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 3);
  216. args.method = (grub_ieee1275_cell_t) "vscsi-report-luns";
  217. args.ihandle = ihandle;
  218. args.table = 0;
  219. args.nentries = 0;
  220. if (IEEE1275_CALL_ENTRY_FN (&args) == -1 || args.catch_result)
  221. {
  222. grub_ieee1275_close (ihandle);
  223. return;
  224. }
  225. if (grub_add (grub_strlen (alias->path), 32, &sz))
  226. {
  227. grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for vscsi");
  228. grub_ieee1275_close (ihandle);
  229. return;
  230. }
  231. buf = grub_malloc (sz);
  232. if (!buf)
  233. {
  234. grub_ieee1275_close (ihandle);
  235. return;
  236. }
  237. bufptr = grub_stpcpy (buf, alias->path);
  238. for (i = 0; i < args.nentries; i++)
  239. {
  240. grub_uint64_t *ptr;
  241. ptr = *(grub_uint64_t **) (args.table + 4 + 8 * i);
  242. while (*ptr)
  243. {
  244. grub_snprintf (bufptr, 32, "/disk@%" PRIxGRUB_UINT64_T, *ptr++);
  245. dev_iterate_real (buf, buf);
  246. }
  247. }
  248. grub_ieee1275_close (ihandle);
  249. grub_free (buf);
  250. return;
  251. }
  252. else if (grub_strcmp (alias->type, "sas_ioa") == 0)
  253. {
  254. /* The method returns the number of disks and a table where
  255. * each ID is 64-bit long. Example of sas paths:
  256. * /pci@80000002000001f/pci1014,034A@0/sas/disk@c05db70800
  257. * /pci@80000002000001f/pci1014,034A@0/sas/disk@a05db70800
  258. * /pci@80000002000001f/pci1014,034A@0/sas/disk@805db70800 */
  259. struct sas_children
  260. {
  261. struct grub_ieee1275_common_hdr common;
  262. grub_ieee1275_cell_t method;
  263. grub_ieee1275_cell_t ihandle;
  264. grub_ieee1275_cell_t max;
  265. grub_ieee1275_cell_t table;
  266. grub_ieee1275_cell_t catch_result;
  267. grub_ieee1275_cell_t nentries;
  268. }
  269. args;
  270. char *buf, *bufptr;
  271. unsigned i;
  272. grub_uint64_t *table;
  273. grub_uint16_t table_size;
  274. grub_ieee1275_ihandle_t ihandle;
  275. grub_size_t sz;
  276. if (grub_add (grub_strlen (alias->path), sizeof ("/disk@7766554433221100"), &sz))
  277. {
  278. grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for sas_ioa");
  279. return;
  280. }
  281. buf = grub_malloc (sz);
  282. if (!buf)
  283. return;
  284. bufptr = grub_stpcpy (buf, alias->path);
  285. /* Power machines documentation specify 672 as maximum SAS disks in
  286. one system. Using a slightly larger value to be safe. */
  287. table_size = 768;
  288. table = grub_calloc (table_size, sizeof (grub_uint64_t));
  289. if (!table)
  290. {
  291. grub_free (buf);
  292. return;
  293. }
  294. if (grub_ieee1275_open (alias->path, &ihandle))
  295. {
  296. grub_free (buf);
  297. grub_free (table);
  298. return;
  299. }
  300. INIT_IEEE1275_COMMON (&args.common, "call-method", 4, 2);
  301. args.method = (grub_ieee1275_cell_t) "get-sas-children";
  302. args.ihandle = ihandle;
  303. args.max = table_size;
  304. args.table = (grub_ieee1275_cell_t) table;
  305. args.catch_result = 0;
  306. args.nentries = 0;
  307. if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
  308. {
  309. grub_ieee1275_close (ihandle);
  310. grub_free (table);
  311. grub_free (buf);
  312. return;
  313. }
  314. for (i = 0; i < args.nentries; i++)
  315. {
  316. grub_snprintf (bufptr, sizeof ("/disk@7766554433221100"),
  317. "/disk@%" PRIxGRUB_UINT64_T, table[i]);
  318. dev_iterate_real (buf, buf);
  319. }
  320. grub_ieee1275_close (ihandle);
  321. grub_free (table);
  322. grub_free (buf);
  323. }
  324. if (!grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS)
  325. && grub_strcmp (alias->type, "block") == 0)
  326. {
  327. dev_iterate_real (alias->path, alias->path);
  328. return;
  329. }
  330. {
  331. struct grub_ieee1275_devalias child;
  332. FOR_IEEE1275_DEVCHILDREN(alias->path, child)
  333. dev_iterate (&child);
  334. }
  335. }
  336. static void
  337. scan (void)
  338. {
  339. struct grub_ieee1275_devalias alias;
  340. FOR_IEEE1275_DEVALIASES(alias)
  341. {
  342. if (grub_strcmp (alias.type, "block") != 0)
  343. continue;
  344. dev_iterate_real (alias.name, alias.path);
  345. }
  346. FOR_IEEE1275_DEVCHILDREN("/", alias)
  347. dev_iterate (&alias);
  348. }
  349. static int
  350. grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
  351. grub_disk_pull_t pull)
  352. {
  353. unsigned i;
  354. if (pull != GRUB_DISK_PULL_NONE)
  355. return 0;
  356. scan ();
  357. for (i = 0; i < ARRAY_SIZE (ofdisk_hash); i++)
  358. {
  359. static struct ofdisk_hash_ent *ent;
  360. for (ent = ofdisk_hash[i]; ent; ent = ent->next)
  361. {
  362. if (!ent->shortest)
  363. continue;
  364. if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY))
  365. {
  366. grub_ieee1275_phandle_t dev;
  367. char tmp[8];
  368. if (grub_ieee1275_finddevice (ent->devpath, &dev))
  369. {
  370. grub_dprintf ("disk", "finddevice (%s) failed\n",
  371. ent->devpath);
  372. continue;
  373. }
  374. if (grub_ieee1275_get_property (dev, "iconname", tmp,
  375. sizeof tmp, 0))
  376. {
  377. grub_dprintf ("disk", "get iconname failed\n");
  378. continue;
  379. }
  380. if (grub_strcmp (tmp, "sdmmc") != 0)
  381. {
  382. grub_dprintf ("disk", "device is not an SD card\n");
  383. continue;
  384. }
  385. }
  386. if (!ent->is_boot && ent->is_removable)
  387. continue;
  388. if (hook (ent->grub_shortest, hook_data))
  389. return 1;
  390. }
  391. }
  392. return 0;
  393. }
  394. static char *
  395. compute_dev_path (const char *name)
  396. {
  397. char *devpath;
  398. char *p, c;
  399. grub_size_t sz;
  400. if (grub_add (grub_strlen (name), 3, &sz))
  401. {
  402. grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path"));
  403. return NULL;
  404. }
  405. devpath = grub_malloc (sz);
  406. if (!devpath)
  407. return NULL;
  408. /* Un-escape commas. */
  409. p = devpath;
  410. while ((c = *name++) != '\0')
  411. {
  412. if (c == '\\' && *name == ',')
  413. {
  414. *p++ = ',';
  415. name++;
  416. }
  417. else
  418. *p++ = c;
  419. }
  420. *p++ = '\0';
  421. return devpath;
  422. }
  423. static grub_err_t
  424. grub_ofdisk_open (const char *name, grub_disk_t disk)
  425. {
  426. grub_ieee1275_phandle_t dev;
  427. char *devpath;
  428. /* XXX: This should be large enough for any possible case. */
  429. char prop[64];
  430. grub_ssize_t actual;
  431. grub_uint32_t block_size = 0;
  432. grub_err_t err;
  433. if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0)
  434. return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
  435. "not IEEE1275 device");
  436. devpath = compute_dev_path (name + sizeof ("ieee1275/") - 1);
  437. if (! devpath)
  438. return grub_errno;
  439. grub_dprintf ("disk", "Opening `%s'.\n", devpath);
  440. if (grub_ieee1275_finddevice (devpath, &dev))
  441. {
  442. grub_free (devpath);
  443. return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
  444. "can't read device properties");
  445. }
  446. if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop),
  447. &actual))
  448. {
  449. grub_free (devpath);
  450. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type");
  451. }
  452. if (grub_strcmp (prop, "block"))
  453. {
  454. grub_free (devpath);
  455. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device");
  456. }
  457. /* XXX: There is no property to read the number of blocks. There
  458. should be a property `#blocks', but it is not there. Perhaps it
  459. is possible to use seek for this. */
  460. disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
  461. {
  462. struct ofdisk_hash_ent *op;
  463. op = ofdisk_hash_find (devpath);
  464. if (!op)
  465. op = ofdisk_hash_add (devpath, NULL);
  466. if (!op)
  467. {
  468. grub_free (devpath);
  469. return grub_errno;
  470. }
  471. disk->id = (unsigned long) op;
  472. disk->data = op->open_path;
  473. err = grub_ofdisk_get_block_size (devpath, &block_size, op);
  474. if (err)
  475. {
  476. grub_free (devpath);
  477. return err;
  478. }
  479. if (block_size != 0)
  480. disk->log_sector_size = grub_log2ull (block_size);
  481. else
  482. disk->log_sector_size = 9;
  483. }
  484. grub_free (devpath);
  485. return 0;
  486. }
  487. static void
  488. grub_ofdisk_close (grub_disk_t disk)
  489. {
  490. if (disk->data == last_devpath)
  491. {
  492. if (last_ihandle)
  493. grub_ieee1275_close (last_ihandle);
  494. last_ihandle = 0;
  495. last_devpath = NULL;
  496. }
  497. disk->data = 0;
  498. }
  499. static grub_err_t
  500. grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector)
  501. {
  502. grub_ssize_t status;
  503. unsigned long long pos;
  504. if (disk->data != last_devpath)
  505. {
  506. if (last_ihandle)
  507. grub_ieee1275_close (last_ihandle);
  508. last_ihandle = 0;
  509. last_devpath = NULL;
  510. grub_ieee1275_open (disk->data, &last_ihandle);
  511. if (! last_ihandle)
  512. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
  513. last_devpath = disk->data;
  514. }
  515. pos = sector << disk->log_sector_size;
  516. grub_ieee1275_seek (last_ihandle, pos, &status);
  517. if (status < 0)
  518. return grub_error (GRUB_ERR_READ_ERROR,
  519. "seek error, can't seek block %llu",
  520. (long long) sector);
  521. return 0;
  522. }
  523. static grub_err_t
  524. grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
  525. grub_size_t size, char *buf)
  526. {
  527. grub_err_t err;
  528. grub_ssize_t actual;
  529. err = grub_ofdisk_prepare (disk, sector);
  530. if (err)
  531. return err;
  532. grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size,
  533. &actual);
  534. if (actual != (grub_ssize_t) (size << disk->log_sector_size))
  535. return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx "
  536. "from `%s'"),
  537. (unsigned long long) sector,
  538. disk->name);
  539. return 0;
  540. }
  541. static grub_err_t
  542. grub_ofdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
  543. grub_size_t size, const char *buf)
  544. {
  545. grub_err_t err;
  546. grub_ssize_t actual;
  547. err = grub_ofdisk_prepare (disk, sector);
  548. if (err)
  549. return err;
  550. grub_ieee1275_write (last_ihandle, buf, size << disk->log_sector_size,
  551. &actual);
  552. if (actual != (grub_ssize_t) (size << disk->log_sector_size))
  553. return grub_error (GRUB_ERR_WRITE_ERROR, N_("failure writing sector 0x%llx "
  554. "to `%s'"),
  555. (unsigned long long) sector,
  556. disk->name);
  557. return 0;
  558. }
  559. static struct grub_disk_dev grub_ofdisk_dev =
  560. {
  561. .name = "ofdisk",
  562. .id = GRUB_DISK_DEVICE_OFDISK_ID,
  563. .disk_iterate = grub_ofdisk_iterate,
  564. .disk_open = grub_ofdisk_open,
  565. .disk_close = grub_ofdisk_close,
  566. .disk_read = grub_ofdisk_read,
  567. .disk_write = grub_ofdisk_write,
  568. .next = 0
  569. };
  570. static void
  571. insert_bootpath (void)
  572. {
  573. char *bootpath;
  574. grub_ssize_t bootpath_size;
  575. char *type;
  576. grub_size_t sz;
  577. if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath",
  578. &bootpath_size)
  579. || bootpath_size <= 0)
  580. {
  581. /* Should never happen. */
  582. grub_printf ("/chosen/bootpath property missing!\n");
  583. return;
  584. }
  585. if (grub_add (bootpath_size, 64, &sz))
  586. {
  587. grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining bootpath size"));
  588. return;
  589. }
  590. bootpath = (char *) grub_malloc (sz);
  591. if (! bootpath)
  592. {
  593. grub_print_error ();
  594. return;
  595. }
  596. grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath,
  597. (grub_size_t) bootpath_size + 1, 0);
  598. bootpath[bootpath_size] = '\0';
  599. /* Transform an OF device path to a GRUB path. */
  600. type = grub_ieee1275_get_device_type (bootpath);
  601. if (!(type && grub_strcmp (type, "network") == 0))
  602. {
  603. struct ofdisk_hash_ent *op;
  604. char *device = grub_ieee1275_get_devname (bootpath);
  605. op = ofdisk_hash_add (device, NULL);
  606. op->is_boot = 1;
  607. }
  608. grub_free (type);
  609. grub_free (bootpath);
  610. }
  611. void
  612. grub_ofdisk_fini (void)
  613. {
  614. if (last_ihandle)
  615. grub_ieee1275_close (last_ihandle);
  616. last_ihandle = 0;
  617. last_devpath = NULL;
  618. grub_disk_dev_unregister (&grub_ofdisk_dev);
  619. }
  620. void
  621. grub_ofdisk_init (void)
  622. {
  623. grub_disk_firmware_fini = grub_ofdisk_fini;
  624. insert_bootpath ();
  625. grub_disk_dev_register (&grub_ofdisk_dev);
  626. }
  627. static grub_err_t
  628. grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size,
  629. struct ofdisk_hash_ent *op)
  630. {
  631. struct size_args_ieee1275
  632. {
  633. struct grub_ieee1275_common_hdr common;
  634. grub_ieee1275_cell_t method;
  635. grub_ieee1275_cell_t ihandle;
  636. grub_ieee1275_cell_t result;
  637. grub_ieee1275_cell_t size1;
  638. grub_ieee1275_cell_t size2;
  639. } args_ieee1275;
  640. if (last_ihandle)
  641. grub_ieee1275_close (last_ihandle);
  642. last_ihandle = 0;
  643. last_devpath = NULL;
  644. grub_ieee1275_open (device, &last_ihandle);
  645. if (! last_ihandle)
  646. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
  647. *block_size = 0;
  648. if (op->block_size_fails >= 2)
  649. return GRUB_ERR_NONE;
  650. INIT_IEEE1275_COMMON (&args_ieee1275.common, "call-method", 2, 2);
  651. args_ieee1275.method = (grub_ieee1275_cell_t) "block-size";
  652. args_ieee1275.ihandle = last_ihandle;
  653. args_ieee1275.result = 1;
  654. if (IEEE1275_CALL_ENTRY_FN (&args_ieee1275) == -1)
  655. {
  656. grub_dprintf ("disk", "can't get block size: failed call-method\n");
  657. op->block_size_fails++;
  658. }
  659. else if (args_ieee1275.result)
  660. {
  661. grub_dprintf ("disk", "can't get block size: %lld\n",
  662. (long long) args_ieee1275.result);
  663. op->block_size_fails++;
  664. }
  665. else if (args_ieee1275.size1
  666. && !(args_ieee1275.size1 & (args_ieee1275.size1 - 1))
  667. && args_ieee1275.size1 >= 512 && args_ieee1275.size1 <= 16384)
  668. {
  669. op->block_size_fails = 0;
  670. *block_size = args_ieee1275.size1;
  671. }
  672. return 0;
  673. }