using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

internal static class CR
{
    public static string Get() { return Console.ReadLine(); }
    public static IEnumerable<string> GetTexts() { return Console.ReadLine().Split(' '); }
    public static int GetInteger() { return int.Parse(Console.ReadLine()); }
    public static IEnumerable<int> GetIntegers() { return Console.ReadLine().Split(' ').Select(x => int.Parse(x)); }
}

namespace AtCoderBeginnerContest
{
    internal class Program
    {
        public static int H { get; private set; }
        public static int W { get; private set; }
        public static List<List<bool>> S { get; private set; }

        private static void Main() { var r = GetResult(); Debug.WriteLine(r); Console.WriteLine(r); }

        private static object GetResult()
        {
            var inputs = CR.GetIntegers().ToList();
            H = inputs[0];
            W = inputs[1];

            S = GetRows().ToList();

            var max = 0;
            for (int i = 0; i < H; i++)
            {
                for (int j = 0; j < W; j++)
                {
                    var nm = NewMethod(i, j);
                    max = max > nm ? max : nm;
                }
            }

            return max;
        }

        private static int NewMethod(int xPoint, int yPoint)
        {
            var searched = Enumerable.Range(0, H).Select(x => Enumerable.Range(0, W).Select(y => new Result()).ToList()).ToList();
            var step = 0;

            SearchStart(xPoint, yPoint, searched);
            for (int i = 0; i < H * W; i++)
            {
                step++;
                for (int j = 0; j < H; j++)
                {
                    for (int k = 0; k < W; k++)
                    {
                        if (searched[j][k].Step == step - 1)
                        {
                            Search(j, k, searched, step);
                        }
                    }
                }
            }

            return searched.Select(x => x.Max(y => y.Step)).Max();
        }

        private static void SearchStart(int x, int y, List<List<Result>> searched)
        {
            if (x < 0 || W <= x || y < 0 || H <= y || !S[x][y]) return;
            if (searched[x][y].Searched) return;

            searched[x][y].Searched = true;
            searched[x][y].Step = 0;
        }

        private static void Search(int x, int y, List<List<Result>> searched, int step)
        {
            Search2(x + 1, y, searched, step);
            Search2(x, y + 1, searched, step);
            Search2(x - 1, y, searched, step);
            Search2(x, y - 1, searched, step);
        }
        private static void Search2(int x, int y, List<List<Result>> searched, int step)
        {
            if (x < 0 || W <= x || y < 0 || H <= y || !S[x][y]) return;
            if (searched[x][y].Searched) return;

            searched[x][y].Searched = true;
            searched[x][y].Step = step;
        }
        private static IEnumerable<List<bool>> GetRows()
        {
            for (int i = 0; i < H; i++)
            {
                yield return CR.Get().Select(x => x == '.').ToList();
            }
        }

        internal class Result
        {
            public bool Searched { get; set; }
            public int Step { get; set; } = -1;
        }
    }
}
